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.h"
17 
18 #include <cstring>
19 #include "ace_event_error_code.h"
20 #include "ace_log.h"
21 #include "acelite_config.h"
22 #include "async_task_manager.h"
23 #if (OHOS_ACELITE_PRODUCT_WATCH == 1)
24 #include "dft_impl.h"
25 #endif // OHOS_ACELITE_PRODUCT_WATCH
26 #include "fatal_handler.h"
27 #include "js_ability_impl.h"
28 #include "js_async_work.h"
29 #include "js_profiler.h"
30 #include "product_adapter.h"
31 #if (defined(__LINUX__) || defined(__LITEOS_A__))
32 #include "ace_ability.h"
33 #endif
34 #include "module_manager.h"
35 
36 namespace OHOS {
37 namespace ACELite {
38 /**
39  * This is a helper function to cast void* to JSAbilityImpl*, for header separating purpose.
40  */
CastAbilityImpl(void * abilityImpl)41 static JSAbilityImpl *CastAbilityImpl(void *abilityImpl)
42 {
43     if (abilityImpl == nullptr) {
44         return nullptr;
45     }
46 
47     return static_cast<JSAbilityImpl *>(abilityImpl);
48 }
49 
DumpNativeMemoryUsage()50 static void DumpNativeMemoryUsage()
51 {
52 #if (OHOS_ACELITE_PRODUCT_WATCH == 1)
53     NativeMemInfo memInfo;
54     ProductAdapter::GetNativeMemInfo(&memInfo);
55     HILOG_DEBUG(HILOG_MODULE_ACE, "available free size: %{public}d", memInfo.freeSize);
56 #endif // OHOS_ACELITE_PRODUCT_WATCH
57 }
58 
~JSAbility()59 JSAbility::~JSAbility()
60 {
61     // check the status
62     if (jsAbilityImpl_ != nullptr) {
63         // the JSAbility instance can only be destroied after transfering the app to DESTROY state
64         ProductAdapter::RestoreSystemWrapper("AMS is deleting app task but without normal lifecycle transition!");
65     }
66 }
67 
Launch(const char * const abilityPath,const char * const bundleName,uint16_t token,const char * pageInfo)68 void JSAbility::Launch(const char * const abilityPath, const char * const bundleName, uint16_t token,
69                        const char *pageInfo)
70 {
71     if (jsAbilityImpl_ != nullptr) {
72         HILOG_ERROR(HILOG_MODULE_ACE, "Launch only can be triggered once");
73         ACE_ERROR_CODE_PRINT(EXCE_ACE_FWK_LAUNCH_FAILED, EXCE_ACE_APP_ALREADY_LAUNCHED);
74         return;
75     }
76 
77     if ((abilityPath == nullptr) || (strlen(abilityPath) == 0)) {
78         HILOG_ERROR(HILOG_MODULE_ACE, "invalid app path");
79         ACE_ERROR_CODE_PRINT(EXCE_ACE_FWK_LAUNCH_FAILED, EXCE_ACE_INVALID_APP_PATH);
80         return;
81     }
82 
83     if ((bundleName == nullptr) || (strlen(bundleName) == 0)) {
84         HILOG_ERROR(HILOG_MODULE_ACE, "invalid bundle name");
85         ACE_ERROR_CODE_PRINT(EXCE_ACE_FWK_LAUNCH_FAILED, EXCE_ACE_INVALID_BUNDLE_NAME);
86         return;
87     }
88 
89     HILOG_INFO(HILOG_MODULE_ACE, "LIFECYCLE: JS Ability is launching");
90 
91 #if (MOCK_JS_ASYNC_WORK != 1)
92     JsAsyncWork::SetFatalHandleFunc(FatalHandler::IsErrorHittedWrapper, FatalHandler::IsAppExitingWrapper);
93 #endif
94 #if (defined(__LINUX__) || defined(__LITEOS_A__))
95     JsAsyncWork::SetPostUITaskFunc(AceAbility::PostUITask);
96 #endif
97     ModuleManager::GetInstance()->SetBundleNameGetter(JSAbility::GetPackageName);
98     DumpNativeMemoryUsage();
99     jsAbilityImpl_ = new JSAbilityImpl();
100     if (jsAbilityImpl_ == nullptr) {
101         HILOG_ERROR(HILOG_MODULE_ACE, "Create JSAbilityRuntime failed");
102         return;
103     }
104     START_TRACING(LAUNCH);
105     // mark the flag in advance to make sure we can take over render tick as soon as possible
106     ProductAdapter::UpdateRenderTickAcceptable(true);
107     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
108 #if (MOCK_JS_ASYNC_WORK != 1)
109     // simulator uses the self-implementation for async work, this interface is not included
110     JsAsyncWork::SetEnvStatus(true);
111 #endif
112     jsAbilityImpl->InitEnvironment(abilityPath, bundleName, token);
113     ACE_EVENT_PRINT(MT_ACE_FWK_LAUNCHING, 0);
114     FatalHandler::GetInstance().RegisterFatalHandler(this);
115 #ifdef _MINI_MULTI_TASKS_
116     jsAbilityImpl->DeliverCreate();
117 #else
118     jsAbilityImpl->DeliverCreate(pageInfo);
119 #endif
120     ProductAdapter::UpdateDefaultFont();
121     STOP_TRACING();
122     OUTPUT_TRACE();
123 }
124 
125 #ifdef _MINI_MULTI_TASKS_
OnRestoreData(AbilitySlite::AbilitySavedData * data)126 void JSAbility::OnRestoreData(AbilitySlite::AbilitySavedData *data)
127 {
128     if (jsAbilityImpl_ == nullptr) {
129         HILOG_ERROR(HILOG_MODULE_ACE, "Must trigger Launch first");
130         return;
131     }
132     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
133     jsAbilityImpl->OnRestoreData(data);
134 }
135 #endif
136 
Show()137 void JSAbility::Show()
138 {
139     if (jsAbilityImpl_ == nullptr) {
140         HILOG_ERROR(HILOG_MODULE_ACE, "Must trigger Launch first");
141         return;
142     }
143 
144     HILOG_INFO(HILOG_MODULE_ACE, "LIFECYCLE: JS Ability will be shown");
145     ACE_EVENT_PRINT(MT_ACE_FWK_ACTIVING, 0);
146     FatalHandler::GetInstance().SetExitingFlag(false);
147     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
148     jsAbilityImpl->Show();
149     AsyncTaskManager::GetInstance().SetFront(true);
150     ProductAdapter::UpdateRenderTickAcceptable(true);
151     isActived_ = true;
152 }
153 
Hide()154 void JSAbility::Hide()
155 {
156     if (jsAbilityImpl_ == nullptr) {
157         HILOG_ERROR(HILOG_MODULE_ACE, "Must trigger Launch first");
158         return;
159     }
160     HILOG_INFO(HILOG_MODULE_ACE, "LIFECYCLE: JS Ability will be hidden");
161     ACE_EVENT_PRINT(MT_ACE_FWK_HIDING, 0);
162     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
163     jsAbilityImpl->Hide();
164     AsyncTaskManager::GetInstance().SetFront(false);
165     ProductAdapter::UpdateRenderTickAcceptable(false);
166     isActived_ = false;
167 }
168 
169 #ifdef _MINI_MULTI_TASKS_
OnSaveData(AbilitySlite::AbilitySavedData * data)170 void JSAbility::OnSaveData(AbilitySlite::AbilitySavedData *data)
171 {
172     if (jsAbilityImpl_ == nullptr) {
173         HILOG_ERROR(HILOG_MODULE_ACE, "Must trigger Launch first");
174         return;
175     }
176     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
177     jsAbilityImpl->OnSaveData(data);
178 }
179 #endif
180 
TransferToDestroy()181 void JSAbility::TransferToDestroy()
182 {
183     if (jsAbilityImpl_ == nullptr) {
184         HILOG_ERROR(HILOG_MODULE_ACE, "Must trigger Launch first");
185         return;
186     }
187 
188 #if (MOCK_JS_ASYNC_WORK != 1)
189     // simulator uses the self-implementation for async work, this interface is not included
190     JsAsyncWork::SetEnvStatus(false);
191 #endif
192     HILOG_INFO(HILOG_MODULE_ACE, "LIFECYCLE: JS Ability is exiting");
193     ACE_EVENT_PRINT(MT_ACE_FWK_DESTROYING, 0);
194     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
195     jsAbilityImpl->CleanUp();
196     // Reset render flag or low layer task mutex in case we are during the rendering process,
197     // this situation might happen if the destroy function is called outside of JS thread, such as AMS.
198     ProductAdapter::UpdateRenderTickAcceptable(false);
199     FatalHandler::GetInstance().ResetRendering();
200     FatalHandler::GetInstance().SetExitingFlag(false);
201 #if (FEATURE_SCREEN_ON_VISIBLE == 1)
202     if (ProductAdapter::SetScreenOnVisible(false) == false) {
203         HILOG_ERROR(HILOG_MODULE_ACE, "Fail to recover screen visible property");
204     }
205 #endif
206 #if (OHOS_ACELITE_PRODUCT_WATCH == 1)
207     JsAsyncWork::SetAppQueueHandler(nullptr);
208     DftImpl::GetInstance()->RegisterPageReplaced(nullptr);
209 #endif // OHOS_ACELITE_PRODUCT_WATCH
210     delete reinterpret_cast<JSAbilityImpl *>(jsAbilityImpl_);
211     jsAbilityImpl_ = nullptr;
212     DumpNativeMemoryUsage();
213 }
214 
BackPressed()215 void JSAbility::BackPressed()
216 {
217     if (jsAbilityImpl_ == nullptr) {
218         HILOG_ERROR(HILOG_MODULE_ACE, "Must trigger Launch first");
219         return;
220     }
221 
222     JSAbilityImpl *jsAbilityImpl = CastAbilityImpl(jsAbilityImpl_);
223     jsAbilityImpl->NotifyBackPressed();
224 }
225 
GetPackageName()226 const char *JSAbility::GetPackageName()
227 {
228     return JsAppContext::GetInstance()->GetCurrentBundleName();
229 }
230 
231 // this public interface will be deprecated, only fatal scenario can trigger force destroy
ForceDestroy()232 void JSAbility::ForceDestroy()
233 {
234     HILOG_ERROR(HILOG_MODULE_ACE, "ForceDestroy interface is deprecated as JS engine can not run on other task");
235 }
236 
IsRecycled()237 bool JSAbility::IsRecycled()
238 {
239     return (jsAbilityImpl_ == nullptr);
240 }
241 
GetLazyLoadManager()242 LazyLoadManager *GetLazyLoadManager()
243 {
244     JsAppContext *context = JsAppContext::GetInstance();
245     return const_cast<LazyLoadManager *>(context->GetLazyLoadManager());
246 }
247 
GetLazyLoadManagerState()248 LazyLoadState GetLazyLoadManagerState()
249 {
250     LazyLoadManager *lazyLoadManager = GetLazyLoadManager();
251     return lazyLoadManager->GetState();
252 }
253 
LazyLoadHandleRenderTick(void * data)254 void JSAbility::LazyLoadHandleRenderTick(void *data)
255 {
256     UNUSED(data);
257     // double check, if state reseted, break
258     LazyLoadState state = GetLazyLoadManagerState();
259     if (state == LazyLoadState::INIT || state == LazyLoadState::DONE) {
260         return;
261     }
262 
263     GetLazyLoadManager()->RenderLazyLoadWatcher();
264 }
265 
HandleRenderTick()266 void JSAbility::HandleRenderTick()
267 {
268     if (!isActived_) {
269         // skip the TE tick if we are not foreground
270         ProductAdapter::NotifyRenderEnd();
271         errorTickCount_++;
272         if ((errorTickCount_ % ERR_TICK_COUNT_TRACE_CTRL) == 1) {
273             HILOG_WARN(HILOG_MODULE_ACE, "skip one render tick process since not activated, count[%{public}d]",
274                        errorTickCount_);
275         }
276         if (errorTickCount_ == UINT32_MAX) {
277             errorTickCount_ = 0;
278         }
279         return;
280     }
281 
282     // reset error tick tracing count
283     errorTickCount_ = 0;
284     if ((ProductAdapter::IsTEHandlersRegisted()) && !(FatalHandler::GetInstance().IsAppExiting())) {
285         FatalHandler::GetInstance().SetTEHandlingFlag(true);
286         ProductAdapter::ProcessOneTE();
287         // check if state is ready
288         if (GetLazyLoadManagerState() == LazyLoadState::READY) {
289             JsAsyncWork::DispatchAsyncWork(LazyLoadHandleRenderTick, nullptr);
290         }
291         FatalHandler::GetInstance().SetTEHandlingFlag(false);
292     }
293 }
294 } // namespace ACELite
295 } // namespace OHOS
296