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
16 #include "request_permission_on_setting.h"
17 #include "ability_access_ctrl_common.h"
18 #include "ability.h"
19 #include "access_token.h"
20 #include "macro.h"
21 #include "token_setproc.h"
22 #include "want.h"
23
24 using namespace OHOS::FFI;
25 using OHOS::Security::AccessToken::AccessTokenID;
26 using OHOS::Security::AccessToken::AccessTokenKit;
27
28 namespace OHOS {
29 namespace CJSystemapi {
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
34 // error code from dialog
35 const int32_t RET_SUCCESS = 0;
36 const int32_t REQUEST_ALREADY_EXIST = 1;
37 const int32_t PERM_NOT_BELONG_TO_SAME_GROUP = 2;
38 const int32_t PERM_IS_NOT_DECLARE = 3;
39 const int32_t ALL_PERM_GRANTED = 4;
40 const int32_t PERM_REVOKE_BY_USER = 5;
41
42 std::mutex g_lockFlag;
43 } // namespace
44
45 extern "C" {
TransferToCJErrorCode(int32_t errCode)46 static int32_t TransferToCJErrorCode(int32_t errCode)
47 {
48 int32_t cjCode = CJ_OK;
49 switch (errCode) {
50 case RET_SUCCESS:
51 cjCode = CJ_OK;
52 break;
53 case REQUEST_ALREADY_EXIST:
54 cjCode = CJ_ERROR_REQUEST_IS_ALREADY_EXIST;
55 break;
56 case PERM_NOT_BELONG_TO_SAME_GROUP:
57 cjCode = CJ_ERROR_PARAM_INVALID;
58 break;
59 case PERM_IS_NOT_DECLARE:
60 cjCode = CJ_ERROR_PARAM_INVALID;
61 break;
62 case ALL_PERM_GRANTED:
63 cjCode = CJ_ERROR_ALL_PERM_GRANTED;
64 break;
65 case PERM_REVOKE_BY_USER:
66 cjCode = CJ_ERROR_PERM_REVOKE_BY_USER;
67 break;
68 default:
69 cjCode = CJ_ERROR_INNER;
70 break;
71 }
72 return cjCode;
73 }
74
ReleaseHandler(int32_t code)75 void PermissonOnSettingUICallback::ReleaseHandler(int32_t code)
76 {
77 {
78 std::lock_guard<std::mutex> lock(g_lockFlag);
79 if (this->reqContext_->releaseFlag) {
80 return;
81 }
82 this->reqContext_->releaseFlag = true;
83 }
84 Ace::UIContent* uiContent = nullptr;
85 if (this->reqContext_->uiAbilityFlag) {
86 uiContent = this->reqContext_->abilityContext->GetUIContent();
87 } else {
88 uiContent = this->reqContext_->uiExtensionContext->GetUIContent();
89 }
90 if (uiContent != nullptr) {
91 LOGI("Close uiextension component");
92 uiContent->CloseModalUIExtension(this->sessionId_);
93 }
94 if (code == 0) { // dialog terminate normally
95 return;
96 }
97 LOGI("ReleaseHandler code %{public}d", code);
98 RetDataCArrI32 retArr = {.code = code, .data = {.head = nullptr, .size = 0}};
99 this->reqContext_->callbackRef(retArr);
100 }
101
PermissonOnSettingUICallback(const std::shared_ptr<RequestPermOnSettingAsyncContext> & reqContext)102 PermissonOnSettingUICallback::PermissonOnSettingUICallback(
103 const std::shared_ptr<RequestPermOnSettingAsyncContext>& reqContext)
104 {
105 this->reqContext_ = reqContext;
106 }
107
~PermissonOnSettingUICallback()108 PermissonOnSettingUICallback::~PermissonOnSettingUICallback()
109 {}
110
SetSessionId(int32_t sessionId)111 void PermissonOnSettingUICallback::SetSessionId(int32_t sessionId)
112 {
113 this->sessionId_ = sessionId;
114 }
115
116 /*
117 * when UIExtensionAbility use terminateSelfWithResult
118 */
OnResult(int32_t resultCode,const AAFwk::Want & result)119 void PermissonOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
120 {
121 this->reqContext_->errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0);
122 this->reqContext_->stateList = result.GetIntArrayParam(PERMISSION_RESULT_KEY);
123 LOGI("ResultCode is %{public}d, errorCode=%{public}d, listSize=%{public}zu",
124 resultCode, this->reqContext_->errorCode, this->reqContext_->stateList.size());
125 ReleaseHandler(0);
126 RetDataCArrI32 retArr = {.code = CJ_OK, .data = {.head = nullptr, .size = 0}};
127 if (this->reqContext_->errorCode != 0) {
128 retArr.code = TransferToCJErrorCode(this->reqContext_->errorCode);
129 this->reqContext_->callbackRef(retArr);
130 return;
131 }
132
133 auto size = this->reqContext_->stateList.size();
134 if (size <= 0) {
135 LOGE("StateList empty");
136 retArr.code = CJ_ERROR_INNER;
137 this->reqContext_->callbackRef(retArr);
138 return;
139 }
140 auto arr = static_cast<int32_t*>(malloc(sizeof(int32_t) * size));
141 if (!arr) {
142 LOGE("Array malloc failed");
143 retArr.code = CJ_ERROR_INNER;
144 this->reqContext_->callbackRef(retArr);
145 return;
146 }
147
148 for (int i = 0; i < static_cast<int32_t>(size); i++) {
149 arr[i] = this->reqContext_->stateList[i];
150 }
151 retArr.data.head = arr;
152 retArr.data.size = static_cast<int64_t>(size);
153 this->reqContext_->callbackRef(retArr);
154 }
155
156 /*
157 * when UIExtensionAbility send message to UIExtensionComponent
158 */
OnReceive(const AAFwk::WantParams & receive)159 void PermissonOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive)
160 {
161 LOGI("OnReceive Called!");
162 }
163
164 /*
165 * when UIExtensionAbility disconnect or use terminate or process die
166 * releaseCode is 0 when process normal exit
167 */
OnRelease(int32_t releaseCode)168 void PermissonOnSettingUICallback::OnRelease(int32_t releaseCode)
169 {
170 LOGI("releaseCode is %{public}d", releaseCode);
171 ReleaseHandler(releaseCode);
172 }
173
174 /*
175 * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
176 */
OnError(int32_t code,const std::string & name,const std::string & message)177 void PermissonOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
178 {
179 LOGE("OnError: code is %{public}d, name is %{public}s, message is %{public}s",
180 code, name.c_str(), message.c_str());
181 ReleaseHandler(code);
182 }
183
184 /*
185 * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
186 * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
187 */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)188 void PermissonOnSettingUICallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
189 {
190 LOGI("Connect to UIExtensionAbility successfully.");
191 }
192
193 /*
194 * when UIExtensionComponent destructed
195 */
OnDestroy()196 void PermissonOnSettingUICallback::OnDestroy()
197 {
198 LOGI("UIExtensionAbility destructed.");
199 }
200
BindCallbacks(std::shared_ptr<PermissonOnSettingUICallback> uiExtCallback)201 static Ace::ModalUIExtensionCallbacks BindCallbacks(std::shared_ptr<PermissonOnSettingUICallback> uiExtCallback)
202 {
203 Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
204 [uiExtCallback](int32_t releaseCode) {
205 uiExtCallback->OnRelease(releaseCode);
206 },
207 [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
208 uiExtCallback->OnResult(resultCode, result);
209 },
210 [uiExtCallback](const OHOS::AAFwk::WantParams& request) {
211 uiExtCallback->OnReceive(request);
212 },
213 [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]]const std::string& message) {
214 uiExtCallback->OnError(code, name, name);
215 },
216 [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy) {
217 uiExtCallback->OnRemoteReady(uiProxy);
218 },
219 [uiExtCallback] {
220 uiExtCallback->OnDestroy();
221 },
222 };
223 return uiExtensionCallbacks;
224 }
225
CreateUIExtension(const Want & want,std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)226 static int32_t CreateUIExtension(const Want &want, std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)
227 {
228 if (asyncContext == nullptr) {
229 return CJ_ERROR_INNER;
230 }
231 Ace::UIContent* uiContent = nullptr;
232 if (asyncContext->uiAbilityFlag) {
233 uiContent = asyncContext->abilityContext->GetUIContent();
234 } else {
235 uiContent = asyncContext->uiExtensionContext->GetUIContent();
236 }
237 if (uiContent == nullptr) {
238 LOGE("Get ui content failed!");
239 return CJ_ERROR_INNER;
240 }
241 auto uiExtCallback = std::make_shared<PermissonOnSettingUICallback>(asyncContext);
242 auto uiExtensionCallbacks = BindCallbacks(uiExtCallback);
243 Ace::ModalUIExtensionConfig config;
244 config.isProhibitBack = true;
245 int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
246 if (sessionId == 0) {
247 LOGE("SessionId invalid");
248 return CJ_ERROR_INNER;
249 }
250 uiExtCallback->SetSessionId(sessionId);
251 return CJ_OK;
252 }
253
StartUIExtension(std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)254 static int32_t StartUIExtension(std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext)
255 {
256 AAFwk::Want want;
257 AccessTokenKit::GetPermissionManagerInfo(asyncContext->info);
258 LOGI("bundleName: %{public}s, permStateAbilityName: %{public}s.",
259 asyncContext->info.grantBundleName.c_str(), asyncContext->info.permStateAbilityName.c_str());
260 want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.permStateAbilityName);
261 want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
262 want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
263 return CreateUIExtension(want, asyncContext);
264 }
265
RequestPermissionOnSetting(OHOS::AbilityRuntime::Context * context,CArrString cPermissionList,const std::function<void (RetDataCArrI32)> & callbackRef)266 void FfiRequestPermissionOnSetting::RequestPermissionOnSetting(OHOS::AbilityRuntime::Context* context,
267 CArrString cPermissionList, const std::function<void(RetDataCArrI32)>& callbackRef)
268 {
269 RetDataCArrI32 retArr = {.code = CJ_OK, .data = {.head = nullptr, .size = 0}};
270 std::shared_ptr<RequestPermOnSettingAsyncContext> asyncContext =
271 std::make_shared<RequestPermOnSettingAsyncContext>();
272 if (!ParseRequestPermissionOnSetting(context, cPermissionList, asyncContext)) {
273 LOGE("Param invalid");
274 retArr.code = CJ_ERROR_PARAM_INVALID;
275 callbackRef(retArr);
276 return;
277 }
278 asyncContext->callbackRef = callbackRef;
279
280 int32_t result = StartUIExtension(asyncContext);
281 if (result != CJ_OK) {
282 LOGE("Start UI failed, result %{public}d", result);
283 retArr.code = result;
284 callbackRef(retArr);
285 }
286 return;
287 }
288
ParseRequestPermissionOnSetting(OHOS::AbilityRuntime::Context * context,CArrString cPermissionList,const std::shared_ptr<RequestPermOnSettingAsyncContext> & asyncContext)289 bool FfiRequestPermissionOnSetting::ParseRequestPermissionOnSetting(OHOS::AbilityRuntime::Context* context,
290 CArrString cPermissionList, const std::shared_ptr<RequestPermOnSettingAsyncContext>& asyncContext)
291 {
292 AccessTokenID tokenID = 0;
293 auto contextSharedPtr = context->shared_from_this();
294 asyncContext->abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(contextSharedPtr);
295 if (asyncContext->abilityContext != nullptr) {
296 asyncContext->uiAbilityFlag = true;
297 tokenID = asyncContext->abilityContext->GetApplicationInfo()->accessTokenId;
298 } else {
299 asyncContext->uiExtensionContext =
300 AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(contextSharedPtr);
301 if (asyncContext->uiExtensionContext == nullptr) {
302 LOGE("Convert to ui extension context failed");
303 return false;
304 }
305 tokenID = asyncContext->uiExtensionContext->GetApplicationInfo()->accessTokenId;
306 }
307 if (tokenID != static_cast<AccessTokenID>(GetSelfTokenID())) {
308 LOGE("tokenID invalid");
309 return false;
310 }
311
312 // check PermissionList
313 if (cPermissionList.size == 0) {
314 LOGE("PermissionList is empty");
315 return false;
316 }
317
318 std::vector<std::string> permList;
319 for (int64_t i = 0; i < cPermissionList.size; i++) {
320 permList.emplace_back(std::string(cPermissionList.head[i]));
321 }
322 asyncContext->permissionList = permList;
323 return true;
324 }
325 }
326 } // namespace CJSystemapi
327 } // namespace OHOS
328