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 #include "feature_ability.h"
16 
17 #include <cstring>
18 #include <uv.h>
19 #include <vector>
20 
21 #include "napi_common_ability.h"
22 #include "js_napi_common_ability.h"
23 #include "ability_process.h"
24 #include "element_name.h"
25 #include "hilog_tag_wrapper.h"
26 #include "hitrace_meter.h"
27 #include "js_runtime_utils.h"
28 #ifdef SUPPORT_GRAPHICS
29 #include "js_window.h"
30 #endif
31 #include "napi_common_util.h"
32 #include "napi_context.h"
33 #include "napi_data_ability_helper.h"
34 #include "napi/native_api.h"
35 #include "napi/native_node_api.h"
36 #include "securec.h"
37 
38 using namespace OHOS::AAFwk;
39 using namespace OHOS::AppExecFwk;
40 
41 namespace OHOS {
42 namespace AppExecFwk {
43 using namespace OHOS::AbilityRuntime;
44 static int64_t dummyRequestCode_ = 0;
45 CallbackInfo g_aceCallbackInfo;
46 
47 const int PARA_SIZE_IS_ONE = 1;
48 const int PARA_SIZE_IS_TWO = 2;
49 
50 /**
51  * @brief FeatureAbility NAPI module registration.
52  *
53  * @param env The environment that the Node-API call is invoked under.
54  * @param exports An empty object via the exports parameter as a convenience.
55  *
56  * @return The return value from Init is treated as the exports object for the module.
57  */
FeatureAbilityInit(napi_env env,napi_value exports)58 napi_value FeatureAbilityInit(napi_env env, napi_value exports)
59 {
60     TAG_LOGD(AAFwkTag::FA, "called");
61     napi_property_descriptor properties[] = {
62         DECLARE_NAPI_FUNCTION("finishWithResult", NAPI_SetResult),
63         DECLARE_NAPI_FUNCTION("getAppType", NAPI_GetAppType),
64         DECLARE_NAPI_FUNCTION("getAbilityName", NAPI_GetAbilityName),
65         DECLARE_NAPI_FUNCTION("getAbilityInfo", NAPI_GetAbilityInfo),
66         DECLARE_NAPI_FUNCTION("getHapModuleInfo", NAPI_GetHapModuleInfo),
67         DECLARE_NAPI_FUNCTION("getDataAbilityHelper", NAPI_GetDataAbilityHelper),
68         DECLARE_NAPI_FUNCTION("acquireDataAbilityHelper", NAPI_AcquireDataAbilityHelper),
69         DECLARE_NAPI_FUNCTION("continueAbility", NAPI_FAContinueAbility),
70         DECLARE_NAPI_FUNCTION("getWantSync", NAPI_GetWantSync),
71     };
72     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties));
73 
74     return JsFeatureAbilityInit(env, exports);
75 }
76 
77 class JsFeatureAbility : public JsNapiCommon {
78 public:
79     JsFeatureAbility() = default;
80     virtual ~JsFeatureAbility() override = default;
81 
82     Ability* GetAbility(napi_env env);
83     static void Finalizer(napi_env env, void *data, void *hint);
84     static napi_value StartAbility(napi_env env, napi_callback_info info);
85     static napi_value HasWindowFocus(napi_env env, napi_callback_info info);
86     static napi_value ConnectAbility(napi_env env, napi_callback_info info);
87     static napi_value DisconnectAbility(napi_env env, napi_callback_info info);
88     static napi_value GetWant(napi_env env, napi_callback_info info);
89     static napi_value StartAbilityForResult(napi_env env, napi_callback_info info);
90     static napi_value GetContext(napi_env env, napi_callback_info info);
91     static napi_value FinishWithResult(napi_env env, napi_callback_info info);
92     static napi_value TerminateAbility(napi_env env, napi_callback_info info);
93     static napi_value GetWindow(napi_env env, napi_callback_info info);
94     std::shared_ptr<NativeReference> GetFAContext();
95     void SetFAContext(std::shared_ptr<NativeReference> context);
96 private:
97     napi_value OnStartAbilityForResult(napi_env env, NapiCallbackInfo& info);
98     napi_value OnFinishWithResult(napi_env env, NapiCallbackInfo& info);
99     napi_value OnGetWindow(napi_env env, napi_callback_info info);
100 #ifdef SUPPORT_GRAPHICS
101     napi_value OnHasWindowFocus(napi_env env, const NapiCallbackInfo& info);
102 #endif
103     std::shared_ptr<NativeReference> context_;
104 };
105 
Finalizer(napi_env env,void * data,void * hint)106 void JsFeatureAbility::Finalizer(napi_env env, void *data, void *hint)
107 {
108     TAG_LOGD(AAFwkTag::FA, "called");
109     std::unique_ptr<JsFeatureAbility>(static_cast<JsFeatureAbility*>(data));
110 }
111 
JsFeatureAbilityInit(napi_env env,napi_value exports)112 napi_value JsFeatureAbilityInit(napi_env env, napi_value exports)
113 {
114     TAG_LOGD(AAFwkTag::FA, "called");
115     if (env == nullptr || exports == nullptr) {
116         TAG_LOGE(AAFwkTag::FA, "Invalid input parameters");
117         return exports;
118     }
119 
120     if (!AppExecFwk::CheckTypeForNapiValue(env, exports, napi_object)) {
121         TAG_LOGE(AAFwkTag::FA, "null object");
122         return exports;
123     }
124 
125     std::unique_ptr<JsFeatureAbility> jsFeatureAbility = std::make_unique<JsFeatureAbility>();
126     jsFeatureAbility->ability_ = jsFeatureAbility->GetAbility(env);
127     napi_value contextValue = CreateNapiJSContext(env);
128     if (contextValue != nullptr) {
129         napi_ref contextRef = nullptr;
130         napi_create_reference(env, contextValue, 1, &contextRef);
131         jsFeatureAbility->SetFAContext(
132             std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(contextRef)));
133     }
134     napi_wrap(env, exports, jsFeatureAbility.release(), JsFeatureAbility::Finalizer, nullptr, nullptr);
135 
136     const char *moduleName = "JsFeatureAbility";
137     BindNativeFunction(env, exports, "startAbility", moduleName, JsFeatureAbility::StartAbility);
138     BindNativeFunction(env, exports, "getWant", moduleName, JsFeatureAbility::GetWant);
139     BindNativeFunction(env, exports, "hasWindowFocus", moduleName, JsFeatureAbility::HasWindowFocus);
140     BindNativeFunction(env, exports, "connectAbility", moduleName, JsFeatureAbility::ConnectAbility);
141     BindNativeFunction(env, exports, "disconnectAbility", moduleName, JsFeatureAbility::DisconnectAbility);
142     BindNativeFunction(env, exports, "startAbilityForResult", moduleName, JsFeatureAbility::StartAbilityForResult);
143     BindNativeFunction(env, exports, "getContext", moduleName, JsFeatureAbility::GetContext);
144     BindNativeFunction(env, exports, "getWindow", moduleName, JsFeatureAbility::GetWindow);
145     BindNativeFunction(env, exports, "terminateSelfWithResult", moduleName, JsFeatureAbility::FinishWithResult);
146     BindNativeFunction(env, exports, "terminateSelf", moduleName, JsFeatureAbility::TerminateAbility);
147     return exports;
148 }
149 
SetFAContext(std::shared_ptr<NativeReference> context)150 void JsFeatureAbility::SetFAContext(std::shared_ptr<NativeReference> context)
151 {
152     context_ = context;
153 }
154 
GetFAContext()155 std::shared_ptr<NativeReference> JsFeatureAbility::GetFAContext()
156 {
157     return context_;
158 }
159 
StartAbility(napi_env env,napi_callback_info info)160 napi_value JsFeatureAbility::StartAbility(napi_env env, napi_callback_info info)
161 {
162     JsFeatureAbility *me = CheckParamsAndGetThis<JsFeatureAbility>(env, info);
163     return (me != nullptr) ? me->JsStartAbility(env, info, AbilityType::PAGE) : nullptr;
164 }
165 
GetWant(napi_env env,napi_callback_info info)166 napi_value JsFeatureAbility::GetWant(napi_env env, napi_callback_info info)
167 {
168     JsFeatureAbility *me = CheckParamsAndGetThis<JsFeatureAbility>(env, info);
169     return (me != nullptr) ? me->JsGetWant(env, info, AbilityType::PAGE) : nullptr;
170 }
171 
HasWindowFocus(napi_env env,napi_callback_info info)172 napi_value JsFeatureAbility::HasWindowFocus(napi_env env, napi_callback_info info)
173 {
174 #ifdef SUPPORT_GRAPHICS
175     GET_NAPI_INFO_AND_CALL(env, info, JsFeatureAbility, OnHasWindowFocus);
176 #else
177     return nullptr;
178 #endif
179 }
180 
ConnectAbility(napi_env env,napi_callback_info info)181 napi_value JsFeatureAbility::ConnectAbility(napi_env env, napi_callback_info info)
182 {
183     JsFeatureAbility *me = CheckParamsAndGetThis<JsFeatureAbility>(env, info);
184     return (me != nullptr) ? me->JsConnectAbility(env, info, AbilityType::PAGE) : nullptr;
185 }
186 
DisconnectAbility(napi_env env,napi_callback_info info)187 napi_value JsFeatureAbility::DisconnectAbility(napi_env env, napi_callback_info info)
188 {
189     JsFeatureAbility *me = CheckParamsAndGetThis<JsFeatureAbility>(env, info);
190     return (me != nullptr) ? me->JsDisConnectAbility(env, info, AbilityType::PAGE) : nullptr;
191 }
192 
StartAbilityForResult(napi_env env,napi_callback_info info)193 napi_value JsFeatureAbility::StartAbilityForResult(napi_env env, napi_callback_info info)
194 {
195     GET_NAPI_INFO_AND_CALL(env, info, JsFeatureAbility, OnStartAbilityForResult);
196 }
197 
GetContext(napi_env env,napi_callback_info info)198 napi_value JsFeatureAbility::GetContext(napi_env env, napi_callback_info info)
199 {
200     JsFeatureAbility *me = CheckParamsAndGetThis<JsFeatureAbility>(env, info);
201     if (me != nullptr) {
202         std::shared_ptr<NativeReference> contextObj = me->GetFAContext();
203         if (contextObj != nullptr) {
204             return contextObj->GetNapiValue();
205         }
206         napi_value contextValue = me->JsGetContext(env, info, AbilityType::PAGE);
207         if (contextValue != nullptr) {
208             napi_ref contextRef = nullptr;
209             napi_create_reference(env, contextValue, 1, &contextRef);
210             me->SetFAContext(std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(contextRef)));
211             return contextValue;
212         }
213     }
214     return nullptr;
215 }
216 
FinishWithResult(napi_env env,napi_callback_info info)217 napi_value JsFeatureAbility::FinishWithResult(napi_env env, napi_callback_info info)
218 {
219     GET_NAPI_INFO_AND_CALL(env, info, JsFeatureAbility, OnFinishWithResult);
220 }
221 
TerminateAbility(napi_env env,napi_callback_info info)222 napi_value JsFeatureAbility::TerminateAbility(napi_env env, napi_callback_info info)
223 {
224     GET_NAPI_INFO_AND_CALL(env, info, JsFeatureAbility, JsTerminateAbility);
225 }
226 
227 #ifdef SUPPORT_GRAPHICS
OnHasWindowFocus(napi_env env,const NapiCallbackInfo & info)228 napi_value JsFeatureAbility::OnHasWindowFocus(napi_env env, const NapiCallbackInfo& info)
229 {
230     TAG_LOGD(AAFwkTag::FA, "called");
231     if (info.argc > ARGS_ONE || info.argc < ARGS_ZERO) {
232         TAG_LOGE(AAFwkTag::FA, "invalid argc");
233         return CreateJsUndefined(env);
234     }
235     NapiAsyncTask::CompleteCallback complete =
236         [obj = this](napi_env env, NapiAsyncTask &task, int32_t status) {
237             if (obj->ability_ == nullptr) {
238                 TAG_LOGE(AAFwkTag::FA, "HasWindowFocus execute error, the ability is nullptr");
239                 task.Reject(env, CreateJsError(env, NAPI_ERR_ACE_ABILITY, "HasWindowFocus failed"));
240                 return;
241             }
242             auto ret = obj->ability_->HasWindowFocus();
243             task.Resolve(env, CreateJsValue(env, ret));
244         };
245     napi_value result = nullptr;
246     napi_value lastParam = (info.argc == ARGS_ZERO) ? nullptr : info.argv[PARAM0];
247     NapiAsyncTask::ScheduleHighQos("JSFeatureAbility::OnHasWindowFocus",
248         env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
249     TAG_LOGD(AAFwkTag::FA, "end");
250     return result;
251 }
252 #endif
253 
GetAbility(napi_env env)254 Ability* JsFeatureAbility::GetAbility(napi_env env)
255 {
256     napi_status ret;
257     napi_value global = nullptr;
258     const napi_extended_error_info *errorInfo = nullptr;
259     ret = napi_get_global(env, &global);
260     if (ret != napi_ok) {
261         napi_get_last_error_info(env, &errorInfo);
262         TAG_LOGE(AAFwkTag::FA, "get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
263         return nullptr;
264     }
265 
266     napi_value abilityObj = nullptr;
267     ret = napi_get_named_property(env, global, "ability", &abilityObj);
268     if (ret != napi_ok) {
269         napi_get_last_error_info(env, &errorInfo);
270         TAG_LOGE(AAFwkTag::FA, "get_named_property=%{public}d err:%{public}s", ret, errorInfo->error_message);
271         return nullptr;
272     }
273 
274     Ability *ability = nullptr;
275     ret = napi_get_value_external(env, abilityObj, reinterpret_cast<void **>(&ability));
276     if (ret != napi_ok) {
277         napi_get_last_error_info(env, &errorInfo);
278         TAG_LOGE(AAFwkTag::FA, "get_value_external=%{public}d err:%{public}s", ret, errorInfo->error_message);
279         return nullptr;
280     }
281 
282     return ability;
283 }
284 
OnStartAbilityForResult(napi_env env,NapiCallbackInfo & info)285 napi_value JsFeatureAbility::OnStartAbilityForResult(napi_env env, NapiCallbackInfo& info)
286 {
287     TAG_LOGD(AAFwkTag::FA, "called");
288     if (info.argc < ARGS_ONE || info.argc > ARGS_TWO) {
289         TAG_LOGE(AAFwkTag::FA, "invalid argc");
290         return CreateJsUndefined(env);
291     }
292 
293     if (ability_ == nullptr) {
294         TAG_LOGE(AAFwkTag::FA, "null ability");
295         return CreateJsUndefined(env);
296     }
297 
298     std::shared_ptr<CallAbilityParam> abilityParam = std::make_shared<CallAbilityParam>();
299     std::shared_ptr<CallbackInfo> startAbilityCallback = std::make_shared<CallbackInfo>();
300     startAbilityCallback->env = env;
301 
302     if (UnwrapForResultParam(*abilityParam, env, info.argv[0]) == nullptr) {
303         TAG_LOGE(AAFwkTag::FA, "unwrapForResultParam failed");
304         startAbilityCallback->errCode = NAPI_ERR_PARAM_INVALID;
305     }
306 
307     napi_value result = nullptr;
308     napi_value lastParam = (info.argc == ARGS_TWO) ? info.argv[ARGS_ONE] : nullptr;
309     startAbilityCallback->napiAsyncTask =
310         AbilityRuntime::CreateAsyncTaskWithLastParam(env, lastParam, nullptr, nullptr, &result).release();
311 
312     AbilityProcess::GetInstance()->AddAbilityResultCallback(ability_,
313         *abilityParam, startAbilityCallback->errCode, *startAbilityCallback);
314 
315     if (startAbilityCallback->errCode == NAPI_ERR_NO_ERROR) {
316         startAbilityCallback->errCode = AbilityProcess::GetInstance()->StartAbility(ability_,
317             *abilityParam, *startAbilityCallback);
318     }
319 
320     if (startAbilityCallback->errCode != NAPI_ERR_NO_ERROR) {
321         // Callback the errcode when StartAbilityForResult failed.
322         Want resultData;
323         AbilityProcess::GetInstance()->OnAbilityResult(ability_, abilityParam->requestCode, 0, resultData);
324     }
325 
326     return result;
327 }
328 
OnFinishWithResult(napi_env env,NapiCallbackInfo & info)329 napi_value JsFeatureAbility::OnFinishWithResult(napi_env env, NapiCallbackInfo& info)
330 {
331     TAG_LOGD(AAFwkTag::FA, "called");
332     if (info.argc > ARGS_TWO || info.argc < ARGS_ONE) {
333         TAG_LOGE(AAFwkTag::FA, "invalid argc");
334         return CreateJsUndefined(env);
335     }
336 
337     if (!AppExecFwk::IsTypeForNapiValue(env, info.argv[0], napi_object)) {
338         TAG_LOGE(AAFwkTag::FA, "param not object");
339         return CreateJsUndefined(env);
340     }
341 
342     CallAbilityParam param;
343     napi_value jsRequestCode = nullptr;
344     napi_get_named_property(env, info.argv[0], "resultCode", &jsRequestCode);
345     if (!AppExecFwk::IsTypeForNapiValue(env, jsRequestCode, napi_number)) {
346         TAG_LOGE(AAFwkTag::FA, "resultCode type failed");
347         return CreateJsUndefined(env);
348     }
349     if (!ConvertFromJsValue(env, jsRequestCode, param.requestCode)) {
350         TAG_LOGE(AAFwkTag::FA, "convert resultCode failed");
351         return CreateJsUndefined(env);
352     }
353     bool hasWant = false;
354     napi_has_named_property(env, info.argv[0], "want", &hasWant);
355     if (hasWant) {
356         napi_value jsWant = nullptr;
357         napi_get_named_property(env, info.argv[0], "want", &jsWant);
358         if (!AppExecFwk::IsTypeForNapiValue(env, jsWant, napi_object)) {
359             TAG_LOGE(AAFwkTag::FA, "want type failed");
360             return CreateJsUndefined(env);
361         }
362         if (!UnwrapWant(env, jsWant, param.want)) {
363             TAG_LOGE(AAFwkTag::FA, "unwrapWant failed");
364             return CreateJsUndefined(env);
365         }
366     }
367 
368     NapiAsyncTask::CompleteCallback complete = [obj = this, param](napi_env env, NapiAsyncTask &task, int32_t status) {
369         if (obj->ability_ != nullptr) {
370             obj->ability_->SetResult(param.requestCode, param.want);
371             obj->ability_->TerminateAbility();
372         } else {
373             TAG_LOGE(AAFwkTag::FA, "null ability");
374         }
375         task.Resolve(env, CreateJsNull(env));
376     };
377     napi_value result = nullptr;
378     napi_value lastParam = (info.argc >= ARGS_TWO) ? info.argv[ARGS_ONE] : nullptr;
379     NapiAsyncTask::ScheduleHighQos("JSFeatureAbility::OnFinishWithResult",
380         env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
381     return result;
382 }
383 
384 #ifdef SUPPORT_GRAPHICS
GetWindow(napi_env env,napi_callback_info info)385 napi_value JsFeatureAbility::GetWindow(napi_env env, napi_callback_info info)
386 {
387     if (env == nullptr || info == nullptr) {
388         TAG_LOGE(AAFwkTag::FA, "null %{public}s", ((env == nullptr) ? "env" : "info"));
389         return nullptr;
390     }
391 
392     auto object = CheckParamsAndGetThis<JsFeatureAbility>(env, info);
393     if (object == nullptr) {
394         TAG_LOGE(AAFwkTag::FA, "null obj");
395         return nullptr;
396     }
397 
398     return object->OnGetWindow(env, info);
399 }
400 
OnGetWindow(napi_env env,napi_callback_info info)401 napi_value JsFeatureAbility::OnGetWindow(napi_env env, napi_callback_info info)
402 {
403     TAG_LOGD(AAFwkTag::FA, "called");
404     size_t argc = ARGS_MAX_COUNT;
405     napi_value argv[ARGS_MAX_COUNT] = { nullptr };
406     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
407     if (argc > ARGS_ONE) {
408         TAG_LOGE(AAFwkTag::FA, "input params count error, argc=%{public}zu", argc);
409         return CreateJsUndefined(env);
410     }
411 
412     auto complete = [obj = this] (napi_env env, NapiAsyncTask& task, int32_t status) {
413         if (obj->ability_ == nullptr) {
414             TAG_LOGE(AAFwkTag::FA, "null ability");
415             task.Resolve(env, CreateJsNull(env));
416             return;
417         }
418         auto window = obj->ability_->GetWindow();
419         task.Resolve(env, OHOS::Rosen::CreateJsWindowObject(env, window));
420     };
421 
422     auto callback = argc == ARGS_ZERO ? nullptr : argv[PARAM0];
423     napi_value result = nullptr;
424     NapiAsyncTask::ScheduleHighQos("JsFeatureAbility::OnGetWindow",
425         env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
426 
427     return result;
428 }
429 #else
430 
GetWindow(napi_env env,napi_callback_info info)431 napi_value JsFeatureAbility::GetWindow(napi_env env, napi_callback_info info)
432 {
433     return nullptr;
434 }
435 
OnGetWindow(napi_env env,napi_callback_info info)436 napi_value JsFeatureAbility::OnGetWindow(napi_env env, napi_callback_info info)
437 {
438     return nullptr;
439 }
440 #endif
441 
442 /**
443  * @brief FeatureAbility NAPI method : setResult.
444  *
445  * @param env The environment that the Node-API call is invoked under.
446  * @param info The callback info passed into the callback function.
447  *
448  * @return The return value from NAPI C++ to JS for the module.
449  */
NAPI_SetResult(napi_env env,napi_callback_info info)450 napi_value NAPI_SetResult(napi_env env, napi_callback_info info)
451 {
452     TAG_LOGI(AAFwkTag::FA, "called");
453     AsyncCallbackInfo *asyncCallbackInfo = CreateAsyncCallbackInfo(env);
454     if (asyncCallbackInfo == nullptr) {
455         TAG_LOGE(AAFwkTag::FA, "null asyncCallbackInfo");
456         return WrapVoidToJS(env);
457     }
458 
459     napi_value ret = SetResultWrap(env, info, asyncCallbackInfo);
460     if (ret == nullptr) {
461         TAG_LOGE(AAFwkTag::FA, "null ret");
462         if (asyncCallbackInfo != nullptr) {
463             delete asyncCallbackInfo;
464             asyncCallbackInfo = nullptr;
465         }
466         ret = WrapVoidToJS(env);
467     }
468     TAG_LOGI(AAFwkTag::FA, "end");
469     return ret;
470 }
471 
472 /**
473  * @brief SetResult processing function.
474  *
475  * @param env The environment that the Node-API call is invoked under.
476  * @param asyncCallbackInfo Process data asynchronously.
477  *
478  * @return Return JS data successfully, otherwise return nullptr.
479  */
SetResultWrap(napi_env env,napi_callback_info info,AsyncCallbackInfo * asyncCallbackInfo)480 napi_value SetResultWrap(napi_env env, napi_callback_info info, AsyncCallbackInfo *asyncCallbackInfo)
481 {
482     TAG_LOGI(AAFwkTag::FA, "called");
483     size_t argcAsync = 2;
484     const size_t argcPromise = 1;
485     const size_t argCountWithAsync = argcPromise + ARGS_ASYNC_COUNT;
486     napi_value args[ARGS_MAX_COUNT] = {nullptr};
487     napi_value ret = nullptr;
488 
489     NAPI_CALL(env, napi_get_cb_info(env, info, &argcAsync, args, nullptr, nullptr));
490     if (argcAsync > argCountWithAsync || argcAsync > ARGS_MAX_COUNT) {
491         TAG_LOGE(AAFwkTag::FA, "invalid argc");
492         return nullptr;
493     }
494 
495     CallAbilityParam param;
496     if (UnwrapAbilityResult(param, env, args[0]) == nullptr) {
497         TAG_LOGE(AAFwkTag::FA, "call unwrapWant failed");
498         return nullptr;
499     }
500     asyncCallbackInfo->param = param;
501 
502     if (argcAsync > argcPromise) {
503         ret = SetResultAsync(env, args, 1, asyncCallbackInfo);
504     } else {
505         ret = SetResultPromise(env, asyncCallbackInfo);
506     }
507     TAG_LOGI(AAFwkTag::FA, "end");
508     return ret;
509 }
510 
CreateAsyncWork(napi_env env,napi_value & resourceName,AsyncCallbackInfo * asyncCallbackInfo)511 napi_value CreateAsyncWork(napi_env env, napi_value &resourceName, AsyncCallbackInfo *asyncCallbackInfo)
512 {
513     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName,
514     [](napi_env env, void *data) {
515         TAG_LOGI(AAFwkTag::FA, "worker pool thread");
516         AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
517         if (asyncCallbackInfo == nullptr) {
518             TAG_LOGE(AAFwkTag::FA, "null asyncCallbackInfo");
519             return;
520         }
521 
522         if (asyncCallbackInfo->ability != nullptr) {
523             asyncCallbackInfo->ability->SetResult(
524                 asyncCallbackInfo->param.requestCode, asyncCallbackInfo->param.want);
525             asyncCallbackInfo->ability->TerminateAbility();
526         } else {
527             TAG_LOGE(AAFwkTag::FA, "null ability");
528         }
529         TAG_LOGI(AAFwkTag::FA, "worker pool thread execute exit");
530     },
531     [](napi_env env, napi_status status, void *data) {
532         TAG_LOGI(AAFwkTag::FA, "complete");
533         AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
534         if (asyncCallbackInfo == nullptr) {
535             TAG_LOGE(AAFwkTag::FA, "null asyncCallbackInfo");
536             return;
537         }
538         napi_value result[ARGS_TWO] = {nullptr};
539         napi_value callback = nullptr;
540         napi_value undefined = nullptr;
541         napi_value callResult = nullptr;
542         napi_get_undefined(env, &undefined);
543         result[PARAM0] = GetCallbackErrorValue(env, NO_ERROR);
544         napi_get_null(env, &result[PARAM1]);
545         napi_get_reference_value(env, asyncCallbackInfo->cbInfo.callback, &callback);
546         napi_call_function(env, undefined, callback, ARGS_TWO, &result[PARAM0], &callResult);
547 
548         if (asyncCallbackInfo->cbInfo.callback != nullptr) {
549             TAG_LOGD(AAFwkTag::FA, "napi_delete_reference");
550             napi_delete_reference(env, asyncCallbackInfo->cbInfo.callback);
551         }
552         napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
553         delete asyncCallbackInfo;
554         TAG_LOGI(AAFwkTag::FA, "complete end");
555     },
556     static_cast<void *>(asyncCallbackInfo),
557     &asyncCallbackInfo->asyncWork));
558     NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
559     napi_value result = nullptr;
560     NAPI_CALL(env, napi_get_null(env, &result));
561     TAG_LOGI(AAFwkTag::FA, "end");
562     return result;
563 }
564 
SetResultAsync(napi_env env,napi_value * args,const size_t argCallback,AsyncCallbackInfo * asyncCallbackInfo)565 napi_value SetResultAsync(
566     napi_env env, napi_value *args, const size_t argCallback, AsyncCallbackInfo *asyncCallbackInfo)
567 {
568     TAG_LOGI(AAFwkTag::FA, "called");
569     if (args == nullptr || asyncCallbackInfo == nullptr) {
570         TAG_LOGE(AAFwkTag::FA, "null param");
571         return nullptr;
572     }
573     napi_value resourceName = nullptr;
574     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
575 
576     napi_valuetype valuetype = napi_undefined;
577     NAPI_CALL(env, napi_typeof(env, args[argCallback], &valuetype));
578     if (valuetype == napi_function) {
579         napi_create_reference(env, args[argCallback], 1, &asyncCallbackInfo->cbInfo.callback);
580     }
581 
582     return CreateAsyncWork(env, resourceName, asyncCallbackInfo);
583 }
584 
SetResultPromise(napi_env env,AsyncCallbackInfo * asyncCallbackInfo)585 napi_value SetResultPromise(napi_env env, AsyncCallbackInfo *asyncCallbackInfo)
586 {
587     TAG_LOGI(AAFwkTag::FA, "promise");
588     if (asyncCallbackInfo == nullptr) {
589         TAG_LOGE(AAFwkTag::FA, "null param");
590         return nullptr;
591     }
592     napi_value resourceName = nullptr;
593     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
594     napi_deferred deferred;
595     napi_value promise = nullptr;
596     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
597     asyncCallbackInfo->deferred = deferred;
598 
599     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName,
600         [](napi_env env, void *data) {
601             TAG_LOGI(AAFwkTag::FA, "worker pool thread execute");
602             AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
603             if (asyncCallbackInfo->ability != nullptr) {
604                 asyncCallbackInfo->ability->SetResult(
605                     asyncCallbackInfo->param.requestCode, asyncCallbackInfo->param.want);
606                 asyncCallbackInfo->ability->TerminateAbility();
607             } else {
608                 TAG_LOGE(AAFwkTag::FA, "ability == nullptr");
609             }
610             TAG_LOGI(AAFwkTag::FA, "execute end");
611         },
612         [](napi_env env, napi_status status, void *data) {
613             TAG_LOGI(AAFwkTag::FA, "complete called");
614             AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
615             napi_value result = nullptr;
616             napi_get_null(env, &result);
617             napi_resolve_deferred(env, asyncCallbackInfo->deferred, result);
618             napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
619             delete asyncCallbackInfo;
620             TAG_LOGI(AAFwkTag::FA, "complete end");
621         },
622         static_cast<void *>(asyncCallbackInfo),
623         &asyncCallbackInfo->asyncWork));
624     NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
625     TAG_LOGI(AAFwkTag::FA, "end");
626     return promise;
627 }
628 
629 EXTERN_C_START
CreateUVQueueWork(uv_loop_t * loop,uv_work_t * work)630 int CreateUVQueueWork(uv_loop_t *loop, uv_work_t *work)
631 {
632     int rev = uv_queue_work(
633         loop,
634         work,
635         [](uv_work_t *work) {},
636         [](uv_work_t *work, int status) {
637             // JS Thread
638             if (work == nullptr) {
639                 TAG_LOGE(AAFwkTag::FA, "null work");
640                 return;
641             }
642             auto onAbilityCB = static_cast<OnAbilityCallback *>(work->data);
643             if (onAbilityCB == nullptr) {
644                 TAG_LOGE(AAFwkTag::FA, "null onAbilityCB");
645                 delete work;
646                 work = nullptr;
647                 return;
648             }
649 
650             if (onAbilityCB->cb.errCode != ERR_OK) {
651                 int32_t errCode = GetStartAbilityErrorCode(onAbilityCB->cb.errCode);
652                 onAbilityCB->cb.napiAsyncTask->Reject(onAbilityCB->cb.env,
653                     CreateJsError(onAbilityCB->cb.env, errCode, "StartAbilityForResult Error"));
654                 delete onAbilityCB->cb.napiAsyncTask;
655                 onAbilityCB->cb.napiAsyncTask = nullptr;
656                 delete onAbilityCB;
657                 onAbilityCB = nullptr;
658                 delete work;
659                 work = nullptr;
660                 return;
661             }
662 
663             napi_value objValue = nullptr;
664             napi_create_object(onAbilityCB->cb.env, &objValue);
665 
666             napi_set_named_property(onAbilityCB->cb.env,
667                 objValue, "resultCode", CreateJsValue(onAbilityCB->cb.env, onAbilityCB->resultCode));
668             napi_set_named_property(onAbilityCB->cb.env,
669                 objValue, "want", CreateJsWant(onAbilityCB->cb.env, onAbilityCB->resultData));
670 
671             onAbilityCB->cb.napiAsyncTask->Resolve(onAbilityCB->cb.env, objValue);
672             delete onAbilityCB->cb.napiAsyncTask;
673             onAbilityCB->cb.napiAsyncTask = nullptr;
674             delete onAbilityCB;
675             onAbilityCB = nullptr;
676             delete work;
677             work = nullptr;
678             TAG_LOGI(AAFwkTag::FA, "uv_queue_work end");
679         });
680     return rev;
681 }
682 
CallOnAbilityResult(int requestCode,int resultCode,const Want & resultData,CallbackInfo callbackInfo)683 void CallOnAbilityResult(int requestCode, int resultCode, const Want &resultData, CallbackInfo callbackInfo)
684 {
685     TAG_LOGI(AAFwkTag::FA, "called");
686     if (callbackInfo.env == nullptr) {
687         TAG_LOGE(AAFwkTag::FA, "null cb.env");
688         return;
689     }
690 
691     if (callbackInfo.napiAsyncTask == nullptr) {
692         TAG_LOGE(AAFwkTag::FA, "null cb.asyncTask");
693         return;
694     }
695 
696     uv_loop_t *loop = nullptr;
697     napi_get_uv_event_loop(callbackInfo.env, &loop);
698     if (loop == nullptr) {
699         TAG_LOGE(AAFwkTag::FA, "null loop");
700         return;
701     }
702 
703     auto work = new uv_work_t;
704     auto onAbilityCB = new (std::nothrow) OnAbilityCallback;
705     if (onAbilityCB == nullptr) {
706         TAG_LOGE(AAFwkTag::FA, "Failed to allocate OnAbilityCallback");
707         delete work;
708         return;
709     }
710 
711     onAbilityCB->requestCode = requestCode;
712     onAbilityCB->resultCode = resultCode;
713     onAbilityCB->resultData = resultData;
714     onAbilityCB->cb = callbackInfo;
715 
716     if (work == nullptr) {
717         TAG_LOGE(AAFwkTag::FA, "null work");
718         return;
719     }
720     work->data = static_cast<void *>(onAbilityCB);
721 
722     int rev = CreateUVQueueWork(loop, work);
723     if (rev != 0) {
724         if (onAbilityCB != nullptr) {
725             delete onAbilityCB;
726             onAbilityCB = nullptr;
727         }
728         if (work != nullptr) {
729             delete work;
730             work = nullptr;
731         }
732     }
733     TAG_LOGI(AAFwkTag::FA, "end");
734 }
735 EXTERN_C_END
736 
InnerUnwrapWant(napi_env env,napi_value args,Want & want)737 bool InnerUnwrapWant(napi_env env, napi_value args, Want &want)
738 {
739     TAG_LOGI(AAFwkTag::FA, "called");
740     napi_valuetype valueType = napi_undefined;
741     NAPI_CALL_BASE(env, napi_typeof(env, args, &valueType), false);
742     if (valueType != napi_object) {
743         TAG_LOGE(AAFwkTag::FA, "wrong argument type");
744         return false;
745     }
746 
747     napi_value jsWant = GetPropertyValueByPropertyName(env, args, "want", napi_object);
748     if (jsWant == nullptr) {
749         TAG_LOGE(AAFwkTag::FA, "null jsWant");
750         return false;
751     }
752 
753     return UnwrapWant(env, jsWant, want);
754 }
755 
756 /**
757  * @brief Parse the parameters.
758  *
759  * @param param Indicates the parameters saved the parse result.
760  * @param env The environment that the Node-API call is invoked under.
761  * @param args Indicates the arguments passed into the callback.
762  *
763  * @return The return value from NAPI C++ to JS for the module.
764  */
UnwrapForResultParam(CallAbilityParam & param,napi_env env,napi_value args)765 napi_value UnwrapForResultParam(CallAbilityParam &param, napi_env env, napi_value args)
766 {
767     TAG_LOGI(AAFwkTag::FA, "called");
768     // dummy requestCode for NativeC++ interface and onabilityresult callback
769     param.requestCode = dummyRequestCode_;
770     param.forResultOption = true;
771     dummyRequestCode_ = (dummyRequestCode_ < INT32_MAX) ? (dummyRequestCode_ + 1) : 0;
772     TAG_LOGI(AAFwkTag::FA, "reqCode=%{public}d forResultOption=%{public}d",
773         param.requestCode,
774         param.forResultOption);
775 
776     // unwrap the param : want object
777     if (!InnerUnwrapWant(env, args, param.want)) {
778         TAG_LOGE(AAFwkTag::FA, "Failed to InnerUnwrapWant");
779         return nullptr;
780     }
781 
782     // unwrap the param : abilityStartSetting (optional)
783     napi_value jsSettingObj = GetPropertyValueByPropertyName(env, args, "abilityStartSettings", napi_object);
784     if (jsSettingObj == nullptr) {
785         jsSettingObj = GetPropertyValueByPropertyName(env, args, "abilityStartSetting", napi_object);
786     }
787     if (jsSettingObj != nullptr) {
788         param.setting = AbilityStartSetting::GetEmptySetting();
789         if (!UnwrapAbilityStartSetting(env, jsSettingObj, *(param.setting))) {
790             TAG_LOGE(AAFwkTag::FA, "unwrap abilityStartSetting failed");
791         }
792         TAG_LOGI(AAFwkTag::FA, "abilityStartSetting");
793     }
794 
795     napi_value result;
796     NAPI_CALL(env, napi_create_int32(env, 1, &result));
797     TAG_LOGI(AAFwkTag::FA, "end");
798     return result;
799 }
800 
801 /**
802  * @brief Parse the abilityResult parameters.
803  *
804  * @param param Indicates the want parameters saved the parse result.
805  * @param env The environment that the Node-API call is invoked under.
806  * @param args Indicates the arguments passed into the callback.
807  *
808  * @return The return value from NAPI C++ to JS for the module.
809  */
UnwrapAbilityResult(CallAbilityParam & param,napi_env env,napi_value args)810 napi_value UnwrapAbilityResult(CallAbilityParam &param, napi_env env, napi_value args)
811 {
812     TAG_LOGI(AAFwkTag::FA, "called");
813     // unwrap the param
814     napi_valuetype valueType = napi_undefined;
815     NAPI_CALL(env, napi_typeof(env, args, &valueType));
816     NAPI_ASSERT(env, valueType == napi_object, "param type mismatch!");
817     // get resultCode property
818     napi_value property = nullptr;
819     NAPI_CALL(env, napi_get_named_property(env, args, "resultCode", &property));
820     NAPI_CALL(env, napi_typeof(env, property, &valueType));
821     NAPI_ASSERT(env, valueType == napi_number, "property type mismatch!");
822     NAPI_CALL(env, napi_get_value_int32(env, property, &param.requestCode));
823     TAG_LOGI(AAFwkTag::FA, "requestCode=%{public}d", param.requestCode);
824 
825     // unwrap the param : want object
826     InnerUnwrapWant(env, args, param.want);
827 
828     napi_value result;
829     NAPI_CALL(env, napi_create_int32(env, 1, &result));
830     TAG_LOGI(AAFwkTag::FA, "end");
831     return result;
832 }
833 
834 /**
835  * @brief GetWantSyncWrap processing function.
836  *
837  * @param env The environment that the Node-API call is invoked under.
838  * @param CallingBundleCB Process data asynchronously.
839  *
840  * @return Return JS data successfully, otherwise return nullptr.
841  */
GetWantSyncWrap(napi_env env,napi_callback_info info,AsyncCallbackInfo * asyncCallbackInfo)842 napi_value GetWantSyncWrap(napi_env env, napi_callback_info info, AsyncCallbackInfo *asyncCallbackInfo)
843 {
844     TAG_LOGI(AAFwkTag::FA, "called");
845     if (asyncCallbackInfo == nullptr) {
846         TAG_LOGE(AAFwkTag::FA, "null asyncCallbackInfo");
847         return nullptr;
848     }
849 
850     asyncCallbackInfo->errCode = NAPI_ERR_NO_ERROR;
851     if (asyncCallbackInfo->ability == nullptr) {
852         TAG_LOGE(AAFwkTag::FA, "null ability");
853         asyncCallbackInfo->errCode = NAPI_ERR_ACE_ABILITY;
854         return nullptr;
855     }
856 
857     std::shared_ptr<AAFwk::Want> ptrWant = asyncCallbackInfo->ability->GetWant();
858     if (ptrWant != nullptr) {
859         asyncCallbackInfo->param.want = *ptrWant;
860     } else {
861         asyncCallbackInfo->errCode = NAPI_ERR_ABILITY_CALL_INVALID;
862     }
863 
864     napi_value result = nullptr;
865     if (asyncCallbackInfo->errCode == NAPI_ERR_NO_ERROR) {
866         result = WrapWant(env, asyncCallbackInfo->param.want);
867     } else {
868         result = WrapVoidToJS(env);
869     }
870     TAG_LOGI(AAFwkTag::FA, "end");
871     return result;
872 }
873 
874 /**
875  * @brief Get want(Sync).
876  *
877  * @param env The environment that the Node-API call is invoked under.
878  * @param info The callback info passed into the callback function.
879  *
880  * @return The return value from NAPI C++ to JS for the module.
881  */
NAPI_GetWantSync(napi_env env,napi_callback_info info)882 napi_value NAPI_GetWantSync(napi_env env, napi_callback_info info)
883 {
884     TAG_LOGI(AAFwkTag::FA, "called");
885     AsyncCallbackInfo *asyncCallbackInfo = CreateAsyncCallbackInfo(env);
886     if (asyncCallbackInfo == nullptr) {
887         return WrapVoidToJS(env);
888     }
889 
890     asyncCallbackInfo->errCode = NAPI_ERR_NO_ERROR;
891     napi_value ret = GetWantSyncWrap(env, info, asyncCallbackInfo);
892 
893     delete asyncCallbackInfo;
894     asyncCallbackInfo = nullptr;
895 
896     if (ret == nullptr) {
897         ret = WrapVoidToJS(env);
898         TAG_LOGE(AAFwkTag::FA, "null ret");
899     } else {
900         TAG_LOGI(AAFwkTag::FA, "exit");
901     }
902     return ret;
903 }
904 
905 /**
906  * @brief Obtains the type of this application.
907  *
908  * @param env The environment that the Node-API call is invoked under.
909  * @param info The callback info passed into the callback function.
910  *
911  * @return The return value from NAPI C++ to JS for the module.
912  */
NAPI_GetAppType(napi_env env,napi_callback_info info)913 napi_value NAPI_GetAppType(napi_env env, napi_callback_info info)
914 {
915     TAG_LOGI(AAFwkTag::FA, "called");
916     return NAPI_GetAppTypeCommon(env, info, AbilityType::PAGE);
917 }
918 
919 /**
920  * @brief Obtains the class name in this ability name, without the prefixed bundle name.
921  *
922  * @param env The environment that the Node-API call is invoked under.
923  * @param info The callback info passed into the callback function.
924  *
925  * @return The return value from NAPI C++ to JS for the module.
926  */
NAPI_GetAbilityName(napi_env env,napi_callback_info info)927 napi_value NAPI_GetAbilityName(napi_env env, napi_callback_info info)
928 {
929     TAG_LOGI(AAFwkTag::FA, "called");
930     return NAPI_GetAbilityNameCommon(env, info, AbilityType::PAGE);
931 }
932 
933 /**
934  * @brief Obtains information about the current ability.
935  *
936  * @param env The environment that the Node-API call is invoked under.
937  * @param info The callback info passed into the callback function.
938  *
939  * @return The return value from NAPI C++ to JS for the module.
940  */
NAPI_GetAbilityInfo(napi_env env,napi_callback_info info)941 napi_value NAPI_GetAbilityInfo(napi_env env, napi_callback_info info)
942 {
943     TAG_LOGI(AAFwkTag::FA, "called");
944     return NAPI_GetAbilityInfoCommon(env, info, AbilityType::PAGE);
945 }
946 
947 /**
948  * @brief Obtains the HapModuleInfo object of the application.
949  *
950  * @param env The environment that the Node-API call is invoked under.
951  * @param info The callback info passed into the callback function.
952  *
953  * @return The return value from NAPI C++ to JS for the module.
954  */
NAPI_GetHapModuleInfo(napi_env env,napi_callback_info info)955 napi_value NAPI_GetHapModuleInfo(napi_env env, napi_callback_info info)
956 {
957     TAG_LOGI(AAFwkTag::FA, "called");
958     return NAPI_GetHapModuleInfoCommon(env, info, AbilityType::PAGE);
959 }
960 
961 /**
962  * @brief FeatureAbility NAPI method : getDataAbilityHelper.
963  *
964  * @param env The environment that the Node-API call is invoked under.
965  * @param info The callback info passed into the callback function.
966  *
967  * @return The return value from NAPI C++ to JS for the module.
968  */
NAPI_GetDataAbilityHelper(napi_env env,napi_callback_info info)969 napi_value NAPI_GetDataAbilityHelper(napi_env env, napi_callback_info info)
970 {
971     TAG_LOGI(AAFwkTag::FA, "called");
972     DataAbilityHelperCB *dataAbilityHelperCB = new (std::nothrow) DataAbilityHelperCB;
973     if (dataAbilityHelperCB == nullptr) {
974         TAG_LOGE(AAFwkTag::FA, "null dataAbilityHelperCB");
975         return WrapVoidToJS(env);
976     }
977     dataAbilityHelperCB->cbBase.cbInfo.env = env;
978     napi_value ret = GetDataAbilityHelperWrap(env, info, dataAbilityHelperCB);
979     if (ret == nullptr) {
980         TAG_LOGE(AAFwkTag::FA, "null ret");
981         if (dataAbilityHelperCB != nullptr) {
982             delete dataAbilityHelperCB;
983             dataAbilityHelperCB = nullptr;
984         }
985         ret = WrapVoidToJS(env);
986     }
987     TAG_LOGI(AAFwkTag::FA, "end");
988     return ret;
989 }
990 
991 /**
992  * @brief getDataAbilityHelper processing function.
993  *
994  * @param env The environment that the Node-API call is invoked under.
995  * @param dataAbilityHelperCB Process data asynchronously.
996  *
997  * @return Return JS data successfully, otherwise return nullptr.
998  */
GetDataAbilityHelperWrap(napi_env env,napi_callback_info info,DataAbilityHelperCB * dataAbilityHelperCB)999 napi_value GetDataAbilityHelperWrap(napi_env env, napi_callback_info info, DataAbilityHelperCB *dataAbilityHelperCB)
1000 {
1001     TAG_LOGI(AAFwkTag::FA, "called");
1002     if (dataAbilityHelperCB == nullptr) {
1003         TAG_LOGE(AAFwkTag::FA, "null dataAbilityHelperCB");
1004         return nullptr;
1005     }
1006 
1007     size_t argcAsync = 2;
1008     const size_t argcPromise = 1;
1009     const size_t argCountWithAsync = argcPromise + ARGS_ASYNC_COUNT;
1010     napi_value args[ARGS_MAX_COUNT] = {nullptr};
1011     napi_value ret = nullptr;
1012 
1013     NAPI_CALL(env, napi_get_cb_info(env, info, &argcAsync, args, nullptr, nullptr));
1014     if (argcAsync > argCountWithAsync || argcAsync > ARGS_MAX_COUNT) {
1015         TAG_LOGE(AAFwkTag::FA, "invalid argc");
1016         return nullptr;
1017     }
1018 
1019     napi_valuetype valuetype = napi_undefined;
1020     NAPI_CALL(env, napi_typeof(env, args[PARAM0], &valuetype));
1021     if (valuetype == napi_string) {
1022         NAPI_CALL(env, napi_create_reference(env, args[PARAM0], 1, &dataAbilityHelperCB->uri));
1023     }
1024 
1025     if (argcAsync > argcPromise) {
1026         ret = GetDataAbilityHelperAsync(env, args, 1, dataAbilityHelperCB);
1027     } else {
1028         ret = GetDataAbilityHelperPromise(env, dataAbilityHelperCB);
1029     }
1030     TAG_LOGI(AAFwkTag::FA, "end");
1031     return ret;
1032 }
1033 
GetDataAbilityHelperAsync(napi_env env,napi_value * args,const size_t argCallback,DataAbilityHelperCB * dataAbilityHelperCB)1034 napi_value GetDataAbilityHelperAsync(
1035     napi_env env, napi_value *args, const size_t argCallback, DataAbilityHelperCB *dataAbilityHelperCB)
1036 {
1037     TAG_LOGI(AAFwkTag::FA, "asyncCallback");
1038     if (args == nullptr || dataAbilityHelperCB == nullptr) {
1039         TAG_LOGE(AAFwkTag::FA, "null param");
1040         return nullptr;
1041     }
1042     napi_value resourceName = nullptr;
1043     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
1044 
1045     napi_valuetype valuetype = napi_undefined;
1046     NAPI_CALL(env, napi_typeof(env, args[argCallback], &valuetype));
1047     if (valuetype == napi_function) {
1048         NAPI_CALL(env, napi_create_reference(env, args[argCallback], 1, &dataAbilityHelperCB->cbBase.cbInfo.callback));
1049     }
1050 
1051     NAPI_CALL(env,
1052         napi_create_async_work(env, nullptr, resourceName,
1053             [](napi_env env, void *data) {
1054                 TAG_LOGI(AAFwkTag::FA, "worker pool thread execute");
1055             },
1056             GetDataAbilityHelperAsyncCompleteCB,
1057             static_cast<void *>(dataAbilityHelperCB),
1058             &dataAbilityHelperCB->cbBase.asyncWork));
1059     NAPI_CALL(env, napi_queue_async_work_with_qos(env, dataAbilityHelperCB->cbBase.asyncWork,
1060         napi_qos_user_initiated));
1061     napi_value result = nullptr;
1062     NAPI_CALL(env, napi_get_null(env, &result));
1063     TAG_LOGI(AAFwkTag::FA, "end");
1064     return result;
1065 }
1066 
GetDataAbilityHelperPromise(napi_env env,DataAbilityHelperCB * dataAbilityHelperCB)1067 napi_value GetDataAbilityHelperPromise(napi_env env, DataAbilityHelperCB *dataAbilityHelperCB)
1068 {
1069     TAG_LOGI(AAFwkTag::FA, "promise");
1070     if (dataAbilityHelperCB == nullptr) {
1071         TAG_LOGE(AAFwkTag::FA, "null param");
1072         return nullptr;
1073     }
1074     napi_value resourceName;
1075     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
1076     napi_deferred deferred;
1077     napi_value promise = nullptr;
1078     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
1079     dataAbilityHelperCB->cbBase.deferred = deferred;
1080 
1081     NAPI_CALL(env,
1082         napi_create_async_work(env, nullptr, resourceName,
1083             [](napi_env env, void *data) {
1084                 TAG_LOGI(AAFwkTag::FA, "worker pool thread execute");
1085             },
1086             GetDataAbilityHelperPromiseCompleteCB,
1087             static_cast<void *>(dataAbilityHelperCB),
1088             &dataAbilityHelperCB->cbBase.asyncWork));
1089     NAPI_CALL(env, napi_queue_async_work_with_qos(env, dataAbilityHelperCB->cbBase.asyncWork,
1090         napi_qos_user_initiated));
1091     TAG_LOGI(AAFwkTag::FA, "end");
1092     return promise;
1093 }
1094 
GetDataAbilityHelperAsyncCompleteCB(napi_env env,napi_status status,void * data)1095 void GetDataAbilityHelperAsyncCompleteCB(napi_env env, napi_status status, void *data)
1096 {
1097     TAG_LOGI(AAFwkTag::FA, "called");
1098     DataAbilityHelperCB *dataAbilityHelperCB = static_cast<DataAbilityHelperCB *>(data);
1099     std::unique_ptr<DataAbilityHelperCB> callbackPtr {dataAbilityHelperCB};
1100     napi_value uri = nullptr;
1101     napi_value callback = nullptr;
1102     napi_value undefined = nullptr;
1103     napi_value result[ARGS_TWO] = {nullptr};
1104     napi_value callResult = nullptr;
1105     napi_get_undefined(env, &undefined);
1106     napi_get_reference_value(env, dataAbilityHelperCB->uri, &uri);
1107     napi_get_reference_value(env, dataAbilityHelperCB->cbBase.cbInfo.callback, &callback);
1108     napi_new_instance(env, GetGlobalDataAbilityHelper(env), 1, &uri, &dataAbilityHelperCB->result);
1109     if (IsTypeForNapiValue(env, dataAbilityHelperCB->result, napi_object)) {
1110         result[PARAM1] = dataAbilityHelperCB->result;
1111     } else {
1112         TAG_LOGI(AAFwkTag::FA, "helper is nullptr");
1113         result[PARAM1] = WrapVoidToJS(env);
1114     }
1115     result[PARAM0] = GetCallbackErrorValue(env, NO_ERROR);
1116     napi_call_function(env, undefined, callback, ARGS_TWO, &result[PARAM0], &callResult);
1117     if (dataAbilityHelperCB->cbBase.cbInfo.callback != nullptr) {
1118         napi_delete_reference(env, dataAbilityHelperCB->cbBase.cbInfo.callback);
1119     }
1120     if (dataAbilityHelperCB->uri != nullptr) {
1121         napi_delete_reference(env, dataAbilityHelperCB->uri);
1122     }
1123     napi_delete_async_work(env, dataAbilityHelperCB->cbBase.asyncWork);
1124     TAG_LOGI(AAFwkTag::FA, "end");
1125 }
1126 
GetDataAbilityHelperPromiseCompleteCB(napi_env env,napi_status status,void * data)1127 void GetDataAbilityHelperPromiseCompleteCB(napi_env env, napi_status status, void *data)
1128 {
1129     TAG_LOGI(AAFwkTag::FA, "called");
1130     DataAbilityHelperCB *dataAbilityHelperCB = static_cast<DataAbilityHelperCB *>(data);
1131     napi_value uri = nullptr;
1132     napi_value result = nullptr;
1133     napi_get_reference_value(env, dataAbilityHelperCB->uri, &uri);
1134     napi_new_instance(env, GetGlobalDataAbilityHelper(env), 1, &uri, &dataAbilityHelperCB->result);
1135     if (IsTypeForNapiValue(env, dataAbilityHelperCB->result, napi_object)) {
1136         result = dataAbilityHelperCB->result;
1137         napi_resolve_deferred(env, dataAbilityHelperCB->cbBase.deferred, result);
1138     } else {
1139         result = GetCallbackErrorValue(env, dataAbilityHelperCB->cbBase.errCode);
1140         napi_reject_deferred(env, dataAbilityHelperCB->cbBase.deferred, result);
1141         TAG_LOGI(AAFwkTag::FA, "null helper");
1142     }
1143 
1144     if (dataAbilityHelperCB->uri != nullptr) {
1145         napi_delete_reference(env, dataAbilityHelperCB->uri);
1146     }
1147     napi_delete_async_work(env, dataAbilityHelperCB->cbBase.asyncWork);
1148     TAG_LOGI(AAFwkTag::FA, "end");
1149 }
1150 
1151 /**
1152  * @brief FeatureAbility NAPI method : acquireDataAbilityHelper.
1153  *
1154  * @param env The environment that the Node-API call is invoked under.
1155  * @param info The callback info passed into the callback function.
1156  *
1157  * @return The return value from NAPI C++ to JS for the module.
1158  */
NAPI_AcquireDataAbilityHelper(napi_env env,napi_callback_info info)1159 napi_value NAPI_AcquireDataAbilityHelper(napi_env env, napi_callback_info info)
1160 {
1161     return NAPI_AcquireDataAbilityHelperCommon(env, info, AbilityType::PAGE);
1162 }
1163 
1164 /**
1165  * @brief FeatureAbility NAPI method : continueAbility.
1166  *
1167  * @param env The environment that the Node-API call is invoked under.
1168  * @param info The callback info passed into the callback function.
1169  *
1170  * @return The return value from NAPI C++ to JS for the module.
1171  */
NAPI_FAContinueAbility(napi_env env,napi_callback_info info)1172 napi_value NAPI_FAContinueAbility(napi_env env, napi_callback_info info)
1173 {
1174     TAG_LOGI(AAFwkTag::FA, "called");
1175     AsyncCallbackInfo *asyncCallbackInfo = CreateAsyncCallbackInfo(env);
1176     if (asyncCallbackInfo == nullptr) {
1177         TAG_LOGE(AAFwkTag::FA, "null asyncCallbackInfo");
1178         return WrapVoidToJS(env);
1179     }
1180 
1181     napi_value ret = ContinueAbilityWrap(env, info, asyncCallbackInfo);
1182     if (ret == nullptr) {
1183         if (asyncCallbackInfo != nullptr) {
1184             delete asyncCallbackInfo;
1185             asyncCallbackInfo = nullptr;
1186         }
1187         ret = WrapVoidToJS(env);
1188     }
1189     TAG_LOGI(AAFwkTag::FA, "end");
1190     return ret;
1191 }
1192 
1193 /**
1194  * @brief ContinueAbilityWrap processing function.
1195  *
1196  * @param env The environment that the Node-API call is invoked under.
1197  * @param asyncCallbackInfo Process data asynchronously.
1198  *
1199  * @return Return JS data successfully, otherwise return nullptr.
1200  */
ContinueAbilityWrap(napi_env env,napi_callback_info info,AsyncCallbackInfo * asyncCallbackInfo)1201 napi_value ContinueAbilityWrap(napi_env env, napi_callback_info info, AsyncCallbackInfo *asyncCallbackInfo)
1202 {
1203     TAG_LOGI(AAFwkTag::FA, "called");
1204     size_t argc = 2;
1205     napi_value args[ARGS_MAX_COUNT] = {nullptr};
1206     napi_value ret = nullptr;
1207     napi_valuetype valueType = napi_undefined;
1208 
1209     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
1210     NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
1211     if (valueType != napi_object && valueType != napi_function) {
1212         TAG_LOGE(AAFwkTag::FA, "wrong argument type. Object or function expected");
1213         return nullptr;
1214     }
1215     if (argc == 0) {
1216         ret = ContinueAbilityPromise(env, args, asyncCallbackInfo, argc);
1217     } else if (PARA_SIZE_IS_ONE == argc) {
1218         if (valueType == napi_function) {
1219             ret = ContinueAbilityAsync(env, args, asyncCallbackInfo, argc);
1220         } else {
1221             ret = ContinueAbilityPromise(env, args, asyncCallbackInfo, argc);
1222         }
1223     } else if (PARA_SIZE_IS_TWO == argc) {
1224         napi_valuetype value = napi_undefined;
1225         NAPI_CALL(env, napi_typeof(env, args[1], &value));
1226         if (value != napi_function) {
1227             TAG_LOGE(AAFwkTag::FA, "function expected");
1228             return nullptr;
1229         }
1230         ret = ContinueAbilityAsync(env, args, asyncCallbackInfo, argc);
1231     } else {
1232         TAG_LOGE(AAFwkTag::FA, "invalid argc");
1233     }
1234     TAG_LOGI(AAFwkTag::FA, "end");
1235     return ret;
1236 }
1237 
CreateContinueAsyncWork(napi_env env,napi_value & resourceName,AsyncCallbackInfo * asyncCallbackInfo)1238 void CreateContinueAsyncWork(napi_env env, napi_value &resourceName, AsyncCallbackInfo *asyncCallbackInfo)
1239 {
1240     napi_create_async_work(env, nullptr, resourceName,
1241         [](napi_env env, void *data) {
1242             TAG_LOGI(AAFwkTag::FA, "worker pool thread execute");
1243             AsyncCallbackInfo *asyncCallbackInfo = (AsyncCallbackInfo *)data;
1244             if (asyncCallbackInfo->ability != nullptr) {
1245                 asyncCallbackInfo->ability->ContinueAbility(asyncCallbackInfo->optionInfo.deviceId);
1246             } else {
1247                 TAG_LOGE(AAFwkTag::FA, "null asyncCallbackInfo");
1248             }
1249             TAG_LOGI(AAFwkTag::FA, "worker pool thread execute exit");
1250         },
1251         [](napi_env env, napi_status status, void *data) {
1252             TAG_LOGI(AAFwkTag::FA, "main event thread end");
1253             AsyncCallbackInfo *asyncCallbackInfo = (AsyncCallbackInfo *)data;
1254             napi_value callback = nullptr;
1255             napi_value undefined = nullptr;
1256             napi_value result[ARGS_TWO] = {nullptr};
1257             napi_value callResult = nullptr;
1258             napi_get_undefined(env, &undefined);
1259             result[PARAM0] = GetCallbackErrorValue(env, NO_ERROR);
1260             napi_get_null(env, &result[PARAM1]);
1261             napi_get_reference_value(env, asyncCallbackInfo->cbInfo.callback, &callback);
1262             napi_call_function(env, undefined, callback, ARGS_TWO, &result[PARAM0], &callResult);
1263 
1264             if (asyncCallbackInfo->cbInfo.callback != nullptr) {
1265                 napi_delete_reference(env, asyncCallbackInfo->cbInfo.callback);
1266             }
1267             napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
1268             delete asyncCallbackInfo;
1269             TAG_LOGI(AAFwkTag::FA, "end");
1270         },
1271         static_cast<void *>(asyncCallbackInfo),
1272         &asyncCallbackInfo->asyncWork);
1273 }
1274 
ContinueAbilityAsync(napi_env env,napi_value * args,AsyncCallbackInfo * asyncCallbackInfo,size_t argc)1275 napi_value ContinueAbilityAsync(napi_env env, napi_value *args, AsyncCallbackInfo *asyncCallbackInfo, size_t argc)
1276 {
1277     TAG_LOGI(AAFwkTag::FA, "asyncCallback");
1278     if (args == nullptr || asyncCallbackInfo == nullptr) {
1279         TAG_LOGE(AAFwkTag::FA, "null param");
1280         return nullptr;
1281     }
1282     napi_value resourceName = nullptr;
1283     napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName);
1284 
1285     if (PARA_SIZE_IS_TWO == argc) {
1286         // args[0] : ContinueAbilityOptions
1287         napi_valuetype valueTypeOptions = napi_undefined;
1288         NAPI_CALL(env, napi_typeof(env, args[0], &valueTypeOptions));
1289         if (valueTypeOptions != napi_object) {
1290             TAG_LOGE(AAFwkTag::FA, "object expected");
1291             return nullptr;
1292         }
1293         if (GetContinueAbilityOptionsInfoCommon(env, args[0], asyncCallbackInfo->optionInfo) == nullptr) {
1294             TAG_LOGE(AAFwkTag::FA, "getContinueAbilityOptionsInfoCommon fail");
1295             return nullptr;
1296         }
1297 
1298         // args[1] : callback
1299         napi_valuetype valueTypeCallBack = napi_undefined;
1300         napi_typeof(env, args[1], &valueTypeCallBack);
1301         if (valueTypeCallBack == napi_function) {
1302             napi_create_reference(env, args[1], 1, &asyncCallbackInfo->cbInfo.callback);
1303         }
1304     } else {
1305         // args[0] : callback
1306         napi_valuetype valueTypeCallBack = napi_undefined;
1307         napi_typeof(env, args[1], &valueTypeCallBack);
1308         if (valueTypeCallBack == napi_function) {
1309             napi_create_reference(env, args[0], 1, &asyncCallbackInfo->cbInfo.callback);
1310         }
1311     }
1312 
1313     CreateContinueAsyncWork(env, resourceName, asyncCallbackInfo);
1314 
1315     napi_queue_async_work(env, asyncCallbackInfo->asyncWork);
1316     napi_value result = nullptr;
1317     napi_get_null(env, &result);
1318     TAG_LOGI(AAFwkTag::FA, "end");
1319     return result;
1320 }
1321 
ContinueAbilityPromise(napi_env env,napi_value * args,AsyncCallbackInfo * asyncCallbackInfo,size_t argc)1322 napi_value ContinueAbilityPromise(napi_env env, napi_value *args, AsyncCallbackInfo *asyncCallbackInfo, size_t argc)
1323 {
1324     TAG_LOGI(AAFwkTag::FA, "called");
1325     if (asyncCallbackInfo == nullptr) {
1326         TAG_LOGE(AAFwkTag::FA, "null param");
1327         return nullptr;
1328     }
1329 
1330     if (argc == PARA_SIZE_IS_ONE) {
1331         // args[0] : ContinueAbilityOptions
1332         napi_valuetype valueTypeOptions = napi_undefined;
1333         NAPI_CALL(env, napi_typeof(env, args[0], &valueTypeOptions));
1334         if (valueTypeOptions != napi_object) {
1335             TAG_LOGE(AAFwkTag::FA, "object expected");
1336             return nullptr;
1337         }
1338         if (GetContinueAbilityOptionsInfoCommon(env, args[0], asyncCallbackInfo->optionInfo) == nullptr) {
1339             return nullptr;
1340         }
1341     }
1342 
1343     napi_value resourceName = nullptr;
1344     napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName);
1345     napi_deferred deferred;
1346     napi_value promise = nullptr;
1347     napi_create_promise(env, &deferred, &promise);
1348 
1349     asyncCallbackInfo->deferred = deferred;
1350 
1351     napi_create_async_work(env, nullptr, resourceName,
1352         [](napi_env env, void *data) {
1353             TAG_LOGI(AAFwkTag::FA, "execute called");
1354             AsyncCallbackInfo *asyncCallbackInfo = (AsyncCallbackInfo *)data;
1355             if (asyncCallbackInfo->ability != nullptr) {
1356                 asyncCallbackInfo->ability->ContinueAbility(asyncCallbackInfo->optionInfo.deviceId);
1357             } else {
1358                 TAG_LOGE(AAFwkTag::FA, "null ability");
1359             }
1360             TAG_LOGI(AAFwkTag::FA, "execute end");
1361         },
1362         [](napi_env env, napi_status status, void *data) {
1363             TAG_LOGI(AAFwkTag::FA, "complete called");
1364             AsyncCallbackInfo *asyncCallbackInfo = (AsyncCallbackInfo *)data;
1365             napi_value result = nullptr;
1366             napi_get_null(env, &result);
1367             napi_resolve_deferred(env, asyncCallbackInfo->deferred, result);
1368             napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
1369             delete asyncCallbackInfo;
1370             TAG_LOGI(AAFwkTag::FA, "complete end");
1371         },
1372         static_cast<void *>(asyncCallbackInfo), &asyncCallbackInfo->asyncWork);
1373     napi_queue_async_work(env, asyncCallbackInfo->asyncWork);
1374     TAG_LOGI(AAFwkTag::FA, "end");
1375     return promise;
1376 }
1377 }  // namespace AppExecFwk
1378 }  // namespace OHOS
1379