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