• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_permission.h"
16 
17 #include "ability.h"
18 #include "ability_manager_client.h"
19 #include "access_token.h"
20 #include "accesstoken_kit.h"
21 #include "accesstoken_common_log.h"
22 #include "hisysevent.h"
23 #include "napi_base_context.h"
24 #include "napi_hisysevent_adapter.h"
25 #include "token_setproc.h"
26 #include "want.h"
27 
28 namespace OHOS {
29 namespace Security {
30 namespace AccessToken {
31 std::mutex g_lockFlag;
32 std::map<int32_t, std::vector<std::shared_ptr<RequestAsyncContext>>> RequestAsyncInstanceControl::instanceIdMap_;
33 std::mutex RequestAsyncInstanceControl::instanceIdMutex_;
34 namespace {
35 const std::string PERMISSION_KEY = "ohos.user.grant.permission";
36 const std::string STATE_KEY = "ohos.user.grant.permission.state";
37 const std::string RESULT_KEY = "ohos.user.grant.permission.result";
38 const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType";
39 const std::string UI_EXTENSION_TYPE = "sys/commonUI";
40 const std::string ORI_PERMISSION_MANAGER_BUNDLE_NAME = "com.ohos.permissionmanager";
41 const std::string TOKEN_KEY = "ohos.ability.params.token";
42 const std::string CALLBACK_KEY = "ohos.ability.params.callback";
43 
44 const std::string WINDOW_RECTANGLE_LEFT_KEY = "ohos.ability.params.request.left";
45 const std::string WINDOW_RECTANGLE_TOP_KEY = "ohos.ability.params.request.top";
46 const std::string WINDOW_RECTANGLE_HEIGHT_KEY = "ohos.ability.params.request.height";
47 const std::string WINDOW_RECTANGLE_WIDTH_KEY = "ohos.ability.params.request.width";
48 const std::string REQUEST_TOKEN_KEY = "ohos.ability.params.request.token";
49 
ReturnPromiseResult(napi_env env,const RequestAsyncContext & context,napi_value result)50 static void ReturnPromiseResult(napi_env env, const RequestAsyncContext& context, napi_value result)
51 {
52     if (context.result.errorCode != RET_SUCCESS) {
53         int32_t jsCode = GetJsErrorCode(context.result.errorCode);
54         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode, context.result.errorMsg));
55         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context.deferred, businessError));
56     } else {
57         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context.deferred, result));
58     }
59 }
60 
ReturnCallbackResult(napi_env env,const RequestAsyncContext & context,napi_value result)61 static void ReturnCallbackResult(napi_env env, const RequestAsyncContext& context, napi_value result)
62 {
63     napi_value businessError = GetNapiNull(env);
64     if (context.result.errorCode != RET_SUCCESS) {
65         int32_t jsCode = GetJsErrorCode(context.result.errorCode);
66         businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode, context.result.errorMsg));
67     }
68     napi_value results[ASYNC_CALL_BACK_VALUES_NUM] = { businessError, result };
69 
70     napi_value callback = nullptr;
71     napi_value thisValue = nullptr;
72     napi_value thatValue = nullptr;
73     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &thisValue));
74     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &thatValue));
75     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, context.callbackRef, &callback));
76     NAPI_CALL_RETURN_VOID(env,
77         napi_call_function(env, thisValue, callback, ASYNC_CALL_BACK_VALUES_NUM, results, &thatValue));
78 }
79 } // namespace
80 
WrapVoidToJS(napi_env env)81 static napi_value WrapVoidToJS(napi_env env)
82 {
83     napi_value result = nullptr;
84     NAPI_CALL(env, napi_get_null(env, &result));
85     return result;
86 }
87 
GetUIContent(std::shared_ptr<RequestAsyncContext> asyncContext)88 static Ace::UIContent* GetUIContent(std::shared_ptr<RequestAsyncContext> asyncContext)
89 {
90     if (asyncContext == nullptr) {
91         return nullptr;
92     }
93     Ace::UIContent* uiContent = nullptr;
94     if (asyncContext->uiAbilityFlag) {
95         uiContent = asyncContext->abilityContext->GetUIContent();
96     } else {
97         uiContent = asyncContext->uiExtensionContext->GetUIContent();
98     }
99     return uiContent;
100 }
101 
GetInstanceId(std::shared_ptr<RequestAsyncContext> & asyncContext)102 static void GetInstanceId(std::shared_ptr<RequestAsyncContext>& asyncContext)
103 {
104     auto task = [asyncContext]() {
105         Ace::UIContent* uiContent = GetUIContent(asyncContext);
106         if (uiContent == nullptr) {
107             LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
108             (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
109                 HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", GET_UI_CONTENT_FAILED);
110             return;
111         }
112         asyncContext->uiContentFlag = true;
113         asyncContext->instanceId = uiContent->GetInstanceId();
114     };
115 #ifdef EVENTHANDLER_ENABLE
116     if (asyncContext->handler_ != nullptr) {
117         asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId");
118     } else {
119         task();
120     }
121 #else
122     task();
123 #endif
124     LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d, uiContentFlag: %{public}d",
125         asyncContext->instanceId, asyncContext->uiContentFlag);
126 }
127 
CreateUIExtensionMainThread(std::shared_ptr<RequestAsyncContext> & asyncContext,const AAFwk::Want & want,const Ace::ModalUIExtensionCallbacks & uiExtensionCallbacks,const std::shared_ptr<UIExtensionCallback> & uiExtCallback)128 static void CreateUIExtensionMainThread(std::shared_ptr<RequestAsyncContext>& asyncContext, const AAFwk::Want& want,
129     const Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks,
130     const std::shared_ptr<UIExtensionCallback>& uiExtCallback)
131 {
132     auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() {
133         Ace::UIContent* uiContent = GetUIContent(asyncContext);
134         if (uiContent == nullptr) {
135             LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
136             asyncContext->result.errorCode = RET_FAILED;
137             asyncContext->uiExtensionFlag = false;
138             return;
139         }
140 
141         Ace::ModalUIExtensionConfig config;
142         config.isProhibitBack = true;
143         config.isModalRequestFocus = false;
144         int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
145 
146         LOGI(ATM_DOMAIN, ATM_TAG, "Create end, sessionId: %{public}d, tokenId: %{public}d, permNum: %{public}zu",
147             sessionId, asyncContext->tokenId, asyncContext->permissionList.size());
148         if (sessionId == 0) {
149             LOGE(ATM_DOMAIN, ATM_TAG, "Create component failed, sessionId is 0");
150             asyncContext->result.errorCode = RET_FAILED;
151             asyncContext->uiExtensionFlag = false;
152             (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
153                 HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", CREATE_MODAL_UI_FAILED);
154             return;
155         }
156         uiExtCallback->SetSessionId(sessionId);
157     };
158 #ifdef EVENTHANDLER_ENABLE
159     if (asyncContext->handler_ != nullptr) {
160         asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread");
161     } else {
162         task();
163     }
164 #else
165     task();
166 #endif
167     LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d", asyncContext->instanceId);
168 }
169 
CloseModalUIExtensionMainThread(std::shared_ptr<RequestAsyncContext> & asyncContext,int32_t sessionId)170 static void CloseModalUIExtensionMainThread(std::shared_ptr<RequestAsyncContext>& asyncContext, int32_t sessionId)
171 {
172     auto task = [asyncContext, sessionId]() {
173         Ace::UIContent* uiContent = GetUIContent(asyncContext);
174         if (uiContent == nullptr) {
175             LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
176             asyncContext->result.errorCode = RET_FAILED;
177             return;
178         }
179         uiContent->CloseModalUIExtension(sessionId);
180         LOGI(ATM_DOMAIN, ATM_TAG, "Close end, sessionId: %{public}d", sessionId);
181     };
182 #ifdef EVENTHANDLER_ENABLE
183     if (asyncContext->handler_ != nullptr) {
184         asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread");
185     } else {
186         task();
187     }
188 #else
189     task();
190 #endif
191     LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d", asyncContext->instanceId);
192 }
193 
GetContext(const napi_env & env,const napi_value & value,std::shared_ptr<RequestAsyncContext> & asyncContext)194 static napi_value GetContext(
195     const napi_env &env, const napi_value &value, std::shared_ptr<RequestAsyncContext>& asyncContext)
196 {
197     bool stageMode = false;
198     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
199     if (status != napi_ok || !stageMode) {
200         LOGE(ATM_DOMAIN, ATM_TAG, "It is not a stage mode");
201         return nullptr;
202     } else {
203         auto context = AbilityRuntime::GetStageModeContext(env, value);
204         if (context == nullptr) {
205             LOGE(ATM_DOMAIN, ATM_TAG, "Get context failed");
206             return nullptr;
207         }
208         asyncContext->abilityContext =
209             AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
210         if ((asyncContext->abilityContext != nullptr) &&
211             (asyncContext->abilityContext->GetApplicationInfo() != nullptr)) {
212             asyncContext->uiAbilityFlag = true;
213             asyncContext->tokenId = asyncContext->abilityContext->GetApplicationInfo()->accessTokenId;
214             asyncContext->bundleName = asyncContext->abilityContext->GetApplicationInfo()->bundleName;
215         } else {
216             LOGW(ATM_DOMAIN, ATM_TAG, "Convert to ability context failed");
217             asyncContext->uiExtensionContext =
218                 AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
219             if ((asyncContext->uiExtensionContext == nullptr) ||
220                 (asyncContext->uiExtensionContext->GetApplicationInfo() == nullptr)) {
221                 LOGE(ATM_DOMAIN, ATM_TAG, "Convert to ui extension context failed");
222                 return nullptr;
223             }
224             asyncContext->tokenId = asyncContext->uiExtensionContext->GetApplicationInfo()->accessTokenId;
225             asyncContext->bundleName = asyncContext->uiExtensionContext->GetApplicationInfo()->bundleName;
226         }
227         return WrapVoidToJS(env);
228     }
229 }
230 
WrapRequestResult(const napi_env & env,const std::vector<std::string> & permissions,const std::vector<int> & grantResults,const std::vector<bool> & dialogShownResults,const std::vector<int> & errorReasons)231 static napi_value WrapRequestResult(const napi_env& env, const std::vector<std::string>& permissions,
232     const std::vector<int>& grantResults, const std::vector<bool>& dialogShownResults,
233     const std::vector<int>& errorReasons)
234 {
235     napi_value result = nullptr;
236     NAPI_CALL(env, napi_create_object(env, &result));
237 
238     napi_value objPermissions;
239     NAPI_CALL(env, napi_create_array(env, &objPermissions));
240     for (size_t i = 0; i < permissions.size(); i++) {
241         napi_value nPerm = nullptr;
242         NAPI_CALL(env, napi_create_string_utf8(env, permissions[i].c_str(), NAPI_AUTO_LENGTH, &nPerm));
243         NAPI_CALL(env, napi_set_element(env, objPermissions, i, nPerm));
244     }
245     NAPI_CALL(env, napi_set_named_property(env, result, "permissions", objPermissions));
246 
247     napi_value objGrantResults;
248     NAPI_CALL(env, napi_create_array(env, &objGrantResults));
249     for (size_t i = 0; i < grantResults.size(); i++) {
250         napi_value nGrantResult = nullptr;
251         NAPI_CALL(env, napi_create_int32(env, grantResults[i], &nGrantResult));
252         NAPI_CALL(env, napi_set_element(env, objGrantResults, i, nGrantResult));
253     }
254     NAPI_CALL(env, napi_set_named_property(env, result, "authResults", objGrantResults));
255 
256     napi_value objDialogShown;
257     NAPI_CALL(env, napi_create_array(env, &objDialogShown));
258     for (size_t i = 0; i < dialogShownResults.size(); i++) {
259         napi_value nDialogShown = nullptr;
260         NAPI_CALL(env, napi_get_boolean(env, dialogShownResults[i], &nDialogShown));
261         NAPI_CALL(env, napi_set_element(env, objDialogShown, i, nDialogShown));
262     }
263     NAPI_CALL(env, napi_set_named_property(env, result, "dialogShownResults", objDialogShown));
264 
265     napi_value objErrorReason;
266     NAPI_CALL(env, napi_create_array(env, &objErrorReason));
267     for (size_t i = 0; i < grantResults.size(); i++) {
268         napi_value nErrorReason = nullptr;
269         NAPI_CALL(env, napi_create_int32(env, errorReasons[i], &nErrorReason));
270         NAPI_CALL(env, napi_set_element(env, objErrorReason, i, nErrorReason));
271     }
272     NAPI_CALL(env, napi_set_named_property(env, result, "errorReasons", objErrorReason));
273 
274     return result;
275 }
276 
UpdateGrantPermissionResultOnly(const std::vector<std::string> & permissions,const std::vector<int> & grantResults,std::shared_ptr<RequestAsyncContext> & data,std::vector<int> & newGrantResults)277 static void UpdateGrantPermissionResultOnly(const std::vector<std::string>& permissions,
278     const std::vector<int>& grantResults, std::shared_ptr<RequestAsyncContext>& data, std::vector<int>& newGrantResults)
279 {
280     uint32_t size = permissions.size();
281 
282     for (uint32_t i = 0; i < size; i++) {
283         int result = data->permissionsState[i];
284         if (data->permissionsState[i] == DYNAMIC_OPER) {
285             result = data->result.errorCode == RET_SUCCESS ? grantResults[i] : INVALID_OPER;
286         }
287         newGrantResults.emplace_back(result);
288     }
289 }
290 
RequestResultsHandler(const std::vector<std::string> & permissionList,const std::vector<int32_t> & permissionStates,std::shared_ptr<RequestAsyncContext> & data)291 static void RequestResultsHandler(const std::vector<std::string>& permissionList,
292     const std::vector<int32_t>& permissionStates, std::shared_ptr<RequestAsyncContext>& data)
293 {
294     if (data == nullptr) {
295         LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
296         return;
297     }
298     auto* retCB = new (std::nothrow) ResultCallback();
299     if (retCB == nullptr) {
300         LOGE(ATM_DOMAIN, ATM_TAG, "Insufficient memory for work!");
301         return;
302     }
303     std::vector<int> newGrantResults;
304     UpdateGrantPermissionResultOnly(permissionList, permissionStates, data, newGrantResults);
305 
306     std::unique_ptr<ResultCallback> callbackPtr {retCB};
307     retCB->permissions = permissionList;
308     retCB->grantResults = newGrantResults;
309     retCB->dialogShownResults = data->dialogShownResults;
310     retCB->errorReasons = data->errorReasons;
311     retCB->data = data;
312     auto task = [retCB]() {
313         if ((retCB->data->result.errorCode != RET_SUCCESS) || retCB->grantResults.empty()) {
314             LOGE(ATM_DOMAIN, ATM_TAG, "Result is: %{public}d", retCB->data->result.errorCode);
315             retCB->data->result.errorCode = RET_FAILED;
316         }
317         napi_handle_scope scope = nullptr;
318         napi_open_handle_scope(retCB->data->env, &scope);
319         if (scope == nullptr) {
320             LOGE(ATM_DOMAIN, ATM_TAG, "Napi_open_handle_scope failed");
321             delete retCB;
322             return;
323         }
324         napi_value requestResult = WrapRequestResult(
325             retCB->data->env, retCB->permissions, retCB->grantResults, retCB->dialogShownResults, retCB->errorReasons);
326         if (requestResult == nullptr) {
327             LOGE(ATM_DOMAIN, ATM_TAG, "Wrap requestResult failed");
328             retCB->data->result.errorCode = RET_FAILED;
329         }
330 
331         if (retCB->data->deferred != nullptr) {
332             ReturnPromiseResult(retCB->data->env, *retCB->data, requestResult);
333         } else {
334             ReturnCallbackResult(retCB->data->env, *retCB->data, requestResult);
335         }
336         napi_close_handle_scope(retCB->data->env, scope);
337         delete retCB;
338     };
339     if (napi_status::napi_ok != napi_send_event(data->env, task, napi_eprio_immediate)) {
340         LOGE(ATM_DOMAIN, ATM_TAG, "RequestResultsHandler: Failed to SendEvent");
341     } else {
342         callbackPtr.release();
343     }
344 }
345 
GrantResultsCallback(const std::vector<std::string> & permissionList,const std::vector<int> & grantResults)346 void AuthorizationResult::GrantResultsCallback(const std::vector<std::string>& permissionList,
347     const std::vector<int>& grantResults)
348 {
349     LOGI(ATM_DOMAIN, ATM_TAG, "Called.");
350     std::shared_ptr<RequestAsyncContext> asyncContext = data_;
351     if (asyncContext == nullptr) {
352         return;
353     }
354     RequestResultsHandler(permissionList, grantResults, asyncContext);
355 }
356 
WindowShownCallback()357 void AuthorizationResult::WindowShownCallback()
358 {
359     LOGI(ATM_DOMAIN, ATM_TAG, "Called.");
360 
361     std::shared_ptr<RequestAsyncContext> asyncContext = data_;
362     if (asyncContext == nullptr) {
363         return;
364     }
365 
366     Ace::UIContent* uiContent = GetUIContent(asyncContext);
367     // get uiContent failed when request or when callback called
368     if ((uiContent == nullptr) || !(asyncContext->uiContentFlag)) {
369         LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
370         return;
371     }
372     RequestAsyncInstanceControl::ExecCallback(asyncContext->instanceId);
373     LOGD(ATM_DOMAIN, ATM_TAG, "OnRequestPermissionsFromUser async callback is called end");
374 }
375 
CreateServiceExtension(std::shared_ptr<RequestAsyncContext> asyncContext)376 static void CreateServiceExtension(std::shared_ptr<RequestAsyncContext> asyncContext)
377 {
378     if ((asyncContext == nullptr) || (asyncContext->abilityContext == nullptr)) {
379         return;
380     }
381     if (!asyncContext->uiAbilityFlag) {
382         LOGE(ATM_DOMAIN, ATM_TAG, "UIExtension ability can not pop service ablility window!");
383         asyncContext->needDynamicRequest = false;
384         asyncContext->result.errorCode = RET_FAILED;
385         (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
386             HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", ABILITY_FLAG_ERROR);
387         return;
388     }
389     sptr<IRemoteObject> remoteObject = new (std::nothrow) AccessToken::AuthorizationResult(asyncContext);
390     if (remoteObject == nullptr) {
391         LOGE(ATM_DOMAIN, ATM_TAG, "Create window failed!");
392         asyncContext->needDynamicRequest = false;
393         asyncContext->result.errorCode = RET_FAILED;
394         return;
395     }
396     AAFwk::Want want;
397     want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantServiceAbilityName);
398     want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
399     want.SetParam(STATE_KEY, asyncContext->permissionsState);
400     want.SetParam(TOKEN_KEY, asyncContext->abilityContext->GetToken());
401     want.SetParam(CALLBACK_KEY, remoteObject);
402 
403     int32_t left;
404     int32_t top;
405     int32_t width;
406     int32_t height;
407     asyncContext->abilityContext->GetWindowRect(left, top, width, height);
408     want.SetParam(WINDOW_RECTANGLE_LEFT_KEY, left);
409     want.SetParam(WINDOW_RECTANGLE_TOP_KEY, top);
410     want.SetParam(WINDOW_RECTANGLE_WIDTH_KEY, width);
411     want.SetParam(WINDOW_RECTANGLE_HEIGHT_KEY, height);
412     want.SetParam(REQUEST_TOKEN_KEY, asyncContext->abilityContext->GetToken());
413     int32_t ret = AAFwk::AbilityManagerClient::GetInstance()->RequestDialogService(
414         want, asyncContext->abilityContext->GetToken());
415 
416     LOGI(ATM_DOMAIN, ATM_TAG, "Request end, ret: %{public}d, tokenId: %{public}d, permNum: %{public}zu",
417         ret, asyncContext->tokenId, asyncContext->permissionList.size());
418 }
419 
IsDynamicRequest(std::shared_ptr<RequestAsyncContext> & asyncContext)420 bool NapiRequestPermission::IsDynamicRequest(std::shared_ptr<RequestAsyncContext>& asyncContext)
421 {
422     std::vector<PermissionListState> permList;
423     for (const auto& permission : asyncContext->permissionList) {
424         PermissionListState permState;
425         permState.permissionName = permission;
426         permState.state = INVALID_OPER;
427         permState.errorReason = SERVICE_ABNORMAL;
428         permList.emplace_back(permState);
429     }
430     auto ret = AccessTokenKit::GetSelfPermissionsState(permList, asyncContext->info);
431     if (ret == FORBIDDEN_OPER) { // if app is under control, change state from default -1 to 2
432         for (auto& perm : permList) {
433             perm.state = INVALID_OPER;
434             perm.errorReason = PRIVACY_STATEMENT_NOT_AGREED;
435         }
436     }
437     LOGI(ATM_DOMAIN, ATM_TAG,
438         "TokenID: %{public}d, bundle: %{public}s, uiExAbility: %{public}s, serExAbility: %{public}s.",
439         asyncContext->tokenId, asyncContext->info.grantBundleName.c_str(),
440         asyncContext->info.grantAbilityName.c_str(), asyncContext->info.grantServiceAbilityName.c_str());
441 
442     for (const auto& permState : permList) {
443         LOGI(ATM_DOMAIN, ATM_TAG, "Permission: %{public}s: state: %{public}d, errorReason: %{public}d",
444             permState.permissionName.c_str(), permState.state, permState.errorReason);
445         asyncContext->permissionsState.emplace_back(permState.state);
446         asyncContext->dialogShownResults.emplace_back(permState.state == TypePermissionOper::DYNAMIC_OPER);
447         asyncContext->errorReasons.emplace_back(permState.errorReason);
448     }
449     if (permList.size() != asyncContext->permissionList.size()) {
450         LOGE(ATM_DOMAIN, ATM_TAG, "Returned permList size: %{public}zu.", permList.size());
451         return false;
452     }
453     return ret == TypePermissionOper::DYNAMIC_OPER;
454 }
455 
ReleaseHandler(int32_t code)456 void UIExtensionCallback::ReleaseHandler(int32_t code)
457 {
458     if (this->reqContext_ == nullptr) {
459         LOGE(ATM_DOMAIN, ATM_TAG, "Request context is null.");
460         return;
461     }
462     {
463         std::lock_guard<std::mutex> lock(g_lockFlag);
464         if (this->reqContext_->releaseFlag) {
465             LOGW(ATM_DOMAIN, ATM_TAG, "Callback has executed.");
466             return;
467         }
468         this->reqContext_->releaseFlag = true;
469     }
470     CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_);
471     this->reqContext_->result.errorCode = code;
472     RequestAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId);
473     RequestResultsHandler(this->reqContext_->permissionList, this->reqContext_->permissionsState, this->reqContext_);
474 }
475 
UIExtensionCallback(const std::shared_ptr<RequestAsyncContext> & reqContext)476 UIExtensionCallback::UIExtensionCallback(const std::shared_ptr<RequestAsyncContext>& reqContext)
477 {
478     this->reqContext_ = reqContext;
479     isOnResult_.exchange(false);
480 }
481 
~UIExtensionCallback()482 UIExtensionCallback::~UIExtensionCallback()
483 {}
484 
SetSessionId(int32_t sessionId)485 void UIExtensionCallback::SetSessionId(int32_t sessionId)
486 {
487     this->sessionId_ = sessionId;
488 }
489 
490 /*
491  * when UIExtensionAbility use terminateSelfWithResult
492  */
OnResult(int32_t resultCode,const AAFwk::Want & result)493 void UIExtensionCallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
494 {
495     if (this->reqContext_ == nullptr) {
496         LOGE(ATM_DOMAIN, ATM_TAG, "Request context is null.");
497         return;
498     }
499     isOnResult_.exchange(true);
500     LOGI(ATM_DOMAIN, ATM_TAG, "ResultCode is %{public}d", resultCode);
501     this->reqContext_->permissionList = result.GetStringArrayParam(PERMISSION_KEY);
502     this->reqContext_->permissionsState = result.GetIntArrayParam(RESULT_KEY);
503     ReleaseHandler(0);
504 }
505 
506 /*
507  * when UIExtensionAbility send message to UIExtensionComponent
508  */
OnReceive(const AAFwk::WantParams & receive)509 void UIExtensionCallback::OnReceive(const AAFwk::WantParams& receive)
510 {
511     LOGI(ATM_DOMAIN, ATM_TAG, "Called!");
512 }
513 
514 /*
515  * when UIExtensionAbility disconnect or use terminate or process die
516  * releaseCode is 0 when process normal exit
517  */
OnRelease(int32_t releaseCode)518 void UIExtensionCallback::OnRelease(int32_t releaseCode)
519 {
520     LOGI(ATM_DOMAIN, ATM_TAG, "ReleaseCode is %{public}d", releaseCode);
521     (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
522         HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", TRIGGER_RELEASE, "INNER_CODE", releaseCode);
523     ReleaseHandler(-1);
524 }
525 
526 /*
527  * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
528  */
OnError(int32_t code,const std::string & name,const std::string & message)529 void UIExtensionCallback::OnError(int32_t code, const std::string& name, const std::string& message)
530 {
531     LOGI(ATM_DOMAIN, ATM_TAG, "Code is %{public}d, name is %{public}s, message is %{public}s",
532         code, name.c_str(), message.c_str());
533     (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
534         HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", TRIGGER_ONERROR, "INNER_CODE", code);
535     ReleaseHandler(-1);
536 }
537 
538 /*
539  * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
540  * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
541  */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)542 void UIExtensionCallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
543 {
544     LOGI(ATM_DOMAIN, ATM_TAG, "Connect to UIExtensionAbility successfully.");
545 }
546 
547 /*
548  * when UIExtensionComponent destructed
549  */
OnDestroy()550 void UIExtensionCallback::OnDestroy()
551 {
552     LOGI(ATM_DOMAIN, ATM_TAG, "UIExtensionAbility destructed.");
553     if (isOnResult_.load() == false) {
554         (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
555             HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", TRIGGER_DESTROY);
556     }
557     ReleaseHandler(-1);
558 }
559 
CreateUIExtension(std::shared_ptr<RequestAsyncContext> asyncContext)560 static void CreateUIExtension(std::shared_ptr<RequestAsyncContext> asyncContext)
561 {
562     AAFwk::Want want;
563     want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantAbilityName);
564     want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
565     want.SetParam(STATE_KEY, asyncContext->permissionsState);
566     want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
567 
568     auto uiExtCallback = std::make_shared<UIExtensionCallback>(asyncContext);
569     Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
570         [uiExtCallback](int32_t releaseCode) {
571             uiExtCallback->OnRelease(releaseCode);
572         },
573         [uiExtCallback](int32_t resultCode, const AAFwk::Want &result) {
574             uiExtCallback->OnResult(resultCode, result);
575         },
576         [uiExtCallback](const AAFwk::WantParams &receive) {
577             uiExtCallback->OnReceive(receive);
578         },
579         [uiExtCallback](int32_t code, const std::string &name, [[maybe_unused]] const std::string &message) {
580             uiExtCallback->OnError(code, name, name);
581         },
582         [uiExtCallback](const std::shared_ptr<Ace::ModalUIExtensionProxy> &uiProxy) {
583             uiExtCallback->OnRemoteReady(uiProxy);
584         },
585         [uiExtCallback]() {
586             uiExtCallback->OnDestroy();
587         },
588     };
589     CreateUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback);
590 }
591 
592 
RequestPermissionsFromUser(napi_env env,napi_callback_info info)593 napi_value NapiRequestPermission::RequestPermissionsFromUser(napi_env env, napi_callback_info info)
594 {
595     LOGD(ATM_DOMAIN, ATM_TAG, "RequestPermissionsFromUser begin.");
596     // use handle to protect asyncContext
597     std::shared_ptr<RequestAsyncContext> asyncContext = std::make_shared<RequestAsyncContext>(env);
598 
599     if (!ParseRequestPermissionFromUser(env, info, asyncContext)) {
600         return nullptr;
601     }
602     auto asyncContextHandle = std::make_unique<RequestAsyncContextHandle>(asyncContext);
603     napi_value result = nullptr;
604     if (asyncContextHandle->asyncContextPtr->callbackRef == nullptr) {
605         NAPI_CALL(env, napi_create_promise(env, &(asyncContextHandle->asyncContextPtr->deferred), &result));
606     } else {
607         NAPI_CALL(env, napi_get_undefined(env, &result));
608     }
609 
610     napi_value resource = nullptr; // resource name
611     NAPI_CALL(env, napi_create_string_utf8(env, "RequestPermissionsFromUser", NAPI_AUTO_LENGTH, &resource));
612     NAPI_CALL(env, napi_create_async_work(
613         env, nullptr, resource, RequestPermissionsFromUserExecute, RequestPermissionsFromUserComplete,
614         reinterpret_cast<void*>(asyncContextHandle.get()), &(asyncContextHandle->asyncContextPtr->work)));
615 
616     NAPI_CALL(env,
617         napi_queue_async_work_with_qos(env, asyncContextHandle->asyncContextPtr->work, napi_qos_user_initiated));
618 
619     LOGD(ATM_DOMAIN, ATM_TAG, "RequestPermissionsFromUser end.");
620     asyncContextHandle.release();
621     return result;
622 }
623 
ParseRequestPermissionFromUser(const napi_env & env,const napi_callback_info & cbInfo,std::shared_ptr<RequestAsyncContext> & asyncContext)624 bool NapiRequestPermission::ParseRequestPermissionFromUser(const napi_env& env,
625     const napi_callback_info& cbInfo, std::shared_ptr<RequestAsyncContext>& asyncContext)
626 {
627     size_t argc = MAX_PARAMS_THREE;
628     napi_value argv[MAX_PARAMS_THREE] = { nullptr };
629     napi_value thisVar = nullptr;
630 
631     if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
632         LOGE(ATM_DOMAIN, ATM_TAG, "Napi_get_cb_info failed");
633         return false;
634     }
635     if (argc < MAX_PARAMS_THREE - 1) {
636         NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env,
637             JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
638         return false;
639     }
640     asyncContext->env = env;
641     std::string errMsg;
642 
643     // argv[0] : context : AbilityContext
644     if (GetContext(env, argv[0], asyncContext) == nullptr) {
645         errMsg = GetParamErrorMsg("context", "UIAbility or UIExtension Context");
646         NAPI_CALL_BASE(
647             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
648         return false;
649     }
650     LOGI(ATM_DOMAIN, ATM_TAG, "AsyncContext.uiAbilityFlag is: %{public}d.", asyncContext->uiAbilityFlag);
651 
652     // argv[1] : permissionList
653     if (!ParseStringArray(env, argv[1], asyncContext->permissionList) ||
654         (asyncContext->permissionList.empty())) {
655         errMsg = GetParamErrorMsg("permissionList", "Array<Permissions>");
656         NAPI_CALL_BASE(
657             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
658         return false;
659     }
660 
661     if (argc == MAX_PARAMS_THREE) {
662         // argv[2] : callback
663         if (!IsUndefinedOrNull(env, argv[2]) && !ParseCallback(env, argv[2], asyncContext->callbackRef)) {
664             errMsg = GetParamErrorMsg("callback", "Callback<PermissionRequestResult>");
665             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
666             return false;
667         }
668     }
669 #ifdef EVENTHANDLER_ENABLE
670     asyncContext->handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
671 #endif
672     return true;
673 }
674 
ReportHisysEventReqPermsFromUserBehavior(std::string bundleName,bool uiExtensionFlag)675 static inline void ReportHisysEventReqPermsFromUserBehavior(std::string bundleName, bool uiExtensionFlag)
676 {
677     (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQUEST_PERMISSIONS_FROM_USER",
678         HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
679         "BUNDLENAME", bundleName, "UIEXTENSION_FLAG", uiExtensionFlag);
680 }
681 
RequestPermissionsFromUserExecute(napi_env env,void * data)682 void NapiRequestPermission::RequestPermissionsFromUserExecute(napi_env env, void* data)
683 {
684     // asyncContext release in complete.
685     RequestAsyncContextHandle* asyncContextHandle = reinterpret_cast<RequestAsyncContextHandle*>(data);
686     if (asyncContextHandle == nullptr || asyncContextHandle->asyncContextPtr == nullptr) {
687         LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
688         return;
689     }
690     static AccessTokenID selfTokenID = static_cast<AccessTokenID>(GetSelfTokenID());
691     if (asyncContextHandle->asyncContextPtr->tokenId != selfTokenID) {
692         LOGE(ATM_DOMAIN, ATM_TAG, "The context tokenID: %{public}d, selfTokenID: %{public}d.",
693             asyncContextHandle->asyncContextPtr->tokenId, selfTokenID);
694         asyncContextHandle->asyncContextPtr->result.errorCode = RET_FAILED;
695         asyncContextHandle->asyncContextPtr->result.errorMsg =
696             "The specified context does not belong to the current application.";
697         (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQ_PERM_FROM_USER_ERROR",
698             HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_CODE", TOKENID_INCONSISTENCY,
699             "SELF_TOKEN", selfTokenID, "CONTEXT_TOKEN", asyncContextHandle->asyncContextPtr->tokenId);
700         return;
701     }
702 
703     if (!IsDynamicRequest(asyncContextHandle->asyncContextPtr)) {
704         LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission");
705         asyncContextHandle->asyncContextPtr->needDynamicRequest = false;
706         return;
707     }
708     GetInstanceId(asyncContextHandle->asyncContextPtr);
709     std::string bundleName = asyncContextHandle->asyncContextPtr->bundleName;
710     // service extension dialog
711     if (asyncContextHandle->asyncContextPtr->info.grantBundleName == ORI_PERMISSION_MANAGER_BUNDLE_NAME) {
712         LOGI(ATM_DOMAIN, ATM_TAG, "Pop service extension dialog, uiContentFlag=%{public}d",
713             asyncContextHandle->asyncContextPtr->uiContentFlag);
714         if (asyncContextHandle->asyncContextPtr->uiContentFlag) {
715             RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr);
716         } else {
717             CreateServiceExtension(asyncContextHandle->asyncContextPtr);
718         }
719     } else if (asyncContextHandle->asyncContextPtr->instanceId == -1) {
720         LOGI(ATM_DOMAIN, ATM_TAG, "Pop service extension dialog, instanceId is -1.");
721         CreateServiceExtension(asyncContextHandle->asyncContextPtr);
722         ReportHisysEventReqPermsFromUserBehavior(bundleName, false);
723     } else {
724         LOGI(ATM_DOMAIN, ATM_TAG, "Pop ui extension dialog");
725         asyncContextHandle->asyncContextPtr->uiExtensionFlag = true;
726         RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr);
727         ReportHisysEventReqPermsFromUserBehavior(bundleName, asyncContextHandle->asyncContextPtr->uiExtensionFlag);
728         if (!asyncContextHandle->asyncContextPtr->uiExtensionFlag) {
729             LOGW(ATM_DOMAIN, ATM_TAG, "Pop uiextension dialog fail, start to pop service extension dialog.");
730             RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr);
731         }
732     }
733 }
734 
RequestPermissionsFromUserComplete(napi_env env,napi_status status,void * data)735 void NapiRequestPermission::RequestPermissionsFromUserComplete(napi_env env, napi_status status, void* data)
736 {
737     RequestAsyncContextHandle* asyncContextHandle = reinterpret_cast<RequestAsyncContextHandle*>(data);
738     if (asyncContextHandle == nullptr || asyncContextHandle->asyncContextPtr == nullptr) {
739         LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
740         return;
741     }
742     std::unique_ptr<RequestAsyncContextHandle> callbackPtr {asyncContextHandle};
743 
744     if (asyncContextHandle->asyncContextPtr->needDynamicRequest) {
745         return;
746     }
747     if ((asyncContextHandle->asyncContextPtr->permissionsState.empty()) &&
748         (asyncContextHandle->asyncContextPtr->result.errorCode == RET_SUCCESS)) {
749         LOGE(ATM_DOMAIN, ATM_TAG, "GrantResults empty");
750         asyncContextHandle->asyncContextPtr->result.errorCode = RET_FAILED;
751     }
752     napi_value requestResult = WrapRequestResult(env, asyncContextHandle->asyncContextPtr->permissionList,
753         asyncContextHandle->asyncContextPtr->permissionsState, asyncContextHandle->asyncContextPtr->dialogShownResults,
754         asyncContextHandle->asyncContextPtr->errorReasons);
755     if (requestResult == nullptr) {
756         LOGE(ATM_DOMAIN, ATM_TAG, "Wrap requestResult failed");
757         if (asyncContextHandle->asyncContextPtr->result.errorCode == RET_SUCCESS) {
758             asyncContextHandle->asyncContextPtr->result.errorCode = RET_FAILED;
759         }
760     } else {
761         asyncContextHandle->asyncContextPtr->requestResult = requestResult;
762     }
763     if (asyncContextHandle->asyncContextPtr->deferred != nullptr) {
764         ReturnPromiseResult(
765             env, *asyncContextHandle->asyncContextPtr, asyncContextHandle->asyncContextPtr->requestResult);
766     } else {
767         ReturnCallbackResult(
768             env, *asyncContextHandle->asyncContextPtr, asyncContextHandle->asyncContextPtr->requestResult);
769     }
770 }
771 
GetPermissionsStatus(napi_env env,napi_callback_info info)772 napi_value NapiRequestPermission::GetPermissionsStatus(napi_env env, napi_callback_info info)
773 {
774     LOGD(ATM_DOMAIN, ATM_TAG, "GetPermissionsStatus begin.");
775 
776     auto* asyncContext = new (std::nothrow) RequestAsyncContext(env);
777     if (asyncContext == nullptr) {
778         LOGE(ATM_DOMAIN, ATM_TAG, "New struct fail.");
779         return nullptr;
780     }
781 
782     std::unique_ptr<RequestAsyncContext> context {asyncContext};
783     if (!ParseInputToGetQueryResult(env, info, *asyncContext)) {
784         return nullptr;
785     }
786 
787     napi_value result = nullptr;
788     napi_create_promise(env, &(asyncContext->deferred), &result); // create delay promise object
789 
790     napi_value resource = nullptr; // resource name
791     napi_create_string_utf8(env, "GetPermissionsStatus", NAPI_AUTO_LENGTH, &resource);
792 
793     napi_create_async_work(
794         env, nullptr, resource, GetPermissionsStatusExecute, GetPermissionsStatusComplete,
795         reinterpret_cast<void*>(asyncContext), &(asyncContext->work));
796     // add async work handle to the napi queue and wait for result
797     napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default);
798 
799     LOGD(ATM_DOMAIN, ATM_TAG, "GetPermissionsStatus end.");
800     context.release();
801     return result;
802 }
803 
ParseInputToGetQueryResult(const napi_env & env,const napi_callback_info & info,RequestAsyncContext & asyncContext)804 bool NapiRequestPermission::ParseInputToGetQueryResult(const napi_env& env, const napi_callback_info& info,
805     RequestAsyncContext& asyncContext)
806 {
807     size_t argc = MAX_PARAMS_TWO;
808     napi_value argv[MAX_PARAMS_TWO] = { nullptr };
809     napi_value thatVar = nullptr;
810 
811     void* data = nullptr;
812     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thatVar, &data), false);
813     // 1: can request permissions minnum argc
814     if (argc < MAX_PARAMS_TWO - 1) {
815         NAPI_CALL_BASE(env, napi_throw(env,
816             GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
817         return false;
818     }
819 
820     std::string errMsg;
821     asyncContext.env = env;
822     // the first parameter of argv
823     if (!ParseUint32(env, argv[0], asyncContext.tokenId)) {
824         errMsg = GetParamErrorMsg("tokenID", "number");
825         NAPI_CALL_BASE(env,
826             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
827         return false;
828     }
829 
830     // the second parameter of argv
831     if (!ParseStringArray(env, argv[1], asyncContext.permissionList)) {
832         errMsg = GetParamErrorMsg("permissionList", "Array<Permissions>");
833         NAPI_CALL_BASE(
834             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
835         return false;
836     }
837     LOGD(ATM_DOMAIN, ATM_TAG, "TokenID = %{public}d, permissionList size = %{public}zu", asyncContext.tokenId,
838         asyncContext.permissionList.size());
839     return true;
840 }
841 
GetPermissionsStatusExecute(napi_env env,void * data)842 void NapiRequestPermission::GetPermissionsStatusExecute(napi_env env, void* data)
843 {
844     RequestAsyncContext* asyncContext = reinterpret_cast<RequestAsyncContext*>(data);
845     if (asyncContext == nullptr) {
846         LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
847         return;
848     }
849 
850     std::vector<PermissionListState> permList;
851     for (const auto& permission : asyncContext->permissionList) {
852         LOGD(ATM_DOMAIN, ATM_TAG, "Permission: %{public}s.", permission.c_str());
853         PermissionListState permState;
854         permState.permissionName = permission;
855         permState.state = INVALID_OPER;
856         permList.emplace_back(permState);
857     }
858     LOGD(ATM_DOMAIN, ATM_TAG, "PermList size: %{public}zu, asyncContext->permissionList size: %{public}zu.",
859         permList.size(), asyncContext->permissionList.size());
860 
861     asyncContext->result.errorCode = AccessTokenKit::GetPermissionsStatus(asyncContext->tokenId, permList);
862     for (const auto& permState : permList) {
863         LOGD(ATM_DOMAIN, ATM_TAG, "Permission: %{public}s", permState.permissionName.c_str());
864         asyncContext->permissionQueryResults.emplace_back(permState.state);
865     }
866 }
867 
GetPermissionsStatusComplete(napi_env env,napi_status status,void * data)868 void NapiRequestPermission::GetPermissionsStatusComplete(napi_env env, napi_status status, void* data)
869 {
870     RequestAsyncContext* asyncContext = reinterpret_cast<RequestAsyncContext*>(data);
871     if (asyncContext == nullptr) {
872         LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
873         return;
874     }
875     std::unique_ptr<RequestAsyncContext> callbackPtr {asyncContext};
876 
877     if ((asyncContext->permissionQueryResults.empty()) && asyncContext->result.errorCode == RET_SUCCESS) {
878         LOGE(ATM_DOMAIN, ATM_TAG, "PermissionQueryResults empty");
879         asyncContext->result.errorCode = RET_FAILED;
880         asyncContext->result.errorMsg = "The permissionList is empty.";
881     }
882     napi_value result;
883     NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &result));
884 
885     for (size_t i = 0; i < asyncContext->permissionQueryResults.size(); i++) {
886         napi_value nPermissionQueryResult = nullptr;
887         NAPI_CALL_RETURN_VOID(env, napi_create_int32(env,
888             asyncContext->permissionQueryResults[i], &nPermissionQueryResult));
889         NAPI_CALL_RETURN_VOID(env, napi_set_element(env, result, i, nPermissionQueryResult));
890     }
891     ReturnPromiseResult(env, *asyncContext, result);
892 }
893 
CheckDynamicRequest(std::shared_ptr<RequestAsyncContext> & asyncContext,bool & isDynamic)894 void RequestAsyncInstanceControl::CheckDynamicRequest(
895     std::shared_ptr<RequestAsyncContext>& asyncContext, bool& isDynamic)
896 {
897     asyncContext->permissionsState.clear();
898     asyncContext->dialogShownResults.clear();
899     asyncContext->errorReasons.clear();
900     if (!NapiRequestPermission::IsDynamicRequest(asyncContext)) {
901         LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission exsion");
902         RequestResultsHandler(asyncContext->permissionList, asyncContext->permissionsState, asyncContext);
903         return;
904     }
905     isDynamic = true;
906 }
907 
AddCallbackByInstanceId(std::shared_ptr<RequestAsyncContext> & asyncContext)908 void RequestAsyncInstanceControl::AddCallbackByInstanceId(std::shared_ptr<RequestAsyncContext>& asyncContext)
909 {
910     LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d", asyncContext->instanceId);
911     {
912         std::lock_guard<std::mutex> lock(instanceIdMutex_);
913         auto iter = instanceIdMap_.find(asyncContext->instanceId);
914         // id is existed mean a pop window is showing, add context to waiting queue
915         if (iter != instanceIdMap_.end()) {
916             LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d has existed.", asyncContext->instanceId);
917             instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext);
918             return;
919         }
920         // make sure id is in map to indicate a pop-up window is showing
921         instanceIdMap_[asyncContext->instanceId] = {};
922     }
923 
924     if (asyncContext->uiExtensionFlag) {
925         CreateUIExtension(asyncContext);
926     } else {
927         CreateServiceExtension(asyncContext);
928     }
929 }
930 
ExecCallback(int32_t id)931 void RequestAsyncInstanceControl::ExecCallback(int32_t id)
932 {
933     std::shared_ptr<RequestAsyncContext> asyncContext = nullptr;
934     bool isDynamic = false;
935     {
936         std::lock_guard<std::mutex> lock(instanceIdMutex_);
937         auto iter = instanceIdMap_.find(id);
938         if (iter == instanceIdMap_.end()) {
939             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id);
940             return;
941         }
942         while (!iter->second.empty()) {
943             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size());
944             asyncContext = iter->second[0];
945             if (asyncContext == nullptr) {
946                 LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
947                 iter->second.erase(iter->second.begin());
948                 continue;
949             }
950             iter->second.erase(iter->second.begin());
951             CheckDynamicRequest(asyncContext, isDynamic);
952             if (isDynamic) {
953                 break;
954             }
955         }
956         if (iter->second.empty()) {
957             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map is empty", id);
958             instanceIdMap_.erase(id);
959         }
960     }
961     if (isDynamic) {
962         if (asyncContext->uiExtensionFlag) {
963             CreateUIExtension(asyncContext);
964         } else {
965             CreateServiceExtension(asyncContext);
966         }
967     }
968 }
969 }  // namespace AccessToken
970 }  // namespace Security
971 }  // namespace OHOS