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