• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_startup_task.h"
17 
18 #include "event_report.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_runtime_utils.h"
21 #include "js_startup_task_executor.h"
22 
23 namespace OHOS {
24 namespace AbilityRuntime {
25 namespace {
26 constexpr size_t ARGC_TWO = 2;
27 constexpr int32_t INDEX_ZERO = 0;
28 constexpr int32_t INDEX_ONE = 1;
29 
30 class AsyncTaskCallBack {
31 public:
32     AsyncTaskCallBack() = default;
33     ~AsyncTaskCallBack() = default;
34 
AsyncTaskCompleted(napi_env env,napi_callback_info info)35     static napi_value AsyncTaskCompleted(napi_env env, napi_callback_info info)
36     {
37         TAG_LOGD(AAFwkTag::STARTUP, "called");
38         size_t argc = ARGC_TWO;
39         napi_value argv[ARGC_TWO] = { nullptr };
40         napi_value thisVar = nullptr;
41         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
42 
43         std::string startupName;
44         if (!ConvertFromJsValue(env, argv[INDEX_ZERO], startupName)) {
45             TAG_LOGE(AAFwkTag::STARTUP, "Convert error");
46             return CreateJsUndefined(env);
47         }
48 
49         napi_value resultJs = argv[INDEX_ONE];
50         napi_ref resultRef = nullptr;
51         napi_create_reference(env, resultJs, INDEX_ONE, &resultRef);
52         std::shared_ptr<NativeReference> result(reinterpret_cast<NativeReference*>(resultRef));
53         std::shared_ptr<StartupTaskResult> callbackResult = std::make_shared<JsStartupTaskResult>(result);
54 
55         std::shared_ptr<JsStartupTask> jsStartupTask;
56         for (const auto& iter : jsStartupTaskObjects_) {
57             if (iter.first == startupName) {
58                 jsStartupTask = iter.second.lock();
59             }
60         }
61 
62         if (jsStartupTask != nullptr) {
63             jsStartupTask->OnAsyncTaskCompleted(callbackResult);
64             jsStartupTaskObjects_.erase(startupName);
65         }
66 
67         return CreateJsUndefined(env);
68     }
69 
Constructor(napi_env env,napi_callback_info cbinfo)70     static napi_value Constructor(napi_env env, napi_callback_info cbinfo)
71     {
72         TAG_LOGD(AAFwkTag::STARTUP, "called");
73         return CreateJsUndefined(env);
74     }
75 
76     static std::map<std::string, std::weak_ptr<JsStartupTask>> jsStartupTaskObjects_;
77 };
78 std::map<std::string, std::weak_ptr<JsStartupTask>> AsyncTaskCallBack::jsStartupTaskObjects_;
79 }
80 
81 const std::string JsStartupTask::TASK_TYPE = "Js";
82 
JsStartupTask(const std::string & name,JsRuntime & jsRuntime,const StartupTaskInfo & info,const std::shared_ptr<NativeReference> & contextJsRef)83 JsStartupTask::JsStartupTask(const std::string &name, JsRuntime &jsRuntime, const StartupTaskInfo &info,
84     const std::shared_ptr<NativeReference> &contextJsRef)
85     : AppStartupTask(name), jsRuntime_(jsRuntime), startupJsRef_(nullptr), contextJsRef_(contextJsRef),
86       srcEntry_(info.srcEntry), ohmUrl_(info.ohmUrl), hapPath_(info.hapPath), esModule_(info.esModule)
87 {
88     SetModuleName(info.moduleName);
89 }
90 
JsStartupTask(const std::string & name,JsRuntime & jsRuntime,std::unique_ptr<NativeReference> & startupJsRef,std::shared_ptr<NativeReference> & contextJsRef)91 JsStartupTask::JsStartupTask(const std::string& name, JsRuntime& jsRuntime,
92     std::unique_ptr<NativeReference>& startupJsRef, std::shared_ptr<NativeReference>& contextJsRef)
93     : AppStartupTask(name), jsRuntime_(jsRuntime), startupJsRef_(std::move(startupJsRef)), contextJsRef_(contextJsRef)
94 {
95 }
96 
97 JsStartupTask::~JsStartupTask() = default;
98 
GetType() const99 const std::string &JsStartupTask::GetType() const
100 {
101     return TASK_TYPE;
102 }
103 
RunTaskInit(std::unique_ptr<StartupTaskResultCallback> callback)104 int32_t JsStartupTask::RunTaskInit(std::unique_ptr<StartupTaskResultCallback> callback)
105 {
106     TAG_LOGI(AAFwkTag::STARTUP, "task: %{public}s init", GetName().c_str());
107     if (startupJsRef_ == nullptr) {
108         int32_t result = LoadJsOhmUrl();
109         if (result != ERR_OK) {
110             return result;
111         }
112     }
113     if (callCreateOnMainThread_) {
114         return JsStartupTaskExecutor::RunOnMainThread(jsRuntime_, startupJsRef_, contextJsRef_, std::move(callback));
115     }
116     AAFwk::EventInfo eventInfo;
117     if (LoadJsAsyncTaskExecutor() != ERR_OK) {
118         TAG_LOGE(AAFwkTag::STARTUP, "LoadJsAsyncTaskExecutor failed");
119         eventInfo.errCode = NAPI_CREATE_OBJECT_FAILED;
120         eventInfo.errReason = "LoadJsAsyncTaskExecutor failed";
121         AAFwk::EventReport::SendLaunchFrameworkEvent(
122             AAFwk::EventName::STARTUP_TASK_ERROR, HiSysEventType::FAULT, eventInfo);
123         return ERR_STARTUP_INTERNAL_ERROR;
124     }
125     LoadJsAsyncTaskCallback();
126 
127     startupTaskResultCallback_ = std::move(callback);
128 
129     auto result = JsStartupTaskExecutor::RunOnTaskPool(
130         jsRuntime_, startupJsRef_, contextJsRef_, AsyncTaskExecutorJsRef_, AsyncTaskExecutorCallbackJsRef_, name_);
131     if (result == ERR_OK) {
132         AsyncTaskCallBack::jsStartupTaskObjects_.emplace(name_,
133             std::static_pointer_cast<JsStartupTask>(shared_from_this()));
134     }
135     return result;
136 }
137 
LoadJsOhmUrl()138 int32_t JsStartupTask::LoadJsOhmUrl()
139 {
140     TAG_LOGD(AAFwkTag::STARTUP, "call");
141     if (srcEntry_.empty() && ohmUrl_.empty()) {
142         TAG_LOGE(AAFwkTag::STARTUP, "srcEntry and ohmUrl empty");
143         return ERR_STARTUP_INTERNAL_ERROR;
144     }
145 
146     std::string moduleNameWithStartupTask = moduleName_ + "::startupTask";
147     std::string srcPath(moduleName_ + "/" + srcEntry_);
148     auto pos = srcPath.rfind('.');
149     if (pos == std::string::npos) {
150         TAG_LOGE(AAFwkTag::STARTUP, "invalid srcEntry");
151         return ERR_STARTUP_INTERNAL_ERROR;
152     }
153     srcPath.erase(pos);
154     srcPath.append(".abc");
155     startupJsRef_ = jsRuntime_.LoadModule(moduleNameWithStartupTask, srcPath, hapPath_, esModule_, false, ohmUrl_);
156     if (startupJsRef_ == nullptr) {
157         TAG_LOGE(AAFwkTag::STARTUP, "startup task null");
158         return ERR_STARTUP_INTERNAL_ERROR;
159     }
160     return ERR_OK;
161 }
162 
LoadJsAsyncTaskExecutor()163 int32_t JsStartupTask::LoadJsAsyncTaskExecutor()
164 {
165     TAG_LOGD(AAFwkTag::STARTUP, "called");
166     HandleScope handleScope(jsRuntime_);
167     auto env = jsRuntime_.GetNapiEnv();
168 
169     napi_value object = nullptr;
170     napi_create_object(env, &object);
171     if (object == nullptr) {
172         TAG_LOGE(AAFwkTag::STARTUP, "null object");
173         return ERR_STARTUP_INTERNAL_ERROR;
174     }
175 
176     AsyncTaskExecutorJsRef_ =
177         JsRuntime::LoadSystemModuleByEngine(env, "app.appstartup.AsyncTaskExcutor", &object, 1);
178     return ERR_OK;
179 }
180 
LoadJsAsyncTaskCallback()181 void JsStartupTask::LoadJsAsyncTaskCallback()
182 {
183     TAG_LOGD(AAFwkTag::STARTUP, "called");
184     HandleScope handleScope(jsRuntime_);
185     auto env = jsRuntime_.GetNapiEnv();
186 
187     napi_value config;
188     std::string value = "This is callback value";
189     NAPI_CALL_RETURN_VOID(
190         env, napi_create_string_utf8(env, value.c_str(), value.length(), &config));
191 
192     napi_property_descriptor props[] = {
193         DECLARE_NAPI_STATIC_FUNCTION("onAsyncTaskCompleted", AsyncTaskCallBack::AsyncTaskCompleted),
194         DECLARE_NAPI_INSTANCE_PROPERTY("config", config),
195     };
196     napi_value asyncTaskCallbackClass = nullptr;
197     napi_define_sendable_class(env, "AsyncTaskCallback", NAPI_AUTO_LENGTH, AsyncTaskCallBack::Constructor,
198         nullptr, sizeof(props) / sizeof(props[0]), props, nullptr, &asyncTaskCallbackClass);
199     AsyncTaskExecutorCallbackJsRef_ =
200         JsRuntime::LoadSystemModuleByEngine(env, "app.appstartup.AsyncTaskCallback", &asyncTaskCallbackClass, 1);
201 }
202 
OnAsyncTaskCompleted(const std::shared_ptr<StartupTaskResult> & result)203 void JsStartupTask::OnAsyncTaskCompleted(const std::shared_ptr<StartupTaskResult>  &result)
204 {
205     TAG_LOGD(AAFwkTag::STARTUP, "called");
206     if (startupTaskResultCallback_ == nullptr) {
207         TAG_LOGE(AAFwkTag::STARTUP, "null startupTaskResultCallback");
208         return;
209     }
210     startupTaskResultCallback_->Call(result);
211 }
212 
UpdateContextRef(std::shared_ptr<NativeReference> & contextJsRef)213 void JsStartupTask::UpdateContextRef(std::shared_ptr<NativeReference> &contextJsRef)
214 {
215     contextJsRef_ = contextJsRef;
216 }
217 
RunTaskOnDependencyCompleted(const std::string & dependencyName,const std::shared_ptr<StartupTaskResult> & result)218 int32_t JsStartupTask::RunTaskOnDependencyCompleted(const std::string &dependencyName,
219     const std::shared_ptr<StartupTaskResult> &result)
220 {
221     HandleScope handleScope(jsRuntime_);
222     auto env = jsRuntime_.GetNapiEnv();
223 
224     if (startupJsRef_ == nullptr) {
225         int32_t result = LoadJsOhmUrl();
226         if (result != ERR_OK) {
227             return result;
228         }
229     }
230     napi_value startupValue = startupJsRef_->GetNapiValue();
231     if (!CheckTypeForNapiValue(env, startupValue, napi_object)) {
232         TAG_LOGE(AAFwkTag::STARTUP, "%{public}s, not napi object", name_.c_str());
233         return ERR_STARTUP_INTERNAL_ERROR;
234     }
235     napi_value startupOnDepCompleted = nullptr;
236     napi_get_named_property(env, startupValue, "onDependencyCompleted", &startupOnDepCompleted);
237     if (startupOnDepCompleted == nullptr) {
238         TAG_LOGE(AAFwkTag::STARTUP, "%{public}s, get onDependencyCompleted failed", name_.c_str());
239         return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
240     }
241     bool isCallable = false;
242     napi_is_callable(env, startupOnDepCompleted, &isCallable);
243     if (!isCallable) {
244         TAG_LOGW(AAFwkTag::STARTUP, "onDependencyCompleted not callable:%{public}s", name_.c_str());
245         return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
246     }
247 
248     napi_value jsResult = GetDependencyResult(env, dependencyName, result);
249     napi_value dependency = CreateJsValue(env, dependencyName);
250     constexpr size_t argc = 2;
251     napi_value argv[argc] = { dependency, jsResult };
252     napi_call_function(env, startupValue, startupOnDepCompleted, argc, argv, nullptr);
253     return ERR_OK;
254 }
255 
GetDependencyResult(napi_env env,const std::string & dependencyName,const std::shared_ptr<StartupTaskResult> & result)256 napi_value JsStartupTask::GetDependencyResult(napi_env env, const std::string &dependencyName,
257     const std::shared_ptr<StartupTaskResult> &result)
258 {
259     if (result == nullptr || result->GetResultType() != StartupTaskResult::ResultType::JS) {
260         return CreateJsUndefined(env);
261     } else {
262         std::shared_ptr<JsStartupTaskResult> jsResultPtr = std::static_pointer_cast<JsStartupTaskResult>(result);
263         if (jsResultPtr == nullptr) {
264             TAG_LOGE(AAFwkTag::STARTUP, "%{public}s, convert failed", dependencyName.c_str());
265             return CreateJsUndefined(env);
266         }
267         std::shared_ptr<NativeReference> jsResultRef = jsResultPtr->GetJsStartupResultRef();
268         if (jsResultRef == nullptr) {
269             return CreateJsUndefined(env);
270         }
271         return jsResultRef->GetNapiValue();
272     }
273 }
274 } // namespace AbilityRuntime
275 } // namespace OHOS
276