• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param);
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