1 /*
2 * Copyright (c) 2023-2024 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 #include <fstream>
27 #include <sstream>
28
29 #include "status_mgr_center/form_render_status_task_mgr.h"
30 #include "ecmascript/napi/include/jsnapi.h"
31 #include "extractor.h"
32 #include "fms_log_wrapper.h"
33 #include "form_constants.h"
34 #include "form_memory_guard.h"
35 #include "form_module_checker.h"
36 #include "form_render_event_report.h"
37 #include "nlohmann/json.hpp"
38 #include "xcollie/watchdog.h"
39 #include "dfx_dump_catcher.h"
40
41 using namespace OHOS::AAFwk::GlobalConfigurationKey;
42
43 namespace OHOS {
44 namespace AppExecFwk {
45 namespace FormRender {
46 namespace {
47 constexpr int32_t RENDER_FORM_FAILED = -1;
48 constexpr int32_t RELOAD_FORM_FAILED = -1;
49 constexpr int32_t RECYCLE_FORM_FAILED = -1;
50 constexpr size_t THREAD_BLOCK_TIMEOUT = 10 * 1000;
51 constexpr int32_t MEMORY_MONITOR_INTERVAL = Constants::MS_PER_DAY * 3;
52 constexpr size_t RUNTIME_MEMORY_LIMIT = 16 * 1024 * 1024;
53 constexpr int32_t SET_VISIBLE_CHANGE_FAILED = -1;
54 constexpr int32_t CHECK_THREAD_TIME = 3;
55 constexpr size_t THREAD_NAME_LEN = 15;
56 constexpr char FORM_RENDERER_COMP_ID[] = "ohos.extra.param.key.form_comp_id";
57 constexpr char FORM_RENDERER_PROCESS_ON_ADD_SURFACE[] = "ohos.extra.param.key.process_on_add_surface";
58 constexpr char RENDERING_BLOCK_MONITOR_PREFIX[] = "RenderingBlockMonitorTask_";
59 constexpr char MEMORY_MONITOR_PREFIX[] = "MemoryMonitorTask_";
60
GetThreadNameByBundle(const std::string & bundleName)61 inline std::string GetThreadNameByBundle(const std::string &bundleName)
62 {
63 if (bundleName.length() <= THREAD_NAME_LEN) {
64 return bundleName;
65 }
66 return bundleName.substr(bundleName.length() - THREAD_NAME_LEN);
67 }
68
GetPss()69 uint64_t GetPss()
70 {
71 pid_t pid = getprocpid();
72 std::string filePath = "/proc/" + std::to_string(pid) + "/smaps_rollup";
73 std::ifstream file(filePath);
74 if (!file.is_open()) {
75 HILOG_ERROR("pid:%{public}d get pss failed", pid);
76 return 0;
77 }
78 std::string line;
79 int64_t pss = 0;
80 int64_t swapPss = 0;
81 while (std::getline(file, line)) {
82 std::istringstream iss(line);
83 std::string key;
84 int64_t value;
85 std::string unit;
86 if (iss >> key >> value >> unit) {
87 if (key == "Pss:") {
88 pss = value;
89 } else if (key == "SwapPss:") {
90 swapPss = value;
91 }
92 }
93 }
94 file.close();
95 return pss + swapPss;
96 }
97 }
98
ThreadState(int32_t maxState)99 ThreadState::ThreadState(int32_t maxState) : maxState_(maxState) {}
100
ResetState()101 void ThreadState::ResetState()
102 {
103 state_ = 0;
104 }
105
NextState()106 void ThreadState::NextState()
107 {
108 state_++;
109 }
110
GetCurrentState()111 int32_t ThreadState::GetCurrentState()
112 {
113 return state_;
114 }
115
IsMaxState()116 bool ThreadState::IsMaxState()
117 {
118 return state_ >= maxState_;
119 }
120
Dump(const std::string & message)121 void HandlerDumper::Dump(const std::string &message)
122 {
123 HILOG_INFO("Message=%{public}s", message.c_str());
124 dumpInfo_ += message;
125 }
126
GetTag()127 std::string HandlerDumper::GetTag()
128 {
129 return "";
130 }
131
GetDumpInfo()132 std::string HandlerDumper::GetDumpInfo()
133 {
134 return dumpInfo_;
135 }
136
Create(const std::string & bundleName,const std::string & uid,bool needMonitored,sptr<IFormSupply> client)137 std::shared_ptr<FormRenderRecord> FormRenderRecord::Create(
138 const std::string &bundleName, const std::string &uid, bool needMonitored, sptr<IFormSupply> client)
139 {
140 HILOG_INFO("bundleName is %{public}s, uid is %{public}s", bundleName.c_str(), uid.c_str());
141 std::shared_ptr<FormRenderRecord> renderRecord = std::make_shared<FormRenderRecord>(bundleName, uid, client);
142 if (!renderRecord) {
143 HILOG_ERROR("Create FormRenderRecord failed");
144 return nullptr;
145 }
146
147 if (!renderRecord->CreateEventHandler(bundleName, needMonitored)) {
148 HILOG_ERROR("CreateEventHandler failed");
149 return nullptr;
150 }
151 return renderRecord;
152 }
153
FormRenderRecord(const std::string & bundleName,const std::string & uid,const sptr<IFormSupply> client)154 FormRenderRecord::FormRenderRecord(
155 const std::string &bundleName, const std::string &uid, const sptr<IFormSupply> client)
156 : bundleName_(bundleName), uid_(uid), formSupplyClient_(client)
157 {
158 HILOG_INFO("bundleName is %{public}s,uid is %{public}s", bundleName.c_str(), uid.c_str());
159 threadState_ = std::make_unique<ThreadState>(CHECK_THREAD_TIME);
160 formSupplyClient_ = client;
161 }
162
~FormRenderRecord()163 FormRenderRecord::~FormRenderRecord()
164 {
165 HILOG_INFO("call");
166 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
167 if (eventHandler == nullptr) {
168 HILOG_WARN("null eventHandler");
169 return;
170 }
171
172 // Some resources need to be deleted in a JS thread
173 auto syncTask = [renderRecord = this]() {
174 if (renderRecord == nullptr) {
175 HILOG_ERROR("null renderRecord");
176 return;
177 }
178 renderRecord->HandleDestroyInJsThread();
179 };
180 eventHandler->PostSyncTask(syncTask, "Destory FormRenderRecord");
181 Release();
182 RemoveWatchDogThreadMonitor();
183 }
184
HandleHostDied(const sptr<IRemoteObject> hostRemoteObj)185 bool FormRenderRecord::HandleHostDied(const sptr<IRemoteObject> hostRemoteObj)
186 {
187 HILOG_INFO("Form host is died,clean resources");
188 std::lock_guard<std::mutex> lock(hostsMapMutex_);
189 for (auto iter = hostsMapForFormId_.begin(); iter != hostsMapForFormId_.end();) {
190 std::unordered_set<sptr<IRemoteObject>, RemoteObjHash> &hosts = iter->second;
191 hosts.erase(hostRemoteObj);
192 if (hosts.empty()) {
193 int64_t formId = iter->first;
194 iter = hostsMapForFormId_.erase(iter);
195 DeleteRendererGroup(formId);
196 } else {
197 ++iter;
198 }
199 }
200 return hostsMapForFormId_.empty();
201 }
202
DeleteRendererGroup(int64_t formId)203 void FormRenderRecord::DeleteRendererGroup(int64_t formId)
204 {
205 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
206 if (eventHandler == nullptr) {
207 HILOG_ERROR("null eventHandler");
208 return;
209 }
210
211 auto task = [weak = weak_from_this(), formId]() {
212 auto renderRecord = weak.lock();
213 if (renderRecord == nullptr) {
214 HILOG_ERROR("null renderRecord");
215 return;
216 }
217
218 renderRecord->HandleDeleteRendererGroup(formId);
219 };
220
221 eventHandler->PostSyncTask(task, "DeleteRendererGroup");
222 }
223
HandleDeleteRendererGroup(int64_t formId)224 void FormRenderRecord::HandleDeleteRendererGroup(int64_t formId)
225 {
226 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
227 formRendererGroupMap_.erase(formId);
228 DeleteFormLocation(formId);
229 }
230
CreateEventHandler(const std::string & bundleName,bool needMonitored)231 bool FormRenderRecord::CreateEventHandler(const std::string &bundleName, bool needMonitored)
232 {
233 HILOG_INFO("call");
234 std::lock_guard<std::recursive_mutex> lock(eventHandlerMutex_);
235 if (eventHandler_) {
236 HILOG_DEBUG("EventHandle is exist,no need to create a new one");
237 return true;
238 }
239 // Create event runner
240 HILOG_INFO("Create eventHandle");
241 if (eventRunner_ == nullptr) {
242 eventRunner_ = EventRunner::Create(GetThreadNameByBundle(bundleName));
243 if (eventRunner_ == nullptr) {
244 HILOG_ERROR("Create event runner Failed");
245 return false;
246 }
247 }
248 // Create event handler
249 eventHandler_ = std::make_shared<EventHandler>(eventRunner_);
250 if (eventHandler_ == nullptr) {
251 HILOG_ERROR("Create event handler failed");
252 return false;
253 }
254
255 if (needMonitored && !hasMonitor_) {
256 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
257 auto task = [thisWeakPtr]() {
258 auto renderRecord = thisWeakPtr.lock();
259 if (renderRecord == nullptr) {
260 HILOG_ERROR("null renderRecord");
261 return;
262 }
263 renderRecord->jsThreadId_ = getproctid();
264 renderRecord->processId_ = getprocpid();
265 HILOG_INFO("Get thread %{public}d and psid %{public}d", renderRecord->jsThreadId_,
266 renderRecord->processId_);
267 };
268 eventHandler_->PostHighPriorityTask(task, "GotJSThreadId");
269
270 hasMonitor_.store(true);
271 AddWatchDogThreadMonitor();
272 }
273
274 return true;
275 }
276
AddWatchDogThreadMonitor()277 void FormRenderRecord::AddWatchDogThreadMonitor()
278 {
279 HILOG_INFO("add watchDog monitor, bundleName is %{public}s, uid is %{public}s",
280 bundleName_.c_str(), uid_.c_str());
281
282 auto threadBlockMonitorTask = [weak = weak_from_this()]() {
283 auto renderRecord = weak.lock();
284 if (renderRecord) {
285 renderRecord->Timer();
286 }
287 };
288 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask(RENDERING_BLOCK_MONITOR_PREFIX + bundleName_,
289 threadBlockMonitorTask, THREAD_BLOCK_TIMEOUT);
290
291 auto memoryMonitorTask = [weak = weak_from_this()]() {
292 auto renderRecord = weak.lock();
293 if (renderRecord) {
294 renderRecord->RuntimeMemoryMonitor();
295 }
296 };
297 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask(MEMORY_MONITOR_PREFIX + bundleName_, memoryMonitorTask,
298 MEMORY_MONITOR_INTERVAL);
299 }
300
RemoveWatchDogThreadMonitor()301 void FormRenderRecord::RemoveWatchDogThreadMonitor()
302 {
303 HILOG_INFO("remove watchDog monitor, bundleName: %{public}s", bundleName_.c_str());
304 OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask(RENDERING_BLOCK_MONITOR_PREFIX + bundleName_);
305 OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask(MEMORY_MONITOR_PREFIX + bundleName_);
306 }
307
OnRenderingBlock(const std::string & bundleName)308 void FormRenderRecord::OnRenderingBlock(const std::string &bundleName)
309 {
310 sptr<IFormSupply> formSupplyClient = GetFormSupplyClient();
311
312 if (formSupplyClient == nullptr) {
313 HILOG_ERROR("null formSupplyClient");
314 return;
315 }
316
317 formSupplyClient->OnRenderingBlock(bundleName);
318 }
319
OnNotifyRefreshForm(const int64_t & formId)320 void FormRenderRecord::OnNotifyRefreshForm(const int64_t &formId)
321 {
322 sptr<IFormSupply> formSupplyClient = GetFormSupplyClient();
323
324 if (formSupplyClient == nullptr) {
325 HILOG_ERROR("null formSupplyClient");
326 return;
327 }
328
329 formSupplyClient->OnNotifyRefreshForm(formId);
330 HILOG_WARN("Without this form:%{public}" PRId64 "", formId);
331 }
332
Timer()333 void FormRenderRecord::Timer()
334 {
335 TaskState taskState = RunTask();
336 if (taskState == TaskState::BLOCK) {
337 HILOG_ERROR("FRS block happened when bundleName is %{public}s, uid is %{public}s",
338 bundleName_.c_str(), uid_.c_str());
339 OHOS::HiviewDFX::DfxDumpCatcher dumplog;
340 std::string traceStr;
341 bool ret = dumplog.DumpCatch(processId_, jsThreadId_, traceStr);
342 if (ret) {
343 HILOG_INFO("Print block form's process id %{public}d and thread %{public}d call stack %{public}s",
344 processId_, jsThreadId_, traceStr.c_str());
345 }
346 FormRenderEventReport::SendBlockFaultEvent(bundleName_, "THREAD_BLOCK_" +
347 std::to_string(THREAD_BLOCK_TIMEOUT) + "ms", traceStr);
348 OnRenderingBlock(bundleName_);
349 }
350 }
351
RunTask()352 TaskState FormRenderRecord::RunTask()
353 {
354 auto eventHandler = GetEventHandler();
355 if (eventHandler == nullptr) {
356 HILOG_DEBUG("null eventHandler when bundleName %{public}s", bundleName_.c_str());
357 return TaskState::NO_RUNNING;
358 }
359
360 std::unique_lock<std::mutex> lock(watchDogMutex_);
361 if (!threadIsAlive_) {
362 threadState_->NextState();
363 HILOG_INFO("FRS block happened with threadState is %{public}d when bundleName is %{public}s",
364 threadState_->GetCurrentState(), bundleName_.c_str());
365 DumpEventHandler();
366 return threadState_->IsMaxState() ? TaskState::BLOCK : TaskState::RUNNING;
367 }
368
369 threadIsAlive_ = false;
370 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
371 auto checkTask = [thisWeakPtr] () {
372 auto renderRecord = thisWeakPtr.lock();
373 if (renderRecord == nullptr) {
374 HILOG_ERROR("null renderRecord");
375 return;
376 }
377
378 renderRecord->MarkThreadAlive();
379 };
380
381 if (eventHandler == nullptr) {
382 return TaskState::NO_RUNNING;
383 }
384
385 if (!eventHandler->PostTask(checkTask, "Watchdog Task", 0, AppExecFwk::EventQueue::Priority::IMMEDIATE)) {
386 HILOG_ERROR("Watchdog checkTask postTask false");
387 }
388
389 return TaskState::RUNNING;
390 }
391
DumpEventHandler()392 void FormRenderRecord::DumpEventHandler()
393 {
394 auto eventHandler = GetEventHandler();
395 if (eventHandler == nullptr) {
396 return;
397 }
398
399 HandlerDumper handlerDumper;
400 eventHandler->Dump(handlerDumper);
401 }
402
MarkThreadAlive()403 void FormRenderRecord::MarkThreadAlive()
404 {
405 std::unique_lock<std::mutex> lock(watchDogMutex_);
406 threadIsAlive_ = true;
407 threadState_->ResetState();
408 }
409
MarkRenderFormTaskDone(int32_t renderType)410 void FormRenderRecord::MarkRenderFormTaskDone(int32_t renderType)
411 {
412 if (renderType == Constants::RENDER_FORM) {
413 renderFormTasksNum--;
414 }
415 }
416
HasRenderFormTask()417 bool FormRenderRecord::HasRenderFormTask()
418 {
419 return renderFormTasksNum > 0;
420 }
421
UpdateRenderRecord(const FormJsInfo & formJsInfo,const Want & want,const sptr<IRemoteObject> hostRemoteObj)422 int32_t FormRenderRecord::UpdateRenderRecord(const FormJsInfo &formJsInfo, const Want &want,
423 const sptr<IRemoteObject> hostRemoteObj)
424 {
425 auto renderType = want.GetIntParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
426 if (renderType == Constants::RENDER_FORM) {
427 // Manager delegate proxy invalid, do not render form
428 if (!CheckManagerDelegateValid(formJsInfo, want)) {
429 return RENDER_FORM_FAILED;
430 }
431 renderFormTasksNum++;
432 bool formIsVisible = want.GetBoolParam(Constants::FORM_IS_VISIBLE, false);
433 RecordFormVisibility(formJsInfo.formId, formIsVisible);
434 }
435 int32_t formLocation = want.GetIntParam(Constants::FORM_LOCATION_KEY, -1);
436 FormLocationInfo location = { formJsInfo.formName, formLocation };
437 RecordFormLocation(formJsInfo.formId, location);
438 {
439 // Some resources need to be initialized in a JS thread
440 if (!CheckEventHandler(true, formJsInfo.isDynamic)) {
441 HILOG_ERROR("null eventHandler_ ");
442 return RENDER_FORM_FAILED;
443 }
444 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
445
446 sptr<IFormSupply> formSupplyClient = GetFormSupplyClient();
447 if (formSupplyClient == nullptr) {
448 HILOG_ERROR("null formSupplyClient");
449 return RENDER_FORM_FAILED;
450 }
451
452 UpdateFormRequest(formJsInfo, want);
453
454 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
455 auto task = [thisWeakPtr, formJsInfo, want, formSupplyClient, renderType]() {
456 auto renderRecord = thisWeakPtr.lock();
457 if (renderRecord == nullptr) {
458 HILOG_ERROR("null renderRecord, formId:%{public}" PRId64, formJsInfo.formId);
459 return;
460 }
461 renderRecord->HandleUpdateInJsThread(formJsInfo, want);
462 renderRecord->MarkRenderFormTaskDone(renderType);
463 FormRenderStatusTaskMgr::GetInstance().OnRenderFormDone(formJsInfo.formId,
464 FormFsmEvent::RENDER_FORM_DONE, formSupplyClient);
465 HILOG_INFO("HandleUpdateInJsThread end");
466 };
467 if (eventHandler == nullptr) {
468 HILOG_ERROR("null eventHandler_ ");
469 return RENDER_FORM_FAILED;
470 }
471 eventHandler->PostTask(task, "UpdateRenderRecord");
472 }
473
474 if (hostRemoteObj == nullptr) {
475 HILOG_WARN("null hostRemoteObj");
476 return ERR_OK;
477 }
478 return AddHostByFormId(formJsInfo.formId, hostRemoteObj);
479 }
480
DeleteRenderRecord(int64_t formId,const std::string & compId,const sptr<IRemoteObject> hostRemoteObj,bool & isRenderGroupEmpty)481 void FormRenderRecord::DeleteRenderRecord(int64_t formId, const std::string &compId,
482 const sptr<IRemoteObject> hostRemoteObj, bool &isRenderGroupEmpty)
483 {
484 // Some resources need to be deleted in a JS thread
485 HILOG_INFO("Delete some resources formId:%{public}" PRId64 ",%{public}s", formId, compId.c_str());
486 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
487 if (eventHandler == nullptr) {
488 HILOG_ERROR("null eventHandler");
489 DeleteFormRequest(formId, compId);
490 RecordFormVisibility(formId, false);
491 return;
492 }
493
494 auto task = [weak = weak_from_this(), formId, compId, &isRenderGroupEmpty]() {
495 auto renderRecord = weak.lock();
496 if (renderRecord == nullptr) {
497 HILOG_ERROR("null renderRecord");
498 return;
499 }
500
501 FormMemoryGuard memoryGuard;
502 isRenderGroupEmpty = renderRecord->HandleDeleteInJsThread(formId, compId);
503 renderRecord->DeleteFormRequest(formId, compId);
504 };
505
506 if (hostRemoteObj != nullptr) {
507 DeleteHostRemoteObjByFormId(formId, hostRemoteObj);
508 }
509 if (eventHandler == nullptr) {
510 return;
511 }
512 eventHandler->PostSyncTask(task, "DeleteRenderRecord");
513 }
514
IsEmpty()515 bool FormRenderRecord::IsEmpty()
516 {
517 bool rendererEmpty = false;
518 bool formRequestsEmpty = false;
519 {
520 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
521 rendererEmpty = formRendererGroupMap_.empty();
522 }
523 {
524 std::lock_guard<std::mutex> lock(formRequestsMutex_);
525 formRequestsEmpty = formRequests_.empty();
526 }
527 return rendererEmpty && formRequestsEmpty;
528 }
529
GetUid() const530 std::string FormRenderRecord::GetUid() const
531 {
532 return uid_;
533 }
534
CreateRuntime(const FormJsInfo & formJsInfo)535 bool FormRenderRecord::CreateRuntime(const FormJsInfo &formJsInfo)
536 {
537 if (runtime_) {
538 HILOG_DEBUG("runtime is exist,no need to create a new one");
539 return true;
540 }
541
542 HILOG_INFO("Create a new runtime");
543 if (eventRunner_ == nullptr) {
544 HILOG_ERROR("null eventRunner_");
545 return false;
546 }
547
548 AbilityRuntime::Runtime::Options options;
549 options.bundleName = formJsInfo.bundleName;
550 options.codePath = Constants::LOCAL_CODE_PATH;
551 BundleInfo bundleInfo;
552 options.eventRunner = eventRunner_;
553 options.hapPath = formJsInfo.jsFormCodePath;
554 options.loadAce = true;
555 options.isBundle = true;
556 options.isUnique = true;
557 options.moduleCheckerDelegate = std::make_shared<FormModuleChecker>();
558
559 SetPkgContextInfoMap(formJsInfo, options);
560
561 runtime_ = AbilityRuntime::Runtime::Create(options);
562 if (runtime_ == nullptr) {
563 HILOG_ERROR("Create runtime Failed");
564 return false;
565 }
566 hapPath_ = formJsInfo.jsFormCodePath;
567 RegisterUncatchableErrorHandler();
568 return true;
569 }
570
UpdateRuntime(const FormJsInfo & formJsInfo)571 bool FormRenderRecord::UpdateRuntime(const FormJsInfo &formJsInfo)
572 {
573 if (IsFormContextExist(formJsInfo)) {
574 HILOG_WARN("context is exist. %{public}s", formJsInfo.bundleName.c_str());
575 return false;
576 }
577 if (!runtime_) {
578 HILOG_ERROR("runtime is not exist. %{public}s", formJsInfo.bundleName.c_str());
579 return false;
580 }
581 std::string moduleName = formJsInfo.moduleName;
582 HILOG_INFO("update runtime for bundle:%{public}s, module %{public}s",
583 formJsInfo.bundleName.c_str(), moduleName.c_str());
584 AbilityRuntime::Runtime::Options options;
585 SetPkgContextInfoMap(formJsInfo, options);
586 auto contextInfo = options.pkgContextInfoJsonStringMap.find(moduleName);
587 if (contextInfo != options.pkgContextInfoJsonStringMap.end()) {
588 auto pkgNameInfo = options.packageNameList.find(moduleName);
589 std::string packageName;
590 if (pkgNameInfo != options.packageNameList.end()) {
591 packageName = pkgNameInfo->second;
592 }
593 if (runtime_->GetLanguage() == AbilityRuntime::Runtime::Language::JS) {
594 (static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).SetPkgContextInfoJson(moduleName, contextInfo->second,
595 packageName);
596 HILOG_INFO("%{public}s load components of new module %{public}s",
597 formJsInfo.bundleName.c_str(), moduleName.c_str());
598 (static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).ReloadFormComponent();
599 }
600 }
601 return true;
602 }
603
SetPkgContextInfoMap(const FormJsInfo & formJsInfo,AbilityRuntime::Runtime::Options & options)604 bool FormRenderRecord::SetPkgContextInfoMap(const FormJsInfo &formJsInfo, AbilityRuntime::Runtime::Options &options)
605 {
606 std::map<std::string, std::string> pkgContextInfoJsonStringMap;
607 for (auto modulePkgNamePair : formJsInfo.modulePkgNameMap) {
608 nlohmann::json moduleInfos = nlohmann::json::parse(modulePkgNamePair.second, nullptr, false);
609 if (moduleInfos.is_discarded()) {
610 HILOG_ERROR("fail parse modulePkgNamePair");
611 continue;
612 }
613 std::string pkgName = "";
614 std::string hapPath = "";
615 if (moduleInfos.contains(Constants::MODULE_PKG_NAME_KEY) &&
616 moduleInfos.at(Constants::MODULE_PKG_NAME_KEY).is_string()) {
617 pkgName = moduleInfos[Constants::MODULE_PKG_NAME_KEY].get<std::string>();
618 options.packageNameList[modulePkgNamePair.first] = pkgName;
619 }
620 if (moduleInfos.contains(Constants::MODULE_HAP_PATH_KEY) &&
621 moduleInfos.at(Constants::MODULE_HAP_PATH_KEY).is_string()) {
622 hapPath = moduleInfos[Constants::MODULE_HAP_PATH_KEY].get<std::string>();
623 pkgContextInfoJsonStringMap[modulePkgNamePair.first] = hapPath;
624 }
625 HILOG_INFO("SetPkgContextInfoMap module:%{public}s, pkgName:%{public}s, hapPath:%{public}s",
626 modulePkgNamePair.first.c_str(), pkgName.c_str(), hapPath.c_str());
627 }
628 if (!pkgContextInfoJsonStringMap.empty()) {
629 HILOG_INFO("set pkgContextInfoJsonStringMap for %{public}s", formJsInfo.bundleName.c_str());
630 options.pkgContextInfoJsonStringMap = pkgContextInfoJsonStringMap;
631 }
632 return true;
633 }
634
SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)635 void FormRenderRecord::SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
636 {
637 if (configuration_) {
638 auto checkConfigItem = {SYSTEM_COLORMODE, SYSTEM_LANGUAGE, SYSTEM_FONT_SIZE_SCALE, SYSTEM_FONT_WEIGHT_SCALE};
639 for (const auto& item: checkConfigItem) {
640 std::string value = config->GetItem(item);
641 if (!value.empty()) {
642 configuration_->AddItem(item, value);
643 }
644 }
645 } else {
646 configuration_ = config;
647 }
648 }
649
GetContext(const FormJsInfo & formJsInfo,const Want & want)650 std::shared_ptr<AbilityRuntime::Context> FormRenderRecord::GetContext(const FormJsInfo &formJsInfo, const Want &want)
651 {
652 {
653 std::lock_guard<std::mutex> lock(contextsMapMutex_);
654 auto iter = contextsMapForModuleName_.find(GenerateContextKey(formJsInfo));
655 if (iter != contextsMapForModuleName_.end()) {
656 if (iter->second == nullptr) {
657 HILOG_WARN("null Context, bundle name is %{public}s", formJsInfo.bundleName.c_str());
658 return nullptr;
659 }
660 auto applicationInfo = iter->second->GetApplicationInfo();
661 if (applicationInfo != nullptr) {
662 uint32_t apiCompatibleVersion = static_cast<uint32_t>(
663 want.GetIntParam(Constants::FORM_COMPATIBLE_VERSION_KEY, 0));
664 if (apiCompatibleVersion != 0) {
665 applicationInfo->apiCompatibleVersion = apiCompatibleVersion;
666 }
667 HILOG_INFO("GetContext bundleName %{public}s, apiCompatibleVersion = %{public}d",
668 formJsInfo.bundleName.c_str(), applicationInfo->apiCompatibleVersion);
669 }
670
671 std::shared_ptr<OHOS::AppExecFwk::Configuration> config = iter->second->GetConfiguration();
672 if (config != nullptr && configuration_ != nullptr) {
673 std::string colorMode = configuration_->GetItem(SYSTEM_COLORMODE);
674 std::string languageTag = configuration_->GetItem(SYSTEM_LANGUAGE);
675 config->AddItem(SYSTEM_COLORMODE, colorMode);
676 config->AddItem(SYSTEM_LANGUAGE, languageTag);
677 }
678 return iter->second;
679 }
680 }
681
682 return CreateContext(formJsInfo, want);
683 }
684
CreateContext(const FormJsInfo & formJsInfo,const Want & want)685 std::shared_ptr<AbilityRuntime::Context> FormRenderRecord::CreateContext(const FormJsInfo &formJsInfo, const Want &want)
686 {
687 HILOG_INFO("Create a new context");
688 auto context = std::make_shared<AbilityRuntime::ContextImpl>();
689 if (context == nullptr) {
690 HILOG_ERROR("Create context failed");
691 return nullptr;
692 }
693
694 context->SetConfiguration(configuration_);
695 AppExecFwk::HapModuleInfo hapModuleInfo;
696 hapModuleInfo.name = formJsInfo.moduleName;
697 hapModuleInfo.hapPath = formJsInfo.jsFormCodePath;
698 hapModuleInfo.compileMode = static_cast<CompileMode>(want.GetIntParam(Constants::FORM_COMPILE_MODE_KEY,
699 static_cast<int32_t>(CompileMode::ES_MODULE)));
700 context->InitHapModuleInfo(hapModuleInfo);
701 auto applicationInfo = std::make_shared<AppExecFwk::ApplicationInfo>();
702 applicationInfo->bundleName = formJsInfo.bundleName;
703 applicationInfo->apiCompatibleVersion = static_cast<uint32_t>(want.GetIntParam(
704 Constants::FORM_COMPATIBLE_VERSION_KEY, 0));
705 applicationInfo->apiTargetVersion = static_cast<int32_t>(want.GetIntParam(
706 Constants::FORM_TARGET_VERSION_KEY, 0));
707 context->SetApplicationInfo(applicationInfo);
708 HILOG_DEBUG("bundleName is %{public}s, moduleName is %{public}s",
709 formJsInfo.bundleName.c_str(), formJsInfo.moduleName.c_str());
710
711 std::lock_guard<std::mutex> lock(contextsMapMutex_);
712 contextsMapForModuleName_.emplace(GenerateContextKey(formJsInfo), context);
713 return context;
714 }
715
GetFormRendererGroup(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)716 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::GetFormRendererGroup(const FormJsInfo &formJsInfo,
717 const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
718 {
719 HILOG_INFO("Get formRendererGroup");
720 if (GetEventHandlerNeedReset()) {
721 return nullptr;
722 }
723 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
724 auto key = formJsInfo.formId;
725 auto iter = formRendererGroupMap_.find(key);
726 if (iter != formRendererGroupMap_.end()) {
727 return iter->second;
728 }
729
730 auto formRendererGroup = CreateFormRendererGroupLock(formJsInfo, context, runtime);
731 if (formRendererGroup != nullptr) {
732 HILOG_INFO("formRendererGroupMap emplace formId:%{public}s", std::to_string(key).c_str());
733 formRendererGroupMap_.emplace(key, formRendererGroup);
734 RecordFormVisibility(key, true);
735 }
736 return formRendererGroup;
737 }
738
CreateFormRendererGroupLock(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)739 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::CreateFormRendererGroupLock(const FormJsInfo &formJsInfo,
740 const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
741 {
742 HILOG_INFO("Create formRendererGroup");
743 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
744 if (eventHandler == nullptr) {
745 return nullptr;
746 }
747 auto formRendererGroup = Ace::FormRendererGroup::Create(context, runtime, eventHandler);
748 if (formRendererGroup == nullptr) {
749 HILOG_ERROR("Create formRendererGroup failed");
750 return nullptr;
751 }
752 return formRendererGroup;
753 }
754
UpdateFormRequest(const FormJsInfo & formJsInfo,const Want & want)755 void FormRenderRecord::UpdateFormRequest(const FormJsInfo &formJsInfo, const Want &want)
756 {
757 auto renderType = want.GetIntParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
758 HILOG_DEBUG("renderType is %{public}d", renderType);
759 if (renderType == Constants::RENDER_FORM) {
760 AddFormRequest(formJsInfo, want);
761 return;
762 }
763
764 std::unordered_map<std::string, Ace::FormRequest> formRequests;
765 if (!GetFormRequestByFormId(formJsInfo.formId, formRequests)) {
766 return;
767 }
768
769 for (const auto &iter : formRequests) {
770 auto formRequest = iter.second;
771 MergeFormData(formRequest, formJsInfo);
772 AddFormRequest(formJsInfo.formId, formRequest);
773 }
774 }
775
HandleUpdateInJsThread(const FormJsInfo & formJsInfo,const Want & want)776 int32_t FormRenderRecord::HandleUpdateInJsThread(const FormJsInfo &formJsInfo, const Want &want)
777 {
778 HILOG_INFO("Update record in js thread, formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
779 bool ret = BeforeHandleUpdateForm(formJsInfo);
780 if (!ret) {
781 HILOG_ERROR("Handle Update Form prepare failed");
782 return ERR_APPEXECFWK_FORM_RUNTIME_FAILED;
783 }
784
785 return HandleUpdateForm(formJsInfo, want);
786 }
787
BeforeHandleUpdateForm(const FormJsInfo & formJsInfo)788 bool FormRenderRecord::BeforeHandleUpdateForm(const FormJsInfo &formJsInfo)
789 {
790 MarkThreadAlive();
791 if (runtime_ == nullptr) {
792 if (!CreateRuntime(formJsInfo)) {
793 HILOG_ERROR("Create runtime failed");
794 return false;
795 }
796 } else {
797 UpdateRuntime(formJsInfo);
798 }
799 return true;
800 }
801
HandleUpdateForm(const FormJsInfo & formJsInfo,const Want & want)802 int32_t FormRenderRecord::HandleUpdateForm(const FormJsInfo &formJsInfo, const Want &want)
803 {
804 auto renderType = want.GetIntParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
805 HILOG_DEBUG("renderType is %{public}d", renderType);
806 if (renderType == Constants::RENDER_FORM) {
807 AddRenderer(formJsInfo, want);
808 return ERR_OK;
809 }
810
811 std::unordered_map<std::string, Ace::FormRequest> formRequests;
812 if (!GetFormRequestByFormId(formJsInfo.formId, formRequests)) {
813 OnNotifyRefreshForm(formJsInfo.formId);
814 return ERR_APPEXECFWK_FORM_NOT_EXIST_FORM_REQUEST;
815 }
816 std::string compMaxId = "0";
817 for (const auto& iter : formRequests) {
818 if (iter.second.compId > compMaxId) {
819 compMaxId = iter.second.compId;
820 }
821 }
822
823 bool isDynamicFormNeedRecover = false;
824 for (const auto& iter : formRequests) {
825 auto formRequest = iter.second;
826 if (!formRequest.hasRelease) {
827 UpdateRenderer(formJsInfo);
828 continue;
829 }
830 if (formJsInfo.isDynamic) {
831 isDynamicFormNeedRecover = true;
832 continue;
833 }
834 if (compMaxId == formRequest.compId) {
835 AddRenderer(formJsInfo, formRequest.want);
836 UpdateFormRequestReleaseState(formJsInfo.formId, formRequest.compId, false);
837 }
838 }
839
840 if (isDynamicFormNeedRecover) {
841 std::string statusData = want.GetStringParam(Constants::FORM_STATUS_DATA);
842 bool isHandleClickEvent = false;
843 HandleRecoverForm(formJsInfo, statusData, isHandleClickEvent);
844 }
845
846 return ERR_OK;
847 }
848
MergeFormData(Ace::FormRequest & formRequest,const FormJsInfo & formJsInfo)849 void FormRenderRecord::MergeFormData(Ace::FormRequest &formRequest, const FormJsInfo &formJsInfo)
850 {
851 FormProviderData formProviderData = FormProviderData(formRequest.formJsInfo.formData, true);
852 nlohmann::json newFormData = formJsInfo.formProviderData.GetData();
853 formProviderData.MergeData(newFormData);
854
855 std::map<std::string, sptr<FormAshmem>> imageMap = formRequest.formJsInfo.imageDataMap;
856 formRequest.formJsInfo = formJsInfo;
857 //if imageDataMap of formJsInfo is empty, do not replace
858 if (formJsInfo.imageDataMap.size() == 0) {
859 formRequest.formJsInfo.imageDataMap = imageMap;
860 }
861 formRequest.formJsInfo.formData = formProviderData.GetDataString();
862 }
863
AddRenderer(const FormJsInfo & formJsInfo,const Want & want)864 void FormRenderRecord::AddRenderer(const FormJsInfo &formJsInfo, const Want &want)
865 {
866 auto context = GetContext(formJsInfo, want);
867 if (context == nullptr) {
868 HILOG_ERROR("Create Context failed");
869 return;
870 }
871
872 auto formRendererGroup = GetFormRendererGroup(formJsInfo, context, runtime_);
873 if (formRendererGroup == nullptr) {
874 HILOG_ERROR("Create formRendererGroup failed");
875 return;
876 }
877 formRendererGroup->AddForm(want, formJsInfo);
878 HILOG_INFO("AddForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
879 }
880
UpdateRenderer(const FormJsInfo & formJsInfo)881 void FormRenderRecord::UpdateRenderer(const FormJsInfo &formJsInfo)
882 {
883 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
884 if (auto search = formRendererGroupMap_.find(formJsInfo.formId);
885 search != formRendererGroupMap_.end()) {
886 auto group = search->second;
887 group->UpdateForm(formJsInfo);
888 HILOG_INFO("UpdateForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
889 } else {
890 HILOG_ERROR("UpdateForm failed:%{public}s", std::to_string(formJsInfo.formId).c_str());
891 }
892 }
893
HandleDeleteInJsThread(int64_t formId,const std::string & compId)894 bool FormRenderRecord::HandleDeleteInJsThread(int64_t formId, const std::string &compId)
895 {
896 HILOG_INFO("Delete some resources in js thread");
897 MarkThreadAlive();
898 {
899 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
900 auto search = formRendererGroupMap_.find(formId);
901 if (search == formRendererGroupMap_.end()) {
902 HILOG_ERROR("invalid FormRendererGroup");
903 return false;
904 }
905 if (!search->second) {
906 HILOG_ERROR("FormRendererGroup was founded but null");
907 return false;
908 }
909 if (!compId.empty()) {
910 search->second->DeleteForm(compId);
911 RecordFormVisibility(formId, false);
912 HILOG_ERROR("HandleDeleteInJsThread compid is %{public}s", compId.c_str());
913 if (search->second->IsFormRequestsEmpty()) {
914 formRendererGroupMap_.erase(formId);
915 DeleteFormLocation(formId);
916 }
917 return false;
918 }
919 search->second->DeleteForm();
920 formRendererGroupMap_.erase(formId);
921 DeleteFormLocation(formId);
922 }
923 RemoveHostByFormId(formId);
924 return true;
925 }
926
CheckEventHandler(bool createThead,bool needMonitored)927 bool FormRenderRecord::CheckEventHandler(bool createThead, bool needMonitored)
928 {
929 if (eventHandler_ == nullptr && createThead) {
930 CreateEventHandler(bundleName_, needMonitored);
931 }
932
933 return eventHandler_ != nullptr;
934 }
935
AddFormRequest(const FormJsInfo & formJsInfo,const Want & want)936 void FormRenderRecord::AddFormRequest(const FormJsInfo &formJsInfo, const Want &want)
937 {
938 auto compId = want.GetStringParam(FORM_RENDERER_COMP_ID);
939 HILOG_INFO("AddFormRequest formId: %{public}s, compId: %{public}s, formJsInfo.formData.size: %{public}zu.",
940 std::to_string(formJsInfo.formId).c_str(),
941 compId.c_str(),
942 formJsInfo.formData.size());
943 if (compId.empty()) {
944 return;
945 }
946
947 std::lock_guard<std::mutex> lock(formRequestsMutex_);
948 Ace::FormRequest formRequest;
949 formRequest.compId = compId;
950 formRequest.want = want;
951 formRequest.want.SetParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
952 formRequest.isDynamic = formJsInfo.isDynamic;
953 formRequest.formJsInfo = formJsInfo;
954 auto iter = formRequests_.find(formJsInfo.formId);
955 if (iter == formRequests_.end()) {
956 std::unordered_map<std::string, Ace::FormRequest> formRequests;
957 formRequests.emplace(compId, formRequest);
958 formRequests_.emplace(formJsInfo.formId, formRequests);
959 return;
960 }
961
962 auto innerIter = iter->second.find(compId);
963 if (innerIter != iter->second.end()) {
964 iter->second.erase(innerIter);
965 }
966 iter->second.emplace(compId, formRequest);
967 }
968
AddFormRequest(int64_t formId,Ace::FormRequest & formRequest)969 void FormRenderRecord::AddFormRequest(int64_t formId, Ace::FormRequest &formRequest)
970 {
971 HILOG_INFO("AddFormRequest by FormRequest formId: %{public}s, compId: %{public}s, formData.size: %{public}zu",
972 std::to_string(formId).c_str(),
973 formRequest.compId.c_str(),
974 formRequest.formJsInfo.formData.size());
975 std::lock_guard<std::mutex> lock(formRequestsMutex_);
976 auto iter = formRequests_.find(formId);
977 if (iter == formRequests_.end()) {
978 std::unordered_map<std::string, Ace::FormRequest> formRequests;
979 formRequests.emplace(formRequest.compId, formRequest);
980 formRequests_.emplace(formId, formRequests);
981 return;
982 }
983
984 auto innerIter = iter->second.find(formRequest.compId);
985 if (innerIter != iter->second.end()) {
986 iter->second.erase(innerIter);
987 }
988 iter->second.emplace(formRequest.compId, formRequest);
989 }
990
DeleteFormRequest(int64_t formId,const std::string & compId)991 void FormRenderRecord::DeleteFormRequest(int64_t formId, const std::string &compId)
992 {
993 bool isRequestEmpty = false;
994 {
995 std::lock_guard<std::mutex> lock(formRequestsMutex_);
996 auto iter = formRequests_.find(formId);
997 if (iter == formRequests_.end()) {
998 HILOG_ERROR("invalid request,formId:%{public}" PRId64, formId);
999 return;
1000 }
1001
1002 if (compId.empty()) {
1003 formRequests_.erase(iter);
1004 isRequestEmpty = true;
1005 } else {
1006 auto innerIter = iter->second.find(compId);
1007 if (innerIter != iter->second.end()) {
1008 iter->second.erase(innerIter);
1009 }
1010 if (iter->second.empty()) {
1011 formRequests_.erase(iter);
1012 isRequestEmpty = true;
1013 }
1014 }
1015 }
1016 if (isRequestEmpty) {
1017 DeleteRecycledFormCompIds(formId);
1018 }
1019 HILOG_INFO("delete request formId:%{public}" PRId64 " compId:%{public}s request empty:%{public}d",
1020 formId, compId.c_str(), isRequestEmpty);
1021 }
1022
UpdateFormRequestReleaseState(int64_t formId,const std::string & compId,bool hasRelease)1023 void FormRenderRecord::UpdateFormRequestReleaseState(
1024 int64_t formId, const std::string &compId, bool hasRelease)
1025 {
1026 HILOG_INFO("Update ReleaseState formId:%{public}" PRId64 ", compId:%{public}s, hasRelease:%{public}d",
1027 formId, compId.c_str(), hasRelease);
1028 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1029 auto iter = formRequests_.find(formId);
1030 if (iter == formRequests_.end()) {
1031 HILOG_ERROR("invalid request,formId:%{public}" PRId64, formId);
1032 return;
1033 }
1034
1035 auto innerIter = iter->second.find(compId);
1036 if (innerIter == iter->second.end()) {
1037 HILOG_ERROR("invalid compId,formId:%{public}" PRId64, formId);
1038 return;
1039 }
1040
1041 for (auto& formRequest : iter->second) {
1042 formRequest.second.hasRelease = hasRelease;
1043 }
1044 }
1045
ReleaseRenderer(int64_t formId,const std::string & compId,bool & isRenderGroupEmpty)1046 void FormRenderRecord::ReleaseRenderer(
1047 int64_t formId, const std::string &compId, bool &isRenderGroupEmpty)
1048 {
1049 HILOG_INFO("Release renderer which formId:%{public}s, compId:%{public}s start.",
1050 std::to_string(formId).c_str(), compId.c_str());
1051 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
1052 if (eventHandler == nullptr) {
1053 HILOG_ERROR("null eventHandler");
1054 return;
1055 }
1056
1057 auto task = [weak = weak_from_this(), formId, compId, &isRenderGroupEmpty]() {
1058 auto renderRecord = weak.lock();
1059 if (renderRecord == nullptr) {
1060 HILOG_ERROR("null renderRecord");
1061 return;
1062 }
1063
1064 FormMemoryGuard memoryGuard;
1065 bool ret = renderRecord->HandleReleaseRendererInJsThread(formId, compId, isRenderGroupEmpty);
1066 if (ret) {
1067 renderRecord->UpdateFormRequestReleaseState(formId, compId, true);
1068 } else {
1069 HILOG_ERROR("release renderer error, skip update state, formId:%{public}" PRId64, formId);
1070 }
1071 };
1072 eventHandler->PostSyncTask(task, "ReleaseRenderer");
1073 }
1074
HandleReleaseRendererInJsThread(int64_t formId,const std::string & compId,bool & isRenderGroupEmpty)1075 bool FormRenderRecord::HandleReleaseRendererInJsThread(
1076 int64_t formId, const std::string &compId, bool &isRenderGroupEmpty)
1077 {
1078 HILOG_INFO("Release renderer which formId:%{public}s, compId:%{public}s in js thread.",
1079 std::to_string(formId).c_str(), compId.c_str());
1080 MarkThreadAlive();
1081 if (compId.empty()) {
1082 HILOG_ERROR("compId empty");
1083 return false;
1084 }
1085
1086 std::pair<std::vector<std::string>, std::string> compIds;
1087 {
1088 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1089 auto search = formRendererGroupMap_.find(formId);
1090 if (search == formRendererGroupMap_.end()) {
1091 HILOG_ERROR("invalid rendererGroup");
1092 return false;
1093 }
1094
1095 if (!search->second) {
1096 HILOG_ERROR("null rendererGroup");
1097 return false;
1098 }
1099
1100 compIds = search->second->GetOrderedAndCurrentCompIds();
1101 search->second->DeleteForm();
1102 formRendererGroupMap_.erase(formId);
1103 DeleteFormLocation(formId);
1104 isRenderGroupEmpty = formRendererGroupMap_.empty();
1105 }
1106 DeleteRecycledFormCompIds(formId);
1107 InsertRecycledFormCompIds(formId, compIds);
1108 return true;
1109 }
1110
Release()1111 void FormRenderRecord::Release()
1112 {
1113 HILOG_INFO("Release runtime and eventHandler");
1114 std::shared_ptr<EventHandler> eventHandler = eventHandler_;
1115 std::shared_ptr<EventRunner> eventRunner = eventRunner_;
1116 {
1117 std::lock_guard<std::recursive_mutex> lock(eventHandlerMutex_);
1118 if (eventHandler_ == nullptr) {
1119 HILOG_INFO("null eventHandler");
1120 return;
1121 }
1122 eventHandler_ = nullptr;
1123 eventRunner_ = nullptr;
1124 }
1125 auto syncTask = [renderRecord = this]() {
1126 if (renderRecord == nullptr) {
1127 HILOG_ERROR("null renderRecord");
1128 return;
1129 }
1130 renderRecord->HandleReleaseInJsThread();
1131 };
1132 eventHandler->PostSyncTask(syncTask, "HandleReleaseInJsThread");
1133 if (eventRunner) {
1134 eventRunner->Stop();
1135 eventRunner.reset();
1136 }
1137
1138 eventHandler.reset();
1139
1140 std::lock_guard<std::mutex> lock(contextsMapMutex_);
1141 contextsMapForModuleName_.clear();
1142 }
1143
HandleReleaseInJsThread()1144 void FormRenderRecord::HandleReleaseInJsThread()
1145 {
1146 if (runtime_) {
1147 runtime_->ForceFullGC();
1148 runtime_.reset();
1149 }
1150 ReleaseHapFileHandle();
1151 }
1152
RecoverFormsByConfigUpdate(std::vector<int64_t> & formIds,const sptr<IFormSupply> & formSupplyClient)1153 void FormRenderRecord::RecoverFormsByConfigUpdate(std::vector<int64_t> &formIds,
1154 const sptr<IFormSupply> &formSupplyClient)
1155 {
1156 if (formSupplyClient == nullptr) {
1157 HILOG_ERROR("null formSupplyClient");
1158 return;
1159 }
1160
1161 if (formIds.empty()) {
1162 HILOG_INFO("empty needRecoverFormIds");
1163 return;
1164 }
1165
1166 formSupplyClient->OnRecoverFormsByConfigUpdate(formIds);
1167 }
1168
ReAddAllRecycledForms(const sptr<IFormSupply> & formSupplyClient)1169 void FormRenderRecord::ReAddAllRecycledForms(const sptr<IFormSupply> &formSupplyClient)
1170 {
1171 HILOG_INFO("ReAdd all recycled forms start");
1172 if (!CheckEventHandler(false, true)) {
1173 HILOG_ERROR("CheckEventHandler failed");
1174 return;
1175 }
1176
1177 std::vector<int64_t> formIds;
1178 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1179 for (const auto& formRequests : formRequests_) {
1180 for (const auto& formRequest : formRequests.second) {
1181 if (!formRequest.second.hasRelease) {
1182 continue;
1183 }
1184
1185 if (formRequest.second.isDynamic) {
1186 formIds.push_back(formRequest.second.formJsInfo.formId);
1187 continue;
1188 }
1189
1190 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1191 auto task = [thisWeakPtr, formJsInfo = formRequest.second.formJsInfo, want = formRequest.second.want]() {
1192 auto renderRecord = thisWeakPtr.lock();
1193 if (renderRecord) {
1194 renderRecord->HandleUpdateInJsThread(formJsInfo, want);
1195 }
1196 };
1197 eventHandler_->PostTask(task, "ReAddAllRecycledForms");
1198 }
1199 }
1200
1201 RecoverFormsByConfigUpdate(formIds, formSupplyClient);
1202
1203 HILOG_INFO("ReAdd all recycled forms end");
1204 }
1205
PostReAddRecycledForms(const FormJsInfo & formJsInfo,const Want & want)1206 void FormRenderRecord::PostReAddRecycledForms(const FormJsInfo &formJsInfo, const Want &want)
1207 {
1208 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1209 auto task = [thisWeakPtr, formJsInfo, newWant = want]() {
1210 auto renderRecord = thisWeakPtr.lock();
1211 if (renderRecord) {
1212 int32_t ret = renderRecord->HandleUpdateInJsThread(formJsInfo, newWant);
1213 if (ret != ERR_OK) {
1214 FormRenderEventReport::SendFormFailedEvent(FormEventName::RELOAD_FORM_FAILED,
1215 formJsInfo.formId,
1216 formJsInfo.bundleName,
1217 formJsInfo.formName,
1218 static_cast<int32_t>(ReloadFormErrorType::RELOAD_FORM_UPDATE_FORM_ERROR),
1219 ret);
1220 }
1221 }
1222 };
1223 if (eventHandler_ == nullptr) {
1224 HILOG_ERROR("null eventHandler_");
1225 return;
1226 }
1227 eventHandler_->PostTask(task, "ReAddRecycledForms");
1228 }
1229
ReAddRecycledForms(const std::vector<FormJsInfo> & formJsInfos)1230 int32_t FormRenderRecord::ReAddRecycledForms(const std::vector<FormJsInfo> &formJsInfos)
1231 {
1232 HILOG_INFO("ReAdd recycled forms start");
1233 if (!CheckEventHandler(false, true)) {
1234 HILOG_ERROR("CheckEventHandler failed");
1235 return ERR_APPEXECFWK_FORM_EVENT_HANDLER_NULL;
1236 }
1237
1238 for (const auto &form : formJsInfos) {
1239 std::unordered_map<std::string, Ace::FormRequest> formRequests;
1240 if (!GetFormRequestByFormId(form.formId, formRequests)) {
1241 continue;
1242 }
1243
1244 for (const auto &formRequest : formRequests) {
1245 if (!formRequest.second.hasRelease) {
1246 continue;
1247 }
1248
1249 UpdateFormRequest(form, formRequest.second.want);
1250 PostReAddRecycledForms(form, formRequest.second.want);
1251 }
1252 }
1253
1254 HILOG_INFO("ReAdd recycled forms end");
1255 return ERR_OK;
1256 }
1257
HandleDestroyInJsThread()1258 void FormRenderRecord::HandleDestroyInJsThread()
1259 {
1260 HILOG_INFO("FormRenderService is exiting, destroy some resources in js thread");
1261 MarkThreadAlive();
1262 {
1263 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1264 formRequests_.clear();
1265 }
1266 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1267 formRendererGroupMap_.clear();
1268 }
1269
ReleaseHapFileHandle()1270 void FormRenderRecord::ReleaseHapFileHandle()
1271 {
1272 HILOG_INFO("ReleaseHapFileHandle:%{public}s", hapPath_.c_str());
1273 if (hapPath_.empty()) {
1274 return;
1275 }
1276
1277 std::string loadFilePath = AbilityBase::ExtractorUtil::GetLoadFilePath(hapPath_);
1278 AbilityBase::ExtractorUtil::DeleteExtractor(loadFilePath);
1279 }
1280
GenerateContextKey(const FormJsInfo & formJsInfo)1281 inline std::string FormRenderRecord::GenerateContextKey(const FormJsInfo &formJsInfo)
1282 {
1283 return formJsInfo.bundleName + ":" + formJsInfo.moduleName;
1284 }
1285
ReloadFormRecord(const std::vector<FormJsInfo> && formJsInfos,const Want & want)1286 int32_t FormRenderRecord::ReloadFormRecord(const std::vector<FormJsInfo> &&formJsInfos, const Want &want)
1287 {
1288 HILOG_INFO("Reload form record");
1289 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
1290 if (eventHandler == nullptr) {
1291 if (!CheckEventHandler(true, true)) {
1292 HILOG_ERROR("null eventHandler");
1293 return ERR_APPEXECFWK_FORM_EVENT_HANDLER_NULL;
1294 }
1295
1296 return ReAddRecycledForms(formJsInfos);
1297 }
1298
1299 if (ReAddIfHapPathChanged(formJsInfos)) {
1300 return ERR_OK;
1301 }
1302
1303 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1304 auto task = [thisWeakPtr, ids = std::forward<decltype(formJsInfos)>(formJsInfos), want]() {
1305 HILOG_DEBUG("HandleReloadFormRecord begin");
1306 auto renderRecord = thisWeakPtr.lock();
1307 if (renderRecord == nullptr) {
1308 HILOG_ERROR("null renderRecord");
1309 return;
1310 }
1311 renderRecord->HandleReloadFormRecord(std::move(ids), want);
1312 };
1313 eventHandler->PostTask(task, "ReloadFormRecord");
1314 return ReAddRecycledForms(formJsInfos);
1315 }
1316
ReAddIfHapPathChanged(const std::vector<FormJsInfo> & formJsInfos)1317 bool FormRenderRecord::ReAddIfHapPathChanged(const std::vector<FormJsInfo> &formJsInfos)
1318 {
1319 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
1320 if (eventHandler == nullptr) {
1321 HILOG_ERROR("null eventHandler");
1322 return false;
1323 }
1324 HILOG_INFO("restart runtime");
1325 auto task = [weak = weak_from_this()]() {
1326 auto renderRecord = weak.lock();
1327 if (renderRecord == nullptr) {
1328 HILOG_ERROR("null renderRecord");
1329 return;
1330 }
1331 FormMemoryGuard memoryGuard;
1332 renderRecord->HandleReleaseAllRendererInJsThread();
1333 };
1334 SetEventHandlerNeedResetFlag(true);
1335 eventHandler->PostSyncTask(task, "ReleaseAllRenderer");
1336 Release();
1337 UpdateAllFormRequest(formJsInfos, true);
1338 SetEventHandlerNeedResetFlag(false);
1339 {
1340 std::lock_guard<std::recursive_mutex> lock(eventHandlerMutex_);
1341 CreateEventHandler(bundleName_, true);
1342 }
1343 return ReAddRecycledForms(formJsInfos) == ERR_OK;
1344 }
1345
HandleReleaseAllRendererInJsThread()1346 void FormRenderRecord::HandleReleaseAllRendererInJsThread()
1347 {
1348 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1349 MarkThreadAlive();
1350 for (const auto& iter : formRendererGroupMap_) {
1351 if (!iter.second) {
1352 HILOG_ERROR("null rendererGroup");
1353 continue;
1354 }
1355 int64_t formId = iter.first;
1356 HILOG_INFO("Release renderer which formId:%{public}" PRId64, formId);
1357 std::pair<std::vector<std::string>, std::string> compIds = iter.second->GetOrderedAndCurrentCompIds();
1358 iter.second->DeleteForm();
1359 DeleteRecycledFormCompIds(formId);
1360 InsertRecycledFormCompIds(formId, compIds);
1361 }
1362 formRendererGroupMap_.clear();
1363 }
1364
UpdateAllFormRequest(const std::vector<FormJsInfo> & formJsInfos,bool hasRelease)1365 void FormRenderRecord::UpdateAllFormRequest(const std::vector<FormJsInfo> &formJsInfos, bool hasRelease)
1366 {
1367 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1368 for (const auto &formJsInfo : formJsInfos) {
1369 auto iter = formRequests_.find(formJsInfo.formId);
1370 if (iter == formRequests_.end()) {
1371 HILOG_ERROR("%{public}" PRId64 " doesn't has formRequest", formJsInfo.formId);
1372 continue;
1373 }
1374 for (auto& formRequestIter : iter->second) {
1375 auto& formRequest = formRequestIter.second;
1376 formRequest.isDynamic = formJsInfo.isDynamic;
1377 formRequest.formJsInfo = formJsInfo;
1378 formRequest.hasRelease = hasRelease;
1379 }
1380 }
1381 }
1382
OnUnlock()1383 int32_t FormRenderRecord::OnUnlock()
1384 {
1385 HILOG_DEBUG("call");
1386 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1387 auto task = [thisWeakPtr]() {
1388 HILOG_DEBUG("HandleOnUnlock begin");
1389 auto renderRecord = thisWeakPtr.lock();
1390 if (renderRecord == nullptr) {
1391 HILOG_ERROR("null renderRecord");
1392 return;
1393 }
1394 renderRecord->HandleOnUnlock();
1395 };
1396 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
1397 if (eventHandler == nullptr) {
1398 HILOG_ERROR("null eventHandler_");
1399 return RENDER_FORM_FAILED;
1400 }
1401 eventHandler->PostTask(task, "OnUnlock");
1402 return ERR_OK;
1403 }
1404
HandleOnUnlock()1405 int32_t FormRenderRecord::HandleOnUnlock()
1406 {
1407 HILOG_INFO("call");
1408 {
1409 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1410 for (auto& formRequests : formRequests_) {
1411 for (auto& formRequestElement : formRequests.second) {
1412 formRequestElement.second.want.SetParam(Constants::FORM_RENDER_STATE, true);
1413 }
1414 }
1415 }
1416 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1417 for (const auto& iter : formRendererGroupMap_) {
1418 if (iter.second) {
1419 iter.second->OnUnlock();
1420 }
1421 }
1422 return ERR_OK;
1423 }
1424
SetVisibleChange(const int64_t & formId,bool isVisible)1425 int32_t FormRenderRecord::SetVisibleChange(const int64_t &formId, bool isVisible)
1426 {
1427 HILOG_INFO("SetVisibleChange, formId:%{public}s", std::to_string(formId).c_str());
1428 RecordFormVisibility(formId, isVisible);
1429 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
1430 if (eventHandler == nullptr) {
1431 HILOG_ERROR("null eventHandler");
1432 return SET_VISIBLE_CHANGE_FAILED;
1433 }
1434 auto task = [thisWeakPtr = weak_from_this(), formId, isVisible]() {
1435 auto renderRecord = thisWeakPtr.lock();
1436 if (renderRecord == nullptr) {
1437 HILOG_ERROR("null renderRecord");
1438 return;
1439 }
1440
1441 renderRecord->HandleSetVisibleChange(formId, isVisible);
1442 };
1443
1444 eventHandler->PostTask(task, "SetVisibleChange");
1445 return ERR_OK;
1446 }
1447
HandleSetVisibleChange(const int64_t & formId,bool isVisible)1448 int32_t FormRenderRecord::HandleSetVisibleChange(const int64_t &formId, bool isVisible)
1449 {
1450 HILOG_INFO("HandleSetVisibleChange begin,formId:%{public}s", std::to_string(formId).c_str());
1451 MarkThreadAlive();
1452
1453 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1454 auto search = formRendererGroupMap_.find(formId);
1455 if (search == formRendererGroupMap_.end()) {
1456 HILOG_ERROR("invalid FormRendererGroup");
1457 return SET_VISIBLE_CHANGE_FAILED;
1458 }
1459 if (!search->second) {
1460 HILOG_ERROR("FormRendererGroup was founded but null");
1461 return SET_VISIBLE_CHANGE_FAILED;
1462 }
1463 search->second->SetVisibleChange(isVisible);
1464 return ERR_OK;
1465 }
1466
HandleReloadFormRecord(const std::vector<FormJsInfo> && formJsInfos,const Want & want)1467 int32_t FormRenderRecord::HandleReloadFormRecord(const std::vector<FormJsInfo> &&formJsInfos, const Want &want)
1468 {
1469 HILOG_INFO("Reload record in js thread");
1470 MarkThreadAlive();
1471 if (runtime_ == nullptr) {
1472 HILOG_ERROR("null runtime_");
1473 return RELOAD_FORM_FAILED;
1474 }
1475 if (runtime_->GetLanguage() == AbilityRuntime::Runtime::Language::JS) {
1476 // In the card upgrade condition, new components may be added and need to be reloaded
1477 HILOG_DEBUG("ReloadFormComponent");
1478 (static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).ReloadFormComponent();
1479 }
1480 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1481 for (auto form : formJsInfos) {
1482 auto search = formRendererGroupMap_.find(form.formId);
1483 if (search == formRendererGroupMap_.end()) {
1484 HILOG_ERROR("invalid FormRendererGroup");
1485 continue;
1486 }
1487 auto group = search->second;
1488 if (!group) {
1489 HILOG_ERROR("null FormRendererGroup");
1490 continue;
1491 }
1492 group->ReloadForm(form);
1493 }
1494 return ERR_OK;
1495 }
1496
FormCount()1497 size_t FormRenderRecord::FormCount()
1498 {
1499 return formRequests_.size();
1500 }
1501
UpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config,const sptr<IFormSupply> & formSupplyClient)1502 void FormRenderRecord::UpdateConfiguration(
1503 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config, const sptr<IFormSupply> &formSupplyClient)
1504 {
1505 HILOG_INFO("UpdateConfiguration begin");
1506 if (!config) {
1507 HILOG_ERROR("UpdateConfiguration failed due to null config");
1508 return;
1509 }
1510
1511 SetConfiguration(config);
1512 std::lock_guard<std::recursive_mutex> lock(eventHandlerMutex_);
1513 if (eventHandler_ == nullptr) {
1514 if (!CheckEventHandler(true, true)) {
1515 HILOG_ERROR("null eventHandler");
1516 return;
1517 }
1518
1519 ReAddAllRecycledForms(formSupplyClient);
1520 return;
1521 }
1522
1523 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1524 auto task = [thisWeakPtr, config]() {
1525 auto renderRecord = thisWeakPtr.lock();
1526 if (renderRecord == nullptr) {
1527 HILOG_ERROR("null renderRecord");
1528 return;
1529 }
1530 renderRecord->HandleUpdateConfiguration(config);
1531 };
1532
1533 eventHandler_->PostTask(task, "UpdateConfiguration");
1534 ReAddAllRecycledForms(formSupplyClient);
1535 }
1536
HandleUpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)1537 void FormRenderRecord::HandleUpdateConfiguration(
1538 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
1539 {
1540 HILOG_INFO("HandleUpdateConfiguration begin");
1541 MarkThreadAlive();
1542 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1543 if (!config) {
1544 HILOG_ERROR("null configuration");
1545 return;
1546 }
1547
1548 for (auto iter = formRendererGroupMap_.begin(); iter != formRendererGroupMap_.end(); ++iter) {
1549 if (iter->second) {
1550 iter->second->UpdateConfiguration(config);
1551 }
1552 }
1553 }
1554
FormRenderGC()1555 void FormRenderRecord::FormRenderGC()
1556 {
1557 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1558 auto task = [thisWeakPtr]() {
1559 auto renderRecord = thisWeakPtr.lock();
1560 if (renderRecord == nullptr) {
1561 HILOG_ERROR("null renderRecord");
1562 return;
1563 }
1564 renderRecord->HandleFormRenderGC();
1565 };
1566 if (eventHandler_ == nullptr) {
1567 HILOG_ERROR("null eventHandler_");
1568 return;
1569 }
1570 eventHandler_->PostSyncTask(task, "HandleFormRenderGC");
1571 }
1572
HandleFormRenderGC()1573 void FormRenderRecord::HandleFormRenderGC()
1574 {
1575 HILOG_INFO("HandleFormRenderGC");
1576 if (runtime_ == nullptr) {
1577 HILOG_ERROR("null runtime_");
1578 return;
1579 }
1580 panda::JSNApi::HintGC((static_cast<AbilityRuntime::JsRuntime&>(*runtime_)).GetEcmaVm(),
1581 panda::JSNApi::MemoryReduceDegree::MIDDLE, panda::ecmascript::GCReason::EXTERNAL_TRIGGER);
1582 }
1583
RecycleForm(const int64_t & formId,std::string & statusData)1584 int32_t FormRenderRecord::RecycleForm(const int64_t &formId, std::string &statusData)
1585 {
1586 HILOG_INFO("RecycleForm begin, formId:%{public}s", std::to_string(formId).c_str());
1587 int32_t result = RECYCLE_FORM_FAILED;
1588 if (!CheckEventHandler(true, true)) {
1589 HILOG_ERROR("null eventHandler_");
1590 return RENDER_FORM_FAILED;
1591 }
1592
1593 auto task = [thisWeakPtr = weak_from_this(), formId, &statusData, &result]() {
1594 auto renderRecord = thisWeakPtr.lock();
1595 if (renderRecord == nullptr) {
1596 HILOG_ERROR("null renderRecord");
1597 return;
1598 }
1599
1600 result = renderRecord->HandleRecycleForm(formId, statusData);
1601 };
1602 eventHandler_->PostSyncTask(task, "RecycleForm");
1603 return result;
1604 }
1605
HandleRecycleForm(const int64_t & formId,std::string & statusData)1606 int32_t FormRenderRecord::HandleRecycleForm(const int64_t &formId, std::string &statusData)
1607 {
1608 HILOG_INFO("HandleRecycleForm begin,formId:%{public}s", std::to_string(formId).c_str());
1609 MarkThreadAlive();
1610
1611 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1612 auto search = formRendererGroupMap_.find(formId);
1613 if (search == formRendererGroupMap_.end()) {
1614 HILOG_ERROR("invalid FormRendererGroup");
1615 return RECYCLE_FORM_FAILED;
1616 }
1617 if (!search->second) {
1618 HILOG_ERROR("FormRendererGroup was founded but null");
1619 return RECYCLE_FORM_FAILED;
1620 }
1621
1622 search->second->RecycleForm(statusData);
1623 return ERR_OK;
1624 }
1625
RecoverForm(const FormJsInfo & formJsInfo,const std::string & statusData,const bool & isRecoverFormToHandleClickEvent)1626 int32_t FormRenderRecord::RecoverForm(const FormJsInfo &formJsInfo,
1627 const std::string &statusData, const bool &isRecoverFormToHandleClickEvent)
1628 {
1629 auto formId = formJsInfo.formId;
1630 HILOG_INFO("RecoverForm begin, formId:%{public}s", std::to_string(formId).c_str());
1631 if (!CheckEventHandler(true, true)) {
1632 HILOG_ERROR("null eventHandler_");
1633 return RENDER_FORM_FAILED;
1634 }
1635 std::shared_ptr<EventHandler> eventHandler = GetEventHandler();
1636
1637 sptr<IFormSupply> formSupplyClient = GetFormSupplyClient();
1638 if (formSupplyClient == nullptr) {
1639 HILOG_ERROR("null formSupplyClient");
1640 return RENDER_FORM_FAILED;
1641 }
1642
1643 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
1644 auto task = [thisWeakPtr, formJsInfo, statusData, isRecoverFormToHandleClickEvent, formSupplyClient]() {
1645 auto renderRecord = thisWeakPtr.lock();
1646 if (renderRecord == nullptr) {
1647 HILOG_ERROR("renderRecord");
1648 return;
1649 }
1650 renderRecord->HandleRecoverForm(formJsInfo, statusData, isRecoverFormToHandleClickEvent);
1651 FormRenderStatusTaskMgr::GetInstance().OnRecoverFormDone(formJsInfo.formId,
1652 FormFsmEvent::RECOVER_FORM_DONE, formSupplyClient);
1653 };
1654 if (eventHandler == nullptr) {
1655 HILOG_ERROR("null eventHandler_ ");
1656 return RENDER_FORM_FAILED;
1657 }
1658 eventHandler->PostTask(task, "RecoverForm");
1659 return ERR_OK;
1660 }
1661
HandleRecoverForm(const FormJsInfo & formJsInfo,const std::string & statusData,const bool & isHandleClickEvent)1662 void FormRenderRecord::HandleRecoverForm(const FormJsInfo &formJsInfo,
1663 const std::string &statusData, const bool &isHandleClickEvent)
1664 {
1665 auto formId = formJsInfo.formId;
1666 HILOG_INFO("HandleRecoverForm begin, formId:%{public}s, uid:%{public}s", std::to_string(formId).c_str(),
1667 uid_.c_str());
1668 std::unordered_map<std::string, Ace::FormRequest> formRequests;
1669 if (!GetFormRequestByFormId(formId, formRequests)) {
1670 HILOG_ERROR("not find formRequests");
1671 return;
1672 }
1673 if (formRequests.empty()) {
1674 HILOG_ERROR("empty formRequests");
1675 return;
1676 }
1677
1678 if (!BeforeHandleUpdateForm(formRequests.begin()->second.formJsInfo)) {
1679 HILOG_ERROR("recover form prepare failed");
1680 return;
1681 }
1682
1683 RecoverFormRequestsInGroup(formJsInfo, statusData, isHandleClickEvent, formRequests);
1684 }
1685
GetAndDeleteRecycledCompIds(const int64_t & formId,std::vector<std::string> & orderedCompIds,std::string & currentCompId)1686 bool FormRenderRecord::GetAndDeleteRecycledCompIds(const int64_t &formId,
1687 std::vector<std::string> &orderedCompIds, std::string ¤tCompId)
1688 {
1689 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
1690 auto pairIter = recycledFormCompIds_.find(formId);
1691 if (pairIter == recycledFormCompIds_.end()) {
1692 HILOG_ERROR("invalid compIdPair,formId:%{public}" PRId64, formId);
1693 return false;
1694 }
1695 orderedCompIds = pairIter->second.first;
1696 currentCompId = pairIter->second.second;
1697 recycledFormCompIds_.erase(formId);
1698 HILOG_INFO("compIds size:%{public}zu,currentCompId:%{public}s,formId:%{public}" PRId64,
1699 orderedCompIds.size(), currentCompId.c_str(), formId);
1700 return true;
1701 }
1702
RecoverFormRequestsInGroup(const FormJsInfo & formJsInfo,const std::string & statusData,const bool & isHandleClickEvent,std::unordered_map<std::string,Ace::FormRequest> & recordFormRequests)1703 bool FormRenderRecord::RecoverFormRequestsInGroup(const FormJsInfo &formJsInfo, const std::string &statusData,
1704 const bool &isHandleClickEvent, std::unordered_map<std::string, Ace::FormRequest> &recordFormRequests)
1705 {
1706 auto formId = formJsInfo.formId;
1707 std::vector<std::string> orderedCompIds;
1708 std::string currentCompId;
1709 bool flag = GetAndDeleteRecycledCompIds(formId, orderedCompIds, currentCompId);
1710 if (!flag) {
1711 HILOG_ERROR("init compIds failed,formId:%{public}" PRId64, formId);
1712 return false;
1713 }
1714
1715 std::vector<Ace::FormRequest> groupRequests;
1716 size_t currentRequestIndex = 0;
1717 bool currentRequestFound = false;
1718 if (!GetFormRequestByFormId(formId, recordFormRequests)) {
1719 HILOG_ERROR("find formRequest failed,formId:%{public}" PRId64, formId);
1720 return false;
1721 }
1722
1723 UpdateGroupRequestsWhenRecover(formId, formJsInfo, orderedCompIds, currentCompId, statusData, isHandleClickEvent,
1724 currentRequestIndex, groupRequests, currentRequestFound, recordFormRequests);
1725
1726 if (groupRequests.empty()) {
1727 HILOG_ERROR("group requests empty formId:%{public}" PRId64, formId);
1728 return false;
1729 }
1730
1731 if (!currentRequestFound) {
1732 // maybe current comp deleted between recover, get last comp as new current comp to recover
1733 currentRequestIndex = groupRequests.size() - 1;
1734 HILOG_WARN("current request index:%{public}zu formId:%{public}" PRId64, currentRequestIndex, formId);
1735 }
1736 bool success = RecoverRenderer(groupRequests, currentRequestIndex);
1737 if (success) {
1738 UpdateFormRequestReleaseState(formId, currentCompId, false);
1739 }
1740 return success;
1741 }
1742
UpdateGroupRequestsWhenRecover(const int64_t & formId,const FormJsInfo & formJsInfo,const std::vector<std::string> & orderedCompIds,const std::string & currentCompId,const std::string & statusData,const bool & isHandleClickEvent,size_t & currentRequestIndex,std::vector<Ace::FormRequest> & groupRequests,bool & currentRequestFound,const std::unordered_map<std::string,Ace::FormRequest> & recordFormRequests)1743 void FormRenderRecord::UpdateGroupRequestsWhenRecover(const int64_t &formId, const FormJsInfo &formJsInfo,
1744 const std::vector<std::string> &orderedCompIds, const std::string ¤tCompId, const std::string &statusData,
1745 const bool &isHandleClickEvent, size_t ¤tRequestIndex, std::vector<Ace::FormRequest> &groupRequests,
1746 bool ¤tRequestFound, const std::unordered_map<std::string, Ace::FormRequest> &recordFormRequests)
1747 {
1748 std::set<std::string> groupCompIds;
1749 for (auto compId : orderedCompIds) {
1750 auto recordRequestIter = recordFormRequests.find(compId);
1751 if (recordRequestIter == recordFormRequests.end()) {
1752 HILOG_WARN("invalid formRequest,formId:%{public}" PRId64 " compId=%{public}s", formId, compId.c_str());
1753 continue;
1754 }
1755 if (groupCompIds.find(compId) != groupCompIds.end()) {
1756 continue;
1757 }
1758 groupCompIds.insert(compId);
1759 auto& recordRequest = recordRequestIter->second;
1760 Ace::FormRequest groupRequest;
1761 groupRequest.compId = compId;
1762 groupRequest.want = recordRequest.want;
1763 groupRequest.formJsInfo = recordRequest.formJsInfo; // get json data from record request
1764 MergeMap(groupRequest.formJsInfo.imageDataMap, formJsInfo.imageDataMap);
1765 if (compId == currentCompId) {
1766 groupRequest.want.SetParam(Constants::FORM_STATUS_DATA, statusData);
1767 groupRequest.want.SetParam(Constants::FORM_IS_RECOVER_FORM_TO_HANDLE_CLICK_EVENT, isHandleClickEvent);
1768 currentRequestIndex = groupRequests.size();
1769 currentRequestFound = true;
1770 HILOG_INFO("currentRequestIndex: %{public}zu, formData.size: %{public}zu",
1771 currentRequestIndex, groupRequest.formJsInfo.formData.size());
1772 }
1773 groupRequests.emplace_back(groupRequest);
1774 }
1775 }
1776
MergeMap(std::map<std::string,sptr<FormAshmem>> & dst,const std::map<std::string,sptr<FormAshmem>> & src)1777 void FormRenderRecord::MergeMap(std::map<std::string, sptr<FormAshmem>> &dst,
1778 const std::map<std::string, sptr<FormAshmem>> &src)
1779 {
1780 for (auto iter = src.begin(); iter != src.end(); ++iter) {
1781 auto search = dst.find(iter->first);
1782 if (search == dst.end()) {
1783 dst.emplace(*iter);
1784 } else {
1785 search->second = iter->second;
1786 }
1787 }
1788 }
1789
RecoverRenderer(const std::vector<Ace::FormRequest> & groupRequests,const size_t & currentRequestIndex)1790 bool FormRenderRecord::RecoverRenderer(const std::vector<Ace::FormRequest> &groupRequests,
1791 const size_t ¤tRequestIndex)
1792 {
1793 if (currentRequestIndex >= groupRequests.size()) {
1794 HILOG_ERROR("current comp index %{public}zu invalid", currentRequestIndex);
1795 return false;
1796 }
1797 auto currentRequest = groupRequests[currentRequestIndex];
1798 auto context = GetContext(currentRequest.formJsInfo, currentRequest.want);
1799 if (context == nullptr) {
1800 HILOG_ERROR("Create Context failed");
1801 return false;
1802 }
1803
1804 auto formRendererGroup = GetFormRendererGroup(currentRequest.formJsInfo, context, runtime_);
1805 if (formRendererGroup == nullptr) {
1806 HILOG_ERROR("Create formRendererGroup failed");
1807 return false;
1808 }
1809 auto task = [formRendererGroup, groupRequests, currentRequestIndex]() {
1810 HILOG_INFO("execute recover form task");
1811 formRendererGroup->RecoverRenderer(groupRequests, currentRequestIndex);
1812 };
1813 // the formrenderer_ must be initialized using a sync task
1814 eventHandler_->PostSyncTask(task, "RecoverRenderer");
1815 HILOG_INFO("recover renderer, formId:%{public}" PRId64, currentRequest.formJsInfo.formId);
1816 return true;
1817 }
1818
UpdateFormSizeOfGroups(const int64_t & formId,float width,float height,float borderWidth)1819 void FormRenderRecord::UpdateFormSizeOfGroups(const int64_t &formId, float width, float height, float borderWidth)
1820 {
1821 {
1822 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1823 auto iter = formRequests_.find(formId);
1824 if (iter == formRequests_.end()) {
1825 HILOG_ERROR("%{public}s doesn't has formRequest", std::to_string(formId).c_str());
1826 return;
1827 }
1828 if (iter->second.empty()) {
1829 HILOG_ERROR("empty formRequests");
1830 return;
1831 }
1832
1833 HILOG_INFO("formRequests length: %{public}zu formId: %{public}" PRId64 " width: %{public}f height: %{public}f"
1834 " borderWidth: %{public}f", iter->second.size(), formId, width, height, borderWidth);
1835 for (auto& formRequestIter : iter->second) {
1836 formRequestIter.second.want.SetParam(
1837 OHOS::AppExecFwk::Constants::PARAM_FORM_WIDTH_KEY, static_cast<double>(width));
1838 formRequestIter.second.want.SetParam(
1839 OHOS::AppExecFwk::Constants::PARAM_FORM_HEIGHT_KEY, static_cast<double>(height));
1840 formRequestIter.second.want.SetParam(
1841 OHOS::AppExecFwk::Constants::PARAM_FORM_BORDER_WIDTH_KEY, static_cast<float>(borderWidth));
1842 }
1843 }
1844
1845 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1846 auto search = formRendererGroupMap_.find(formId);
1847 if (search != formRendererGroupMap_.end()) {
1848 auto group = search->second;
1849 group->UpdateFormSizeOfFormRequests(width, height, borderWidth);
1850 }
1851 }
1852
CheckManagerDelegateValid(const FormJsInfo & formJsInfo,const Want & want)1853 bool FormRenderRecord::CheckManagerDelegateValid(const FormJsInfo &formJsInfo, const Want &want)
1854 {
1855 HILOG_DEBUG("call");
1856 if (!want.HasParameter(FORM_RENDERER_PROCESS_ON_ADD_SURFACE)) {
1857 HILOG_INFO("not add surface, ingore it");
1858 return true;
1859 }
1860
1861 auto context = GetContext(formJsInfo, want);
1862 if (context == nullptr) {
1863 return true;
1864 }
1865
1866 {
1867 std::shared_lock<std::shared_mutex> lock(eventHandlerReset_);
1868 if (eventHandleNeedReset) {
1869 return true;
1870 }
1871 }
1872 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
1873 auto key = formJsInfo.formId;
1874 auto iter = formRendererGroupMap_.find(key);
1875 if (iter == formRendererGroupMap_.end() || iter->second == nullptr) {
1876 return true;
1877 }
1878
1879 return iter->second->IsManagerDelegateValid(want);
1880 }
1881
SetFormSupplyClient(const sptr<IFormSupply> & formSupplyClient)1882 void FormRenderRecord::SetFormSupplyClient(const sptr<IFormSupply> &formSupplyClient)
1883 {
1884 std::lock_guard<std::mutex> lock(formSupplyMutex_);
1885 formSupplyClient_ = formSupplyClient;
1886 }
1887
GetFormSupplyClient()1888 sptr<IFormSupply> FormRenderRecord::GetFormSupplyClient()
1889 {
1890 std::lock_guard<std::mutex> lock(formSupplyMutex_);
1891 return formSupplyClient_;
1892 }
1893
GetEventHandler()1894 std::shared_ptr<EventHandler> FormRenderRecord::GetEventHandler()
1895 {
1896 std::lock_guard<std::recursive_mutex> lock(eventHandlerMutex_);
1897 return eventHandler_;
1898 }
1899
AddHostByFormId(int64_t formId,const sptr<IRemoteObject> hostRemoteObj)1900 int32_t FormRenderRecord::AddHostByFormId(int64_t formId, const sptr<IRemoteObject> hostRemoteObj)
1901 {
1902 std::lock_guard<std::mutex> lock(hostsMapMutex_);
1903 auto iter = hostsMapForFormId_.find(formId);
1904 if (iter == hostsMapForFormId_.end()) {
1905 hostsMapForFormId_.emplace(formId, IRemoteObjectSet({hostRemoteObj}));
1906 return ERR_OK;
1907 }
1908 iter->second.emplace(hostRemoteObj);
1909 return ERR_OK;
1910 }
1911
DeleteHostRemoteObjByFormId(int64_t formId,const sptr<IRemoteObject> hostRemoteObj)1912 void FormRenderRecord::DeleteHostRemoteObjByFormId(int64_t formId, const sptr<IRemoteObject> hostRemoteObj)
1913 {
1914 std::lock_guard<std::mutex> lock(hostsMapMutex_);
1915 auto iter = hostsMapForFormId_.find(formId);
1916 if (iter != hostsMapForFormId_.end()) {
1917 std::unordered_set<sptr<IRemoteObject>, RemoteObjHash> &hosts = iter->second;
1918 hosts.erase(hostRemoteObj);
1919 }
1920 }
1921
RemoveHostByFormId(int64_t formId)1922 void FormRenderRecord::RemoveHostByFormId(int64_t formId)
1923 {
1924 std::lock_guard<std::mutex> lock(hostsMapMutex_);
1925 hostsMapForFormId_.erase(formId);
1926 }
1927
IsFormContextExist(const FormJsInfo & formJsInfo)1928 bool FormRenderRecord::IsFormContextExist(const FormJsInfo &formJsInfo)
1929 {
1930 std::lock_guard<std::mutex> lock(contextsMapMutex_);
1931 auto moduleInfo = contextsMapForModuleName_.find(GenerateContextKey(formJsInfo));
1932 return moduleInfo != contextsMapForModuleName_.end();
1933 }
1934
GetFormRequestByFormId(int64_t formId,std::unordered_map<std::string,Ace::FormRequest> & formRequests)1935 bool FormRenderRecord::GetFormRequestByFormId(
1936 int64_t formId, std::unordered_map<std::string, Ace::FormRequest> &formRequests)
1937 {
1938 std::lock_guard<std::mutex> lock(formRequestsMutex_);
1939 auto iter = formRequests_.find(formId);
1940 if (iter == formRequests_.end()) {
1941 HILOG_WARN("not find form request,formId:%{public}" PRId64, formId);
1942 return false;
1943 }
1944
1945 formRequests = iter->second;
1946 return true;
1947 }
1948
SetEventHandlerNeedResetFlag(bool needReset)1949 void FormRenderRecord::SetEventHandlerNeedResetFlag(bool needReset)
1950 {
1951 std::lock_guard<std::shared_mutex> lock(eventHandlerReset_);
1952 HILOG_INFO("eventHandleNeedReset: %{public}d", needReset);
1953 eventHandleNeedReset = needReset;
1954 }
1955
GetEventHandlerNeedReset()1956 bool FormRenderRecord::GetEventHandlerNeedReset()
1957 {
1958 std::lock_guard<std::shared_mutex> lock(eventHandlerReset_);
1959 HILOG_INFO("eventHandleNeedReset: %{public}d", eventHandleNeedReset);
1960 return eventHandleNeedReset;
1961 }
1962
DeleteRecycledFormCompIds(int64_t formId)1963 void FormRenderRecord::DeleteRecycledFormCompIds(int64_t formId)
1964 {
1965 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
1966 recycledFormCompIds_.erase(formId);
1967 }
1968
InsertRecycledFormCompIds(int64_t formId,const std::pair<std::vector<std::string>,std::string> & compIds)1969 void FormRenderRecord::InsertRecycledFormCompIds(
1970 int64_t formId, const std::pair<std::vector<std::string>, std::string> &compIds)
1971 {
1972 std::lock_guard<std::mutex> lock(recycledFormCompIdsMutex_);
1973 recycledFormCompIds_.emplace(formId, compIds);
1974 }
1975
RegisterUncatchableErrorHandler()1976 void FormRenderRecord::RegisterUncatchableErrorHandler()
1977 {
1978 auto nativeEnginePtr = (static_cast<AbilityRuntime::JsRuntime &>(*runtime_)).GetNativeEnginePointer();
1979 if (nativeEnginePtr == nullptr) {
1980 HILOG_ERROR("null nativeEnginePtr");
1981 return;
1982 }
1983 auto uncatchableTask = [weak = weak_from_this()](panda::TryCatch &trycatch) {
1984 auto renderRecord = weak.lock();
1985 if (renderRecord == nullptr) {
1986 HILOG_ERROR("null renderRecord");
1987 return;
1988 }
1989 auto exception = trycatch.GetAndClearException();
1990 if (!exception.IsEmpty() && !exception->IsHole()) {
1991 napi_value obj = reinterpret_cast<napi_value>(*exception);
1992 renderRecord->OnJsError(obj);
1993 }
1994 };
1995 panda::JSNApi::RegisterUncatchableErrorHandler(const_cast<EcmaVM *>(nativeEnginePtr->GetEcmaVm()), uncatchableTask);
1996 }
1997
OnJsError(napi_value value)1998 void FormRenderRecord::OnJsError(napi_value value)
1999 {
2000 HILOG_ERROR("call, bundleName: %{public}s", bundleName_.c_str());
2001 std::string errorName = GetNativeStrFromJsTaggedObj(value, "name");
2002 std::string errorMsg = GetNativeStrFromJsTaggedObj(value, "message");
2003 std::string stack = GetNativeStrFromJsTaggedObj(value, "stack");
2004 std::string errorCode = GetNativeStrFromJsTaggedObj(value, "code");
2005 std::string summary = "Error name:" + errorName + "\n" + "Error message:" + errorMsg + "\n";
2006 if (!errorCode.empty()) {
2007 summary += "Error code:" + errorCode + "\n";
2008 }
2009 HILOG_ERROR("summary: %{public}s", summary.c_str());
2010 HILOG_ERROR("stack: %{public}s", stack.c_str());
2011 FormRenderEventReport::SendBlockFaultEvent(bundleName_, summary, stack);
2012 }
2013
GetNativeStrFromJsTaggedObj(napi_value obj,const char * key)2014 std::string FormRenderRecord::GetNativeStrFromJsTaggedObj(napi_value obj, const char* key)
2015 {
2016 if (obj == nullptr) {
2017 HILOG_ERROR("get value failed");
2018 return "";
2019 }
2020
2021 napi_value valueStr = nullptr;
2022 napi_env env = (static_cast<AbilityRuntime::JsRuntime &>(*runtime_)).GetNapiEnv();
2023 bool hasProperty = false;
2024 napi_has_named_property(env, obj, key, &hasProperty);
2025 if (!hasProperty) {
2026 return "";
2027 }
2028 napi_get_named_property(env, obj, key, &valueStr);
2029 napi_valuetype valueType = napi_undefined;
2030 napi_typeof(env, valueStr, &valueType);
2031 if (valueType != napi_string) {
2032 HILOG_ERROR("convert value failed");
2033 return "";
2034 }
2035
2036 size_t valueStrBufLength = 0;
2037 napi_get_value_string_utf8(env, valueStr, nullptr, 0, &valueStrBufLength);
2038 auto valueCStr = std::make_unique<char[]>(valueStrBufLength + 1);
2039 size_t valueStrLength = 0;
2040 napi_get_value_string_utf8(env, valueStr, valueCStr.get(), valueStrBufLength + 1, &valueStrLength);
2041 std::string ret(valueCStr.get(), valueStrLength);
2042 return ret;
2043 }
2044
IsAllFormsInvisible()2045 bool FormRenderRecord::IsAllFormsInvisible()
2046 {
2047 std::lock_guard<std::mutex> lock(visibilityMapMutex_);
2048 return visibilityMap_.empty();
2049 }
2050
RecordFormVisibility(int64_t formId,bool isVisible)2051 void FormRenderRecord::RecordFormVisibility(int64_t formId, bool isVisible)
2052 {
2053 HILOG_INFO("call formId: %{public}" PRId64 ", isVisible: %{public}d", formId, isVisible);
2054 std::lock_guard<std::mutex> lock(visibilityMapMutex_);
2055 if (isVisible) {
2056 visibilityMap_[formId] = isVisible;
2057 } else {
2058 visibilityMap_.erase(formId);
2059 }
2060 }
2061
RecordFormLocation(int64_t formId,const FormLocationInfo & formLocation)2062 void FormRenderRecord::RecordFormLocation(int64_t formId, const FormLocationInfo &formLocation)
2063 {
2064 std::lock_guard<std::mutex> lock(formLocationMutex_);
2065 formLocationMap_[formId] = formLocation;
2066 }
2067
DeleteFormLocation(int64_t formId)2068 void FormRenderRecord::DeleteFormLocation(int64_t formId)
2069 {
2070 std::lock_guard<std::mutex> lock(formLocationMutex_);
2071 formLocationMap_.erase(formId);
2072 }
2073
ParseFormLocationMap(std::vector<std::string> & formName,std::vector<uint32_t> & formLocation)2074 void FormRenderRecord::ParseFormLocationMap(std::vector<std::string> &formName, std::vector<uint32_t> &formLocation)
2075 {
2076 std::lock_guard<std::mutex> lock(formLocationMutex_);
2077 for (const auto &iter : formLocationMap_) {
2078 const FormLocationInfo &locationInfo = iter.second;
2079 formName.emplace_back(locationInfo.formName);
2080 formLocation.emplace_back(locationInfo.formLocation);
2081 }
2082 }
2083
RuntimeMemoryMonitor()2084 void FormRenderRecord::RuntimeMemoryMonitor()
2085 {
2086 if (runtime_ == nullptr || eventHandler_ == nullptr) {
2087 return;
2088 }
2089
2090 auto nativeEnginePtr = (static_cast<AbilityRuntime::JsRuntime &>(*runtime_)).GetNativeEnginePointer();
2091 if (nativeEnginePtr == nullptr) {
2092 HILOG_ERROR("null nativeEnginePtr");
2093 return;
2094 }
2095
2096 size_t totalSize = 0;
2097 size_t usedSize = 0;
2098 size_t objSize = 0;
2099 size_t limitSize = 0;
2100 // GetHeap must be called on the UI thread.
2101 auto task = [nativeEnginePtr, &totalSize, &usedSize, &objSize, &limitSize]() {
2102 totalSize = nativeEnginePtr->GetHeapTotalSize();
2103 usedSize = nativeEnginePtr->GetHeapUsedSize();
2104 objSize = nativeEnginePtr->GetHeapObjectSize();
2105 limitSize = nativeEnginePtr->GetHeapLimitSize();
2106 };
2107 eventHandler_->PostSyncTask(task, "RuntimeMemoryMonitorTask");
2108
2109 uint64_t processMemory = GetPss();
2110 HILOG_INFO("processMemory: %{public}" PRIu64 ", bundleName: %{public}s, totalSize: %{public}zu, "
2111 "usedSize: %{public}zu, objSize: %{public}zu, limitSize: %{public}zu", processMemory, bundleName_.c_str(),
2112 totalSize, usedSize, objSize, limitSize);
2113 if (totalSize > RUNTIME_MEMORY_LIMIT) {
2114 std::vector<std::string> formName;
2115 std::vector<uint32_t> formLocation;
2116 ParseFormLocationMap(formName, formLocation);
2117 FormRenderEventReport::SendRuntimeMemoryLeakEvent(bundleName_, processMemory,
2118 static_cast<uint64_t>(totalSize), formName, formLocation);
2119 }
2120 }
2121 } // namespace FormRender
2122 } // namespace AppExecFwk
2123 } // namespace OHOS