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