1 /*
2 * Copyright (c) 2021-2023 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_wrapper.h"
19 #include "js_runtime.h"
20 namespace OHOS {
21 namespace AbilityRuntime {
22 namespace {
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,std::unique_ptr<AsyncTask::ExecuteCallback> && execute,std::unique_ptr<AsyncTask::CompleteCallback> && complete,NativeValue ** result)23 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine &engine, NativeValue *lastParam,
24 std::unique_ptr<AsyncTask::ExecuteCallback> &&execute, std::unique_ptr<AsyncTask::CompleteCallback> &&complete,
25 NativeValue **result)
26 {
27 if (lastParam == nullptr || lastParam->TypeOf() != NATIVE_FUNCTION) {
28 NativeDeferred *nativeDeferred = nullptr;
29 *result = engine.CreatePromise(&nativeDeferred);
30 return std::make_unique<AsyncTask>(nativeDeferred, std::move(execute), std::move(complete));
31 } else {
32 *result = engine.CreateUndefined();
33 NativeReference *callbackRef = engine.CreateReference(lastParam, 1);
34 return std::make_unique<AsyncTask>(callbackRef, std::move(execute), std::move(complete));
35 }
36 }
37 } // namespace
38
39 // Help Functions
CreateJsError(NativeEngine & engine,int32_t errCode,const std::string & message)40 NativeValue *CreateJsError(NativeEngine &engine, int32_t errCode, const std::string &message)
41 {
42 return engine.CreateError(CreateJsValue(engine, errCode), CreateJsValue(engine, message));
43 }
44
BindNativeFunction(NativeEngine & engine,NativeObject & object,const char * name,const char * moduleName,NativeCallback func)45 void BindNativeFunction(NativeEngine &engine, NativeObject &object, const char *name,
46 const char *moduleName, NativeCallback func)
47 {
48 std::string fullName(moduleName);
49 fullName += ".";
50 fullName += name;
51 object.SetProperty(name, engine.CreateFunction(fullName.c_str(), fullName.length(), func, nullptr));
52 }
53
BindNativeProperty(NativeObject & object,const char * name,NativeCallback getter)54 void BindNativeProperty(NativeObject &object, const char *name, NativeCallback getter)
55 {
56 NativePropertyDescriptor property;
57 property.utf8name = name;
58 property.name = nullptr;
59 property.method = nullptr;
60 property.getter = getter;
61 property.setter = nullptr;
62 property.value = nullptr;
63 property.attributes = napi_default;
64 property.data = nullptr;
65 object.DefineProperty(property);
66 }
67
GetNativePointerFromCallbackInfo(const NativeEngine * engine,NativeCallbackInfo * info,const char * name)68 void *GetNativePointerFromCallbackInfo(const NativeEngine *engine, NativeCallbackInfo *info, const char *name)
69 {
70 if (engine == nullptr || info == nullptr) {
71 return nullptr;
72 }
73
74 NativeObject *object = ConvertNativeValueTo<NativeObject>(info->thisVar);
75 if (object != nullptr && name != nullptr) {
76 object = ConvertNativeValueTo<NativeObject>(object->GetProperty(name));
77 }
78 return (object != nullptr) ? object->GetNativePointer() : nullptr;
79 }
80
SetNamedNativePointer(NativeEngine & engine,NativeObject & object,const char * name,void * ptr,NativeFinalize func)81 void SetNamedNativePointer(NativeEngine &engine, NativeObject &object, const char *name, void *ptr, NativeFinalize func)
82 {
83 NativeValue *value = engine.CreateObject();
84 NativeObject *newObject = ConvertNativeValueTo<NativeObject>(value);
85 if (newObject == nullptr) {
86 return;
87 }
88 newObject->SetNativePointer(ptr, func, nullptr);
89 object.SetProperty(name, value);
90 }
91
GetNamedNativePointer(NativeEngine & engine,NativeObject & object,const char * name)92 void *GetNamedNativePointer(NativeEngine &engine, NativeObject &object, const char *name)
93 {
94 NativeObject *namedObj = ConvertNativeValueTo<NativeObject>(object.GetProperty(name));
95 return (namedObj != nullptr) ? namedObj->GetNativePointer() : nullptr;
96 }
97
98 // Async Task
AsyncTask(NativeDeferred * deferred,std::unique_ptr<AsyncTask::ExecuteCallback> && execute,std::unique_ptr<AsyncTask::CompleteCallback> && complete)99 AsyncTask::AsyncTask(NativeDeferred *deferred, std::unique_ptr<AsyncTask::ExecuteCallback> &&execute,
100 std::unique_ptr<AsyncTask::CompleteCallback> &&complete)
101 : deferred_(deferred), execute_(std::move(execute)), complete_(std::move(complete))
102 {}
103
AsyncTask(NativeReference * callbackRef,std::unique_ptr<AsyncTask::ExecuteCallback> && execute,std::unique_ptr<AsyncTask::CompleteCallback> && complete)104 AsyncTask::AsyncTask(NativeReference *callbackRef, std::unique_ptr<AsyncTask::ExecuteCallback> &&execute,
105 std::unique_ptr<AsyncTask::CompleteCallback> &&complete)
106 : callbackRef_(callbackRef), execute_(std::move(execute)), complete_(std::move(complete))
107 {}
108
109 AsyncTask::~AsyncTask() = default;
110
Schedule(const std::string & name,NativeEngine & engine,std::unique_ptr<AsyncTask> && task)111 void AsyncTask::Schedule(const std::string &name, NativeEngine &engine, std::unique_ptr<AsyncTask> &&task)
112 {
113 if (task && task->Start(name, engine)) {
114 task.release();
115 }
116 }
117
Resolve(NativeEngine & engine,NativeValue * value)118 void AsyncTask::Resolve(NativeEngine &engine, NativeValue *value)
119 {
120 HILOG_DEBUG("AsyncTask::Resolve is called");
121 if (deferred_) {
122 deferred_->Resolve(value);
123 deferred_.reset();
124 }
125 if (callbackRef_) {
126 NativeValue *argv[] = {
127 CreateJsError(engine, 0),
128 value,
129 };
130 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
131 callbackRef_.reset();
132 }
133 HILOG_DEBUG("AsyncTask::Resolve is called end.");
134 }
135
ResolveWithNoError(NativeEngine & engine,NativeValue * value)136 void AsyncTask::ResolveWithNoError(NativeEngine &engine, NativeValue *value)
137 {
138 HILOG_DEBUG("AsyncTask::Resolve is called");
139 if (deferred_) {
140 deferred_->Resolve(value);
141 deferred_.reset();
142 }
143 if (callbackRef_) {
144 NativeValue *argv[] = {
145 engine.CreateNull(),
146 value,
147 };
148 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
149 callbackRef_.reset();
150 }
151 HILOG_DEBUG("AsyncTask::Resolve is called end.");
152 }
153
Reject(NativeEngine & engine,NativeValue * error)154 void AsyncTask::Reject(NativeEngine &engine, NativeValue *error)
155 {
156 if (deferred_) {
157 deferred_->Reject(error);
158 deferred_.reset();
159 }
160 if (callbackRef_) {
161 NativeValue *argv[] = {
162 error,
163 engine.CreateUndefined(),
164 };
165 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
166 callbackRef_.reset();
167 }
168 }
169
ResolveWithCustomize(NativeEngine & engine,NativeValue * error,NativeValue * value)170 void AsyncTask::ResolveWithCustomize(NativeEngine &engine, NativeValue *error, NativeValue *value)
171 {
172 HILOG_DEBUG("AsyncTask::ResolveWithCustomize is called");
173 if (deferred_) {
174 deferred_->Resolve(value);
175 deferred_.reset();
176 }
177 if (callbackRef_) {
178 NativeValue *argv[] = {
179 error,
180 value,
181 };
182 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
183 callbackRef_.reset();
184 }
185 HILOG_DEBUG("AsyncTask::ResolveWithCustomize is called end.");
186 }
187
RejectWithCustomize(NativeEngine & engine,NativeValue * error,NativeValue * value)188 void AsyncTask::RejectWithCustomize(NativeEngine &engine, NativeValue *error, NativeValue *value)
189 {
190 HILOG_DEBUG("AsyncTask::RejectWithCustomize is called");
191 if (deferred_) {
192 deferred_->Reject(error);
193 deferred_.reset();
194 }
195 if (callbackRef_) {
196 NativeValue *argv[] = {
197 error,
198 value,
199 };
200 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
201 callbackRef_.reset();
202 }
203 HILOG_DEBUG("AsyncTask::RejectWithCustomize is called end.");
204 }
205
Execute(NativeEngine * engine,void * data)206 void AsyncTask::Execute(NativeEngine *engine, void *data)
207 {
208 if (engine == nullptr || data == nullptr) {
209 return;
210 }
211 auto me = static_cast<AsyncTask*>(data);
212 if (me->execute_ && *(me->execute_)) {
213 (*me->execute_)();
214 }
215 }
216
Complete(NativeEngine * engine,int32_t status,void * data)217 void AsyncTask::Complete(NativeEngine *engine, int32_t status, void *data)
218 {
219 if (engine == nullptr || data == nullptr) {
220 return;
221 }
222 std::unique_ptr<AsyncTask> me(static_cast<AsyncTask*>(data));
223 if (me->complete_ && *(me->complete_)) {
224 (*me->complete_)(*engine, *me, status);
225 }
226 }
227
Start(const std::string & name,NativeEngine & engine)228 bool AsyncTask::Start(const std::string &name, NativeEngine &engine)
229 {
230 work_.reset(engine.CreateAsyncWork(name, Execute, Complete, this));
231 return work_->Queue();
232 }
233
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,AsyncTask::ExecuteCallback && execute,AsyncTask::CompleteCallback && complete,NativeValue ** result)234 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine &engine, NativeValue *lastParam,
235 AsyncTask::ExecuteCallback &&execute, AsyncTask::CompleteCallback &&complete, NativeValue **result)
236 {
237 return CreateAsyncTaskWithLastParam(engine, lastParam,
238 std::make_unique<AsyncTask::ExecuteCallback>(std::move(execute)),
239 std::make_unique<AsyncTask::CompleteCallback>(std::move(complete)), result);
240 }
241
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,AsyncTask::ExecuteCallback && execute,nullptr_t,NativeValue ** result)242 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine &engine, NativeValue *lastParam,
243 AsyncTask::ExecuteCallback &&execute, nullptr_t, NativeValue **result)
244 {
245 return CreateAsyncTaskWithLastParam(
246 engine, lastParam, std::make_unique<AsyncTask::ExecuteCallback>(std::move(execute)), nullptr, result);
247 }
248
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,nullptr_t,AsyncTask::CompleteCallback && complete,NativeValue ** result)249 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine &engine, NativeValue *lastParam,
250 nullptr_t, AsyncTask::CompleteCallback &&complete, NativeValue **result)
251 {
252 return CreateAsyncTaskWithLastParam(
253 engine, lastParam, nullptr, std::make_unique<AsyncTask::CompleteCallback>(std::move(complete)), result);
254 }
255
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,nullptr_t,nullptr_t,NativeValue ** result)256 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine &engine, NativeValue *lastParam,
257 nullptr_t, nullptr_t, NativeValue **result)
258 {
259 return CreateAsyncTaskWithLastParam(engine, lastParam, std::unique_ptr<AsyncTask::ExecuteCallback>(),
260 std::unique_ptr<AsyncTask::CompleteCallback>(), result);
261 }
262
LoadSystemModuleByEngine(NativeEngine * engine,const std::string & moduleName,NativeValue * const * argv,size_t argc)263 std::unique_ptr<NativeReference> JsRuntime::LoadSystemModuleByEngine(NativeEngine *engine,
264 const std::string &moduleName, NativeValue *const *argv, size_t argc)
265 {
266 HILOG_DEBUG("JsRuntime::LoadSystemModule(%{public}s)", moduleName.c_str());
267 if (engine == nullptr) {
268 HILOG_DEBUG("JsRuntime::LoadSystemModule: invalid engine.");
269 return std::unique_ptr<NativeReference>();
270 }
271
272 NativeObject *globalObj = ConvertNativeValueTo<NativeObject>(engine->GetGlobal());
273 std::unique_ptr<NativeReference> methodRequireNapiRef_;
274 methodRequireNapiRef_.reset(engine->CreateReference(globalObj->GetProperty("requireNapi"), 1));
275 if (!methodRequireNapiRef_) {
276 HILOG_ERROR("Failed to create reference for global.requireNapi");
277 return nullptr;
278 }
279 NativeValue *className = engine->CreateString(moduleName.c_str(), moduleName.length());
280 NativeValue *classValue =
281 engine->CallFunction(engine->GetGlobal(), methodRequireNapiRef_->Get(), &className, 1);
282 NativeValue *instanceValue = engine->CreateInstance(classValue, argv, argc);
283 if (instanceValue == nullptr) {
284 HILOG_ERROR("Failed to create object instance");
285 return std::unique_ptr<NativeReference>();
286 }
287
288 return std::unique_ptr<NativeReference>(engine->CreateReference(instanceValue, 1));
289 }
290 } // namespace AbilityRuntime
291 } // namespace OHOS