1 /*
2 * Copyright (c) 2022 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_adapter_impl.h"
17
18 #include "aafwk_browser_client_adapter_impl.h"
19 #include "nweb_log.h"
20 #include "res_sched_client_adapter.h"
21 #include "system_properties_adapter_impl.h"
22 #include "transaction/rs_interfaces.h"
23
24 namespace OHOS::NWeb {
25 namespace {
26 const std::string THREAD_NAME = "VSync-webview";
27 constexpr int32_t WEBVIEW_FRAME_RATE_TYPE = 4;
28 }
29
30 void (*VSyncAdapterImpl::callback_)() = nullptr;
31 void (*VSyncAdapterImpl::onVsyncEndCallback_)() = nullptr;
32
~VSyncAdapterImpl()33 VSyncAdapterImpl::~VSyncAdapterImpl()
34 {
35 if (vsyncHandler_) {
36 vsyncHandler_->RemoveAllEvents();
37 auto runner = vsyncHandler_->GetEventRunner();
38 if (runner) {
39 runner->Stop();
40 ResSchedClientAdapter::ReportKeyThread(ResSchedStatusAdapter::THREAD_DESTROYED,
41 getprocpid(), runner->GetKernelThreadId(), ResSchedRoleAdapter::USER_INTERACT);
42 }
43 vsyncHandler_ = nullptr;
44 }
45 hasReportedKeyThread_ = false;
46 }
47
GetInstance()48 VSyncAdapterImpl& VSyncAdapterImpl::GetInstance()
49 {
50 static VSyncAdapterImpl instance;
51 return instance;
52 }
53
Init()54 VSyncErrorCode VSyncAdapterImpl::Init()
55 {
56 if (!receiver_) {
57 if (!vsyncHandler_) {
58 std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create(THREAD_NAME);
59 vsyncHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
60 runner->Run();
61 }
62 auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
63 frameRateLinker_ = OHOS::Rosen::RSFrameRateLinker::Create();
64 receiver_ = rsClient.CreateVSyncReceiver("NWeb_" + std::to_string(::getprocpid()),
65 frameRateLinker_->GetId(), vsyncHandler_);
66 if (!receiver_) {
67 WVLOG_E("CreateVSyncReceiver failed");
68 return VSyncErrorCode::ERROR;
69 }
70 VsyncError ret = receiver_->Init();
71 if (ret != VsyncError::GSERROR_OK) {
72 receiver_ = nullptr;
73 WVLOG_E("vsync receiver init failed, ret=%{public}d", ret);
74 return VSyncErrorCode::ERROR;
75 }
76 }
77 return VSyncErrorCode::SUCCESS;
78 }
79
RequestVsync(void * data,NWebVSyncCb cb)80 VSyncErrorCode VSyncAdapterImpl::RequestVsync(void* data, NWebVSyncCb cb)
81 {
82 if (Init() != VSyncErrorCode::SUCCESS) {
83 WVLOG_E("NWebWindowAdapter init fail");
84 return VSyncErrorCode::ERROR;
85 }
86
87 if (!hasReportedKeyThread_) {
88 auto runner = vsyncHandler_->GetEventRunner();
89 // At this point, the threadId corresponding to eventrunner may not be available,
90 // so need to confirm it several times
91 if (runner && runner->GetKernelThreadId() != 0) {
92 if (!isGPUProcess_) {
93 ResSchedClientAdapter::ReportKeyThread(ResSchedStatusAdapter::THREAD_CREATED,
94 getprocpid(), runner->GetKernelThreadId(), ResSchedRoleAdapter::USER_INTERACT);
95 } else {
96 AafwkBrowserClientAdapterImpl::GetInstance().ReportThread(ResSchedStatusAdapter::THREAD_CREATED,
97 getprocpid(), runner->GetKernelThreadId(), ResSchedRoleAdapter::USER_INTERACT);
98 }
99 hasReportedKeyThread_ = true;
100 }
101 }
102
103 std::lock_guard<std::mutex> lock(mtx_);
104 vsyncCallbacks_.insert({data, cb});
105
106 if (hasRequestedVsync_) {
107 return VSyncErrorCode::SUCCESS;
108 }
109
110 VsyncError ret = receiver_->RequestNextVSync(frameCallback_);
111 if (ret != VsyncError::GSERROR_OK) {
112 WVLOG_E("NWebWindowAdapter RequestNextVSync fail, ret=%{public}d", ret);
113 return VSyncErrorCode::ERROR;
114 }
115 hasRequestedVsync_ = true;
116 return VSyncErrorCode::SUCCESS;
117 }
118
OnVsync(int64_t timestamp,void * client)119 void VSyncAdapterImpl::OnVsync(int64_t timestamp, void* client)
120 {
121 auto vsyncClient = static_cast<VSyncAdapterImpl*>(client);
122 if (vsyncClient) {
123 if (callback_) {
124 callback_();
125 }
126 vsyncClient->VsyncCallbackInner(timestamp);
127 if (onVsyncEndCallback_) {
128 onVsyncEndCallback_();
129 }
130 } else {
131 WVLOG_E("VsyncClient is null");
132 }
133 }
134
VsyncCallbackInner(int64_t timestamp)135 void VSyncAdapterImpl::VsyncCallbackInner(int64_t timestamp)
136 {
137 std::unordered_map<void*, NWebVSyncCb> vsyncCallbacks;
138 std::lock_guard<std::mutex> lock(mtx_);
139 vsyncCallbacks = vsyncCallbacks_;
140 vsyncCallbacks_.clear();
141
142 for (const auto& callback : vsyncCallbacks) {
143 auto func = callback.second;
144 if (func) {
145 func(timestamp, callback.first);
146 }
147 }
148 hasRequestedVsync_ = false;
149 }
150
GetVSyncPeriod()151 int64_t VSyncAdapterImpl::GetVSyncPeriod()
152 {
153 int64_t period = 0;
154 if (Init() != VSyncErrorCode::SUCCESS) {
155 WVLOG_E("NWebWindowAdapter init fail");
156 return period;
157 }
158
159 VsyncError ret = receiver_->GetVSyncPeriod(period);
160 if (ret != VsyncError::GSERROR_OK) {
161 WVLOG_E("NWebWindowAdapter GetVSyncPeriod fail, ret=%{public}d", ret);
162 }
163 return period;
164 }
165
SetFrameRateLinkerEnable(bool enabled)166 void VSyncAdapterImpl::SetFrameRateLinkerEnable(bool enabled)
167 {
168 WVLOG_D("NWebWindowAdapter SetFrameRateLinkerEnable enabled=%{public}d", enabled);
169 if (frameRateLinkerEnable_ == enabled) {
170 return;
171 }
172
173 if (frameRateLinker_) {
174 if (!enabled) {
175 Rosen::FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, 0, WEBVIEW_FRAME_RATE_TYPE};
176 frameRateLinker_->UpdateFrameRateRangeImme(range);
177 }
178 frameRateLinker_->SetEnable(enabled);
179 frameRateLinkerEnable_ = enabled;
180 }
181 }
182
SetFramePreferredRate(int32_t preferredRate)183 void VSyncAdapterImpl::SetFramePreferredRate(int32_t preferredRate)
184 {
185 Rosen::FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, preferredRate, WEBVIEW_FRAME_RATE_TYPE};
186 if (frameRateLinker_ && frameRateLinker_->IsEnable()) {
187 WVLOG_D("NWebWindowAdapter SetFramePreferredRate preferredRate=%{public}d", preferredRate);
188 frameRateLinker_->UpdateFrameRateRangeImme(range);
189 }
190 }
191
SetOnVsyncCallback(void (* callback)())192 void VSyncAdapterImpl::SetOnVsyncCallback(void (*callback)())
193 {
194 WVLOG_D("callback function: %{public}ld", (long)callback);
195 callback_ = callback;
196 }
197
SetOnVsyncEndCallback(void (* onVsyncEndCallback)())198 void VSyncAdapterImpl::SetOnVsyncEndCallback(void (*onVsyncEndCallback)())
199 {
200 WVLOG_D("onVsyncEndCallback function: %{public}ld", (long)onVsyncEndCallback);
201 onVsyncEndCallback_ = onVsyncEndCallback;
202 }
203
SetIsGPUProcess(bool isGPU)204 void VSyncAdapterImpl::SetIsGPUProcess(bool isGPU)
205 {
206 isGPUProcess_ = isGPU;
207 }
208 } // namespace OHOS::NWeb
209