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