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