• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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