• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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_runtime_utils.h"
17 
18 #include "hilog_tag_wrapper.h"
19 
20 namespace OHOS {
21 namespace AbilityRuntime {
22 #define ARGS_MAX_COUNT 10
23 namespace {
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,std::unique_ptr<NapiAsyncTask::ExecuteCallback> && execute,std::unique_ptr<NapiAsyncTask::CompleteCallback> && complete,napi_value * result)24 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
25     std::unique_ptr<NapiAsyncTask::ExecuteCallback> &&execute,
26     std::unique_ptr<NapiAsyncTask::CompleteCallback> &&complete, napi_value* result)
27 {
28     napi_valuetype type = napi_undefined;
29     napi_typeof(env, lastParam, &type);
30     if (lastParam == nullptr || type != napi_function) {
31         napi_deferred nativeDeferred = nullptr;
32         napi_create_promise(env, &nativeDeferred, result);
33         return std::make_unique<NapiAsyncTask>(nativeDeferred, std::move(execute), std::move(complete));
34     } else {
35         napi_get_undefined(env, result);
36         napi_ref callbackRef = nullptr;
37         napi_create_reference(env, lastParam, 1, &callbackRef);
38         return std::make_unique<NapiAsyncTask>(callbackRef, std::move(execute), std::move(complete));
39     }
40 }
41 } // namespace
42 
43 // Help Functions
CreateJsError(napi_env env,int32_t errCode,const std::string & message)44 napi_value CreateJsError(napi_env env, int32_t errCode, const std::string &message)
45 {
46     napi_value result = nullptr;
47     napi_create_error(env, CreateJsValue(env, errCode), CreateJsValue(env, message), &result);
48     return result;
49 }
50 
BindNativeFunction(napi_env env,napi_value object,const char * name,const char * moduleName,napi_callback func)51 void BindNativeFunction(napi_env env, napi_value object, const char *name,
52     const char *moduleName, napi_callback func)
53 {
54     std::string fullName(moduleName);
55     fullName += ".";
56     fullName += name;
57     napi_value result = nullptr;
58     napi_create_function(env, fullName.c_str(), fullName.length(), func, nullptr, &result);
59     napi_set_named_property(env, object, name, result);
60 }
61 
BindNativeProperty(napi_env env,napi_value object,const char * name,napi_callback getter)62 void BindNativeProperty(napi_env env, napi_value object, const char *name, napi_callback getter)
63 {
64     napi_property_descriptor properties[1];
65     properties[0].utf8name = name;
66     properties[0].name = nullptr;
67     properties[0].method = nullptr;
68     properties[0].getter = getter;
69     properties[0].setter = nullptr;
70     properties[0].value = nullptr;
71     properties[0].attributes = napi_default;
72     properties[0].data = nullptr;
73     napi_define_properties(env, object, 1, properties);
74 }
75 
GetNativePointerFromCallbackInfo(const napi_env env,napi_callback_info info,const char * name)76 void *GetNativePointerFromCallbackInfo(const napi_env env, napi_callback_info info, const char *name)
77 {
78     size_t argcAsync = ARGS_MAX_COUNT;
79     napi_value args[ARGS_MAX_COUNT] = {nullptr};
80     napi_value thisVar = nullptr;
81     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argcAsync, args, &thisVar, nullptr), nullptr);
82     if (name != nullptr) {
83         napi_get_named_property(env, thisVar, name, &thisVar);
84     }
85     void* result = nullptr;
86     NAPI_CALL_NO_THROW(napi_unwrap(env, thisVar, &result), nullptr);
87     return result;
88 }
89 
GetNapiCallbackInfoAndThis(napi_env env,napi_callback_info info,NapiCallbackInfo & napiInfo,const char * name)90 void* GetNapiCallbackInfoAndThis(napi_env env, napi_callback_info info, NapiCallbackInfo& napiInfo, const char* name)
91 {
92     NAPI_CALL_NO_THROW(napi_get_cb_info(
93         env, info, &napiInfo.argc, napiInfo.argv, &napiInfo.thisVar, nullptr), nullptr);
94     napi_value value = napiInfo.thisVar;
95     if (name != nullptr) {
96         napi_get_named_property(env, value, name, &value);
97     }
98     void* result = nullptr;
99     NAPI_CALL_NO_THROW(napi_unwrap(env, value, &result), nullptr);
100     return result;
101 }
102 
SetNamedNativePointer(napi_env env,napi_value object,const char * name,void * ptr,napi_finalize func)103 void SetNamedNativePointer(napi_env env, napi_value object, const char *name, void *ptr, napi_finalize func)
104 {
105     napi_value objValue = nullptr;
106     napi_create_object(env, &objValue);
107     napi_wrap(env, objValue, ptr, func, nullptr, nullptr);
108     napi_set_named_property(env, object, name, objValue);
109 }
110 
GetNamedNativePointer(napi_env env,napi_value object,const char * name)111 void *GetNamedNativePointer(napi_env env, napi_value object, const char *name)
112 {
113     napi_value proValue = nullptr;
114     napi_get_named_property(env, object, name, &proValue);
115     void* result = nullptr;
116     napi_unwrap(env, proValue, &result);
117     return result;
118 }
119 
CheckTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)120 bool CheckTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
121 {
122     napi_valuetype valueType = napi_undefined;
123     if (napi_typeof(env, param, &valueType) != napi_ok) {
124         return false;
125     }
126     return valueType == expectType;
127 }
128 
129 // Async Task
NapiAsyncTask(napi_deferred deferred,std::unique_ptr<NapiAsyncTask::ExecuteCallback> && execute,std::unique_ptr<NapiAsyncTask::CompleteCallback> && complete)130 NapiAsyncTask::NapiAsyncTask(napi_deferred deferred, std::unique_ptr<NapiAsyncTask::ExecuteCallback> &&execute,
131     std::unique_ptr<NapiAsyncTask::CompleteCallback> &&complete)
132     : deferred_(deferred), execute_(std::move(execute)), complete_(std::move(complete))
133 {}
134 
NapiAsyncTask(napi_ref callbackRef,std::unique_ptr<NapiAsyncTask::ExecuteCallback> && execute,std::unique_ptr<NapiAsyncTask::CompleteCallback> && complete)135 NapiAsyncTask::NapiAsyncTask(napi_ref callbackRef, std::unique_ptr<NapiAsyncTask::ExecuteCallback> &&execute,
136     std::unique_ptr<NapiAsyncTask::CompleteCallback> &&complete)
137     : callbackRef_(callbackRef), execute_(std::move(execute)), complete_(std::move(complete))
138 {}
139 
140 NapiAsyncTask::~NapiAsyncTask() = default;
141 
Schedule(const std::string & name,napi_env env,std::unique_ptr<NapiAsyncTask> && task)142 void NapiAsyncTask::Schedule(const std::string &name, napi_env env, std::unique_ptr<NapiAsyncTask> &&task)
143 {
144     if (task && task->Start(name, env)) {
145         task.release();
146     }
147 }
148 
Resolve(napi_env env,napi_value value)149 void NapiAsyncTask::Resolve(napi_env env, napi_value value)
150 {
151     TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
152     if (deferred_) {
153         napi_resolve_deferred(env, deferred_, value);
154         deferred_ = nullptr;
155     }
156     if (callbackRef_) {
157         napi_value argv[] = {
158             CreateJsError(env, 0),
159             value,
160         };
161         napi_value func = nullptr;
162         napi_get_reference_value(env, callbackRef_, &func);
163         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
164         napi_delete_reference(env, callbackRef_);
165         callbackRef_ = nullptr;
166     }
167 }
168 
ResolveWithNoError(napi_env env,napi_value value)169 void NapiAsyncTask::ResolveWithNoError(napi_env env, napi_value value)
170 {
171     TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
172     if (deferred_) {
173         napi_resolve_deferred(env, deferred_, value);
174         deferred_ = nullptr;
175     }
176     if (callbackRef_) {
177         napi_value argv[] = {
178             CreateJsNull(env),
179             value,
180         };
181         napi_value func = nullptr;
182         napi_get_reference_value(env, callbackRef_, &func);
183         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
184         napi_delete_reference(env, callbackRef_);
185         callbackRef_ = nullptr;
186     }
187 }
188 
Reject(napi_env env,napi_value error)189 void NapiAsyncTask::Reject(napi_env env, napi_value error)
190 {
191     if (deferred_) {
192         napi_reject_deferred(env, deferred_, error);
193         deferred_ = nullptr;
194     }
195     if (callbackRef_) {
196         napi_value argv[] = {
197             error,
198             CreateJsUndefined(env),
199         };
200         napi_value func = nullptr;
201         napi_get_reference_value(env, callbackRef_, &func);
202         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
203         napi_delete_reference(env, callbackRef_);
204         callbackRef_ = nullptr;
205     }
206 }
207 
ResolveWithCustomize(napi_env env,napi_value error,napi_value value)208 void NapiAsyncTask::ResolveWithCustomize(napi_env env, napi_value error, napi_value value)
209 {
210     TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
211     if (deferred_) {
212         napi_resolve_deferred(env, deferred_, value);
213         deferred_ = nullptr;
214     }
215     if (callbackRef_) {
216         napi_value argv[] = {
217             error,
218             value,
219         };
220         napi_value func = nullptr;
221         napi_get_reference_value(env, callbackRef_, &func);
222         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
223         napi_delete_reference(env, callbackRef_);
224         callbackRef_ = nullptr;
225     }
226 }
227 
RejectWithCustomize(napi_env env,napi_value error,napi_value value)228 void NapiAsyncTask::RejectWithCustomize(napi_env env, napi_value error, napi_value value)
229 {
230     TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
231     if (deferred_) {
232         napi_reject_deferred(env, deferred_, error);
233         deferred_ = nullptr;
234     }
235     if (callbackRef_) {
236         napi_value argv[] = {
237             error,
238             value,
239         };
240         napi_value func = nullptr;
241         napi_get_reference_value(env, callbackRef_, &func);
242         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
243         napi_delete_reference(env, callbackRef_);
244         callbackRef_ = nullptr;
245     }
246 }
247 
Execute(napi_env env,void * data)248 void NapiAsyncTask::Execute(napi_env env, void *data)
249 {
250     if (env == nullptr || data == nullptr) {
251         return;
252     }
253     auto me = static_cast<NapiAsyncTask*>(data);
254     if (me->execute_ && *(me->execute_)) {
255         (*me->execute_)();
256     }
257 }
258 
Complete(napi_env env,napi_status status,void * data)259 void NapiAsyncTask::Complete(napi_env env, napi_status status, void *data)
260 {
261     if (data == nullptr) {
262         return;
263     }
264     std::unique_ptr<NapiAsyncTask> me(static_cast<NapiAsyncTask*>(data));
265     if (me->complete_ && *(me->complete_)) {
266         (*me->complete_)(env, *me, static_cast<int32_t>(status));
267     }
268 }
269 
Start(const std::string & name,napi_env env)270 bool NapiAsyncTask::Start(const std::string &name, napi_env env)
271 {
272     if (work_) {
273         napi_delete_async_work(env, work_);
274         work_ = nullptr;
275     }
276     if (env == nullptr) {
277         return false;
278     }
279     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
280     work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
281         reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
282         reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
283     napi_queue_async_work(env, work_);
284     return true;
285 }
286 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,NapiAsyncTask::ExecuteCallback && execute,NapiAsyncTask::CompleteCallback && complete,napi_value * result)287 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
288     NapiAsyncTask::ExecuteCallback &&execute, NapiAsyncTask::CompleteCallback &&complete, napi_value *result)
289 {
290     return CreateAsyncTaskWithLastParam(env, lastParam,
291         std::make_unique<NapiAsyncTask::ExecuteCallback>(std::move(execute)),
292         std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)), result);
293 }
294 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,NapiAsyncTask::ExecuteCallback && execute,std::nullptr_t,napi_value * result)295 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
296     NapiAsyncTask::ExecuteCallback &&execute, std::nullptr_t, napi_value *result)
297 {
298     return CreateAsyncTaskWithLastParam(
299         env, lastParam, std::make_unique<NapiAsyncTask::ExecuteCallback>(std::move(execute)), nullptr, result);
300 }
301 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,std::nullptr_t,NapiAsyncTask::CompleteCallback && complete,napi_value * result)302 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
303     std::nullptr_t, NapiAsyncTask::CompleteCallback &&complete, napi_value *result)
304 {
305     return CreateAsyncTaskWithLastParam(
306         env, lastParam, nullptr, std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)), result);
307 }
308 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,std::nullptr_t,std::nullptr_t,napi_value * result)309 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
310     std::nullptr_t, std::nullptr_t, napi_value *result)
311 {
312     return CreateAsyncTaskWithLastParam(env, lastParam, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
313         std::unique_ptr<NapiAsyncTask::CompleteCallback>(), result);
314 }
315 
SendNapiEvent(napi_env env,napi_event_priority eventPriority)316 bool NapiAsyncTask::SendNapiEvent(napi_env env, napi_event_priority eventPriority)
317 {
318     if (napi_send_event(
319         env,
320         [env, this]() {
321             napi_status status = napi_ok;
322             Complete(env, status, this);
323         },
324         eventPriority) != napi_ok) {
325         TAG_LOGE(AAFwkTag::ABILITY_SIM, "SendNapiEvent failed");
326         return false;
327     }
328     return true;
329 }
330 
ScheduleHighQos(const std::string & name,napi_env env,std::unique_ptr<NapiAsyncTask> && task)331 void NapiAsyncTask::ScheduleHighQos(const std::string &name, napi_env env, std::unique_ptr<NapiAsyncTask> &&task)
332 {
333     if (task && task->StartHighQos(name, env)) {
334         task.release();
335     }
336 }
337 
StartHighQos(const std::string & name,napi_env env)338 bool NapiAsyncTask::StartHighQos(const std::string &name, napi_env env)
339 {
340     if (work_) {
341         napi_delete_async_work(env, work_);
342         work_ = nullptr;
343     }
344     if (env == nullptr) {
345         return false;
346     }
347     if (execute_ == nullptr) {
348         return SendNapiEvent(env, napi_eprio_immediate);
349     }
350     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
351     work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
352         reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
353         reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
354     napi_queue_async_work_with_qos(env, work_, napi_qos_user_initiated);
355     return true;
356 }
357 } // namespace AbilityRuntime
358 } // namespace OHOS