1 /*
2 * Copyright (c) 2021-2022 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 // Handle Scope
HandleScope(JsRuntime & jsRuntime)99 HandleScope::HandleScope(JsRuntime& jsRuntime)
100 {
101 scopeManager_ = jsRuntime.GetNativeEngine().GetScopeManager();
102 if (scopeManager_ != nullptr) {
103 nativeScope_ = scopeManager_->Open();
104 }
105 }
106
HandleScope(NativeEngine & engine)107 HandleScope::HandleScope(NativeEngine& engine)
108 {
109 scopeManager_ = engine.GetScopeManager();
110 if (scopeManager_ != nullptr) {
111 nativeScope_ = scopeManager_->Open();
112 }
113 }
114
~HandleScope()115 HandleScope::~HandleScope()
116 {
117 if (nativeScope_ != nullptr) {
118 scopeManager_->Close(nativeScope_);
119 nativeScope_ = nullptr;
120 }
121 scopeManager_ = nullptr;
122 }
123
124 // Handle Escape
HandleEscape(JsRuntime & jsRuntime)125 HandleEscape::HandleEscape(JsRuntime& jsRuntime)
126 {
127 scopeManager_ = jsRuntime.GetNativeEngine().GetScopeManager();
128 if (scopeManager_ != nullptr) {
129 nativeScope_ = scopeManager_->OpenEscape();
130 }
131 }
132
HandleEscape(NativeEngine & engine)133 HandleEscape::HandleEscape(NativeEngine& engine)
134 {
135 scopeManager_ = engine.GetScopeManager();
136 if (scopeManager_ != nullptr) {
137 nativeScope_ = scopeManager_->OpenEscape();
138 }
139 }
140
~HandleEscape()141 HandleEscape::~HandleEscape()
142 {
143 if (nativeScope_ != nullptr) {
144 scopeManager_->CloseEscape(nativeScope_);
145 nativeScope_ = nullptr;
146 }
147 scopeManager_ = nullptr;
148 }
149
Escape(NativeValue * value)150 NativeValue* HandleEscape::Escape(NativeValue* value)
151 {
152 if (nativeScope_ != nullptr) {
153 scopeManager_->Escape(nativeScope_, value);
154 }
155 return value;
156 }
157
158 // Async Task
AsyncTask(NativeDeferred * deferred,std::unique_ptr<AsyncTask::ExecuteCallback> && execute,std::unique_ptr<AsyncTask::CompleteCallback> && complete)159 AsyncTask::AsyncTask(NativeDeferred* deferred, std::unique_ptr<AsyncTask::ExecuteCallback>&& execute,
160 std::unique_ptr<AsyncTask::CompleteCallback>&& complete)
161 : deferred_(deferred), execute_(std::move(execute)), complete_(std::move(complete))
162 {}
163
AsyncTask(NativeReference * callbackRef,std::unique_ptr<AsyncTask::ExecuteCallback> && execute,std::unique_ptr<AsyncTask::CompleteCallback> && complete)164 AsyncTask::AsyncTask(NativeReference* callbackRef, std::unique_ptr<AsyncTask::ExecuteCallback>&& execute,
165 std::unique_ptr<AsyncTask::CompleteCallback>&& complete)
166 : callbackRef_(callbackRef), execute_(std::move(execute)), complete_(std::move(complete))
167 {}
168
169 AsyncTask::~AsyncTask() = default;
170
Schedule(const std::string & name,NativeEngine & engine,std::unique_ptr<AsyncTask> && task)171 void AsyncTask::Schedule(const std::string &name, NativeEngine& engine, std::unique_ptr<AsyncTask>&& task)
172 {
173 if (task && task->Start(name, engine)) {
174 task.release();
175 }
176 }
177
ScheduleHighQos(const std::string & name,NativeEngine & engine,std::unique_ptr<AsyncTask> && task)178 void AsyncTask::ScheduleHighQos(const std::string &name, NativeEngine& engine, std::unique_ptr<AsyncTask>&& task)
179 {
180 if (task && task->StartHighQos(name, engine)) {
181 task.release();
182 }
183 }
184
ScheduleLowQos(const std::string & name,NativeEngine & engine,std::unique_ptr<AsyncTask> && task)185 void AsyncTask::ScheduleLowQos(const std::string &name, NativeEngine& engine, std::unique_ptr<AsyncTask>&& task)
186 {
187 if (task && task->StartLowQos(name, engine)) {
188 task.release();
189 }
190 }
191
ScheduleWithDefaultQos(const std::string & name,NativeEngine & engine,std::unique_ptr<AsyncTask> && task)192 void AsyncTask::ScheduleWithDefaultQos(const std::string &name,
193 NativeEngine& engine, std::unique_ptr<AsyncTask>&& task)
194 {
195 if (task && task->StartWithDefaultQos(name, engine)) {
196 task.release();
197 }
198 }
199
StartWithDefaultQos(const std::string & name,NativeEngine & engine)200 bool AsyncTask::StartWithDefaultQos(const std::string &name, NativeEngine& engine)
201 {
202 work_.reset(engine.CreateAsyncWork(name, Execute, Complete, this));
203 return work_->QueueWithQos(napi_qos_default);
204 }
205
Resolve(NativeEngine & engine,NativeValue * value)206 void AsyncTask::Resolve(NativeEngine& engine, NativeValue* value)
207 {
208 HILOG_DEBUG("AsyncTask::Resolve is called");
209 if (deferred_) {
210 deferred_->Resolve(value);
211 deferred_.reset();
212 }
213 if (callbackRef_) {
214 NativeValue* argv[] = {
215 CreateJsError(engine, 0),
216 value,
217 };
218 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
219 callbackRef_.reset();
220 }
221 HILOG_DEBUG("AsyncTask::Resolve is called end.");
222 }
223
ResolveWithNoError(NativeEngine & engine,NativeValue * value)224 void AsyncTask::ResolveWithNoError(NativeEngine& engine, NativeValue* value)
225 {
226 HILOG_DEBUG("AsyncTask::Resolve is called");
227 if (deferred_) {
228 deferred_->Resolve(value);
229 deferred_.reset();
230 }
231 if (callbackRef_) {
232 NativeValue* argv[] = {
233 engine.CreateNull(),
234 value,
235 };
236 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
237 callbackRef_.reset();
238 }
239 HILOG_DEBUG("AsyncTask::Resolve is called end.");
240 }
241
Reject(NativeEngine & engine,NativeValue * error)242 void AsyncTask::Reject(NativeEngine& engine, NativeValue* error)
243 {
244 if (deferred_) {
245 deferred_->Reject(error);
246 deferred_.reset();
247 }
248 if (callbackRef_) {
249 NativeValue* argv[] = {
250 error,
251 engine.CreateUndefined(),
252 };
253 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
254 callbackRef_.reset();
255 }
256 }
257
ResolveWithCustomize(NativeEngine & engine,NativeValue * error,NativeValue * value)258 void AsyncTask::ResolveWithCustomize(NativeEngine& engine, NativeValue* error, NativeValue* value)
259 {
260 HILOG_DEBUG("AsyncTask::ResolveWithCustomize is called");
261 if (deferred_) {
262 deferred_->Resolve(value);
263 deferred_.reset();
264 }
265 if (callbackRef_) {
266 NativeValue* argv[] = {
267 error,
268 value,
269 };
270 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
271 callbackRef_.reset();
272 }
273 HILOG_DEBUG("AsyncTask::ResolveWithCustomize is called end.");
274 }
275
RejectWithCustomize(NativeEngine & engine,NativeValue * error,NativeValue * value)276 void AsyncTask::RejectWithCustomize(NativeEngine& engine, NativeValue* error, NativeValue* value)
277 {
278 HILOG_DEBUG("AsyncTask::RejectWithCustomize is called");
279 if (deferred_) {
280 deferred_->Reject(error);
281 deferred_.reset();
282 }
283 if (callbackRef_) {
284 NativeValue* argv[] = {
285 error,
286 value,
287 };
288 engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
289 callbackRef_.reset();
290 }
291 HILOG_DEBUG("AsyncTask::RejectWithCustomize is called end.");
292 }
293
Execute(NativeEngine * engine,void * data)294 void AsyncTask::Execute(NativeEngine* engine, void* data)
295 {
296 if (engine == nullptr || data == nullptr) {
297 return;
298 }
299 auto me = static_cast<AsyncTask*>(data);
300 if (me->execute_ && *(me->execute_)) {
301 (*me->execute_)();
302 }
303 }
304
Complete(NativeEngine * engine,int32_t status,void * data)305 void AsyncTask::Complete(NativeEngine* engine, int32_t status, void* data)
306 {
307 if (engine == nullptr || data == nullptr) {
308 return;
309 }
310 std::unique_ptr<AsyncTask> me(static_cast<AsyncTask*>(data));
311 if (me->complete_ && *(me->complete_)) {
312 HandleScope handleScope(*engine);
313 (*me->complete_)(*engine, *me, status);
314 }
315 }
316
Start(const std::string & name,NativeEngine & engine)317 bool AsyncTask::Start(const std::string &name, NativeEngine& engine)
318 {
319 work_.reset(engine.CreateAsyncWork(name, Execute, Complete, this));
320 return work_->Queue();
321 }
322
StartHighQos(const std::string & name,NativeEngine & engine)323 bool AsyncTask::StartHighQos(const std::string &name, NativeEngine& engine)
324 {
325 work_.reset(engine.CreateAsyncWork(name, Execute, Complete, this));
326 return work_->QueueWithQos(napi_qos_user_initiated);
327 }
328
StartLowQos(const std::string & name,NativeEngine & engine)329 bool AsyncTask::StartLowQos(const std::string &name, NativeEngine& engine)
330 {
331 work_.reset(engine.CreateAsyncWork(name, Execute, Complete, this));
332 return work_->QueueWithQos(napi_qos_utility);
333 }
334
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,AsyncTask::ExecuteCallback && execute,AsyncTask::CompleteCallback && complete,NativeValue ** result)335 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
336 AsyncTask::ExecuteCallback&& execute, AsyncTask::CompleteCallback&& complete, NativeValue** result)
337 {
338 return CreateAsyncTaskWithLastParam(engine, lastParam,
339 std::make_unique<AsyncTask::ExecuteCallback>(std::move(execute)),
340 std::make_unique<AsyncTask::CompleteCallback>(std::move(complete)), result);
341 }
342
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,AsyncTask::ExecuteCallback && execute,nullptr_t,NativeValue ** result)343 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
344 AsyncTask::ExecuteCallback&& execute, nullptr_t, NativeValue** result)
345 {
346 return CreateAsyncTaskWithLastParam(
347 engine, lastParam, std::make_unique<AsyncTask::ExecuteCallback>(std::move(execute)), nullptr, result);
348 }
349
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,nullptr_t,AsyncTask::CompleteCallback && complete,NativeValue ** result)350 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
351 nullptr_t, AsyncTask::CompleteCallback&& complete, NativeValue** result)
352 {
353 return CreateAsyncTaskWithLastParam(
354 engine, lastParam, nullptr, std::make_unique<AsyncTask::CompleteCallback>(std::move(complete)), result);
355 }
356
CreateAsyncTaskWithLastParam(NativeEngine & engine,NativeValue * lastParam,nullptr_t,nullptr_t,NativeValue ** result)357 std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
358 nullptr_t, nullptr_t, NativeValue** result)
359 {
360 return CreateAsyncTaskWithLastParam(engine, lastParam, std::unique_ptr<AsyncTask::ExecuteCallback>(),
361 std::unique_ptr<AsyncTask::CompleteCallback>(), result);
362 }
363 } // namespace AbilityRuntime
364 } // namespace OHOS
365