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