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 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
240 work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
241 reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
242 reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
243 napi_queue_async_work_with_qos(env, work_, napi_qos_default);
244 return true;
245 }
246
Resolve(napi_env env,napi_value value)247 void NapiAsyncTask::Resolve(napi_env env, napi_value value)
248 {
249 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
250 if (deferred_) {
251 napi_resolve_deferred(env, deferred_, value);
252 deferred_ = nullptr;
253 }
254 if (callbackRef_) {
255 napi_value argv[] = {
256 CreateJsError(env, 0),
257 value,
258 };
259 napi_value func = nullptr;
260 napi_get_reference_value(env, callbackRef_, &func);
261 napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
262 napi_delete_reference(env, callbackRef_);
263 callbackRef_ = nullptr;
264 }
265 }
266
ResolveWithNoError(napi_env env,napi_value value)267 void NapiAsyncTask::ResolveWithNoError(napi_env env, napi_value value)
268 {
269 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
270 if (deferred_) {
271 napi_resolve_deferred(env, deferred_, value);
272 deferred_ = nullptr;
273 }
274 if (callbackRef_) {
275 napi_value argv[] = {
276 CreateJsNull(env),
277 value,
278 };
279 napi_value func = nullptr;
280 napi_get_reference_value(env, callbackRef_, &func);
281 napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
282 napi_delete_reference(env, callbackRef_);
283 callbackRef_ = nullptr;
284 }
285 }
286
Reject(napi_env env,napi_value error)287 void NapiAsyncTask::Reject(napi_env env, napi_value error)
288 {
289 if (deferred_) {
290 napi_reject_deferred(env, deferred_, error);
291 deferred_ = nullptr;
292 }
293 if (callbackRef_) {
294 napi_value argv[] = {
295 error,
296 CreateJsUndefined(env),
297 };
298 napi_value func = nullptr;
299 napi_get_reference_value(env, callbackRef_, &func);
300 napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
301 napi_delete_reference(env, callbackRef_);
302 callbackRef_ = nullptr;
303 }
304 }
305
ResolveWithCustomize(napi_env env,napi_value error,napi_value value)306 void NapiAsyncTask::ResolveWithCustomize(napi_env env, napi_value error, napi_value value)
307 {
308 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
309 if (deferred_) {
310 napi_resolve_deferred(env, deferred_, value);
311 deferred_ = nullptr;
312 }
313 if (callbackRef_) {
314 napi_value argv[] = {
315 error,
316 value,
317 };
318 napi_value func = nullptr;
319 napi_get_reference_value(env, callbackRef_, &func);
320 napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
321 napi_delete_reference(env, callbackRef_);
322 callbackRef_ = nullptr;
323 }
324 }
325
RejectWithCustomize(napi_env env,napi_value error,napi_value value)326 void NapiAsyncTask::RejectWithCustomize(napi_env env, napi_value error, napi_value value)
327 {
328 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
329 if (deferred_) {
330 napi_reject_deferred(env, deferred_, error);
331 deferred_ = nullptr;
332 }
333 if (callbackRef_) {
334 napi_value argv[] = {
335 error,
336 value,
337 };
338 napi_value func = nullptr;
339 napi_get_reference_value(env, callbackRef_, &func);
340 napi_call_function(env, CreateJsUndefined(env), func, ArraySize(argv), argv, nullptr);
341 napi_delete_reference(env, callbackRef_);
342 callbackRef_ = nullptr;
343 }
344 }
345
Execute(napi_env env,void * data)346 void NapiAsyncTask::Execute(napi_env env, void* data)
347 {
348 if (data == nullptr) {
349 return;
350 }
351 auto me = static_cast<NapiAsyncTask*>(data);
352 if (me->execute_ && *(me->execute_)) {
353 (*me->execute_)();
354 }
355 }
356
Complete(napi_env env,napi_status status,void * data)357 void NapiAsyncTask::Complete(napi_env env, napi_status status, void* data)
358 {
359 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
360 if (data == nullptr) {
361 return;
362 }
363 std::unique_ptr<NapiAsyncTask> me(static_cast<NapiAsyncTask*>(data));
364 if (me->complete_ && *(me->complete_)) {
365 HandleScope handleScope(env);
366 (*me->complete_)(env, *me, static_cast<int32_t>(status));
367 }
368 }
369
Start(const std::string & name,napi_env env)370 bool NapiAsyncTask::Start(const std::string &name, napi_env env)
371 {
372 if (work_) {
373 napi_delete_async_work(env, work_);
374 work_ = nullptr;
375 }
376 if (env == nullptr) {
377 return false;
378 }
379 env_ = env;
380 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
381 work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
382 reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
383 reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
384 napi_queue_async_work(env, work_);
385 return true;
386 }
387
StartHighQos(const std::string & name,napi_env env)388 bool NapiAsyncTask::StartHighQos(const std::string &name, napi_env env)
389 {
390 if (work_) {
391 napi_delete_async_work(env, work_);
392 work_ = nullptr;
393 }
394 if (env == nullptr) {
395 return false;
396 }
397 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
398 work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
399 reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
400 reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
401 napi_queue_async_work_with_qos(env, work_, napi_qos_user_initiated);
402 return true;
403 }
404
StartLowQos(const std::string & name,napi_env env)405 bool NapiAsyncTask::StartLowQos(const std::string &name, napi_env env)
406 {
407 if (work_) {
408 napi_delete_async_work(env, work_);
409 work_ = nullptr;
410 }
411 if (env == nullptr) {
412 return false;
413 }
414 NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
415 work_ = reinterpret_cast<napi_async_work>(engine->CreateAsyncWork(name,
416 reinterpret_cast<NativeAsyncExecuteCallback>(Execute),
417 reinterpret_cast<NativeAsyncCompleteCallback>(Complete), this));
418 napi_queue_async_work_with_qos(env, work_, napi_qos_utility);
419 return true;
420 }
421
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,NapiAsyncTask::ExecuteCallback && execute,NapiAsyncTask::CompleteCallback && complete,napi_value * result)422 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
423 NapiAsyncTask::ExecuteCallback&& execute, NapiAsyncTask::CompleteCallback&& complete, napi_value* result)
424 {
425 return CreateAsyncTaskWithLastParam(env, lastParam,
426 std::make_unique<NapiAsyncTask::ExecuteCallback>(std::move(execute)),
427 std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)), result);
428 }
429
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,NapiAsyncTask::ExecuteCallback && execute,nullptr_t,napi_value * result)430 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
431 NapiAsyncTask::ExecuteCallback&& execute, nullptr_t, napi_value* result)
432 {
433 return CreateAsyncTaskWithLastParam(
434 env, lastParam, std::make_unique<NapiAsyncTask::ExecuteCallback>(std::move(execute)), nullptr, result);
435 }
436
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,nullptr_t,NapiAsyncTask::CompleteCallback && complete,napi_value * result)437 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
438 nullptr_t, NapiAsyncTask::CompleteCallback&& complete, napi_value* result)
439 {
440 return CreateAsyncTaskWithLastParam(
441 env, lastParam, nullptr, std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)), result);
442 }
443
CreateAsyncTaskWithLastParam(napi_env env,napi_value lastParam,nullptr_t,nullptr_t,napi_value * result)444 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
445 nullptr_t, nullptr_t, napi_value* result)
446 {
447 return CreateAsyncTaskWithLastParam(env, lastParam, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
448 std::unique_ptr<NapiAsyncTask::CompleteCallback>(), result);
449 }
450
CreateEmptyAsyncTask(napi_env env,napi_value lastParam,napi_value * result)451 std::unique_ptr<NapiAsyncTask> CreateEmptyAsyncTask(napi_env env, napi_value lastParam, napi_value* result)
452 {
453 napi_valuetype type = napi_undefined;
454 napi_typeof(env, lastParam, &type);
455 if (lastParam == nullptr || type != napi_function) {
456 napi_deferred nativeDeferred = nullptr;
457 napi_create_promise(env, &nativeDeferred, result);
458 return std::make_unique<NapiAsyncTask>(nativeDeferred, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
459 std::unique_ptr<NapiAsyncTask::CompleteCallback>());
460 } else {
461 napi_get_undefined(env, result);
462 napi_ref callbackRef = nullptr;
463 napi_create_reference(env, lastParam, 1, &callbackRef);
464 return std::make_unique<NapiAsyncTask>(callbackRef, std::unique_ptr<NapiAsyncTask::ExecuteCallback>(),
465 std::unique_ptr<NapiAsyncTask::CompleteCallback>());
466 }
467 }
468 } // namespace AbilityRuntime
469 } // namespace OHOS
470