1 /*
2 * Copyright (c) 2020-2021 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_impl.h"
17 #include "ace_event_error_code.h"
18 #include "ace_log.h"
19 #include "component.h"
20 #include "component_utils.h"
21 #include "fatal_handler.h"
22 #include "js_app_context.h"
23 #include "js_app_environment.h"
24 #include "js_profiler.h"
25 #include "module_manager.h"
26 #include "presets/localization_module.h"
27 #include "presets/timer_module.h"
28 #include "securec.h"
29 #ifdef _MINI_MULTI_TASKS_
30 #include "string_util.h"
31 #endif
32
33 namespace OHOS {
34 namespace ACELite {
35 #ifdef _MINI_MULTI_TASKS_
36 namespace {
37 constexpr char EMPTY_OBJECT_JSON_STRING[] = "{}";
38 constexpr char ERROR_CODE_KEY[] = "errorCode";
39 } // namespace
40 #endif
InitEnvironment(const char * const abilityPath,const char * const bundleName,uint16_t token)41 void JSAbilityImpl::InitEnvironment(const char * const abilityPath, const char * const bundleName, uint16_t token)
42 {
43 if ((abilityPath == nullptr) || strlen(abilityPath) == 0 || (bundleName == nullptr) || strlen(bundleName) == 0) {
44 HILOG_ERROR(HILOG_MODULE_ACE, "invalid input parameters");
45 return;
46 }
47
48 if (isEnvInit_) {
49 HILOG_ERROR(HILOG_MODULE_ACE, "already initialized, return");
50 return;
51 }
52 // init engine && js fwk
53 JsAppEnvironment *appJsEnv = JsAppEnvironment::GetInstance();
54 appContext_ = JsAppContext::GetInstance();
55 // check if we should use snapshot mode, do this before everything,
56 // but after debugger config is set
57 appJsEnv->InitRuntimeMode();
58 appContext_->SetCurrentAbilityInfo(abilityPath, bundleName, token);
59 appContext_->SetTopJSAbilityImpl(this);
60 appJsEnv->InitJsFramework();
61 appContext_->LoadApiVersion();
62
63 // initialize js object after engine started up
64 abilityModel_ = UNDEFINED;
65 nativeElement_ = UNDEFINED;
66 isEnvInit_ = true;
67
68 // relocate app.js fullpath
69 const char * const appJSFileName = (appJsEnv->IsSnapshotMode()) ? "app.bc" : "app.js";
70 char *fileFullPath = RelocateJSSourceFilePath(abilityPath, appJSFileName);
71 if (fileFullPath == nullptr) {
72 HILOG_ERROR(HILOG_MODULE_ACE, "relocate js file failed");
73 ACE_ERROR_CODE_PRINT(EXCE_ACE_FWK_LAUNCH_FAILED, EXCE_ACE_APP_ENTRY_MISSING);
74 return;
75 }
76
77 appContext_->SetAbilityState(TopAbilityState::ABILITY_INITIALIZED);
78 START_TRACING(APP_CODE_EVAL);
79 MarkAppViewModelEvaling(true);
80 abilityModel_ = appContext_->Eval(fileFullPath, strlen(fileFullPath), true); // generate global.$app js object
81 MarkAppViewModelEvaling(false);
82 STOP_TRACING();
83
84 ace_free(fileFullPath);
85 fileFullPath = nullptr;
86 router_ = new Router();
87 if (router_ == nullptr) {
88 HILOG_ERROR(HILOG_MODULE_ACE, "malloc router heap memory failed.");
89 return;
90 }
91 }
92
CleanUp()93 void JSAbilityImpl::CleanUp()
94 {
95 if (appContext_ == nullptr) {
96 return;
97 }
98 appContext_->SetAbilityState(TopAbilityState::ABILITY_DESTROYING);
99 if (!isEnvInit_) {
100 return;
101 }
102 START_TRACING(APP_ON_DESTROY);
103 // clean up user's js
104 InvokeOnDestroy();
105 STOP_TRACING();
106
107 // delete router's resources about page
108 if (router_ != nullptr) {
109 delete router_;
110 router_ = nullptr;
111 }
112 #ifdef _MINI_MULTI_TASKS_
113 if (pageInfo_ != nullptr) {
114 ACE_FREE(pageInfo_);
115 pageInfo_ = nullptr;
116 }
117 #endif
118 TimersModule::Clear();
119 LocalModule::Clear();
120
121 appContext_->ClearContext();
122
123 ModuleManager::GetInstance()->OnTerminate();
124 JsAppEnvironment::GetInstance()->Cleanup();
125 isEnvInit_ = false;
126 appContext_->SetAbilityState(TopAbilityState::ABILITY_DESTROYED);
127 OUTPUT_TRACE();
128 }
129
DeliverCreate(const char * param)130 void JSAbilityImpl::DeliverCreate(const char *param)
131 {
132 if (appContext_ == nullptr) {
133 return;
134 }
135 appContext_->SetAbilityState(TopAbilityState::ABILITY_LAUNCHING);
136 START_TRACING(APP_ON_CREATE);
137 // call InvokeOnCreate
138 InvokeOnCreate();
139 STOP_TRACING();
140 // if we have done the render or not initialized yet, don't call render
141 if (rendered_) {
142 ACE_ERROR_CODE_PRINT(EXCE_ACE_FWK_LAUNCH_FAILED, EXCE_ACE_APP_RENDER_FAILED);
143 return;
144 }
145
146 #ifndef _MINI_MULTI_TASKS_
147 // call render to setup user interface
148 jerry_value_t object = UNDEFINED;
149 if (param == nullptr) {
150 object = jerry_create_object();
151 JerrySetStringProperty(object, ROUTER_PAGE_URI, PATH_DEFAULT);
152 } else {
153 object = jerry_json_parse(reinterpret_cast<const jerry_char_t *>(param), strlen(param));
154 }
155 if (router_) {
156 jerry_release_value(router_->Replace(object, false));
157 rendered_ = true;
158 }
159 jerry_release_value(object);
160 appContext_->SetAbilityState(TopAbilityState::ABILITY_LAUNCHDONE);
161 #endif
162 }
163
164 #ifdef _MINI_MULTI_TASKS_
OnRestoreData(AbilitySlite::AbilitySavedData * abilitySavedData)165 void JSAbilityImpl::OnRestoreData(AbilitySlite::AbilitySavedData *abilitySavedData)
166 {
167 if (pageInfo_ != nullptr) {
168 ACE_FREE(pageInfo_);
169 pageInfo_ = nullptr;
170 }
171
172 if (abilitySavedData == nullptr) {
173 InvokeOnRestoreData(EMPTY_OBJECT_JSON_STRING, AbilitySlite::SavedResultCode::SAVED_RESULT_NO_DATA);
174 return;
175 }
176
177 // deal user saved data
178 char *userData = StringUtil::Malloc(AbilitySlite::SAVED_DATA_LIMIT);
179 if (userData == nullptr) {
180 InvokeOnRestoreData(EMPTY_OBJECT_JSON_STRING, AbilitySlite::SavedResultCode::SAVED_RESULT_ALLOC_ERROR);
181 return;
182 }
183
184 uint16_t userDataLen = AbilitySlite::SAVED_DATA_LIMIT;
185 AbilitySlite::SavedResultCode userDataRet = abilitySavedData->GetUserSavedData(
186 reinterpret_cast<void *>(userData), AbilitySlite::SAVED_DATA_LIMIT, &userDataLen);
187 if (userDataRet != AbilitySlite::SavedResultCode::SAVED_RESULT_OK) {
188 InvokeOnRestoreData(EMPTY_OBJECT_JSON_STRING, userDataRet);
189 ACE_FREE(userData);
190 return;
191 }
192
193 // deal framework saved data pageInfo
194 pageInfo_ = StringUtil::Malloc(AbilitySlite::SAVED_DATA_LIMIT);
195 if (pageInfo_ == nullptr) {
196 InvokeOnRestoreData(EMPTY_OBJECT_JSON_STRING, AbilitySlite::SavedResultCode::SAVED_RESULT_NO_DATA);
197 ACE_FREE(userData);
198 return;
199 }
200 uint16_t pageInfoLen = AbilitySlite::SAVED_DATA_LIMIT;
201 AbilitySlite::SavedResultCode pageInfoRet = abilitySavedData->GetSavedData(
202 reinterpret_cast<void*>(pageInfo_), AbilitySlite::SAVED_DATA_LIMIT, &pageInfoLen);
203 if (pageInfoRet != AbilitySlite::SavedResultCode::SAVED_RESULT_OK) {
204 ACE_FREE(pageInfo_);
205 pageInfo_ = nullptr;
206 InvokeOnRestoreData(EMPTY_OBJECT_JSON_STRING, AbilitySlite::SavedResultCode::SAVED_RESULT_NO_DATA);
207 ACE_FREE(userData);
208 return;
209 }
210
211 // call js function
212 bool success = InvokeOnRestoreData(userData, AbilitySlite::SavedResultCode::SAVED_RESULT_OK);
213 ACE_FREE(userData);
214 if (!success) {
215 // if restore data failed, not restore page
216 ACE_FREE(pageInfo_);
217 pageInfo_ = nullptr;
218 return;
219 }
220 }
221 #endif
222
Show()223 void JSAbilityImpl::Show()
224 {
225 if (appContext_ == nullptr) {
226 return;
227 }
228 if (router_ == nullptr) {
229 HILOG_ERROR(HILOG_MODULE_ACE, "no router instance to perform the show request");
230 return;
231 }
232 #ifdef _MINI_MULTI_TASKS_
233 if (pageInfo_ == nullptr) {
234 GotoPage(PATH_DEFAULT);
235 } else {
236 GotoPage(pageInfo_);
237 ACE_FREE(pageInfo_);
238 pageInfo_ = nullptr;
239 }
240 #endif
241 appContext_->SetAbilityState(TopAbilityState::ABILITY_SHOWING);
242 router_->Show();
243 FatalHandler::GetInstance().NotifyVisibleStatusChange(true);
244 appContext_->SetAbilityState(TopAbilityState::ABILITY_SHOWN);
245 }
246
247 #ifdef _MINI_MULTI_TASKS_
OnSaveData(AbilitySlite::AbilitySavedData * abilitySavedData)248 void JSAbilityImpl::OnSaveData(AbilitySlite::AbilitySavedData *abilitySavedData)
249 {
250 if (abilitySavedData == nullptr) {
251 return;
252 }
253
254 if (IS_UNDEFINED(abilityModel_) || (router_ == nullptr)) {
255 HILOG_ERROR(HILOG_MODULE_ACE, "view model or router is invalid when call user's onSaveData");
256 abilitySavedData->SetSavedResultCode(AbilitySlite::SavedResultCode::SAVED_RESULT_NO_DATA);
257 return;
258 }
259 // get js function
260 jerry_value_t onSaveFunction = jerryx_get_property_str(abilityModel_, ABILITY_LIFECYCLE_CALLBACK_ON_SAVE_DATA);
261 if (IS_UNDEFINED(onSaveFunction)) {
262 // user does not set onRestore method
263 abilitySavedData->SetSavedResultCode(AbilitySlite::SavedResultCode::SAVED_RESULT_NO_DATA);
264 return;
265 }
266
267 JSValue jerryUserData = jerry_create_object();
268 jerry_value_t args[1] = { jerryUserData };
269 CallJSFunctionAutoRelease(onSaveFunction, abilityModel_, args, 1);
270
271 jerry_value_t dataJson = jerry_json_stringify(args[0]);
272
273 char *userData = MallocStringOf(dataJson);
274 ReleaseJerryValue(dataJson, jerryUserData, onSaveFunction, VA_ARG_END_FLAG);
275
276 if (userData == nullptr) {
277 abilitySavedData->SetSavedResultCode(AbilitySlite::SavedResultCode::SAVED_RESULT_ALLOC_ERROR);
278 return;
279 }
280
281 AbilitySlite::SavedResultCode retCode =
282 abilitySavedData->SetUserSavedData(reinterpret_cast<const void *>(userData), strlen(userData) + 1);
283 ACE_FREE(userData);
284 if (retCode != AbilitySlite::SavedResultCode::SAVED_RESULT_OK) {
285 abilitySavedData->SetSavedResultCode(retCode);
286 return;
287 }
288
289 const char* uri = appContext_->GetCurrentUri();
290 if (uri == nullptr) {
291 retCode =
292 abilitySavedData->SetSavedData(reinterpret_cast<const void *>(PATH_DEFAULT), strlen(PATH_DEFAULT) + 1);
293 } else {
294 retCode = abilitySavedData->SetSavedData(reinterpret_cast<const void *>(uri), strlen(uri) + 1);
295 }
296 if (retCode != AbilitySlite::SavedResultCode::SAVED_RESULT_OK) {
297 abilitySavedData->SetSavedResultCode(retCode);
298 return;
299 }
300 abilitySavedData->SetSavedResultCode(AbilitySlite::SavedResultCode::SAVED_RESULT_OK);
301 }
302 #endif
303
Hide() const304 void JSAbilityImpl::Hide() const
305 {
306 if (appContext_ == nullptr) {
307 return;
308 }
309 if (router_ == nullptr) {
310 HILOG_ERROR(HILOG_MODULE_ACE, "no router instance to perform the hide request");
311 return;
312 }
313 appContext_->SetAbilityState(TopAbilityState::ABILITY_HIDING);
314 router_->Hide();
315 FatalHandler::GetInstance().NotifyVisibleStatusChange(false);
316 appContext_->SetAbilityState(TopAbilityState::ABILITY_HIDDEN);
317 }
318
NotifyBackPressed() const319 void JSAbilityImpl::NotifyBackPressed() const
320 {
321 if (appContext_ == nullptr) {
322 return;
323 }
324
325 InvokeOnBackPressed();
326
327 appContext_->TerminateAbility();
328 }
329
InvokeOnCreate() const330 void JSAbilityImpl::InvokeOnCreate() const
331 {
332 if (IS_UNDEFINED(abilityModel_)) {
333 HILOG_ERROR(HILOG_MODULE_ACE, "view model is undefined when call user's init");
334 return;
335 }
336 jerry_value_t onCreateFunction = jerryx_get_property_str(abilityModel_, ABILITY_LIFECYCLE_CALLBACK_ON_CREATE);
337 if (IS_UNDEFINED(onCreateFunction)) {
338 // user does not set onInit method
339 return;
340 }
341 CallJSFunctionAutoRelease(onCreateFunction, abilityModel_, nullptr, 0);
342 jerry_release_value(onCreateFunction);
343 }
344
345 #ifdef _MINI_MULTI_TASKS_
346 // call js function
InvokeOnRestoreData(const char * userData,AbilitySlite::SavedResultCode retCode) const347 bool JSAbilityImpl::InvokeOnRestoreData(const char* userData, AbilitySlite::SavedResultCode retCode) const
348 {
349 // call render to setup user interface
350 if (userData == nullptr) {
351 return false;
352 }
353 if (IS_UNDEFINED(abilityModel_)) {
354 HILOG_ERROR(HILOG_MODULE_ACE, "view model is undefined when call user's onRestoreData");
355 return false;
356 }
357
358 jerry_value_t args[1];
359 args[0] = jerry_json_parse(reinterpret_cast<const jerry_char_t *>(userData), strlen(userData));
360
361 int16_t errorCode = 0;
362 switch (retCode) {
363 case AbilitySlite::SavedResultCode::SAVED_RESULT_OK:
364 errorCode = 0;
365 break;
366 case AbilitySlite::SavedResultCode::SAVED_RESULT_EXCEED_UPPER_LIMIT:
367 errorCode = 1;
368 break;
369 default:
370 errorCode = 2; // 2: default
371 break;
372 }
373 jerry_value_t propName = jerry_create_string(reinterpret_cast<const jerry_char_t *>(ERROR_CODE_KEY));
374 jerry_value_t propValue = jerry_create_number(errorCode);
375 jerry_value_t setResult = jerry_set_property(args[0], propName, propValue);
376
377 jerry_value_t onRestoreDataFunction =
378 jerryx_get_property_str(abilityModel_, ABILITY_LIFECYCLE_CALLBACK_ON_RESTORE_DATA);
379 if (IS_UNDEFINED(onRestoreDataFunction)) {
380 // user does not set onRestore method
381 ReleaseJerryValue(propName, propValue, setResult, args[0], VA_ARG_END_FLAG);
382 return false;
383 }
384 CallJSFunctionAutoRelease(onRestoreDataFunction, abilityModel_, args, 1); // todo lizhiqi args release?
385 ReleaseJerryValue(propName, propValue, setResult, args[0], onRestoreDataFunction, VA_ARG_END_FLAG);
386 return true;
387 }
388 #endif
389
InvokeOnDestroy() const390 void JSAbilityImpl::InvokeOnDestroy() const
391 {
392 InvokeMethodWithoutParameter(ABILITY_LIFECYCLE_CALLBACK_ON_DESTROY);
393 // release FeatureAbility object
394 jerry_release_value(abilityModel_);
395 }
396
InvokeOnBackPressed() const397 void JSAbilityImpl::InvokeOnBackPressed() const
398 {
399 InvokeMethodWithoutParameter(BACK_PRESSED_NAME);
400 }
401
InvokeMethodWithoutParameter(const char * const name) const402 void JSAbilityImpl::InvokeMethodWithoutParameter(const char * const name) const
403 {
404 if (FatalHandler::GetInstance().IsJSRuntimeFatal()) {
405 // can not continue to involve any JS object creating on engine in case runtime fatal
406 return;
407 }
408 if ((name == nullptr) || strlen(name) == 0) {
409 return;
410 }
411
412 jerry_value_t function = jerryx_get_property_str(abilityModel_, name);
413 if (IS_UNDEFINED(function)) {
414 // user does not set onBackpress method
415 return;
416 }
417 CallJSFunctionAutoRelease(function, abilityModel_, nullptr, 0);
418 jerry_release_value(function);
419 }
420
MarkAppViewModelEvaling(bool evaling) const421 void JSAbilityImpl::MarkAppViewModelEvaling(bool evaling) const
422 {
423 jerry_value_t propNameValue = jerry_create_string(reinterpret_cast<const jerry_char_t *>("__appVing__"));
424 jerry_value_t globalObject = jerry_get_global_object();
425 jerry_value_t evalingValue = jerry_create_boolean(evaling);
426 jerry_release_value(jerry_set_property(globalObject, propNameValue, evalingValue));
427 jerry_release_value(evalingValue);
428 jerry_release_value(propNameValue);
429 jerry_release_value(globalObject);
430 }
431
432 #ifdef _MINI_MULTI_TASKS_
GotoPage(const char * uri)433 void JSAbilityImpl::GotoPage(const char* uri)
434 {
435 if ((uri == nullptr) || (router_ == nullptr)) {
436 return;
437 }
438
439 jerry_value_t object = jerry_create_object();
440 JerrySetStringProperty(object, ROUTER_PAGE_URI, uri);
441 jerry_release_value(router_->Replace(object, false));
442 jerry_release_value(object);
443
444 rendered_ = true;
445 }
446 #endif
447 } // namespace ACELite
448 } // namespace OHOS
449