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