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