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