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