1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "distributed_bundle_mgr.h"
16
17 #include <string>
18
19 #include "app_log_wrapper.h"
20 #include "appexecfwk_errors.h"
21 #include "bundle_constants.h"
22 #include "distributed_bms_interface.h"
23 #include "distributed_bms_proxy.h"
24 #include "if_system_ability_manager.h"
25 #include "ipc_skeleton.h"
26 #include "iservice_registry.h"
27 #include "napi/native_api.h"
28 #include "napi/native_node_api.h"
29 #include "securec.h"
30 #include "system_ability_definition.h"
31
32 namespace OHOS {
33 namespace AppExecFwk {
34 using namespace OHOS;
35 using namespace OHOS::AppExecFwk;
36
37 namespace {
38 constexpr size_t ARGS_SIZE_ONE = 1;
39 constexpr size_t ARGS_SIZE_THREE = 3;
40 constexpr int32_t PARAM0 = 0;
41 constexpr int32_t PARAM1 = 1;
42 constexpr int32_t PARAM2 = 2;
43 constexpr int32_t NAPI_RETURN_ZERO = 0;
44 constexpr int32_t NAPI_RETURN_ONE = 1;
45 constexpr int32_t GET_REMOTE_ABILITY_INFO_MAX_SIZE = 10;
46 enum GetRemoteAbilityInfoErrorCode : int32_t {
47 SUCCESS = 0,
48 ERR_INNER_ERROR,
49 ERR_INVALID_PARAM,
50 ERR_PARAMETERS_MORE_THAN_MAX,
51 ERR_RPC_ERROR,
52 };
53 }
54
AsyncWorkData(napi_env napiEnv)55 AsyncWorkData::AsyncWorkData(napi_env napiEnv) : env(napiEnv) {}
56
~AsyncWorkData()57 AsyncWorkData::~AsyncWorkData()
58 {
59 if (callbackRef) {
60 APP_LOGD("AsyncWorkData::~AsyncWorkData delete callbackRef");
61 napi_delete_reference(env, callbackRef);
62 callbackRef = nullptr;
63 }
64 if (asyncWork) {
65 APP_LOGD("AsyncWorkData::~AsyncWorkData delete asyncWork");
66 napi_delete_async_work(env, asyncWork);
67 asyncWork = nullptr;
68 }
69 }
70
GetDistributedBundleMgr()71 static OHOS::sptr<OHOS::AppExecFwk::IDistributedBms> GetDistributedBundleMgr()
72 {
73 APP_LOGI("GetDistributedBundleMgr");
74 auto samgr = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
75 // OHOS::sptr<OHOS::IRemoteObject> remoteObject;
76 auto remoteObject = samgr->GetSystemAbility(OHOS::DISTRIBUTED_BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
77 return OHOS::iface_cast<IDistributedBms>(remoteObject);
78 }
79
GetStringFromNAPI(napi_env env,napi_value value)80 static std::string GetStringFromNAPI(napi_env env, napi_value value)
81 {
82 std::string result;
83 size_t size = 0;
84
85 if (napi_get_value_string_utf8(env, value, nullptr, NAPI_RETURN_ZERO, &size) != napi_ok) {
86 APP_LOGE("can not get string size");
87 return "";
88 }
89 result.reserve(size + NAPI_RETURN_ONE);
90 result.resize(size);
91 if (napi_get_value_string_utf8(env, value, result.data(), (size + NAPI_RETURN_ONE), &size) != napi_ok) {
92 APP_LOGE("can not get string value");
93 return "";
94 }
95 return result;
96 }
97
ParseString(napi_env env,std::string & param,napi_value args)98 static napi_value ParseString(napi_env env, std::string ¶m, napi_value args)
99 {
100 napi_status status;
101 napi_valuetype valuetype;
102 NAPI_CALL(env, napi_typeof(env, args, &valuetype));
103 NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type. String expected.");
104 param = GetStringFromNAPI(env, args);
105 APP_LOGD("param=%{public}s.", param.c_str());
106 napi_value result;
107 status = napi_create_int32(env, NAPI_RETURN_ONE, &result);
108 NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!");
109 return result;
110 }
111
ConvertResultCode(int32_t code)112 static int32_t ConvertResultCode(int32_t code)
113 {
114 APP_LOGD("ConvertResultCode resultCode:%{public}d", code);
115 switch (code) {
116 case SUCCESS:
117 return SUCCESS;
118 case ERR_APPEXECFWK_FAILED_GET_REMOTE_PROXY:
119 return ERR_RPC_ERROR;
120 default:
121 break;
122 }
123 return ERR_INNER_ERROR;
124 }
125
ConvertElementName(napi_env env,napi_value objElementName,const ElementName & elementName)126 static void ConvertElementName(napi_env env, napi_value objElementName, const ElementName &elementName)
127 {
128 napi_value nDeviceId;
129 NAPI_CALL_RETURN_VOID(
130 env, napi_create_string_utf8(env, elementName.GetDeviceID().c_str(), NAPI_AUTO_LENGTH, &nDeviceId));
131 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objElementName, "deviceId", nDeviceId));
132
133 napi_value nBundleName;
134 NAPI_CALL_RETURN_VOID(
135 env, napi_create_string_utf8(env, elementName.GetBundleName().c_str(), NAPI_AUTO_LENGTH, &nBundleName));
136 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objElementName, "bundleName", nBundleName));
137
138 napi_value nModuleName;
139 NAPI_CALL_RETURN_VOID(
140 env, napi_create_string_utf8(env, elementName.GetModuleName().c_str(), NAPI_AUTO_LENGTH, &nModuleName));
141 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objElementName, "moduleName", nModuleName));
142
143 napi_value nAbilityName;
144 NAPI_CALL_RETURN_VOID(
145 env, napi_create_string_utf8(env, elementName.GetAbilityName().c_str(), NAPI_AUTO_LENGTH, &nAbilityName));
146 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objElementName, "abilityName", nAbilityName));
147 }
148
ConvertRemoteAbilityInfo(napi_env env,napi_value objRemoteAbilityInfo,const RemoteAbilityInfo & remoteAbilityInfo)149 static void ConvertRemoteAbilityInfo(
150 napi_env env, napi_value objRemoteAbilityInfo, const RemoteAbilityInfo &remoteAbilityInfo)
151 {
152 napi_value objElementName;
153 NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objElementName));
154 ConvertElementName(env, objElementName, remoteAbilityInfo.elementName);
155 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objRemoteAbilityInfo, "elementName", objElementName));
156
157 napi_value nLabel;
158 NAPI_CALL_RETURN_VOID(
159 env, napi_create_string_utf8(env, remoteAbilityInfo.label.c_str(), NAPI_AUTO_LENGTH, &nLabel));
160 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objRemoteAbilityInfo, "label", nLabel));
161
162 napi_value nIcon;
163 NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, remoteAbilityInfo.icon.c_str(), NAPI_AUTO_LENGTH, &nIcon));
164 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objRemoteAbilityInfo, "icon", nIcon));
165 }
166
ConvertRemoteAbilityInfos(napi_env env,napi_value objRemoteAbilityInfos,const std::vector<RemoteAbilityInfo> & remoteAbilityInfos)167 static void ConvertRemoteAbilityInfos(
168 napi_env env, napi_value objRemoteAbilityInfos, const std::vector<RemoteAbilityInfo> &remoteAbilityInfos)
169 {
170 if (remoteAbilityInfos.size() == 0) {
171 APP_LOGE("ConvertRemoteAbilityInfos remoteAbilityInfos is empty");
172 return;
173 }
174 size_t index = 0;
175 for (const auto &remoteAbilityInfo : remoteAbilityInfos) {
176 APP_LOGD("remoteAbilityInfo bundleName:%{public}s, abilityName:%{public}s, label:%{public}s",
177 remoteAbilityInfo.elementName.GetBundleName().c_str(),
178 remoteAbilityInfo.elementName.GetAbilityName().c_str(),
179 remoteAbilityInfo.label.c_str());
180 napi_value objRemoteAbilityInfo = nullptr;
181 NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objRemoteAbilityInfo));
182 ConvertRemoteAbilityInfo(env, objRemoteAbilityInfo, remoteAbilityInfo);
183 NAPI_CALL_RETURN_VOID(env, napi_set_element(env, objRemoteAbilityInfos, index, objRemoteAbilityInfo));
184 index++;
185 }
186 }
187
ParseModuleName(napi_env env,std::string & moduleName,napi_value args)188 static bool ParseModuleName(napi_env env, std::string &moduleName, napi_value args)
189 {
190 napi_status status;
191 napi_valuetype valueType;
192 napi_value prop = nullptr;
193 bool hasKey = false;
194 napi_has_named_property(env, args, "moduleName", &hasKey);
195 if (hasKey) {
196 status = napi_get_named_property(env, args, "moduleName", &prop);
197 napi_typeof(env, prop, &valueType);
198 if ((status == napi_ok) && (valueType == napi_string)) {
199 moduleName = GetStringFromNAPI(env, prop);
200 } else {
201 APP_LOGE("begin to parse ElementName moduleName failed");
202 return false;
203 }
204 }
205 return true;
206 }
207
ParseElementName(napi_env env,OHOS::AppExecFwk::ElementName & elementName,napi_value args)208 static bool ParseElementName(napi_env env, OHOS::AppExecFwk::ElementName &elementName, napi_value args)
209 {
210 APP_LOGD("begin to parse ElementName");
211 napi_status status;
212 napi_valuetype valueType;
213 NAPI_CALL_BASE(env, napi_typeof(env, args, &valueType), false);
214 if (valueType != napi_object) {
215 APP_LOGE("args not object type");
216 return false;
217 }
218 napi_value prop = nullptr;
219 status = napi_get_named_property(env, args, "deviceId", &prop);
220 napi_typeof(env, prop, &valueType);
221 if (status == napi_ok && valueType == napi_string) {
222 elementName.SetDeviceID(GetStringFromNAPI(env, prop));
223 } else {
224 APP_LOGE("begin to parse ElementName deviceId failed");
225 return false;
226 }
227 prop = nullptr;
228 status = napi_get_named_property(env, args, "bundleName", &prop);
229 napi_typeof(env, prop, &valueType);
230 if (status == napi_ok && valueType == napi_string) {
231 elementName.SetBundleName(GetStringFromNAPI(env, prop));
232 } else {
233 APP_LOGE("begin to parse ElementName bundleName failed");
234 return false;
235 }
236 prop = nullptr;
237 status = napi_get_named_property(env, args, "abilityName", &prop);
238 napi_typeof(env, prop, &valueType);
239 if (status == napi_ok && valueType == napi_string) {
240 elementName.SetAbilityName(GetStringFromNAPI(env, prop));
241 } else {
242 APP_LOGE("begin to parse ElementName abilityName failed");
243 return false;
244 }
245 std::string moduleName;
246 if (!ParseModuleName(env, moduleName, args)) {
247 return false;
248 }
249 elementName.SetModuleName(moduleName);
250 APP_LOGD("parse ElementName end");
251 return true;
252 }
253
ParseElementNames(napi_env env,std::vector<ElementName> & elementNames,napi_value args)254 static bool ParseElementNames(napi_env env, std::vector<ElementName> &elementNames, napi_value args)
255 {
256 APP_LOGD("begin to parse ElementNames");
257 bool isArray = false;
258 NAPI_CALL_BASE(env, napi_is_array(env, args, &isArray), false);
259 if (!isArray) {
260 APP_LOGE("parseElementNames args not array");
261 return false;
262 }
263 uint32_t arrayLength = 0;
264 NAPI_CALL_BASE(env, napi_get_array_length(env, args, &arrayLength), false);
265 APP_LOGD("arrayLength:%{public}d", arrayLength);
266 for (uint32_t i = 0; i < arrayLength; i++) {
267 napi_value value = nullptr;
268 NAPI_CALL_BASE(env, napi_get_element(env, args, i, &value), false);
269 napi_valuetype valueType = napi_undefined;
270 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
271 if (valueType != napi_object) {
272 APP_LOGE("array inside not object type");
273 elementNames.clear();
274 return false;
275 }
276 ElementName elementName;
277 if (ParseElementName(env, elementName, value)) {
278 elementNames.push_back(elementName);
279 } else {
280 APP_LOGE("elementNames parse elementName failed");
281 return false;
282 }
283 }
284 return true;
285 }
286
InnerGetRemoteAbilityInfo(const OHOS::AppExecFwk::ElementName & elementName,const std::string & locale,RemoteAbilityInfo & remoteAbilityInfo)287 static int32_t InnerGetRemoteAbilityInfo(
288 const OHOS::AppExecFwk::ElementName &elementName, const std::string &locale, RemoteAbilityInfo &remoteAbilityInfo)
289 {
290 auto iDistBundleMgr = GetDistributedBundleMgr();
291 if (!iDistBundleMgr) {
292 APP_LOGE("can not get iDistBundleMgr");
293 return ERR_INNER_ERROR;
294 }
295 int32_t result = iDistBundleMgr->GetRemoteAbilityInfo(elementName, locale, remoteAbilityInfo);
296 if (result != 0) {
297 APP_LOGE("InnerGetRemoteAbilityInfo failed");
298 }
299 return ConvertResultCode(result);
300 }
301
InnerGetRemoteAbilityInfos(const std::vector<ElementName> & elementNames,const std::string & locale,std::vector<RemoteAbilityInfo> & remoteAbilityInfos)302 static int32_t InnerGetRemoteAbilityInfos(const std::vector<ElementName> &elementNames, const std::string &locale,
303 std::vector<RemoteAbilityInfo> &remoteAbilityInfos)
304 {
305 if (elementNames.size() == 0) {
306 APP_LOGE("InnerGetRemoteAbilityInfos elementNames is empty");
307 return ERR_INVALID_PARAM;
308 }
309 auto iDistBundleMgr = GetDistributedBundleMgr();
310 if (!iDistBundleMgr) {
311 APP_LOGE("can not get iDistBundleMgr");
312 return ERR_INNER_ERROR;
313 }
314 int32_t result = iDistBundleMgr->GetRemoteAbilityInfos(elementNames, locale, remoteAbilityInfos);
315 if (result != 0) {
316 APP_LOGE("InnerGetRemoteAbilityInfo failed");
317 }
318 return ConvertResultCode(result);
319 }
320
GetRemoteAbilityInfo(napi_env env,napi_callback_info info)321 napi_value GetRemoteAbilityInfo(napi_env env, napi_callback_info info)
322 {
323 size_t requireArgc = ARGS_SIZE_ONE;
324 size_t argc = ARGS_SIZE_THREE;
325 napi_value argv[ARGS_SIZE_THREE] = { 0 };
326 napi_value thisArg = nullptr;
327 void *data = nullptr;
328
329 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data));
330 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
331
332 ElementNameInfo *asyncCallbackInfo = new (std::nothrow) ElementNameInfo(env);
333 if (asyncCallbackInfo == nullptr) {
334 return nullptr;
335 }
336 std::unique_ptr<ElementNameInfo> callbackPtr {asyncCallbackInfo};
337 for (size_t i = 0; i < argc; ++i) {
338 napi_valuetype valueType = napi_undefined;
339 NAPI_CALL(env, napi_typeof(env, argv[i], &valueType));
340 if ((i == PARAM0) && (valueType == napi_object)) {
341 if (!ParseElementName(env, asyncCallbackInfo->elementName, argv[i])) {
342 asyncCallbackInfo->errCode = ERR_INVALID_PARAM;
343 }
344 } else if ((i == PARAM1) && (valueType == napi_string)) {
345 ParseString(env, asyncCallbackInfo->locale, argv[i]);
346 } else if ((i == PARAM1 || i == PARAM2) && (valueType == napi_function)) {
347 NAPI_CALL(env, napi_create_reference(env, argv[i], NAPI_RETURN_ONE, &asyncCallbackInfo->callbackRef));
348 break;
349 } else {
350 asyncCallbackInfo->errCode = ERR_INVALID_PARAM;
351 asyncCallbackInfo->errMssage = "type misMatch";
352 }
353 }
354
355 napi_value promise = nullptr;
356 if (asyncCallbackInfo->callbackRef == nullptr) {
357 NAPI_CALL(env, napi_create_promise(env, &asyncCallbackInfo->deferred, &promise));
358 } else {
359 NAPI_CALL(env, napi_get_undefined(env, &promise));
360 }
361 napi_value resource = nullptr;
362 NAPI_CALL(env, napi_create_string_utf8(env, "getRemoteAbilityInfo", NAPI_AUTO_LENGTH, &resource));
363 NAPI_CALL(env, napi_create_async_work(
364 env, nullptr, resource,
365 [](napi_env env, void* data) {
366 ElementNameInfo* asyncCallbackInfo = reinterpret_cast<ElementNameInfo *>(data);
367 if (!asyncCallbackInfo->errCode) {
368 asyncCallbackInfo->errCode =
369 InnerGetRemoteAbilityInfo(asyncCallbackInfo->elementName,
370 asyncCallbackInfo->locale,
371 asyncCallbackInfo->remoteAbilityInfo);
372 }
373 },
374 [](napi_env env, napi_status status, void* data) {
375 ElementNameInfo* asyncCallbackInfo = reinterpret_cast<ElementNameInfo *>(data);
376 std::unique_ptr<ElementNameInfo> callbackPtr {asyncCallbackInfo};
377 napi_value result[2] = { 0 };
378 if (asyncCallbackInfo->errCode) {
379 napi_create_int32(env, asyncCallbackInfo->errCode, &result[0]);
380 } else {
381 napi_create_uint32(env, 0, &result[0]);
382 NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &result[1]));
383 ConvertRemoteAbilityInfo(env, result[1], asyncCallbackInfo->remoteAbilityInfo);
384 }
385 if (asyncCallbackInfo->callbackRef) {
386 napi_value callback = nullptr;
387 napi_value placeHolder = nullptr;
388 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callbackRef, &callback));
389 napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &placeHolder);
390 } else {
391 if (asyncCallbackInfo->errCode) {
392 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncCallbackInfo->deferred, result[0]));
393 } else {
394 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncCallbackInfo->deferred, result[1]));
395 }
396 }
397 },
398 reinterpret_cast<void*>(asyncCallbackInfo), &asyncCallbackInfo->asyncWork));
399 NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
400 callbackPtr.release();
401 return promise;
402 }
403
GetRemoteAbilityInfos(napi_env env,napi_callback_info info)404 napi_value GetRemoteAbilityInfos(napi_env env, napi_callback_info info)
405 {
406 size_t requireArgc = ARGS_SIZE_ONE;
407 size_t argc = ARGS_SIZE_THREE;
408 napi_value argv[ARGS_SIZE_THREE] = { 0 };
409 napi_value thisArg = nullptr;
410 void *data = nullptr;
411
412 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data));
413 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
414
415 ElementNameInfos *asyncCallbackInfo = new (std::nothrow) ElementNameInfos(env);
416 if (asyncCallbackInfo == nullptr) {
417 return nullptr;
418 }
419 std::unique_ptr<ElementNameInfos> callbackPtr {asyncCallbackInfo};
420 for (size_t i = 0; i < argc; ++i) {
421 napi_valuetype valueType = napi_undefined;
422 napi_typeof(env, argv[i], &valueType);
423 if (i == PARAM0) {
424 if (!ParseElementNames(env, asyncCallbackInfo->elementNames, argv[i])) {
425 asyncCallbackInfo->errCode = ERR_INVALID_PARAM;
426 }
427 if (static_cast<int32_t>(asyncCallbackInfo->elementNames.size()) > GET_REMOTE_ABILITY_INFO_MAX_SIZE) {
428 APP_LOGE("InnerGetRemoteAbilityInfos elementNames more than max");
429 asyncCallbackInfo->errCode = ERR_PARAMETERS_MORE_THAN_MAX;
430 }
431 } else if ((i == PARAM1) && (valueType == napi_string)) {
432 ParseString(env, asyncCallbackInfo->locale, argv[i]);
433 } else if ((i == PARAM1 || i == PARAM2) && (valueType == napi_function)) {
434 NAPI_CALL(env, napi_create_reference(env, argv[i], NAPI_RETURN_ONE, &asyncCallbackInfo->callbackRef));
435 break;
436 } else {
437 asyncCallbackInfo->errCode = ERR_INVALID_PARAM;
438 asyncCallbackInfo->errMssage = "type misMatch";
439 }
440 }
441
442 napi_value promise = nullptr;
443 if (asyncCallbackInfo->callbackRef == nullptr) {
444 NAPI_CALL(env, napi_create_promise(env, &asyncCallbackInfo->deferred, &promise));
445 } else {
446 NAPI_CALL(env, napi_get_undefined(env, &promise));
447 }
448 napi_value resource = nullptr;
449 NAPI_CALL(env, napi_create_string_utf8(env, "getRemoteAbilityInfos", NAPI_AUTO_LENGTH, &resource));
450 NAPI_CALL(env, napi_create_async_work(
451 env, nullptr, resource,
452 [](napi_env env, void* data) {
453 ElementNameInfos* asyncCallbackInfo = reinterpret_cast<ElementNameInfos *>(data);
454 if (!asyncCallbackInfo->errCode) {
455 asyncCallbackInfo->errCode =
456 InnerGetRemoteAbilityInfos(asyncCallbackInfo->elementNames,
457 asyncCallbackInfo->locale,
458 asyncCallbackInfo->remoteAbilityInfos);
459 }
460 },
461 [](napi_env env, napi_status status, void* data) {
462 ElementNameInfos* asyncCallbackInfo = reinterpret_cast<ElementNameInfos *>(data);
463 std::unique_ptr<ElementNameInfos> callbackPtr {asyncCallbackInfo};
464 napi_value result[2] = { 0 };
465 if (asyncCallbackInfo->errCode) {
466 napi_create_int32(env, asyncCallbackInfo->errCode, &result[0]);
467 } else {
468 napi_create_uint32(env, 0, &result[0]);
469 NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &result[1]));
470 ConvertRemoteAbilityInfos(env, result[1], asyncCallbackInfo->remoteAbilityInfos);
471 }
472 if (asyncCallbackInfo->callbackRef) {
473 napi_value callback = nullptr;
474 napi_value placeHolder = nullptr;
475 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callbackRef, &callback));
476 napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &placeHolder);
477 } else {
478 if (asyncCallbackInfo->errCode) {
479 napi_reject_deferred(env, asyncCallbackInfo->deferred, result[0]);
480 } else {
481 napi_resolve_deferred(env, asyncCallbackInfo->deferred, result[1]);
482 }
483 }
484 },
485 reinterpret_cast<void*>(asyncCallbackInfo), &asyncCallbackInfo->asyncWork));
486 NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
487 callbackPtr.release();
488 return promise;
489 }
490 }
491 }