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_receiver.h"
17 #include <memory>
18 #include <mutex>
19 #include <unistd.h>
20 #include <scoped_bytrace.h>
21 #include <fcntl.h>
22 #include <hitrace_meter.h>
23 #include "event_handler.h"
24 #include "graphic_common.h"
25 #include "rs_frame_report_ext.h"
26 #include "vsync_log.h"
27 #include "sandbox_utils.h"
28 #include <rs_trace.h>
29 #include "qos.h"
30 
31 namespace OHOS {
32 namespace Rosen {
33 namespace {
34 constexpr int32_t INVALID_FD = -1;
35 }
OnReadable(int32_t fileDescriptor)36 void VSyncCallBackListener::OnReadable(int32_t fileDescriptor)
37 {
38     HitracePerfScoped perfTrace(ScopedDebugTrace::isEnabled(), HITRACE_TAG_GRAPHIC_AGP, "OnReadablePerfCount");
39     if (fileDescriptor < 0) {
40         VLOGE("OnReadable Invalid fileDescriptor:%{public}d", fileDescriptor);
41         return;
42     }
43     // 3 is array size.
44     int64_t data[3];
45     ssize_t dataCount = 0;
46     if (ReadFdInternal(fileDescriptor, data, dataCount) != VSYNC_ERROR_OK) {
47         return;
48     }
49     HandleVsyncCallbacks(data, dataCount, fileDescriptor);
50 }
51 
OnShutdown(int32_t fileDescriptor)52 void VSyncCallBackListener::OnShutdown(int32_t fileDescriptor)
53 {
54     VLOGI("OnShutdown, fileDescriptor:%{public}d", fileDescriptor);
55     std::lock_guard<std::mutex> locker(cbMutex_);
56     if (fdShutDownCallback_ != nullptr) {
57         fdShutDownCallback_(fileDescriptor);
58     }
59 }
60 
ReadFdInternal(int32_t fd,int64_t (& data)[3],ssize_t & dataCount)61 VsyncError VSyncCallBackListener::ReadFdInternal(int32_t fd, int64_t (&data)[3], ssize_t &dataCount)
62 {
63     std::lock_guard<std::mutex> locker(fdMutex_);
64     if (fdClosed_) {
65         return VSYNC_ERROR_API_FAILED;
66     }
67     ssize_t ret = 0;
68     do {
69         // only take the latest timestamp
70         ret = read(fd, data, sizeof(data));
71         if (ret == 0) {
72             VLOGE("ReadFdInternal, ret is 0, read fd:%{public}d failed, errno:%{public}d", fd, errno);
73             return VSYNC_ERROR_OK;
74         }
75         if (ret == -1) {
76             if (errno == EINTR) {
77                 ret = 0;
78                 continue;
79             } else if (errno != EAGAIN) {
80                 VLOGE("ReadFdInternal, read fd:%{public}d failed, errno:%{public}d", fd, errno);
81             }
82         } else {
83             dataCount += ret;
84         }
85     } while (ret != -1);
86 
87     return VSYNC_ERROR_OK;
88 }
89 
HandleVsyncCallbacks(int64_t data[],ssize_t dataCount,int32_t fileDescriptor)90 void VSyncCallBackListener::HandleVsyncCallbacks(int64_t data[], ssize_t dataCount, int32_t fileDescriptor)
91 {
92     VSyncCallback cb = nullptr;
93     VSyncCallbackWithId cbWithId = nullptr;
94     void *userData = nullptr;
95     int64_t now = 0;
96     int64_t expectedEnd = 0;
97     std::vector<FrameCallback> callbacks;
98     {
99         std::lock_guard<std::mutex> locker(mtx_);
100         cb = vsyncCallbacks_;
101         cbWithId = vsyncCallbacksWithId_;
102         userData = userData_;
103         RNVFlag_ = false;
104         now = data[0];
105         period_ = data[1];
106         periodShared_ = data[1];
107         timeStamp_ = data[0];
108         timeStampShared_ = data[0];
109         expectedEnd = CalculateExpectedEndLocked(now);
110         callbacks = frameCallbacks_;
111         frameCallbacks_.clear();
112     }
113 
114     VLOGD("dataCount:%{public}d, cb == nullptr:%{public}d", dataCount, (cb == nullptr));
115     // 1, 2: index of array data.
116     RS_TRACE_NAME_FMT("ReceiveVsync dataCount: %ldbytes now: %ld expectedEnd: %ld vsyncId: %ld, fd:%d",
117         dataCount, now, expectedEnd, data[2], fileDescriptor); // data[2] is vsyncId
118     if (callbacks.empty() && dataCount > 0 && (cbWithId != nullptr || cb != nullptr)) {
119         // data[2] is frameCount
120         cbWithId != nullptr ? cbWithId(now, data[2], userData) : cb(now, userData);
121     }
122     for (const auto& cb : callbacks) {
123         if (cb.callback_ != nullptr) {
124             cb.callback_(now, cb.userData_);
125         } else if (cb.callbackWithId_ != nullptr) {
126             cb.callbackWithId_(now, data[2], cb.userData_); // data[2] is vsyncId
127         }
128     }
129     if (OHOS::Rosen::RsFrameReportExt::GetInstance().GetEnable()) {
130         OHOS::Rosen::RsFrameReportExt::GetInstance().ReceiveVSync();
131     }
132 }
133 
CalculateExpectedEndLocked(int64_t now)134 int64_t VSyncCallBackListener::CalculateExpectedEndLocked(int64_t now)
135 {
136     int64_t expectedEnd = 0;
137     if (period_ < 0 || now < period_ || now > INT64_MAX - period_) {
138         RS_TRACE_NAME_FMT("invalid timestamps, now:%ld, period_:%ld", now, period_);
139         VLOGE("invalid timestamps, now:" VPUBI64 ", period_:" VPUBI64, now, period_);
140         return 0;
141     }
142     expectedEnd = now + period_;
143     if (name_ == "rs") {
144         // rs vsync offset is 5000000ns
145         expectedEnd = expectedEnd + period_ - 5000000;
146     }
147     return expectedEnd;
148 }
149 
SetFdClosedFlagLocked(bool fdClosed)150 void VSyncCallBackListener::SetFdClosedFlagLocked(bool fdClosed)
151 {
152     fdClosed_ = fdClosed;
153 }
154 
RegisterFdShutDownCallback(FdShutDownCallback cb)155 void VSyncCallBackListener::RegisterFdShutDownCallback(FdShutDownCallback cb)
156 {
157     std::lock_guard<std::mutex> locker(cbMutex_);
158     fdShutDownCallback_ = cb;
159 }
160 
VSyncReceiver(const sptr<IVSyncConnection> & conn,const sptr<IRemoteObject> & token,const std::shared_ptr<OHOS::AppExecFwk::EventHandler> & looper,const std::string & name)161 VSyncReceiver::VSyncReceiver(const sptr<IVSyncConnection>& conn,
162     const sptr<IRemoteObject>& token,
163     const std::shared_ptr<OHOS::AppExecFwk::EventHandler>& looper,
164     const std::string& name)
165     : connection_(conn), token_(token), looper_(looper),
166     listener_(std::make_shared<VSyncCallBackListener>()),
167     init_(false),
168     fd_(INVALID_FD),
169     name_(name)
170 {
171 };
172 
Init()173 VsyncError VSyncReceiver::Init()
174 {
175     std::lock_guard<std::mutex> locker(initMutex_);
176     if (init_) {
177         return VSYNC_ERROR_OK;
178     }
179     if (connection_ == nullptr) {
180         return VSYNC_ERROR_NULLPTR;
181     }
182 
183     VsyncError ret = connection_->GetReceiveFd(fd_);
184     if (ret != VSYNC_ERROR_OK) {
185         return ret;
186     }
187 
188     int32_t retVal = fcntl(fd_, F_SETFL, O_NONBLOCK); // set fd to NonBlock mode
189     if (retVal != 0) {
190         VLOGW("%{public}s fcntl set fd_:%{public}d NonBlock failed, retVal:%{public}d, errno:%{public}d",
191             __func__, fd_, retVal, errno);
192     }
193 
194     listener_->SetName(name_);
195     listener_->RegisterFdShutDownCallback([this](int32_t fileDescriptor) {
196         std::lock_guard<std::mutex> locker(initMutex_);
197         if (fileDescriptor != fd_) {
198             VLOGE("OnShutdown Invalid fileDescriptor:%{public}d, fd_:%{public}d", fileDescriptor, fd_);
199             return;
200         }
201         RemoveAndCloseFdLocked();
202     });
203 
204     if (looper_ == nullptr) {
205         std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create("OS_VSyncThread");
206         looper_ = std::make_shared<AppExecFwk::EventHandler>(runner);
207         runner->Run();
208         looper_->PostTask([] {
209             SetThreadQos(QOS::QosLevel::QOS_USER_INTERACTIVE);
210         });
211     }
212 
213     looper_->AddFileDescriptorListener(fd_, AppExecFwk::FILE_DESCRIPTOR_INPUT_EVENT, listener_, "vSyncTask");
214     init_ = true;
215     return VSYNC_ERROR_OK;
216 }
217 
~VSyncReceiver()218 VSyncReceiver::~VSyncReceiver()
219 {
220     listener_->RegisterFdShutDownCallback(nullptr);
221     std::lock_guard<std::mutex> locker(initMutex_);
222     RemoveAndCloseFdLocked();
223     DestroyLocked();
224 }
225 
RemoveAndCloseFdLocked()226 void VSyncReceiver::RemoveAndCloseFdLocked()
227 {
228     if (looper_ != nullptr) {
229         looper_->RemoveFileDescriptorListener(fd_);
230         VLOGI("%{public}s looper remove fd listener, fd=%{public}d", __func__, fd_);
231     }
232 
233     std::lock_guard<std::mutex> locker(listener_->fdMutex_);
234     if (fd_ >= 0) {
235         close(fd_);
236         listener_->SetFdClosedFlagLocked(true);
237         fd_ = INVALID_FD;
238     }
239 }
240 
RequestNextVSync(FrameCallback callback)241 VsyncError VSyncReceiver::RequestNextVSync(FrameCallback callback)
242 {
243     return RequestNextVSync(callback, "unknown", 0);
244 }
245 
RequestNextVSync(FrameCallback callback,const std::string & fromWhom,int64_t lastVSyncTS)246 VsyncError VSyncReceiver::RequestNextVSync(FrameCallback callback, const std::string &fromWhom, int64_t lastVSyncTS)
247 {
248     std::lock_guard<std::mutex> locker(initMutex_);
249     if (!init_) {
250         VLOGE("%{public}s not init", __func__);
251         return VSYNC_ERROR_NOT_INIT;
252     }
253     listener_->SetCallback(callback);
254     listener_->SetRNVFlag(true);
255     ScopedDebugTrace func("VSyncReceiver::RequestNextVSync:" + name_);
256     if (OHOS::Rosen::RsFrameReportExt::GetInstance().GetEnable()) {
257         OHOS::Rosen::RsFrameReportExt::GetInstance().RequestNextVSync();
258     }
259     return connection_->RequestNextVSync(fromWhom, lastVSyncTS);
260 }
261 
RequestNextVSyncWithMultiCallback(FrameCallback callback)262 VsyncError VSyncReceiver::RequestNextVSyncWithMultiCallback(FrameCallback callback)
263 {
264     std::lock_guard<std::mutex> locker(initMutex_);
265     if (!init_) {
266         VLOGE("%{public}s not init", __func__);
267         return VSYNC_ERROR_NOT_INIT;
268     }
269     listener_->AddCallback(callback);
270     listener_->SetRNVFlag(true);
271     ScopedDebugTrace func("VSyncReceiver::RequestNextVSync:" + name_);
272     if (OHOS::Rosen::RsFrameReportExt::GetInstance().GetEnable()) {
273         OHOS::Rosen::RsFrameReportExt::GetInstance().RequestNextVSync();
274     }
275     return connection_->RequestNextVSync();
276 }
277 
SetVSyncRate(FrameCallback callback,int32_t rate)278 VsyncError VSyncReceiver::SetVSyncRate(FrameCallback callback, int32_t rate)
279 {
280     std::lock_guard<std::mutex> locker(initMutex_);
281     if (!init_) {
282         return VSYNC_ERROR_API_FAILED;
283     }
284     listener_->SetCallback(callback);
285     return connection_->SetVSyncRate(rate);
286 }
287 
288 /* 设置每帧回调 */
SetVsyncCallBackForEveryFrame(FrameCallback callback,bool isOpen)289 VsyncError VSyncReceiver::SetVsyncCallBackForEveryFrame(FrameCallback callback, bool isOpen)
290 {
291     if (isOpen) {
292         return SetVSyncRate(callback, 1);
293     } else {
294         return SetVSyncRate(callback, -1);
295     }
296 }
297 
GetVSyncPeriod(int64_t & period)298 VsyncError VSyncReceiver::GetVSyncPeriod(int64_t &period)
299 {
300     int64_t timeStamp;
301     return GetVSyncPeriodAndLastTimeStamp(period, timeStamp);
302 }
303 
GetVSyncPeriodAndLastTimeStamp(int64_t & period,int64_t & timeStamp,bool isThreadShared)304 VsyncError VSyncReceiver::GetVSyncPeriodAndLastTimeStamp(int64_t &period, int64_t &timeStamp, bool isThreadShared)
305 {
306     std::lock_guard<std::mutex> locker(initMutex_);
307     if (!init_) {
308         VLOGE("%{public}s not init", __func__);
309         return VSYNC_ERROR_NOT_INIT;
310     }
311     if (isThreadShared == false) {
312         int64_t periodNotShared = listener_->GetPeriod();
313         int64_t timeStampNotShared = listener_->GetTimeStamp();
314         if (periodNotShared == 0 || timeStampNotShared == 0) {
315             VLOGD("%{public}s Hardware vsync is not available. please try again later!", __func__);
316             return VSYNC_ERROR_UNKOWN;
317         }
318         period = periodNotShared;
319         timeStamp = timeStampNotShared;
320     } else {
321         int64_t periodShared = listener_->GetPeriodShared();
322         int64_t timeStampShared = listener_->GetTimeStampShared();
323         if (periodShared == 0 || timeStampShared == 0) {
324             VLOGD("%{public}s Hardware vsync is not available. please try again later!", __func__);
325             return VSYNC_ERROR_UNKOWN;
326         }
327         period = periodShared;
328         timeStamp = timeStampShared;
329     }
330     RS_TRACE_NAME_FMT("VSyncReceiver:period:%ld timeStamp:%ld isThreadShared:%d", period, timeStamp, isThreadShared);
331     return VSYNC_ERROR_OK;
332 }
333 
CloseVsyncReceiverFd()334 void VSyncReceiver::CloseVsyncReceiverFd()
335 {
336     std::lock_guard<std::mutex> locker(initMutex_);
337     RemoveAndCloseFdLocked();
338 }
339 
DestroyLocked()340 VsyncError VSyncReceiver::DestroyLocked()
341 {
342     if (connection_ == nullptr) {
343         return VSYNC_ERROR_API_FAILED;
344     }
345     return connection_->Destroy();
346 }
347 
IsRequestedNextVSync()348 bool VSyncReceiver::IsRequestedNextVSync()
349 {
350     std::lock_guard<std::mutex> locker(initMutex_);
351     if (!init_) {
352         return false;
353     }
354     return listener_->GetRNVFlag();
355 }
356 
SetUiDvsyncSwitch(bool dvsyncSwitch)357 VsyncError VSyncReceiver::SetUiDvsyncSwitch(bool dvsyncSwitch)
358 {
359     std::lock_guard<std::mutex> locker(initMutex_);
360     if (!init_) {
361         return VSYNC_ERROR_API_FAILED;
362     }
363     return connection_->SetUiDvsyncSwitch(dvsyncSwitch);
364 }
365 
SetUiDvsyncConfig(int32_t bufferCount)366 VsyncError VSyncReceiver::SetUiDvsyncConfig(int32_t bufferCount)
367 {
368     std::lock_guard<std::mutex> locker(initMutex_);
369     if (!init_) {
370         return VSYNC_ERROR_API_FAILED;
371     }
372     VLOGI("%{public}s bufferCount:%{public}d", __func__, bufferCount);
373     return connection_->SetUiDvsyncConfig(bufferCount);
374 }
375 
SetNativeDVSyncSwitch(bool dvsyncSwitch)376 VsyncError VSyncReceiver::SetNativeDVSyncSwitch(bool dvsyncSwitch)
377 {
378     std::lock_guard<std::mutex> locker(initMutex_);
379     if (!init_) {
380         return VSYNC_ERROR_API_FAILED;
381     }
382     return connection_->SetNativeDVSyncSwitch(dvsyncSwitch);
383 }
384 } // namespace Rosen
385 } // namespace OHOS
386