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_executor.h"
17
18 #include "hilog_tag_wrapper.h"
19 #include "js_runtime_utils.h"
20 #include "js_startup_task_result.h"
21
22 #define TMP_NAPI_ANONYMOUS_FUNC "_"
23 namespace {
24 constexpr size_t ARGC_FOUR = 4;
25 }
26 namespace OHOS {
27 namespace AbilityRuntime {
RunOnMainThread(JsRuntime & jsRuntime,const std::unique_ptr<NativeReference> & startup,const std::shared_ptr<NativeReference> & context,std::unique_ptr<StartupTaskResultCallback> callback)28 int32_t JsStartupTaskExecutor::RunOnMainThread(JsRuntime &jsRuntime,
29 const std::unique_ptr<NativeReference> &startup, const std::shared_ptr<NativeReference> &context,
30 std::unique_ptr<StartupTaskResultCallback> callback)
31 {
32 HandleScope handleScope(jsRuntime);
33 auto env = jsRuntime.GetNapiEnv();
34
35 napi_value returnVal = nullptr;
36 int32_t resultCode = CallStartupInit(env, startup, context, callback, returnVal);
37 if (resultCode != ERR_OK) {
38 return resultCode;
39 }
40 return HandleReturnVal(env, returnVal, callback);
41 }
42
RunOnTaskPool(JsRuntime & jsRuntime,const std::unique_ptr<NativeReference> & startup,const std::shared_ptr<NativeReference> & context,const std::unique_ptr<NativeReference> & asyncTaskExcutor,const std::unique_ptr<NativeReference> & asyncTaskCallback,const std::string & startupName)43 int32_t JsStartupTaskExecutor::RunOnTaskPool(
44 JsRuntime &jsRuntime,
45 const std::unique_ptr<NativeReference> &startup,
46 const std::shared_ptr<NativeReference> &context,
47 const std::unique_ptr<NativeReference> &asyncTaskExcutor,
48 const std::unique_ptr<NativeReference> &asyncTaskCallback,
49 const std::string &startupName)
50 {
51 TAG_LOGD(AAFwkTag::STARTUP, "called");
52 HandleScope handleScope(jsRuntime);
53 auto env = jsRuntime.GetNapiEnv();
54
55 if (startup == nullptr || context == nullptr || asyncTaskExcutor == nullptr || asyncTaskCallback == nullptr) {
56 TAG_LOGE(AAFwkTag::STARTUP, "args null");
57 return ERR_STARTUP_INTERNAL_ERROR;
58 }
59 napi_value asyncTaskExcutorValue = asyncTaskExcutor->GetNapiValue();
60 if (!CheckTypeForNapiValue(env, asyncTaskExcutorValue, napi_object)) {
61 TAG_LOGE(AAFwkTag::STARTUP, "not napi object");
62 return ERR_STARTUP_INTERNAL_ERROR;
63 }
64 napi_value asyncPushTask = nullptr;
65 napi_get_named_property(env, asyncTaskExcutorValue, "asyncPushTask", &asyncPushTask);
66 if (asyncPushTask == nullptr) {
67 TAG_LOGE(AAFwkTag::STARTUP, "AsyncPushTask null");
68 return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
69 }
70 bool isCallable = false;
71 napi_is_callable(env, asyncPushTask, &isCallable);
72 if (!isCallable) {
73 TAG_LOGE(AAFwkTag::STARTUP, "AsyncPushTask not callable");
74 return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
75 }
76 napi_value returnVal = nullptr;
77 napi_value argv[] = { startup->GetNapiValue(), asyncTaskCallback->GetNapiValue(),
78 context->GetNapiValue(), CreateJsValue(env, startupName) };
79 napi_call_function(env, asyncTaskExcutorValue, asyncPushTask, ARGC_FOUR, argv, &returnVal);
80 return ERR_OK;
81 }
82
CallStartupInit(napi_env env,const std::unique_ptr<NativeReference> & startup,const std::shared_ptr<NativeReference> & context,std::unique_ptr<StartupTaskResultCallback> & callback,napi_value & returnVal)83 int32_t JsStartupTaskExecutor::CallStartupInit(napi_env env, const std::unique_ptr<NativeReference> &startup,
84 const std::shared_ptr<NativeReference> &context, std::unique_ptr<StartupTaskResultCallback> &callback,
85 napi_value &returnVal)
86 {
87 if (startup == nullptr || context == nullptr) {
88 ReplyFailed(std::move(callback), ERR_STARTUP_INTERNAL_ERROR,
89 "startup task is null or context is null.");
90 return ERR_STARTUP_INTERNAL_ERROR;
91 }
92 napi_value startupValue = startup->GetNapiValue();
93 if (!CheckTypeForNapiValue(env, startupValue, napi_object)) {
94 ReplyFailed(std::move(callback), ERR_STARTUP_INTERNAL_ERROR,
95 "startup task is not napi object.");
96 return ERR_STARTUP_INTERNAL_ERROR;
97 }
98 napi_value startupInit = nullptr;
99 napi_get_named_property(env, startupValue, "init", &startupInit);
100 if (startupInit == nullptr) {
101 ReplyFailed(std::move(callback), ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP,
102 "failed to get property init from startup task.");
103 return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
104 }
105 bool isCallable = false;
106 napi_is_callable(env, startupInit, &isCallable);
107 if (!isCallable) {
108 ReplyFailed(std::move(callback), ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP,
109 "startup task init is not callable.");
110 return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
111 }
112 napi_value argv[1] = { context->GetNapiValue() };
113 napi_call_function(env, startupValue, startupInit, 1, argv, &returnVal);
114 return ERR_OK;
115 }
116
HandleReturnVal(napi_env env,napi_value returnVal,std::unique_ptr<StartupTaskResultCallback> & callback)117 int32_t JsStartupTaskExecutor::HandleReturnVal(napi_env env, napi_value returnVal,
118 std::unique_ptr<StartupTaskResultCallback> &callback)
119 {
120 bool isPromise = false;
121 napi_is_promise(env, returnVal, &isPromise);
122 if (!isPromise) {
123 ReplyFailed(std::move(callback), ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP,
124 "the return value of startup task init is not promise.");
125 return ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP;
126 }
127
128 auto *callbackPtr = callback.release();
129 napi_value promiseThen = nullptr;
130 napi_get_named_property(env, returnVal, "then", &promiseThen);
131 napi_value promiseResolveCallback = nullptr;
132 napi_create_function(env, TMP_NAPI_ANONYMOUS_FUNC, strlen(TMP_NAPI_ANONYMOUS_FUNC),
133 ResolveResultCallback, callbackPtr, &promiseResolveCallback);
134 napi_value argvThen[1] = { promiseResolveCallback };
135 napi_call_function(env, returnVal, promiseThen, 1, argvThen, nullptr);
136
137 napi_value promiseCatch = nullptr;
138 napi_get_named_property(env, returnVal, "catch", &promiseCatch);
139 napi_value promiseRejectCallback = nullptr;
140 napi_create_function(env, TMP_NAPI_ANONYMOUS_FUNC, strlen(TMP_NAPI_ANONYMOUS_FUNC),
141 RejectResultCallback, callbackPtr, &promiseRejectCallback);
142 napi_value argvCatch[1] = { promiseRejectCallback };
143 napi_call_function(env, returnVal, promiseCatch, 1, argvCatch, nullptr);
144 return ERR_OK;
145 }
146
ResolveResultCallback(napi_env env,napi_callback_info info)147 napi_value JsStartupTaskExecutor::ResolveResultCallback(napi_env env, napi_callback_info info)
148 {
149 TAG_LOGD(AAFwkTag::STARTUP, "enter");
150 size_t argc = 1;
151 napi_value argv[1] = { nullptr };
152 void *data = nullptr;
153 napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
154 auto *callback = static_cast<StartupTaskResultCallback *>(data);
155 napi_value resultJs = argv[0];
156 napi_ref resultRef = nullptr;
157 napi_create_reference(env, resultJs, 1, &resultRef);
158 std::shared_ptr<NativeReference> result(reinterpret_cast<NativeReference*>(resultRef));
159 ReplySucceeded(callback, result);
160 return nullptr;
161 }
162
RejectResultCallback(napi_env env,napi_callback_info info)163 napi_value JsStartupTaskExecutor::RejectResultCallback(napi_env env, napi_callback_info info)
164 {
165 TAG_LOGD(AAFwkTag::STARTUP, "enter");
166 void *data = nullptr;
167 napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data);
168 auto *callback = static_cast<StartupTaskResultCallback *>(data);
169 ReplyFailed(callback, ERR_STARTUP_FAILED_TO_EXECUTE_STARTUP,
170 "the promise of startup task init is reject.");
171 return nullptr;
172 }
173
ReplyFailed(StartupTaskResultCallback * callback,int32_t resultCode,const std::string & resultMessage)174 void JsStartupTaskExecutor::ReplyFailed(StartupTaskResultCallback *callback,
175 int32_t resultCode, const std::string &resultMessage)
176 {
177 TAG_LOGD(AAFwkTag::STARTUP, "enter");
178 if (callback == nullptr) {
179 return;
180 }
181 std::shared_ptr<StartupTaskResult> result = std::make_shared<JsStartupTaskResult>(resultCode, resultMessage);
182 callback->Call(result);
183 delete callback;
184 callback = nullptr;
185 }
186
ReplyFailed(std::unique_ptr<StartupTaskResultCallback> callback,int32_t resultCode,const std::string & resultMessage)187 void JsStartupTaskExecutor::ReplyFailed(std::unique_ptr<StartupTaskResultCallback> callback,
188 int32_t resultCode, const std::string &resultMessage)
189 {
190 TAG_LOGE(AAFwkTag::STARTUP, "Failed to execute: %{public}s", resultMessage.c_str());
191 if (callback == nullptr) {
192 return;
193 }
194 std::shared_ptr<StartupTaskResult> result = std::make_shared<JsStartupTaskResult>(resultCode, resultMessage);
195 callback->Call(result);
196 }
197
ReplySucceeded(StartupTaskResultCallback * callback,const std::shared_ptr<NativeReference> & resultRef)198 void JsStartupTaskExecutor::ReplySucceeded(StartupTaskResultCallback *callback,
199 const std::shared_ptr<NativeReference> &resultRef)
200 {
201 TAG_LOGD(AAFwkTag::STARTUP, "enter");
202 if (callback == nullptr) {
203 return;
204 }
205 std::shared_ptr<StartupTaskResult> result = std::make_shared<JsStartupTaskResult>(resultRef);
206 callback->Call(result);
207 delete callback;
208 callback = nullptr;
209 }
210 } // namespace AbilityRuntime
211 } // namespace OHOS
212