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