• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utility>
19 
20 #include "form_constants.h"
21 #include "hilog_wrapper.h"
22 
23 namespace OHOS {
24 namespace AppExecFwk {
25 namespace FormRender {
26 constexpr int32_t RENDER_FORM_FAILED = -1;
27 constexpr int32_t RELOAD_FORM_FAILED = -1;
28 
Create(const std::string & bundleName,const std::string & uid)29 std::shared_ptr<FormRenderRecord> FormRenderRecord::Create(const std::string &bundleName, const std::string &uid)
30 {
31     HILOG_INFO("%{public}s called.", __func__);
32     std::shared_ptr<FormRenderRecord> renderRecord = std::make_shared<FormRenderRecord>(bundleName, uid);
33     if (!renderRecord) {
34         HILOG_ERROR("Create FormRenderRecord failed.");
35         return nullptr;
36     }
37 
38     if (!renderRecord->CreateEventHandler(bundleName)) {
39         HILOG_ERROR("CreateEventHandler failed.");
40         return nullptr;
41     }
42     return renderRecord;
43 }
44 
FormRenderRecord(const std::string & bundleName,const std::string & uid)45 FormRenderRecord::FormRenderRecord(
46     const std::string &bundleName, const std::string &uid) : bundleName_(bundleName), uid_(uid) {}
47 
~FormRenderRecord()48 FormRenderRecord::~FormRenderRecord()
49 {
50     // Some resources need to be deleted in a JS thread
51     auto syncTask = [renderRecord = this]() {
52         if (renderRecord == nullptr) {
53             HILOG_ERROR("renderRecord is nullptr.");
54             return;
55         }
56         renderRecord->HandleDestroyInJsThread();
57     };
58     eventHandler_->PostSyncTask(syncTask);
59 }
60 
HandleHostDied(const sptr<IRemoteObject> hostRemoteObj)61 bool FormRenderRecord::HandleHostDied(const sptr<IRemoteObject> hostRemoteObj)
62 {
63     HILOG_INFO("Form host is died, clean resources.");
64     std::lock_guard<std::mutex> lock(hostsMapMutex_);
65     for (auto iter = hostsMapForFormId_.begin(); iter != hostsMapForFormId_.end();) {
66         std::unordered_set<sptr<IRemoteObject>, RemoteObjHash> &hosts = iter->second;
67         hosts.erase(hostRemoteObj);
68         if (hosts.empty()) {
69             iter = hostsMapForFormId_.erase(iter);
70         } else {
71             ++iter;
72         }
73     }
74     return hostsMapForFormId_.empty();
75 }
76 
CreateEventHandler(const std::string & bundleName)77 bool FormRenderRecord::CreateEventHandler(const std::string &bundleName)
78 {
79     HILOG_INFO("%{public}s called.", __func__);
80     if (eventHandler_) {
81         HILOG_DEBUG("EventHandle is exist, no need to create a new one.");
82         return true;
83     }
84     // Create event runner
85     HILOG_INFO("Create eventHandle.");
86     if (eventRunner_ == nullptr) {
87         eventRunner_ = EventRunner::Create(bundleName);
88         if (eventRunner_ == nullptr) {
89             HILOG_ERROR("Create event runner Failed.");
90             return false;
91         }
92     }
93     // Create event handler
94     eventHandler_ = std::make_shared<EventHandler>(eventRunner_);
95     if (eventHandler_ == nullptr) {
96         HILOG_ERROR("Create event handler failed.");
97         return false;
98     }
99     return true;
100 }
101 
UpdateRenderRecord(const FormJsInfo & formJsInfo,const Want & want,const sptr<IRemoteObject> hostRemoteObj)102 int32_t FormRenderRecord::UpdateRenderRecord(const FormJsInfo &formJsInfo, const Want &want, const sptr<IRemoteObject> hostRemoteObj)
103 {
104     HILOG_INFO("Updated record.");
105 
106     // Some resources need to be initialized in a JS thread
107     std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
108     auto task = [thisWeakPtr, formJsInfo, want]() {
109         HILOG_DEBUG("HandleUpdateInJsThread begin.");
110         auto renderRecord = thisWeakPtr.lock();
111         if (renderRecord == nullptr) {
112             HILOG_ERROR("renderRecord is nullptr.");
113             return;
114         }
115         renderRecord->HandleUpdateInJsThread(formJsInfo, want);
116     };
117 
118     if (eventHandler_ == nullptr) {
119         HILOG_ERROR("eventHandler_ is nullptr");
120         return RENDER_FORM_FAILED;
121     }
122     eventHandler_->PostTask(task);
123 
124     if (hostRemoteObj == nullptr) {
125         HILOG_ERROR("hostRemoteObj is nullptr");
126         return RENDER_FORM_FAILED;
127     }
128     std::lock_guard<std::mutex> lock(hostsMapMutex_);
129     auto iter = hostsMapForFormId_.find(formJsInfo.formId);
130     if (iter == hostsMapForFormId_.end()) {
131         hostsMapForFormId_.emplace(formJsInfo.formId, IRemoteObjectSet({ hostRemoteObj }));
132         return ERR_OK;
133     }
134     iter->second.emplace(hostRemoteObj);
135     return ERR_OK;
136 }
137 
DeleteRenderRecord(int64_t formId,const std::string & compId,const sptr<IRemoteObject> hostRemoteObj,bool & isRenderGroupEmpty)138 void FormRenderRecord::DeleteRenderRecord(int64_t formId, const std::string &compId, const sptr<IRemoteObject> hostRemoteObj, bool &isRenderGroupEmpty)
139 {
140     // Some resources need to be deleted in a JS thread
141     HILOG_INFO("Delete some resources formId:%{public}s %{public}s", std::to_string(formId).c_str(), compId.c_str());
142     if (eventHandler_ == nullptr) {
143         HILOG_ERROR("eventHandler_ is nullptr");
144         return;
145     }
146 
147     auto task = [weak = weak_from_this(), formId, compId, &isRenderGroupEmpty]() {
148         auto renderRecord = weak.lock();
149         if (renderRecord == nullptr) {
150             HILOG_ERROR("renderRecord is nullptr.");
151             return;
152         }
153 
154         isRenderGroupEmpty = renderRecord->HandleDeleteInJsThread(formId, compId);
155     };
156 
157     if (hostRemoteObj != nullptr) {
158         std::lock_guard<std::mutex> lock(hostsMapMutex_);
159         auto iter = hostsMapForFormId_.find(formId);
160         if (iter != hostsMapForFormId_.end()) {
161             std::unordered_set<sptr<IRemoteObject>, RemoteObjHash> &hosts = iter->second;
162             hosts.erase(hostRemoteObj);
163         }
164     }
165     eventHandler_->PostSyncTask(task);
166 }
167 
IsEmpty()168 bool FormRenderRecord::IsEmpty()
169 {
170     std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
171     return formRendererGroupMap_.empty();
172 }
173 
GetUid() const174 std::string FormRenderRecord::GetUid() const
175 {
176     return uid_;
177 }
178 
CreateRuntime(const FormJsInfo & formJsInfo)179 bool FormRenderRecord::CreateRuntime(const FormJsInfo &formJsInfo)
180 {
181     if (runtime_) {
182         HILOG_DEBUG("runtime is exist, no need to create a new one.");
183         return true;
184     }
185 
186     HILOG_INFO("Create a new runtime.");
187     if (eventRunner_ == nullptr) {
188         HILOG_ERROR("eventRunner_ is nullptr");
189         return false;
190     }
191     AbilityRuntime::Runtime::Options options;
192     options.bundleName = formJsInfo.bundleName;
193     options.codePath = Constants::LOCAL_CODE_PATH;
194     BundleInfo bundleInfo;
195     options.eventRunner = eventRunner_;
196     options.hapPath = formJsInfo.jsFormCodePath;
197     options.loadAce = true;
198     options.isBundle = true;
199     options.isUnique = true;
200     runtime_ = AbilityRuntime::Runtime::Create(options);
201     if (runtime_ == nullptr) {
202         HILOG_ERROR("Create runtime Failed!");
203         return false;
204     }
205     return true;
206 }
207 
GetContext(const FormJsInfo & formJsInfo,const Want & want)208 std::shared_ptr<AbilityRuntime::Context> FormRenderRecord::GetContext(const FormJsInfo &formJsInfo, const Want &want)
209 {
210     {
211         std::lock_guard<std::mutex> lock(contextsMapMutex_);
212         auto iter = contextsMapForModuleName_.find(GenerateContextKey(formJsInfo));
213         if (iter != contextsMapForModuleName_.end()) {
214             HILOG_DEBUG("Find context.");
215             return iter->second;
216         }
217     }
218 
219     return CreateContext(formJsInfo, want);
220 }
221 
CreateContext(const FormJsInfo & formJsInfo,const Want & want)222 std::shared_ptr<AbilityRuntime::Context> FormRenderRecord::CreateContext(const FormJsInfo &formJsInfo, const Want &want)
223 {
224     HILOG_INFO("Create a new context.");
225     auto context = std::make_shared<AbilityRuntime::ContextImpl>();
226     if (context == nullptr) {
227         HILOG_ERROR("Create context failed!");
228         return nullptr;
229     }
230     AppExecFwk::HapModuleInfo hapModuleInfo;
231     hapModuleInfo.name = formJsInfo.moduleName;
232     hapModuleInfo.hapPath = formJsInfo.jsFormCodePath;
233     hapModuleInfo.compileMode = static_cast<CompileMode>(want.GetIntParam(Constants::FORM_COMPILE_MODE_KEY,
234         static_cast<int32_t>(CompileMode::ES_MODULE)));
235     context->InitHapModuleInfo(hapModuleInfo);
236     auto applicationInfo = std::make_shared<AppExecFwk::ApplicationInfo>();
237     applicationInfo->bundleName = formJsInfo.bundleName;
238     applicationInfo->minCompatibleVersionCode = want.GetIntParam(Constants::FORM_COMPATIBLE_VERSION_CODE_KEY, 0);
239     context->SetApplicationInfo(applicationInfo);
240     HILOG_DEBUG("bundleName is %{public}s, moduleName is %{public}s",
241         formJsInfo.bundleName.c_str(), formJsInfo.moduleName.c_str());
242 
243     std::lock_guard<std::mutex> lock(contextsMapMutex_);
244     contextsMapForModuleName_.emplace(GenerateContextKey(formJsInfo), context);
245     return context;
246 }
247 
GetFormRendererGroup(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)248 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::GetFormRendererGroup(const FormJsInfo &formJsInfo,
249     const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
250 {
251     HILOG_INFO("Get formRendererGroup.");
252     std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
253     auto key = formJsInfo.formId;
254     auto iter = formRendererGroupMap_.find(key);
255     if (iter != formRendererGroupMap_.end()) {
256         return iter->second;
257     }
258 
259     auto formRendererGroup = CreateFormRendererGroupLock(formJsInfo, context, runtime);
260     if (formRendererGroup != nullptr) {
261         HILOG_INFO("formRendererGroupMap emplace formId:%{public}s", std::to_string(key).c_str());
262         formRendererGroupMap_.emplace(key, formRendererGroup);
263     }
264     return formRendererGroup;
265 }
266 
CreateFormRendererGroupLock(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)267 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::CreateFormRendererGroupLock(const FormJsInfo &formJsInfo,
268     const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
269 {
270     HILOG_INFO("Create formRendererGroup.");
271     auto formRendererGroup = Ace::FormRendererGroup::Create(context, runtime);
272     if (formRendererGroup == nullptr) {
273         HILOG_ERROR("Create formRendererGroup failed");
274         return nullptr;
275     }
276     return formRendererGroup;
277 }
278 
HandleUpdateInJsThread(const FormJsInfo & formJsInfo,const Want & want)279 void FormRenderRecord::HandleUpdateInJsThread(const FormJsInfo &formJsInfo, const Want &want)
280 {
281     HILOG_INFO("Update record in js thread.");
282     if (runtime_ == nullptr && !CreateRuntime(formJsInfo)) {
283         HILOG_ERROR("Create runtime failed.");
284         return;
285     }
286     auto context = GetContext(formJsInfo, want);
287     if (context == nullptr) {
288         HILOG_ERROR("Create Context failed.");
289         return;
290     }
291     auto renderType = want.GetIntParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
292     HILOG_INFO("renderType is %{public}d.", renderType);
293     if (renderType == Constants::RENDER_FORM) {
294         auto formRendererGroup = GetFormRendererGroup(formJsInfo, context, runtime_);
295         if (formRendererGroup == nullptr) {
296             HILOG_ERROR("Create formRendererGroup failed.");
297             return;
298         }
299         formRendererGroup->AddForm(want, formJsInfo);
300         HILOG_INFO("AddForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
301     } else {
302         std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
303         if (auto search = formRendererGroupMap_.find(formJsInfo.formId);
304             search != formRendererGroupMap_.end()) {
305             auto group = search->second;
306             group->UpdateForm(formJsInfo);
307         }
308         HILOG_INFO("UpdateForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
309     }
310     return;
311 }
312 
HandleDeleteInJsThread(int64_t formId,const std::string & compId)313 bool FormRenderRecord::HandleDeleteInJsThread(int64_t formId, const std::string &compId)
314 {
315     HILOG_INFO("Delete some resources in js thread.");
316     {
317         std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
318         auto search = formRendererGroupMap_.find(formId);
319         if (search == formRendererGroupMap_.end()) {
320             HILOG_INFO("HandleDeleteInJsThread failed. FormRendererGroup was not founded.");
321             return false;
322         }
323         if (!search->second) {
324             HILOG_INFO("HandleDeleteInJsThread failed. FormRendererGroup was founded but is null.");
325             return false;
326         }
327         if (!compId.empty()) {
328             search->second->DeleteForm(compId);
329             HILOG_INFO("HandleDeleteInJsThread compid is %{public}s", compId.c_str());
330             return false;
331         }
332         search->second->DeleteForm();
333         formRendererGroupMap_.erase(formId);
334     }
335     std::lock_guard<std::mutex> lock(hostsMapMutex_);
336     hostsMapForFormId_.erase(formId);
337     return true;
338 }
339 
HandleDestroyInJsThread()340 void FormRenderRecord::HandleDestroyInJsThread()
341 {
342     HILOG_INFO("FormRenderService is exiting, destroy some resources in js thread.");
343     std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
344     formRendererGroupMap_.clear();
345     runtime_.reset();
346 }
347 
GenerateContextKey(const FormJsInfo & formJsInfo)348 inline std::string FormRenderRecord::GenerateContextKey(const FormJsInfo &formJsInfo)
349 {
350     return formJsInfo.bundleName + ":" +  formJsInfo.moduleName;
351 }
352 
ReloadFormRecord(const std::vector<int64_t> && formIds,const Want & want)353 int32_t FormRenderRecord::ReloadFormRecord(const std::vector<int64_t> &&formIds, const Want &want)
354 {
355     HILOG_INFO("Reload form record");
356     std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
357     auto task = [thisWeakPtr, ids = std::forward<decltype(formIds)>(formIds), want]() {
358         HILOG_DEBUG("HandleReloadFormRecord begin.");
359         auto renderRecord = thisWeakPtr.lock();
360         if (renderRecord == nullptr) {
361             HILOG_ERROR("renderRecord is nullptr.");
362             return;
363         }
364         renderRecord->HandleReloadFormRecord(std::move(ids), want);
365     };
366     if (eventHandler_ == nullptr) {
367         HILOG_ERROR("eventHandler_ is nullptr");
368         return RELOAD_FORM_FAILED;
369     }
370     eventHandler_->PostTask(task);
371     return ERR_OK;
372 }
373 
HandleReloadFormRecord(const std::vector<int64_t> && formIds,const Want & want)374 int32_t FormRenderRecord::HandleReloadFormRecord(const std::vector<int64_t> &&formIds, const Want &want)
375 {
376     HILOG_INFO("Reload record in js thread.");
377     std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
378     for (auto formId : formIds) {
379         auto search = formRendererGroupMap_.find(formId);
380         if (search == formRendererGroupMap_.end()) {
381             HILOG_ERROR("HandleReloadFormRecord failed. FormRendererGroup was not found.");
382             continue;
383         }
384         auto group = search->second;
385         if (!group) {
386             HILOG_ERROR("HandleReloadFormRecord failed. FormRendererGroup is null.");
387             continue;
388         }
389         group->ReloadForm();
390     }
391     return ERR_OK;
392 }
393 
UpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)394 void FormRenderRecord::UpdateConfiguration(
395     const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
396 {
397     HILOG_INFO("UpdateConfiguration begin");
398     if (!config) {
399         HILOG_ERROR("UpdateConfiguration failed due to config is nullptr");
400         return;
401     }
402 
403     std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
404     auto task = [thisWeakPtr, config]() {
405         auto renderRecord = thisWeakPtr.lock();
406         if (renderRecord == nullptr) {
407             HILOG_ERROR("renderRecord is nullptr.");
408             return;
409         }
410         renderRecord->HandleUpdateConfiguration(config);
411     };
412     if (eventHandler_ == nullptr) {
413         HILOG_ERROR("eventHandler_ is nullptr");
414         return;
415     }
416     eventHandler_->PostTask(task);
417 }
418 
HandleUpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)419 void FormRenderRecord::HandleUpdateConfiguration(
420     const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
421 {
422     HILOG_INFO("HandleUpdateConfiguration begin.");
423     std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
424     for (auto iter = formRendererGroupMap_.begin(); iter != formRendererGroupMap_.end(); ++iter) {
425         if (iter->second) {
426             iter->second->UpdateConfiguration(config);
427         }
428     }
429 }
430 } // namespace FormRender
431 } // namespace AppExecFwk
432 } // namespace OHOS
433