1 /*
2  * Copyright (c) 2021-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 "js_ability_stage.h"
17 
18 #include "ability_delegator_registry.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_ability_stage_context.h"
21 #include "js_context_utils.h"
22 #include "js_runtime.h"
23 #include "js_runtime_utils.h"
24 #include "js_startup_config.h"
25 #include "napi_common_configuration.h"
26 #include "napi_common_util.h"
27 #include "napi_common_want.h"
28 #include "ohos_application.h"
29 #include "startup_manager.h"
30 #include <algorithm>
31 #include <cstring>
32 #include <exception>
33 #include <fstream>
34 #include <iterator>
35 #include <memory>
36 #include <string>
37 #include <vector>
38 
39 namespace OHOS {
40 namespace AbilityRuntime {
41 constexpr const char* PROFILE_FILE_PREFIX = "$profile:";
42 constexpr const char* STARTUP_TASKS = "startupTasks";
43 constexpr const char* NAME = "name";
44 constexpr const char* SRC_ENTRY = "srcEntry";
45 constexpr const char* DEPENDENCIES = "dependencies";
46 constexpr const char* EXCLUDE_FROM_AUTO_START = "excludeFromAutoStart";
47 constexpr const char* RUN_ON_THREAD = "runOnThread";
48 constexpr const char* WAIT_ON_MAIN_THREAD = "waitOnMainThread";
49 constexpr const char* CONFIG_ENTRY = "configEntry";
50 constexpr const char *TASKPOOL = "taskPool";
51 constexpr const char *TASKPOOL_LOWER = "taskpool";
52 
AttachAbilityStageContext(napi_env env,void * value,void *)53 napi_value AttachAbilityStageContext(napi_env env, void *value, void *)
54 {
55     TAG_LOGD(AAFwkTag::APPKIT, "AttachAbilityStageContext");
56     if (env == nullptr || value == nullptr) {
57         TAG_LOGW(AAFwkTag::APPKIT, "invalid parameter, env or value is nullptr");
58         return nullptr;
59     }
60     auto ptr = reinterpret_cast<std::weak_ptr<AbilityContext> *>(value)->lock();
61     if (ptr == nullptr) {
62         TAG_LOGW(AAFwkTag::APPKIT, "invalid context");
63         return nullptr;
64     }
65     napi_value object = CreateJsAbilityStageContext(env, ptr);
66     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.AbilityStageContext", &object, 1);
67     if (systemModule == nullptr) {
68         TAG_LOGW(AAFwkTag::APPKIT, "invalid systemModule");
69         return nullptr;
70     }
71     auto contextObj = systemModule->GetNapiValue();
72     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
73         TAG_LOGW(AAFwkTag::APPKIT, "LoadSystemModuleByEngine or ConvertNativeValueTo failed");
74         return nullptr;
75     }
76     napi_coerce_to_native_binding_object(
77         env, contextObj, DetachCallbackFunc, AttachAbilityStageContext, value, nullptr);
78     auto workContext = new (std::nothrow) std::weak_ptr<AbilityRuntime::Context>(ptr);
79     napi_wrap(env, contextObj, workContext,
80         [](napi_env, void *data, void *) {
81             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer context is called");
82             delete static_cast<std::weak_ptr<AbilityRuntime::Context> *>(data);
83         },
84         nullptr, nullptr);
85     return contextObj;
86 }
87 
UseCommonChunk(const AppExecFwk::HapModuleInfo & hapModuleInfo)88 bool JsAbilityStage::UseCommonChunk(const AppExecFwk::HapModuleInfo& hapModuleInfo)
89 {
90     for (auto &md: hapModuleInfo.metadata) {
91         if (md.name == "USE_COMMON_CHUNK") {
92             if (md.value != "true") {
93                 TAG_LOGW(AAFwkTag::APPKIT, "USE_COMMON_CHUNK = %s{public}s", md.value.c_str());
94                 return false;
95             }
96             return true;
97         }
98     }
99     return false;
100 }
101 
Create(const std::unique_ptr<Runtime> & runtime,const AppExecFwk::HapModuleInfo & hapModuleInfo)102 std::shared_ptr<AbilityStage> JsAbilityStage::Create(
103     const std::unique_ptr<Runtime>& runtime, const AppExecFwk::HapModuleInfo& hapModuleInfo)
104 {
105     if (runtime == nullptr) {
106         TAG_LOGW(AAFwkTag::APPKIT, "runtime is nullptr");
107         return nullptr;
108     }
109     auto& jsRuntime = static_cast<JsRuntime&>(*runtime);
110     std::string srcPath(hapModuleInfo.name);
111     std::string moduleName(hapModuleInfo.moduleName);
112     moduleName.append("::").append("AbilityStage");
113     bool commonChunkFlag = UseCommonChunk(hapModuleInfo);
114     /* temporary compatibility api8 + config.json */
115     if (!hapModuleInfo.isModuleJson) {
116         srcPath.append("/assets/js/");
117         if (hapModuleInfo.srcPath.empty()) {
118             srcPath.append("AbilityStage.abc");
119         } else {
120             srcPath.append(hapModuleInfo.srcPath);
121             srcPath.append("/AbilityStage.abc");
122         }
123         std::string key(moduleName);
124         key.append("::");
125         key.append(srcPath);
126         std::unique_ptr<NativeReference> moduleObj = nullptr;
127         if (jsRuntime.PopPreloadObj(key, moduleObj)) {
128             return std::make_shared<JsAbilityStage>(jsRuntime, std::move(moduleObj));
129         } else {
130             auto moduleObj = jsRuntime.LoadModule(moduleName, srcPath, hapModuleInfo.hapPath,
131                 hapModuleInfo.compileMode == AppExecFwk::CompileMode::ES_MODULE, commonChunkFlag);
132             return std::make_shared<JsAbilityStage>(jsRuntime, std::move(moduleObj));
133         }
134     }
135 
136     std::unique_ptr<NativeReference> moduleObj;
137     srcPath.append("/");
138     if (!hapModuleInfo.srcEntrance.empty()) {
139         srcPath.append(hapModuleInfo.srcEntrance);
140         srcPath.erase(srcPath.rfind("."));
141         srcPath.append(".abc");
142         moduleObj = jsRuntime.LoadModule(moduleName, srcPath, hapModuleInfo.hapPath,
143             hapModuleInfo.compileMode == AppExecFwk::CompileMode::ES_MODULE, commonChunkFlag);
144         TAG_LOGD(AAFwkTag::APPKIT, "srcPath is %{public}s", srcPath.c_str());
145     }
146     return std::make_shared<JsAbilityStage>(jsRuntime, std::move(moduleObj));
147 }
148 
JsAbilityStage(JsRuntime & jsRuntime,std::unique_ptr<NativeReference> && jsAbilityStageObj)149 JsAbilityStage::JsAbilityStage(JsRuntime& jsRuntime, std::unique_ptr<NativeReference>&& jsAbilityStageObj)
150     : jsRuntime_(jsRuntime), jsAbilityStageObj_(std::move(jsAbilityStageObj))
151 {}
152 
~JsAbilityStage()153 JsAbilityStage::~JsAbilityStage()
154 {
155     auto context = GetContext();
156     if (context) {
157         context->Unbind();
158     }
159 
160     jsRuntime_.FreeNativeReference(std::move(jsAbilityStageObj_));
161     jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
162 }
163 
Init(const std::shared_ptr<Context> & context,const std::weak_ptr<AppExecFwk::OHOSApplication> application)164 void JsAbilityStage::Init(const std::shared_ptr<Context> &context,
165     const std::weak_ptr<AppExecFwk::OHOSApplication> application)
166 {
167     AbilityStage::Init(context, application);
168 
169     if (!context) {
170         TAG_LOGE(AAFwkTag::APPKIT, "context is nullptr");
171         return;
172     }
173 
174     if (!jsAbilityStageObj_) {
175         TAG_LOGE(AAFwkTag::APPKIT, "stage is nullptr");
176         return;
177     }
178 
179     SetJsAbilityStage(context);
180 }
181 
OnCreate(const AAFwk::Want & want) const182 void JsAbilityStage::OnCreate(const AAFwk::Want &want) const
183 {
184     AbilityStage::OnCreate(want);
185 
186     if (!jsAbilityStageObj_) {
187         TAG_LOGW(AAFwkTag::APPKIT, "Not found AbilityStage.js");
188         return;
189     }
190 
191     HandleScope handleScope(jsRuntime_);
192     auto env = jsRuntime_.GetNapiEnv();
193 
194     napi_value obj = jsAbilityStageObj_->GetNapiValue();
195     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
196         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get AbilityStage object");
197         return;
198     }
199 
200     napi_value methodOnCreate = nullptr;
201     napi_get_named_property(env, obj, "onCreate", &methodOnCreate);
202     if (methodOnCreate == nullptr) {
203         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get 'onCreate' from AbilityStage object");
204         return;
205     }
206     napi_call_function(env, obj, methodOnCreate, 0, nullptr, nullptr);
207 
208     auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator();
209     if (delegator) {
210         delegator->PostPerformStageStart(CreateStageProperty());
211     }
212 }
213 
OnDestroy() const214 void JsAbilityStage::OnDestroy() const
215 {
216     TAG_LOGD(AAFwkTag::APPKIT, "Called");
217     AbilityStage::OnDestroy();
218 
219     if (!jsAbilityStageObj_) {
220         TAG_LOGW(AAFwkTag::APPKIT, "Not found AbilityStage.js");
221         return;
222     }
223 
224     HandleScope handleScope(jsRuntime_);
225     auto env = jsRuntime_.GetNapiEnv();
226 
227     napi_value obj = jsAbilityStageObj_->GetNapiValue();
228     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
229         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get AbilityStage object");
230         return;
231     }
232 
233     napi_value methodOnDestroy = nullptr;
234     napi_get_named_property(env, obj, "onDestroy", &methodOnDestroy);
235     if (methodOnDestroy == nullptr) {
236         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get 'onDestroy' from AbilityStage object");
237         return;
238     }
239     napi_call_function(env, obj, methodOnDestroy, 0, nullptr, nullptr);
240 }
241 
OnAcceptWant(const AAFwk::Want & want)242 std::string JsAbilityStage::OnAcceptWant(const AAFwk::Want &want)
243 {
244     TAG_LOGD(AAFwkTag::APPKIT, "called");
245     AbilityStage::OnAcceptWant(want);
246 
247     if (!jsAbilityStageObj_) {
248         TAG_LOGW(AAFwkTag::APPKIT, "Not found AbilityStage.js");
249         return "";
250     }
251 
252     HandleScope handleScope(jsRuntime_);
253     auto env = jsRuntime_.GetNapiEnv();
254 
255     napi_value obj = jsAbilityStageObj_->GetNapiValue();
256     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
257         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get AbilityStage object");
258         return "";
259     }
260 
261     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
262     napi_value methodOnAcceptWant = nullptr;
263     napi_get_named_property(env, obj, "onAcceptWant", &methodOnAcceptWant);
264     if (methodOnAcceptWant == nullptr) {
265         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get 'OnAcceptWant' from AbilityStage object");
266         return "";
267     }
268 
269     napi_value argv[] = { napiWant };
270     napi_value flagNative = nullptr;
271     napi_call_function(env, obj, methodOnAcceptWant, 1, argv, &flagNative);
272     return AppExecFwk::UnwrapStringFromJS(env, flagNative);
273 }
274 
275 
OnNewProcessRequest(const AAFwk::Want & want)276 std::string JsAbilityStage::OnNewProcessRequest(const AAFwk::Want &want)
277 {
278     TAG_LOGD(AAFwkTag::APPKIT, "called");
279     AbilityStage::OnNewProcessRequest(want);
280 
281     if (!jsAbilityStageObj_) {
282         TAG_LOGW(AAFwkTag::APPKIT, "Not found AbilityStage.js");
283         return "";
284     }
285 
286     HandleScope handleScope(jsRuntime_);
287     auto env = jsRuntime_.GetNapiEnv();
288 
289     napi_value obj = jsAbilityStageObj_->GetNapiValue();
290     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
291         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get AbilityStage object");
292         return "";
293     }
294 
295     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
296     napi_value methodOnNewProcessRequest = nullptr;
297     napi_get_named_property(env, obj, "onNewProcessRequest", &methodOnNewProcessRequest);
298     if (methodOnNewProcessRequest == nullptr) {
299         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get 'onNewProcessRequest' from AbilityStage object");
300         return "";
301     }
302 
303     napi_value argv[] = { napiWant };
304     napi_value flagNative = nullptr;
305     napi_call_function(env, obj, methodOnNewProcessRequest, 1, argv, &flagNative);
306     return AppExecFwk::UnwrapStringFromJS(env, flagNative);
307 }
308 
OnConfigurationUpdated(const AppExecFwk::Configuration & configuration)309 void JsAbilityStage::OnConfigurationUpdated(const AppExecFwk::Configuration& configuration)
310 {
311     AbilityStage::OnConfigurationUpdated(configuration);
312 
313     HandleScope handleScope(jsRuntime_);
314     auto env = jsRuntime_.GetNapiEnv();
315     auto application = application_.lock();
316     if (application == nullptr) {
317         TAG_LOGE(AAFwkTag::APPKIT, "application is nullptr");
318         return;
319     }
320     // Notify Ability stage context
321     auto fullConfig = application->GetConfiguration();
322     if (!fullConfig) {
323         TAG_LOGE(AAFwkTag::APPKIT, "configuration is nullptr");
324         return;
325     }
326     JsAbilityStageContext::ConfigurationUpdated(env, shellContextRef_, fullConfig);
327 
328     napi_value napiConfiguration = OHOS::AppExecFwk::WrapConfiguration(env, *fullConfig);
329     CallObjectMethod("onConfigurationUpdated", &napiConfiguration, 1);
330     CallObjectMethod("onConfigurationUpdate", &napiConfiguration, 1);
331 }
332 
OnMemoryLevel(int32_t level)333 void JsAbilityStage::OnMemoryLevel(int32_t level)
334 {
335     TAG_LOGD(AAFwkTag::APPKIT, "called");
336     AbilityStage::OnMemoryLevel(level);
337 
338     if (!jsAbilityStageObj_) {
339         TAG_LOGW(AAFwkTag::APPKIT, "Not found stage");
340         return;
341     }
342 
343     HandleScope handleScope(jsRuntime_);
344     auto env = jsRuntime_.GetNapiEnv();
345 
346     napi_value obj = jsAbilityStageObj_->GetNapiValue();
347     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
348         TAG_LOGE(AAFwkTag::APPKIT, "OnMemoryLevel, Failed to get AbilityStage object");
349         return;
350     }
351 
352     napi_value jsLevel = CreateJsValue(env, level);
353     napi_value argv[] = { jsLevel };
354     CallObjectMethod("onMemoryLevel", argv, ArraySize(argv));
355     TAG_LOGD(AAFwkTag::APPKIT, "end");
356 }
357 
RunAutoStartupTask(const std::function<void ()> & callback,bool & isAsyncCallback,const std::shared_ptr<Context> & stageContext)358 int32_t JsAbilityStage::RunAutoStartupTask(const std::function<void()> &callback, bool &isAsyncCallback,
359     const std::shared_ptr<Context> &stageContext)
360 {
361     TAG_LOGD(AAFwkTag::APPKIT, "called");
362     isAsyncCallback = false;
363     auto context = GetContext();
364     if (!context) {
365         TAG_LOGE(AAFwkTag::APPKIT, "context invalid");
366         return ERR_INVALID_VALUE;
367     }
368     auto hapModuleInfo = context->GetHapModuleInfo();
369     if (!hapModuleInfo) {
370         TAG_LOGE(AAFwkTag::APPKIT, "hapModuleInfo invalid");
371         return ERR_INVALID_VALUE;
372     }
373     if (hapModuleInfo->moduleType != AppExecFwk::ModuleType::ENTRY || hapModuleInfo->appStartup.empty()) {
374         TAG_LOGD(AAFwkTag::APPKIT, "not entry module or appStartup not exist");
375         return ERR_INVALID_VALUE;
376     }
377     if (!shellContextRef_) {
378         SetJsAbilityStage(stageContext);
379     }
380     std::vector<JsStartupTask> jsStartupTasks;
381     int32_t result = RegisterStartupTaskFromProfile(jsStartupTasks);
382     if (result != ERR_OK) {
383         return result;
384     }
385     std::shared_ptr<StartupManager> startupManager = DelayedSingleton<StartupManager>::GetInstance();
386     if (startupManager == nullptr) {
387         TAG_LOGE(AAFwkTag::APPKIT, "failed to get startupManager");
388         return ERR_INVALID_VALUE;
389     }
390     std::shared_ptr<StartupTaskManager> startupTaskManager = nullptr;
391     result = startupManager->BuildAutoStartupTaskManager(startupTaskManager);
392     if (result != ERR_OK) {
393         return result;
394     }
395     result = startupTaskManager->Prepare();
396     if (result != ERR_OK) {
397         return result;
398     }
399     auto runAutoStartupCallback = std::make_shared<OnCompletedCallback>(
400         [callback](const std::shared_ptr<StartupTaskResult> &) {
401             TAG_LOGI(AAFwkTag::APPKIT, "RunAutoStartupCallback");
402             callback();
403         });
404     result = startupTaskManager->Run(runAutoStartupCallback);
405     if (result != ERR_OK) {
406         isAsyncCallback = runAutoStartupCallback->IsCalled();
407         return result;
408     }
409     isAsyncCallback = true;
410     return ERR_OK;
411 }
412 
RegisterStartupTaskFromProfile(std::vector<JsStartupTask> & jsStartupTasks)413 int32_t JsAbilityStage::RegisterStartupTaskFromProfile(std::vector<JsStartupTask> &jsStartupTasks)
414 {
415     TAG_LOGD(AAFwkTag::APPKIT, "called");
416     std::vector<std::string> profileInfo;
417     if (!GetProfileInfoFromResourceManager(profileInfo)) {
418         TAG_LOGE(AAFwkTag::APPKIT, "appStartup config not exist");
419         return ERR_INVALID_VALUE;
420     }
421 
422     if (!AnalyzeProfileInfoAndRegisterStartupTask(profileInfo)) {
423         TAG_LOGE(AAFwkTag::APPKIT, "appStartup config not exist");
424         return ERR_INVALID_VALUE;
425     }
426 
427     return ERR_OK;
428 }
429 
GetProfileInfoFromResourceManager(std::vector<std::string> & profileInfo)430 bool JsAbilityStage::GetProfileInfoFromResourceManager(std::vector<std::string> &profileInfo)
431 {
432     TAG_LOGD(AAFwkTag::APPKIT, "called");
433     auto context = GetContext();
434     if (!context) {
435         TAG_LOGE(AAFwkTag::APPKIT, "context is nullptr");
436         return false;
437     }
438 
439     auto resMgr = context->GetResourceManager();
440     if (!resMgr) {
441         TAG_LOGE(AAFwkTag::APPKIT, "resMgr is nullptr");
442         return false;
443     }
444 
445     auto hapModuleInfo = context->GetHapModuleInfo();
446     if (!hapModuleInfo) {
447         TAG_LOGE(AAFwkTag::APPKIT, "hapModuleInfo is nullptr");
448         return false;
449     }
450 
451     jsRuntime_.UpdateModuleNameAndAssetPath(hapModuleInfo->moduleName);
452     bool isCompressed = !hapModuleInfo->hapPath.empty();
453     std::string appStartup = hapModuleInfo->appStartup;
454     if (appStartup.empty()) {
455         TAG_LOGE(AAFwkTag::APPKIT, "appStartup invalid");
456         return false;
457     }
458 
459     GetResFromResMgr(appStartup, resMgr, isCompressed, profileInfo);
460     if (profileInfo.empty()) {
461         TAG_LOGE(AAFwkTag::APPKIT, "appStartup config not exist");
462         return false;
463     }
464     return true;
465 }
466 
LoadJsSrcEntry(const std::string & srcEntry)467 std::unique_ptr<NativeReference> JsAbilityStage::LoadJsSrcEntry(const std::string &srcEntry)
468 {
469     TAG_LOGD(AAFwkTag::APPKIT, "call");
470     if (srcEntry.empty()) {
471         TAG_LOGE(AAFwkTag::APPKIT, "srcEntry invalid");
472         return nullptr;
473     }
474     auto context = GetContext();
475     if (!context) {
476         TAG_LOGE(AAFwkTag::APPKIT, "context is nullptr");
477         return nullptr;
478     }
479     auto hapModuleInfo = context->GetHapModuleInfo();
480     if (!hapModuleInfo) {
481         TAG_LOGE(AAFwkTag::APPKIT, "hapModuleInfo is nullptr");
482         return nullptr;
483     }
484 
485     bool esmodule = hapModuleInfo->compileMode == AppExecFwk::CompileMode::ES_MODULE;
486     std::string moduleName(hapModuleInfo->moduleName);
487     std::string srcPath(moduleName + "/" + srcEntry);
488 
489     auto pos = srcPath.rfind('.');
490     if (pos == std::string::npos) {
491         return nullptr;
492     }
493     srcPath.erase(pos);
494     srcPath.append(".abc");
495 
496     std::unique_ptr<NativeReference> jsCode(
497         jsRuntime_.LoadModule(moduleName, srcPath, hapModuleInfo->hapPath, esmodule));
498 
499     return jsCode;
500 }
501 
LoadJsStartupConfig(const std::string & srcEntry)502 bool JsAbilityStage::LoadJsStartupConfig(const std::string &srcEntry)
503 {
504     std::unique_ptr<NativeReference> startupConfigEntry = LoadJsSrcEntry(srcEntry);
505     if (startupConfigEntry == nullptr) {
506         TAG_LOGE(AAFwkTag::APPKIT, "fail to load config src entry");
507         return false;
508     }
509     auto env = jsRuntime_.GetNapiEnv();
510     std::shared_ptr<JsStartupConfig> startupConfig = std::make_shared<JsStartupConfig>(env);
511     if (startupConfig == nullptr) {
512         TAG_LOGE(AAFwkTag::APPKIT, "startupConfig is null");
513         return false;
514     }
515     if (startupConfig->Init(startupConfigEntry) != ERR_OK) {
516         return false;
517     }
518     std::shared_ptr<StartupManager> startupManager = DelayedSingleton<StartupManager>::GetInstance();
519     if (startupManager == nullptr) {
520         TAG_LOGE(AAFwkTag::APPKIT, "failed to get startupManager.");
521         return false;
522     }
523     startupManager->SetDefaultConfig(startupConfig);
524     return true;
525 }
526 
SetOptionalParameters(const nlohmann::json & module,JsStartupTask & jsStartupTask)527 void JsAbilityStage::SetOptionalParameters(
528     const nlohmann::json &module,
529     JsStartupTask &jsStartupTask)
530 {
531     TAG_LOGD(AAFwkTag::APPKIT, "called");
532     if (module.contains(DEPENDENCIES) && module[DEPENDENCIES].is_array()) {
533         std::vector<std::string> dependencies;
534         for (const auto& dependency : module.at(DEPENDENCIES)) {
535             if (dependency.is_string()) {
536                 dependencies.push_back(dependency.get<std::string>());
537             }
538         }
539         jsStartupTask.SetDependencies(dependencies);
540     }
541 
542     if (module.contains(EXCLUDE_FROM_AUTO_START) && module[EXCLUDE_FROM_AUTO_START].is_boolean()) {
543         jsStartupTask.SetIsExcludeFromAutoStart(module.at(EXCLUDE_FROM_AUTO_START).get<bool>());
544     } else {
545         jsStartupTask.SetIsExcludeFromAutoStart(false);
546     }
547 
548     if (module.contains(RUN_ON_THREAD) && module[RUN_ON_THREAD].is_string()) {
549         std::string profileName = module.at(RUN_ON_THREAD).get<std::string>();
550         if (profileName == TASKPOOL || profileName == TASKPOOL_LOWER) {
551             jsStartupTask.SetCallCreateOnMainThread(false);
552         } else {
553             jsStartupTask.SetCallCreateOnMainThread(true);
554         }
555     }
556 
557     if (module.contains(WAIT_ON_MAIN_THREAD) && module[WAIT_ON_MAIN_THREAD].is_boolean()) {
558         jsStartupTask.SetWaitOnMainThread(module.at(WAIT_ON_MAIN_THREAD).get<bool>());
559     } else {
560         jsStartupTask.SetWaitOnMainThread(true);
561     }
562 }
563 
AnalyzeProfileInfoAndRegisterStartupTask(const std::vector<std::string> & profileInfo)564 bool JsAbilityStage::AnalyzeProfileInfoAndRegisterStartupTask(const std::vector<std::string> &profileInfo)
565 {
566     TAG_LOGD(AAFwkTag::APPKIT, "called");
567     std::string startupInfo;
568     for (const std::string& info: profileInfo) {
569         startupInfo.append(info);
570     }
571     if (startupInfo.empty()) {
572         TAG_LOGE(AAFwkTag::APPKIT, "startupInfo invalid.");
573         return false;
574     }
575 
576     nlohmann::json startupInfoJson = nlohmann::json::parse(startupInfo, nullptr, false);
577     if (startupInfoJson.is_discarded()) {
578         TAG_LOGE(AAFwkTag::APPKIT, "Failed to parse json string.");
579         return false;
580     }
581 
582     if (!(startupInfoJson.contains(CONFIG_ENTRY) && startupInfoJson[CONFIG_ENTRY].is_string())) {
583         TAG_LOGE(AAFwkTag::APPKIT, "no config entry.");
584         return false;
585     }
586     if (!LoadJsStartupConfig(startupInfoJson.at(CONFIG_ENTRY).get<std::string>())) {
587         TAG_LOGE(AAFwkTag::APPKIT, "failed to load config entry.");
588         return false;
589     }
590 
591     if (!(startupInfoJson.contains(STARTUP_TASKS) && startupInfoJson[STARTUP_TASKS].is_array())) {
592         TAG_LOGE(AAFwkTag::APPKIT, "startupTasks invalid.");
593         return false;
594     }
595     std::vector<std::shared_ptr<JsStartupTask>> jsStartupTasks;
596     for (const auto& module : startupInfoJson.at(STARTUP_TASKS).get<nlohmann::json>()) {
597         if (!module.contains(SRC_ENTRY) || !module[SRC_ENTRY].is_string() ||
598         !module.contains(NAME) || !module[NAME].is_string()) {
599             TAG_LOGE(AAFwkTag::APPKIT, "Invalid module data.");
600             return false;
601         }
602 
603         std::unique_ptr<NativeReference> startupJsRef = LoadJsSrcEntry(module.at(SRC_ENTRY).get<std::string>());
604         if (startupJsRef == nullptr) {
605             TAG_LOGE(AAFwkTag::APPKIT, "load js appStartup tasks failed.");
606             return false;
607         }
608 
609         auto jsStartupTask = std::make_shared<JsStartupTask>(
610             module.at(NAME).get<std::string>(), jsRuntime_, startupJsRef, shellContextRef_);
611         SetOptionalParameters(module, *jsStartupTask);
612         jsStartupTasks.push_back(jsStartupTask);
613     }
614     for (auto &iter : jsStartupTasks) {
615         DelayedSingleton<StartupManager>::GetInstance()->RegisterStartupTask(iter->GetName(), iter);
616     }
617     return true;
618 }
619 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc)620 napi_value JsAbilityStage::CallObjectMethod(const char* name, napi_value const * argv, size_t argc)
621 {
622     TAG_LOGD(AAFwkTag::APPKIT, "call %{public}s", name);
623     if (!jsAbilityStageObj_) {
624         TAG_LOGW(AAFwkTag::APPKIT, "Not found AbilityStage.js");
625         return nullptr;
626     }
627 
628     HandleScope handleScope(jsRuntime_);
629     auto env = jsRuntime_.GetNapiEnv();
630 
631     napi_value obj = jsAbilityStageObj_->GetNapiValue();
632     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
633         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get AbilityStage object");
634         return nullptr;
635     }
636 
637     napi_value method = nullptr;
638     napi_get_named_property(env, obj, name, &method);
639     if (!CheckTypeForNapiValue(env, method, napi_function)) {
640         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get '%{public}s' from AbilityStage object", name);
641         return nullptr;
642     }
643 
644     napi_value result = nullptr;
645     napi_call_function(env, obj, method, argc, argv, &result);
646     return result;
647 }
648 
CreateStageProperty() const649 std::shared_ptr<AppExecFwk::DelegatorAbilityStageProperty> JsAbilityStage::CreateStageProperty() const
650 {
651     auto property = std::make_shared<AppExecFwk::DelegatorAbilityStageProperty>();
652     property->moduleName_ = GetHapModuleProp("name");
653     property->srcEntrance_ = GetHapModuleProp("srcEntrance");
654     property->object_ = jsAbilityStageObj_;
655     return property;
656 }
657 
GetHapModuleProp(const std::string & propName) const658 std::string JsAbilityStage::GetHapModuleProp(const std::string &propName) const
659 {
660     auto context = GetContext();
661     if (!context) {
662         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get context");
663         return std::string();
664     }
665     auto hapModuleInfo = context->GetHapModuleInfo();
666     if (!hapModuleInfo) {
667         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get hapModuleInfo");
668         return std::string();
669     }
670     if (propName.compare("name") == 0) {
671         return hapModuleInfo->name;
672     }
673     if (propName.compare("srcEntrance") == 0) {
674         return hapModuleInfo->srcEntrance;
675     }
676     TAG_LOGE(AAFwkTag::APPKIT, "name = %{public}s", propName.c_str());
677     return std::string();
678 }
679 
IsFileExisted(const std::string & filePath)680 bool JsAbilityStage::IsFileExisted(const std::string &filePath)
681 {
682     if (filePath.empty()) {
683         TAG_LOGE(AAFwkTag::APPKIT, "the file is not exist due to empty file path.");
684         return false;
685     }
686 
687     if (access(filePath.c_str(), F_OK) != 0) {
688         TAG_LOGE(AAFwkTag::APPKIT, "can not access the file: %{private}s, errno:%{public}d.", filePath.c_str(), errno);
689         return false;
690     }
691     return true;
692 }
693 
TransformFileToJsonString(const std::string & resPath,std::string & profile)694 bool JsAbilityStage::TransformFileToJsonString(const std::string &resPath, std::string &profile)
695 {
696     if (!IsFileExisted(resPath)) {
697         TAG_LOGE(AAFwkTag::APPKIT, "the file is not exist");
698         return false;
699     }
700     std::fstream in;
701     in.open(resPath, std::ios_base::in | std::ios_base::binary);
702     if (!in.is_open()) {
703         TAG_LOGE(AAFwkTag::APPKIT, "the file cannot be open errno:%{public}d.", errno);
704         return false;
705     }
706     in.seekg(0, std::ios::end);
707     int64_t size = in.tellg();
708     if (size <= 0) {
709         TAG_LOGE(AAFwkTag::APPKIT, "the file is an empty file, errno:%{public}d.", errno);
710         in.close();
711         return false;
712     }
713     in.seekg(0, std::ios::beg);
714     nlohmann::json profileJson = nlohmann::json::parse(in, nullptr, false);
715     if (profileJson.is_discarded()) {
716         TAG_LOGE(AAFwkTag::APPKIT, "bad profile file.");
717         in.close();
718         return false;
719     }
720     profile = profileJson.dump();
721     in.close();
722     return true;
723 }
724 
GetResFromResMgr(const std::string & resName,const std::shared_ptr<Global::Resource::ResourceManager> & resMgr,bool isCompressed,std::vector<std::string> & profileInfo)725 bool JsAbilityStage::GetResFromResMgr(
726     const std::string &resName,
727     const std::shared_ptr<Global::Resource::ResourceManager> &resMgr,
728     bool isCompressed, std::vector<std::string> &profileInfo)
729 {
730     if (resName.empty()) {
731         TAG_LOGE(AAFwkTag::APPKIT, "res name is empty.");
732         return false;
733     }
734 
735     size_t pos = resName.rfind(PROFILE_FILE_PREFIX);
736     if ((pos == std::string::npos) || (pos == resName.length() - strlen(PROFILE_FILE_PREFIX))) {
737         TAG_LOGE(AAFwkTag::APPKIT, "res name %{public}s is invalid.", resName.c_str());
738         return false;
739     }
740     std::string profileName = resName.substr(pos + strlen(PROFILE_FILE_PREFIX));
741         // hap is compressed status, get file content.
742     if (isCompressed) {
743         TAG_LOGD(AAFwkTag::APPKIT, "compressed status.");
744         std::unique_ptr<uint8_t[]> fileContentPtr = nullptr;
745         size_t len = 0;
746         if (resMgr->GetProfileDataByName(profileName.c_str(), len, fileContentPtr) != Global::Resource::SUCCESS) {
747             TAG_LOGE(AAFwkTag::APPKIT, "GetProfileDataByName failed.");
748             return false;
749         }
750         if (fileContentPtr == nullptr || len == 0) {
751             TAG_LOGE(AAFwkTag::APPKIT, "invalid data.");
752             return false;
753         }
754         std::string rawData(fileContentPtr.get(), fileContentPtr.get() + len);
755         nlohmann::json profileJson = nlohmann::json::parse(rawData, nullptr, false);
756         if (profileJson.is_discarded()) {
757             TAG_LOGE(AAFwkTag::APPKIT, "bad profile file.");
758             return false;
759         }
760         profileInfo.emplace_back(profileJson.dump());
761         return true;
762     }
763     // hap is decompressed status, get file path then read file.
764     std::string resPath;
765     if (resMgr->GetProfileByName(profileName.c_str(), resPath) != Global::Resource::SUCCESS) {
766         TAG_LOGD(AAFwkTag::APPKIT, "profileName cannot be found.");
767         return false;
768     }
769     TAG_LOGD(AAFwkTag::APPKIT, "resPath is %{private}s.", resPath.c_str());
770     std::string profile;
771     if (!TransformFileToJsonString(resPath, profile)) {
772         TAG_LOGE(AAFwkTag::APPKIT, "Transform file to json string filed.");
773         return false;
774     }
775     profileInfo.emplace_back(profile);
776     return true;
777 }
778 
SetJsAbilityStage(const std::shared_ptr<Context> & context)779 void JsAbilityStage::SetJsAbilityStage(const std::shared_ptr<Context> &context)
780 {
781     if (!context) {
782         TAG_LOGE(AAFwkTag::APPKIT, "context is nullptr");
783         return;
784     }
785 
786     HandleScope handleScope(jsRuntime_);
787     auto env = jsRuntime_.GetNapiEnv();
788 
789     napi_value obj = nullptr;
790     if (jsAbilityStageObj_) {
791         obj = jsAbilityStageObj_->GetNapiValue();
792         if (!CheckTypeForNapiValue(env, obj, napi_object)) {
793             TAG_LOGE(AAFwkTag::APPKIT, "Failed to get AbilityStage object");
794             return;
795         }
796     }
797 
798     napi_value contextObj = CreateJsAbilityStageContext(env, context);
799     shellContextRef_ = JsRuntime::LoadSystemModuleByEngine(env, "application.AbilityStageContext", &contextObj, 1);
800     if (shellContextRef_ == nullptr) {
801         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get LoadSystemModuleByEngine");
802         return;
803     }
804     contextObj = shellContextRef_->GetNapiValue();
805     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
806         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get context native object");
807         return;
808     }
809     auto workContext = new (std::nothrow) std::weak_ptr<AbilityRuntime::Context>(context);
810     napi_coerce_to_native_binding_object(
811         env, contextObj, DetachCallbackFunc, AttachAbilityStageContext, workContext, nullptr);
812     context->Bind(jsRuntime_, shellContextRef_.get());
813 
814     if (obj != nullptr) {
815         napi_set_named_property(env, obj, "context", contextObj);
816     }
817     TAG_LOGD(AAFwkTag::APPKIT, "Set ability stage context");
818     napi_status status = napi_wrap(env, contextObj, workContext,
819         [](napi_env, void* data, void*) {
820             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr ability stage context is called");
821             delete static_cast<std::weak_ptr<AbilityRuntime::Context>*>(data);
822         },
823         nullptr, nullptr);
824     if (status != napi_ok && workContext != nullptr) {
825         TAG_LOGD(AAFwkTag::APPKIT, "napi_wrap Failed: %{public}d", status);
826         delete workContext;
827         return;
828     }
829 }
830 }  // namespace AbilityRuntime
831 }  // namespace OHOS
832