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