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