• 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_on_setting.h"
16 #include "accesstoken_kit.h"
17 #include "accesstoken_common_log.h"
18 #include "ani_common.h"
19 #include "token_setproc.h"
20 #include "want.h"
21 
22 namespace OHOS {
23 namespace Security {
24 namespace AccessToken {
25 namespace {
26 constexpr int32_t REQUEST_ALREADY_EXIST = 1;
27 constexpr int32_t PERM_NOT_BELONG_TO_SAME_GROUP = 2;
28 constexpr int32_t PERM_IS_NOT_DECLARE = 3;
29 constexpr int32_t ALL_PERM_GRANTED = 4;
30 constexpr int32_t PERM_NOT_REVOKE_BY_USER = 5;
31 const std::string PERMISSION_SETTING_KEY = "ohos.user.setting.permission";
32 const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType";
33 const std::string UI_EXTENSION_TYPE = "sys/commonUI";
34 const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code";
35 const std::string PERMISSION_RESULT_KEY = "ohos.user.setting.permission.result";
36 std::shared_ptr<RequestInstanceControl> g_requestInstanceControl = nullptr;
37 std::mutex g_requestInstanceControlLock;
38 }
39 
GetRequestInstanceControl()40 static std::shared_ptr<RequestInstanceControl> GetRequestInstanceControl()
41 {
42     std::lock_guard<std::mutex> lock(g_requestInstanceControlLock);
43     if (g_requestInstanceControl == nullptr) {
44         g_requestInstanceControl = std::make_shared<RequestInstanceControl>();
45     }
46     return g_requestInstanceControl;
47 }
48 
RequestPermOnSettingAsyncContext(ani_vm * vm,ani_env * env)49 RequestPermOnSettingAsyncContext::RequestPermOnSettingAsyncContext(ani_vm* vm, ani_env* env)
50     : RequestAsyncContextBase(vm, env, REQUEST_PERMISSION_ON_SETTING)
51 {}
52 
~RequestPermOnSettingAsyncContext()53 RequestPermOnSettingAsyncContext::~RequestPermOnSettingAsyncContext()
54 {
55     Clear();
56 }
57 
StateToEnumIndex(int32_t state,ani_size & enumIndex)58 static void StateToEnumIndex(int32_t state, ani_size& enumIndex)
59 {
60     if (state == 0) {
61         enumIndex = 1;
62     } else {
63         enumIndex = 0;
64     }
65 }
66 
WrapResult(ani_env * env)67 ani_object RequestPermOnSettingAsyncContext::WrapResult(ani_env* env)
68 {
69     ani_class arrayCls = nullptr;
70     if (env->FindClass("Lescompat/Array;", &arrayCls) != ANI_OK) {
71         LOGE(ATM_DOMAIN, ATM_TAG, "Failed to FindClass name Lescompat/Array!");
72         return nullptr;
73     }
74 
75     ani_method arrayCtor;
76     if (env->Class_FindMethod(arrayCls, "<ctor>", "I:V", &arrayCtor) != ANI_OK) {
77         LOGE(ATM_DOMAIN, ATM_TAG, "Failed to FindClass <ctor>!");
78         return nullptr;
79     }
80 
81     ani_object arrayObj;
82     if (env->Object_New(arrayCls, arrayCtor, &arrayObj, this->stateList.size()) != ANI_OK) {
83         LOGE(ATM_DOMAIN, ATM_TAG, "Object new failed!");
84         return nullptr;
85     }
86 
87     const char* enumDescriptor = "L@ohos/abilityAccessCtrl/abilityAccessCtrl/GrantStatus;";
88     ani_enum enumType;
89     if (env->FindEnum(enumDescriptor, &enumType) != ANI_OK) {
90         LOGE(ATM_DOMAIN, ATM_TAG, "Failed to FindClass name %{public}s!", enumDescriptor);
91         return nullptr;
92     }
93 
94     ani_size index = 0;
95     for (const auto& state: this->stateList) {
96         ani_enum_item enumItem;
97         ani_size enumIndex = 0;
98         StateToEnumIndex(state, enumIndex);
99         if (env->Enum_GetEnumItemByIndex(enumType, enumIndex, &enumItem) != ANI_OK) {
100             LOGE(ATM_DOMAIN, ATM_TAG, "Failed to GetEnumItemByIndex value %{public}u!", state);
101             break;
102         }
103 
104         if (env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", index, enumItem) != ANI_OK) {
105             LOGE(ATM_DOMAIN, ATM_TAG, "Failed to Object_CallMethodByName_Void set!");
106             break;
107         }
108         index++;
109     }
110 
111     return arrayObj;
112 }
113 
ConvertErrorCode(int32_t errorCode)114 int32_t RequestPermOnSettingAsyncContext::ConvertErrorCode(int32_t errorCode)
115 {
116     int32_t stsCode = STS_OK;
117     switch (errorCode) {
118         case RET_SUCCESS:
119             stsCode = STS_OK;
120             break;
121         case REQUEST_ALREADY_EXIST:
122             stsCode = STS_ERROR_REQUEST_IS_ALREADY_EXIST;
123             break;
124         case PERM_NOT_BELONG_TO_SAME_GROUP:
125             stsCode = STS_ERROR_PARAM_INVALID;
126             break;
127         case PERM_IS_NOT_DECLARE:
128             stsCode = STS_ERROR_PARAM_INVALID;
129             break;
130         case ALL_PERM_GRANTED:
131             stsCode = STS_ERROR_ALL_PERM_GRANTED;
132             break;
133         case PERM_NOT_REVOKE_BY_USER:
134             stsCode = STS_ERROR_PERM_NOT_REVOKE_BY_USER;
135             break;
136         default:
137             stsCode = STS_ERROR_INNER;
138             break;
139     }
140     LOGI(ATM_DOMAIN, ATM_TAG, "Dialog error(%{public}d) stsCode(%{public}d).", errorCode, stsCode);
141     return stsCode;
142 }
143 
ProcessUIExtensionCallback(const OHOS::AAFwk::Want & result)144 void RequestPermOnSettingAsyncContext::ProcessUIExtensionCallback(const OHOS::AAFwk::Want& result)
145 {
146     this->result.errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0);
147     this->stateList = result.GetIntArrayParam(PERMISSION_RESULT_KEY);
148 }
149 
StartExtensionAbility(std::shared_ptr<RequestAsyncContextBase> asyncContext)150 void RequestPermOnSettingAsyncContext::StartExtensionAbility(std::shared_ptr<RequestAsyncContextBase> asyncContext)
151 {
152     AccessTokenKit::GetPermissionManagerInfo(this->info);
153     LOGI(ATM_DOMAIN, ATM_TAG, "BundleName: %{public}s, permStateAbilityName: %{public}s.",
154         this->info.grantBundleName.c_str(), this->info.permStateAbilityName.c_str());
155     OHOS::AAFwk::Want want;
156     want.SetElementName(this->info.grantBundleName, this->info.permStateAbilityName);
157     want.SetParam(PERMISSION_SETTING_KEY, this->permissionList);
158     want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
159     CreateUIExtension(want, asyncContext, GetRequestInstanceControl());
160 }
161 
CheckPermList(std::vector<std::string> permList,std::vector<std::string> tmpPermList)162 static bool CheckPermList(std::vector<std::string> permList, std::vector<std::string> tmpPermList)
163 {
164     if (permList.size() != tmpPermList.size()) {
165         LOGE(ATM_DOMAIN, ATM_TAG, "Perm list size not equal, CurrentPermList size: %{public}zu.", tmpPermList.size());
166         return false;
167     }
168 
169     for (const auto& item : permList) {
170         auto iter = std::find_if(tmpPermList.begin(), tmpPermList.end(), [item](const std::string& perm) {
171             return item == perm;
172         });
173         if (iter == tmpPermList.end()) {
174             LOGE(ATM_DOMAIN, ATM_TAG, "Different permission lists.");
175             return false;
176         }
177     }
178     return true;
179 }
180 
IsSameRequest(const std::shared_ptr<RequestAsyncContextBase> other)181 bool RequestPermOnSettingAsyncContext::IsSameRequest(const std::shared_ptr<RequestAsyncContextBase> other)
182 {
183     if (other == nullptr) {
184         LOGE(ATM_DOMAIN, ATM_TAG, "other is nullptr.");
185         return false;
186     }
187     auto ptr = std::static_pointer_cast<RequestPermOnSettingAsyncContext>(other);
188     return CheckPermList(permissionList, ptr->permissionList);
189 }
190 
CopyResult(const std::shared_ptr<RequestAsyncContextBase> other)191 void RequestPermOnSettingAsyncContext::CopyResult(const std::shared_ptr<RequestAsyncContextBase> other)
192 {
193     if (other == nullptr) {
194         LOGE(ATM_DOMAIN, ATM_TAG, "other is nullptr.");
195         return;
196     }
197     auto ptr = std::static_pointer_cast<RequestPermOnSettingAsyncContext>(other);
198     this->result.errorCode = ptr->result.errorCode;
199     this->stateList = ptr->stateList;
200     this->isDynamic = false;
201 }
202 
CheckDynamicRequest()203 bool RequestPermOnSettingAsyncContext::CheckDynamicRequest()
204 {
205     if (!this->isDynamic) {
206         LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission extension");
207         FinishCallback();
208         return false;
209     }
210     return true;
211 }
212 
ProcessFailResult(int32_t code)213 void RequestPermOnSettingAsyncContext::ProcessFailResult(int32_t code)
214 {
215     if (code == -1) {
216         this->result.errorCode = code;
217     }
218 }
219 
NoNeedUpdate()220 bool RequestPermOnSettingAsyncContext::NoNeedUpdate()
221 {
222     if (result.errorCode != RET_SUCCESS) {
223         return true;
224     }
225     for (int32_t item : this->stateList) {
226         if (item != PERMISSION_GRANTED) {
227             return true;
228         }
229     }
230     return false;
231 }
232 
ParseRequestPermissionOnSetting(ani_env * env,ani_object & aniContext,ani_array_ref & aniPermissionList,ani_object callback,std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext)233 static bool ParseRequestPermissionOnSetting(ani_env* env, ani_object& aniContext, ani_array_ref& aniPermissionList,
234     ani_object callback, std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext)
235 {
236     if (!asyncContext->FillInfoFromContext(aniContext)) {
237         BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL,
238             GetParamErrorMsg("context", "UIAbility or UIExtension Context"));
239         return false;
240     }
241     asyncContext->permissionList = ParseAniStringVector(env, aniPermissionList);
242     if (!AniParseCallback(env, reinterpret_cast<ani_ref>(callback), asyncContext->callbackRef)) {
243         return false;
244     }
245     return true;
246 }
247 
RequestPermissionOnSettingExecute(ani_env * env,ani_object object,ani_object aniContext,ani_array_ref permissionList,ani_object callback)248 void RequestPermissionOnSettingExecute([[maybe_unused]] ani_env* env,
249     [[maybe_unused]] ani_object object, ani_object aniContext, ani_array_ref permissionList, ani_object callback)
250 {
251     if (env == nullptr || permissionList == nullptr || callback == nullptr) {
252         LOGE(ATM_DOMAIN, ATM_TAG, "Env or permissionList or callback is null.");
253         return;
254     }
255 
256     ani_vm* vm;
257     ani_status status = env->GetVM(&vm);
258     if (status != ANI_OK) {
259         LOGE(ATM_DOMAIN, ATM_TAG, "Failed to GetVM, error=%{public}d.", static_cast<int32_t>(status));
260         return;
261     }
262 
263     std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext =
264         std::make_shared<RequestPermOnSettingAsyncContext>(vm, env);
265     if (!ParseRequestPermissionOnSetting(env, aniContext, permissionList, callback, asyncContext)) {
266         return;
267     }
268     ani_ref nullRef = nullptr;
269     env->GetNull(&nullRef);
270     ani_object result = reinterpret_cast<ani_object>(nullRef);
271     static AccessTokenID selfTokenID = static_cast<AccessTokenID>(GetSelfTokenID());
272     if (selfTokenID != asyncContext->tokenId) {
273         LOGE(ATM_DOMAIN, ATM_TAG, "The context tokenID %{public}d is not same with selfTokenID %{public}d.",
274             asyncContext->tokenId, selfTokenID);
275         ani_object error =
276             BusinessErrorAni::CreateError(env, STS_ERROR_PARAM_INVALID, GetErrorMessage(STS_ERROR_PARAM_INVALID,
277             "The specified context does not belong to the current application."));
278         (void)ExecuteAsyncCallback(env, callback, error, result);
279         return;
280     }
281     asyncContext->GetInstanceId();
282     GetRequestInstanceControl()->AddCallbackByInstanceId(asyncContext);
283     LOGI(ATM_DOMAIN, ATM_TAG, "Start to pop ui extension dialog.");
284 
285     if (asyncContext->result.errorCode != RET_SUCCESS) {
286         asyncContext->FinishCallback();
287         LOGW(ATM_DOMAIN, ATM_TAG, "Failed to pop uiextension dialog.");
288     }
289 }
290 }  // namespace AccessToken
291 }  // namespace Security
292 }  // namespace OHOS