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 #include "napi_request_global_switch_on_setting.h"
16
17 #include "ability.h"
18 #include "accesstoken_kit.h"
19 #include "accesstoken_common_log.h"
20 #include "napi_base_context.h"
21 #include "token_setproc.h"
22 #include "want.h"
23
24 namespace OHOS {
25 namespace Security {
26 namespace AccessToken {
27 std::map<int32_t, std::vector<std::shared_ptr<RequestGlobalSwitchAsyncContext>>>
28 RequestGlobalSwitchAsyncInstanceControl::instanceIdMap_;
29 std::mutex RequestGlobalSwitchAsyncInstanceControl::instanceIdMutex_;
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 const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code";
34 const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType";
35 const std::string UI_EXTENSION_TYPE = "sys/commonUI";
36
37 // error code from dialog
38 const int32_t REQUEST_ALREADY_EXIST = 1;
39 const int32_t GLOBAL_TYPE_IS_NOT_SUPPORT = 2;
40 const int32_t SWITCH_IS_ALREADY_OPEN = 3;
41 std::mutex g_lockFlag;
42 } // namespace
TransferToJsErrorCode(int32_t errCode)43 static int32_t TransferToJsErrorCode(int32_t errCode)
44 {
45 int32_t jsCode = JS_ERROR_INNER;
46 switch (errCode) {
47 case RET_SUCCESS:
48 jsCode = JS_OK;
49 break;
50 case REQUEST_ALREADY_EXIST:
51 jsCode = JS_ERROR_REQUEST_IS_ALREADY_EXIST;
52 break;
53 case GLOBAL_TYPE_IS_NOT_SUPPORT:
54 jsCode = JS_ERROR_PARAM_INVALID;
55 break;
56 case SWITCH_IS_ALREADY_OPEN:
57 jsCode = JS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN;
58 break;
59 default:
60 break;
61 }
62 LOGI(ATM_DOMAIN, ATM_TAG, "Dialog error(%{public}d) jsCode(%{public}d).", errCode, jsCode);
63 return jsCode;
64 }
65
ReturnPromiseResult(napi_env env,const RequestGlobalSwitchAsyncContext & context,napi_value result)66 static void ReturnPromiseResult(napi_env env, const RequestGlobalSwitchAsyncContext& context, napi_value result)
67 {
68 if (context.result.errorCode != RET_SUCCESS) {
69 int32_t jsCode = TransferToJsErrorCode(context.result.errorCode);
70 napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode, context.result.errorMsg));
71 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, context.deferred, businessError));
72 } else {
73 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, context.deferred, result));
74 }
75 }
76
WrapVoidToJS(napi_env env)77 static napi_value WrapVoidToJS(napi_env env)
78 {
79 napi_value result = nullptr;
80 NAPI_CALL(env, napi_get_null(env, &result));
81 return result;
82 }
83
GetUIContent(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)84 static Ace::UIContent* GetUIContent(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
85 {
86 if (asyncContext == nullptr) {
87 return nullptr;
88 }
89 Ace::UIContent* uiContent = nullptr;
90 if (asyncContext->uiAbilityFlag) {
91 uiContent = asyncContext->abilityContext->GetUIContent();
92 } else {
93 uiContent = asyncContext->uiExtensionContext->GetUIContent();
94 }
95 return uiContent;
96 }
97
GetContext(const napi_env & env,const napi_value & value,std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)98 static napi_value GetContext(
99 const napi_env &env, const napi_value &value, std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
100 {
101 bool stageMode = false;
102 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
103 if (status != napi_ok || !stageMode) {
104 LOGE(ATM_DOMAIN, ATM_TAG, "It is not a stage mode.");
105 return nullptr;
106 } else {
107 auto context = AbilityRuntime::GetStageModeContext(env, value);
108 if (context == nullptr) {
109 LOGE(ATM_DOMAIN, ATM_TAG, "Failed to Get application context.");
110 return nullptr;
111 }
112 asyncContext->abilityContext =
113 AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
114 if (asyncContext->abilityContext != nullptr) {
115 asyncContext->uiAbilityFlag = true;
116 } else {
117 LOGW(ATM_DOMAIN, ATM_TAG, "Failed to convert to ability context.");
118 asyncContext->uiExtensionContext =
119 AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
120 if (asyncContext->uiExtensionContext == nullptr) {
121 LOGE(ATM_DOMAIN, ATM_TAG, "Failed to convert to ui extension context.");
122 return nullptr;
123 }
124 }
125 return WrapVoidToJS(env);
126 }
127 }
128
GlobalSwitchResultsCallbackUI(int32_t errorCode,bool switchStatus,std::shared_ptr<RequestGlobalSwitchAsyncContext> & data)129 static void GlobalSwitchResultsCallbackUI(int32_t errorCode,
130 bool switchStatus, std::shared_ptr<RequestGlobalSwitchAsyncContext>& data)
131 {
132 auto* retCB = new (std::nothrow) SwitchOnSettingResultCallback();
133 if (retCB == nullptr) {
134 LOGE(ATM_DOMAIN, ATM_TAG, "Insufficient memory for work!");
135 return;
136 }
137 std::unique_ptr<SwitchOnSettingResultCallback> callbackPtr {retCB};
138 retCB->errorCode = errorCode;
139 retCB->switchStatus = switchStatus;
140 retCB->data = data;
141 auto task = [retCB]() {
142 std::unique_ptr<SwitchOnSettingResultCallback> callback {retCB};
143 std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext = retCB->data;
144 if (asyncContext == nullptr) {
145 return;
146 }
147 asyncContext->result.errorCode = retCB->errorCode;
148 napi_handle_scope scope = nullptr;
149 napi_open_handle_scope(asyncContext->env, &scope);
150 if (scope == nullptr) {
151 LOGE(ATM_DOMAIN, ATM_TAG, "Napi_open_handle_scope failed");
152 return;
153 }
154 napi_value requestResult = nullptr;
155 NAPI_CALL_RETURN_VOID(asyncContext->env,
156 napi_get_boolean(asyncContext->env, retCB->switchStatus, &requestResult));
157
158 ReturnPromiseResult(asyncContext->env, *asyncContext, requestResult);
159 napi_close_handle_scope(asyncContext->env, scope);
160 };
161 if (napi_status::napi_ok != napi_send_event(data->env, task, napi_eprio_immediate)) {
162 LOGE(ATM_DOMAIN, ATM_TAG, "GlobalSwitchResultsCallbackUI: Failed to SendEvent");
163 } else {
164 callbackPtr.release();
165 }
166 }
167
CloseModalUIExtensionMainThread(std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext,int32_t sessionId)168 static void CloseModalUIExtensionMainThread(std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext,
169 int32_t sessionId)
170 {
171 auto task = [asyncContext, sessionId]() {
172 Ace::UIContent* uiContent = GetUIContent(asyncContext);
173 if (uiContent == nullptr) {
174 LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
175 return;
176 }
177 LOGI(ATM_DOMAIN, ATM_TAG, "Close uiextension component");
178 uiContent->CloseModalUIExtension(sessionId);
179 };
180 #ifdef EVENTHANDLER_ENABLE
181 if (asyncContext->handler_ != nullptr) {
182 asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread");
183 } else {
184 task();
185 }
186 #else
187 task();
188 #endif
189 }
190
ReleaseHandler(int32_t code)191 void SwitchOnSettingUICallback::ReleaseHandler(int32_t code)
192 {
193 if (this->reqContext_ == nullptr) {
194 LOGE(ATM_DOMAIN, ATM_TAG, "Request context is null.");
195 return;
196 }
197 {
198 std::lock_guard<std::mutex> lock(g_lockFlag);
199 if (this->reqContext_->releaseFlag) {
200 LOGW(ATM_DOMAIN, ATM_TAG, "Callback has executed.");
201 return;
202 }
203 this->reqContext_->releaseFlag = true;
204 }
205 CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_);
206 if (code == -1) {
207 this->reqContext_->errorCode = code;
208 }
209 RequestGlobalSwitchAsyncInstanceControl::UpdateQueueData(this->reqContext_);
210 RequestGlobalSwitchAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId);
211 GlobalSwitchResultsCallbackUI(this->reqContext_->errorCode, this->reqContext_->switchStatus, this->reqContext_);
212 }
213
SwitchOnSettingUICallback(const std::shared_ptr<RequestGlobalSwitchAsyncContext> & reqContext)214 SwitchOnSettingUICallback::SwitchOnSettingUICallback(
215 const std::shared_ptr<RequestGlobalSwitchAsyncContext>& reqContext)
216 {
217 this->reqContext_ = reqContext;
218 }
219
~SwitchOnSettingUICallback()220 SwitchOnSettingUICallback::~SwitchOnSettingUICallback()
221 {}
222
SetSessionId(int32_t sessionId)223 void SwitchOnSettingUICallback::SetSessionId(int32_t sessionId)
224 {
225 this->sessionId_ = sessionId;
226 }
227
228 /*
229 * when UIExtensionAbility use terminateSelfWithResult
230 */
OnResult(int32_t resultCode,const AAFwk::Want & result)231 void SwitchOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
232 {
233 if (this->reqContext_ == nullptr) {
234 LOGE(ATM_DOMAIN, ATM_TAG, "Request context is null.");
235 return;
236 }
237 this->reqContext_->errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0);
238 this->reqContext_->switchStatus = result.GetBoolParam(GLOBAL_SWITCH_RESULT_KEY, 0);
239 LOGI(ATM_DOMAIN, ATM_TAG, "ResultCode is %{public}d, errorCode=%{public}d, switchStatus=%{public}d",
240 resultCode, this->reqContext_->errorCode, this->reqContext_->switchStatus);
241 ReleaseHandler(0);
242 }
243
244 /*
245 * when UIExtensionAbility send message to UIExtensionComponent
246 */
OnReceive(const AAFwk::WantParams & receive)247 void SwitchOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive)
248 {
249 LOGI(ATM_DOMAIN, ATM_TAG, "Called!");
250 }
251
252 /*
253 * when UIExtensionAbility disconnect or use terminate or process die
254 * releaseCode is 0 when process normal exit
255 */
OnRelease(int32_t releaseCode)256 void SwitchOnSettingUICallback::OnRelease(int32_t releaseCode)
257 {
258 LOGI(ATM_DOMAIN, ATM_TAG, "ReleaseCode is %{public}d", releaseCode);
259
260 ReleaseHandler(-1);
261 }
262
263 /*
264 * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
265 */
OnError(int32_t code,const std::string & name,const std::string & message)266 void SwitchOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
267 {
268 LOGI(ATM_DOMAIN, ATM_TAG, "Code is %{public}d, name is %{public}s, message is %{public}s",
269 code, name.c_str(), message.c_str());
270
271 ReleaseHandler(-1);
272 }
273
274 /*
275 * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
276 * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
277 */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)278 void SwitchOnSettingUICallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
279 {
280 LOGI(ATM_DOMAIN, ATM_TAG, "Connect to UIExtensionAbility successfully.");
281 }
282
283 /*
284 * when UIExtensionComponent destructed
285 */
OnDestroy()286 void SwitchOnSettingUICallback::OnDestroy()
287 {
288 LOGI(ATM_DOMAIN, ATM_TAG, "UIExtensionAbility destructed.");
289 ReleaseHandler(-1);
290 }
291
CreateUIExtensionMainThread(std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext,const AAFwk::Want & want,const Ace::ModalUIExtensionCallbacks & uiExtensionCallbacks,const std::shared_ptr<SwitchOnSettingUICallback> & uiExtCallback)292 static void CreateUIExtensionMainThread(std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext,
293 const AAFwk::Want& want, const Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks,
294 const std::shared_ptr<SwitchOnSettingUICallback>& uiExtCallback)
295 {
296 auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() {
297 Ace::UIContent* uiContent = GetUIContent(asyncContext);
298 if (uiContent == nullptr) {
299 LOGE(ATM_DOMAIN, ATM_TAG, "Failed to get ui content!");
300 asyncContext->result.errorCode = RET_FAILED;
301 return;
302 }
303
304 Ace::ModalUIExtensionConfig config;
305 config.isProhibitBack = true;
306 config.isModalRequestFocus = false;
307 int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
308 LOGI(ATM_DOMAIN, ATM_TAG, "Create end, sessionId: %{public}d, tokenId: %{public}d, switchType: %{public}d.",
309 sessionId, asyncContext->tokenId, asyncContext->switchType);
310 if (sessionId == 0) {
311 LOGE(ATM_DOMAIN, ATM_TAG, "Failed to create component, sessionId is 0.");
312 asyncContext->result.errorCode = RET_FAILED;
313 return;
314 }
315 uiExtCallback->SetSessionId(sessionId);
316 };
317 #ifdef EVENTHANDLER_ENABLE
318 if (asyncContext->handler_ != nullptr) {
319 asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread");
320 } else {
321 task();
322 }
323 #else
324 task();
325 #endif
326 }
327
CreateUIExtension(const Want & want,std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)328 static int32_t CreateUIExtension(const Want &want, std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
329 {
330 auto uiExtCallback = std::make_shared<SwitchOnSettingUICallback>(asyncContext);
331 Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
332 [uiExtCallback](int32_t releaseCode) {
333 uiExtCallback->OnRelease(releaseCode);
334 },
335 [uiExtCallback](int32_t resultCode, const AAFwk::Want &result) {
336 uiExtCallback->OnResult(resultCode, result);
337 },
338 [uiExtCallback](const AAFwk::WantParams &receive) {
339 uiExtCallback->OnReceive(receive);
340 },
341 [uiExtCallback](int32_t code, const std::string &name, [[maybe_unused]] const std::string &message) {
342 uiExtCallback->OnError(code, name, name);
343 },
344 [uiExtCallback](const std::shared_ptr<Ace::ModalUIExtensionProxy> &uiProxy) {
345 uiExtCallback->OnRemoteReady(uiProxy);
346 },
347 [uiExtCallback]() {
348 uiExtCallback->OnDestroy();
349 },
350 };
351
352 CreateUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback);
353 if (asyncContext->result.errorCode == RET_FAILED) {
354 return RET_FAILED;
355 }
356 return RET_SUCCESS;
357 }
358
StartUIExtension(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)359 static int32_t StartUIExtension(std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext)
360 {
361 AAFwk::Want want;
362 AccessTokenKit::GetPermissionManagerInfo(asyncContext->info);
363 LOGI(ATM_DOMAIN, ATM_TAG, "bundleName: %{public}s, globalSwitchAbilityName: %{public}s.",
364 asyncContext->info.grantBundleName.c_str(), asyncContext->info.globalSwitchAbilityName.c_str());
365 want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.globalSwitchAbilityName);
366 want.SetParam(GLOBAL_SWITCH_KEY, asyncContext->switchType);
367 want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
368
369 return CreateUIExtension(want, asyncContext);
370 }
371
GetInstanceId(std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)372 static void GetInstanceId(std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
373 {
374 auto task = [asyncContext]() {
375 Ace::UIContent* uiContent = GetUIContent(asyncContext);
376 if (uiContent == nullptr) {
377 LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!");
378 return;
379 }
380 asyncContext->instanceId = uiContent->GetInstanceId();
381 };
382 #ifdef EVENTHANDLER_ENABLE
383 if (asyncContext->handler_ != nullptr) {
384 asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId");
385 } else {
386 task();
387 }
388 #else
389 task();
390 #endif
391 LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d", asyncContext->instanceId);
392 }
393
AddCallbackByInstanceId(std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)394 void RequestGlobalSwitchAsyncInstanceControl::AddCallbackByInstanceId(
395 std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
396 {
397 LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d", asyncContext->instanceId);
398 {
399 std::lock_guard<std::mutex> lock(instanceIdMutex_);
400 auto iter = instanceIdMap_.find(asyncContext->instanceId);
401 // id is existed mean a pop window is showing, add context to waiting queue
402 if (iter != instanceIdMap_.end()) {
403 LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d has existed.", asyncContext->instanceId);
404 instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext);
405 return;
406 }
407 // make sure id is in map to indicate a pop-up window is showing
408 instanceIdMap_[asyncContext->instanceId] = {};
409 }
410 (void)StartUIExtension(asyncContext);
411 }
412
UpdateQueueData(const std::shared_ptr<RequestGlobalSwitchAsyncContext> & reqContext)413 void RequestGlobalSwitchAsyncInstanceControl::UpdateQueueData(
414 const std::shared_ptr<RequestGlobalSwitchAsyncContext>& reqContext)
415 {
416 if ((reqContext->errorCode != RET_SUCCESS) || !(reqContext->switchStatus)) {
417 LOGI(ATM_DOMAIN, ATM_TAG, "The queue data does not need to be updated.");
418 return;
419 }
420
421 {
422 std::lock_guard<std::mutex> lock(instanceIdMutex_);
423 int32_t id = reqContext->instanceId;
424 auto iter = instanceIdMap_.find(id);
425 if (iter == instanceIdMap_.end()) {
426 LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id);
427 return;
428 }
429 int32_t targetSwitchType = reqContext->switchType;
430 LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size());
431 for (auto& asyncContext : iter->second) {
432 if (asyncContext == nullptr) {
433 LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
434 continue;
435 }
436 if (targetSwitchType == asyncContext->switchType) {
437 asyncContext->errorCode = reqContext->errorCode;
438 asyncContext->switchStatus = reqContext->switchStatus;
439 asyncContext->isDynamic = false;
440 }
441 }
442 }
443 }
444
ExecCallback(int32_t id)445 void RequestGlobalSwitchAsyncInstanceControl::ExecCallback(int32_t id)
446 {
447 std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext = nullptr;
448 bool isDynamic = false;
449 {
450 std::lock_guard<std::mutex> lock(instanceIdMutex_);
451 auto iter = instanceIdMap_.find(id);
452 if (iter == instanceIdMap_.end()) {
453 LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id);
454 return;
455 }
456 while (!iter->second.empty()) {
457 LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size());
458 asyncContext = iter->second[0];
459 if (asyncContext == nullptr) {
460 LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
461 iter->second.erase(iter->second.begin());
462 continue;
463 }
464 iter->second.erase(iter->second.begin());
465 CheckDynamicRequest(asyncContext, isDynamic);
466 if (isDynamic) {
467 break;
468 }
469 }
470 if (iter->second.empty()) {
471 LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map is empty", id);
472 instanceIdMap_.erase(id);
473 }
474 }
475 if (isDynamic) {
476 (void)StartUIExtension(asyncContext);
477 }
478 }
479
CheckDynamicRequest(std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext,bool & isDynamic)480 void RequestGlobalSwitchAsyncInstanceControl::CheckDynamicRequest(
481 std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext, bool& isDynamic)
482 {
483 isDynamic = asyncContext->isDynamic;
484 if (!isDynamic) {
485 LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission exsion");
486 GlobalSwitchResultsCallbackUI(asyncContext->errorCode, asyncContext->switchStatus, asyncContext);
487 return;
488 }
489 }
490
RequestGlobalSwitch(napi_env env,napi_callback_info info)491 napi_value NapiRequestGlobalSwitch::RequestGlobalSwitch(napi_env env, napi_callback_info info)
492 {
493 LOGD(ATM_DOMAIN, ATM_TAG, "RequestGlobalSwitch begin.");
494 // use handle to protect asyncContext
495 std::shared_ptr<RequestGlobalSwitchAsyncContext> asyncContext =
496 std::make_shared<RequestGlobalSwitchAsyncContext>(env);
497
498 if (!ParseRequestGlobalSwitch(env, info, asyncContext)) {
499 return nullptr;
500 }
501 auto asyncContextHandle = std::make_unique<RequestGlobalSwitchAsyncContextHandle>(asyncContext);
502 if (asyncContextHandle->asyncContextPtr == nullptr) {
503 LOGE(ATM_DOMAIN, ATM_TAG, "AsyncContext is null.");
504 return nullptr;
505 }
506 napi_value result = nullptr;
507 if (asyncContextHandle->asyncContextPtr->callbackRef == nullptr) {
508 NAPI_CALL(env, napi_create_promise(env, &(asyncContextHandle->asyncContextPtr->deferred), &result));
509 } else {
510 NAPI_CALL(env, napi_get_undefined(env, &result));
511 }
512
513 napi_value resource = nullptr; // resource name
514 NAPI_CALL(env, napi_create_string_utf8(env, "RequestGlobalSwitch", NAPI_AUTO_LENGTH, &resource));
515 NAPI_CALL(env, napi_create_async_work(
516 env, nullptr, resource, RequestGlobalSwitchExecute, RequestGlobalSwitchComplete,
517 reinterpret_cast<void*>(asyncContextHandle.get()), &(asyncContextHandle->asyncContextPtr->work)));
518
519 NAPI_CALL(env,
520 napi_queue_async_work_with_qos(env, asyncContextHandle->asyncContextPtr->work, napi_qos_user_initiated));
521
522 LOGD(ATM_DOMAIN, ATM_TAG, "RequestGlobalSwitch end.");
523 asyncContextHandle.release();
524 return result;
525 }
526
ParseRequestGlobalSwitch(const napi_env & env,const napi_callback_info & cbInfo,std::shared_ptr<RequestGlobalSwitchAsyncContext> & asyncContext)527 bool NapiRequestGlobalSwitch::ParseRequestGlobalSwitch(const napi_env& env,
528 const napi_callback_info& cbInfo, std::shared_ptr<RequestGlobalSwitchAsyncContext>& asyncContext)
529 {
530 size_t argc = MAX_PARAMS_TWO;
531 napi_value argv[MAX_PARAMS_TWO] = { nullptr };
532 napi_value thisVar = nullptr;
533
534 if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
535 LOGE(ATM_DOMAIN, ATM_TAG, "Napi_get_cb_info failed");
536 return false;
537 }
538 if (argc < MAX_PARAMS_TWO) {
539 NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env,
540 JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
541 return false;
542 }
543 asyncContext->env = env;
544 std::string errMsg;
545
546 // argv[0] : context : AbilityContext
547 if (GetContext(env, argv[0], asyncContext) == nullptr) {
548 errMsg = GetParamErrorMsg("context", "UIAbility or UIExtension Context");
549 NAPI_CALL_BASE(
550 env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
551 return false;
552 }
553 LOGI(ATM_DOMAIN, ATM_TAG, "AsyncContext.uiAbilityFlag is: %{public}d.", asyncContext->uiAbilityFlag);
554
555 // argv[1] : type
556 if (!ParseInt32(env, argv[1], asyncContext->switchType)) {
557 errMsg = GetParamErrorMsg("type", "SwitchType");
558 NAPI_CALL_BASE(
559 env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
560 return false;
561 }
562 #ifdef EVENTHANDLER_ENABLE
563 asyncContext->handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
564 #endif
565 return true;
566 }
567
RequestGlobalSwitchExecute(napi_env env,void * data)568 void NapiRequestGlobalSwitch::RequestGlobalSwitchExecute(napi_env env, void* data)
569 {
570 // asyncContext release in complete
571 RequestGlobalSwitchAsyncContextHandle* asyncContextHandle =
572 reinterpret_cast<RequestGlobalSwitchAsyncContextHandle*>(data);
573 if ((asyncContextHandle == nullptr) || (asyncContextHandle->asyncContextPtr == nullptr)) {
574 return;
575 }
576 if (asyncContextHandle->asyncContextPtr->uiAbilityFlag) {
577 if ((asyncContextHandle->asyncContextPtr->abilityContext == nullptr) ||
578 (asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo() == nullptr)) {
579 return;
580 }
581 asyncContextHandle->asyncContextPtr->tokenId =
582 asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo()->accessTokenId;
583 } else {
584 if ((asyncContextHandle->asyncContextPtr->uiExtensionContext == nullptr) ||
585 (asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo() == nullptr)) {
586 return;
587 }
588 asyncContextHandle->asyncContextPtr->tokenId =
589 asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo()->accessTokenId;
590 }
591 static AccessTokenID currToken = static_cast<AccessTokenID>(GetSelfTokenID());
592 if (asyncContextHandle->asyncContextPtr->tokenId != currToken) {
593 LOGE(ATM_DOMAIN, ATM_TAG,
594 "The context(token=%{public}d) is not belong to the current application(currToken=%{public}d).",
595 asyncContextHandle->asyncContextPtr->tokenId, currToken);
596 asyncContextHandle->asyncContextPtr->result.errorCode = ERR_PARAM_INVALID;
597 asyncContextHandle->asyncContextPtr->result.errorMsg =
598 "The specified context does not belong to the current application.";
599 return;
600 }
601
602 GetInstanceId(asyncContextHandle->asyncContextPtr);
603 LOGI(ATM_DOMAIN, ATM_TAG, "Start to pop ui extension dialog");
604
605 RequestGlobalSwitchAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr);
606 if (asyncContextHandle->asyncContextPtr->result.errorCode != RET_SUCCESS) {
607 LOGW(ATM_DOMAIN, ATM_TAG, "Failed to pop uiextension dialog.");
608 }
609 }
610
RequestGlobalSwitchComplete(napi_env env,napi_status status,void * data)611 void NapiRequestGlobalSwitch::RequestGlobalSwitchComplete(napi_env env, napi_status status, void* data)
612 {
613 LOGD(ATM_DOMAIN, ATM_TAG, "RequestGlobalSwitchComplete begin.");
614 RequestGlobalSwitchAsyncContextHandle* asyncContextHandle =
615 reinterpret_cast<RequestGlobalSwitchAsyncContextHandle*>(data);
616 if (asyncContextHandle == nullptr || asyncContextHandle->asyncContextPtr == nullptr) {
617 return;
618 }
619 std::unique_ptr<RequestGlobalSwitchAsyncContextHandle> callbackPtr {asyncContextHandle};
620
621 // need pop dialog
622 if (asyncContextHandle->asyncContextPtr->result.errorCode == RET_SUCCESS) {
623 return;
624 }
625 // return error
626 if (asyncContextHandle->asyncContextPtr->deferred != nullptr) {
627 int32_t jsCode = GetJsErrorCode(asyncContextHandle->asyncContextPtr->result.errorCode);
628 napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
629 NAPI_CALL_RETURN_VOID(env,
630 napi_reject_deferred(env, asyncContextHandle->asyncContextPtr->deferred, businessError));
631 }
632 }
633 } // namespace AccessToken
634 } // namespace Security
635 } // namespace OHOS