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_global_switch_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 const std::string GLOBAL_SWITCH_KEY = "ohos.user.setting.global_switch";
27 const std::string GLOBAL_SWITCH_RESULT_KEY = "ohos.user.setting.global_switch.result";
28 const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code";
29 const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType";
30 const std::string UI_EXTENSION_TYPE = "sys/commonUI";
31 std::shared_ptr<RequestInstanceControl> g_requestInstanceControl = nullptr;
32 std::mutex g_requestInstanceControlLock;
33
34 // error code from dialog
35 constexpr int32_t REQUEST_ALREADY_EXIST = 1;
36 constexpr int32_t GLOBAL_TYPE_IS_NOT_SUPPORT = 2;
37 constexpr int32_t SWITCH_IS_ALREADY_OPEN = 3;
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
RequestGlobalSwitchAsyncContext(ani_vm * vm,ani_env * env)49 RequestGlobalSwitchAsyncContext::RequestGlobalSwitchAsyncContext(ani_vm* vm, ani_env* env)
50 : RequestAsyncContextBase(vm, env, REQUEST_GLOBAL_SWITCH_ON_SETTING)
51 {}
52
~RequestGlobalSwitchAsyncContext()53 RequestGlobalSwitchAsyncContext::~RequestGlobalSwitchAsyncContext()
54 {
55 Clear();
56 }
57
ConvertErrorCode(int32_t errCode)58 int32_t RequestGlobalSwitchAsyncContext::ConvertErrorCode(int32_t errCode)
59 {
60 int32_t stsCode = STS_OK;
61 switch (errCode) {
62 case RET_SUCCESS:
63 stsCode = STS_OK;
64 break;
65 case REQUEST_ALREADY_EXIST:
66 stsCode = STS_ERROR_REQUEST_IS_ALREADY_EXIST;
67 break;
68 case GLOBAL_TYPE_IS_NOT_SUPPORT:
69 stsCode = STS_ERROR_PARAM_INVALID;
70 break;
71 case SWITCH_IS_ALREADY_OPEN:
72 stsCode = STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN;
73 break;
74 default:
75 stsCode = STS_ERROR_INNER;
76 break;
77 }
78 LOGI(ATM_DOMAIN, ATM_TAG, "Dialog error(%{public}d) stsCode(%{public}d).", errCode, stsCode);
79 return stsCode;
80 }
81
82
WrapResult(ani_env * env)83 ani_object RequestGlobalSwitchAsyncContext::WrapResult(ani_env* env)
84 {
85 return CreateBooleanObject(env, this->switchStatus);
86 }
87
ProcessUIExtensionCallback(const OHOS::AAFwk::Want & result)88 void RequestGlobalSwitchAsyncContext::ProcessUIExtensionCallback(const OHOS::AAFwk::Want& result)
89 {
90 this->result.errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0);
91 this->switchStatus = result.GetBoolParam(GLOBAL_SWITCH_RESULT_KEY, 0);
92 }
93
StartExtensionAbility(std::shared_ptr<RequestAsyncContextBase> asyncContext)94 void RequestGlobalSwitchAsyncContext::StartExtensionAbility(std::shared_ptr<RequestAsyncContextBase> asyncContext)
95 {
96 AccessTokenKit::GetPermissionManagerInfo(this->info);
97 LOGI(ATM_DOMAIN, ATM_TAG, "BundleName: %{public}s, permStateAbilityName: %{public}s.",
98 this->info.grantBundleName.c_str(), this->info.permStateAbilityName.c_str());
99 OHOS::AAFwk::Want want;
100 want.SetElementName(this->info.grantBundleName, this->info.globalSwitchAbilityName);
101 want.SetParam(GLOBAL_SWITCH_KEY, this->switchType);
102 want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
103 CreateUIExtension(want, asyncContext, GetRequestInstanceControl());
104 }
105
IsSameRequest(const std::shared_ptr<RequestAsyncContextBase> other)106 bool RequestGlobalSwitchAsyncContext::IsSameRequest(const std::shared_ptr<RequestAsyncContextBase> other)
107 {
108 if (other == nullptr) {
109 LOGE(ATM_DOMAIN, ATM_TAG, "other is nullptr.");
110 return false;
111 }
112 auto ptr = std::static_pointer_cast<RequestGlobalSwitchAsyncContext>(other);
113 return switchType == ptr->switchType;
114 }
115
CopyResult(const std::shared_ptr<RequestAsyncContextBase> other)116 void RequestGlobalSwitchAsyncContext::CopyResult(const std::shared_ptr<RequestAsyncContextBase> other)
117 {
118 if (other == nullptr) {
119 LOGE(ATM_DOMAIN, ATM_TAG, "other is nullptr.");
120 return;
121 }
122 auto ptr = std::static_pointer_cast<RequestGlobalSwitchAsyncContext>(other);
123 this->result.errorCode = ptr->result.errorCode;
124 this->switchStatus = ptr->switchStatus;
125 this->isDynamic = false;
126 }
127
CheckDynamicRequest()128 bool RequestGlobalSwitchAsyncContext::CheckDynamicRequest()
129 {
130 if (!this->isDynamic) {
131 LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission extension");
132 FinishCallback();
133 return false;
134 }
135 return true;
136 }
137
NoNeedUpdate()138 bool RequestGlobalSwitchAsyncContext::NoNeedUpdate()
139 {
140 return result.errorCode != RET_SUCCESS || switchStatus == false;
141 }
142
ProcessFailResult(int32_t code)143 void RequestGlobalSwitchAsyncContext::ProcessFailResult(int32_t code)
144 {
145 if (code == -1) {
146 result.errorCode = code;
147 }
148 }
149
ParseRequestGlobalSwitch(ani_env * env,ani_object & aniContext,ani_int type,ani_object callback,std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)150 static bool ParseRequestGlobalSwitch(ani_env* env, ani_object& aniContext, ani_int type,
151 ani_object callback, std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
152 {
153 asyncContext->switchType = static_cast<SwitchType>(type);
154
155 if (!asyncContext->FillInfoFromContext(aniContext) != ANI_OK) {
156 BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL,
157 GetParamErrorMsg("context", "UIAbility or UIExtension Context"));
158 return false;
159 }
160 if (!AniParseCallback(env, reinterpret_cast<ani_ref>(callback), asyncContext->callbackRef)) {
161 return false;
162 }
163 return true;
164 }
165
RequestGlobalSwitchExecute(ani_env * env,ani_object object,ani_object aniContext,ani_int type,ani_object callback)166 void RequestGlobalSwitchExecute([[maybe_unused]] ani_env* env,
167 [[maybe_unused]] ani_object object, ani_object aniContext, ani_int type, ani_object callback)
168 {
169 if (env == nullptr || callback == nullptr) {
170 LOGE(ATM_DOMAIN, ATM_TAG, "Env or permissionList or callback is null.");
171 return;
172 }
173
174 ani_vm* vm;
175 ani_status status = env->GetVM(&vm);
176 if (status != ANI_OK) {
177 LOGE(ATM_DOMAIN, ATM_TAG, "Failed to GetVM, error=%{public}d.", static_cast<int32_t>(status));
178 return;
179 }
180 std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext =
181 std::make_shared<RequestGlobalSwitchAsyncContext>(vm, env);
182 if (!ParseRequestGlobalSwitch(env, aniContext, type, callback, asyncContext)) {
183 return;
184 }
185
186 ani_object result = CreateBooleanObject(env, false);
187 static AccessTokenID selfTokenID = static_cast<AccessTokenID>(GetSelfTokenID());
188 if (selfTokenID != asyncContext->tokenId) {
189 LOGE(ATM_DOMAIN, ATM_TAG, "The context tokenID %{public}d is not same with selfTokenID %{public}d.",
190 asyncContext->tokenId, selfTokenID);
191 ani_object error =
192 BusinessErrorAni::CreateError(env, STS_ERROR_PARAM_INVALID, GetErrorMessage(STS_ERROR_PARAM_INVALID,
193 "The specified context does not belong to the current application."));
194 (void)ExecuteAsyncCallback(env, callback, error, result);
195 return;
196 }
197 asyncContext->GetInstanceId();
198 GetRequestInstanceControl()->AddCallbackByInstanceId(asyncContext);
199 LOGI(ATM_DOMAIN, ATM_TAG, "Start to pop ui extension dialog");
200
201 if (asyncContext->result.errorCode != RET_SUCCESS) {
202 asyncContext->FinishCallback();
203 LOGW(ATM_DOMAIN, ATM_TAG, "Failed to pop uiextension dialog.");
204 }
205 }
206 } // namespace AccessToken
207 } // namespace Security
208 } // namespace OHOS