1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "vsync_distributor.h"
17 #include <chrono>
18 #include <condition_variable>
19 #include <algorithm>
20 #include <sched.h>
21 #include <sys/resource.h>
22 #include <scoped_bytrace.h>
23 #include "vsync_log.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 constexpr int32_t SOFT_VSYNC_PERIOD = 16;
29 constexpr int32_t ERRNO_EAGAIN = -1;
30 constexpr int32_t ERRNO_OTHER = -2;
31 constexpr int32_t THREAD_PRIORTY = -6;
32 constexpr int32_t SCHED_PRIORITY = 2;
33 constexpr uint32_t SOCKET_CHANNEL_SIZE = 1024;
34 }
35
VSyncConnectionDeathRecipient(wptr<VSyncConnection> conn)36 VSyncConnection::VSyncConnectionDeathRecipient::VSyncConnectionDeathRecipient(
37 wptr<VSyncConnection> conn) : conn_(conn)
38 {
39 }
40
OnRemoteDied(const wptr<IRemoteObject> & token)41 void VSyncConnection::VSyncConnectionDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& token)
42 {
43 auto tokenSptr = token.promote();
44 if (tokenSptr == nullptr) {
45 VLOGW("%{public}s: can't promote remote object.", __func__);
46 return;
47 }
48 auto vsyncConn = conn_.promote();
49 if (vsyncConn == nullptr) {
50 VLOGW("%{public}s: VSyncConnection was dead, do nothing.", __func__);
51 return;
52 }
53 if (vsyncConn->token_ != tokenSptr) {
54 VLOGI("%{public}s: token doesn't match, ignore it.", __func__);
55 return;
56 }
57 VLOGW("%{public}s: clear socketPair, conn name:%{public}s.", __func__, vsyncConn->info_.name_.c_str());
58 vsyncConn->OnVSyncRemoteDied();
59 }
60
VSyncConnection(const sptr<VSyncDistributor> & distributor,std::string name,const sptr<IRemoteObject> & token)61 VSyncConnection::VSyncConnection(
62 const sptr<VSyncDistributor>& distributor,
63 std::string name,
64 const sptr<IRemoteObject>& token)
65 : rate_(-1),
66 info_(name),
67 vsyncConnDeathRecipient_(new VSyncConnectionDeathRecipient(this)),
68 token_(token),
69 distributor_(distributor)
70 {
71 socketPair_ = new LocalSocketPair();
72 int32_t err = socketPair_->CreateChannel(SOCKET_CHANNEL_SIZE, SOCKET_CHANNEL_SIZE);
73 if (err != 0) {
74 ScopedBytrace func("Create socket channel failed, errno = " + std::to_string(errno));
75 }
76 if (token_ != nullptr) {
77 token_->AddDeathRecipient(vsyncConnDeathRecipient_);
78 }
79 isRemoteDead_ = false;
80 }
81
~VSyncConnection()82 VSyncConnection::~VSyncConnection()
83 {
84 if ((token_ != nullptr) && (vsyncConnDeathRecipient_ != nullptr)) {
85 token_->RemoveDeathRecipient(vsyncConnDeathRecipient_);
86 }
87 }
88
RequestNextVSync()89 VsyncError VSyncConnection::RequestNextVSync()
90 {
91 std::unique_lock<std::mutex> locker(mutex_);
92 if (isRemoteDead_) {
93 VLOGE("%{public}s VSync Client Connection is dead, name:%{public}s.", __func__, info_.name_.c_str());
94 return VSYNC_ERROR_API_FAILED;
95 }
96 if (distributor_ == nullptr) {
97 return VSYNC_ERROR_NULLPTR;
98 }
99 const sptr<VSyncDistributor> distributor = distributor_.promote();
100 if (distributor == nullptr) {
101 return VSYNC_ERROR_NULLPTR;
102 }
103 return distributor->RequestNextVSync(this);
104 }
105
GetReceiveFd(int32_t & fd)106 VsyncError VSyncConnection::GetReceiveFd(int32_t &fd)
107 {
108 std::unique_lock<std::mutex> locker(mutex_);
109 if (isRemoteDead_) {
110 VLOGE("%{public}s VSync Client Connection is dead, name:%{public}s.", __func__, info_.name_.c_str());
111 return VSYNC_ERROR_API_FAILED;
112 }
113 fd = socketPair_->GetReceiveDataFd();
114 return VSYNC_ERROR_OK;
115 }
116
PostEvent(int64_t now,int64_t period,int64_t vsyncCount)117 int32_t VSyncConnection::PostEvent(int64_t now, int64_t period, int64_t vsyncCount)
118 {
119 std::unique_lock<std::mutex> locker(mutex_);
120 if (isRemoteDead_) {
121 VLOGE("%{public}s VSync Client Connection is dead, name:%{public}s.", __func__, info_.name_.c_str());
122 return ERRNO_OTHER;
123 }
124 ScopedBytrace func("SendVsyncTo conn: " + info_.name_ + ", now:" + std::to_string(now)
125 + ", postVSyncCount_:" + std::to_string(vsyncCount));
126 // 3 is array size.
127 int64_t data[3];
128 data[0] = now;
129 // 1, 2: index of array data.
130 data[1] = now + period;
131 data[2] = vsyncCount;
132 if (info_.name_ == "rs") {
133 // 5000000 is the vsync offset.
134 data[1] += period - 5000000;
135 }
136 int32_t ret = socketPair_->SendData(data, sizeof(data));
137 if (ret > -1) {
138 ScopedBytrace successful("successful");
139 info_.postVSyncCount_++;
140 } else {
141 ScopedBytrace failed("failed");
142 }
143 return ret;
144 }
145
SetVSyncRate(int32_t rate)146 VsyncError VSyncConnection::SetVSyncRate(int32_t rate)
147 {
148 std::unique_lock<std::mutex> locker(mutex_);
149 if (isRemoteDead_) {
150 VLOGE("%{public}s VSync Client Connection is dead, name:%{public}s.", __func__, info_.name_.c_str());
151 return VSYNC_ERROR_API_FAILED;
152 }
153 if (distributor_ == nullptr) {
154 return VSYNC_ERROR_NULLPTR;
155 }
156 const sptr<VSyncDistributor> distributor = distributor_.promote();
157 if (distributor == nullptr) {
158 return VSYNC_ERROR_NULLPTR;
159 }
160 return distributor->SetVSyncRate(rate, this);
161 }
162
GetVSyncPeriod(int64_t & period)163 VsyncError VSyncConnection::GetVSyncPeriod(int64_t &period)
164 {
165 std::unique_lock<std::mutex> locker(mutex_);
166 if (isRemoteDead_) {
167 VLOGE("%{public}s VSync Client Connection is dead, name:%{public}s.", __func__, info_.name_.c_str());
168 return VSYNC_ERROR_API_FAILED;
169 }
170 const sptr<VSyncDistributor> distributor = distributor_.promote();
171 if (distributor == nullptr) {
172 return VSYNC_ERROR_NULLPTR;
173 }
174 return distributor->GetVSyncPeriod(period);
175 }
176
OnVSyncRemoteDied()177 VsyncError VSyncConnection::OnVSyncRemoteDied()
178 {
179 std::unique_lock<std::mutex> locker(mutex_);
180 socketPair_ = nullptr;
181 distributor_->RemoveConnection(this);
182 isRemoteDead_ = true;
183 return VSYNC_ERROR_OK;
184 }
185
VSyncDistributor(sptr<VSyncController> controller,std::string name)186 VSyncDistributor::VSyncDistributor(sptr<VSyncController> controller, std::string name)
187 : controller_(controller), mutex_(), con_(), connections_(),
188 event_(), vsyncEnabled_(false), name_(name)
189 {
190 vsyncThreadRunning_ = true;
191 threadLoop_ = std::thread(std::bind(&VSyncDistributor::ThreadMain, this));
192 std::string threadName = "VSync-" + name;
193 pthread_setname_np(threadLoop_.native_handle(), threadName.c_str());
194 }
195
~VSyncDistributor()196 VSyncDistributor::~VSyncDistributor()
197 {
198 {
199 std::unique_lock<std::mutex> locker(mutex_);
200 vsyncThreadRunning_ = false;
201 }
202 if (threadLoop_.joinable()) {
203 con_.notify_all();
204 threadLoop_.join();
205 }
206 }
207
AddConnection(const sptr<VSyncConnection> & connection)208 VsyncError VSyncDistributor::AddConnection(const sptr<VSyncConnection>& connection)
209 {
210 if (connection == nullptr) {
211 return VSYNC_ERROR_NULLPTR;
212 }
213 std::lock_guard<std::mutex> locker(mutex_);
214 auto it = find(connections_.begin(), connections_.end(), connection);
215 if (it != connections_.end()) {
216 return VSYNC_ERROR_INVALID_ARGUMENTS;
217 }
218 ScopedBytrace func("Add VSyncConnection: " + connection->info_.name_);
219 connections_.push_back(connection);
220 return VSYNC_ERROR_OK;
221 }
222
RemoveConnection(const sptr<VSyncConnection> & connection)223 VsyncError VSyncDistributor::RemoveConnection(const sptr<VSyncConnection>& connection)
224 {
225 if (connection == nullptr) {
226 return VSYNC_ERROR_NULLPTR;
227 }
228 std::lock_guard<std::mutex> locker(mutex_);
229 auto it = find(connections_.begin(), connections_.end(), connection);
230 if (it == connections_.end()) {
231 return VSYNC_ERROR_INVALID_ARGUMENTS;
232 }
233 ScopedBytrace func("Remove VSyncConnection: " + connection->info_.name_);
234 connections_.erase(it);
235 return VSYNC_ERROR_OK;
236 }
237
ThreadMain()238 void VSyncDistributor::ThreadMain()
239 {
240 // set thread priorty
241 setpriority(PRIO_PROCESS, 0, THREAD_PRIORTY);
242 struct sched_param param = {0};
243 param.sched_priority = SCHED_PRIORITY;
244 sched_setscheduler(0, SCHED_FIFO, ¶m);
245
246 int64_t timestamp;
247 int64_t vsyncCount;
248 while (vsyncThreadRunning_ == true) {
249 std::vector<sptr<VSyncConnection>> conns;
250 {
251 bool waitForVSync = false;
252 std::unique_lock<std::mutex> locker(mutex_);
253 timestamp = event_.timestamp;
254 event_.timestamp = 0;
255 vsyncCount = event_.vsyncCount;
256 CollectConnections(waitForVSync, timestamp, conns, vsyncCount);
257 // no vsync signal
258 if (timestamp == 0) {
259 // there is some connections request next vsync, enable vsync if vsync disable and
260 // and start the software vsync with wait_for function
261 if (waitForVSync == true && vsyncEnabled_ == false) {
262 EnableVSync();
263 if (con_.wait_for(locker, std::chrono::milliseconds(SOFT_VSYNC_PERIOD)) ==
264 std::cv_status::timeout) {
265 const auto &now = std::chrono::steady_clock::now().time_since_epoch();
266 timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
267 event_.timestamp = timestamp;
268 event_.vsyncCount++;
269 }
270 } else {
271 // just wait request or vsync signal
272 if (vsyncThreadRunning_ == true) {
273 con_.wait(locker);
274 }
275 }
276 continue;
277 } else if ((timestamp > 0) && (waitForVSync == false)) {
278 // if there is a vsync signal but no vaild connections, we should disable vsync
279 DisableVSync();
280 continue;
281 }
282 }
283 ScopedBytrace func(name_ + "_SendVsync");
284 for (uint32_t i = 0; i < conns.size(); i++) {
285 int32_t ret = conns[i]->PostEvent(timestamp, event_.period, event_.vsyncCount);
286 VLOGD("Distributor name:%{public}s, connection name:%{public}s, ret:%{public}d",
287 name_.c_str(), conns[i]->info_.name_.c_str(), ret);
288 if (ret == 0 || ret == ERRNO_OTHER) {
289 RemoveConnection(conns[i]);
290 } else if (ret == ERRNO_EAGAIN) {
291 std::unique_lock<std::mutex> locker(mutex_);
292 // Exclude SetVSyncRate
293 if (conns[i]->rate_ < 0) {
294 conns[i]->rate_ = 0;
295 }
296 }
297 }
298 }
299 }
300
EnableVSync()301 void VSyncDistributor::EnableVSync()
302 {
303 if (controller_ != nullptr && vsyncEnabled_ == false) {
304 controller_->SetCallback(this);
305 controller_->SetEnable(true, vsyncEnabled_);
306 }
307 }
308
DisableVSync()309 void VSyncDistributor::DisableVSync()
310 {
311 if (controller_ != nullptr && vsyncEnabled_ == true) {
312 controller_->SetEnable(false, vsyncEnabled_);
313 }
314 }
315
OnVSyncEvent(int64_t now,int64_t period)316 void VSyncDistributor::OnVSyncEvent(int64_t now, int64_t period)
317 {
318 std::lock_guard<std::mutex> locker(mutex_);
319 event_.timestamp = now;
320 event_.vsyncCount++;
321 event_.period = period;
322 con_.notify_all();
323 }
324
CollectConnections(bool & waitForVSync,int64_t timestamp,std::vector<sptr<VSyncConnection>> & conns,int64_t vsyncCount)325 void VSyncDistributor::CollectConnections(bool &waitForVSync, int64_t timestamp,
326 std::vector<sptr<VSyncConnection>> &conns, int64_t vsyncCount)
327 {
328 for (uint32_t i = 0; i < connections_.size(); i++) {
329 int32_t rate = connections_[i]->highPriorityState_ ? connections_[i]->highPriorityRate_ :
330 connections_[i]->rate_;
331 if (rate == 0) { // for RequestNextVSync
332 waitForVSync = true;
333 if (timestamp > 0) {
334 connections_[i]->rate_ = -1;
335 conns.push_back(connections_[i]);
336 }
337 } else if (rate > 0) {
338 if (connections_[i]->rate_ == 0) { // for SetHighPriorityVSyncRate with RequestNextVSync
339 waitForVSync = true;
340 if (timestamp > 0 && (vsyncCount % rate == 0)) {
341 connections_[i]->rate_ = -1;
342 conns.push_back(connections_[i]);
343 }
344 } else if (connections_[i]->rate_ > 0) { // for SetVSyncRate
345 waitForVSync = true;
346 if (timestamp > 0 && (vsyncCount % rate == 0)) {
347 conns.push_back(connections_[i]);
348 }
349 }
350 }
351 }
352 }
353
RequestNextVSync(const sptr<VSyncConnection> & connection)354 VsyncError VSyncDistributor::RequestNextVSync(const sptr<VSyncConnection>& connection)
355 {
356 if (connection == nullptr) {
357 VLOGE("connection is nullptr");
358 return VSYNC_ERROR_NULLPTR;
359 }
360 ScopedBytrace func(connection->info_.name_ + "_RequestNextVSync");
361 std::lock_guard<std::mutex> locker(mutex_);
362 auto it = find(connections_.begin(), connections_.end(), connection);
363 if (it == connections_.end()) {
364 VLOGE("connection is invalid arguments");
365 return VSYNC_ERROR_INVALID_ARGUMENTS;
366 }
367 if (connection->rate_ < 0) {
368 connection->rate_ = 0;
369 con_.notify_all();
370 }
371 VLOGD("conn name:%{public}s, rate:%{public}d", connection->info_.name_.c_str(), connection->rate_);
372 return VSYNC_ERROR_OK;
373 }
374
SetVSyncRate(int32_t rate,const sptr<VSyncConnection> & connection)375 VsyncError VSyncDistributor::SetVSyncRate(int32_t rate, const sptr<VSyncConnection>& connection)
376 {
377 if (rate <= 0 || connection == nullptr) {
378 return VSYNC_ERROR_INVALID_ARGUMENTS;
379 }
380 std::lock_guard<std::mutex> locker(mutex_);
381 auto it = find(connections_.begin(), connections_.end(), connection);
382 if (it == connections_.end()) {
383 return VSYNC_ERROR_INVALID_ARGUMENTS;
384 }
385 if (connection->rate_ == rate) {
386 return VSYNC_ERROR_INVALID_ARGUMENTS;
387 }
388 connection->rate_ = rate;
389 VLOGD("conn name:%{public}s", connection->info_.name_.c_str());
390 con_.notify_all();
391 return VSYNC_ERROR_OK;
392 }
393
SetHighPriorityVSyncRate(int32_t highPriorityRate,const sptr<VSyncConnection> & connection)394 VsyncError VSyncDistributor::SetHighPriorityVSyncRate(int32_t highPriorityRate, const sptr<VSyncConnection>& connection)
395 {
396 if (highPriorityRate <= 0 || connection == nullptr) {
397 return VSYNC_ERROR_INVALID_ARGUMENTS;
398 }
399
400 std::lock_guard<std::mutex> locker(mutex_);
401 auto it = find(connections_.begin(), connections_.end(), connection);
402 if (it == connections_.end()) {
403 return VSYNC_ERROR_INVALID_ARGUMENTS;
404 }
405 if (connection->highPriorityRate_ == highPriorityRate) {
406 return VSYNC_ERROR_INVALID_ARGUMENTS;
407 }
408 connection->highPriorityRate_ = highPriorityRate;
409 connection->highPriorityState_ = true;
410 VLOGD("in, conn name:%{public}s, highPriorityRate:%{public}d", connection->info_.name_.c_str(),
411 connection->highPriorityRate_);
412 con_.notify_all();
413 return VSYNC_ERROR_OK;
414 }
415
GetVSyncConnectionInfos(std::vector<ConnectionInfo> & infos)416 VsyncError VSyncDistributor::GetVSyncConnectionInfos(std::vector<ConnectionInfo>& infos)
417 {
418 infos.clear();
419 for (auto &connection : connections_) {
420 infos.push_back(connection->info_);
421 }
422 return VSYNC_ERROR_OK;
423 }
424
QosGetPidByName(const std::string & name,uint32_t & pid)425 VsyncError VSyncDistributor::QosGetPidByName(const std::string& name, uint32_t& pid)
426 {
427 if (name.find("WM") == std::string::npos) {
428 return VSYNC_ERROR_INVALID_ARGUMENTS;
429 }
430 std::string::size_type pos = name.find("_");
431 if (pos == std::string::npos) {
432 return VSYNC_ERROR_INVALID_ARGUMENTS;
433 }
434 pid = (uint32_t)stoi(name.substr(pos + 1));
435 return VSYNC_ERROR_OK;
436 }
437
SetQosVSyncRate(uint32_t pid,int32_t rate)438 VsyncError VSyncDistributor::SetQosVSyncRate(uint32_t pid, int32_t rate)
439 {
440 std::lock_guard<std::mutex> locker(mutex_);
441 for (auto connection : connections_) {
442 uint32_t tmpPid;
443 if (QosGetPidByName(connection->info_.name_, tmpPid) != VSYNC_ERROR_OK) {
444 continue;
445 }
446
447 if (tmpPid == pid) {
448 if (connection->highPriorityRate_ != rate) {
449 connection->highPriorityRate_ = rate;
450 connection->highPriorityState_ = true;
451 VLOGD("in, conn name:%{public}s, highPriorityRate:%{public}d", connection->info_.name_.c_str(),
452 connection->highPriorityRate_);
453 con_.notify_all();
454 }
455 break;
456 }
457 }
458 return VSYNC_ERROR_OK;
459 }
460
GetQosVSyncRateInfos(std::vector<std::pair<uint32_t,int32_t>> & vsyncRateInfos)461 VsyncError VSyncDistributor::GetQosVSyncRateInfos(std::vector<std::pair<uint32_t, int32_t>>& vsyncRateInfos)
462 {
463 vsyncRateInfos.clear();
464
465 std::lock_guard<std::mutex> locker(mutex_);
466 for (auto &connection : connections_) {
467 uint32_t tmpPid;
468 if (QosGetPidByName(connection->info_.name_, tmpPid) != VSYNC_ERROR_OK) {
469 continue;
470 }
471 int32_t tmpRate = connection->highPriorityState_ ? connection->highPriorityRate_ : connection->rate_;
472 vsyncRateInfos.push_back(std::make_pair(tmpPid, tmpRate));
473 }
474 return VSYNC_ERROR_OK;
475 }
476
GetVSyncPeriod(int64_t & period)477 VsyncError VSyncDistributor::GetVSyncPeriod(int64_t &period)
478 {
479 std::lock_guard<std::mutex> locker(mutex_);
480 period = event_.period;
481 return VSYNC_ERROR_OK;
482 }
483 }
484 }
485