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_record.h"
17
18 #include <chrono>
19 #include <cstdio>
20 #include <iostream>
21 #include <securec.h>
22 #include <string>
23 #include <thread>
24 #include <unistd.h>
25 #include <utility>
26
27 #include "ecmascript/napi/include/jsnapi.h"
28 #include "extractor.h"
29 #include "fms_log_wrapper.h"
30 #include "form_constants.h"
31 #include "form_memory_guard.h"
32 #include "form_module_checker.h"
33 #include "form_render_event_report.h"
34 #include "nlohmann/json.hpp"
35 #include "xcollie/watchdog.h"
36
37 using namespace OHOS::AAFwk::GlobalConfigurationKey;
38
39 namespace OHOS {
40 namespace AppExecFwk {
41 namespace FormRender {
42 constexpr int32_t RENDER_FORM_FAILED = -1;
43 constexpr int32_t RELOAD_FORM_FAILED = -1;
44 constexpr int32_t RECYCLE_FORM_FAILED = -1;
45 constexpr int32_t SET_VISIBLE_CHANGE_FAILED = -1;
46 constexpr int32_t TIMEOUT = 10 * 1000;
47 constexpr int32_t CHECK_THREAD_TIME = 3;
48 constexpr char FORM_RENDERER_COMP_ID[] = "ohos.extra.param.key.form_comp_id";
49 namespace {
GetCurrentTickMillseconds()50 uint64_t GetCurrentTickMillseconds()
51 {
52 return std::chrono::duration_cast<std::chrono::milliseconds>(
53 std::chrono::steady_clock::now().time_since_epoch()).count();
54 }
55 }
56
ThreadState(int32_t maxState)57 ThreadState::ThreadState(int32_t maxState) : maxState_(maxState) {}
58
ResetState()59 void ThreadState::ResetState()
60 {
61 state_ = 0;
62 }
63
NextState()64 void ThreadState::NextState()
65 {
66 state_++;
67 }
68
GetCurrentState()69 int32_t ThreadState::GetCurrentState()
70 {
71 return state_;
72 }
73
IsMaxState()74 bool ThreadState::IsMaxState()
75 {
76 return state_ >= maxState_;
77 }
78
Dump(const std::string & message)79 void HandlerDumper::Dump(const std::string &message)
80 {
81 HILOG_INFO("Message=%{public}s", message.c_str());
82 dumpInfo_ += message;
83 }
84
GetTag()85 std::string HandlerDumper::GetTag()
86 {
87 return "";
88 }
89
GetDumpInfo()90 std::string HandlerDumper::GetDumpInfo()
91 {
92 return dumpInfo_;
93 }
94
Create(const std::string & bundleName,const std::string & uid,bool needMonitored,sptr<IFormSupply> client)95 std::shared_ptr<FormRenderRecord> FormRenderRecord::Create(
96 const std::string &bundleName, const std::string &uid, bool needMonitored, sptr<IFormSupply> client)
97 {
98 HILOG_INFO("bundleName is %{public}s, uid is %{public}s", bundleName.c_str(), uid.c_str());
99 std::shared_ptr<FormRenderRecord> renderRecord = std::make_shared<FormRenderRecord>(bundleName, uid, client);
100 if (!renderRecord) {
101 HILOG_ERROR("Create FormRenderRecord failed");
102 return nullptr;
103 }
104
105 if (!renderRecord->CreateEventHandler(bundleName, needMonitored)) {
106 HILOG_ERROR("CreateEventHandler failed");
107 return nullptr;
108 }
109 return renderRecord;
110 }
111
FormRenderRecord(const std::string & bundleName,const std::string & uid,const sptr<IFormSupply> client)112 FormRenderRecord::FormRenderRecord(
113 const std::string &bundleName, const std::string &uid, const sptr<IFormSupply> client)
114 : bundleName_(bundleName), uid_(uid), formSupplyClient_(client)
115 {
116 HILOG_INFO("bundleName is %{public}s,uid is %{public}s", bundleName.c_str(), uid.c_str());
117 threadState_ = std::make_shared<ThreadState>(CHECK_THREAD_TIME);
118 formSupplyClient_ = client;
119 }
120
~FormRenderRecord()121 FormRenderRecord::~FormRenderRecord()
122 {
123 HILOG_INFO("call");
124 std::shared_ptr<EventHandler> eventHandler = nullptr;
125 {
126 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
127 eventHandler = eventHandler_;
128 }
129
130 if (eventHandler == nullptr) {
131 HILOG_WARN("null eventHandler");
132 return;
133 }
134
135 // Some resources need to be deleted in a JS thread
136 auto syncTask = [renderRecord = this]() {
137 if (renderRecord == nullptr) {
138 HILOG_ERROR("null renderRecord");
139 return;
140 }
141 renderRecord->HandleDestroyInJsThread();
142 };
143 eventHandler->PostSyncTask(syncTask, "Destory FormRenderRecord");
144 }
145
HandleHostDied(const sptr<IRemoteObject> hostRemoteObj)146 bool FormRenderRecord::HandleHostDied(const sptr<IRemoteObject> hostRemoteObj)
147 {
148 HILOG_INFO("Form host is died,clean resources");
149 std::lock_guard<std::mutex> lock(hostsMapMutex_);
150 for (auto iter = hostsMapForFormId_.begin(); iter != hostsMapForFormId_.end();) {
151 std::unordered_set<sptr<IRemoteObject>, RemoteObjHash> &hosts = iter->second;
152 hosts.erase(hostRemoteObj);
153 if (hosts.empty()) {
154 int64_t formId = iter->first;
155 iter = hostsMapForFormId_.erase(iter);
156 DeleteRendererGroup(formId);
157 } else {
158 ++iter;
159 }
160 }
161 return hostsMapForFormId_.empty();
162 }
163
DeleteRendererGroup(int64_t formId)164 void FormRenderRecord::DeleteRendererGroup(int64_t formId)
165 {
166 std::shared_ptr<EventHandler> eventHandler = nullptr;
167 {
168 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
169 eventHandler = eventHandler_;
170 }
171
172 if (eventHandler == nullptr) {
173 HILOG_ERROR("null eventHandler");
174 return;
175 }
176
177 auto task = [weak = weak_from_this(), formId]() {
178 auto renderRecord = weak.lock();
179 if (renderRecord == nullptr) {
180 HILOG_ERROR("null renderRecord");
181 return;
182 }
183
184 renderRecord->HandleDeleteRendererGroup(formId);
185 };
186
187 eventHandler->PostSyncTask(task, "DeleteRendererGroup");
188 }
189
HandleDeleteRendererGroup(int64_t formId)190 void FormRenderRecord::HandleDeleteRendererGroup(int64_t formId)
191 {
192 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
193 formRendererGroupMap_.erase(formId);
194 }
195
CreateEventHandler(const std::string & bundleName,bool needMonitored)196 bool FormRenderRecord::CreateEventHandler(const std::string &bundleName, bool needMonitored)
197 {
198 HILOG_INFO("call");
199 if (eventHandler_) {
200 HILOG_DEBUG("EventHandle is exist,no need to create a new one");
201 return true;
202 }
203 // Create event runner
204 HILOG_INFO("Create eventHandle");
205 if (eventRunner_ == nullptr) {
206 eventRunner_ = EventRunner::Create(bundleName);
207 if (eventRunner_ == nullptr) {
208 HILOG_ERROR("Create event runner Failed");
209 return false;
210 }
211 }
212 // Create event handler
213 eventHandler_ = std::make_shared<EventHandler>(eventRunner_);
214 if (eventHandler_ == nullptr) {
215 HILOG_ERROR("Create event handler failed");
216 return false;
217 }
218
219 if (needMonitored && !hasMonitor_) {
220 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
221 auto task = [thisWeakPtr]() {
222 auto renderRecord = thisWeakPtr.lock();
223 if (renderRecord == nullptr) {
224 HILOG_ERROR("null renderRecord");
225 return;
226 }
227 renderRecord->jsThreadId_ = getproctid();
228 renderRecord->processId_ = getprocpid();
229 HILOG_INFO("Get thread %{public}d and psid %{public}d", renderRecord->jsThreadId_,
230 renderRecord->processId_);
231 };
232 eventHandler_->PostHighPriorityTask(task, "GotJSThreadId");
233
234 hasMonitor_.store(true);
235 AddWatchDogThreadMonitor();
236 }
237
238 return true;
239 }
240
AddWatchDogThreadMonitor()241 void FormRenderRecord::AddWatchDogThreadMonitor()
242 {
243 HILOG_INFO("add watchDog monitor, bundleName is %{public}s, uid is %{public}s",
244 bundleName_.c_str(), uid_.c_str());
245 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
246 auto watchdogTask = [thisWeakPtr]() {
247 auto renderRecord = thisWeakPtr.lock();
248 if (renderRecord) {
249 renderRecord->Timer();
250 }
251 };
252
253 std::string eventHandleName;
254 eventHandleName.append(bundleName_).append(std::to_string(GetCurrentTickMillseconds()));
255 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask(eventHandleName, watchdogTask, TIMEOUT);
256 }
257
OnRenderingBlock(const std::string & bundleName)258 void FormRenderRecord::OnRenderingBlock(const std::string &bundleName)
259 {
260 sptr<IFormSupply> formSupplyClient = nullptr;
261 {
262 std::lock_guard<std::mutex> lock(formSupplyMutex_);
263 formSupplyClient = formSupplyClient_;
264 }
265
266 if (formSupplyClient == nullptr) {
267 HILOG_ERROR("null formSupplyClient");
268 return;
269 }
270
271 formSupplyClient->OnRenderingBlock(bundleName);
272 }
273
Timer()274 void FormRenderRecord::Timer()
275 {
276 TaskState taskState = RunTask();
277 if (taskState == TaskState::BLOCK) {
278 HILOG_ERROR("FRS block happened when bundleName is %{public}s, uid is %{public}s",
279 bundleName_.c_str(), uid_.c_str());
280 FormRenderEventReport::SendBlockFaultEvent(processId_, jsThreadId_, bundleName_);
281 OnRenderingBlock(bundleName_);
282 }
283 }
284
RunTask()285 TaskState FormRenderRecord::RunTask()
286 {
287 std::unique_lock<std::mutex> lock(watchDogMutex_);
288 {
289 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
290 if (eventHandler_ == nullptr) {
291 HILOG_DEBUG("null eventHandler when bundleName %{public}s", bundleName_.c_str());
292 return TaskState::NO_RUNNING;
293 }
294 }
295
296 if (!threadIsAlive_) {
297 threadState_->NextState();
298 HILOG_INFO("FRS block happened with threadState is %{public}d when bundleName is %{public}s",
299 threadState_->GetCurrentState(), bundleName_.c_str());
300 DumpEventHandler();
301 return threadState_->IsMaxState() ? TaskState::BLOCK : TaskState::RUNNING;
302 }
303
304 threadIsAlive_ = false;
305 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
306 auto checkTask = [thisWeakPtr] () {
307 auto renderRecord = thisWeakPtr.lock();
308 if (renderRecord == nullptr) {
309 HILOG_ERROR("null renderRecord");
310 return;
311 }
312
313 renderRecord->MarkThreadAlive();
314 };
315
316 {
317 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
318 if (eventHandler_ == nullptr) {
319 return TaskState::NO_RUNNING;
320 }
321
322 if (!eventHandler_->PostTask(checkTask, "Watchdog Task", 0, AppExecFwk::EventQueue::Priority::IMMEDIATE)) {
323 HILOG_ERROR("Watchdog checkTask postTask false");
324 }
325 }
326
327 return TaskState::RUNNING;
328 }
329
DumpEventHandler()330 void FormRenderRecord::DumpEventHandler()
331 {
332 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
333 if (eventHandler_ == nullptr) {
334 return;
335 }
336
337 HandlerDumper handlerDumper;
338 eventHandler_->Dump(handlerDumper);
339 }
340
MarkThreadAlive()341 void FormRenderRecord::MarkThreadAlive()
342 {
343 std::unique_lock<std::mutex> lock(watchDogMutex_);
344 threadIsAlive_ = true;
345 threadState_->ResetState();
346 }
347
UpdateRenderRecord(const FormJsInfo & formJsInfo,const Want & want,const sptr<IRemoteObject> hostRemoteObj)348 int32_t FormRenderRecord::UpdateRenderRecord(const FormJsInfo &formJsInfo, const Want &want,
349 const sptr<IRemoteObject> hostRemoteObj)
350 {
351 HILOG_DEBUG("Updated record");
352 {
353 // Some resources need to be initialized in a JS thread
354 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
355 if (!CheckEventHandler(true, formJsInfo.isDynamic)) {
356 HILOG_ERROR("null eventHandler_ ");
357 return RENDER_FORM_FAILED;
358 }
359
360 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
361 auto task = [thisWeakPtr, formJsInfo, want]() {
362 HILOG_DEBUG("HandleUpdateInJsThread begin");
363 auto renderRecord = thisWeakPtr.lock();
364 if (renderRecord == nullptr) {
365 HILOG_ERROR("null renderRecord");
366 return;
367 }
368 renderRecord->HandleUpdateInJsThread(formJsInfo, want);
369 };
370 eventHandler_->PostTask(task, "UpdateRenderRecord");
371 }
372
373 if (hostRemoteObj == nullptr) {
374 HILOG_WARN("null hostRemoteObj");
375 return RENDER_FORM_FAILED;
376 }
377 std::lock_guard<std::mutex> lock(hostsMapMutex_);
378 auto iter = hostsMapForFormId_.find(formJsInfo.formId);
379 if (iter == hostsMapForFormId_.end()) {
380 hostsMapForFormId_.emplace(formJsInfo.formId, IRemoteObjectSet({ hostRemoteObj }));
381 return ERR_OK;
382 }
383 iter->second.emplace(hostRemoteObj);
384 return ERR_OK;
385 }
386
DeleteRenderRecord(int64_t formId,const std::string & compId,const sptr<IRemoteObject> hostRemoteObj,bool & isRenderGroupEmpty)387 void FormRenderRecord::DeleteRenderRecord(int64_t formId, const std::string &compId,
388 const sptr<IRemoteObject> hostRemoteObj, bool &isRenderGroupEmpty)
389 {
390 // Some resources need to be deleted in a JS thread
391 HILOG_INFO("Delete some resources formId:%{public}" PRId64 ",%{public}s", formId, compId.c_str());
392 std::shared_ptr<EventHandler> eventHandler = nullptr;
393 {
394 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
395 eventHandler = eventHandler_;
396 }
397
398 if (eventHandler == nullptr) {
399 HILOG_ERROR("null eventHandler");
400 DeleteFormRequest(formId, compId);
401 return;
402 }
403
404 auto task = [weak = weak_from_this(), formId, compId, &isRenderGroupEmpty]() {
405 auto renderRecord = weak.lock();
406 if (renderRecord == nullptr) {
407 HILOG_ERROR("null renderRecord");
408 return;
409 }
410
411 FormMemoryGuard memoryGuard;
412 isRenderGroupEmpty = renderRecord->HandleDeleteInJsThread(formId, compId);
413 renderRecord->DeleteFormRequest(formId, compId);
414 };
415
416 if (hostRemoteObj != nullptr) {
417 std::lock_guard<std::mutex> lock(hostsMapMutex_);
418 auto iter = hostsMapForFormId_.find(formId);
419 if (iter != hostsMapForFormId_.end()) {
420 std::unordered_set<sptr<IRemoteObject>, RemoteObjHash> &hosts = iter->second;
421 hosts.erase(hostRemoteObj);
422 }
423 }
424 eventHandler_->PostSyncTask(task, "DeleteRenderRecord");
425 }
426
IsEmpty()427 bool FormRenderRecord::IsEmpty()
428 {
429 bool rendererEmpty = false;
430 bool formRequestsEmpty = false;
431 {
432 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
433 rendererEmpty = formRendererGroupMap_.empty();
434 }
435 {
436 std::lock_guard<std::mutex> lock(formRequestsMutex_);
437 formRequestsEmpty = formRequests_.empty();
438 }
439 return rendererEmpty && formRequestsEmpty;
440 }
441
GetUid() const442 std::string FormRenderRecord::GetUid() const
443 {
444 return uid_;
445 }
446
CreateRuntime(const FormJsInfo & formJsInfo)447 bool FormRenderRecord::CreateRuntime(const FormJsInfo &formJsInfo)
448 {
449 if (runtime_) {
450 HILOG_DEBUG("runtime is exist,no need to create a new one");
451 return true;
452 }
453
454 HILOG_INFO("Create a new runtime");
455 if (eventRunner_ == nullptr) {
456 HILOG_ERROR("null eventRunner_");
457 return false;
458 }
459
460 AbilityRuntime::Runtime::Options options;
461 options.bundleName = formJsInfo.bundleName;
462 options.codePath = Constants::LOCAL_CODE_PATH;
463 BundleInfo bundleInfo;
464 options.eventRunner = eventRunner_;
465 options.hapPath = formJsInfo.jsFormCodePath;
466 options.loadAce = true;
467 options.isBundle = true;
468 options.isUnique = true;
469 options.moduleCheckerDelegate = std::make_shared<FormModuleChecker>();
470
471 SetPkgContextInfoMap(formJsInfo, options);
472
473 runtime_ = AbilityRuntime::Runtime::Create(options);
474 if (runtime_ == nullptr) {
475 HILOG_ERROR("Create runtime Failed");
476 return false;
477 }
478 hapPath_ = formJsInfo.jsFormCodePath;
479 return true;
480 }
481
UpdateRuntime(const FormJsInfo & formJsInfo)482 bool FormRenderRecord::UpdateRuntime(const FormJsInfo &formJsInfo)
483 {
484 {
485 std::lock_guard<std::mutex> lock(contextsMapMutex_);
486 auto moduleInfo = contextsMapForModuleName_.find(GenerateContextKey(formJsInfo));
487 if (moduleInfo != contextsMapForModuleName_.end()) {
488 return false;
489 }
490 }
491 if (!runtime_) {
492 HILOG_ERROR("runtime is not exist. %{public}s", formJsInfo.bundleName.c_str());
493 return false;
494 }
495 std::string moduleName = formJsInfo.moduleName;
496 HILOG_INFO("update runtime for bundle:%{public}s, module %{public}s",
497 formJsInfo.bundleName.c_str(), moduleName.c_str());
498 AbilityRuntime::Runtime::Options options;
499 SetPkgContextInfoMap(formJsInfo, options);
500 auto contextInfo = options.pkgContextInfoJsonStringMap.find(moduleName);
501 if (contextInfo != options.pkgContextInfoJsonStringMap.end()) {
502 auto pkgNameInfo = options.packageNameList.find(moduleName);
503 std::string packageName;
504 if (pkgNameInfo != options.packageNameList.end()) {
505 packageName = pkgNameInfo->second;
506 }
507 runtime_->UpdatePkgContextInfoJson(moduleName, contextInfo->second, packageName);
508 if (runtime_->GetLanguage() == AbilityRuntime::Runtime::Language::JS) {
509 HILOG_INFO("%{public}s load components of new module %{public}s",
510 formJsInfo.bundleName.c_str(), moduleName.c_str());
511 (static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).ReloadFormComponent();
512 }
513 }
514 return true;
515 }
516
SetPkgContextInfoMap(const FormJsInfo & formJsInfo,AbilityRuntime::Runtime::Options & options)517 bool FormRenderRecord::SetPkgContextInfoMap(const FormJsInfo &formJsInfo, AbilityRuntime::Runtime::Options &options)
518 {
519 std::map<std::string, std::string> pkgContextInfoJsonStringMap;
520 for (auto modulePkgNamePair : formJsInfo.modulePkgNameMap) {
521 nlohmann::json moduleInfos = nlohmann::json::parse(modulePkgNamePair.second, nullptr, false);
522 if (moduleInfos.is_discarded()) {
523 HILOG_ERROR("fail parse modulePkgNamePair");
524 continue;
525 }
526 std::string pkgName = "";
527 std::string hapPath = "";
528 if (moduleInfos.contains(Constants::MODULE_PKG_NAME_KEY) &&
529 moduleInfos.at(Constants::MODULE_PKG_NAME_KEY).is_string()) {
530 pkgName = moduleInfos[Constants::MODULE_PKG_NAME_KEY].get<std::string>();
531 options.packageNameList[modulePkgNamePair.first] = pkgName;
532 }
533 if (moduleInfos.contains(Constants::MODULE_HAP_PATH_KEY) &&
534 moduleInfos.at(Constants::MODULE_HAP_PATH_KEY).is_string()) {
535 hapPath = moduleInfos[Constants::MODULE_HAP_PATH_KEY].get<std::string>();
536 pkgContextInfoJsonStringMap[modulePkgNamePair.first] = hapPath;
537 }
538 HILOG_DEBUG("SetPkgContextInfoMap module:%{public}s, pkgName:%{public}s, hapPath:%{public}s",
539 modulePkgNamePair.first.c_str(), pkgName.c_str(), hapPath.c_str());
540 }
541 if (!pkgContextInfoJsonStringMap.empty()) {
542 HILOG_INFO("set pkgContextInfoJsonStringMap for %{public}s", formJsInfo.bundleName.c_str());
543 options.pkgContextInfoJsonStringMap = pkgContextInfoJsonStringMap;
544 }
545 return true;
546 }
547
SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)548 void FormRenderRecord::SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
549 {
550 configuration_ = config;
551 }
552
GetContext(const FormJsInfo & formJsInfo,const Want & want)553 std::shared_ptr<AbilityRuntime::Context> FormRenderRecord::GetContext(const FormJsInfo &formJsInfo, const Want &want)
554 {
555 {
556 std::lock_guard<std::mutex> lock(contextsMapMutex_);
557 auto iter = contextsMapForModuleName_.find(GenerateContextKey(formJsInfo));
558 if (iter != contextsMapForModuleName_.end()) {
559 if (iter->second == nullptr) {
560 HILOG_WARN("null Context, bundle name is %{public}s", formJsInfo.bundleName.c_str());
561 return nullptr;
562 }
563 auto applicationInfo = iter->second->GetApplicationInfo();
564 if (applicationInfo != nullptr) {
565 uint32_t apiCompatibleVersion = static_cast<uint32_t>(
566 want.GetIntParam(Constants::FORM_COMPATIBLE_VERSION_KEY, 0));
567 if (apiCompatibleVersion != 0) {
568 applicationInfo->apiCompatibleVersion = apiCompatibleVersion;
569 }
570 HILOG_INFO("GetContext bundleName %{public}s, apiCompatibleVersion = %{public}d",
571 formJsInfo.bundleName.c_str(), applicationInfo->apiCompatibleVersion);
572 }
573
574 std::shared_ptr<OHOS::AppExecFwk::Configuration> config = iter->second->GetConfiguration();
575 if (config != nullptr && configuration_ != nullptr) {
576 std::string colorMode = configuration_->GetItem(SYSTEM_COLORMODE);
577 std::string languageTag = configuration_->GetItem(SYSTEM_LANGUAGE);
578 config->AddItem(SYSTEM_COLORMODE, colorMode);
579 config->AddItem(SYSTEM_LANGUAGE, languageTag);
580 }
581 return iter->second;
582 }
583 }
584
585 return CreateContext(formJsInfo, want);
586 }
587
CreateContext(const FormJsInfo & formJsInfo,const Want & want)588 std::shared_ptr<AbilityRuntime::Context> FormRenderRecord::CreateContext(const FormJsInfo &formJsInfo, const Want &want)
589 {
590 HILOG_INFO("Create a new context");
591 auto context = std::make_shared<AbilityRuntime::ContextImpl>();
592 if (context == nullptr) {
593 HILOG_ERROR("Create context failed");
594 return nullptr;
595 }
596
597 context->SetConfiguration(configuration_);
598 AppExecFwk::HapModuleInfo hapModuleInfo;
599 hapModuleInfo.name = formJsInfo.moduleName;
600 hapModuleInfo.hapPath = formJsInfo.jsFormCodePath;
601 hapModuleInfo.compileMode = static_cast<CompileMode>(want.GetIntParam(Constants::FORM_COMPILE_MODE_KEY,
602 static_cast<int32_t>(CompileMode::ES_MODULE)));
603 context->InitHapModuleInfo(hapModuleInfo);
604 auto applicationInfo = std::make_shared<AppExecFwk::ApplicationInfo>();
605 applicationInfo->bundleName = formJsInfo.bundleName;
606 applicationInfo->apiCompatibleVersion = static_cast<uint32_t>(want.GetIntParam(
607 Constants::FORM_COMPATIBLE_VERSION_KEY, 0));
608 applicationInfo->apiTargetVersion = static_cast<int32_t>(want.GetIntParam(
609 Constants::FORM_TARGET_VERSION_KEY, 0));
610 context->SetApplicationInfo(applicationInfo);
611 HILOG_DEBUG("bundleName is %{public}s, moduleName is %{public}s",
612 formJsInfo.bundleName.c_str(), formJsInfo.moduleName.c_str());
613
614 std::lock_guard<std::mutex> lock(contextsMapMutex_);
615 contextsMapForModuleName_.emplace(GenerateContextKey(formJsInfo), context);
616 return context;
617 }
618
GetFormRendererGroup(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)619 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::GetFormRendererGroup(const FormJsInfo &formJsInfo,
620 const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
621 {
622 HILOG_INFO("Get formRendererGroup");
623 auto key = formJsInfo.formId;
624 auto iter = formRendererGroupMap_.find(key);
625 if (iter != formRendererGroupMap_.end()) {
626 return iter->second;
627 }
628
629 auto formRendererGroup = CreateFormRendererGroupLock(formJsInfo, context, runtime);
630 if (formRendererGroup != nullptr) {
631 HILOG_INFO("formRendererGroupMap emplace formId:%{public}s", std::to_string(key).c_str());
632 formRendererGroupMap_.emplace(key, formRendererGroup);
633 }
634 return formRendererGroup;
635 }
636
CreateFormRendererGroupLock(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)637 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::CreateFormRendererGroupLock(const FormJsInfo &formJsInfo,
638 const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
639 {
640 HILOG_INFO("Create formRendererGroup");
641 auto formRendererGroup = Ace::FormRendererGroup::Create(context, runtime, eventHandler_);
642 if (formRendererGroup == nullptr) {
643 HILOG_ERROR("Create formRendererGroup failed");
644 return nullptr;
645 }
646 return formRendererGroup;
647 }
648
HandleUpdateInJsThread(const FormJsInfo & formJsInfo,const Want & want)649 void FormRenderRecord::HandleUpdateInJsThread(const FormJsInfo &formJsInfo, const Want &want)
650 {
651 HILOG_INFO("Update record in js thread, formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
652 bool ret = BeforeHandleUpdateForm(formJsInfo);
653 if (!ret) {
654 HILOG_ERROR("Handle Update Form prepare failed");
655 return;
656 }
657
658 HandleUpdateForm(formJsInfo, want);
659 }
660
BeforeHandleUpdateForm(const FormJsInfo & formJsInfo)661 bool FormRenderRecord::BeforeHandleUpdateForm(const FormJsInfo &formJsInfo)
662 {
663 MarkThreadAlive();
664 if (runtime_ == nullptr) {
665 if (!CreateRuntime(formJsInfo)) {
666 HILOG_ERROR("Create runtime failed");
667 return false;
668 }
669 } else {
670 UpdateRuntime(formJsInfo);
671 }
672 HILOG_DEBUG("BeforeHandleUpdateForm end");
673 return true;
674 }
675
HandleUpdateForm(const FormJsInfo & formJsInfo,const Want & want)676 void FormRenderRecord::HandleUpdateForm(const FormJsInfo &formJsInfo, const Want &want)
677 {
678 auto renderType = want.GetIntParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
679 HILOG_DEBUG("renderType is %{public}d", renderType);
680 if (renderType == Constants::RENDER_FORM) {
681 AddRenderer(formJsInfo, want);
682 AddFormRequest(formJsInfo, want);
683 return;
684 }
685
686 std::unordered_map<std::string, Ace::FormRequest> formRequests;
687 {
688 std::lock_guard<std::mutex> lock(formRequestsMutex_);
689 auto iter = formRequests_.find(formJsInfo.formId);
690 if (iter == formRequests_.end()) {
691 HILOG_WARN("Without this form: %{public}" PRId64 "", formJsInfo.formId);
692 return;
693 }
694
695 formRequests = iter->second;
696 }
697 std::string compMaxId = "0";
698 for (const auto& iter : formRequests) {
699 if (iter.second.compId > compMaxId) {
700 compMaxId = iter.second.compId;
701 }
702 }
703
704 bool isDynamicFormNeedRecover = false;
705 for (const auto& iter : formRequests) {
706 auto formRequest = iter.second;
707 MergeFormData(formRequest, formJsInfo);
708 if (!formRequest.hasRelease) {
709 UpdateRenderer(formJsInfo);
710 AddFormRequest(formJsInfo.formId, formRequest);
711 continue;
712 }
713 if (formJsInfo.isDynamic) {
714 isDynamicFormNeedRecover = true;
715 continue;
716 }
717 if (compMaxId == formRequest.compId) {
718 AddRenderer(formJsInfo, formRequest.want);
719 formRequest.hasRelease = false;
720 AddFormRequest(formJsInfo.formId, formRequest);
721 }
722 }
723
724 if (isDynamicFormNeedRecover) {
725 std::string statusData = want.GetStringParam(Constants::FORM_STATUS_DATA);
726 bool isHandleClickEvent = false;
727 HandleRecoverForm(formJsInfo, statusData, isHandleClickEvent);
728 UpdateRenderer(formJsInfo);
729 }
730 }
731
MergeFormData(Ace::FormRequest & formRequest,const FormJsInfo & formJsInfo)732 void FormRenderRecord::MergeFormData(Ace::FormRequest &formRequest, const FormJsInfo &formJsInfo)
733 {
734 FormProviderData formProviderData = FormProviderData(formRequest.formJsInfo.formData, true);
735 nlohmann::json newFormData = formJsInfo.formProviderData.GetData();
736 formProviderData.MergeData(newFormData);
737
738 formRequest.formJsInfo = formJsInfo;
739 formRequest.formJsInfo.formData = formProviderData.GetDataString();
740 }
741
AddRenderer(const FormJsInfo & formJsInfo,const Want & want)742 void FormRenderRecord::AddRenderer(const FormJsInfo &formJsInfo, const Want &want)
743 {
744 auto context = GetContext(formJsInfo, want);
745 if (context == nullptr) {
746 HILOG_ERROR("Create Context failed");
747 return;
748 }
749
750 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
751 auto formRendererGroup = GetFormRendererGroup(formJsInfo, context, runtime_);
752 if (formRendererGroup == nullptr) {
753 HILOG_ERROR("Create formRendererGroup failed");
754 return;
755 }
756 formRendererGroup->AddForm(want, formJsInfo);
757 HILOG_INFO("AddForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
758 }
759
UpdateRenderer(const FormJsInfo & formJsInfo)760 void FormRenderRecord::UpdateRenderer(const FormJsInfo &formJsInfo)
761 {
762 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
763 if (auto search = formRendererGroupMap_.find(formJsInfo.formId);
764 search != formRendererGroupMap_.end()) {
765 auto group = search->second;
766 group->UpdateForm(formJsInfo);
767 }
768 HILOG_INFO("UpdateForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
769 }
770
HandleDeleteInJsThread(int64_t formId,const std::string & compId)771 bool FormRenderRecord::HandleDeleteInJsThread(int64_t formId, const std::string &compId)
772 {
773 HILOG_INFO("Delete some resources in js thread");
774 MarkThreadAlive();
775 {
776 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
777 auto search = formRendererGroupMap_.find(formId);
778 if (search == formRendererGroupMap_.end()) {
779 HILOG_ERROR("invalid FormRendererGroup");
780 return false;
781 }
782 if (!search->second) {
783 HILOG_ERROR("FormRendererGroup was founded but null");
784 return false;
785 }
786 if (!compId.empty()) {
787 search->second->DeleteForm(compId);
788 HILOG_ERROR("HandleDeleteInJsThread compid is %{public}s", compId.c_str());
789 return false;
790 }
791 search->second->DeleteForm();
792 formRendererGroupMap_.erase(formId);
793 }
794 std::lock_guard<std::mutex> lock(hostsMapMutex_);
795 hostsMapForFormId_.erase(formId);
796 return true;
797 }
798
CheckEventHandler(bool createThead,bool needMonitored)799 bool FormRenderRecord::CheckEventHandler(bool createThead, bool needMonitored)
800 {
801 if (eventHandler_ == nullptr && createThead) {
802 CreateEventHandler(bundleName_, needMonitored);
803 }
804
805 return eventHandler_ != nullptr;
806 }
807
AddFormRequest(const FormJsInfo & formJsInfo,const Want & want)808 void FormRenderRecord::AddFormRequest(const FormJsInfo &formJsInfo, const Want &want)
809 {
810 auto compId = want.GetStringParam(FORM_RENDERER_COMP_ID);
811 HILOG_INFO("AddFormRequest formId: %{public}s, compId: %{public}s, formJsInfo.formData.size: %{public}zu.",
812 std::to_string(formJsInfo.formId).c_str(),
813 compId.c_str(),
814 formJsInfo.formData.size());
815 if (compId.empty()) {
816 return;
817 }
818
819 std::lock_guard<std::mutex> lock(formRequestsMutex_);
820 Ace::FormRequest formRequest;
821 formRequest.compId = compId;
822 formRequest.want = want;
823 formRequest.want.SetParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
824 formRequest.isDynamic = formJsInfo.isDynamic;
825 formRequest.formJsInfo = formJsInfo;
826 auto iter = formRequests_.find(formJsInfo.formId);
827 if (iter == formRequests_.end()) {
828 std::unordered_map<std::string, Ace::FormRequest> formRequests;
829 formRequests.emplace(compId, formRequest);
830 formRequests_.emplace(formJsInfo.formId, formRequests);
831 return;
832 }
833
834 auto innerIter = iter->second.find(compId);
835 if (innerIter != iter->second.end()) {
836 iter->second.erase(innerIter);
837 }
838 iter->second.emplace(compId, formRequest);
839 }
840
AddFormRequest(int64_t formId,const Ace::FormRequest & formRequest)841 void FormRenderRecord::AddFormRequest(int64_t formId, const Ace::FormRequest &formRequest)
842 {
843 HILOG_INFO("AddFormRequest by FormRequest formId: %{public}s, compId: %{public}s, formData.size: %{public}zu",
844 std::to_string(formId).c_str(),
845 formRequest.compId.c_str(),
846 formRequest.formJsInfo.formData.size());
847 std::lock_guard<std::mutex> lock(formRequestsMutex_);
848 auto iter = formRequests_.find(formId);
849 if (iter == formRequests_.end()) {
850 std::unordered_map<std::string, Ace::FormRequest> formRequests;
851 formRequests.emplace(formRequest.compId, formRequest);
852 formRequests_.emplace(formId, formRequests);
853 return;
854 }
855
856 auto innerIter = iter->second.find(formRequest.compId);
857 if (innerIter != iter->second.end()) {
858 iter->second.erase(innerIter);
859 }
860 iter->second.emplace(formRequest.compId, formRequest);
861 }
862
DeleteFormRequest(int64_t formId,const std::string & compId)863 void FormRenderRecord::DeleteFormRequest(int64_t formId, const std::string &compId)
864 {
865 bool isRequestEmpty = false;
866 {
867 std::lock_guard<std::mutex> lock(formRequestsMutex_);
868 auto iter = formRequests_.find(formId);
869 if (iter == formRequests_.end()) {
870 HILOG_ERROR("invalid request,formId:%{public}" PRId64, formId);
871 return;
872 }
873
874 if (compId.empty()) {
875 formRequests_.erase(iter);
876 isRequestEmpty = true;
877 } else {
878 auto innerIter = iter->second.find(compId);
879 if (innerIter != iter->second.end()) {
880 iter->second.erase(innerIter);
881 }
882 if (iter->second.empty()) {
883 formRequests_.erase(iter);
884 isRequestEmpty = true;
885 }
886 }
887 }
888 if (isRequestEmpty) {
889 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
890 recycledFormCompIds_.erase(formId);
891 }
892 HILOG_INFO("delete request formId:%{public}" PRId64 " compId:%{public}s request empty:%{public}d",
893 formId, compId.c_str(), isRequestEmpty);
894 }
895
UpdateFormRequestReleaseState(int64_t formId,const std::string & compId,bool hasRelease)896 void FormRenderRecord::UpdateFormRequestReleaseState(
897 int64_t formId, const std::string &compId, bool hasRelease)
898 {
899 HILOG_INFO("Update ReleaseState formId:%{public}" PRId64 ", compId:%{public}s, hasRelease:%{public}d",
900 formId, compId.c_str(), hasRelease);
901 std::lock_guard<std::mutex> lock(formRequestsMutex_);
902 auto iter = formRequests_.find(formId);
903 if (iter == formRequests_.end()) {
904 HILOG_ERROR("invalid request,formId:%{public}" PRId64, formId);
905 return;
906 }
907
908 auto innerIter = iter->second.find(compId);
909 if (innerIter == iter->second.end()) {
910 HILOG_ERROR("invalid compId,formId:%{public}" PRId64, formId);
911 return;
912 }
913
914 for (auto& formRequest : iter->second) {
915 formRequest.second.hasRelease = hasRelease;
916 }
917 }
918
ReleaseRenderer(int64_t formId,const std::string & compId,bool & isRenderGroupEmpty)919 void FormRenderRecord::ReleaseRenderer(
920 int64_t formId, const std::string &compId, bool &isRenderGroupEmpty)
921 {
922 HILOG_INFO("Release renderer which formId:%{public}s, compId:%{public}s start.",
923 std::to_string(formId).c_str(), compId.c_str());
924 std::shared_ptr<EventHandler> eventHandler = nullptr;
925 {
926 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
927 eventHandler = eventHandler_;
928 }
929
930 if (eventHandler == nullptr) {
931 HILOG_ERROR("null eventHandler");
932 return;
933 }
934
935 auto task = [weak = weak_from_this(), formId, compId, &isRenderGroupEmpty]() {
936 auto renderRecord = weak.lock();
937 if (renderRecord == nullptr) {
938 HILOG_ERROR("null renderRecord");
939 return;
940 }
941
942 FormMemoryGuard memoryGuard;
943 bool ret = renderRecord->HandleReleaseRendererInJsThread(formId, compId, isRenderGroupEmpty);
944 if (ret) {
945 renderRecord->UpdateFormRequestReleaseState(formId, compId, true);
946 } else {
947 HILOG_ERROR("release renderer error, skip update state, formId:%{public}" PRId64, formId);
948 }
949 };
950 eventHandler->PostSyncTask(task, "ReleaseRenderer");
951 }
952
HandleReleaseRendererInJsThread(int64_t formId,const std::string & compId,bool & isRenderGroupEmpty)953 bool FormRenderRecord::HandleReleaseRendererInJsThread(
954 int64_t formId, const std::string &compId, bool &isRenderGroupEmpty)
955 {
956 HILOG_INFO("Release renderer which formId:%{public}s, compId:%{public}s in js thread.",
957 std::to_string(formId).c_str(), compId.c_str());
958 MarkThreadAlive();
959 if (compId.empty()) {
960 HILOG_ERROR("compId empty");
961 return false;
962 }
963
964 std::pair<std::vector<std::string>, std::string> compIds;
965 {
966 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
967 auto search = formRendererGroupMap_.find(formId);
968 if (search == formRendererGroupMap_.end()) {
969 HILOG_ERROR("invalid rendererGroup");
970 return false;
971 }
972
973 if (!search->second) {
974 HILOG_ERROR("null rendererGroup");
975 return false;
976 }
977
978 compIds = search->second->GetOrderedAndCurrentCompIds();
979 search->second->DeleteForm();
980 formRendererGroupMap_.erase(formId);
981 isRenderGroupEmpty = formRendererGroupMap_.empty();
982 }
983 {
984 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
985 recycledFormCompIds_.erase(formId);
986 recycledFormCompIds_.emplace(formId, compIds);
987 }
988 return true;
989 }
990
Release()991 void FormRenderRecord::Release()
992 {
993 HILOG_INFO("Release runtime and eventHandler");
994 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
995 if (eventHandler_ == nullptr) {
996 HILOG_INFO("null eventHandler");
997 return;
998 }
999
1000 auto syncTask = [renderRecord = this]() {
1001 if (renderRecord == nullptr) {
1002 HILOG_ERROR("null renderRecord");
1003 return;
1004 }
1005 renderRecord->HandleReleaseInJsThread();
1006 };
1007 eventHandler_->PostSyncTask(syncTask, "HandleReleaseInJsThread");
1008 if (eventRunner_) {
1009 eventRunner_->Stop();
1010 eventRunner_.reset();
1011 }
1012
1013 eventHandler_.reset();
1014 contextsMapForModuleName_.clear();
1015 }
1016
HandleReleaseInJsThread()1017 void FormRenderRecord::HandleReleaseInJsThread()
1018 {
1019 if (runtime_) {
1020 runtime_.reset();
1021 }
1022 ReleaseHapFileHandle();
1023 }
1024
RecoverFormsByConfigUpdate(std::vector<int64_t> & formIds,const sptr<IFormSupply> & formSupplyClient)1025 void FormRenderRecord::RecoverFormsByConfigUpdate(std::vector<int64_t> &formIds,
1026 const sptr<IFormSupply> &formSupplyClient)
1027 {
1028 if (formSupplyClient == nullptr) {
1029 HILOG_ERROR("null formSupplyClient");
1030 return;
1031 }
1032
1033 if (formIds.empty()) {
1034 HILOG_INFO("empty needRecoverFormIds");
1035 return;
1036 }
1037
1038 formSupplyClient->OnRecoverFormsByConfigUpdate(formIds);
1039 }
1040
ReAddAllRecycledForms(const sptr<IFormSupply> & formSupplyClient)1041 void FormRenderRecord::ReAddAllRecycledForms(const sptr<IFormSupply> &formSupplyClient)
1042 {
1043 HILOG_INFO("ReAdd all recycled forms start");
1044 if (!CheckEventHandler(false, true)) {
1045 HILOG_ERROR("CheckEventHandler failed");
1046 return;
1047 }
1048
1049 std::vector<int64_t> formIds;
1050 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1051 for (const auto& formRequests : formRequests_) {
1052 for (const auto& formRequest : formRequests.second) {
1053 if (!formRequest.second.hasRelease) {
1054 continue;
1055 }
1056
1057 if (formRequest.second.isDynamic) {
1058 formIds.push_back(formRequest.second.formJsInfo.formId);
1059 continue;
1060 }
1061
1062 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1063 auto task = [thisWeakPtr, formJsInfo = formRequest.second.formJsInfo,
1064 want = formRequest.second.want]() {
1065 auto renderRecord = thisWeakPtr.lock();
1066 if (renderRecord) {
1067 renderRecord->HandleUpdateInJsThread(formJsInfo, want);
1068 }
1069 };
1070 eventHandler_->PostTask(task, "ReAddAllRecycledForms");
1071 }
1072 }
1073
1074 RecoverFormsByConfigUpdate(formIds, formSupplyClient);
1075
1076 HILOG_INFO("ReAdd all recycled forms end");
1077 }
1078
ReAddRecycledForms(const std::vector<FormJsInfo> & formJsInfos)1079 void FormRenderRecord::ReAddRecycledForms(const std::vector<FormJsInfo> &formJsInfos)
1080 {
1081 HILOG_INFO("ReAdd recycled form start");
1082 if (!CheckEventHandler(false, true)) {
1083 HILOG_ERROR("CheckEventHandler failed");
1084 return;
1085 }
1086
1087 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1088 for (const auto &form : formJsInfos) {
1089 auto iter = formRequests_.find(form.formId);
1090 if (iter == formRequests_.end()) {
1091 continue;
1092 }
1093
1094 for (const auto& formRequest : iter->second) {
1095 if (!formRequest.second.hasRelease) {
1096 continue;
1097 }
1098
1099 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1100 auto task = [thisWeakPtr, form,
1101 want = formRequest.second.want]() {
1102 auto renderRecord = thisWeakPtr.lock();
1103 if (renderRecord) {
1104 renderRecord->HandleUpdateInJsThread(form, want);
1105 }
1106 };
1107 eventHandler_->PostTask(task, "ReAddRecycledForms");
1108 }
1109 }
1110
1111 HILOG_INFO("ReAdd recycled forms end");
1112 }
1113
HandleDestroyInJsThread()1114 void FormRenderRecord::HandleDestroyInJsThread()
1115 {
1116 HILOG_INFO("FormRenderService is exiting, destroy some resources in js thread");
1117 MarkThreadAlive();
1118 {
1119 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1120 formRequests_.clear();
1121 }
1122 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1123 formRendererGroupMap_.clear();
1124 runtime_.reset();
1125 ReleaseHapFileHandle();
1126 }
1127
ReleaseHapFileHandle()1128 void FormRenderRecord::ReleaseHapFileHandle()
1129 {
1130 HILOG_INFO("ReleaseHapFileHandle:%{public}s", hapPath_.c_str());
1131 if (hapPath_.empty()) {
1132 return;
1133 }
1134
1135 std::string loadFilePath = AbilityBase::ExtractorUtil::GetLoadFilePath(hapPath_);
1136 AbilityBase::ExtractorUtil::DeleteExtractor(loadFilePath);
1137 }
1138
GenerateContextKey(const FormJsInfo & formJsInfo)1139 inline std::string FormRenderRecord::GenerateContextKey(const FormJsInfo &formJsInfo)
1140 {
1141 return formJsInfo.bundleName + ":" + formJsInfo.moduleName;
1142 }
1143
ReloadFormRecord(const std::vector<FormJsInfo> && formJsInfos,const Want & want)1144 int32_t FormRenderRecord::ReloadFormRecord(const std::vector<FormJsInfo> &&formJsInfos, const Want &want)
1145 {
1146 HILOG_INFO("Reload form record");
1147 std::shared_ptr<EventHandler> eventHandler = nullptr;
1148 {
1149 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
1150 eventHandler = eventHandler_;
1151 }
1152 if (eventHandler == nullptr) {
1153 if (!CheckEventHandler(true, true)) {
1154 HILOG_ERROR("null eventHandler");
1155 return RELOAD_FORM_FAILED;
1156 }
1157
1158 ReAddRecycledForms(formJsInfos);
1159 return ERR_OK;
1160 }
1161
1162 if (ReAddIfHapPathChanged(formJsInfos)) {
1163 return ERR_OK;
1164 }
1165
1166 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1167 auto task = [thisWeakPtr, ids = std::forward<decltype(formJsInfos)>(formJsInfos), want]() {
1168 HILOG_DEBUG("HandleReloadFormRecord begin");
1169 auto renderRecord = thisWeakPtr.lock();
1170 if (renderRecord == nullptr) {
1171 HILOG_ERROR("null renderRecord");
1172 return;
1173 }
1174 renderRecord->HandleReloadFormRecord(std::move(ids), want);
1175 };
1176 eventHandler->PostTask(task, "ReloadFormRecord");
1177 ReAddRecycledForms(formJsInfos);
1178 return ERR_OK;
1179 }
1180
ReAddIfHapPathChanged(const std::vector<FormJsInfo> & formJsInfos)1181 bool FormRenderRecord::ReAddIfHapPathChanged(const std::vector<FormJsInfo> &formJsInfos)
1182 {
1183 std::shared_ptr<EventHandler> eventHandler = nullptr;
1184 {
1185 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
1186 eventHandler = eventHandler_;
1187 }
1188 if (eventHandler == nullptr) {
1189 HILOG_ERROR("eventHandler is nullptr");
1190 return false;
1191 }
1192 std::lock_guard<std::mutex> lock(contextsMapMutex_);
1193 HILOG_INFO("hap path changed");
1194 auto task = [weak = weak_from_this()]() {
1195 auto renderRecord = weak.lock();
1196 if (renderRecord == nullptr) {
1197 HILOG_ERROR("renderRecord is null");
1198 return;
1199 }
1200 FormMemoryGuard memoryGuard;
1201 renderRecord->HandleReleaseAllRendererInJsThread();
1202 };
1203 eventHandler->PostSyncTask(task, "ReleaseAllRenderer");
1204 Release();
1205 UpdateAllFormRequest(formJsInfos, true);
1206 CreateEventHandler(bundleName_, true);
1207 ReAddRecycledForms(formJsInfos);
1208 return true;
1209 }
1210
HandleReleaseAllRendererInJsThread()1211 void FormRenderRecord::HandleReleaseAllRendererInJsThread()
1212 {
1213 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1214 MarkThreadAlive();
1215 for (const auto& iter : formRendererGroupMap_) {
1216 if (!iter.second) {
1217 HILOG_ERROR("null rendererGroup");
1218 continue;
1219 }
1220 int64_t formId = iter.first;
1221 HILOG_INFO("Release renderer which formId:%{public}" PRId64, formId);
1222 std::pair<std::vector<std::string>, std::string> compIds = iter.second->GetOrderedAndCurrentCompIds();
1223 iter.second->DeleteForm();
1224 {
1225 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
1226 recycledFormCompIds_.erase(formId);
1227 recycledFormCompIds_.emplace(formId, compIds);
1228 }
1229 }
1230 formRendererGroupMap_.clear();
1231 }
1232
UpdateAllFormRequest(const std::vector<FormJsInfo> & formJsInfos,bool hasRelease)1233 void FormRenderRecord::UpdateAllFormRequest(const std::vector<FormJsInfo> &formJsInfos, bool hasRelease)
1234 {
1235 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1236 for (const auto &formJsInfo : formJsInfos) {
1237 auto iter = formRequests_.find(formJsInfo.formId);
1238 if (iter == formRequests_.end()) {
1239 HILOG_ERROR("%{public}" PRId64 " doesn't has formRequest", formJsInfo.formId);
1240 continue;
1241 }
1242 for (auto& formRequestIter : iter->second) {
1243 auto& formRequest = formRequestIter.second;
1244 formRequest.isDynamic = formJsInfo.isDynamic;
1245 formRequest.formJsInfo = formJsInfo;
1246 formRequest.hasRelease = hasRelease;
1247 }
1248 }
1249 }
1250
OnUnlock()1251 int32_t FormRenderRecord::OnUnlock()
1252 {
1253 HILOG_DEBUG("call");
1254 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1255 auto task = [thisWeakPtr]() {
1256 HILOG_DEBUG("HandleOnUnlock begin");
1257 auto renderRecord = thisWeakPtr.lock();
1258 if (renderRecord == nullptr) {
1259 HILOG_ERROR("null renderRecord");
1260 return;
1261 }
1262 renderRecord->HandleOnUnlock();
1263 };
1264 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
1265 if (eventHandler_ == nullptr) {
1266 HILOG_ERROR("null eventHandler_");
1267 return RENDER_FORM_FAILED;
1268 }
1269 eventHandler_->PostTask(task, "OnUnlock");
1270 return ERR_OK;
1271 }
1272
HandleOnUnlock()1273 int32_t FormRenderRecord::HandleOnUnlock()
1274 {
1275 HILOG_INFO("call");
1276 {
1277 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1278 for (auto& formRequests : formRequests_) {
1279 for (auto& formRequestElement : formRequests.second) {
1280 formRequestElement.second.want.SetParam(Constants::FORM_RENDER_STATE, true);
1281 }
1282 }
1283 }
1284 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1285 for (const auto& iter : formRendererGroupMap_) {
1286 if (iter.second) {
1287 iter.second->OnUnlock();
1288 }
1289 }
1290 return ERR_OK;
1291 }
1292
SetVisibleChange(const int64_t & formId,bool isVisible)1293 int32_t FormRenderRecord::SetVisibleChange(const int64_t &formId, bool isVisible)
1294 {
1295 HILOG_INFO("SetVisibleChange, formId:%{public}s", std::to_string(formId).c_str());
1296 std::shared_ptr<EventHandler> eventHandler = nullptr;
1297 {
1298 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
1299 eventHandler = eventHandler_;
1300 }
1301 auto task = [thisWeakPtr = weak_from_this(), formId, isVisible]() {
1302 auto renderRecord = thisWeakPtr.lock();
1303 if (renderRecord == nullptr) {
1304 HILOG_ERROR("null renderRecord");
1305 return;
1306 }
1307
1308 renderRecord->HandleSetVisibleChange(formId, isVisible);
1309 };
1310
1311 if (eventHandler == nullptr) {
1312 HILOG_ERROR("null eventHandler");
1313 return SET_VISIBLE_CHANGE_FAILED;
1314 }
1315 eventHandler->PostSyncTask(task, "SetVisibleChange");
1316 return ERR_OK;
1317 }
1318
HandleSetVisibleChange(const int64_t & formId,bool isVisible)1319 int32_t FormRenderRecord::HandleSetVisibleChange(const int64_t &formId, bool isVisible)
1320 {
1321 HILOG_INFO("HandleSetVisibleChange begin,formId:%{public}s", std::to_string(formId).c_str());
1322 MarkThreadAlive();
1323
1324 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1325 auto search = formRendererGroupMap_.find(formId);
1326 if (search == formRendererGroupMap_.end()) {
1327 HILOG_ERROR("invalid FormRendererGroup");
1328 return SET_VISIBLE_CHANGE_FAILED;
1329 }
1330 if (!search->second) {
1331 HILOG_ERROR("FormRendererGroup was founded but null");
1332 return SET_VISIBLE_CHANGE_FAILED;
1333 }
1334 search->second->SetVisibleChange(isVisible);
1335 return ERR_OK;
1336 }
1337
HandleReloadFormRecord(const std::vector<FormJsInfo> && formJsInfos,const Want & want)1338 int32_t FormRenderRecord::HandleReloadFormRecord(const std::vector<FormJsInfo> &&formJsInfos, const Want &want)
1339 {
1340 HILOG_INFO("Reload record in js thread");
1341 MarkThreadAlive();
1342 if (runtime_ == nullptr) {
1343 HILOG_ERROR("null runtime_");
1344 return RELOAD_FORM_FAILED;
1345 }
1346 if (runtime_->GetLanguage() == AbilityRuntime::Runtime::Language::JS) {
1347 // In the card upgrade condition, new components may be added and need to be reloaded
1348 HILOG_DEBUG("ReloadFormComponent");
1349 (static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).ReloadFormComponent();
1350 }
1351 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1352 for (auto form : formJsInfos) {
1353 auto search = formRendererGroupMap_.find(form.formId);
1354 if (search == formRendererGroupMap_.end()) {
1355 HILOG_ERROR("invalid FormRendererGroup");
1356 continue;
1357 }
1358 auto group = search->second;
1359 if (!group) {
1360 HILOG_ERROR("null FormRendererGroup");
1361 continue;
1362 }
1363 for (auto formRequest : group->GetAllRendererFormRequests()) {
1364 formRequest.isDynamic = form.isDynamic;
1365 formRequest.formJsInfo = form;
1366 AddFormRequest(form.formId, formRequest);
1367 }
1368 group->ReloadForm(form);
1369 }
1370 return ERR_OK;
1371 }
1372
FormCount()1373 size_t FormRenderRecord::FormCount()
1374 {
1375 return formRequests_.size();
1376 }
1377
UpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config,const sptr<IFormSupply> & formSupplyClient)1378 void FormRenderRecord::UpdateConfiguration(
1379 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config, const sptr<IFormSupply> &formSupplyClient)
1380 {
1381 HILOG_INFO("UpdateConfiguration begin");
1382 if (!config) {
1383 HILOG_ERROR("UpdateConfiguration failed due to null config");
1384 return;
1385 }
1386
1387 SetConfiguration(config);
1388 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
1389 if (eventHandler_ == nullptr) {
1390 if (!CheckEventHandler(true, true)) {
1391 HILOG_ERROR("null eventHandler");
1392 return;
1393 }
1394
1395 ReAddAllRecycledForms(formSupplyClient);
1396 return;
1397 }
1398
1399 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1400 auto task = [thisWeakPtr, config]() {
1401 auto renderRecord = thisWeakPtr.lock();
1402 if (renderRecord == nullptr) {
1403 HILOG_ERROR("null renderRecord");
1404 return;
1405 }
1406 renderRecord->HandleUpdateConfiguration(config);
1407 };
1408
1409 eventHandler_->PostTask(task, "UpdateConfiguration");
1410 ReAddAllRecycledForms(formSupplyClient);
1411 }
1412
HandleUpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)1413 void FormRenderRecord::HandleUpdateConfiguration(
1414 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
1415 {
1416 HILOG_INFO("HandleUpdateConfiguration begin");
1417 MarkThreadAlive();
1418 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1419 if (!config) {
1420 HILOG_ERROR("null configuration");
1421 return;
1422 }
1423
1424 for (auto iter = formRendererGroupMap_.begin(); iter != formRendererGroupMap_.end(); ++iter) {
1425 if (iter->second) {
1426 iter->second->UpdateConfiguration(config);
1427 }
1428 }
1429 }
1430
FormRenderGC()1431 void FormRenderRecord::FormRenderGC()
1432 {
1433 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1434 auto task = [thisWeakPtr]() {
1435 auto renderRecord = thisWeakPtr.lock();
1436 if (renderRecord == nullptr) {
1437 HILOG_ERROR("null renderRecord");
1438 return;
1439 }
1440 renderRecord->HandleFormRenderGC();
1441 };
1442 if (eventHandler_ == nullptr) {
1443 HILOG_ERROR("null eventHandler_");
1444 return;
1445 }
1446 eventHandler_->PostSyncTask(task, "HandleFormRenderGC");
1447 }
1448
HandleFormRenderGC()1449 void FormRenderRecord::HandleFormRenderGC()
1450 {
1451 HILOG_INFO("HandleFormRenderGC");
1452 if (runtime_ == nullptr) {
1453 HILOG_ERROR("null runtime_");
1454 return;
1455 }
1456 panda::JSNApi::TriggerGC((static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).GetEcmaVm(),
1457 panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
1458 }
1459
RecycleForm(const int64_t & formId,std::string & statusData)1460 int32_t FormRenderRecord::RecycleForm(const int64_t &formId, std::string &statusData)
1461 {
1462 HILOG_INFO("RecycleForm begin, formId:%{public}s", std::to_string(formId).c_str());
1463 int32_t result = RECYCLE_FORM_FAILED;
1464 if (!CheckEventHandler(true, true)) {
1465 HILOG_ERROR("null eventHandler_");
1466 return RENDER_FORM_FAILED;
1467 }
1468
1469 auto task = [thisWeakPtr = weak_from_this(), formId, &statusData, &result]() {
1470 auto renderRecord = thisWeakPtr.lock();
1471 if (renderRecord == nullptr) {
1472 HILOG_ERROR("null renderRecord");
1473 return;
1474 }
1475
1476 result = renderRecord->HandleRecycleForm(formId, statusData);
1477 };
1478 eventHandler_->PostSyncTask(task, "RecycleForm");
1479 return result;
1480 }
1481
HandleRecycleForm(const int64_t & formId,std::string & statusData)1482 int32_t FormRenderRecord::HandleRecycleForm(const int64_t &formId, std::string &statusData)
1483 {
1484 HILOG_INFO("HandleRecycleForm begin,formId:%{public}s", std::to_string(formId).c_str());
1485 MarkThreadAlive();
1486
1487 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1488 auto search = formRendererGroupMap_.find(formId);
1489 if (search == formRendererGroupMap_.end()) {
1490 HILOG_ERROR("invalid FormRendererGroup");
1491 return RECYCLE_FORM_FAILED;
1492 }
1493 if (!search->second) {
1494 HILOG_ERROR("FormRendererGroup was founded but null");
1495 return RECYCLE_FORM_FAILED;
1496 }
1497
1498 search->second->RecycleForm(statusData);
1499 return ERR_OK;
1500 }
1501
RecoverForm(const FormJsInfo & formJsInfo,const std::string & statusData,const bool & isRecoverFormToHandleClickEvent)1502 int32_t FormRenderRecord::RecoverForm(const FormJsInfo &formJsInfo,
1503 const std::string &statusData, const bool &isRecoverFormToHandleClickEvent)
1504 {
1505 auto formId = formJsInfo.formId;
1506 HILOG_INFO("RecoverForm begin, formId:%{public}s", std::to_string(formId).c_str());
1507 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
1508 if (!CheckEventHandler(true, true)) {
1509 HILOG_ERROR("null eventHandler_");
1510 return RENDER_FORM_FAILED;
1511 }
1512
1513 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1514 auto task = [thisWeakPtr, formJsInfo, statusData, isRecoverFormToHandleClickEvent]() {
1515 auto renderRecord = thisWeakPtr.lock();
1516 if (renderRecord == nullptr) {
1517 HILOG_ERROR("renderRecord");
1518 return;
1519 }
1520 renderRecord->HandleRecoverForm(formJsInfo, statusData, isRecoverFormToHandleClickEvent);
1521 };
1522 eventHandler_->PostTask(task, "RecoverForm");
1523 return ERR_OK;
1524 }
1525
HandleRecoverForm(const FormJsInfo & formJsInfo,const std::string & statusData,const bool & isHandleClickEvent)1526 void FormRenderRecord::HandleRecoverForm(const FormJsInfo &formJsInfo,
1527 const std::string &statusData, const bool &isHandleClickEvent)
1528 {
1529 auto formId = formJsInfo.formId;
1530 HILOG_INFO("HandleRecoverForm begin, formId:%{public}s, uid:%{public}s", std::to_string(formId).c_str(),
1531 uid_.c_str());
1532 std::unordered_map<std::string, Ace::FormRequest> formRequests;
1533 {
1534 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1535 auto iter = formRequests_.find(formId);
1536 if (iter == formRequests_.end()) {
1537 HILOG_ERROR("%{public}s doesn't has formRequest", std::to_string(formId).c_str());
1538 return;
1539 }
1540 formRequests = iter->second;
1541 }
1542 if (formRequests.empty()) {
1543 HILOG_ERROR("empty formRequests");
1544 return;
1545 }
1546
1547 if (!BeforeHandleUpdateForm(formRequests.begin()->second.formJsInfo)) {
1548 HILOG_ERROR("recover form prepare failed");
1549 return;
1550 }
1551
1552 if (RecoverFormRequestsInGroup(formJsInfo, statusData, isHandleClickEvent, formRequests)) {
1553 for (auto formRequestIter : formRequests) {
1554 formRequestIter.second.hasRelease = false;
1555 AddFormRequest(formId, formRequestIter.second);
1556 }
1557 }
1558 }
1559
InitCompIds(const int64_t & formId,std::vector<std::string> & orderedCompIds,std::string & currentCompId)1560 bool FormRenderRecord::InitCompIds(const int64_t &formId,
1561 std::vector<std::string> &orderedCompIds, std::string ¤tCompId)
1562 {
1563 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
1564 auto pairIter = recycledFormCompIds_.find(formId);
1565 if (pairIter == recycledFormCompIds_.end()) {
1566 HILOG_ERROR("invalid compIdPair,formId:%{public}" PRId64, formId);
1567 return false;
1568 }
1569 orderedCompIds = pairIter->second.first;
1570 currentCompId = pairIter->second.second;
1571 HILOG_INFO("compIds size:%{public}zu,currentCompId:%{public}s,formId:%{public}" PRId64,
1572 orderedCompIds.size(), currentCompId.c_str(), formId);
1573 return true;
1574 }
1575
RecoverFormRequestsInGroup(const FormJsInfo & formJsInfo,const std::string & statusData,const bool & isHandleClickEvent,const std::unordered_map<std::string,Ace::FormRequest> & recordFormRequests)1576 bool FormRenderRecord::RecoverFormRequestsInGroup(const FormJsInfo &formJsInfo, const std::string &statusData,
1577 const bool &isHandleClickEvent, const std::unordered_map<std::string, Ace::FormRequest> &recordFormRequests)
1578 {
1579 auto formId = formJsInfo.formId;
1580 std::vector<std::string> orderedCompIds;
1581 std::string currentCompId;
1582 bool flag = InitCompIds(formId, orderedCompIds, currentCompId);
1583 if (!flag) {
1584 HILOG_INFO("init compIds failed,formId:%{public}" PRId64, formId);
1585 return false;
1586 }
1587
1588 std::vector<Ace::FormRequest> groupRequests;
1589 size_t currentRequestIndex;
1590 bool currentRequestFound = false;
1591
1592 for (auto compId : orderedCompIds) {
1593 auto recordRequestIter = recordFormRequests.find(compId);
1594 if (recordRequestIter == recordFormRequests.end()) {
1595 HILOG_WARN("invalid formRequest,formId:%{public}" PRId64 " compId=%{public}s", formId, compId.c_str());
1596 continue;
1597 }
1598 auto recordRequest = recordRequestIter->second;
1599 Ace::FormRequest groupRequest;
1600 groupRequest.compId = compId;
1601 groupRequest.want = recordRequest.want;
1602 groupRequest.formJsInfo = recordRequest.formJsInfo; // get json data from record request
1603 groupRequest.formJsInfo.imageDataMap = formJsInfo.imageDataMap;
1604
1605 if (compId == currentCompId) {
1606 groupRequest.want.SetParam(Constants::FORM_STATUS_DATA, statusData);
1607 groupRequest.want.SetParam(Constants::FORM_IS_RECOVER_FORM_TO_HANDLE_CLICK_EVENT, isHandleClickEvent);
1608 currentRequestIndex = groupRequests.size();
1609 currentRequestFound = true;
1610 HILOG_INFO("currentRequestIndex: %{public}zu, formData.size: %{public}zu",
1611 currentRequestIndex, groupRequest.formJsInfo.formData.size());
1612 }
1613 groupRequests.emplace_back(groupRequest);
1614 }
1615
1616 if (groupRequests.empty()) {
1617 HILOG_ERROR("group requests empty formId:%{public}" PRId64, formId);
1618 return false;
1619 }
1620
1621 if (!currentRequestFound) {
1622 // maybe current comp deleted between recover, get last comp as new current comp to recover
1623 currentRequestIndex = groupRequests.size() - 1;
1624 HILOG_WARN("current request index:%{public}zu formId:%{public}" PRId64, currentRequestIndex, formId);
1625 }
1626 return RecoverRenderer(groupRequests, currentRequestIndex);
1627 }
1628
RecoverRenderer(const std::vector<Ace::FormRequest> & groupRequests,const size_t & currentRequestIndex)1629 bool FormRenderRecord::RecoverRenderer(const std::vector<Ace::FormRequest> &groupRequests,
1630 const size_t ¤tRequestIndex)
1631 {
1632 if (currentRequestIndex >= groupRequests.size()) {
1633 HILOG_ERROR("current comp index %{public}zu invalid", currentRequestIndex);
1634 return false;
1635 }
1636 auto currentRequest = groupRequests[currentRequestIndex];
1637 auto context = GetContext(currentRequest.formJsInfo, currentRequest.want);
1638 if (context == nullptr) {
1639 HILOG_ERROR("Create Context failed");
1640 return false;
1641 }
1642
1643 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1644 auto formRendererGroup = GetFormRendererGroup(currentRequest.formJsInfo, context, runtime_);
1645 if (formRendererGroup == nullptr) {
1646 HILOG_ERROR("Create formRendererGroup failed");
1647 return false;
1648 }
1649 formRendererGroup->RecoverRenderer(groupRequests, currentRequestIndex);
1650 HILOG_INFO("recover renderer, formId:%{public}" PRId64, currentRequest.formJsInfo.formId);
1651 return true;
1652 }
1653 } // namespace FormRender
1654 } // namespace AppExecFwk
1655 } // namespace OHOS
1656