1 /*
2 * Copyright (c) 2023 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 "form_render_impl.h"
17
18 #include <cstddef>
19 #include <memory>
20
21 #include "event_handler.h"
22 #include "fms_log_wrapper.h"
23 #include "form_constants.h"
24 #include "form_render_event_report.h"
25 #include "form_render_service_extension.h"
26 #include "js_runtime.h"
27 #include "service_extension.h"
28 #include "form_memmgr_client.h"
29 #ifdef SUPPORT_POWER
30 #include "power_mgr_client.h"
31 #endif
32
33 namespace OHOS {
34 namespace AppExecFwk {
35 namespace FormRender {
36 namespace {
37 constexpr int32_t RENDER_FORM_FAILED = -1;
38 constexpr int32_t RELOAD_FORM_FAILED = -1;
39 constexpr int32_t RECYCLE_FORM_FAILED = -1;
40 constexpr int32_t SET_VISIBLE_CHANGE_FAILED = -1;
41 constexpr int32_t FORM_RENDER_TASK_DELAY_TIME = 20; // ms
42 constexpr int32_t ENABLE_FORM_FAILED = -1;
43 }
44 using namespace AbilityRuntime;
45 using namespace OHOS::AAFwk::GlobalConfigurationKey;
46
FormRenderServiceCreator(const std::unique_ptr<Runtime> & runtime)47 static OHOS::AbilityRuntime::ServiceExtension *FormRenderServiceCreator(const std::unique_ptr<Runtime> &runtime)
48 {
49 HILOG_DEBUG("Create FormRenderServiceExtension");
50 return FormRenderServiceExtension::Create(runtime);
51 }
52
RegisterServiceExtensionCreator()53 __attribute__((constructor)) void RegisterServiceExtensionCreator()
54 {
55 HILOG_DEBUG("Set FormRenderServiceExtension creator");
56 OHOS::AbilityRuntime::ServiceExtension::SetCreator(FormRenderServiceCreator);
57 }
58
FormRenderImpl()59 FormRenderImpl::FormRenderImpl()
60 {
61 const std::string queueName = "FormRenderSerialQueue";
62 serialQueue_ = std::make_shared<FormRenderSerialQueue>(queueName);
63 if (serialQueue_ == nullptr) {
64 HILOG_ERROR("null serialQueue_");
65 }
66 }
67
68 FormRenderImpl::~FormRenderImpl() = default;
69
RenderForm(const FormJsInfo & formJsInfo,const Want & want,sptr<IRemoteObject> callerToken)70 int32_t FormRenderImpl::RenderForm(const FormJsInfo &formJsInfo, const Want &want,
71 sptr<IRemoteObject> callerToken)
72 {
73 HILOG_INFO("Render form,bundleName=%{public}s,abilityName=%{public}s,formName=%{public}s,"
74 "moduleName=%{public}s,jsFormCodePath=%{public}s,formSrc=%{public}s,formId=%{public}" PRId64,
75 formJsInfo.bundleName.c_str(), formJsInfo.abilityName.c_str(), formJsInfo.formName.c_str(),
76 formJsInfo.moduleName.c_str(), formJsInfo.jsFormCodePath.c_str(), formJsInfo.formSrc.c_str(),
77 formJsInfo.formId);
78
79 sptr<IFormSupply> formSupplyClient = iface_cast<IFormSupply>(callerToken);
80 if (formSupplyClient == nullptr) {
81 HILOG_ERROR("null IFormSupply");
82 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
83 }
84 {
85 std::lock_guard<std::mutex> lock(formSupplyMutex_);
86 formSupplyClient_ = formSupplyClient;
87 }
88 HILOG_DEBUG("connectId:%{public}d",
89 want.GetIntParam(Constants::FORM_CONNECT_ID, 0L));
90
91 std::string uid = want.GetStringParam(Constants::FORM_SUPPLY_UID);
92 if (uid.empty()) {
93 HILOG_ERROR("GetUid failed");
94 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
95 }
96 int32_t result = ERR_OK;
97 Want formRenderWant(want);
98 sptr<IRemoteObject> hostToken = formRenderWant.GetRemoteObject(Constants::PARAM_FORM_HOST_TOKEN);
99 {
100 std::lock_guard<std::mutex> lock(renderRecordMutex_);
101 ConfirmUnlockState(formRenderWant);
102 if (auto search = renderRecordMap_.find(uid); search != renderRecordMap_.end()) {
103 result = search->second->UpdateRenderRecord(formJsInfo, formRenderWant, hostToken);
104 } else {
105 auto record = FormRenderRecord::Create(formJsInfo.bundleName, uid, formJsInfo.isDynamic, formSupplyClient);
106 if (record == nullptr) {
107 HILOG_ERROR("null record");
108 return RENDER_FORM_FAILED;
109 }
110
111 record->SetConfiguration(configuration_);
112 result = record->UpdateRenderRecord(formJsInfo, formRenderWant, hostToken);
113 if (renderRecordMap_.empty()) {
114 FormMemmgrClient::GetInstance().SetCritical(true);
115 }
116 renderRecordMap_.emplace(uid, record);
117 FormRenderGCTask(uid);
118 }
119 }
120 formSupplyClient->OnRenderTaskDone(formJsInfo.formId, formRenderWant);
121 return result;
122 }
123
StopRenderingForm(const FormJsInfo & formJsInfo,const Want & want,const sptr<IRemoteObject> & callerToken)124 int32_t FormRenderImpl::StopRenderingForm(const FormJsInfo &formJsInfo, const Want &want,
125 const sptr<IRemoteObject> &callerToken)
126 {
127 HILOG_INFO("call");
128 sptr<IFormSupply> formSupplyClient = iface_cast<IFormSupply>(callerToken);
129 if (formSupplyClient == nullptr) {
130 HILOG_ERROR("null IFormSupply");
131 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
132 }
133
134 std::string uid = want.GetStringParam(Constants::FORM_SUPPLY_UID);
135 if (uid.empty()) {
136 HILOG_ERROR("GetUid failed");
137 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
138 }
139
140 bool isRenderGroupEmpty = false;
141 sptr<IRemoteObject> hostToken = want.GetRemoteObject(Constants::PARAM_FORM_HOST_TOKEN);
142 {
143 std::lock_guard<std::mutex> lock(renderRecordMutex_);
144 auto search = renderRecordMap_.find(uid);
145 if (search == renderRecordMap_.end()) {
146 HILOG_ERROR("fail");
147 return RENDER_FORM_FAILED;
148 }
149
150 if (!search->second) {
151 HILOG_ERROR("fail");
152 return RENDER_FORM_FAILED;
153 }
154
155 std::string compId = want.GetStringParam(Constants::FORM_RENDER_COMP_ID);
156 search->second->DeleteRenderRecord(formJsInfo.formId, compId, hostToken, isRenderGroupEmpty);
157 if (search->second->IsEmpty()) {
158 renderRecordMap_.erase(search);
159 HILOG_INFO("DeleteRenderRecord success,uid:%{public}s", uid.c_str());
160 if (renderRecordMap_.empty()) {
161 FormMemmgrClient::GetInstance().SetCritical(false);
162 }
163 }
164 }
165
166 HILOG_INFO("connectId:%{public}d",
167 want.GetIntParam(Constants::FORM_CONNECT_ID, 0L));
168 if (isRenderGroupEmpty) {
169 formSupplyClient->OnStopRenderingTaskDone(formJsInfo.formId, want);
170 }
171
172 return ERR_OK;
173 }
174
ReleaseRenderer(int64_t formId,const std::string & compId,const std::string & uid)175 int32_t FormRenderImpl::ReleaseRenderer(int64_t formId, const std::string &compId, const std::string &uid)
176 {
177 HILOG_INFO("formId:%{public}" PRId64 ",compId:%{public}s,uid:%{public}s", formId, compId.c_str(), uid.c_str());
178 if (formId <= 0 || compId.empty() || uid.empty()) {
179 HILOG_ERROR("param invalid");
180 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
181 }
182
183 std::lock_guard<std::mutex> lock(renderRecordMutex_);
184 bool isRenderGroupEmpty = false;
185 auto search = renderRecordMap_.find(uid);
186 if (search == renderRecordMap_.end()) {
187 HILOG_ERROR("invalid record,formId:%{public}" PRId64, formId);
188 return RENDER_FORM_FAILED;
189 }
190
191 if (!search->second) {
192 HILOG_ERROR("record invalid,formId:%{public}" PRId64, formId);
193 return RENDER_FORM_FAILED;
194 }
195
196 search->second->ReleaseRenderer(formId, compId, isRenderGroupEmpty);
197 HILOG_INFO("end,isRenderGroupEmpty:%{public}d", isRenderGroupEmpty);
198 if (isRenderGroupEmpty) {
199 search->second->Release();
200 }
201
202 return ERR_OK;
203 }
204
CleanFormHost(const sptr<IRemoteObject> & hostToken)205 int32_t FormRenderImpl::CleanFormHost(const sptr<IRemoteObject> &hostToken)
206 {
207 HILOG_INFO("Form host is died,clean renderRecord");
208 std::lock_guard<std::mutex> lock(renderRecordMutex_);
209 for (auto iter = renderRecordMap_.begin(); iter != renderRecordMap_.end();) {
210 auto renderRecord = iter->second;
211 if (renderRecord && renderRecord->HandleHostDied(hostToken)) {
212 HILOG_DEBUG("empty renderRecord,remove");
213 iter = renderRecordMap_.erase(iter);
214 } else {
215 ++iter;
216 }
217 }
218 if (renderRecordMap_.empty()) {
219 HILOG_INFO("empty renderRecordMap_,FormRenderService will exit later");
220 FormMemmgrClient::GetInstance().SetCritical(false);
221 }
222 return ERR_OK;
223 }
224
ReloadForm(const std::vector<FormJsInfo> && formJsInfos,const Want & want)225 int32_t FormRenderImpl::ReloadForm(const std::vector<FormJsInfo> &&formJsInfos, const Want &want)
226 {
227 HILOG_INFO("ReloadForm start");
228 std::lock_guard<std::mutex> lock(renderRecordMutex_);
229 std::string uid = want.GetStringParam(Constants::FORM_SUPPLY_UID);
230 if (uid.empty()) {
231 HILOG_ERROR("Get uid failed");
232 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
233 }
234 auto search = renderRecordMap_.find(uid);
235 if (search == renderRecordMap_.end()) {
236 HILOG_ERROR("RenderRecord not find");
237 return RELOAD_FORM_FAILED;
238 }
239 if (search->second) {
240 search->second->ReloadFormRecord(std::forward<decltype(formJsInfos)>(formJsInfos), want);
241 }
242 return ERR_OK;
243 }
244
OnUnlock()245 int32_t FormRenderImpl::OnUnlock()
246 {
247 HILOG_INFO("OnUnlock start");
248 std::lock_guard<std::mutex> lock(renderRecordMutex_);
249 if (isVerified_) {
250 HILOG_WARN("Has been unlocked in render form, maybe miss or delay unlock event");
251 return ERR_OK;
252 }
253
254 isVerified_ = true;
255 for (const auto& iter : renderRecordMap_) {
256 if (iter.second) {
257 iter.second->OnUnlock();
258 }
259 }
260 return ERR_OK;
261 }
262
SetVisibleChange(const int64_t & formId,bool isVisible,const Want & want)263 int32_t FormRenderImpl::SetVisibleChange(const int64_t &formId, bool isVisible, const Want &want)
264 {
265 HILOG_INFO("SetVisibleChange start");
266 if (formId <= 0) {
267 HILOG_ERROR("formId is negative");
268 return ERR_APPEXECFWK_FORM_INVALID_FORM_ID;
269 }
270
271 std::string uid = want.GetStringParam(Constants::FORM_SUPPLY_UID);
272 if (uid.empty()) {
273 HILOG_ERROR("empty uid,formId:%{public}" PRId64, formId);
274 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
275 }
276 HILOG_INFO("formId:%{public}" PRId64 ",uid:%{public}s", formId, uid.c_str());
277
278 std::lock_guard<std::mutex> lock(renderRecordMutex_);
279 if (auto search = renderRecordMap_.find(uid); search != renderRecordMap_.end()) {
280 if (search->second == nullptr) {
281 HILOG_ERROR("null renderRecord of %{public}s", std::to_string(formId).c_str());
282 return SET_VISIBLE_CHANGE_FAILED;
283 }
284 auto ret = search->second->SetVisibleChange(formId, isVisible);
285 if (ret != ERR_OK) {
286 return ret;
287 }
288 } else {
289 HILOG_ERROR("can't find render record of %{public}s", std::to_string(formId).c_str());
290 return SET_VISIBLE_CHANGE_FAILED;
291 }
292 return ERR_OK;
293 }
294
OnConfigurationUpdated(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & configuration)295 void FormRenderImpl::OnConfigurationUpdated(
296 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& configuration)
297 {
298 HILOG_DEBUG("OnConfigurationUpdated start");
299 std::lock_guard<std::mutex> lock(renderRecordMutex_);
300 if (!configuration) {
301 HILOG_ERROR("null configuration");
302 return;
303 }
304
305 SetConfiguration(configuration);
306
307 #ifdef SUPPORT_POWER
308 bool screenOnFlag = PowerMgr::PowerMgrClient::GetInstance().IsScreenOn();
309 bool collaborationScreenOnFlag = PowerMgr::PowerMgrClient::GetInstance().IsCollaborationScreenOn();
310 if (!screenOnFlag && !collaborationScreenOnFlag) {
311 HILOG_WARN("screen off");
312 hasCachedConfig_ = true;
313 return;
314 }
315 #endif
316
317 constexpr int64_t minDurationMs = 1500;
318 const std::string taskName = "FormRenderImpl::OnConfigurationUpdated";
319 serialQueue_->CancelDelayTask(taskName);
320 auto duration = std::chrono::steady_clock::now() - configUpdateTime_;
321 if (std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() < minDurationMs) {
322 HILOG_INFO("OnConfigurationUpdated ignored");
323 auto configUpdateFunc = [this]() {
324 HILOG_INFO("OnConfigurationUpdated task run");
325 this->OnConfigurationUpdatedInner();
326 };
327 constexpr int64_t taskDelayMs = 1000;
328 serialQueue_->ScheduleDelayTask(taskName, taskDelayMs, configUpdateFunc);
329 return;
330 }
331 OnConfigurationUpdatedInner();
332 }
333
OnConfigurationUpdatedInner()334 void FormRenderImpl::OnConfigurationUpdatedInner()
335 {
336 sptr<IFormSupply> formSupplyClient = nullptr;
337 {
338 std::lock_guard<std::mutex> lock(formSupplyMutex_);
339 formSupplyClient = formSupplyClient_;
340 }
341 if (formSupplyClient == nullptr) {
342 HILOG_ERROR("null formSupplyClient");
343 }
344
345 configUpdateTime_ = std::chrono::steady_clock::now();
346 size_t allFormCount = 0;
347 for (auto iter = renderRecordMap_.begin(); iter != renderRecordMap_.end(); ++iter) {
348 if (iter->second) {
349 iter->second->UpdateConfiguration(configuration_, formSupplyClient);
350 allFormCount += iter->second->FormCount();
351 }
352 }
353 HILOG_INFO("OnConfigurationUpdated %{public}zu forms updated.", allFormCount);
354 hasCachedConfig_ = false;
355 PerformanceEventInfo eventInfo;
356 eventInfo.timeStamp = FormRenderEventReport::GetNowMillisecond();
357 eventInfo.bundleName = Constants::FRS_BUNDLE_NAME;
358 eventInfo.sceneId = Constants::CPU_SCENE_ID_CONFIG_UPDATE;
359 FormRenderEventReport::SendPerformanceEvent(SceneType::CPU_SCENE_ENTRY, eventInfo);
360 }
361
SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)362 void FormRenderImpl::SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
363 {
364 if (config != nullptr && configuration_ != nullptr) {
365 std::string colorMode = config->GetItem(SYSTEM_COLORMODE);
366 std::string languageTag = config->GetItem(SYSTEM_LANGUAGE);
367 std::string colorModeOld = configuration_->GetItem(SYSTEM_COLORMODE);
368 std::string languageTagOld = configuration_->GetItem(SYSTEM_LANGUAGE);
369 configuration_ = config;
370 if (colorMode.empty()) {
371 configuration_->AddItem(SYSTEM_COLORMODE, colorModeOld);
372 }
373 if (languageTag.empty()) {
374 configuration_->AddItem(SYSTEM_LANGUAGE, languageTagOld);
375 }
376 return;
377 }
378
379 configuration_ = config;
380 }
381
RunCachedConfigurationUpdated()382 void FormRenderImpl::RunCachedConfigurationUpdated()
383 {
384 HILOG_INFO("RunCachedConfigUpdated");
385 std::lock_guard<std::mutex> lock(renderRecordMutex_);
386 if (hasCachedConfig_) {
387 OnConfigurationUpdatedInner();
388 }
389 }
390
FormRenderGCTask(const std::string & uid)391 void FormRenderImpl::FormRenderGCTask(const std::string &uid)
392 {
393 auto mainHandler = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
394 if (mainHandler == nullptr) {
395 HILOG_ERROR("null mainHandler");
396 return;
397 }
398 auto formRenderGCFunc = [uid]() {
399 auto formRenderImpl = OHOS::DelayedSingleton<FormRenderImpl>::GetInstance();
400 if (formRenderImpl == nullptr) {
401 HILOG_ERROR("null formRenderImpl");
402 return;
403 }
404 formRenderImpl->FormRenderGC(uid);
405 };
406 mainHandler->PostTask(formRenderGCFunc, "FormRenderGC", FORM_RENDER_TASK_DELAY_TIME);
407 }
408
FormRenderGC(const std::string & uid)409 void FormRenderImpl::FormRenderGC(const std::string &uid)
410 {
411 HILOG_INFO("form gc, uid is %{s}public", uid.c_str());
412 std::lock_guard<std::mutex> lock(renderRecordMutex_);
413 if (auto search = renderRecordMap_.find(uid); search != renderRecordMap_.end()) {
414 search->second->FormRenderGC();
415 }
416 }
417
RecycleForm(const int64_t & formId,const Want & want)418 int32_t FormRenderImpl::RecycleForm(const int64_t &formId, const Want &want)
419 {
420 if (formId <= 0) {
421 HILOG_ERROR("formId is negative");
422 return ERR_APPEXECFWK_FORM_INVALID_FORM_ID;
423 }
424
425 std::string uid = want.GetStringParam(Constants::FORM_SUPPLY_UID);
426 if (uid.empty()) {
427 HILOG_ERROR("empty uid,formId:%{public}" PRId64, formId);
428 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
429 }
430 HILOG_INFO("formId:%{public}" PRId64 ",uid:%{public}s", formId, uid.c_str());
431
432 std::string statusData;
433 {
434 std::lock_guard<std::mutex> lock(renderRecordMutex_);
435 if (auto search = renderRecordMap_.find(uid); search != renderRecordMap_.end()) {
436 if (search->second == nullptr) {
437 HILOG_ERROR("null renderRecord of %{public}s", std::to_string(formId).c_str());
438 return RECYCLE_FORM_FAILED;
439 }
440 auto ret = search->second->RecycleForm(formId, statusData);
441 if (ret != ERR_OK) {
442 return ret;
443 }
444 } else {
445 HILOG_ERROR("can't find render record of %{public}s", std::to_string(formId).c_str());
446 return RECYCLE_FORM_FAILED;
447 }
448 if (statusData.empty()) {
449 HILOG_WARN("empty statusData of %{public}s", std::to_string(formId).c_str());
450 }
451 }
452
453 sptr<IFormSupply> formSupplyClient = nullptr;
454 {
455 std::lock_guard<std::mutex> lock(formSupplyMutex_);
456 formSupplyClient = formSupplyClient_;
457 }
458 if (formSupplyClient == nullptr) {
459 HILOG_ERROR("null formSupplyClient, formId:%{public}" PRId64, formId);
460 return RECYCLE_FORM_FAILED;
461 }
462
463 Want newWant = want;
464 newWant.SetParam(Constants::FORM_STATUS_DATA, statusData);
465 formSupplyClient->OnRecycleForm(formId, newWant);
466 return ERR_OK;
467 }
468
RecoverForm(const FormJsInfo & formJsInfo,const Want & want)469 int32_t FormRenderImpl::RecoverForm(const FormJsInfo &formJsInfo, const Want &want)
470 {
471 auto formId = formJsInfo.formId;
472 if (formId <= 0) {
473 HILOG_ERROR("formId is negative");
474 return ERR_APPEXECFWK_FORM_INVALID_FORM_ID;
475 }
476
477 std::string uid = want.GetStringParam(Constants::FORM_SUPPLY_UID);
478 if (uid.empty()) {
479 HILOG_ERROR("empty uid,formId:%{public}" PRId64, formId);
480 return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED;
481 }
482 HILOG_INFO("formId:%{public}" PRId64 ", connectId:%{public}d, uid:%{public}s",
483 formId, want.GetIntParam(Constants::FORM_CONNECT_ID, 0L), uid.c_str());
484
485 std::string statusData = want.GetStringParam(Constants::FORM_STATUS_DATA);
486 if (statusData.empty()) {
487 HILOG_WARN("empty statusData of %{public}s", std::to_string(formId).c_str());
488 }
489
490 bool isRecoverFormToHandleClickEvent = want.GetBoolParam(
491 Constants::FORM_IS_RECOVER_FORM_TO_HANDLE_CLICK_EVENT, false);
492 std::lock_guard<std::mutex> lock(renderRecordMutex_);
493 if (auto search = renderRecordMap_.find(uid); search != renderRecordMap_.end()) {
494 if (search->second == nullptr) {
495 HILOG_ERROR("null renderRecord of %{public}s", std::to_string(formId).c_str());
496 return RECYCLE_FORM_FAILED;
497 }
498 return search->second->RecoverForm(formJsInfo, statusData, isRecoverFormToHandleClickEvent);
499 }
500 HILOG_ERROR("can't find render record of %{public}s", std::to_string(formId).c_str());
501 return RENDER_FORM_FAILED;
502 }
503
ConfirmUnlockState(Want & renderWant)504 void FormRenderImpl::ConfirmUnlockState(Want &renderWant)
505 {
506 // Ensure that there are no issues with adding form and unlocking drawing concurrency
507 if (isVerified_) {
508 renderWant.SetParam(Constants::FORM_RENDER_STATE, true);
509 } else if (renderWant.GetBoolParam(Constants::FORM_RENDER_STATE, false)) {
510 HILOG_WARN("Maybe unlock event is missed or delayed, all form record begin to render");
511 isVerified_ = true;
512 for (const auto& iter : renderRecordMap_) {
513 if (iter.second) {
514 iter.second->OnUnlock();
515 }
516 }
517 }
518 }
519 } // namespace FormRender
520 } // namespace AppExecFwk
521 } // namespace OHOS
522