• 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 #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