• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "ani_request_permission.h"
16 
17 #include <atomic>
18 #include <map>
19 #include <mutex>
20 #include <thread>
21 
22 #include "ability_manager_client.h"
23 #include "accesstoken_kit.h"
24 #include "accesstoken_common_log.h"
25 #include "ani_common.h"
26 #include "hisysevent.h"
27 #include "token_setproc.h"
28 #include "want.h"
29 
30 namespace OHOS {
31 namespace Security {
32 namespace AccessToken {
33 namespace {
34 #define SETTER_METHOD_NAME(property) "" #property
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 const std::string WINDOW_RECTANGLE_LEFT_KEY = "ohos.ability.params.request.left";
44 const std::string WINDOW_RECTANGLE_TOP_KEY = "ohos.ability.params.request.top";
45 const std::string WINDOW_RECTANGLE_HEIGHT_KEY = "ohos.ability.params.request.height";
46 const std::string WINDOW_RECTANGLE_WIDTH_KEY = "ohos.ability.params.request.width";
47 const std::string REQUEST_TOKEN_KEY = "ohos.ability.params.request.token";
48 std::shared_ptr<RequestInstanceControl> g_requestInstanceControl = nullptr;
49 std::mutex g_requestInstanceControlLock;
50 }
51 
GetRequestInstanceControl()52 static std::shared_ptr<RequestInstanceControl> GetRequestInstanceControl()
53 {
54     std::lock_guard<std::mutex> lock(g_requestInstanceControlLock);
55     if (g_requestInstanceControl == nullptr) {
56         g_requestInstanceControl = std::make_shared<RequestInstanceControl>();
57     }
58     return g_requestInstanceControl;
59 }
60 
RequestAsyncContext(ani_vm * vm,ani_env * env)61 RequestAsyncContext::RequestAsyncContext(ani_vm* vm, ani_env* env)
62     : RequestAsyncContextBase(vm, env, REQUEST_PERMISSIONS_FROM_USER)
63 {}
64 
~RequestAsyncContext()65 RequestAsyncContext::~RequestAsyncContext()
66 {
67     Clear();
68 }
69 
CreateServiceExtension(std::shared_ptr<RequestAsyncContext> asyncContext)70 static void CreateServiceExtension(std::shared_ptr<RequestAsyncContext> asyncContext)
71 {
72     auto abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(
73         asyncContext->stageContext_);
74     if (abilityContext == nullptr) {
75         LOGE(ATM_DOMAIN, ATM_TAG, "Convert to AbilityContext failed. " \
76             "UIExtension ability can not pop service ablility window!");
77         asyncContext->needDynamicRequest = false;
78         asyncContext->result.errorCode = RET_FAILED;
79         return;
80     }
81     OHOS::sptr<IRemoteObject> remoteObject = new (std::nothrow) AuthorizationResult(asyncContext);
82     if (remoteObject == nullptr) {
83         LOGE(ATM_DOMAIN, ATM_TAG, "Create window failed!");
84         asyncContext->needDynamicRequest = false;
85         asyncContext->result.errorCode = RET_FAILED;
86         return;
87     }
88     OHOS::AAFwk::Want want;
89     want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantServiceAbilityName);
90     want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
91     want.SetParam(STATE_KEY, asyncContext->permissionsState);
92     want.SetParam(TOKEN_KEY, abilityContext->GetToken());
93     want.SetParam(CALLBACK_KEY, remoteObject);
94 
95     int32_t left = 0;
96     int32_t top = 0;
97     int32_t width = 0;
98     int32_t height = 0;
99     abilityContext->GetWindowRect(left, top, width, height);
100     want.SetParam(WINDOW_RECTANGLE_LEFT_KEY, left);
101     want.SetParam(WINDOW_RECTANGLE_TOP_KEY, top);
102     want.SetParam(WINDOW_RECTANGLE_WIDTH_KEY, width);
103     want.SetParam(WINDOW_RECTANGLE_HEIGHT_KEY, height);
104     want.SetParam(REQUEST_TOKEN_KEY, abilityContext->GetToken());
105     int32_t ret = OHOS::AAFwk::AbilityManagerClient::GetInstance()->RequestDialogService(
106         want, abilityContext->GetToken());
107     LOGI(ATM_DOMAIN, ATM_TAG, "Request end, ret: %{public}d, tokenId: %{public}d, permNum: %{public}zu", ret,
108         asyncContext->tokenId, asyncContext->permissionList.size());
109 }
110 
StartExtensionAbility(std::shared_ptr<RequestAsyncContextBase> asyncContext)111 void RequestAsyncContext::StartExtensionAbility(std::shared_ptr<RequestAsyncContextBase> asyncContext)
112 {
113     if (asyncContext == nullptr) {
114         LOGI(ATM_DOMAIN, ATM_TAG, "asyncContext is nullptr.");
115         return;
116     }
117     if (uiExtensionFlag) {
118         OHOS::AAFwk::Want want;
119         want.SetElementName(this->info.grantBundleName, this->info.grantAbilityName);
120         want.SetParam(PERMISSION_KEY, this->permissionList);
121         want.SetParam(STATE_KEY, this->permissionsState);
122         want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
123         CreateUIExtension(want,
124             std::static_pointer_cast<RequestAsyncContext>(asyncContext),
125             GetRequestInstanceControl());
126     } else {
127         CreateServiceExtension(std::static_pointer_cast<RequestAsyncContext>(asyncContext));
128     }
129 }
130 
131 template<typename valueType>
CallSetter(ani_env * env,ani_class cls,ani_object object,const char * setterName,valueType value)132 static inline bool CallSetter(ani_env* env, ani_class cls, ani_object object, const char* setterName, valueType value)
133 {
134     ani_status status = ANI_ERROR;
135     ani_field fieldValue;
136     if (env->Class_FindField(cls, setterName, &fieldValue) != ANI_OK) {
137         LOGE(ATM_DOMAIN, ATM_TAG, "Class_FindField Fail %{public}d, name: %{public}s.",
138             static_cast<int32_t>(status), setterName);
139         return false;
140     }
141     if ((status = env->Object_SetField_Ref(object, fieldValue, value)) != ANI_OK) {
142         LOGE(ATM_DOMAIN, ATM_TAG, "Object_SetField_Ref Fail %{public}d, name: %{public}s.",
143             static_cast<int32_t>(status), setterName);
144         return false;
145     }
146     return true;
147 }
148 
WrapResult(ani_env * env)149 ani_object RequestAsyncContext::WrapResult(ani_env* env)
150 {
151     ani_status status = ANI_ERROR;
152     ani_class cls = nullptr;
153     if (env == nullptr) {
154         LOGE(ATM_DOMAIN, ATM_TAG, "env is nullptr");
155         return nullptr;
156     }
157     if ((status = env->FindClass("Lsecurity/PermissionRequestResult/PermissionRequestResult;", &cls)) != ANI_OK) {
158         LOGE(ATM_DOMAIN, ATM_TAG, "FindClass status %{public}d ", static_cast<int32_t>(status));
159         return nullptr;
160     }
161     if (cls == nullptr) {
162         LOGE(ATM_DOMAIN, ATM_TAG, "null cls");
163         return nullptr;
164     }
165     ani_method method = nullptr;
166     if ((status = env->Class_FindMethod(cls, "<ctor>", ":V", &method)) != ANI_OK) {
167         LOGE(ATM_DOMAIN, ATM_TAG, "Class_FindMethod status %{public}d ", static_cast<int32_t>(status));
168         return nullptr;
169     }
170     ani_object aObject = nullptr;
171     if ((status = env->Object_New(cls, method, &aObject)) != ANI_OK) {
172         LOGE(ATM_DOMAIN, ATM_TAG, "Object_New status %{public}d ", static_cast<int32_t>(status));
173         return nullptr;
174     }
175     auto state = this->needDynamicRequest ? this->grantResults : this->permissionsState;
176     ani_ref aniPerms = CreateAniArrayString(env, permissionList);
177     ani_ref aniAuthRes = CreateAniArrayInt(env, state);
178     ani_ref aniDiasShownRes = CreateAniArrayBool(env, dialogShownResults);
179     ani_ref aniErrorReasons = CreateAniArrayInt(env, errorReasons);
180     if (aniPerms == nullptr || aniAuthRes == nullptr || aniDiasShownRes == nullptr || aniErrorReasons == nullptr ||
181         !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(permissions), aniPerms) ||
182         !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(authResults), aniAuthRes) ||
183         !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(dialogShownResults), aniDiasShownRes) ||
184         !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(errorReasons), aniErrorReasons)) {
185         aObject = nullptr;
186     }
187     DeleteReference(env, aniPerms);
188     DeleteReference(env, aniAuthRes);
189     DeleteReference(env, aniDiasShownRes);
190     DeleteReference(env, aniErrorReasons);
191     return aObject;
192 }
193 
HandleResult(const std::vector<std::string> & permissionList,const std::vector<int32_t> & grantResults)194 void RequestAsyncContext::HandleResult(const std::vector<std::string>& permissionList,
195     const std::vector<int32_t>& grantResults)
196 {
197     std::vector<int32_t> newGrantResults;
198     size_t size = permissionList.size();
199     for (size_t i = 0; i < size; i++) {
200         int32_t result = static_cast<int32_t>(this->permissionsState[i]);
201         if (this->permissionsState[i] == AccessToken::DYNAMIC_OPER) {
202             result = this->result.errorCode == AccessToken::RET_SUCCESS ?
203                 grantResults[i] : AccessToken::INVALID_OPER;
204         }
205         newGrantResults.emplace_back(result);
206     }
207 
208     if (newGrantResults.empty()) {
209         LOGE(ATM_DOMAIN, ATM_TAG, "GrantResults empty");
210         result.errorCode = RET_FAILED;
211     }
212     this->grantResults.assign(newGrantResults.begin(), newGrantResults.end());
213 }
214 
IsDynamicRequest()215 bool RequestAsyncContext::IsDynamicRequest()
216 {
217     std::vector<AccessToken::PermissionListState> permList;
218     for (const auto& permission : this->permissionList) {
219         AccessToken::PermissionListState permState;
220         permState.permissionName = permission;
221         permState.errorReason = SERVICE_ABNORMAL;
222         permState.state = AccessToken::INVALID_OPER;
223         permList.emplace_back(permState);
224     }
225     auto ret = AccessToken::AccessTokenKit::GetSelfPermissionsState(permList, this->info);
226     LOGI(ATM_DOMAIN, ATM_TAG,
227         "TokenID: %{public}d, bundle: %{public}s, uiExAbility: %{public}s, serExAbility: %{public}s.",
228         this->tokenId, this->info.grantBundleName.c_str(), this->info.grantAbilityName.c_str(),
229         this->info.grantServiceAbilityName.c_str());
230     if (ret == AccessToken::FORBIDDEN_OPER) {
231         LOGE(ATM_DOMAIN, ATM_TAG, "FORBIDDEN_OPER");
232         for (auto& perm : permList) {
233             perm.state = AccessToken::INVALID_OPER;
234             perm.errorReason = PRIVACY_STATEMENT_NOT_AGREED;
235         }
236     }
237     for (const auto& permState : permList) {
238         LOGI(ATM_DOMAIN, ATM_TAG, "Permission: %{public}s: state: %{public}d, errorReason: %{public}d",
239             permState.permissionName.c_str(), permState.state, permState.errorReason);
240         this->permissionsState.emplace_back(permState.state);
241         this->dialogShownResults.emplace_back(permState.state == AccessToken::TypePermissionOper::DYNAMIC_OPER);
242         this->errorReasons.emplace_back(permState.errorReason);
243     }
244     if (permList.size() != this->permissionList.size()) {
245         LOGE(ATM_DOMAIN, ATM_TAG, "permList.size: %{public}zu, permissionList.size: %{public}zu", permList.size(),
246             this->permissionList.size());
247         return false;
248     }
249     return ret == AccessToken::TypePermissionOper::DYNAMIC_OPER;
250 }
251 
CheckDynamicRequest()252 bool RequestAsyncContext::CheckDynamicRequest()
253 {
254     permissionsState.clear();
255     dialogShownResults.clear();
256     if (!IsDynamicRequest()) {
257         HandleResult(this->permissionList, this->permissionsState);
258         FinishCallback();
259         return false;
260     }
261     return true;
262 }
263 
ProcessUIExtensionCallback(const OHOS::AAFwk::Want & result)264 void RequestAsyncContext::ProcessUIExtensionCallback(const OHOS::AAFwk::Want& result)
265 {
266     this->permissionList = result.GetStringArrayParam(PERMISSION_KEY);
267     this->permissionsState = result.GetIntArrayParam(RESULT_KEY);
268     HandleResult(permissionList, permissionsState);
269 }
270 
ConvertErrorCode(int32_t code)271 int32_t RequestAsyncContext::ConvertErrorCode(int32_t code)
272 {
273     return BusinessErrorAni::GetStsErrorCode(result.errorCode);
274 }
275 
NoNeedUpdate()276 bool RequestAsyncContext::NoNeedUpdate()
277 {
278     return true;
279 }
280 
RequestPermissionsFromUserProcess(std::shared_ptr<RequestAsyncContext> & asyncContext)281 static void RequestPermissionsFromUserProcess(std::shared_ptr<RequestAsyncContext>& asyncContext)
282 {
283     if (!asyncContext->IsDynamicRequest()) {
284         LOGE(ATM_DOMAIN, ATM_TAG, "It does not need to request permission");
285         asyncContext->needDynamicRequest = false;
286         if ((asyncContext->permissionsState.empty()) && (asyncContext->result.errorCode == RET_SUCCESS)) {
287             LOGE(ATM_DOMAIN, ATM_TAG, "GrantResults empty");
288             asyncContext->result.errorCode = RET_FAILED;
289         }
290         return;
291     }
292 
293     asyncContext->GetInstanceId();
294     if (asyncContext->info.grantBundleName == ORI_PERMISSION_MANAGER_BUNDLE_NAME) {
295         LOGI(ATM_DOMAIN, ATM_TAG,
296             "Pop service extension dialog, uiContentFlag=%{public}d", asyncContext->uiContentFlag);
297         if (asyncContext->uiContentFlag) {
298             GetRequestInstanceControl()->AddCallbackByInstanceId(asyncContext);
299         } else {
300             CreateServiceExtension(asyncContext);
301         }
302     } else if (asyncContext->instanceId == -1) {
303         LOGE(ATM_DOMAIN, ATM_TAG, "Pop service extension dialog, instanceId is -1.");
304         CreateServiceExtension(asyncContext);
305         (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQUEST_PERMISSIONS_FROM_USER",
306             HiviewDFX::HiSysEvent::EventType::BEHAVIOR, "BUNDLENAME", asyncContext->bundleName.c_str(),
307             "UIEXTENSION_FLAG", false);
308     } else {
309         LOGI(ATM_DOMAIN, ATM_TAG, "Pop ui extension dialog");
310         asyncContext->uiExtensionFlag = true;
311         GetRequestInstanceControl()->AddCallbackByInstanceId(asyncContext);
312         (void)HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQUEST_PERMISSIONS_FROM_USER",
313             HiviewDFX::HiSysEvent::EventType::BEHAVIOR, "BUNDLENAME", asyncContext->bundleName, "UIEXTENSION_FLAG",
314             false);
315         if (!asyncContext->uiExtensionFlag) {
316             LOGW(ATM_DOMAIN, ATM_TAG, "Pop uiextension dialog fail, start to pop service extension dialog.");
317             GetRequestInstanceControl()->AddCallbackByInstanceId(asyncContext);
318         }
319     }
320 }
321 
ParseParameter(ani_env * env,ani_object aniContext,ani_array_ref aniPermissionList,ani_object callback,std::shared_ptr<RequestAsyncContext> & asyncContext)322 static bool ParseParameter(ani_env* env, ani_object aniContext, ani_array_ref aniPermissionList,
323     ani_object callback, std::shared_ptr<RequestAsyncContext>& asyncContext)
324 {
325     if (!asyncContext->FillInfoFromContext(aniContext)) {
326         LOGE(ATM_DOMAIN, ATM_TAG, "FillInfoFromContext failed.");
327         BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL,
328             GetParamErrorMsg("context", "UIAbility or UIExtension Context"));
329         return false;
330     }
331     asyncContext->permissionList = ParseAniStringVector(env, aniPermissionList);
332     if (!AniParseCallback(env, reinterpret_cast<ani_ref>(callback), asyncContext->callbackRef)) {
333         return false;
334     }
335     return true;
336 }
337 
RequestPermissionsFromUserExecute(ani_env * env,ani_object object,ani_object aniContext,ani_array_ref aniPermissionList,ani_object callback)338 void RequestPermissionsFromUserExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
339     ani_object aniContext, ani_array_ref aniPermissionList, ani_object callback)
340 {
341     if (env == nullptr || aniPermissionList == nullptr || callback == nullptr) {
342         LOGE(ATM_DOMAIN, ATM_TAG, "env or aniPermissionList or callback is null.");
343         return;
344     }
345     ani_vm* vm;
346     ani_status status = env->GetVM(&vm);
347     if (status != ANI_OK) {
348         LOGE(ATM_DOMAIN, ATM_TAG, "GetVM failed, error=%{public}d.", static_cast<int32_t>(status));
349         return;
350     }
351     std::shared_ptr<RequestAsyncContext> asyncContext = std::make_shared<RequestAsyncContext>(vm, env);
352     if (!ParseParameter(env, aniContext, aniPermissionList, callback, asyncContext)) {
353         return;
354     }
355 
356     static AccessTokenID selfTokenID = static_cast<AccessTokenID>(GetSelfTokenID());
357     if (selfTokenID != asyncContext->tokenId) {
358         LOGE(ATM_DOMAIN, ATM_TAG,
359             "The context tokenID: %{public}d, selfTokenID: %{public}d.", asyncContext->tokenId, selfTokenID);
360 
361         ani_ref nullRef = nullptr;
362         env->GetNull(&nullRef);
363         ani_object result = reinterpret_cast<ani_object>(nullRef);
364         ani_object error = BusinessErrorAni::CreateError(env, STS_ERROR_INNER, GetErrorMessage(STS_ERROR_INNER,
365             "The specified context does not belong to the current application."));
366         (void)ExecuteAsyncCallback(env, callback, error, result);
367         return;
368     }
369     RequestPermissionsFromUserProcess(asyncContext);
370     if (asyncContext->needDynamicRequest) {
371         return;
372     }
373     asyncContext->FinishCallback();
374     LOGI(ATM_DOMAIN, ATM_TAG, "uiExtensionFlag: %{public}d, uiContentFlag: %{public}d",
375         asyncContext->uiExtensionFlag, asyncContext->uiContentFlag);
376 }
377 
378 
AuthorizationResult(std::shared_ptr<RequestAsyncContext> & data)379 AuthorizationResult::AuthorizationResult(std::shared_ptr<RequestAsyncContext>& data) : data_(data)
380 {
381     LOGI(ATM_DOMAIN, ATM_TAG, "AuthorizationResult");
382 }
383 
~AuthorizationResult()384 AuthorizationResult::~AuthorizationResult()
385 {
386     LOGI(ATM_DOMAIN, ATM_TAG, "~AuthorizationResult");
387 }
388 
GrantResultsCallback(const std::vector<std::string> & permissionList,const std::vector<int32_t> & grantResults)389 void AuthorizationResult::GrantResultsCallback(
390     const std::vector<std::string>& permissionList, const std::vector<int32_t>& grantResults)
391 {
392     std::shared_ptr<RequestAsyncContext> asyncContext = data_;
393     if (asyncContext == nullptr) {
394         return;
395     }
396     LOGI(ATM_DOMAIN, ATM_TAG, "GrantResultsCallback");
397     asyncContext->HandleResult(permissionList, grantResults);
398     asyncContext->FinishCallback();
399 }
400 
WindowShownCallback()401 void AuthorizationResult::WindowShownCallback()
402 {
403     std::shared_ptr<RequestAsyncContext> asyncContext = data_;
404     if (asyncContext == nullptr) {
405         return;
406     }
407     OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->stageContext_);
408     if ((uiContent == nullptr) || !(asyncContext->uiContentFlag)) {
409         return;
410     }
411     GetRequestInstanceControl()->ExecCallback(asyncContext->instanceId);
412 }
413 }  // namespace AccessToken
414 }  // namespace Security
415 }  // namespace OHOS