• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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