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