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