• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 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_on_setting.h"
16 
17 #include "ability.h"
18 #include "accesstoken_kit.h"
19 #include "accesstoken_common_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 std::map<int32_t, std::vector<std::shared_ptr<RequestPermOnSettingAsyncContext>>>
28     RequestOnSettingAsyncInstanceControl::instanceIdMap_;
29 std::mutex RequestOnSettingAsyncInstanceControl::instanceIdMutex_;
30 namespace {
31 const std::string PERMISSION_KEY = "ohos.user.setting.permission";
32 const std::string PERMISSION_RESULT_KEY = "ohos.user.setting.permission.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_ALREADY_EXIST = 1;
39 const int32_t PERM_NOT_BELONG_TO_SAME_GROUP = 2;
40 const int32_t PERM_IS_NOT_DECLARE = 3;
41 const int32_t ALL_PERM_GRANTED = 4;
42 const int32_t PERM_REVOKE_BY_USER = 5;
43 std::mutex g_lockFlag;
44 } // namespace
45 
TransferToJsErrorCode(int32_t errCode)46 static int32_t TransferToJsErrorCode(int32_t errCode)
47 {
48     int32_t jsCode = JS_OK;
49     switch (errCode) {
50         case RET_SUCCESS:
51             jsCode = JS_OK;
52             break;
53         case REQUEST_ALREADY_EXIST:
54             jsCode = JS_ERROR_REQUEST_IS_ALREADY_EXIST;
55             break;
56         case PERM_NOT_BELONG_TO_SAME_GROUP:
57             jsCode = JS_ERROR_PARAM_INVALID;
58             break;
59         case PERM_IS_NOT_DECLARE:
60             jsCode = JS_ERROR_PARAM_INVALID;
61             break;
62         case ALL_PERM_GRANTED:
63             jsCode = JS_ERROR_ALL_PERM_GRANTED;
64             break;
65         case PERM_REVOKE_BY_USER:
66             jsCode = JS_ERROR_PERM_REVOKE_BY_USER;
67             break;
68         default:
69             jsCode = JS_ERROR_INNER;
70             break;
71     }
72     LOGI(ATM_DOMAIN, ATM_TAG, "dialog error(%{public}d) jsCode(%{public}d).", errCode, jsCode);
73     return jsCode;
74 }
75 
ReturnPromiseResult(napi_env env,const RequestPermOnSettingAsyncContext & context,napi_value result)76 static void ReturnPromiseResult(napi_env env, const RequestPermOnSettingAsyncContext& context, napi_value result)
77 {
78     if (context.result.errorCode != RET_SUCCESS) {
79         int32_t jsCode = TransferToJsErrorCode(context.result.errorCode);
80         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode, context.result.errorMsg));
81         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context.deferred, businessError));
82     } else {
83         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context.deferred, result));
84     }
85 }
86 
WrapVoidToJS(napi_env env)87 static napi_value WrapVoidToJS(napi_env env)
88 {
89     napi_value result = nullptr;
90     NAPI_CALL(env, napi_get_null(env, &result));
91     return result;
92 }
93 
GetUIContent(std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)94 static Ace::UIContent* GetUIContent(std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)
95 {
96     if (asyncContext == nullptr) {
97         return nullptr;
98     }
99     Ace::UIContent* uiContent = nullptr;
100     if (asyncContext->uiAbilityFlag) {
101         uiContent = asyncContext->abilityContext->GetUIContent();
102     } else {
103         uiContent = asyncContext->uiExtensionContext->GetUIContent();
104     }
105     return uiContent;
106 }
107 
GetContext(const napi_env & env,const napi_value & value,std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext)108 static napi_value GetContext(
109     const napi_env &env, const napi_value &value, std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext)
110 {
111     bool stageMode = false;
112     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
113     if (status != napi_ok || !stageMode) {
114         LOGE(ATM_DOMAIN, ATM_TAG, "It is not a stage mode.");
115         return nullptr;
116     } else {
117         auto context = AbilityRuntime::GetStageModeContext(env, value);
118         if (context == nullptr) {
119             LOGE(ATM_DOMAIN, ATM_TAG, "Failed to Get application context.");
120             return nullptr;
121         }
122         asyncContext->abilityContext =
123             AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
124         if (asyncContext->abilityContext != nullptr) {
125             asyncContext->uiAbilityFlag = true;
126         } else {
127             LOGW(ATM_DOMAIN, ATM_TAG, "Failed to convert to ability context.");
128             asyncContext->uiExtensionContext =
129                 AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
130             if (asyncContext->uiExtensionContext == nullptr) {
131                 LOGE(ATM_DOMAIN, ATM_TAG, "Failed to convert to ui extension context.");
132                 return nullptr;
133             }
134         }
135         return WrapVoidToJS(env);
136     }
137 }
138 
WrapRequestResult(const napi_env & env,const std::vector<int32_t> & pemResults)139 static napi_value WrapRequestResult(const napi_env& env, const std::vector<int32_t>& pemResults)
140 {
141     napi_value result;
142     NAPI_CALL(env, napi_create_array(env, &result));
143 
144     for (size_t i = 0; i < pemResults.size(); i++) {
145         napi_value nPermissionResult = nullptr;
146         NAPI_CALL(env, napi_create_int32(env, pemResults[i], &nPermissionResult));
147         NAPI_CALL(env, napi_set_element(env, result, i, nPermissionResult));
148     }
149     return result;
150 }
151 
PermissionResultsCallbackUI(int32_t errorCode,const std::vector<int32_t> stateList,std::shared_ptr<RequestPermOnSettingAsyncContext> & data)152 static void PermissionResultsCallbackUI(int32_t errorCode,
153     const std::vector<int32_t> stateList, std::shared_ptr<RequestPermOnSettingAsyncContext>& data)
154 {
155     auto* retCB = new (std::nothrow) PermissonOnSettingResultCallback();
156     if (retCB == nullptr) {
157         LOGE(ATM_DOMAIN, ATM_TAG, "Insufficient memory for work!");
158         return;
159     }
160 
161     std::unique_ptr<PermissonOnSettingResultCallback> callbackPtr {retCB};
162     retCB->errorCode = errorCode;
163     retCB->stateList = stateList;
164     retCB->data = data;
165     auto task = [retCB]() {
166         std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext = retCB->data;
167         if (asyncContext == nullptr) {
168             delete retCB;
169             return;
170         }
171 
172         asyncContext->result.errorCode = retCB->errorCode;
173         napi_handle_scope scope = nullptr;
174         napi_open_handle_scope(asyncContext->env, &scope);
175         if (scope == nullptr) {
176             LOGE(ATM_DOMAIN, ATM_TAG, "Napi_open_handle_scope failed");
177             delete retCB;
178             return;
179         }
180         napi_value requestResult = WrapRequestResult(asyncContext->env, retCB->stateList);
181         if ((asyncContext->result.errorCode == RET_SUCCESS) && (requestResult == nullptr)) {
182             LOGE(ATM_DOMAIN, ATM_TAG, "Wrap requestResult failed");
183             asyncContext->result.errorCode = RET_FAILED;
184         }
185 
186         ReturnPromiseResult(asyncContext->env, *asyncContext, requestResult);
187         napi_close_handle_scope(asyncContext->env, scope);
188         delete retCB;
189     };
190     if (napi_status::napi_ok != napi_send_event(data->env, task, napi_eprio_immediate)) {
191         LOGE(ATM_DOMAIN, ATM_TAG, "PermissionResultsCallbackUI: Failed to SendEvent");
192     } else {
193         callbackPtr.release();
194     }
195 }
196 
CloseModalUIExtensionMainThread(std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext,int32_t sessionId)197 static void CloseModalUIExtensionMainThread(std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext,
198     int32_t sessionId)
199 {
200     auto task = [asyncContext, sessionId]() {
201         Ace::UIContent* uiContent = GetUIContent(asyncContext);
202         if (uiContent == nullptr) {
203             LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
204             return;
205         }
206         LOGI(ATM_DOMAIN, ATM_TAG, "Close uiextension component");
207         uiContent->CloseModalUIExtension(sessionId);
208     };
209 #ifdef EVENTHANDLER_ENABLE
210     if (asyncContext->handler_ != nullptr) {
211         asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread");
212     } else {
213         task();
214     }
215 #else
216     task();
217 #endif
218 }
219 
ReleaseHandler(int32_t code)220 void PermissonOnSettingUICallback::ReleaseHandler(int32_t code)
221 {
222     if (this->reqContext_ == nullptr) {
223         LOGE(ATM_DOMAIN, ATM_TAG, "Request context is null.");
224         return;
225     }
226     {
227         std::lock_guard<std::mutex> lock(g_lockFlag);
228         if (this->reqContext_->releaseFlag) {
229             LOGW(ATM_DOMAIN, ATM_TAG, "Callback has executed.");
230             return;
231         }
232         this->reqContext_->releaseFlag = true;
233     }
234     CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_);
235     if (code == -1) {
236         this->reqContext_->errorCode = code;
237     }
238     RequestOnSettingAsyncInstanceControl::UpdateQueueData(this->reqContext_);
239     RequestOnSettingAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId);
240     PermissionResultsCallbackUI(this->reqContext_->errorCode, this->reqContext_->stateList, this->reqContext_);
241 }
242 
PermissonOnSettingUICallback(const std::shared_ptr<RequestPermOnSettingAsyncContext> & reqContext)243 PermissonOnSettingUICallback::PermissonOnSettingUICallback(
244     const std::shared_ptr<RequestPermOnSettingAsyncContext>& reqContext)
245 {
246     this->reqContext_ = reqContext;
247 }
248 
~PermissonOnSettingUICallback()249 PermissonOnSettingUICallback::~PermissonOnSettingUICallback()
250 {}
251 
SetSessionId(int32_t sessionId)252 void PermissonOnSettingUICallback::SetSessionId(int32_t sessionId)
253 {
254     this->sessionId_ = sessionId;
255 }
256 
257 /*
258  * when UIExtensionAbility use terminateSelfWithResult
259  */
OnResult(int32_t resultCode,const AAFwk::Want & result)260 void PermissonOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
261 {
262     this->reqContext_->errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0);
263     this->reqContext_->stateList = result.GetIntArrayParam(PERMISSION_RESULT_KEY);
264     LOGI(ATM_DOMAIN, ATM_TAG, "ResultCode is %{public}d, errorCode=%{public}d, listSize=%{public}zu",
265         resultCode, this->reqContext_->errorCode, this->reqContext_->stateList.size());
266     ReleaseHandler(0);
267 }
268 
269 /*
270  * when UIExtensionAbility send message to UIExtensionComponent
271  */
OnReceive(const AAFwk::WantParams & receive)272 void PermissonOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive)
273 {
274     LOGI(ATM_DOMAIN, ATM_TAG, "Called!");
275 }
276 
277 /*
278  * when UIExtensionAbility disconnect or use terminate or process die
279  * releaseCode is 0 when process normal exit
280  */
OnRelease(int32_t releaseCode)281 void PermissonOnSettingUICallback::OnRelease(int32_t releaseCode)
282 {
283     LOGI(ATM_DOMAIN, ATM_TAG, "ReleaseCode is %{public}d", releaseCode);
284 
285     ReleaseHandler(-1);
286 }
287 
288 /*
289  * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
290  */
OnError(int32_t code,const std::string & name,const std::string & message)291 void PermissonOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
292 {
293     LOGI(ATM_DOMAIN, ATM_TAG, "Code is %{public}d, name is %{public}s, message is %{public}s",
294         code, name.c_str(), message.c_str());
295 
296     ReleaseHandler(-1);
297 }
298 
299 /*
300  * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
301  * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
302  */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)303 void PermissonOnSettingUICallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
304 {
305     LOGI(ATM_DOMAIN, ATM_TAG, "Connect to UIExtensionAbility successfully.");
306 }
307 
308 /*
309  * when UIExtensionComponent destructed
310  */
OnDestroy()311 void PermissonOnSettingUICallback::OnDestroy()
312 {
313     LOGI(ATM_DOMAIN, ATM_TAG, "UIExtensionAbility destructed.");
314     ReleaseHandler(-1);
315 }
316 
CreateUIExtensionMainThread(std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext,const AAFwk::Want & want,const Ace::ModalUIExtensionCallbacks & uiExtensionCallbacks,const std::shared_ptr<PermissonOnSettingUICallback> & uiExtCallback)317 static void CreateUIExtensionMainThread(std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext,
318     const AAFwk::Want& want, const Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks,
319     const std::shared_ptr<PermissonOnSettingUICallback>& uiExtCallback)
320 {
321     auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() {
322         Ace::UIContent* uiContent = GetUIContent(asyncContext);
323         if (uiContent == nullptr) {
324             LOGE(ATM_DOMAIN, ATM_TAG, "Failed to get ui content!");
325             asyncContext->result.errorCode = RET_FAILED;
326             return;
327         }
328 
329         Ace::ModalUIExtensionConfig config;
330         config.isProhibitBack = true;
331         config.isModalRequestFocus = false;
332         int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
333         LOGI(ATM_DOMAIN, ATM_TAG, "Create end, sessionId: %{public}d, tokenId: %{public}d.",
334             sessionId, asyncContext->tokenId);
335         if (sessionId == 0) {
336             LOGE(ATM_DOMAIN, ATM_TAG, "Failed to create component, sessionId is 0.");
337             asyncContext->result.errorCode = RET_FAILED;
338             return;
339         }
340         uiExtCallback->SetSessionId(sessionId);
341     };
342 #ifdef EVENTHANDLER_ENABLE
343     if (asyncContext->handler_ != nullptr) {
344         asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread");
345     } else {
346         task();
347     }
348 #else
349     task();
350 #endif
351 }
352 
CreateUIExtension(const Want & want,std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)353 static int32_t CreateUIExtension(const Want &want, std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)
354 {
355     auto uiExtCallback = std::make_shared<PermissonOnSettingUICallback>(asyncContext);
356     Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
357         [uiExtCallback](int32_t releaseCode) {
358             uiExtCallback->OnRelease(releaseCode);
359         },
360         [uiExtCallback](int32_t resultCode, const AAFwk::Want &result) {
361             uiExtCallback->OnResult(resultCode, result);
362         },
363         [uiExtCallback](const AAFwk::WantParams &receive) {
364             uiExtCallback->OnReceive(receive);
365         },
366         [uiExtCallback](int32_t code, const std::string &name, [[maybe_unused]] const std::string &message) {
367             uiExtCallback->OnError(code, name, name);
368         },
369         [uiExtCallback](const std::shared_ptr<Ace::ModalUIExtensionProxy> &uiProxy) {
370             uiExtCallback->OnRemoteReady(uiProxy);
371         },
372         [uiExtCallback]() {
373             uiExtCallback->OnDestroy();
374         },
375     };
376 
377     CreateUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback);
378     if (asyncContext->result.errorCode == RET_FAILED) {
379         return RET_FAILED;
380     }
381     return RET_SUCCESS;
382 }
383 
StartUIExtension(std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)384 static int32_t StartUIExtension(std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)
385 {
386     AAFwk::Want want;
387     AccessTokenKit::GetPermissionManagerInfo(asyncContext->info);
388     LOGI(ATM_DOMAIN, ATM_TAG, "bundleName: %{public}s, permStateAbilityName: %{public}s.",
389         asyncContext->info.grantBundleName.c_str(), asyncContext->info.permStateAbilityName.c_str());
390     want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.permStateAbilityName);
391     want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
392     want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
393     return CreateUIExtension(want, asyncContext);
394 }
395 
GetInstanceId(std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext)396 static void GetInstanceId(std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext)
397 {
398     auto task = [asyncContext]() {
399         Ace::UIContent* uiContent = GetUIContent(asyncContext);
400         if (uiContent == nullptr) {
401             LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
402             return;
403         }
404         asyncContext->instanceId = uiContent->GetInstanceId();
405     };
406 #ifdef EVENTHANDLER_ENABLE
407     if (asyncContext->handler_ != nullptr) {
408         asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId");
409     } else {
410         task();
411     }
412 #else
413     task();
414 #endif
415     LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d", asyncContext->instanceId);
416 }
417 
AddCallbackByInstanceId(std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext)418 void RequestOnSettingAsyncInstanceControl::AddCallbackByInstanceId(
419     std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext)
420 {
421     LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d", asyncContext->instanceId);
422     {
423         std::lock_guard<std::mutex> lock(instanceIdMutex_);
424         auto iter = instanceIdMap_.find(asyncContext->instanceId);
425         // id is existed mean a pop window is showing, add context to waiting queue
426         if (iter != instanceIdMap_.end()) {
427             LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d has existed.", asyncContext->instanceId);
428             instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext);
429             return;
430         }
431         // make sure id is in map to indicate a pop-up window is showing
432         instanceIdMap_[asyncContext->instanceId] = {};
433     }
434     (void)StartUIExtension(asyncContext);
435 }
436 
CheckPermList(std::vector<std::string> permList,std::vector<std::string> tmpPermList)437 bool static CheckPermList(std::vector<std::string> permList, std::vector<std::string> tmpPermList)
438 {
439     if (permList.size() != tmpPermList.size()) {
440         LOGI(ATM_DOMAIN, ATM_TAG, "Perm list size not equal, CurrentPermList size: %{public}zu.", tmpPermList.size());
441         return false;
442     }
443 
444     for (const auto& item : permList) {
445         auto iter = std::find_if(tmpPermList.begin(), tmpPermList.end(), [item](const std::string& perm) {
446             return item == perm;
447         });
448         if (iter == tmpPermList.end()) {
449             LOGI(ATM_DOMAIN, ATM_TAG, "Different permission lists.");
450             return false;
451         }
452     }
453     return true;
454 }
455 
UpdateQueueData(const std::shared_ptr<RequestPermOnSettingAsyncContext> & reqContext)456 void RequestOnSettingAsyncInstanceControl::UpdateQueueData(
457     const std::shared_ptr<RequestPermOnSettingAsyncContext>& reqContext)
458 {
459     if (reqContext->errorCode != RET_SUCCESS) {
460         LOGI(ATM_DOMAIN, ATM_TAG, "The queue data does not need to be updated.");
461         return;
462     }
463     for (const int32_t item : reqContext->stateList) {
464         if (item != PERMISSION_GRANTED) {
465             LOGI(ATM_DOMAIN, ATM_TAG, "The queue data does not need to be updated");
466             return;
467         }
468     }
469 
470     {
471         std::lock_guard<std::mutex> lock(instanceIdMutex_);
472         int32_t id = reqContext->instanceId;
473         auto iter = instanceIdMap_.find(id);
474         if (iter == instanceIdMap_.end()) {
475             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id);
476             return;
477         }
478         std::vector<std::string> permList = reqContext->permissionList;
479         LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size());
480         for (auto& asyncContext : iter->second) {
481             if (asyncContext == nullptr) {
482                 LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
483                 continue;
484             }
485             std::vector<std::string> tmpPermList = asyncContext->permissionList;
486 
487             if (CheckPermList(permList, tmpPermList)) {
488                 asyncContext->errorCode = reqContext->errorCode;
489                 asyncContext->stateList = reqContext->stateList;
490                 asyncContext->isDynamic = false;
491             }
492         }
493     }
494 }
495 
ExecCallback(int32_t id)496 void RequestOnSettingAsyncInstanceControl::ExecCallback(int32_t id)
497 {
498     std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext = nullptr;
499     bool isDynamic = false;
500     {
501         std::lock_guard<std::mutex> lock(instanceIdMutex_);
502         auto iter = instanceIdMap_.find(id);
503         if (iter == instanceIdMap_.end()) {
504             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id);
505             return;
506         }
507         while (!iter->second.empty()) {
508             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size());
509             asyncContext = iter->second[0];
510             if (asyncContext == nullptr) {
511                 LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
512                 iter->second.erase(iter->second.begin());
513                 continue;
514             }
515             iter->second.erase(iter->second.begin());
516             CheckDynamicRequest(asyncContext, isDynamic);
517             if (isDynamic) {
518                 break;
519             }
520         }
521         if (iter->second.empty()) {
522             LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map is empty", id);
523             instanceIdMap_.erase(id);
524         }
525     }
526     if (isDynamic) {
527         (void)StartUIExtension(asyncContext);
528     }
529 }
530 
CheckDynamicRequest(std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext,bool & isDynamic)531 void RequestOnSettingAsyncInstanceControl::CheckDynamicRequest(
532     std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext, bool& isDynamic)
533 {
534     isDynamic = asyncContext->isDynamic;
535     if (!isDynamic) {
536         LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission exsion");
537         PermissionResultsCallbackUI(asyncContext->errorCode, asyncContext->stateList, asyncContext);
538         return;
539     }
540 }
541 
RequestPermissionOnSetting(napi_env env,napi_callback_info info)542 napi_value NapiRequestPermissionOnSetting::RequestPermissionOnSetting(napi_env env, napi_callback_info info)
543 {
544     LOGD(ATM_DOMAIN, ATM_TAG, "RequestPermissionOnSetting begin.");
545     // use handle to protect asyncContext
546     std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext =
547         std::make_shared<RequestPermOnSettingAsyncContext>(env);
548 
549     if (!ParseRequestPermissionOnSetting(env, info, asyncContext)) {
550         return nullptr;
551     }
552     auto asyncContextHandle = std::make_unique<RequestOnSettingAsyncContextHandle>(asyncContext);
553     if (asyncContextHandle->asyncContextPtr == nullptr) {
554         LOGE(ATM_DOMAIN, ATM_TAG, "Async context is null.");
555         return nullptr;
556     }
557     napi_value result = nullptr;
558     if (asyncContextHandle->asyncContextPtr->callbackRef == nullptr) {
559         NAPI_CALL(env, napi_create_promise(env, &(asyncContextHandle->asyncContextPtr->deferred), &result));
560     } else {
561         NAPI_CALL(env, napi_get_undefined(env, &result));
562     }
563 
564     napi_value resource = nullptr; // resource name
565     NAPI_CALL(env, napi_create_string_utf8(env, "RequestPermissionOnSetting", NAPI_AUTO_LENGTH, &resource));
566     NAPI_CALL(env, napi_create_async_work(
567         env, nullptr, resource, RequestPermissionOnSettingExecute, RequestPermissionOnSettingComplete,
568         reinterpret_cast<void*>(asyncContextHandle.get()), &(asyncContextHandle->asyncContextPtr->work)));
569 
570     NAPI_CALL(env,
571         napi_queue_async_work_with_qos(env, asyncContextHandle->asyncContextPtr->work, napi_qos_user_initiated));
572 
573     LOGD(ATM_DOMAIN, ATM_TAG, "RequestPermissionOnSetting end.");
574     asyncContextHandle.release();
575     return result;
576 }
577 
ParseRequestPermissionOnSetting(const napi_env & env,const napi_callback_info & cbInfo,std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext)578 bool NapiRequestPermissionOnSetting::ParseRequestPermissionOnSetting(const napi_env& env,
579     const napi_callback_info& cbInfo, std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext)
580 {
581     size_t argc = MAX_PARAMS_TWO;
582     napi_value argv[MAX_PARAMS_TWO] = { nullptr };
583     napi_value thisVar = nullptr;
584 
585     if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
586         LOGE(ATM_DOMAIN, ATM_TAG, "Napi_get_cb_info failed");
587         return false;
588     }
589     if (argc < MAX_PARAMS_TWO) {
590         NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env,
591             JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
592         return false;
593     }
594     asyncContext->env = env;
595     std::string errMsg;
596 
597     // argv[0] : context : AbilityContext
598     if (GetContext(env, argv[0], asyncContext) == nullptr) {
599         errMsg = GetParamErrorMsg("context", "UIAbility or UIExtension Context");
600         NAPI_CALL_BASE(
601             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
602         return false;
603     }
604     LOGI(ATM_DOMAIN, ATM_TAG, "AsyncContext.uiAbilityFlag is: %{public}d.", asyncContext->uiAbilityFlag);
605 
606     // argv[1] : permissionList
607     if (!ParseStringArray(env, argv[1], asyncContext->permissionList) ||
608         (asyncContext->permissionList.empty())) {
609         errMsg = GetParamErrorMsg("permissionList", "Array<Permissions>");
610         NAPI_CALL_BASE(
611             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
612         return false;
613     }
614 #ifdef EVENTHANDLER_ENABLE
615     asyncContext->handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
616 #endif
617     return true;
618 }
619 
RequestPermissionOnSettingExecute(napi_env env,void * data)620 void NapiRequestPermissionOnSetting::RequestPermissionOnSettingExecute(napi_env env, void* data)
621 {
622     // asyncContext release in complete
623     RequestOnSettingAsyncContextHandle* asyncContextHandle =
624         reinterpret_cast<RequestOnSettingAsyncContextHandle*>(data);
625     if ((asyncContextHandle == nullptr) || (asyncContextHandle->asyncContextPtr == nullptr)) {
626         return;
627     }
628     if (asyncContextHandle->asyncContextPtr->uiAbilityFlag) {
629         if ((asyncContextHandle->asyncContextPtr->abilityContext == nullptr) ||
630             (asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo() == nullptr)) {
631             return;
632         }
633         asyncContextHandle->asyncContextPtr->tokenId =
634             asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo()->accessTokenId;
635     } else {
636         if ((asyncContextHandle->asyncContextPtr->uiExtensionContext == nullptr) ||
637             (asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo() == nullptr)) {
638             return;
639         }
640         asyncContextHandle->asyncContextPtr->tokenId =
641             asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo()->accessTokenId;
642     }
643     static AccessTokenID currToken = static_cast<AccessTokenID>(GetSelfTokenID());
644     if (asyncContextHandle->asyncContextPtr->tokenId != currToken) {
645         LOGE(ATM_DOMAIN, ATM_TAG,
646             "The context(token=%{public}d) is not belong to the current application(currToken=%{public}d).",
647             asyncContextHandle->asyncContextPtr->tokenId, currToken);
648         asyncContextHandle->asyncContextPtr->result.errorCode = ERR_PARAM_INVALID;
649         asyncContextHandle->asyncContextPtr->result.errorMsg =
650             "The specified context does not belong to the current application.";
651         return;
652     }
653 
654     GetInstanceId(asyncContextHandle->asyncContextPtr);
655     LOGI(ATM_DOMAIN, ATM_TAG, "Start to pop ui extension dialog");
656 
657     RequestOnSettingAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr);
658     if (asyncContextHandle->asyncContextPtr->result.errorCode != RET_SUCCESS) {
659         LOGW(ATM_DOMAIN, ATM_TAG, "Failed to pop uiextension dialog.");
660     }
661 }
662 
RequestPermissionOnSettingComplete(napi_env env,napi_status status,void * data)663 void NapiRequestPermissionOnSetting::RequestPermissionOnSettingComplete(napi_env env, napi_status status, void* data)
664 {
665     LOGD(ATM_DOMAIN, ATM_TAG, "RequestPermissionOnSettingComplete begin.");
666     RequestOnSettingAsyncContextHandle* asyncContextHandle =
667         reinterpret_cast<RequestOnSettingAsyncContextHandle*>(data);
668     if (asyncContextHandle == nullptr || asyncContextHandle->asyncContextPtr == nullptr) {
669         return;
670     }
671     std::unique_ptr<RequestOnSettingAsyncContextHandle> callbackPtr {asyncContextHandle};
672 
673     // need pop dialog
674     if (asyncContextHandle->asyncContextPtr->result.errorCode == RET_SUCCESS) {
675         return;
676     }
677     // return error
678     if (asyncContextHandle->asyncContextPtr->deferred != nullptr) {
679         int32_t jsCode = GetJsErrorCode(asyncContextHandle->asyncContextPtr->result.errorCode);
680         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
681         NAPI_CALL_RETURN_VOID(env,
682             napi_reject_deferred(env, asyncContextHandle->asyncContextPtr->deferred, businessError));
683     }
684 }
685 }  // namespace AccessToken
686 }  // namespace Security
687 }  // namespace OHOS