• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <dlfcn.h>
19 
20 #include "aafwk_browser_client_adapter_impl.h"
21 #include "application_context.h"
22 #include "nweb_log.h"
23 #include "res_sched_client_adapter.h"
24 #include "system_properties_adapter_impl.h"
25 #include "transaction/rs_interfaces.h"
26 #include "../../../ohos_nweb/include/nweb_config_helper.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 const std::string APS_CLIENT_SO = "/system/lib64/libaps_client.z.so";
33 }
34 
35 void (*VSyncAdapterImpl::callback_)() = nullptr;
36 void (*VSyncAdapterImpl::onVsyncEndCallback_)() = nullptr;
37 
~VSyncAdapterImpl()38 VSyncAdapterImpl::~VSyncAdapterImpl()
39 {
40     if (vsyncHandler_) {
41         UninitAPSClient();
42         vsyncHandler_->RemoveAllEvents();
43         auto runner = vsyncHandler_->GetEventRunner();
44         if (runner) {
45             runner->Stop();
46             ResSchedClientAdapter::ReportKeyThread(ResSchedStatusAdapter::THREAD_DESTROYED,
47                 getprocpid(), runner->GetKernelThreadId(), ResSchedRoleAdapter::USER_INTERACT);
48         }
49         vsyncHandler_ = nullptr;
50     }
51     hasReportedKeyThread_ = false;
52 }
53 
GetInstance()54 VSyncAdapterImpl& VSyncAdapterImpl::GetInstance()
55 {
56     static VSyncAdapterImpl instance;
57     return instance;
58 }
59 
Init()60 VSyncErrorCode VSyncAdapterImpl::Init()
61 {
62     if (!receiver_) {
63         if (!vsyncHandler_) {
64             std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create(THREAD_NAME);
65             vsyncHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
66             runner->Run();
67         }
68         auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
69         frameRateLinker_ = OHOS::Rosen::RSFrameRateLinker::Create();
70         receiver_ = rsClient.CreateVSyncReceiver("NWeb_" + std::to_string(::getprocpid()),
71             frameRateLinker_->GetId(), vsyncHandler_);
72         if (!receiver_) {
73             WVLOG_E("CreateVSyncReceiver failed");
74             return VSyncErrorCode::ERROR;
75         }
76         VsyncError ret = receiver_->Init();
77         if (ret != VsyncError::GSERROR_OK) {
78             receiver_ = nullptr;
79             WVLOG_E("vsync receiver init failed, ret=%{public}d", ret);
80             return VSyncErrorCode::ERROR;
81         }
82         InitAPSClient();
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 
SetOnVsyncEndCallback(void (* onVsyncEndCallback)())205 void VSyncAdapterImpl::SetOnVsyncEndCallback(void (*onVsyncEndCallback)())
206 {
207     WVLOG_D("onVsyncEndCallback function: %{public}ld", (long)onVsyncEndCallback);
208     onVsyncEndCallback_ = onVsyncEndCallback;
209 }
210 
SetIsGPUProcess(bool isGPU)211 void VSyncAdapterImpl::SetIsGPUProcess(bool isGPU)
212 {
213     isGPUProcess_ = isGPU;
214 }
215 
SetScene(const std::string & sceneName,uint32_t state)216 void VSyncAdapterImpl::SetScene(const std::string& sceneName, uint32_t state)
217 {
218     WVLOG_D("APSManagerAdapterImpl SetScene sceneName=%{public}s state=%{public}u", sceneName.c_str(), state);
219     if (pkgName_.empty()) {
220         auto appInfo = AbilityRuntime::ApplicationContext::GetInstance()->GetApplicationInfo();
221         if (appInfo != nullptr) {
222             pkgName_ = appInfo->bundleName.c_str();
223         }
224     }
225     if (setApsSceneFunc_) {
226         setApsSceneFunc_(pkgName_, sceneName, state);
227     }
228 }
229 
InitAPSClient()230 void VSyncAdapterImpl::InitAPSClient()
231 {
232     apsClientHandler_ = dlopen(APS_CLIENT_SO.c_str(), RTLD_NOW);
233     if (!apsClientHandler_) {
234         WVLOG_E("APSManagerClient not found");
235         return;
236     }
237     setApsSceneFunc_ = reinterpret_cast<SetApsSceneFuncType>(dlsym(apsClientHandler_, "SetApsScene"));
238     if (!setApsSceneFunc_) {
239         WVLOG_E("APSManagerClient not found");
240         dlclose(apsClientHandler_);
241     }
242 }
243 
UninitAPSClient()244 void VSyncAdapterImpl::UninitAPSClient()
245 {
246     if (setApsSceneFunc_) {
247         dlclose(apsClientHandler_);
248         setApsSceneFunc_ = nullptr;
249         apsClientHandler_ = nullptr;
250     }
251 }
252 
SetDVSyncSwitch(bool dvsyncSwitch)253 void VSyncAdapterImpl::SetDVSyncSwitch(bool dvsyncSwitch)
254 {
255     if (Init() != VSyncErrorCode::SUCCESS) {
256         WVLOG_E("NWebWindowAdatrper init fail!");
257         return;
258     }
259 
260     if (!receiver_) {
261         WVLOG_E("NWebWindowAdatrper SetDVSyncSwitch: receiver_ is nullptr!");
262         return;
263     } else if (OHOS::NWeb::SystemPropertiesAdapterImpl::GetInstance().GetBoolParameter("web.dvsync.enabled", false)) {
264         WVLOG_D("NWebWindowAdatrper SetDVSyncSwitch: dvsyncSwitch = %{public}d", dvsyncSwitch);
265         VsyncError ret = receiver_->SetNativeDVSyncSwitch(dvsyncSwitch);
266         if (ret != VsyncError::GSERROR_OK) {
267             WVLOG_E("SetNativeDVSyncSwitch failed, ret = %{public}d", ret);
268             return;
269         }
270     } else {
271         WVLOG_D("NWebWindowAdatrper SetDVSyncSwitch Disabled!");
272     }
273 }
274 } // namespace OHOS::NWeb
275