• 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 #include "js_runtime.h"
20 #include "napi/native_api.h"
21 
22 namespace OHOS {
23 namespace AbilityRuntime {
24 namespace {
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,std::unique_ptr<NapiAsyncTask::ExecuteCallback> && execute,std::unique_ptr<NapiAsyncTask::CompleteCallback> && complete,napi_value * result)25 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
26     std::unique_ptr<NapiAsyncTask::ExecuteCallback>&& execute,
27     std::unique_ptr<NapiAsyncTask::CompleteCallback>&& complete,
28     napi_value* result)
29 {
30     napi_valuetype type = napi_undefined;
31     napi_typeof(env, lastParam, &type);
32     if (lastParam == nullptr || type != napi_function) {
33         napi_deferred nativeDeferred = nullptr;
34         napi_create_promise(env, &nativeDeferred, result);
35         return std::make_unique<NapiAsyncTask>(nativeDeferred, std::move(execute), std::move(complete));
36     } else {
37         napi_get_undefined(env, result);
38         napi_ref callbackRef = nullptr;
39         napi_create_reference(env, lastParam, 1, &callbackRef);
40         return std::make_unique<NapiAsyncTask>(callbackRef, std::move(execute), std::move(complete));
41     }
42 }
43 } // namespace
44 
45 // Help Functions
CreateJsError(napi_env env,int32_t errCode,const std::string & message)46 napi_value CreateJsError(napi_env env, int32_t errCode, const std::string& message)
47 {
48     napi_value result = nullptr;
49     napi_create_error(env, CreateJsValue(env, errCode), CreateJsValue(env, message), &result);
50     return result;
51 }
52 
BindNativeFunction(napi_env env,napi_value object,const char * name,const char * moduleName,napi_callback func)53 void BindNativeFunction(napi_env env, napi_value object, const char* name,
54     const char* moduleName, napi_callback func)
55 {
56     std::string fullName(moduleName);
57     fullName += ".";
58     fullName += name;
59     napi_value result = nullptr;
60     napi_create_function(env, fullName.c_str(), fullName.length(), func, nullptr, &result);
61     napi_set_named_property(env, object, name, result);
62 }
63 
BindNativeProperty(napi_env env,napi_value object,const char * name,napi_callback getter)64 void BindNativeProperty(napi_env env, napi_value object, const char* name, napi_callback getter)
65 {
66     napi_property_descriptor properties[1];
67     properties[0].utf8name = name;
68     properties[0].name = nullptr;
69     properties[0].method = nullptr;
70     properties[0].getter = getter;
71     properties[0].setter = nullptr;
72     properties[0].value = nullptr;
73     properties[0].attributes = napi_default;
74     properties[0].data = nullptr;
75     napi_define_properties(env, object, 1, properties);
76 }
77 
GetNativePointerFromCallbackInfo(napi_env env,napi_callback_info info,const char * name)78 void* GetNativePointerFromCallbackInfo(napi_env env, napi_callback_info info, const char* name)
79 {
80     size_t argcAsync = ARGC_MAX_COUNT;
81     napi_value args[ARGC_MAX_COUNT] = {nullptr};
82     napi_value thisVar = nullptr;
83     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argcAsync, args, &thisVar, nullptr), nullptr);
84     if (name != nullptr) {
85         napi_get_named_property(env, thisVar, name, &thisVar);
86     }
87     void* result = nullptr;
88     NAPI_CALL_NO_THROW(napi_unwrap(env, thisVar, &result), nullptr);
89     return result;
90 }
91 
GetCbInfoFromCallbackInfo(napi_env env,napi_callback_info info,size_t * argc,napi_value * argv)92 void* GetCbInfoFromCallbackInfo(napi_env env, napi_callback_info info, size_t* argc, napi_value* argv)
93 {
94     napi_value thisVar = nullptr;
95     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, argc, argv, &thisVar, nullptr), nullptr);
96     void* result = nullptr;
97     NAPI_CALL_NO_THROW(napi_unwrap(env, thisVar, &result), nullptr);
98     return result;
99 }
100 
GetNapiCallbackInfoAndThis(napi_env env,napi_callback_info info,NapiCallbackInfo & napiInfo,const char * name)101 void* GetNapiCallbackInfoAndThis(napi_env env, napi_callback_info info, NapiCallbackInfo& napiInfo, const char* name)
102 {
103     NAPI_CALL_NO_THROW(napi_get_cb_info(
104         env, info, &napiInfo.argc, napiInfo.argv, &napiInfo.thisVar, nullptr), nullptr);
105     napi_value value = napiInfo.thisVar;
106     if (name != nullptr) {
107         napi_get_named_property(env, value, name, &value);
108     }
109     void* result = nullptr;
110     NAPI_CALL_NO_THROW(napi_unwrap(env, value, &result), nullptr);
111     return result;
112 }
113 
SetNamedNativePointer(napi_env env,napi_value object,const char * name,void * ptr,napi_finalize func)114 void SetNamedNativePointer(napi_env env, napi_value object, const char* name, void* ptr, napi_finalize func)
115 {
116     napi_value objValue = nullptr;
117     napi_create_object(env, &objValue);
118     napi_wrap(env, objValue, ptr, func, nullptr, nullptr);
119     napi_set_named_property(env, object, name, objValue);
120 }
121 
GetNamedNativePointer(napi_env env,napi_value object,const char * name)122 void* GetNamedNativePointer(napi_env env, napi_value object, const char* name)
123 {
124     napi_value proValue = nullptr;
125     napi_get_named_property(env, object, name, &proValue);
126     void* result = nullptr;
127     napi_unwrap(env, proValue, &result);
128     return result;
129 }
130 
CheckTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)131 bool CheckTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
132 {
133     napi_valuetype valueType = napi_undefined;
134     if (napi_typeof(env, param, &valueType) != napi_ok) {
135         return false;
136     }
137     return valueType == expectType;
138 }
139 
140 // Handle Scope
HandleScope(JsRuntime & jsRuntime)141 HandleScope::HandleScope(JsRuntime& jsRuntime)
142 {
143     env_ = (napi_env)jsRuntime.GetNativeEnginePointer();
144     napi_open_handle_scope(env_, &scope_);
145 }
146 
HandleScope(napi_env env)147 HandleScope::HandleScope(napi_env env)
148 {
149     env_ = env;
150     napi_open_handle_scope(env_, &scope_);
151 }
152 
~HandleScope()153 HandleScope::~HandleScope()
154 {
155     napi_close_handle_scope(env_, scope_);
156 }
157 
158 // Handle Escape
HandleEscape(JsRuntime & jsRuntime)159 HandleEscape::HandleEscape(JsRuntime& jsRuntime)
160 {
161     env_ = (napi_env)jsRuntime.GetNativeEnginePointer();
162     napi_open_escapable_handle_scope(env_, &scope_);
163 }
164 
HandleEscape(napi_env env)165 HandleEscape::HandleEscape(napi_env env)
166 {
167     env_ = env;
168     napi_open_escapable_handle_scope(env_, &scope_);
169 }
170 
~HandleEscape()171 HandleEscape::~HandleEscape()
172 {
173     napi_close_escapable_handle_scope(env_, scope_);
174 }
175 
Escape(napi_value value)176 napi_value HandleEscape::Escape(napi_value value)
177 {
178     napi_value result = nullptr;
179     napi_escape_handle(env_, scope_, value, &result);
180     return result;
181 }
182 
183 // Async Task
NapiAsyncTask(napi_deferred deferred,std::unique_ptr<NapiAsyncTask::ExecuteCallback> && execute,std::unique_ptr<NapiAsyncTask::CompleteCallback> && complete)184 NapiAsyncTask::NapiAsyncTask(napi_deferred deferred, std::unique_ptr<NapiAsyncTask::ExecuteCallback>&& execute,
185     std::unique_ptr<NapiAsyncTask::CompleteCallback>&& complete)
186     : deferred_(deferred), execute_(std::move(execute)), complete_(std::move(complete))
187 {}
188 
NapiAsyncTask(napi_ref callbackRef,std::unique_ptr<NapiAsyncTask::ExecuteCallback> && execute,std::unique_ptr<NapiAsyncTask::CompleteCallback> && complete)189 NapiAsyncTask::NapiAsyncTask(napi_ref callbackRef, std::unique_ptr<NapiAsyncTask::ExecuteCallback>&& execute,
190     std::unique_ptr<NapiAsyncTask::CompleteCallback>&& complete)
191     : callbackRef_(callbackRef), execute_(std::move(execute)), complete_(std::move(complete))
192 {}
193 
~NapiAsyncTask()194 NapiAsyncTask::~NapiAsyncTask()
195 {
196     if (work_ && env_) {
197         napi_delete_async_work(env_, work_);
198         work_ = nullptr;
199     }
200 }
201 
Schedule(const std::string & name,napi_env env,std::unique_ptr<NapiAsyncTask> && task)202 void NapiAsyncTask::Schedule(const std::string &name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task)
203 {
204     if (task && task->Start(name, env)) {
205         task.release();
206     }
207 }
208 
ScheduleHighQos(const std::string & name,napi_env env,std::unique_ptr<NapiAsyncTask> && task)209 void NapiAsyncTask::ScheduleHighQos(const std::string &name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task)
210 {
211     if (task && task->StartHighQos(name, env)) {
212         task.release();
213     }
214 }
215 
ScheduleLowQos(const std::string & name,napi_env env,std::unique_ptr<NapiAsyncTask> && task)216 void NapiAsyncTask::ScheduleLowQos(const std::string &name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task)
217 {
218     if (task && task->StartLowQos(name, env)) {
219         task.release();
220     }
221 }
222 
ScheduleWithDefaultQos(const std::string & name,napi_env env,std::unique_ptr<NapiAsyncTask> && task)223 void NapiAsyncTask::ScheduleWithDefaultQos(const std::string &name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task)
224 {
225     if (task && task->StartWithDefaultQos(name, env)) {
226         task.release();
227     }
228 }
229 
StartWithDefaultQos(const std::string & name,napi_env env)230 bool NapiAsyncTask::StartWithDefaultQos(const std::string &name, napi_env env)
231 {
232     if (work_) {
233         napi_delete_async_work(env, work_);
234         work_ = nullptr;
235     }
236     if (env == nullptr) {
237         return false;
238     }
239     if (execute_ == nullptr) {
240         return SendNapiEvent(env, napi_eprio_high);
241     }
242     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
243     work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
244         reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
245         reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
246     napi_queue_async_work_with_qos(env, work_, napi_qos_default);
247     return true;
248 }
249 
Resolve(napi_env env,napi_value value)250 void NapiAsyncTask::Resolve(napi_env env, napi_value value)
251 {
252     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
253     if (deferred_) {
254         napi_resolve_deferred(env, deferred_, value);
255         deferred_ = nullptr;
256     }
257     if (callbackRef_) {
258         napi_value argv[] = {
259             CreateJsError(env, 0),
260             value,
261         };
262         napi_value func = nullptr;
263         napi_get_reference_value(env, callbackRef_, &func);
264         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
265         napi_delete_reference(env, callbackRef_);
266         callbackRef_ = nullptr;
267     }
268 }
269 
ResolveWithNoError(napi_env env,napi_value value)270 void NapiAsyncTask::ResolveWithNoError(napi_env env, napi_value value)
271 {
272     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
273     if (deferred_) {
274         napi_resolve_deferred(env, deferred_, value);
275         deferred_ = nullptr;
276     }
277     if (callbackRef_) {
278         napi_value argv[] = {
279             CreateJsNull(env),
280             value,
281         };
282         napi_value func = nullptr;
283         napi_get_reference_value(env, callbackRef_, &func);
284         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
285         napi_delete_reference(env, callbackRef_);
286         callbackRef_ = nullptr;
287     }
288 }
289 
Reject(napi_env env,napi_value error)290 void NapiAsyncTask::Reject(napi_env env, napi_value error)
291 {
292     if (deferred_) {
293         napi_reject_deferred(env, deferred_, error);
294         deferred_ = nullptr;
295     }
296     if (callbackRef_) {
297         napi_value argv[] = {
298             error,
299             CreateJsUndefined(env),
300         };
301         napi_value func = nullptr;
302         napi_get_reference_value(env, callbackRef_, &func);
303         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
304         napi_delete_reference(env, callbackRef_);
305         callbackRef_ = nullptr;
306     }
307 }
308 
ResolveWithCustomize(napi_env env,napi_value error,napi_value value)309 void NapiAsyncTask::ResolveWithCustomize(napi_env env, napi_value error, napi_value value)
310 {
311     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
312     if (deferred_) {
313         napi_resolve_deferred(env, deferred_, value);
314         deferred_ = nullptr;
315     }
316     if (callbackRef_) {
317         napi_value argv[] = {
318             error,
319             value,
320         };
321         napi_value func = nullptr;
322         napi_get_reference_value(env, callbackRef_, &func);
323         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
324         napi_delete_reference(env, callbackRef_);
325         callbackRef_ = nullptr;
326     }
327 }
328 
RejectWithCustomize(napi_env env,napi_value error,napi_value value)329 void NapiAsyncTask::RejectWithCustomize(napi_env env, napi_value error, napi_value value)
330 {
331     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
332     if (deferred_) {
333         napi_reject_deferred(env, deferred_, error);
334         deferred_ = nullptr;
335     }
336     if (callbackRef_) {
337         napi_value argv[] = {
338             error,
339             value,
340         };
341         napi_value func = nullptr;
342         napi_get_reference_value(env, callbackRef_, &func);
343         napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
344         napi_delete_reference(env, callbackRef_);
345         callbackRef_ = nullptr;
346     }
347 }
348 
Execute(napi_env env,void * data)349 void NapiAsyncTask::Execute(napi_env env, void* data)
350 {
351     if (data == nullptr) {
352         return;
353     }
354     auto me = static_cast<NapiAsyncTask*>(data);
355     if (me->execute_ && *(me->execute_)) {
356         (*me->execute_)();
357     }
358 }
359 
Complete(napi_env env,napi_status status,void * data)360 void NapiAsyncTask::Complete(napi_env env, napi_status status, void* data)
361 {
362     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
363     if (data == nullptr) {
364         return;
365     }
366     std::unique_ptr<NapiAsyncTask> me(static_cast<NapiAsyncTask*>(data));
367     if (me->complete_ && *(me->complete_)) {
368         HandleScope handleScope(env);
369         (*me->complete_)(env, *me, static_cast<int32_t>(status));
370     }
371 }
372 
Start(const std::string & name,napi_env env)373 bool NapiAsyncTask::Start(const std::string &name, napi_env env)
374 {
375     if (work_) {
376         napi_delete_async_work(env, work_);
377         work_ = nullptr;
378     }
379     if (env == nullptr) {
380         return false;
381     }
382     if (execute_ == nullptr) {
383         return SendNapiEvent(env, napi_eprio_high);
384     }
385     env_ = env;
386     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
387     work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
388         reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
389         reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
390     napi_queue_async_work(env, work_);
391     return true;
392 }
393 
StartHighQos(const std::string & name,napi_env env)394 bool NapiAsyncTask::StartHighQos(const std::string &name, napi_env env)
395 {
396     if (work_) {
397         napi_delete_async_work(env, work_);
398         work_ = nullptr;
399     }
400     if (env == nullptr) {
401         return false;
402     }
403     if (execute_ == nullptr) {
404         return SendNapiEvent(env, napi_eprio_immediate);
405     }
406     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
407     work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
408         reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
409         reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
410     napi_queue_async_work_with_qos(env, work_, napi_qos_user_initiated);
411     return true;
412 }
413 
StartLowQos(const std::string & name,napi_env env)414 bool NapiAsyncTask::StartLowQos(const std::string &name, napi_env env)
415 {
416     if (work_) {
417         napi_delete_async_work(env, work_);
418         work_ = nullptr;
419     }
420     if (env == nullptr) {
421         return false;
422     }
423     if (execute_ == nullptr) {
424         return SendNapiEvent(env, napi_eprio_low);
425     }
426     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
427     work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
428         reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
429         reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
430     napi_queue_async_work_with_qos(env, work_, napi_qos_utility);
431     return true;
432 }
433 
SendNapiEvent(napi_env env,napi_event_priority eventPriority)434 bool NapiAsyncTask::SendNapiEvent(napi_env env, napi_event_priority eventPriority)
435 {
436     if (napi_send_event(
437         env,
438         [env, this]() {
439             napi_status status = napi_ok;
440             Complete(env, status, this);
441         },
442         eventPriority) != napi_ok) {
443         TAG_LOGE(AAFwkTag::JSRUNTIME, "SendNapiEvent failed");
444         return false;
445     }
446     return true;
447 }
448 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,NapiAsyncTask::ExecuteCallback && execute,NapiAsyncTask::CompleteCallback && complete,napi_value * result)449 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
450     NapiAsyncTask::ExecuteCallback&& execute, NapiAsyncTask::CompleteCallback&& complete, napi_value* result)
451 {
452     return CreateAsyncTaskWithLastParam(env, lastParam,
453         std::make_unique<NapiAsyncTask::ExecuteCallback>(std::move(execute)),
454         std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)), result);
455 }
456 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,NapiAsyncTask::ExecuteCallback && execute,nullptr_t,napi_value * result)457 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
458     NapiAsyncTask::ExecuteCallback&& execute, nullptr_t, napi_value* result)
459 {
460     return CreateAsyncTaskWithLastParam(
461         env, lastParam, std::make_unique<NapiAsyncTask::ExecuteCallback>(std::move(execute)), nullptr, result);
462 }
463 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,nullptr_t,NapiAsyncTask::CompleteCallback && complete,napi_value * result)464 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
465     nullptr_t, NapiAsyncTask::CompleteCallback&& complete, napi_value* result)
466 {
467     return CreateAsyncTaskWithLastParam(
468         env, lastParam, nullptr, std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)), result);
469 }
470 
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,nullptr_t,nullptr_t,napi_value * result)471 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
472     nullptr_t, nullptr_t, napi_value* result)
473 {
474     return CreateAsyncTaskWithLastParam(env, lastParam, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
475         std::unique_ptr<NapiAsyncTask::CompleteCallback>(), result);
476 }
477 
CreateEmptyAsyncTask(napi_env env,napi_value lastParam,napi_value * result)478 std::unique_ptr<NapiAsyncTask> CreateEmptyAsyncTask(napi_env env, napi_value lastParam, napi_value* result)
479 {
480     napi_valuetype type = napi_undefined;
481     napi_typeof(env, lastParam, &type);
482     if (lastParam == nullptr || type != napi_function) {
483         napi_deferred nativeDeferred = nullptr;
484         napi_create_promise(env, &nativeDeferred, result);
485         return std::make_unique<NapiAsyncTask>(nativeDeferred, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
486             std::unique_ptr<NapiAsyncTask::CompleteCallback>());
487     } else {
488         napi_get_undefined(env, result);
489         napi_ref callbackRef = nullptr;
490         napi_create_reference(env, lastParam, 1, &callbackRef);
491         return std::make_unique<NapiAsyncTask>(callbackRef, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
492             std::unique_ptr<NapiAsyncTask::CompleteCallback>());
493     }
494 }
495 }  // namespace AbilityRuntime
496 }  // namespace OHOS
497