1 /*
2 * Copyright (c) 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 "napi_request_global_switch_on_setting.h"
16
17 #include "ability.h"
18 #include "accesstoken_kit.h"
19 #include "accesstoken_log.h"
20 #include "napi_base_context.h"
21 #include "token_setproc.h"
22 #include "want.h"
23
24 namespace OHOS {
25 namespace Security {
26 namespace AccessToken {
27 namespace {
28 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
29 LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "NapiRequestGlobalSwitch"
30 };
31 const std::string GLOBAL_SWITCH_KEY = "ohos.user.setting.global_switch";
32 const std::string GLOBAL_SWITCH_RESULT_KEY = "ohos.user.setting.global_switch.result";
33 const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code";
34 const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType";
35 const std::string UI_EXTENSION_TYPE = "sys/commonUI";
36
37 // error code from dialog
38 const int32_t REQUEST_REALDY_EXIST = 1;
39 const int32_t GLOBAL_TYPE_IS_NOT_SUPPORT = 2;
40 const int32_t SWITCH_IS_ALREADY_OPEN = 3;
41 std::mutex g_lockFlag;
42 } // namespace
ReturnPromiseResult(napi_env env,int32_t jsCode,napi_deferred deferred,napi_value result)43 static void ReturnPromiseResult(napi_env env, int32_t jsCode, napi_deferred deferred, napi_value result)
44 {
45 if (jsCode != JS_OK) {
46 napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
47 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, deferred, businessError));
48 } else {
49 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, deferred, result));
50 }
51 }
52
WrapVoidToJS(napi_env env)53 static napi_value WrapVoidToJS(napi_env env)
54 {
55 napi_value result = nullptr;
56 NAPI_CALL(env, napi_get_null(env, &result));
57 return result;
58 }
59
GetUIContent(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)60 static Ace::UIContent* GetUIContent(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
61 {
62 if (asyncContext == nullptr) {
63 return nullptr;
64 }
65 Ace::UIContent* uiContent = nullptr;
66 if (asyncContext->uiAbilityFlag) {
67 uiContent = asyncContext->abilityContext->GetUIContent();
68 } else {
69 uiContent = asyncContext->uiExtensionContext->GetUIContent();
70 }
71 return uiContent;
72 }
73
GetContext(const napi_env & env,const napi_value & value,std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)74 static napi_value GetContext(
75 const napi_env &env, const napi_value &value, std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
76 {
77 bool stageMode = false;
78 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
79 if (status != napi_ok || !stageMode) {
80 ACCESSTOKEN_LOG_ERROR(LABEL, "It is not a stage mode.");
81 return nullptr;
82 } else {
83 auto context = AbilityRuntime::GetStageModeContext(env, value);
84 if (context == nullptr) {
85 ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to Get application context.");
86 return nullptr;
87 }
88 asyncContext->abilityContext =
89 AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
90 if (asyncContext->abilityContext != nullptr) {
91 asyncContext->uiAbilityFlag = true;
92 } else {
93 ACCESSTOKEN_LOG_WARN(LABEL, "Failed to convert to ability context.");
94 asyncContext->uiExtensionContext =
95 AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
96 if (asyncContext->uiExtensionContext == nullptr) {
97 ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to convert to ui extension context.");
98 return nullptr;
99 }
100 }
101 return WrapVoidToJS(env);
102 }
103 }
104
105
TransferToJsErrorCode(int32_t errCode)106 static int32_t TransferToJsErrorCode(int32_t errCode)
107 {
108 int32_t jsCode = JS_OK;
109 switch (errCode) {
110 case RET_SUCCESS:
111 jsCode = JS_OK;
112 break;
113 case REQUEST_REALDY_EXIST:
114 jsCode = JS_ERROR_REQUEST_IS_ALREADY_EXIST;
115 break;
116 case GLOBAL_TYPE_IS_NOT_SUPPORT:
117 jsCode = JS_ERROR_PARAM_INVALID;
118 break;
119 case SWITCH_IS_ALREADY_OPEN:
120 jsCode = JS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN;
121 break;
122 default:
123 jsCode = JS_ERROR_INNER;
124 break;
125 }
126 ACCESSTOKEN_LOG_INFO(LABEL, "dialog error(%{public}d) jsCode(%{public}d).", errCode, jsCode);
127 return jsCode;
128 }
129
ResultCallbackJSThreadWorker(uv_work_t * work,int32_t status)130 static void ResultCallbackJSThreadWorker(uv_work_t* work, int32_t status)
131 {
132 (void)status;
133 if (work == nullptr) {
134 ACCESSTOKEN_LOG_ERROR(LABEL, "Uv_queue_work_with_qos input work is nullptr");
135 return;
136 }
137 std::unique_ptr<uv_work_t> uvWorkPtr {work};
138 SwitchOnSettingResultCallback *retCB = reinterpret_cast<SwitchOnSettingResultCallback*>(work->data);
139 if (retCB == nullptr) {
140 ACCESSTOKEN_LOG_ERROR(LABEL, "RetCB is nullptr");
141 return;
142 }
143 std::unique_ptr<SwitchOnSettingResultCallback> callbackPtr {retCB};
144 std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext = retCB->data;
145 if (asyncContext == nullptr) {
146 return;
147 }
148
149 napi_handle_scope scope = nullptr;
150 napi_open_handle_scope(asyncContext->env, &scope);
151 if (scope == nullptr) {
152 ACCESSTOKEN_LOG_ERROR(LABEL, "Napi_open_handle_scope failed");
153 return;
154 }
155 napi_value requestResult = nullptr;
156 NAPI_CALL_RETURN_VOID(asyncContext->env, napi_get_boolean(asyncContext->env, retCB->switchStatus, &requestResult));
157
158 ReturnPromiseResult(asyncContext->env, retCB->jsCode, asyncContext->deferred, requestResult);
159 napi_close_handle_scope(asyncContext->env, scope);
160 }
161
GlobalSwitchResultsCallbackUI(int32_t jsCode,bool switchStatus,std::shared_ptr<RequestGlobalSwitchAsyncContext> & data)162 static void GlobalSwitchResultsCallbackUI(int32_t jsCode,
163 bool switchStatus, std::shared_ptr<RequestGlobalSwitchAsyncContext>& data)
164 {
165 auto* retCB = new (std::nothrow) SwitchOnSettingResultCallback();
166 if (retCB == nullptr) {
167 ACCESSTOKEN_LOG_ERROR(LABEL, "Insufficient memory for work!");
168 return;
169 }
170
171 std::unique_ptr<SwitchOnSettingResultCallback> callbackPtr {retCB};
172 retCB->jsCode = jsCode;
173 retCB->switchStatus = switchStatus;
174 retCB->data = data;
175
176 uv_loop_s* loop = nullptr;
177 NAPI_CALL_RETURN_VOID(data->env, napi_get_uv_event_loop(data->env, &loop));
178 if (loop == nullptr) {
179 ACCESSTOKEN_LOG_ERROR(LABEL, "Loop instance is nullptr");
180 return;
181 }
182 uv_work_t* work = new (std::nothrow) uv_work_t;
183 if (work == nullptr) {
184 ACCESSTOKEN_LOG_ERROR(LABEL, "Insufficient memory for work!");
185 return;
186 }
187 std::unique_ptr<uv_work_t> uvWorkPtr {work};
188 work->data = reinterpret_cast<void *>(retCB);
189 NAPI_CALL_RETURN_VOID(data->env, uv_queue_work_with_qos(
190 loop, work, [](uv_work_t* work) {}, ResultCallbackJSThreadWorker, uv_qos_user_initiated));
191
192 uvWorkPtr.release();
193 callbackPtr.release();
194 }
195
ReleaseHandler(int32_t code)196 void SwitchOnSettingUICallback::ReleaseHandler(int32_t code)
197 {
198 {
199 std::lock_guard<std::mutex> lock(g_lockFlag);
200 if (this->reqContext_->releaseFlag) {
201 ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed.");
202 return;
203 }
204 this->reqContext_->releaseFlag = true;
205 }
206 Ace::UIContent* uiContent = GetUIContent(this->reqContext_);
207 if (uiContent == nullptr) {
208 ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!");
209 return;
210 }
211 ACCESSTOKEN_LOG_INFO(LABEL, "Close uiextension component");
212 uiContent->CloseModalUIExtension(this->sessionId_);
213 if (code == -1) {
214 this->reqContext_->errorCode = code;
215 }
216 GlobalSwitchResultsCallbackUI(
217 TransferToJsErrorCode(this->reqContext_->errorCode), this->reqContext_->switchStatus, this->reqContext_);
218 }
219
SwitchOnSettingUICallback(const std::shared_ptr<RequestGlobalSwitchAsyncContext> & reqContext)220 SwitchOnSettingUICallback::SwitchOnSettingUICallback(
221 const std::shared_ptr<RequestGlobalSwitchAsyncContext>& reqContext)
222 {
223 this->reqContext_ = reqContext;
224 }
225
~SwitchOnSettingUICallback()226 SwitchOnSettingUICallback::~SwitchOnSettingUICallback()
227 {}
228
SetSessionId(int32_t sessionId)229 void SwitchOnSettingUICallback::SetSessionId(int32_t sessionId)
230 {
231 this->sessionId_ = sessionId;
232 }
233
234 /*
235 * when UIExtensionAbility use terminateSelfWithResult
236 */
OnResult(int32_t resultCode,const AAFwk::Want & result)237 void SwitchOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
238 {
239 this->reqContext_->errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0);
240 this->reqContext_->switchStatus = result.GetBoolParam(GLOBAL_SWITCH_RESULT_KEY, 0);
241 ACCESSTOKEN_LOG_INFO(LABEL, "ResultCode is %{public}d, errorCode=%{public}d, switchStatus=%{public}d",
242 resultCode, this->reqContext_->errorCode, this->reqContext_->switchStatus);
243 ReleaseHandler(0);
244 }
245
246 /*
247 * when UIExtensionAbility send message to UIExtensionComponent
248 */
OnReceive(const AAFwk::WantParams & receive)249 void SwitchOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive)
250 {
251 ACCESSTOKEN_LOG_INFO(LABEL, "Called!");
252 }
253
254 /*
255 * when UIExtensionAbility disconnect or use terminate or process die
256 * releaseCode is 0 when process normal exit
257 */
OnRelease(int32_t releaseCode)258 void SwitchOnSettingUICallback::OnRelease(int32_t releaseCode)
259 {
260 ACCESSTOKEN_LOG_INFO(LABEL, "ReleaseCode is %{public}d", releaseCode);
261
262 ReleaseHandler(-1);
263 }
264
265 /*
266 * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
267 */
OnError(int32_t code,const std::string & name,const std::string & message)268 void SwitchOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
269 {
270 ACCESSTOKEN_LOG_INFO(LABEL, "Code is %{public}d, name is %{public}s, message is %{public}s",
271 code, name.c_str(), message.c_str());
272
273 ReleaseHandler(-1);
274 }
275
276 /*
277 * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
278 * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
279 */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)280 void SwitchOnSettingUICallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
281 {
282 ACCESSTOKEN_LOG_INFO(LABEL, "Connect to UIExtensionAbility successfully.");
283 }
284
285 /*
286 * when UIExtensionComponent destructed
287 */
OnDestroy()288 void SwitchOnSettingUICallback::OnDestroy()
289 {
290 ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed.");
291 ReleaseHandler(-1);
292 }
293
CreateUIExtension(const Want & want,std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)294 static int32_t CreateUIExtension(const Want &want, std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
295 {
296 Ace::UIContent* uiContent = GetUIContent(asyncContext);
297 if (uiContent == nullptr) {
298 ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to get ui content!");
299 asyncContext->result = RET_FAILED;
300 return RET_FAILED;
301 }
302 auto uiExtCallback = std::make_shared<SwitchOnSettingUICallback>(asyncContext);
303 Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
304 [uiExtCallback](int32_t releaseCode) {
305 uiExtCallback->OnRelease(releaseCode);
306 },
307 [uiExtCallback](int32_t resultCode, const AAFwk::Want &result) {
308 uiExtCallback->OnResult(resultCode, result);
309 },
310 [uiExtCallback](const AAFwk::WantParams &receive) {
311 uiExtCallback->OnReceive(receive);
312 },
313 [uiExtCallback](int32_t code, const std::string &name, [[maybe_unused]] const std::string &message) {
314 uiExtCallback->OnError(code, name, name);
315 },
316 [uiExtCallback](const std::shared_ptr<Ace::ModalUIExtensionProxy> &uiProxy) {
317 uiExtCallback->OnRemoteReady(uiProxy);
318 },
319 [uiExtCallback]() {
320 uiExtCallback->OnDestroy();
321 },
322 };
323
324 Ace::ModalUIExtensionConfig config;
325 config.isProhibitBack = true;
326 int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
327 ACCESSTOKEN_LOG_INFO(LABEL, "Create end, sessionId: %{public}d, tokenId: %{public}d, switchType: %{public}d.",
328 sessionId, asyncContext->tokenId, asyncContext->switchType);
329 if (sessionId == 0) {
330 ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create component, sessionId is 0.");
331 asyncContext->result = RET_FAILED;
332 return RET_FAILED;
333 }
334 uiExtCallback->SetSessionId(sessionId);
335 return JS_OK;
336 }
337
StartUIExtension(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)338 static int32_t StartUIExtension(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
339 {
340 AAFwk::Want want;
341 AccessTokenKit::GetPermissionManagerInfo(asyncContext->info);
342 ACCESSTOKEN_LOG_INFO(LABEL, "bundleName: %{public}s, globalSwitchAbilityName: %{public}s.",
343 asyncContext->info.grantBundleName.c_str(), asyncContext->info.globalSwitchAbilityName.c_str());
344 want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.globalSwitchAbilityName);
345 want.SetParam(GLOBAL_SWITCH_KEY, asyncContext->switchType);
346 want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
347
348 return CreateUIExtension(want, asyncContext);
349 }
350
RequestGlobalSwitch(napi_env env,napi_callback_info info)351 napi_value NapiRequestGlobalSwitch::RequestGlobalSwitch(napi_env env, napi_callback_info info)
352 {
353 ACCESSTOKEN_LOG_DEBUG(LABEL, "RequestGlobalSwitch begin.");
354 // use handle to protect asyncContext
355 std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext =
356 std::make_shared<RequestGlobalSwitchAsyncContext>(env);
357
358 if (!ParseRequestGlobalSwitch(env, info, asyncContext)) {
359 return nullptr;
360 }
361 auto asyncContextHandle = std::make_unique<RequestGlobalSwitchAsyncContextHandle>(asyncContext);
362 napi_value result = nullptr;
363 if (asyncContextHandle->asyncContextPtr->callbackRef == nullptr) {
364 NAPI_CALL(env, napi_create_promise(env, &(asyncContextHandle->asyncContextPtr->deferred), &result));
365 } else {
366 NAPI_CALL(env, napi_get_undefined(env, &result));
367 }
368
369 napi_value resource = nullptr; // resource name
370 NAPI_CALL(env, napi_create_string_utf8(env, "RequestGlobalSwitch", NAPI_AUTO_LENGTH, &resource));
371 NAPI_CALL(env, napi_create_async_work(
372 env, nullptr, resource, RequestGlobalSwitchExecute, RequestGlobalSwitchComplete,
373 reinterpret_cast<void *>(asyncContextHandle.get()), &(asyncContextHandle->asyncContextPtr->work)));
374
375 NAPI_CALL(env,
376 napi_queue_async_work_with_qos(env, asyncContextHandle->asyncContextPtr->work, napi_qos_user_initiated));
377
378 ACCESSTOKEN_LOG_DEBUG(LABEL, "RequestGlobalSwitch end.");
379 asyncContextHandle.release();
380 return result;
381 }
382
ParseRequestGlobalSwitch(const napi_env & env,const napi_callback_info & cbInfo,std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)383 bool NapiRequestGlobalSwitch::ParseRequestGlobalSwitch(const napi_env& env,
384 const napi_callback_info& cbInfo, std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
385 {
386 size_t argc = NapiContextCommon::MAX_PARAMS_TWO;
387 napi_value argv[NapiContextCommon::MAX_PARAMS_TWO] = { nullptr };
388 napi_value thisVar = nullptr;
389
390 if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
391 ACCESSTOKEN_LOG_ERROR(LABEL, "Napi_get_cb_info failed");
392 return false;
393 }
394 if (argc < NapiContextCommon::MAX_PARAMS_TWO - 1) {
395 NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env,
396 JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
397 return false;
398 }
399 asyncContext->env = env;
400 std::string errMsg;
401
402 // argv[0] : context : AbilityContext
403 if (GetContext(env, argv[0], asyncContext) == nullptr) {
404 errMsg = GetParamErrorMsg("context", "UIAbility or UIExtension Context");
405 NAPI_CALL_BASE(
406 env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
407 return false;
408 }
409 ACCESSTOKEN_LOG_INFO(LABEL, "AsyncContext.uiAbilityFlag is: %{public}d.", asyncContext->uiAbilityFlag);
410
411 // argv[1] : type
412 if (!ParseInt32(env, argv[1], asyncContext->switchType)) {
413 errMsg = GetParamErrorMsg("type", "SwitchType");
414 NAPI_CALL_BASE(
415 env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
416 return false;
417 }
418 return true;
419 }
420
RequestGlobalSwitchExecute(napi_env env,void * data)421 void NapiRequestGlobalSwitch::RequestGlobalSwitchExecute(napi_env env, void* data)
422 {
423 // asyncContext release in complete
424 RequestGlobalSwitchAsyncContextHandle* asyncContextHandle =
425 reinterpret_cast<RequestGlobalSwitchAsyncContextHandle*>(data);
426 if ((asyncContextHandle == nullptr) || (asyncContextHandle->asyncContextPtr == nullptr)) {
427 return;
428 }
429 if (asyncContextHandle->asyncContextPtr->uiAbilityFlag) {
430 if ((asyncContextHandle->asyncContextPtr->abilityContext == nullptr) ||
431 (asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo() == nullptr)) {
432 return;
433 }
434 asyncContextHandle->asyncContextPtr->tokenId =
435 asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo()->accessTokenId;
436 } else {
437 if ((asyncContextHandle->asyncContextPtr->uiExtensionContext == nullptr) ||
438 (asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo() == nullptr)) {
439 return;
440 }
441 asyncContextHandle->asyncContextPtr->tokenId =
442 asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo()->accessTokenId;
443 }
444 static AccessTokenID currToken = static_cast<AccessTokenID>(GetSelfTokenID());
445 if (asyncContextHandle->asyncContextPtr->tokenId != currToken) {
446 ACCESSTOKEN_LOG_ERROR(LABEL,
447 "The context(token=%{public}d) is not belong to the current application(currToken=%{public}d).",
448 asyncContextHandle->asyncContextPtr->tokenId, currToken);
449 asyncContextHandle->asyncContextPtr->result = ERR_PARAM_INVALID;
450 return;
451 }
452
453 ACCESSTOKEN_LOG_INFO(LABEL, "Start to pop ui extension dialog");
454 StartUIExtension(asyncContextHandle->asyncContextPtr);
455 if (asyncContextHandle->asyncContextPtr->result != JsErrorCode::JS_OK) {
456 ACCESSTOKEN_LOG_WARN(LABEL, "Failed to pop uiextension dialog.");
457 }
458 }
459
RequestGlobalSwitchComplete(napi_env env,napi_status status,void * data)460 void NapiRequestGlobalSwitch::RequestGlobalSwitchComplete(napi_env env, napi_status status, void* data)
461 {
462 ACCESSTOKEN_LOG_DEBUG(LABEL, "RequestGlobalSwitchComplete begin.");
463 RequestGlobalSwitchAsyncContextHandle* asyncContextHandle =
464 reinterpret_cast<RequestGlobalSwitchAsyncContextHandle*>(data);
465 if (asyncContextHandle == nullptr || asyncContextHandle->asyncContextPtr == nullptr) {
466 return;
467 }
468 std::unique_ptr<RequestGlobalSwitchAsyncContextHandle> callbackPtr {asyncContextHandle};
469
470 // need pop dialog
471 if (asyncContextHandle->asyncContextPtr->result == RET_SUCCESS) {
472 return;
473 }
474 // return error
475 if (asyncContextHandle->asyncContextPtr->deferred != nullptr) {
476 int32_t jsCode = NapiContextCommon::GetJsErrorCode(asyncContextHandle->asyncContextPtr->result);
477 napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
478 NAPI_CALL_RETURN_VOID(env,
479 napi_reject_deferred(env, asyncContextHandle->asyncContextPtr->deferred, businessError));
480 }
481 }
482 } // namespace AccessToken
483 } // namespace Security
484 } // namespace OHOS