• 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_global_switch_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 GLOBAL_SWITCH_KEY = "ohos.user.setting.global_switch";
32 const std::string GLOBAL_SWITCH_RESULT_KEY = "ohos.user.setting.global_switch.result";
33 
34 // error code from dialog of global switch
35 const int32_t RET_SUCCESS = 0;
36 const int32_t REQUEST_ALREADY_EXIST = 1;
37 const int32_t GLOBAL_TYPE_IS_NOT_SUPPORT = 2;
38 const int32_t SWITCH_IS_ALREADY_OPEN = 3;
39 
40 std::mutex g_lockFlag;
41 }
42 
43 extern "C" {
TransferToCJErrorCode(int32_t errCode)44 static int32_t TransferToCJErrorCode(int32_t errCode)
45 {
46     int32_t cjCode = CJ_OK;
47     switch (errCode) {
48         case RET_SUCCESS:
49             cjCode = CJ_OK;
50             break;
51         case REQUEST_ALREADY_EXIST:
52             cjCode = CJ_ERROR_REQUEST_IS_ALREADY_EXIST;
53             break;
54         case GLOBAL_TYPE_IS_NOT_SUPPORT:
55             cjCode = CJ_ERROR_PARAM_INVALID;
56             break;
57         case SWITCH_IS_ALREADY_OPEN:
58             cjCode = CJ_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN;
59             break;
60         default:
61             cjCode = CJ_ERROR_INNER;
62             break;
63     }
64     return cjCode;
65 }
66 
ReleaseHandler(int32_t code)67 void SwitchOnSettingUICallback::ReleaseHandler(int32_t code)
68 {
69     {
70         std::lock_guard<std::mutex> lock(g_lockFlag);
71         if (this->reqContext_->releaseFlag) {
72             return;
73         }
74         this->reqContext_->releaseFlag = true;
75     }
76     Ace::UIContent* uiContent = nullptr;
77     if (this->reqContext_->uiAbilityFlag) {
78         uiContent = this->reqContext_->abilityContext->GetUIContent();
79     } else {
80         uiContent = this->reqContext_->uiExtensionContext->GetUIContent();
81     }
82     if (uiContent != nullptr) {
83         LOGI("Close uiextension component");
84         uiContent->CloseModalUIExtension(this->sessionId_);
85     }
86     if (code == 0) { // the dialog terminate normally
87         return;
88     }
89     LOGE("ReleaseHandler exception: %{public}d", code);
90     RetDataBool ret = {.code = code, .data = this->reqContext_->switchStatus};
91     this->reqContext_->callbackRef(ret);
92 }
93 
SwitchOnSettingUICallback(const std::shared_ptr<RequestGlobalSwitchAsyncContext> & reqContext)94 SwitchOnSettingUICallback::SwitchOnSettingUICallback(const std::shared_ptr<RequestGlobalSwitchAsyncContext>& reqContext)
95 {
96     this->reqContext_ = reqContext;
97 }
98 
~SwitchOnSettingUICallback()99 SwitchOnSettingUICallback::~SwitchOnSettingUICallback()
100 {}
101 
SetSessionId(int32_t sessionId)102 void SwitchOnSettingUICallback::SetSessionId(int32_t sessionId)
103 {
104     this->sessionId_ = sessionId;
105 }
106 
107 /*
108  * when UIExtensionAbility disconnect or use terminate or process die
109  * releaseCode is 0 when process normal exit
110  */
OnRelease(int32_t releaseCode)111 void SwitchOnSettingUICallback::OnRelease(int32_t releaseCode)
112 {
113     LOGI("OnRelease releaseCode is %{public}d", releaseCode);
114     ReleaseHandler(releaseCode);
115 }
116 
117 /*
118  * when UIExtensionAbility use terminateSelfWithResult
119  */
OnResult(int32_t resultCode,const AAFwk::Want & result)120 void SwitchOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
121 {
122     this->reqContext_->errorCode = result.GetIntParam(RESULT_ERROR_KEY, -1);
123     this->reqContext_->switchStatus = result.GetBoolParam(GLOBAL_SWITCH_RESULT_KEY, false);
124     LOGI("ResultCode is %{public}d, errorCode=%{public}d, switchStatus=%{public}d",
125         resultCode, this->reqContext_->errorCode, this->reqContext_->switchStatus);
126 
127     int32_t cjErrorCode = TransferToCJErrorCode(this->reqContext_->errorCode);
128     RetDataBool ret = {.code = cjErrorCode, .data = this->reqContext_->switchStatus};
129     this->reqContext_->callbackRef(ret);
130     ReleaseHandler(0);
131 }
132 
133 /*
134  * when UIExtensionAbility send message to UIExtensionComponent
135  */
OnReceive(const AAFwk::WantParams & receive)136 void SwitchOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive)
137 {
138     LOGI("OnReceive called!");
139 }
140 
141 /*
142  * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
143  */
OnError(int32_t code,const std::string & name,const std::string & message)144 void SwitchOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
145 {
146     LOGE("OnError: code is %{public}d, name is %{public}s, message is %{public}s",
147         code, name.c_str(), message.c_str());
148     ReleaseHandler(code);
149 }
150 
151 /*
152  * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
153  * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
154  */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)155 void SwitchOnSettingUICallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
156 {
157     LOGI("Connect to UIExtensionAbility successfully.");
158 }
159 
160 /*
161  * when UIExtensionComponent destructed
162  */
OnDestroy()163 void SwitchOnSettingUICallback::OnDestroy()
164 {
165     LOGI("UIExtensionAbility destructed.");
166 }
167 
BindCallbacks(std::shared_ptr<SwitchOnSettingUICallback> uiExtCallback)168 static Ace::ModalUIExtensionCallbacks BindCallbacks(std::shared_ptr<SwitchOnSettingUICallback> uiExtCallback)
169 {
170     Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
171         [uiExtCallback](int32_t releaseCode) {
172             uiExtCallback->OnRelease(releaseCode);
173         },
174         [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
175             uiExtCallback->OnResult(resultCode, result);
176         },
177         [uiExtCallback](const OHOS::AAFwk::WantParams& request) {
178             uiExtCallback->OnReceive(request);
179         },
180         [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]]const std::string& message) {
181             uiExtCallback->OnError(code, name, name);
182         },
183         [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy) {
184             uiExtCallback->OnRemoteReady(uiProxy);
185         },
186         [uiExtCallback] {
187             uiExtCallback->OnDestroy();
188         },
189     };
190     return uiExtensionCallbacks;
191 }
192 
CreateUIExtension(const Want & want,std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)193 static int32_t CreateUIExtension(const Want &want, std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
194 {
195     if (asyncContext == nullptr) {
196         return CJ_ERROR_INNER;
197     }
198     Ace::UIContent* uiContent = nullptr;
199     if (asyncContext->uiAbilityFlag) {
200         uiContent = asyncContext->abilityContext->GetUIContent();
201     } else {
202         uiContent = asyncContext->uiExtensionContext->GetUIContent();
203     }
204 
205     if (uiContent == nullptr) {
206         LOGE("Get ui content failed.");
207         return CJ_ERROR_PARAM_INVALID;
208     }
209     auto uiExtCallback = std::make_shared<SwitchOnSettingUICallback>(asyncContext);
210     auto uiExtensionCallbacks = BindCallbacks(uiExtCallback);
211     Ace::ModalUIExtensionConfig config;
212     config.isProhibitBack = true;
213     int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
214     if (sessionId == 0) {
215         LOGE("CreateModalUIExtension failed.");
216         return CJ_ERROR_INNER;
217     }
218     uiExtCallback->SetSessionId(sessionId);
219     return CJ_OK;
220 }
221 
StartUIExtension(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)222 static int32_t StartUIExtension(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
223 {
224     AAFwk::Want want;
225     AccessTokenKit::GetPermissionManagerInfo(asyncContext->info);
226     LOGI("bundleName: %{public}s, globalSwitchAbilityName: %{public}s.",
227         asyncContext->info.grantBundleName.c_str(), asyncContext->info.globalSwitchAbilityName.c_str());
228     want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.globalSwitchAbilityName);
229     want.SetParam(GLOBAL_SWITCH_KEY, asyncContext->switchType);
230     want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
231     return CreateUIExtension(want, asyncContext);
232 }
233 
RequestGlobalSwitch(OHOS::AbilityRuntime::Context * context,int32_t switchType,const std::function<void (RetDataBool)> & callbackRef)234 void FfiRequestGlobalSwitchOnSetting::RequestGlobalSwitch(OHOS::AbilityRuntime::Context* context, int32_t switchType,
235     const std::function<void(RetDataBool)>& callbackRef)
236 {
237     RetDataBool ret = {.code = CJ_ERROR_INNER, .data = false};
238     std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext = std::make_shared<RequestGlobalSwitchAsyncContext>();
239     if (!ParseRequestGlobalSwitch(context, asyncContext)) {
240         LOGE("RequestGlobalSwitch param invalid.");
241         ret.code = CJ_ERROR_PARAM_INVALID;
242         callbackRef(ret);
243         return;
244     }
245     asyncContext->switchType = switchType;
246     asyncContext->callbackRef = callbackRef;
247 
248     int32_t result = StartUIExtension(asyncContext);
249     ret.code = result;
250     if (result != CJ_OK) {
251         callbackRef(ret);
252     }
253     return;
254 }
255 
ParseRequestGlobalSwitch(OHOS::AbilityRuntime::Context * context,const std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)256 bool FfiRequestGlobalSwitchOnSetting::ParseRequestGlobalSwitch(OHOS::AbilityRuntime::Context* context,
257     const std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
258 {
259     AccessTokenID tokenID = 0;
260     auto contextSharedPtr = context->shared_from_this();
261     asyncContext->abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(contextSharedPtr);
262     if (asyncContext->abilityContext != nullptr) {
263         asyncContext->uiAbilityFlag = true;
264         tokenID = asyncContext->abilityContext->GetApplicationInfo()->accessTokenId;
265     } else {
266         asyncContext->uiExtensionContext =
267             AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(contextSharedPtr);
268         if (asyncContext->uiExtensionContext == nullptr) {
269             LOGE("Convert to ui extension context failed");
270             return false;
271         }
272         tokenID = asyncContext->uiExtensionContext->GetApplicationInfo()->accessTokenId;
273     }
274     if (tokenID != static_cast<AccessTokenID>(GetSelfTokenID())) {
275         LOGE("tokenID error");
276         return false;
277     }
278     return true;
279 }
280 }
281 } // namespace CJSystemapi
282 } // namespace OHOS
283