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
231 context->SetConfiguration(configuration_);
232 AppExecFwk::HapModuleInfo hapModuleInfo;
233 hapModuleInfo.name = formJsInfo.moduleName;
234 hapModuleInfo.hapPath = formJsInfo.jsFormCodePath;
235 hapModuleInfo.compileMode = static_cast<CompileMode>(want.GetIntParam(Constants::FORM_COMPILE_MODE_KEY,
236 static_cast<int32_t>(CompileMode::ES_MODULE)));
237 context->InitHapModuleInfo(hapModuleInfo);
238 auto applicationInfo = std::make_shared<AppExecFwk::ApplicationInfo>();
239 applicationInfo->bundleName = formJsInfo.bundleName;
240 applicationInfo->minCompatibleVersionCode = want.GetIntParam(Constants::FORM_COMPATIBLE_VERSION_CODE_KEY, 0);
241 context->SetApplicationInfo(applicationInfo);
242 HILOG_DEBUG("bundleName is %{public}s, moduleName is %{public}s",
243 formJsInfo.bundleName.c_str(), formJsInfo.moduleName.c_str());
244
245 std::lock_guard<std::mutex> lock(contextsMapMutex_);
246 contextsMapForModuleName_.emplace(GenerateContextKey(formJsInfo), context);
247 return context;
248 }
249
SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)250 void FormRenderRecord::SetConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
251 {
252 configuration_ = config;
253 }
254
GetFormRendererGroup(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)255 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::GetFormRendererGroup(const FormJsInfo &formJsInfo,
256 const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
257 {
258 HILOG_INFO("Get formRendererGroup.");
259 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
260 auto key = formJsInfo.formId;
261 auto iter = formRendererGroupMap_.find(key);
262 if (iter != formRendererGroupMap_.end()) {
263 return iter->second;
264 }
265
266 auto formRendererGroup = CreateFormRendererGroupLock(formJsInfo, context, runtime);
267 if (formRendererGroup != nullptr) {
268 HILOG_INFO("formRendererGroupMap emplace formId:%{public}s", std::to_string(key).c_str());
269 formRendererGroupMap_.emplace(key, formRendererGroup);
270 }
271 return formRendererGroup;
272 }
273
CreateFormRendererGroupLock(const FormJsInfo & formJsInfo,const std::shared_ptr<AbilityRuntime::Context> & context,const std::shared_ptr<AbilityRuntime::Runtime> & runtime)274 std::shared_ptr<Ace::FormRendererGroup> FormRenderRecord::CreateFormRendererGroupLock(const FormJsInfo &formJsInfo,
275 const std::shared_ptr<AbilityRuntime::Context> &context, const std::shared_ptr<AbilityRuntime::Runtime> &runtime)
276 {
277 HILOG_INFO("Create formRendererGroup.");
278 auto formRendererGroup = Ace::FormRendererGroup::Create(context, runtime);
279 if (formRendererGroup == nullptr) {
280 HILOG_ERROR("Create formRendererGroup failed");
281 return nullptr;
282 }
283 return formRendererGroup;
284 }
285
HandleUpdateInJsThread(const FormJsInfo & formJsInfo,const Want & want)286 void FormRenderRecord::HandleUpdateInJsThread(const FormJsInfo &formJsInfo, const Want &want)
287 {
288 HILOG_INFO("Update record in js thread.");
289 if (runtime_ == nullptr && !CreateRuntime(formJsInfo)) {
290 HILOG_ERROR("Create runtime failed.");
291 return;
292 }
293 auto context = GetContext(formJsInfo, want);
294 if (context == nullptr) {
295 HILOG_ERROR("Create Context failed.");
296 return;
297 }
298 auto renderType = want.GetIntParam(Constants::FORM_RENDER_TYPE_KEY, Constants::RENDER_FORM);
299 HILOG_INFO("renderType is %{public}d.", renderType);
300 if (renderType == Constants::RENDER_FORM) {
301 auto formRendererGroup = GetFormRendererGroup(formJsInfo, context, runtime_);
302 if (formRendererGroup == nullptr) {
303 HILOG_ERROR("Create formRendererGroup failed.");
304 return;
305 }
306 formRendererGroup->AddForm(want, formJsInfo);
307 HILOG_INFO("AddForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
308 } else {
309 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
310 if (auto search = formRendererGroupMap_.find(formJsInfo.formId);
311 search != formRendererGroupMap_.end()) {
312 auto group = search->second;
313 group->UpdateForm(formJsInfo);
314 }
315 HILOG_INFO("UpdateForm formId:%{public}s", std::to_string(formJsInfo.formId).c_str());
316 }
317 return;
318 }
319
HandleDeleteInJsThread(int64_t formId,const std::string & compId)320 bool FormRenderRecord::HandleDeleteInJsThread(int64_t formId, const std::string &compId)
321 {
322 HILOG_INFO("Delete some resources in js thread.");
323 {
324 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
325 auto search = formRendererGroupMap_.find(formId);
326 if (search == formRendererGroupMap_.end()) {
327 HILOG_INFO("HandleDeleteInJsThread failed. FormRendererGroup was not founded.");
328 return false;
329 }
330 if (!search->second) {
331 HILOG_INFO("HandleDeleteInJsThread failed. FormRendererGroup was founded but is null.");
332 return false;
333 }
334 if (!compId.empty()) {
335 search->second->DeleteForm(compId);
336 HILOG_INFO("HandleDeleteInJsThread compid is %{public}s", compId.c_str());
337 return false;
338 }
339 search->second->DeleteForm();
340 formRendererGroupMap_.erase(formId);
341 }
342 std::lock_guard<std::mutex> lock(hostsMapMutex_);
343 hostsMapForFormId_.erase(formId);
344 return true;
345 }
346
HandleDestroyInJsThread()347 void FormRenderRecord::HandleDestroyInJsThread()
348 {
349 HILOG_INFO("FormRenderService is exiting, destroy some resources in js thread.");
350 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
351 formRendererGroupMap_.clear();
352 runtime_.reset();
353 }
354
GenerateContextKey(const FormJsInfo & formJsInfo)355 inline std::string FormRenderRecord::GenerateContextKey(const FormJsInfo &formJsInfo)
356 {
357 return formJsInfo.bundleName + ":" + formJsInfo.moduleName;
358 }
359
ReloadFormRecord(const std::vector<int64_t> && formIds,const Want & want)360 int32_t FormRenderRecord::ReloadFormRecord(const std::vector<int64_t> &&formIds, const Want &want)
361 {
362 HILOG_INFO("Reload form record");
363 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
364 auto task = [thisWeakPtr, ids = std::forward<decltype(formIds)>(formIds), want]() {
365 HILOG_DEBUG("HandleReloadFormRecord begin.");
366 auto renderRecord = thisWeakPtr.lock();
367 if (renderRecord == nullptr) {
368 HILOG_ERROR("renderRecord is nullptr.");
369 return;
370 }
371 renderRecord->HandleReloadFormRecord(std::move(ids), want);
372 };
373 if (eventHandler_ == nullptr) {
374 HILOG_ERROR("eventHandler_ is nullptr");
375 return RELOAD_FORM_FAILED;
376 }
377 eventHandler_->PostTask(task);
378 return ERR_OK;
379 }
380
HandleReloadFormRecord(const std::vector<int64_t> && formIds,const Want & want)381 int32_t FormRenderRecord::HandleReloadFormRecord(const std::vector<int64_t> &&formIds, const Want &want)
382 {
383 HILOG_INFO("Reload record in js thread.");
384 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
385 for (auto formId : formIds) {
386 auto search = formRendererGroupMap_.find(formId);
387 if (search == formRendererGroupMap_.end()) {
388 HILOG_ERROR("HandleReloadFormRecord failed. FormRendererGroup was not found.");
389 continue;
390 }
391 auto group = search->second;
392 if (!group) {
393 HILOG_ERROR("HandleReloadFormRecord failed. FormRendererGroup is null.");
394 continue;
395 }
396 group->ReloadForm();
397 }
398 return ERR_OK;
399 }
400
UpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)401 void FormRenderRecord::UpdateConfiguration(
402 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
403 {
404 HILOG_INFO("UpdateConfiguration begin");
405 if (!config) {
406 HILOG_ERROR("UpdateConfiguration failed due to config is nullptr");
407 return;
408 }
409
410 std::weak_ptr<FormRenderRecord> thisWeakPtr(shared_from_this());
411 auto task = [thisWeakPtr, config]() {
412 auto renderRecord = thisWeakPtr.lock();
413 if (renderRecord == nullptr) {
414 HILOG_ERROR("renderRecord is nullptr.");
415 return;
416 }
417 renderRecord->HandleUpdateConfiguration(config);
418 };
419 if (eventHandler_ == nullptr) {
420 HILOG_ERROR("eventHandler_ is nullptr");
421 return;
422 }
423 eventHandler_->PostTask(task);
424 }
425
HandleUpdateConfiguration(const std::shared_ptr<OHOS::AppExecFwk::Configuration> & config)426 void FormRenderRecord::HandleUpdateConfiguration(
427 const std::shared_ptr<OHOS::AppExecFwk::Configuration>& config)
428 {
429 HILOG_INFO("HandleUpdateConfiguration begin.");
430 std::lock_guard<std::mutex> lock(formRendererGroupMutex_);
431 for (auto iter = formRendererGroupMap_.begin(); iter != formRendererGroupMap_.end(); ++iter) {
432 if (iter->second) {
433 iter->second->UpdateConfiguration(config);
434 }
435 }
436 }
437 } // namespace FormRender
438 } // namespace AppExecFwk
439 } // namespace OHOS
440