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