• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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_atmanager.h"
16 
17 #include <cinttypes>
18 #include <cstdio>
19 #include <cstring>
20 #include <map>
21 #include <pthread.h>
22 #include <unistd.h>
23 
24 #include "ability.h"
25 #include "ability_manager_client.h"
26 #include "access_token_error.h"
27 #include "accesstoken_kit.h"
28 #include "accesstoken_log.h"
29 #include "napi/native_api.h"
30 #include "napi/native_node_api.h"
31 #include "napi_base_context.h"
32 #include "napi_error.h"
33 #include "parameter.h"
34 #include "remote_object_wrapper.h"
35 #include "string_wrapper.h"
36 #include "token_setproc.h"
37 #include "want_params_wrapper.h"
38 #include "want.h"
39 
40 namespace OHOS {
41 namespace Security {
42 namespace AccessToken {
43 std::mutex g_lockForPermStateChangeRegisters;
44 std::vector<RegisterPermStateChangeInfo*> g_permStateChangeRegisters;
45 std::mutex g_lockCache;
46 std::map<std::string, PermissionStatusCache> g_cache;
47 static PermissionParamCache g_paramCache;
48 std::mutex g_lockForPermRequestCallbacks;
49 
50 namespace {
51 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
52     LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AccessTokenAbilityAccessCtrl"
53 };
54 static constexpr int32_t VERIFY_OR_FLAG_INPUT_MAX_PARAMS = 2;
55 static constexpr int32_t GRANT_OR_REVOKE_INPUT_MAX_PARAMS = 4;
56 static constexpr int32_t REQUEST_PERMISSION_MAX_PARAMS = 3;
57 static constexpr int32_t ON_OFF_MAX_PARAMS = 4;
58 static constexpr int32_t MAX_LENGTH = 256;
59 static constexpr int32_t MAX_WAIT_TIME = 1000;
60 static const char* PERMISSION_STATUS_CHANGE_KEY = "accesstoken.permission.change";
61 static constexpr int32_t VALUE_MAX_LEN = 32;
62 
63 const std::string PERMISSION_KEY = "ohos.user.grant.permission";
64 const std::string STATE_KEY = "ohos.user.grant.permission.state";
65 const std::string RESULT_KEY = "ohos.user.grant.permission.result";
66 const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType";
67 const std::string UI_EXTENSION_TYPE = "sys/commonUI";
68 const std::string ORI_PERMISSION_MANAGER_BUNDLE_NAME = "com.ohos.permissionmanager";
69 const std::string ORI_PERMISSION_MANAGER_ABILITY_NAME = "com.ohos.permissionmanager.GrantAbility";
70 const std::string TOKEN_KEY = "ohos.ability.params.token";
71 const std::string CALLBACK_KEY = "ohos.ability.params.callback";
72 
73 const std::string WINDOW_RECTANGLE_LEFT_KEY = "ohos.ability.params.request.left";
74 const std::string WINDOW_RECTANGLE_TOP_KEY = "ohos.ability.params.request.top";
75 const std::string WINDOW_RECTANGLE_HEIGHT_KEY = "ohos.ability.params.request.height";
76 const std::string WINDOW_RECTANGLE_WIDTH_KEY = "ohos.ability.params.request.width";
77 const std::string REQUEST_TOKEN_KEY = "ohos.ability.params.request.token";
78 
GetJsErrorCode(uint32_t errCode)79 static int32_t GetJsErrorCode(uint32_t errCode)
80 {
81     int32_t jsCode;
82     switch (errCode) {
83         case RET_SUCCESS:
84             jsCode = JS_OK;
85             break;
86         case ERR_PERMISSION_DENIED:
87             jsCode = JS_ERROR_PERMISSION_DENIED;
88             break;
89         case ERR_NOT_SYSTEM_APP:
90             jsCode = JS_ERROR_NOT_SYSTEM_APP;
91             break;
92         case ERR_PARAM_INVALID:
93             jsCode = JS_ERROR_PARAM_INVALID;
94             break;
95         case ERR_TOKENID_NOT_EXIST:
96             jsCode = JS_ERROR_TOKENID_NOT_EXIST;
97             break;
98         case ERR_PERMISSION_NOT_EXIST:
99             jsCode = JS_ERROR_PERMISSION_NOT_EXIST;
100             break;
101         case ERR_INTERFACE_NOT_USED_TOGETHER:
102         case ERR_CALLBACK_ALREADY_EXIST:
103             jsCode = JS_ERROR_NOT_USE_TOGETHER;
104             break;
105         case ERR_CALLBACKS_EXCEED_LIMITATION:
106             jsCode = JS_ERROR_REGISTERS_EXCEED_LIMITATION;
107             break;
108         case ERR_IDENTITY_CHECK_FAILED:
109             jsCode = JS_ERROR_PERMISSION_OPERATION_NOT_ALLOWED;
110             break;
111         case ERR_SERVICE_ABNORMAL:
112         case ERROR_IPC_REQUEST_FAIL:
113         case ERR_READ_PARCEL_FAILED:
114         case ERR_WRITE_PARCEL_FAILED:
115             jsCode = JS_ERROR_SERVICE_NOT_RUNNING;
116             break;
117         case ERR_MALLOC_FAILED:
118             jsCode = JS_ERROR_OUT_OF_MEMORY;
119             break;
120         default:
121             jsCode = JS_ERROR_INNER;
122             break;
123     }
124     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetJsErrorCode nativeCode(%{public}d) jsCode(%{public}d).", errCode, jsCode);
125     return jsCode;
126 }
127 
ReturnPromiseResult(napi_env env,int32_t contextResult,napi_deferred deferred,napi_value result)128 static void ReturnPromiseResult(napi_env env, int32_t contextResult, napi_deferred deferred, napi_value result)
129 {
130     if (contextResult != RET_SUCCESS) {
131         int32_t jsCode = GetJsErrorCode(contextResult);
132         napi_value businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
133         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, deferred, businessError));
134     } else {
135         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, deferred, result));
136     }
137 }
138 
ReturnCallbackResult(napi_env env,int32_t contextResult,napi_ref & callbackRef,napi_value result)139 static void ReturnCallbackResult(napi_env env, int32_t contextResult, napi_ref &callbackRef, napi_value result)
140 {
141     napi_value businessError = GetNapiNull(env);
142     if (contextResult != RET_SUCCESS) {
143         int32_t jsCode = GetJsErrorCode(contextResult);
144         businessError = GenerateBusinessError(env, jsCode, GetErrorMessage(jsCode));
145     }
146     napi_value results[ASYNC_CALL_BACK_VALUES_NUM] = { businessError, result };
147 
148     napi_value callback = nullptr;
149     napi_value thisValue = nullptr;
150     napi_value thatValue = nullptr;
151     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &thisValue));
152     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &thatValue));
153     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, callbackRef, &callback));
154     NAPI_CALL_RETURN_VOID(env,
155         napi_call_function(env, thisValue, callback, ASYNC_CALL_BACK_VALUES_NUM, results, &thatValue));
156 }
157 
ConvertPermStateChangeInfo(napi_env env,napi_value value,const PermStateChangeInfo & result)158 static bool ConvertPermStateChangeInfo(napi_env env, napi_value value, const PermStateChangeInfo& result)
159 {
160     napi_value element;
161     NAPI_CALL_BASE(env, napi_create_int32(env, result.permStateChangeType, &element), false);
162     NAPI_CALL_BASE(env, napi_set_named_property(env, value, "change", element), false);
163     element = nullptr;
164     NAPI_CALL_BASE(env, napi_create_int32(env, result.tokenID, &element), false);
165     NAPI_CALL_BASE(env, napi_set_named_property(env, value, "tokenID", element), false);
166     element = nullptr;
167     NAPI_CALL_BASE(env, napi_create_string_utf8(env, result.permissionName.c_str(),
168         NAPI_AUTO_LENGTH, &element), false);
169     NAPI_CALL_BASE(env, napi_set_named_property(env, value, "permissionName", element), false);
170     return true;
171 };
172 
NotifyPermStateChanged(RegisterPermStateChangeWorker * registerPermStateChangeData)173 static void NotifyPermStateChanged(RegisterPermStateChangeWorker* registerPermStateChangeData)
174 {
175     napi_value result = {nullptr};
176     NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env,
177         napi_create_object(registerPermStateChangeData->env, &result));
178     if (!ConvertPermStateChangeInfo(registerPermStateChangeData->env,
179         result, registerPermStateChangeData->result)) {
180         ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertPermStateChangeInfo failed");
181         return;
182     }
183 
184     napi_value undefined = nullptr;
185     napi_value callback = nullptr;
186     napi_value resultOut = nullptr;
187     NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env,
188         napi_get_undefined(registerPermStateChangeData->env, &undefined));
189     NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env,
190         napi_get_reference_value(registerPermStateChangeData->env, registerPermStateChangeData->ref, &callback));
191     NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env,
192         napi_call_function(registerPermStateChangeData->env, undefined, callback, 1, &result, &resultOut));
193 }
194 
UvQueueWorkPermStateChanged(uv_work_t * work,int status)195 static void UvQueueWorkPermStateChanged(uv_work_t* work, int status)
196 {
197     if (work == nullptr || work->data == nullptr) {
198         ACCESSTOKEN_LOG_ERROR(LABEL, "work == nullptr || work->data == nullptr");
199         return;
200     }
201     std::unique_ptr<uv_work_t> uvWorkPtr {work};
202     RegisterPermStateChangeWorker* registerPermStateChangeData =
203         reinterpret_cast<RegisterPermStateChangeWorker*>(work->data);
204     std::unique_ptr<RegisterPermStateChangeWorker> workPtr {registerPermStateChangeData};
205 
206     napi_handle_scope scope = nullptr;
207     napi_open_handle_scope(registerPermStateChangeData->env, &scope);
208     if (scope == nullptr) {
209         ACCESSTOKEN_LOG_ERROR(LABEL, "fail to open scope");
210         return;
211     }
212     NotifyPermStateChanged(registerPermStateChangeData);
213     napi_close_handle_scope(registerPermStateChangeData->env, scope);
214     ACCESSTOKEN_LOG_DEBUG(LABEL, "UvQueueWorkPermStateChanged end");
215 };
216 
IsPermissionFlagValid(uint32_t flag)217 static bool IsPermissionFlagValid(uint32_t flag)
218 {
219     ACCESSTOKEN_LOG_DEBUG(LABEL, "permission flag is %{public}d", flag);
220     return (flag == PermissionFlag::PERMISSION_USER_SET) || (flag == PermissionFlag::PERMISSION_USER_FIXED) ||
221         (flag == PermissionFlag::PERMISSION_ALLOW_THIS_TIME);
222 };
223 } // namespace
224 
RegisterPermStateChangeScopePtr(const PermStateChangeScope & subscribeInfo)225 RegisterPermStateChangeScopePtr::RegisterPermStateChangeScopePtr(const PermStateChangeScope& subscribeInfo)
226     : PermStateChangeCallbackCustomize(subscribeInfo)
227 {}
228 
~RegisterPermStateChangeScopePtr()229 RegisterPermStateChangeScopePtr::~RegisterPermStateChangeScopePtr()
230 {
231     if (ref_ == nullptr) {
232         return;
233     }
234     DeleteNapiRef();
235 }
236 
PermStateChangeCallback(PermStateChangeInfo & result)237 void RegisterPermStateChangeScopePtr::PermStateChangeCallback(PermStateChangeInfo& result)
238 {
239     std::lock_guard<std::mutex> lock(validMutex_);
240     if (!valid_) {
241         ACCESSTOKEN_LOG_ERROR(LABEL, "object is invalid.");
242         return;
243     }
244     uv_loop_s* loop = nullptr;
245     NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
246     if (loop == nullptr) {
247         ACCESSTOKEN_LOG_ERROR(LABEL, "loop instance is nullptr");
248         return;
249     }
250     uv_work_t* work = new (std::nothrow) uv_work_t;
251     if (work == nullptr) {
252         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!");
253         return;
254     }
255     std::unique_ptr<uv_work_t> uvWorkPtr {work};
256     RegisterPermStateChangeWorker* registerPermStateChangeWorker =
257         new (std::nothrow) RegisterPermStateChangeWorker();
258     if (registerPermStateChangeWorker == nullptr) {
259         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for RegisterPermStateChangeWorker!");
260         return;
261     }
262     std::unique_ptr<RegisterPermStateChangeWorker> workPtr {registerPermStateChangeWorker};
263     registerPermStateChangeWorker->env = env_;
264     registerPermStateChangeWorker->ref = ref_;
265     registerPermStateChangeWorker->result = result;
266     ACCESSTOKEN_LOG_DEBUG(LABEL,
267         "result permStateChangeType = %{public}d, tokenID = %{public}d, permissionName = %{public}s",
268         result.permStateChangeType, result.tokenID, result.permissionName.c_str());
269     registerPermStateChangeWorker->subscriber = shared_from_this();
270     work->data = reinterpret_cast<void *>(registerPermStateChangeWorker);
271     NAPI_CALL_RETURN_VOID(env_,
272         uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, UvQueueWorkPermStateChanged, uv_qos_default));
273     uvWorkPtr.release();
274     workPtr.release();
275 }
276 
SetEnv(const napi_env & env)277 void RegisterPermStateChangeScopePtr::SetEnv(const napi_env& env)
278 {
279     env_ = env;
280 }
281 
SetCallbackRef(const napi_ref & ref)282 void RegisterPermStateChangeScopePtr::SetCallbackRef(const napi_ref& ref)
283 {
284     ref_ = ref;
285 }
286 
SetValid(bool valid)287 void RegisterPermStateChangeScopePtr::SetValid(bool valid)
288 {
289     std::lock_guard<std::mutex> lock(validMutex_);
290     valid_ = valid;
291 }
292 
~PermStateChangeContext()293 PermStateChangeContext::~PermStateChangeContext()
294 {}
295 
UvQueueWorkDeleteRef(uv_work_t * work,int32_t status)296 void UvQueueWorkDeleteRef(uv_work_t *work, int32_t status)
297 {
298     if (work == nullptr) {
299         ACCESSTOKEN_LOG_ERROR(LABEL, "work == nullptr : %{public}d", work == nullptr);
300         return;
301     } else if (work->data == nullptr) {
302         ACCESSTOKEN_LOG_ERROR(LABEL, "work->data == nullptr : %{public}d", work->data == nullptr);
303         return;
304     }
305     RegisterPermStateChangeWorker* registerPermStateChangeWorker =
306         reinterpret_cast<RegisterPermStateChangeWorker*>(work->data);
307     if (registerPermStateChangeWorker == nullptr) {
308         delete work;
309         return;
310     }
311     napi_delete_reference(registerPermStateChangeWorker->env, registerPermStateChangeWorker->ref);
312     delete registerPermStateChangeWorker;
313     registerPermStateChangeWorker = nullptr;
314     delete work;
315     ACCESSTOKEN_LOG_DEBUG(LABEL, "UvQueueWorkDeleteRef end");
316 }
317 
DeleteNapiRef()318 void RegisterPermStateChangeScopePtr::DeleteNapiRef()
319 {
320     uv_loop_s* loop = nullptr;
321     NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
322     if (loop == nullptr) {
323         ACCESSTOKEN_LOG_ERROR(LABEL, "loop instance is nullptr");
324         return;
325     }
326     uv_work_t* work = new (std::nothrow) uv_work_t;
327     if (work == nullptr) {
328         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!");
329         return;
330     }
331 
332     std::unique_ptr<uv_work_t> uvWorkPtr {work};
333     RegisterPermStateChangeWorker* registerPermStateChangeWorker =
334         new (std::nothrow) RegisterPermStateChangeWorker();
335     if (registerPermStateChangeWorker == nullptr) {
336         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for RegisterPermStateChangeWorker!");
337         return;
338     }
339     std::unique_ptr<RegisterPermStateChangeWorker> workPtr {registerPermStateChangeWorker};
340     registerPermStateChangeWorker->env = env_;
341     registerPermStateChangeWorker->ref = ref_;
342 
343     work->data = reinterpret_cast<void *>(registerPermStateChangeWorker);
344     NAPI_CALL_RETURN_VOID(env_,
345         uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, UvQueueWorkDeleteRef, uv_qos_default));
346     ACCESSTOKEN_LOG_DEBUG(LABEL, "DeleteNapiRef");
347     uvWorkPtr.release();
348     workPtr.release();
349 }
350 
SetNamedProperty(napi_env env,napi_value dstObj,const int32_t objValue,const char * propName)351 void NapiAtManager::SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName)
352 {
353     napi_value prop = nullptr;
354     napi_create_int32(env, objValue, &prop);
355     napi_set_named_property(env, dstObj, propName, prop);
356 }
357 
Init(napi_env env,napi_value exports)358 napi_value NapiAtManager::Init(napi_env env, napi_value exports)
359 {
360     ACCESSTOKEN_LOG_DEBUG(LABEL, "enter init.");
361 
362     napi_property_descriptor descriptor[] = { DECLARE_NAPI_FUNCTION("createAtManager", CreateAtManager) };
363 
364     NAPI_CALL(env, napi_define_properties(env,
365         exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
366 
367     napi_property_descriptor properties[] = {
368         DECLARE_NAPI_FUNCTION("verifyAccessToken", VerifyAccessToken),
369         DECLARE_NAPI_FUNCTION("verifyAccessTokenSync", VerifyAccessTokenSync),
370         DECLARE_NAPI_FUNCTION("grantUserGrantedPermission", GrantUserGrantedPermission),
371         DECLARE_NAPI_FUNCTION("revokeUserGrantedPermission", RevokeUserGrantedPermission),
372         DECLARE_NAPI_FUNCTION("checkAccessToken", CheckAccessToken),
373         DECLARE_NAPI_FUNCTION("checkAccessTokenSync", VerifyAccessTokenSync),
374         DECLARE_NAPI_FUNCTION("getPermissionFlags", GetPermissionFlags),
375         DECLARE_NAPI_FUNCTION("on", RegisterPermStateChangeCallback),
376         DECLARE_NAPI_FUNCTION("off", UnregisterPermStateChangeCallback),
377         DECLARE_NAPI_FUNCTION("getVersion", GetVersion),
378         DECLARE_NAPI_FUNCTION("requestPermissionsFromUser", RequestPermissionsFromUser),
379     };
380 
381     napi_value cons = nullptr;
382     NAPI_CALL(env, napi_define_class(env, ATMANAGER_CLASS_NAME.c_str(), ATMANAGER_CLASS_NAME.size(),
383         JsConstructor, nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
384 
385     NAPI_CALL(env, napi_create_reference(env, cons, 1, &g_atManagerRef_));
386     NAPI_CALL(env, napi_set_named_property(env, exports, ATMANAGER_CLASS_NAME.c_str(), cons));
387 
388     napi_value grantStatus = nullptr;
389     napi_create_object(env, &grantStatus);
390 
391     SetNamedProperty(env, grantStatus, PERMISSION_DENIED, "PERMISSION_DENIED");
392     SetNamedProperty(env, grantStatus, PERMISSION_GRANTED, "PERMISSION_GRANTED");
393 
394     napi_value permStateChangeType = nullptr;
395     napi_create_object(env, &permStateChangeType);
396 
397     SetNamedProperty(env, permStateChangeType, PERMISSION_REVOKED_OPER, "PERMISSION_REVOKED_OPER");
398     SetNamedProperty(env, permStateChangeType, PERMISSION_GRANTED_OPER, "PERMISSION_GRANTED_OPER");
399 
400     napi_property_descriptor exportFuncs[] = {
401         DECLARE_NAPI_PROPERTY("GrantStatus", grantStatus),
402         DECLARE_NAPI_PROPERTY("PermissionStateChangeType", permStateChangeType),
403     };
404     napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs);
405 
406     return exports;
407 }
408 
JsConstructor(napi_env env,napi_callback_info cbinfo)409 napi_value NapiAtManager::JsConstructor(napi_env env, napi_callback_info cbinfo)
410 {
411     ACCESSTOKEN_LOG_DEBUG(LABEL, "enter JsConstructor");
412 
413     napi_value thisVar = nullptr;
414     NAPI_CALL(env, napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr));
415     return thisVar;
416 }
417 
CreateAtManager(napi_env env,napi_callback_info cbInfo)418 napi_value NapiAtManager::CreateAtManager(napi_env env, napi_callback_info cbInfo)
419 {
420     ACCESSTOKEN_LOG_DEBUG(LABEL, "enter CreateAtManager");
421 
422     napi_value instance = nullptr;
423     napi_value cons = nullptr;
424 
425     NAPI_CALL(env, napi_get_reference_value(env, g_atManagerRef_, &cons));
426     ACCESSTOKEN_LOG_DEBUG(LABEL, "Get a reference to the global variable g_atManagerRef_ complete");
427 
428     NAPI_CALL(env, napi_new_instance(env, cons, 0, nullptr, &instance));
429 
430     ACCESSTOKEN_LOG_DEBUG(LABEL, "New the js instance complete");
431 
432     return instance;
433 }
434 
ParseInputVerifyPermissionOrGetFlag(const napi_env env,const napi_callback_info info,AtManagerAsyncContext & asyncContext)435 bool NapiAtManager::ParseInputVerifyPermissionOrGetFlag(const napi_env env, const napi_callback_info info,
436     AtManagerAsyncContext& asyncContext)
437 {
438     size_t argc = VERIFY_OR_FLAG_INPUT_MAX_PARAMS;
439 
440     napi_value argv[VERIFY_OR_FLAG_INPUT_MAX_PARAMS] = { nullptr };
441     napi_value thisVar = nullptr;
442     std::string errMsg;
443     void *data = nullptr;
444     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data), false);
445     if (argc < VERIFY_OR_FLAG_INPUT_MAX_PARAMS) {
446         NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env,
447             JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
448         return false;
449     }
450     asyncContext.env = env;
451     // 0: the first parameter of argv
452     if (!ParseUint32(env, argv[0], asyncContext.tokenId)) {
453         errMsg = GetParamErrorMsg("tokenId", "number");
454         NAPI_CALL_BASE(env,
455             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
456         return false;
457     }
458 
459     // 1: the second parameter of argv
460     if (!ParseString(env, argv[1], asyncContext.permissionName)) {
461         errMsg = GetParamErrorMsg("permissionName", "string");
462         NAPI_CALL_BASE(env,
463             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
464         return false;
465     }
466 
467     ACCESSTOKEN_LOG_DEBUG(LABEL, "tokenID = %{public}d, permissionName = %{public}s", asyncContext.tokenId,
468         asyncContext.permissionName.c_str());
469     return true;
470 }
471 
VerifyAccessTokenExecute(napi_env env,void * data)472 void NapiAtManager::VerifyAccessTokenExecute(napi_env env, void *data)
473 {
474     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
475     if (asyncContext == nullptr) {
476         return;
477     }
478     asyncContext->result = AccessTokenKit::VerifyAccessToken(asyncContext->tokenId, asyncContext->permissionName);
479 }
480 
VerifyAccessTokenComplete(napi_env env,napi_status status,void * data)481 void NapiAtManager::VerifyAccessTokenComplete(napi_env env, napi_status status, void *data)
482 {
483     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
484     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
485     napi_value result;
486 
487     ACCESSTOKEN_LOG_DEBUG(LABEL, "tokenId = %{public}d, permissionName = %{public}s, verify result = %{public}d.",
488         asyncContext->tokenId, asyncContext->permissionName.c_str(), asyncContext->result);
489 
490     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, asyncContext->result, &result)); // verify result
491     NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncContext->deferred, result));
492 }
493 
VerifyAccessToken(napi_env env,napi_callback_info info)494 napi_value NapiAtManager::VerifyAccessToken(napi_env env, napi_callback_info info)
495 {
496     ACCESSTOKEN_LOG_DEBUG(LABEL, "VerifyAccessToken begin.");
497 
498     auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env);
499     if (asyncContext == nullptr) {
500         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct failed.");
501         return nullptr;
502     }
503 
504     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
505     if (!ParseInputVerifyPermissionOrGetFlag(env, info, *asyncContext)) {
506         return nullptr;
507     }
508 
509     napi_value result = nullptr;
510     NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
511 
512     napi_value resources = nullptr;
513     NAPI_CALL(env, napi_create_string_utf8(env, "VerifyAccessToken", NAPI_AUTO_LENGTH, &resources));
514 
515     NAPI_CALL(env, napi_create_async_work(
516         env, nullptr, resources,
517         VerifyAccessTokenExecute, VerifyAccessTokenComplete,
518         reinterpret_cast<void *>(asyncContext), &(asyncContext->work)));
519     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default));
520 
521     ACCESSTOKEN_LOG_DEBUG(LABEL, "VerifyAccessToken end.");
522     context.release();
523     return result;
524 }
525 
CheckAccessTokenExecute(napi_env env,void * data)526 void NapiAtManager::CheckAccessTokenExecute(napi_env env, void *data)
527 {
528     if (data == nullptr) {
529         return;
530     }
531     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
532     if (asyncContext == nullptr) {
533         return;
534     }
535     if (asyncContext->tokenId == 0) {
536         asyncContext->errorCode = JS_ERROR_PARAM_INVALID;
537         return;
538     }
539     if (asyncContext->permissionName.empty() || (asyncContext->permissionName.length() > MAX_LENGTH)) {
540         asyncContext->errorCode = JS_ERROR_PARAM_INVALID;
541         return;
542     }
543 
544     asyncContext->result = AccessTokenKit::VerifyAccessToken(asyncContext->tokenId,
545         asyncContext->permissionName);
546 }
547 
CheckAccessTokenComplete(napi_env env,napi_status status,void * data)548 void NapiAtManager::CheckAccessTokenComplete(napi_env env, napi_status status, void *data)
549 {
550     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
551     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
552 
553     napi_value result = nullptr;
554     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, asyncContext->result, &result));
555     ReturnPromiseResult(env, asyncContext->errorCode, asyncContext->deferred, result);
556 }
557 
CheckAccessToken(napi_env env,napi_callback_info info)558 napi_value NapiAtManager::CheckAccessToken(napi_env env, napi_callback_info info)
559 {
560     ACCESSTOKEN_LOG_DEBUG(LABEL, "CheckAccessToken begin.");
561 
562     auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env);
563     if (asyncContext == nullptr) {
564         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
565         return nullptr;
566     }
567 
568     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
569     if (!ParseInputVerifyPermissionOrGetFlag(env, info, *asyncContext)) {
570         return nullptr;
571     }
572 
573     napi_value result = nullptr;
574     NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
575 
576     napi_value resource = nullptr;
577     NAPI_CALL(env, napi_create_string_utf8(env, "CheckAccessToken", NAPI_AUTO_LENGTH, &resource));
578 
579     NAPI_CALL(env, napi_create_async_work(
580         env, nullptr, resource,
581         CheckAccessTokenExecute, CheckAccessTokenComplete,
582         reinterpret_cast<void *>(asyncContext), &(asyncContext->work)));
583     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default));
584 
585     ACCESSTOKEN_LOG_DEBUG(LABEL, "CheckAccessToken end.");
586     context.release();
587     return result;
588 }
589 
GetPermParamValue()590 std::string NapiAtManager::GetPermParamValue()
591 {
592     long long sysCommitId = GetSystemCommitId();
593     if (sysCommitId == g_paramCache.sysCommitIdCache) {
594         ACCESSTOKEN_LOG_DEBUG(LABEL, "sysCommitId = %{public}lld", sysCommitId);
595         return g_paramCache.sysParamCache;
596     }
597     g_paramCache.sysCommitIdCache = sysCommitId;
598     if (g_paramCache.handle == PARAM_DEFAULT_VALUE) {
599         int32_t handle = static_cast<int32_t>(FindParameter(PERMISSION_STATUS_CHANGE_KEY));
600         if (handle == PARAM_DEFAULT_VALUE) {
601             ACCESSTOKEN_LOG_ERROR(LABEL, "FindParameter failed");
602             return "-1";
603         }
604         g_paramCache.handle = handle;
605     }
606 
607     int32_t currCommitId = static_cast<int32_t>(GetParameterCommitId(g_paramCache.handle));
608     if (currCommitId != g_paramCache.commitIdCache) {
609         char value[VALUE_MAX_LEN] = {0};
610         auto ret = GetParameterValue(g_paramCache.handle, value, VALUE_MAX_LEN - 1);
611         if (ret < 0) {
612             ACCESSTOKEN_LOG_ERROR(LABEL, "return default value, ret=%{public}d", ret);
613             return "-1";
614         }
615         std::string resStr(value);
616         g_paramCache.sysParamCache = resStr;
617         g_paramCache.commitIdCache = currCommitId;
618     }
619     return g_paramCache.sysParamCache;
620 }
621 
UpdatePermissionCache(AtManagerAsyncContext * asyncContext)622 void NapiAtManager::UpdatePermissionCache(AtManagerAsyncContext* asyncContext)
623 {
624     std::lock_guard<std::mutex> lock(g_lockCache);
625     auto iter = g_cache.find(asyncContext->permissionName);
626     if (iter != g_cache.end()) {
627         std::string currPara = GetPermParamValue();
628         if (currPara != iter->second.paramValue) {
629             asyncContext->result = AccessTokenKit::VerifyAccessToken(
630                 asyncContext->tokenId, asyncContext->permissionName);
631             iter->second.status = asyncContext->result;
632             iter->second.paramValue = currPara;
633             ACCESSTOKEN_LOG_DEBUG(LABEL, "Param changed currPara %{public}s", currPara.c_str());
634         } else {
635             asyncContext->result = iter->second.status;
636         }
637     } else {
638         asyncContext->result = AccessTokenKit::VerifyAccessToken(asyncContext->tokenId, asyncContext->permissionName);
639         g_cache[asyncContext->permissionName].status = asyncContext->result;
640         g_cache[asyncContext->permissionName].paramValue = GetPermParamValue();
641         ACCESSTOKEN_LOG_DEBUG(LABEL, "g_cacheParam set %{public}s",
642             g_cache[asyncContext->permissionName].paramValue.c_str());
643     }
644 }
645 
VerifyAccessTokenSync(napi_env env,napi_callback_info info)646 napi_value NapiAtManager::VerifyAccessTokenSync(napi_env env, napi_callback_info info)
647 {
648     auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env);
649     if (asyncContext == nullptr) {
650         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
651         return nullptr;
652     }
653 
654     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
655     if (!ParseInputVerifyPermissionOrGetFlag(env, info, *asyncContext)) {
656         return nullptr;
657     }
658     if (asyncContext->tokenId == 0) {
659         std::string errMsg = GetParamErrorMsg("tokenID", "number");
660         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_INVALID, errMsg)));
661         return nullptr;
662     }
663     if (asyncContext->permissionName.empty() || (asyncContext->permissionName.length() > MAX_LENGTH)) {
664         std::string errMsg = GetParamErrorMsg("permissionName", "string");
665         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JS_ERROR_PARAM_INVALID, errMsg)));
666         return nullptr;
667     }
668     if (asyncContext->tokenId != static_cast<AccessTokenID>(GetSelfTokenID())) {
669         asyncContext->result = AccessTokenKit::VerifyAccessToken(asyncContext->tokenId, asyncContext->permissionName);
670         napi_value result = nullptr;
671         NAPI_CALL(env, napi_create_int32(env, asyncContext->result, &result));
672         ACCESSTOKEN_LOG_DEBUG(LABEL, "VerifyAccessTokenSync end.");
673         return result;
674     }
675 
676     UpdatePermissionCache(asyncContext);
677     napi_value result = nullptr;
678     NAPI_CALL(env, napi_create_int32(env, asyncContext->result, &result));
679     return result;
680 }
681 
ParseInputGrantOrRevokePermission(const napi_env env,const napi_callback_info info,AtManagerAsyncContext & asyncContext)682 bool NapiAtManager::ParseInputGrantOrRevokePermission(const napi_env env, const napi_callback_info info,
683     AtManagerAsyncContext& asyncContext)
684 {
685     size_t argc = GRANT_OR_REVOKE_INPUT_MAX_PARAMS;
686     napi_value argv[GRANT_OR_REVOKE_INPUT_MAX_PARAMS] = {nullptr};
687     napi_value thatVar = nullptr;
688 
689     void *data = nullptr;
690     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thatVar, &data), false);
691     // 1: grant and revoke required minnum argc
692     if (argc < GRANT_OR_REVOKE_INPUT_MAX_PARAMS - 1) {
693         NAPI_CALL_BASE(env, napi_throw(env,
694             GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
695         return false;
696     }
697     asyncContext.env = env;
698     std::string errMsg;
699     // 0: the first parameter of argv
700     if (!ParseUint32(env, argv[0], asyncContext.tokenId)) {
701         errMsg = GetParamErrorMsg("tokenId", "number");
702         NAPI_CALL_BASE(
703             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
704         return false;
705     }
706 
707     // 1: the second parameter of argv
708     if (!ParseString(env, argv[1], asyncContext.permissionName)) {
709         errMsg = GetParamErrorMsg("permissionName", "string");
710         NAPI_CALL_BASE(env,
711             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
712         return false;
713     }
714 
715     // 2: the third parameter of argv
716     if (!ParseUint32(env, argv[2], asyncContext.flag)) {
717         errMsg = GetParamErrorMsg("flag", "number");
718         NAPI_CALL_BASE(env,
719             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
720         return false;
721     }
722 
723     if (argc == GRANT_OR_REVOKE_INPUT_MAX_PARAMS) {
724         // 3: the fourth parameter of argv
725         if (!IsUndefinedOrNull(env, argv[3]) && !ParseCallback(env, argv[3], asyncContext.callbackRef)) {
726             NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL,
727                                 GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_ILLEGAL))), false);
728             return false;
729         }
730     }
731 
732     ACCESSTOKEN_LOG_DEBUG(LABEL, "tokenID = %{public}d, permissionName = %{public}s, flag = %{public}d",
733         asyncContext.tokenId, asyncContext.permissionName.c_str(), asyncContext.flag);
734     return true;
735 }
736 
GrantUserGrantedPermissionExecute(napi_env env,void * data)737 void NapiAtManager::GrantUserGrantedPermissionExecute(napi_env env, void *data)
738 {
739     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
740     if (asyncContext == nullptr) {
741         return;
742     }
743     PermissionDef permissionDef;
744 
745     permissionDef.grantMode = 0;
746     permissionDef.availableLevel = APL_NORMAL;
747     permissionDef.provisionEnable = false;
748     permissionDef.distributedSceneEnable = false;
749     permissionDef.labelId = 0;
750     permissionDef.descriptionId = 0;
751 
752     int32_t result = AccessTokenKit::GetDefPermission(asyncContext->permissionName, permissionDef);
753     if (result != AT_PERM_OPERA_SUCC) {
754         asyncContext->result = result;
755         return;
756     }
757 
758     ACCESSTOKEN_LOG_DEBUG(LABEL, "permissionName = %{public}s, grantmode = %{public}d.",
759         asyncContext->permissionName.c_str(), permissionDef.grantMode);
760 
761     if (!IsPermissionFlagValid(asyncContext->flag)) {
762         asyncContext->result = JsErrorCode::JS_ERROR_PARAM_INVALID;
763     }
764     // only user_grant permission can use innerkit class method to grant permission, system_grant return failed
765     if (permissionDef.grantMode == USER_GRANT) {
766         asyncContext->result = AccessTokenKit::GrantPermission(asyncContext->tokenId, asyncContext->permissionName,
767             asyncContext->flag);
768     } else {
769         asyncContext->result = JsErrorCode::JS_ERROR_PERMISSION_NOT_EXIST;
770     }
771     ACCESSTOKEN_LOG_DEBUG(LABEL,
772         "tokenId = %{public}d, permissionName = %{public}s, flag = %{public}d, grant result = %{public}d.",
773         asyncContext->tokenId, asyncContext->permissionName.c_str(), asyncContext->flag, asyncContext->result);
774 }
775 
GrantUserGrantedPermissionComplete(napi_env env,napi_status status,void * data)776 void NapiAtManager::GrantUserGrantedPermissionComplete(napi_env env, napi_status status, void *data)
777 {
778     AtManagerAsyncContext* context = reinterpret_cast<AtManagerAsyncContext*>(data);
779     std::unique_ptr<AtManagerAsyncContext> callbackPtr {context};
780     napi_value result = GetNapiNull(env);
781 
782     if (context->deferred != nullptr) {
783         ReturnPromiseResult(env, context->result, context->deferred, result);
784     } else {
785         ReturnCallbackResult(env, context->result, context->callbackRef, result);
786     }
787 }
788 
GetVersion(napi_env env,napi_callback_info info)789 napi_value NapiAtManager::GetVersion(napi_env env, napi_callback_info info)
790 {
791     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetVersion begin.");
792 
793     auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env);
794     if (asyncContext == nullptr) {
795         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
796         return nullptr;
797     }
798     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
799 
800     napi_value result = nullptr;
801     NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
802 
803     napi_value resource = nullptr;
804     NAPI_CALL(env, napi_create_string_utf8(env, "GetVersion", NAPI_AUTO_LENGTH, &resource));
805 
806     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, GetVersionExecute, GetVersionComplete,
807         reinterpret_cast<void *>(asyncContext), &(asyncContext->work)));
808     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default));
809 
810     context.release();
811     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetVersion end.");
812     return result;
813 }
814 
GetVersionExecute(napi_env env,void * data)815 void NapiAtManager::GetVersionExecute(napi_env env, void *data)
816 {
817     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
818     if (asyncContext == nullptr) {
819         return;
820     }
821     asyncContext->result = AccessTokenKit::GetVersion();
822     ACCESSTOKEN_LOG_DEBUG(LABEL, "version result = %{public}d.", asyncContext->result);
823 }
824 
GetVersionComplete(napi_env env,napi_status status,void * data)825 void NapiAtManager::GetVersionComplete(napi_env env, napi_status status, void *data)
826 {
827     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
828     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
829     napi_value result;
830 
831     ACCESSTOKEN_LOG_DEBUG(LABEL, "version result = %{public}d.", asyncContext->result);
832 
833     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, asyncContext->result, &result));
834     NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncContext->deferred, result));
835 }
836 
GrantUserGrantedPermission(napi_env env,napi_callback_info info)837 napi_value NapiAtManager::GrantUserGrantedPermission(napi_env env, napi_callback_info info)
838 {
839     ACCESSTOKEN_LOG_DEBUG(LABEL, "GrantUserGrantedPermission begin.");
840 
841     auto* context = new (std::nothrow) AtManagerAsyncContext(env); // for async work deliver data
842     if (context == nullptr) {
843         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
844         return nullptr;
845     }
846 
847     std::unique_ptr<AtManagerAsyncContext> contextPtr {context};
848     if (!ParseInputGrantOrRevokePermission(env, info, *context)) {
849         return nullptr;
850     }
851 
852     napi_value result = nullptr;
853 
854     if (context->callbackRef == nullptr) {
855         NAPI_CALL(env, napi_create_promise(env, &(context->deferred), &result));
856     } else {
857         NAPI_CALL(env, napi_get_undefined(env, &result));
858     }
859 
860     napi_value resource = nullptr;
861     NAPI_CALL(env, napi_create_string_utf8(env, "GrantUserGrantedPermission", NAPI_AUTO_LENGTH, &resource));
862 
863     NAPI_CALL(env, napi_create_async_work(
864         env, nullptr, resource,
865         GrantUserGrantedPermissionExecute, GrantUserGrantedPermissionComplete,
866         reinterpret_cast<void *>(context), &(context->work)));
867 
868     NAPI_CALL(env, napi_queue_async_work_with_qos(env, context->work, napi_qos_default));
869 
870     ACCESSTOKEN_LOG_DEBUG(LABEL, "GrantUserGrantedPermission end.");
871     contextPtr.release();
872     return result;
873 }
874 
RevokeUserGrantedPermissionExecute(napi_env env,void * data)875 void NapiAtManager::RevokeUserGrantedPermissionExecute(napi_env env, void *data)
876 {
877     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext *>(data);
878     if (asyncContext == nullptr) {
879         return;
880     }
881     PermissionDef permissionDef;
882 
883     permissionDef.grantMode = 0;
884     permissionDef.availableLevel = APL_NORMAL;
885     permissionDef.provisionEnable = false;
886     permissionDef.distributedSceneEnable = false;
887     permissionDef.labelId = 0;
888     permissionDef.descriptionId = 0;
889 
890     int32_t result = AccessTokenKit::GetDefPermission(asyncContext->permissionName, permissionDef);
891     if (result != AT_PERM_OPERA_SUCC) {
892         asyncContext->result = result;
893         return;
894     }
895 
896     ACCESSTOKEN_LOG_DEBUG(LABEL, "permissionName = %{public}s, grantmode = %{public}d.",
897         asyncContext->permissionName.c_str(), permissionDef.grantMode);
898 
899     if (!IsPermissionFlagValid(asyncContext->flag)) {
900         asyncContext->result = JsErrorCode::JS_ERROR_PARAM_INVALID;
901     }
902     // only user_grant permission can use innerkit class method to grant permission, system_grant return failed
903     if (permissionDef.grantMode == USER_GRANT) {
904         asyncContext->result = AccessTokenKit::RevokePermission(asyncContext->tokenId, asyncContext->permissionName,
905             asyncContext->flag);
906     } else {
907         asyncContext->result = JsErrorCode::JS_ERROR_PERMISSION_NOT_EXIST;
908     }
909     ACCESSTOKEN_LOG_DEBUG(LABEL,
910         "tokenId = %{public}d, permissionName = %{public}s, flag = %{public}d, revoke result = %{public}d.",
911         asyncContext->tokenId, asyncContext->permissionName.c_str(), asyncContext->flag, asyncContext->result);
912 }
913 
RevokeUserGrantedPermissionComplete(napi_env env,napi_status status,void * data)914 void NapiAtManager::RevokeUserGrantedPermissionComplete(napi_env env, napi_status status, void *data)
915 {
916     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext*>(data);
917     std::unique_ptr<AtManagerAsyncContext> callbackPtr {asyncContext};
918 
919     napi_value result = GetNapiNull(env);
920     if (asyncContext->deferred != nullptr) {
921         ReturnPromiseResult(env, asyncContext->result, asyncContext->deferred, result);
922     } else {
923         ReturnCallbackResult(env, asyncContext->result, asyncContext->callbackRef, result);
924     }
925 }
926 
RevokeUserGrantedPermission(napi_env env,napi_callback_info info)927 napi_value NapiAtManager::RevokeUserGrantedPermission(napi_env env, napi_callback_info info)
928 {
929     ACCESSTOKEN_LOG_DEBUG(LABEL, "RevokeUserGrantedPermission begin.");
930 
931     auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env); // for async work deliver data
932     if (asyncContext == nullptr) {
933         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
934         return nullptr;
935     }
936 
937     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
938     if (!ParseInputGrantOrRevokePermission(env, info, *asyncContext)) {
939         return nullptr;
940     }
941 
942     napi_value result = nullptr;
943     if (asyncContext->callbackRef == nullptr) {
944         NAPI_CALL(env, napi_create_promise(env, &(asyncContext->deferred), &result));
945     } else {
946         NAPI_CALL(env, napi_get_undefined(env, &result));
947     }
948 
949     napi_value resource = nullptr;
950     NAPI_CALL(env, napi_create_string_utf8(env, "RevokeUserGrantedPermission", NAPI_AUTO_LENGTH, &resource));
951 
952     NAPI_CALL(env, napi_create_async_work(
953         env, nullptr, resource,
954         RevokeUserGrantedPermissionExecute, RevokeUserGrantedPermissionComplete,
955         reinterpret_cast<void *>(asyncContext), &(asyncContext->work)));
956 
957     NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default));
958     ACCESSTOKEN_LOG_DEBUG(LABEL, "RevokeUserGrantedPermission end.");
959     context.release();
960     return result;
961 }
962 
GetPermissionFlagsExecute(napi_env env,void * data)963 void NapiAtManager::GetPermissionFlagsExecute(napi_env env, void *data)
964 {
965     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext*>(data);
966 
967     asyncContext->result = AccessTokenKit::GetPermissionFlag(asyncContext->tokenId,
968         asyncContext->permissionName, asyncContext->flag);
969 }
970 
GetPermissionFlagsComplete(napi_env env,napi_status status,void * data)971 void NapiAtManager::GetPermissionFlagsComplete(napi_env env, napi_status status, void *data)
972 {
973     AtManagerAsyncContext* asyncContext = reinterpret_cast<AtManagerAsyncContext*>(data);
974     std::unique_ptr<AtManagerAsyncContext> callbackPtr {asyncContext};
975 
976     napi_value result = nullptr;
977     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, asyncContext->flag, &result));
978 
979     ReturnPromiseResult(env, asyncContext->result, asyncContext->deferred, result);
980 }
981 
GetPermissionFlags(napi_env env,napi_callback_info info)982 napi_value NapiAtManager::GetPermissionFlags(napi_env env, napi_callback_info info)
983 {
984     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionFlags begin.");
985 
986     auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(env);
987     if (asyncContext == nullptr) {
988         ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail.");
989         return nullptr;
990     }
991 
992     std::unique_ptr<AtManagerAsyncContext> context {asyncContext};
993     if (!ParseInputVerifyPermissionOrGetFlag(env, info, *asyncContext)) {
994         return nullptr;
995     }
996 
997     napi_value result = nullptr;
998     napi_create_promise(env, &(asyncContext->deferred), &result); // create delay promise object
999 
1000     napi_value resource = nullptr; // resource name
1001     napi_create_string_utf8(env, "GetPermissionFlags", NAPI_AUTO_LENGTH, &resource);
1002 
1003     napi_create_async_work( // define work
1004         env, nullptr, resource, GetPermissionFlagsExecute, GetPermissionFlagsComplete,
1005         reinterpret_cast<void *>(asyncContext), &(asyncContext->work));
1006     // add async work handle to the napi queue and wait for result
1007     napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_default);
1008 
1009     ACCESSTOKEN_LOG_DEBUG(LABEL, "GetPermissionFlags end.");
1010     context.release();
1011     return result;
1012 }
1013 
WrapVoidToJS(napi_env env)1014 static napi_value WrapVoidToJS(napi_env env)
1015 {
1016     napi_value result = nullptr;
1017     NAPI_CALL(env, napi_get_null(env, &result));
1018     return result;
1019 }
1020 
GetContext(const napi_env & env,const napi_value & value,std::shared_ptr<RequestAsyncContext> & asyncContext)1021 static napi_value GetContext(
1022     const napi_env &env, const napi_value &value, std::shared_ptr<RequestAsyncContext>& asyncContext)
1023 {
1024     bool stageMode = false;
1025     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
1026     if (status != napi_ok || !stageMode) {
1027         ACCESSTOKEN_LOG_ERROR(LABEL, "it is not a stage mode");
1028         return nullptr;
1029     } else {
1030         auto context = AbilityRuntime::GetStageModeContext(env, value);
1031         if (context == nullptr) {
1032             ACCESSTOKEN_LOG_ERROR(LABEL, "get context failed");
1033             return nullptr;
1034         }
1035         asyncContext->abilityContext =
1036             AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
1037         if (asyncContext->abilityContext != nullptr) {
1038             asyncContext->uiAbilityFlag = true;
1039         } else {
1040             ACCESSTOKEN_LOG_WARN(LABEL, "convert to ability context failed");
1041             asyncContext->uiExtensionContext =
1042                 AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
1043             if (asyncContext->uiExtensionContext == nullptr) {
1044                 ACCESSTOKEN_LOG_ERROR(LABEL, "convert to ui extension context failed");
1045                 return nullptr;
1046             }
1047         }
1048         return WrapVoidToJS(env);
1049     }
1050 }
1051 
ParseRequestPermissionFromUser(const napi_env & env,const napi_callback_info & cbInfo,std::shared_ptr<RequestAsyncContext> & asyncContext)1052 bool NapiAtManager::ParseRequestPermissionFromUser(const napi_env& env,
1053     const napi_callback_info& cbInfo, std::shared_ptr<RequestAsyncContext>& asyncContext)
1054 {
1055     size_t argc = REQUEST_PERMISSION_MAX_PARAMS;
1056     napi_value argv[REQUEST_PERMISSION_MAX_PARAMS] = { nullptr };
1057     napi_value thisVar = nullptr;
1058 
1059     if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
1060         ACCESSTOKEN_LOG_ERROR(LABEL, "napi_get_cb_info failed");
1061         return false;
1062     }
1063     if (argc < REQUEST_PERMISSION_MAX_PARAMS - 1) {
1064         NAPI_CALL_BASE(env, napi_throw(env, GenerateBusinessError(env,
1065             JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing.")), false);
1066         return false;
1067     }
1068     asyncContext->env = env;
1069     std::string errMsg;
1070 
1071     // argv[0] : context : AbilityContext
1072     if (GetContext(env, argv[0], asyncContext) == nullptr) {
1073         errMsg = GetParamErrorMsg("context", "UIAbility or UIExtension Context");
1074         NAPI_CALL_BASE(
1075             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
1076         return false;
1077     }
1078     ACCESSTOKEN_LOG_INFO(LABEL, "asyncContext.uiAbilityFlag is: %{public}d.", asyncContext->uiAbilityFlag);
1079 
1080     // argv[1] : permissionList
1081     if (!ParseStringArray(env, argv[1], asyncContext->permissionList) ||
1082         (asyncContext->permissionList.empty())) {
1083         errMsg = GetParamErrorMsg("permissions", "Array<string>");
1084         NAPI_CALL_BASE(
1085             env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg)), false);
1086         return false;
1087     }
1088     ACCESSTOKEN_LOG_INFO(LABEL, "asyncContext.permissionList size: %{public}zu.", asyncContext->permissionList.size());
1089 
1090     if (argc == REQUEST_PERMISSION_MAX_PARAMS) {
1091         // argv[2] : callback
1092         if (!IsUndefinedOrNull(env, argv[2]) && !ParseCallback(env, argv[2], asyncContext->callbackRef)) {
1093             errMsg = GetParamErrorMsg("callback", "Callback<PermissionRequestResult>");
1094             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1095             return false;
1096         }
1097     }
1098 
1099     return true;
1100 }
1101 
WrapRequestResult(const napi_env & env,const std::vector<std::string> & permissions,const std::vector<int> & grantResults)1102 static napi_value WrapRequestResult(const napi_env& env,
1103     const std::vector<std::string>& permissions, const std::vector<int>& grantResults)
1104 {
1105     napi_value result = nullptr;
1106     NAPI_CALL(env, napi_create_object(env, &result));
1107 
1108     napi_value objPermissions;
1109     NAPI_CALL(env, napi_create_array(env, &objPermissions));
1110     for (size_t i = 0; i < permissions.size(); i++) {
1111         napi_value nPerm = nullptr;
1112         NAPI_CALL(env, napi_create_string_utf8(env, permissions[i].c_str(), NAPI_AUTO_LENGTH, &nPerm));
1113         NAPI_CALL(env, napi_set_element(env, objPermissions, i, nPerm));
1114     }
1115     NAPI_CALL(env, napi_set_named_property(env, result, "permissions", objPermissions));
1116 
1117     napi_value objGrantResults;
1118     NAPI_CALL(env, napi_create_array(env, &objGrantResults));
1119     for (size_t i = 0; i < grantResults.size(); i++) {
1120         napi_value nGrantResult = nullptr;
1121         NAPI_CALL(env, napi_create_int32(env, grantResults[i], &nGrantResult));
1122         NAPI_CALL(env, napi_set_element(env, objGrantResults, i, nGrantResult));
1123     }
1124     NAPI_CALL(env, napi_set_named_property(env, result, "authResults", objGrantResults));
1125 
1126     return result;
1127 }
1128 
ResultCallbackJSThreadWorker(uv_work_t * work,int32_t status)1129 static void ResultCallbackJSThreadWorker(uv_work_t* work, int32_t status)
1130 {
1131     (void)status;
1132     if (work == nullptr) {
1133         ACCESSTOKEN_LOG_ERROR(LABEL, "uv_queue_work_with_qos input work is nullptr");
1134         return;
1135     }
1136     std::unique_ptr<uv_work_t> uvWorkPtr {work};
1137     ResultCallback *retCB = reinterpret_cast<ResultCallback*>(work->data);
1138     if (retCB == nullptr) {
1139         ACCESSTOKEN_LOG_ERROR(LABEL, "retCB is nullptr");
1140         return;
1141     }
1142     std::unique_ptr<ResultCallback> callbackPtr {retCB};
1143 
1144     std::shared_ptr<RequestAsyncContext> asyncContext = retCB->data;
1145     if (asyncContext == nullptr) {
1146         return;
1147     }
1148 
1149     int32_t result = JsErrorCode::JS_OK;
1150     if (retCB->grantResults.empty()) {
1151         ACCESSTOKEN_LOG_ERROR(LABEL, "grantResults empty");
1152         result = JsErrorCode::JS_ERROR_INNER;
1153     }
1154     napi_handle_scope scope = nullptr;
1155     napi_open_handle_scope(asyncContext->env, &scope);
1156     if (scope == nullptr) {
1157         ACCESSTOKEN_LOG_ERROR(LABEL, "napi_open_handle_scope failed");
1158         return;
1159     }
1160     napi_value requestResult = WrapRequestResult(
1161         asyncContext->env, retCB->permissions, retCB->grantResults);
1162     if (requestResult == nullptr) {
1163         ACCESSTOKEN_LOG_DEBUG(LABEL, "wrap requestResult failed");
1164         result = JsErrorCode::JS_ERROR_INNER;
1165     }
1166 
1167     if (asyncContext->deferred != nullptr) {
1168         ReturnPromiseResult(asyncContext->env, result,
1169             asyncContext->deferred, requestResult);
1170     } else {
1171         ReturnCallbackResult(asyncContext->env, result,
1172             asyncContext->callbackRef, requestResult);
1173     }
1174     napi_close_handle_scope(asyncContext->env, scope);
1175     ACCESSTOKEN_LOG_DEBUG(LABEL, "OnRequestPermissionsFromUser async callback is called end");
1176 }
1177 
UpdateGrantPermissionResultOnly(const std::vector<std::string> & permissions,const std::vector<int> & grantResults,const std::vector<int> & permissionsState,std::vector<int> & newGrantResults)1178 static void UpdateGrantPermissionResultOnly(const std::vector<std::string>& permissions,
1179     const std::vector<int>& grantResults, const std::vector<int>& permissionsState, std::vector<int>& newGrantResults)
1180 {
1181     uint32_t size = permissions.size();
1182 
1183     for (uint32_t i = 0; i < size; i++) {
1184         int result = permissionsState[i] == DYNAMIC_OPER ? grantResults[i] : permissionsState[i];
1185         newGrantResults.emplace_back(result);
1186     }
1187 }
1188 
GrantResultsCallback(const std::vector<std::string> & permissions,const std::vector<int> & grantResults)1189 void AuthorizationResult::GrantResultsCallback(const std::vector<std::string>& permissions,
1190     const std::vector<int>& grantResults)
1191 {
1192     ACCESSTOKEN_LOG_INFO(LABEL, "called.");
1193 
1194     auto* retCB = new (std::nothrow) ResultCallback();
1195     if (retCB == nullptr) {
1196         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!");
1197         return;
1198     }
1199 
1200     std::shared_ptr<RequestAsyncContext> asyncContext = data_;
1201     if (asyncContext == nullptr) {
1202         return;
1203     }
1204 
1205     // only permissions which need to grant change the result, other keey as GetSelfPermissionsState result
1206     std::vector<int> newGrantResults;
1207     UpdateGrantPermissionResultOnly(permissions, grantResults, asyncContext->permissionsState, newGrantResults);
1208 
1209     std::unique_ptr<ResultCallback> callbackPtr {retCB};
1210 
1211     retCB->permissions = permissions;
1212     retCB->grantResults = newGrantResults;
1213     retCB->requestCode = requestCode_;
1214     retCB->data = data_;
1215 
1216     uv_loop_s* loop = nullptr;
1217     NAPI_CALL_RETURN_VOID(asyncContext->env,
1218         napi_get_uv_event_loop(asyncContext->env, &loop));
1219     if (loop == nullptr) {
1220         ACCESSTOKEN_LOG_ERROR(LABEL, "loop instance is nullptr");
1221         return;
1222     }
1223     uv_work_t* work = new (std::nothrow) uv_work_t;
1224     if (work == nullptr) {
1225         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!");
1226         return;
1227     }
1228     std::unique_ptr<uv_work_t> uvWorkPtr {work};
1229     work->data = reinterpret_cast<void *>(retCB);
1230     NAPI_CALL_RETURN_VOID(asyncContext->env,
1231         uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, ResultCallbackJSThreadWorker, uv_qos_default));
1232 
1233     uvWorkPtr.release();
1234     callbackPtr.release();
1235 }
1236 
StartServiceExtension(std::shared_ptr<RequestAsyncContext> & asyncContext)1237 static void StartServiceExtension(std::shared_ptr<RequestAsyncContext>& asyncContext)
1238 {
1239     sptr<IRemoteObject> remoteObject = new (std::nothrow) AccessToken::AuthorizationResult(
1240         curRequestCode_, asyncContext);
1241     if (remoteObject == nullptr) {
1242         ACCESSTOKEN_LOG_DEBUG(LABEL, "it does not need to request permission exsion");
1243         asyncContext->needDynamicRequest = false;
1244         asyncContext->result = JsErrorCode::JS_ERROR_INNER;
1245         return;
1246     }
1247 
1248     AAFwk::Want want;
1249     want.SetElementName(ORI_PERMISSION_MANAGER_BUNDLE_NAME, ORI_PERMISSION_MANAGER_ABILITY_NAME);
1250     want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
1251     want.SetParam(STATE_KEY, asyncContext->permissionsState);
1252     want.SetParam(TOKEN_KEY, asyncContext->abilityContext->GetToken());
1253     want.SetParam(CALLBACK_KEY, remoteObject);
1254 
1255     int32_t left, top, width, height;
1256     asyncContext->abilityContext->GetWindowRect(left, top, width, height);
1257     want.SetParam(WINDOW_RECTANGLE_LEFT_KEY, left);
1258     want.SetParam(WINDOW_RECTANGLE_TOP_KEY, top);
1259     want.SetParam(WINDOW_RECTANGLE_WIDTH_KEY, width);
1260     want.SetParam(WINDOW_RECTANGLE_HEIGHT_KEY, height);
1261     want.SetParam(REQUEST_TOKEN_KEY, asyncContext->abilityContext->GetToken());
1262     int32_t err = AAFwk::AbilityManagerClient::GetInstance()->RequestDialogService(
1263         want, asyncContext->abilityContext->GetToken());
1264 
1265     std::lock_guard<std::mutex> lock(g_lockForPermRequestCallbacks);
1266     curRequestCode_ = (curRequestCode_ == INT_MAX) ? 0 : (curRequestCode_ + 1);
1267     ACCESSTOKEN_LOG_INFO(LABEL, "RequestDialogService end. ret=%{public}d", err);
1268 }
1269 
IsDynamicRequest(const std::vector<std::string> & permissions,std::vector<int32_t> & permissionsState,PermissionGrantInfo & info)1270 bool NapiAtManager::IsDynamicRequest(const std::vector<std::string>& permissions,
1271     std::vector<int32_t>& permissionsState, PermissionGrantInfo& info)
1272 {
1273     std::vector<PermissionListState> permList;
1274     for (const auto& permission : permissions) {
1275         ACCESSTOKEN_LOG_DEBUG(LABEL, "permission: %{public}s.", permission.c_str());
1276         PermissionListState permState;
1277         permState.permissionName = permission;
1278         permState.state = SETTING_OPER;
1279         permList.emplace_back(permState);
1280     }
1281     ACCESSTOKEN_LOG_DEBUG(LABEL, "permList size: %{public}zu, permissions size: %{public}zu.",
1282         permList.size(), permissions.size());
1283 
1284     auto ret = AccessTokenKit::GetSelfPermissionsState(permList, info);
1285     if (ret == FORBIDDEN_OPER) { // if app is under control, change state from default -1 to 2
1286         for (auto& perm : permList) {
1287             perm.state = INVALID_OPER;
1288         }
1289     }
1290 
1291     for (const auto& permState : permList) {
1292         ACCESSTOKEN_LOG_DEBUG(LABEL, "permissions: %{public}s. permissionsState: %{public}u",
1293             permState.permissionName.c_str(), permState.state);
1294         permissionsState.emplace_back(permState.state);
1295     }
1296     if (permList.size() != permissions.size()) {
1297         ACCESSTOKEN_LOG_ERROR(LABEL, "Returned permList size: %{public}zu.", permList.size());
1298         return false;
1299     }
1300     if (ret != TypePermissionOper::DYNAMIC_OPER) {
1301         return false;
1302     }
1303 
1304     return true;
1305 }
1306 
ReleaseOrErrorHandle(int32_t code)1307 void UIExtensionCallback::ReleaseOrErrorHandle(int32_t code)
1308 {
1309     Ace::UIContent* uiContent = nullptr;
1310     if (this->reqContext_->uiAbilityFlag) {
1311         uiContent = this->reqContext_->abilityContext->GetUIContent();
1312     } else {
1313         uiContent = this->reqContext_->uiExtensionContext->GetUIContent();
1314     }
1315     if (uiContent != nullptr) {
1316         ACCESSTOKEN_LOG_INFO(LABEL, "close uiextension component");
1317         uiContent->CloseModalUIExtension(this->sessionId_);
1318     }
1319 
1320     if (code == 0) {
1321         return; // code is 0 means request has return by OnResult
1322     }
1323 
1324     napi_handle_scope scope = nullptr;
1325     napi_open_handle_scope(this->reqContext_->env, &scope);
1326     if (scope == nullptr) {
1327         ACCESSTOKEN_LOG_ERROR(LABEL, "napi_open_handle_scope failed");
1328         return;
1329     }
1330 
1331     napi_value result = GetNapiNull(this->reqContext_->env);
1332     if (this->reqContext_->deferred != nullptr) {
1333         ReturnPromiseResult(this->reqContext_->env, code, this->reqContext_->deferred, result);
1334     } else {
1335         ReturnCallbackResult(this->reqContext_->env, code, this->reqContext_->callbackRef, result);
1336     }
1337     napi_close_handle_scope(this->reqContext_->env, scope);
1338 }
1339 
UIExtensionCallback(const std::shared_ptr<RequestAsyncContext> & reqContext)1340 UIExtensionCallback::UIExtensionCallback(const std::shared_ptr<RequestAsyncContext>& reqContext)
1341 {
1342     this->reqContext_ = reqContext;
1343 }
1344 
~UIExtensionCallback()1345 UIExtensionCallback::~UIExtensionCallback()
1346 {}
1347 
SetSessionId(int32_t sessionId)1348 void UIExtensionCallback::SetSessionId(int32_t sessionId)
1349 {
1350     this->sessionId_ = sessionId;
1351 }
1352 
1353 /*
1354  * when UIExtensionAbility disconnect or use terminate or process die
1355  * releaseCode is 0 when process normal exit
1356  */
OnRelease(int32_t releaseCode)1357 void UIExtensionCallback::OnRelease(int32_t releaseCode)
1358 {
1359     ACCESSTOKEN_LOG_INFO(LABEL, "releaseCode is %{public}d", releaseCode);
1360 
1361     ReleaseOrErrorHandle(releaseCode);
1362 }
1363 
GrantResultsCallbackUI(const std::vector<std::string> & permissionList,const std::vector<int32_t> & permissionStates,std::shared_ptr<RequestAsyncContext> & data)1364 static void GrantResultsCallbackUI(const std::vector<std::string>& permissionList,
1365     const std::vector<int32_t>& permissionStates, std::shared_ptr<RequestAsyncContext>& data)
1366 {
1367     auto* retCB = new (std::nothrow) ResultCallback();
1368     if (retCB == nullptr) {
1369         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!");
1370         return;
1371     }
1372 
1373     // only permissions which need to grant change the result, other keey as GetSelfPermissionsState result
1374     std::vector<int> newGrantResults;
1375     UpdateGrantPermissionResultOnly(permissionList, permissionStates, data->permissionsState, newGrantResults);
1376 
1377     std::unique_ptr<ResultCallback> callbackPtr {retCB};
1378     retCB->permissions = permissionList;
1379     retCB->grantResults = newGrantResults;
1380     retCB->data = data;
1381 
1382     uv_loop_s* loop = nullptr;
1383     NAPI_CALL_RETURN_VOID(data->env, napi_get_uv_event_loop(data->env, &loop));
1384     if (loop == nullptr) {
1385         ACCESSTOKEN_LOG_ERROR(LABEL, "loop instance is nullptr");
1386         return;
1387     }
1388     uv_work_t* work = new (std::nothrow) uv_work_t;
1389     if (work == nullptr) {
1390         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!");
1391         return;
1392     }
1393     std::unique_ptr<uv_work_t> uvWorkPtr {work};
1394     work->data = reinterpret_cast<void *>(retCB);
1395     NAPI_CALL_RETURN_VOID(data->env,
1396         uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, ResultCallbackJSThreadWorker, uv_qos_default));
1397 
1398     uvWorkPtr.release();
1399     callbackPtr.release();
1400 }
1401 
1402 /*
1403  * when UIExtensionAbility use terminateSelfWithResult
1404  */
OnResult(int32_t resultCode,const AAFwk::Want & result)1405 void UIExtensionCallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
1406 {
1407     ACCESSTOKEN_LOG_INFO(LABEL, "resultCode is %{public}d", resultCode);
1408     std::vector<std::string> permissionList = result.GetStringArrayParam(PERMISSION_KEY);
1409     std::vector<int32_t> permissionStates = result.GetIntArrayParam(RESULT_KEY);
1410 
1411     GrantResultsCallbackUI(permissionList, permissionStates, this->reqContext_);
1412 }
1413 
1414 /*
1415  * when UIExtensionAbility send message to UIExtensionComponent
1416  */
OnReceive(const AAFwk::WantParams & receive)1417 void UIExtensionCallback::OnReceive(const AAFwk::WantParams& receive)
1418 {
1419     ACCESSTOKEN_LOG_INFO(LABEL, "called!");
1420 }
1421 
1422 /*
1423  * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
1424  */
OnError(int32_t code,const std::string & name,const std::string & message)1425 void UIExtensionCallback::OnError(int32_t code, const std::string& name, const std::string& message)
1426 {
1427     ACCESSTOKEN_LOG_INFO(LABEL, "code is %{public}d, name is %{public}s, message is %{public}s",
1428         code, name.c_str(), message.c_str());
1429 
1430     ReleaseOrErrorHandle(code);
1431 }
1432 
1433 /*
1434  * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
1435  * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
1436  */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)1437 void UIExtensionCallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
1438 {
1439     ACCESSTOKEN_LOG_INFO(LABEL, "connect to UIExtensionAbility successfully.");
1440 }
1441 
1442 /*
1443  * when UIExtensionComponent destructed
1444  */
OnDestroy()1445 void UIExtensionCallback::OnDestroy()
1446 {
1447     ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed.");
1448 }
1449 
CreateUIExtension(const Want & want,std::shared_ptr<RequestAsyncContext> asyncContext)1450 static void CreateUIExtension(const Want &want, std::shared_ptr<RequestAsyncContext> asyncContext)
1451 {
1452     Ace::UIContent* uiContent = nullptr;
1453     uint64_t beginTime = std::chrono::duration_cast<std::chrono::milliseconds>(
1454         std::chrono::system_clock::now().time_since_epoch()).count();
1455     if (asyncContext->uiAbilityFlag) {
1456         while (true) {
1457             uiContent = asyncContext->abilityContext->GetUIContent();
1458             uint64_t curTime = std::chrono::duration_cast<std::chrono::milliseconds>(
1459                 std::chrono::system_clock::now().time_since_epoch()).count();
1460             if ((uiContent != nullptr) || (curTime - beginTime > MAX_WAIT_TIME)) {
1461                 break;
1462             }
1463         }
1464     } else {
1465         while (true) {
1466             uiContent = asyncContext->uiExtensionContext->GetUIContent();
1467             uint64_t curTime = std::chrono::duration_cast<std::chrono::milliseconds>(
1468                 std::chrono::system_clock::now().time_since_epoch()).count();
1469             if ((uiContent != nullptr) || (curTime - beginTime > MAX_WAIT_TIME)) {
1470                 break;
1471             }
1472         }
1473     }
1474 
1475     if (uiContent == nullptr) {
1476         ACCESSTOKEN_LOG_ERROR(LABEL, "get ui content failed!");
1477         asyncContext->result = JsErrorCode::JS_ERROR_SYSTEM_CAPABILITY_NOT_SUPPORT;
1478         return;
1479     }
1480     auto uiExtCallback = std::make_shared<UIExtensionCallback>(asyncContext);
1481     Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
1482         std::bind(&UIExtensionCallback::OnRelease, uiExtCallback, std::placeholders::_1),
1483         std::bind(&UIExtensionCallback::OnResult, uiExtCallback, std::placeholders::_1, std::placeholders::_2),
1484         std::bind(&UIExtensionCallback::OnReceive, uiExtCallback, std::placeholders::_1),
1485         std::bind(&UIExtensionCallback::OnError, uiExtCallback, std::placeholders::_1, std::placeholders::_2,
1486             std::placeholders::_2),
1487         std::bind(&UIExtensionCallback::OnRemoteReady, uiExtCallback, std::placeholders::_1),
1488         std::bind(&UIExtensionCallback::OnDestroy, uiExtCallback),
1489     };
1490 
1491     Ace::ModalUIExtensionConfig config;
1492     config.isProhibitBack = true;
1493     int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
1494     ACCESSTOKEN_LOG_INFO(LABEL, "end CreateModalUIExtension, sessionId is %{public}d", sessionId);
1495     if (sessionId == 0) {
1496         ACCESSTOKEN_LOG_ERROR(LABEL, "create component failed, sessionId is 0");
1497         asyncContext->result = JsErrorCode::JS_ERROR_INNER;
1498         return;
1499     }
1500     uiExtCallback->SetSessionId(sessionId);
1501 }
1502 
StartUIExtension(std::shared_ptr<RequestAsyncContext> asyncContext)1503 static void StartUIExtension(std::shared_ptr<RequestAsyncContext> asyncContext)
1504 {
1505     AAFwk::Want want;
1506     want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantAbilityName);
1507     want.SetParam(PERMISSION_KEY, asyncContext->permissionList);
1508     want.SetParam(STATE_KEY, asyncContext->permissionsState);
1509     want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE);
1510     if (asyncContext->uiAbilityFlag) {
1511         want.SetParam(TOKEN_KEY, asyncContext->abilityContext->GetToken());
1512     } else {
1513         want.SetParam(TOKEN_KEY, asyncContext->uiExtensionContext->GetToken());
1514     }
1515     CreateUIExtension(want, asyncContext);
1516 }
1517 
RequestPermissionsFromUserExecute(napi_env env,void * data)1518 void NapiAtManager::RequestPermissionsFromUserExecute(napi_env env, void* data)
1519 {
1520     // asyncContext release in complete
1521     RequestAsyncContextHandle* asyncContextHandle = reinterpret_cast<RequestAsyncContextHandle*>(data);
1522     AccessTokenID tokenID = 0;
1523     if (asyncContextHandle->asyncContextPtr->uiAbilityFlag) {
1524         tokenID = asyncContextHandle->asyncContextPtr->abilityContext->GetApplicationInfo()->accessTokenId;
1525     } else {
1526         tokenID = asyncContextHandle->asyncContextPtr->uiExtensionContext->GetApplicationInfo()->accessTokenId;
1527     }
1528     if (tokenID != static_cast<AccessTokenID>(GetSelfTokenID())) {
1529         ACCESSTOKEN_LOG_ERROR(LABEL, "The context is not belong to the current application.");
1530         asyncContextHandle->asyncContextPtr->result = JsErrorCode::JS_ERROR_PARAM_INVALID;
1531         return;
1532     }
1533 
1534     if (!IsDynamicRequest(asyncContextHandle->asyncContextPtr->permissionList,
1535         asyncContextHandle->asyncContextPtr->permissionsState, asyncContextHandle->asyncContextPtr->info)) {
1536         ACCESSTOKEN_LOG_DEBUG(LABEL, "it does not need to request permission exsion");
1537         asyncContextHandle->asyncContextPtr->needDynamicRequest = false;
1538         return;
1539     }
1540     // service extension dialog
1541     if (asyncContextHandle->asyncContextPtr->info.grantBundleName == ORI_PERMISSION_MANAGER_BUNDLE_NAME) {
1542         ACCESSTOKEN_LOG_INFO(LABEL, "pop service extension dialog");
1543         StartServiceExtension(asyncContextHandle->asyncContextPtr);
1544     } else {
1545         ACCESSTOKEN_LOG_INFO(LABEL, "pop ui extension dialog");
1546         StartUIExtension(asyncContextHandle->asyncContextPtr);
1547         if (asyncContextHandle->asyncContextPtr->result != JsErrorCode::JS_OK) {
1548             ACCESSTOKEN_LOG_INFO(LABEL, "pop uiextension dialog fail, start to pop service extension dialog");
1549             StartServiceExtension(asyncContextHandle->asyncContextPtr);
1550         }
1551     }
1552 }
1553 
RequestPermissionsFromUserComplete(napi_env env,napi_status status,void * data)1554 void NapiAtManager::RequestPermissionsFromUserComplete(napi_env env, napi_status status, void* data)
1555 {
1556     RequestAsyncContextHandle* asyncContextHandle = reinterpret_cast<RequestAsyncContextHandle*>(data);
1557     std::unique_ptr<RequestAsyncContextHandle> callbackPtr {asyncContextHandle};
1558 
1559     if (asyncContextHandle->asyncContextPtr->needDynamicRequest) {
1560         return;
1561     }
1562     if ((asyncContextHandle->asyncContextPtr->permissionsState.empty()) &&
1563         (asyncContextHandle->asyncContextPtr->result == JsErrorCode::JS_OK)) {
1564         ACCESSTOKEN_LOG_ERROR(LABEL, "grantResults empty");
1565         asyncContextHandle->asyncContextPtr->result = JsErrorCode::JS_ERROR_INNER;
1566     }
1567     napi_value requestResult = WrapRequestResult(env,
1568         asyncContextHandle->asyncContextPtr->permissionList, asyncContextHandle->asyncContextPtr->permissionsState);
1569     if (requestResult == nullptr) {
1570         ACCESSTOKEN_LOG_DEBUG(LABEL, "wrap requestResult failed");
1571         if (asyncContextHandle->asyncContextPtr->result == JsErrorCode::JS_OK) {
1572             asyncContextHandle->asyncContextPtr->result = JsErrorCode::JS_ERROR_INNER;
1573         }
1574     } else {
1575         asyncContextHandle->asyncContextPtr->requestResult = requestResult;
1576     }
1577     if (asyncContextHandle->asyncContextPtr->deferred != nullptr) {
1578         ReturnPromiseResult(env, asyncContextHandle->asyncContextPtr->result,
1579             asyncContextHandle->asyncContextPtr->deferred, asyncContextHandle->asyncContextPtr->requestResult);
1580     } else {
1581         ReturnCallbackResult(env, asyncContextHandle->asyncContextPtr->result,
1582             asyncContextHandle->asyncContextPtr->callbackRef, asyncContextHandle->asyncContextPtr->requestResult);
1583     }
1584 }
1585 
RequestPermissionsFromUser(napi_env env,napi_callback_info info)1586 napi_value NapiAtManager::RequestPermissionsFromUser(napi_env env, napi_callback_info info)
1587 {
1588     ACCESSTOKEN_LOG_DEBUG(LABEL, "RequestPermissionsFromUser begin.");
1589     // use handle to protect asyncContext
1590     std::shared_ptr<RequestAsyncContext> asyncContext = std::make_shared<RequestAsyncContext>(env);
1591 
1592     if (!ParseRequestPermissionFromUser(env, info, asyncContext)) {
1593         return nullptr;
1594     }
1595     auto asyncContextHandle = std::make_unique<RequestAsyncContextHandle>(asyncContext);
1596     napi_value result = nullptr;
1597     if (asyncContextHandle->asyncContextPtr->callbackRef == nullptr) {
1598         NAPI_CALL(env, napi_create_promise(env, &(asyncContextHandle->asyncContextPtr->deferred), &result));
1599     } else {
1600         NAPI_CALL(env, napi_get_undefined(env, &result));
1601     }
1602 
1603     napi_value resource = nullptr; // resource name
1604     NAPI_CALL(env, napi_create_string_utf8(env, "RequestPermissionsFromUser", NAPI_AUTO_LENGTH, &resource));
1605     NAPI_CALL(env, napi_create_async_work(
1606         env, nullptr, resource, RequestPermissionsFromUserExecute, RequestPermissionsFromUserComplete,
1607         reinterpret_cast<void *>(asyncContextHandle.get()), &(asyncContextHandle->asyncContextPtr->work)));
1608 
1609     NAPI_CALL(env,
1610         napi_queue_async_work_with_qos(env, asyncContextHandle->asyncContextPtr->work, napi_qos_user_initiated));
1611 
1612     ACCESSTOKEN_LOG_DEBUG(LABEL, "RequestPermissionsFromUser end.");
1613     asyncContextHandle.release();
1614     return result;
1615 }
1616 
FillPermStateChangeInfo(const napi_env env,const napi_value * argv,const std::string & type,const napi_value thisVar,RegisterPermStateChangeInfo & registerPermStateChangeInfo)1617 bool NapiAtManager::FillPermStateChangeInfo(const napi_env env, const napi_value* argv, const std::string& type,
1618     const napi_value thisVar, RegisterPermStateChangeInfo& registerPermStateChangeInfo)
1619 {
1620     PermStateChangeScope scopeInfo;
1621     std::string errMsg;
1622     napi_ref callback = nullptr;
1623 
1624     // 1: the second parameter of argv
1625     if (!ParseAccessTokenIDArray(env, argv[1], scopeInfo.tokenIDs)) {
1626         errMsg = GetParamErrorMsg("tokenIDList", "Array<number>");
1627         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1628         return false;
1629     }
1630     // 2: the third parameter of argv
1631     if (!ParseStringArray(env, argv[2], scopeInfo.permList)) {
1632         errMsg = GetParamErrorMsg("tokenIDList", "Array<string>");
1633         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1634         return false;
1635     }
1636     // 3: the fourth parameter of argv
1637     if (!ParseCallback(env, argv[3], callback)) {
1638         errMsg = GetParamErrorMsg("tokenIDList", "Callback<PermissionStateChangeInfo>");
1639         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1640         return false;
1641     }
1642     std::sort(scopeInfo.tokenIDs.begin(), scopeInfo.tokenIDs.end());
1643     std::sort(scopeInfo.permList.begin(), scopeInfo.permList.end());
1644     registerPermStateChangeInfo.env = env;
1645     registerPermStateChangeInfo.callbackRef = callback;
1646     registerPermStateChangeInfo.permStateChangeType = type;
1647     registerPermStateChangeInfo.subscriber = std::make_shared<RegisterPermStateChangeScopePtr>(scopeInfo);
1648     registerPermStateChangeInfo.subscriber->SetEnv(env);
1649     registerPermStateChangeInfo.subscriber->SetCallbackRef(callback);
1650     registerPermStateChangeInfo.threadId_ = std::this_thread::get_id();
1651     std::shared_ptr<RegisterPermStateChangeScopePtr> *subscriber =
1652         new (std::nothrow) std::shared_ptr<RegisterPermStateChangeScopePtr>(
1653             registerPermStateChangeInfo.subscriber);
1654     if (subscriber == nullptr) {
1655         ACCESSTOKEN_LOG_ERROR(LABEL, "failed to create subscriber");
1656         return false;
1657     }
1658     napi_wrap(env, thisVar, reinterpret_cast<void*>(subscriber), [](napi_env nev, void *data, void *hint) {
1659         ACCESSTOKEN_LOG_DEBUG(LABEL, "RegisterPermStateChangeScopePtr delete");
1660         std::shared_ptr<RegisterPermStateChangeScopePtr>* subscriber =
1661             static_cast<std::shared_ptr<RegisterPermStateChangeScopePtr>*>(data);
1662         if (subscriber != nullptr && *subscriber != nullptr) {
1663             (*subscriber)->SetValid(false);
1664             delete subscriber;
1665         }
1666     }, nullptr, nullptr);
1667 
1668     return true;
1669 }
1670 
ParseInputToRegister(const napi_env env,const napi_callback_info cbInfo,RegisterPermStateChangeInfo & registerPermStateChangeInfo)1671 bool NapiAtManager::ParseInputToRegister(const napi_env env, const napi_callback_info cbInfo,
1672     RegisterPermStateChangeInfo& registerPermStateChangeInfo)
1673 {
1674     size_t argc = ON_OFF_MAX_PARAMS;
1675     napi_value argv[ON_OFF_MAX_PARAMS] = {nullptr};
1676     napi_value thisVar = nullptr;
1677     NAPI_CALL_BASE(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr), false);
1678     if (argc < ON_OFF_MAX_PARAMS) {
1679         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing."));
1680         return false;
1681     }
1682     if (thisVar == nullptr) {
1683         ACCESSTOKEN_LOG_ERROR(LABEL, "thisVar is nullptr");
1684         return false;
1685     }
1686     napi_valuetype valueTypeOfThis = napi_undefined;
1687     NAPI_CALL_BASE(env, napi_typeof(env, thisVar, &valueTypeOfThis), false);
1688     if (valueTypeOfThis == napi_undefined) {
1689         ACCESSTOKEN_LOG_ERROR(LABEL, "thisVar is undefined");
1690         return false;
1691     }
1692     // 0: the first parameter of argv
1693     std::string type;
1694     if (!ParseString(env, argv[0], type)) {
1695         std::string errMsg = GetParamErrorMsg("type", "string");
1696         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1697         return false;
1698     }
1699     if (!FillPermStateChangeInfo(env, argv, type, thisVar, registerPermStateChangeInfo)) {
1700         return false;
1701     }
1702 
1703     return true;
1704 }
1705 
RegisterPermStateChangeCallback(napi_env env,napi_callback_info cbInfo)1706 napi_value NapiAtManager::RegisterPermStateChangeCallback(napi_env env, napi_callback_info cbInfo)
1707 {
1708     RegisterPermStateChangeInfo* registerPermStateChangeInfo =
1709         new (std::nothrow) RegisterPermStateChangeInfo();
1710     if (registerPermStateChangeInfo == nullptr) {
1711         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for subscribeCBInfo!");
1712         return nullptr;
1713     }
1714     std::unique_ptr<RegisterPermStateChangeInfo> callbackPtr {registerPermStateChangeInfo};
1715     if (!ParseInputToRegister(env, cbInfo, *registerPermStateChangeInfo)) {
1716         return nullptr;
1717     }
1718     if (IsExistRegister(env, registerPermStateChangeInfo)) {
1719         ACCESSTOKEN_LOG_ERROR(LABEL, "Subscribe failed. The current subscriber has been existed");
1720         std::string errMsg = GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_INVALID);
1721         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_INVALID, errMsg)));
1722         return nullptr;
1723     }
1724     int32_t result = AccessTokenKit::RegisterPermStateChangeCallback(registerPermStateChangeInfo->subscriber);
1725     if (result != RET_SUCCESS) {
1726         ACCESSTOKEN_LOG_ERROR(LABEL, "RegisterPermStateChangeCallback failed");
1727         registerPermStateChangeInfo->errCode = result;
1728         int32_t jsCode = GetJsErrorCode(result);
1729         std::string errMsg = GetErrorMessage(jsCode);
1730         NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, jsCode, errMsg)));
1731         return nullptr;
1732     }
1733     {
1734         std::lock_guard<std::mutex> lock(g_lockForPermStateChangeRegisters);
1735         g_permStateChangeRegisters.emplace_back(registerPermStateChangeInfo);
1736         ACCESSTOKEN_LOG_DEBUG(LABEL, "add g_PermStateChangeRegisters.size = %{public}zu",
1737             g_permStateChangeRegisters.size());
1738     }
1739     callbackPtr.release();
1740     return nullptr;
1741 }
1742 
ParseInputToUnregister(const napi_env env,napi_callback_info cbInfo,UnregisterPermStateChangeInfo & unregisterPermStateChangeInfo)1743 bool NapiAtManager::ParseInputToUnregister(const napi_env env, napi_callback_info cbInfo,
1744     UnregisterPermStateChangeInfo& unregisterPermStateChangeInfo)
1745 {
1746     size_t argc = ON_OFF_MAX_PARAMS;
1747     napi_value argv[ON_OFF_MAX_PARAMS] = {nullptr};
1748     napi_value thisVar = nullptr;
1749     napi_ref callback = nullptr;
1750     std::string errMsg;
1751     if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
1752         ACCESSTOKEN_LOG_ERROR(LABEL, "napi_get_cb_info failed");
1753         return false;
1754     }
1755     // 1: off required minnum argc
1756     if (argc < ON_OFF_MAX_PARAMS - 1) {
1757         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, "Parameter is missing."));
1758         return false;
1759     }
1760     // 0: the first parameter of argv
1761     std::string type;
1762     if (!ParseString(env, argv[0], type)) {
1763         errMsg = GetParamErrorMsg("type", "permissionStateChange");
1764         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1765         return false;
1766     }
1767     PermStateChangeScope scopeInfo;
1768     // 1: the second parameter of argv
1769     if (!ParseAccessTokenIDArray(env, argv[1], scopeInfo.tokenIDs)) {
1770         errMsg = GetParamErrorMsg("tokenIDList", "Array<number>");
1771         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1772         return false;
1773     }
1774     // 2: the third parameter of argv
1775     if (!ParseStringArray(env, argv[2], scopeInfo.permList)) {
1776         errMsg = GetParamErrorMsg("permissionNameList", "Array<string>");
1777         napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1778         return false;
1779     }
1780     if (argc == ON_OFF_MAX_PARAMS) {
1781         // 3: the fourth parameter of argv
1782         if (!ParseCallback(env, argv[3], callback)) {
1783             errMsg = GetParamErrorMsg("callback", "Callback<PermissionStateChangeInfo>");
1784             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_ILLEGAL, errMsg));
1785             return false;
1786         }
1787     }
1788 
1789     std::sort(scopeInfo.tokenIDs.begin(), scopeInfo.tokenIDs.end());
1790     std::sort(scopeInfo.permList.begin(), scopeInfo.permList.end());
1791     unregisterPermStateChangeInfo.env = env;
1792     unregisterPermStateChangeInfo.callbackRef = callback;
1793     unregisterPermStateChangeInfo.permStateChangeType = type;
1794     unregisterPermStateChangeInfo.scopeInfo = scopeInfo;
1795     unregisterPermStateChangeInfo.threadId_ = std::this_thread::get_id();
1796     return true;
1797 }
1798 
UnregisterPermStateChangeCallback(napi_env env,napi_callback_info cbInfo)1799 napi_value NapiAtManager::UnregisterPermStateChangeCallback(napi_env env, napi_callback_info cbInfo)
1800 {
1801     UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo =
1802         new (std::nothrow) UnregisterPermStateChangeInfo();
1803     if (unregisterPermStateChangeInfo == nullptr) {
1804         ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for subscribeCBInfo!");
1805         return nullptr;
1806     }
1807     std::unique_ptr<UnregisterPermStateChangeInfo> callbackPtr {unregisterPermStateChangeInfo};
1808     if (!ParseInputToUnregister(env, cbInfo, *unregisterPermStateChangeInfo)) {
1809         return nullptr;
1810     }
1811     std::vector<RegisterPermStateChangeInfo*> batchPermStateChangeRegisters;
1812     if (!FindAndGetSubscriberInVector(unregisterPermStateChangeInfo, batchPermStateChangeRegisters, env)) {
1813         ACCESSTOKEN_LOG_ERROR(LABEL, "Unsubscribe failed. The current subscriber does not exist");
1814         std::string errMsg = GetErrorMessage(JsErrorCode::JS_ERROR_PARAM_INVALID);
1815         NAPI_CALL(env,
1816             napi_throw(env, GenerateBusinessError(env, JsErrorCode::JS_ERROR_PARAM_INVALID, errMsg)));
1817         return nullptr;
1818     }
1819     for (const auto& item : batchPermStateChangeRegisters) {
1820         PermStateChangeScope scopeInfo;
1821         item->subscriber->GetScope(scopeInfo);
1822         int32_t result = AccessTokenKit::UnRegisterPermStateChangeCallback(item->subscriber);
1823         if (result == RET_SUCCESS) {
1824             DeleteRegisterFromVector(scopeInfo, env, item->callbackRef);
1825         } else {
1826             ACCESSTOKEN_LOG_ERROR(LABEL, "Batch UnregisterPermActiveChangeCompleted failed");
1827             int32_t jsCode = GetJsErrorCode(result);
1828             std::string errMsg = GetErrorMessage(jsCode);
1829             NAPI_CALL(env, napi_throw(env, GenerateBusinessError(env, jsCode, errMsg)));
1830         }
1831     }
1832     return nullptr;
1833 }
1834 
FindAndGetSubscriberInVector(UnregisterPermStateChangeInfo * unregisterPermStateChangeInfo,std::vector<RegisterPermStateChangeInfo * > & batchPermStateChangeRegisters,const napi_env env)1835 bool NapiAtManager::FindAndGetSubscriberInVector(UnregisterPermStateChangeInfo* unregisterPermStateChangeInfo,
1836     std::vector<RegisterPermStateChangeInfo*>& batchPermStateChangeRegisters, const napi_env env)
1837 {
1838     std::lock_guard<std::mutex> lock(g_lockForPermStateChangeRegisters);
1839     std::vector<AccessTokenID> targetTokenIDs = unregisterPermStateChangeInfo->scopeInfo.tokenIDs;
1840     std::vector<std::string> targetPermList = unregisterPermStateChangeInfo->scopeInfo.permList;
1841     for (const auto& item : g_permStateChangeRegisters) {
1842         if (unregisterPermStateChangeInfo->callbackRef != nullptr) {
1843             if (!CompareCallbackRef(env, item->callbackRef, unregisterPermStateChangeInfo->callbackRef,
1844                 item->threadId_)) {
1845                 continue;
1846             }
1847         } else {
1848             // batch delete currentThread callback
1849             if (!IsCurrentThread(item->threadId_)) {
1850                 continue;
1851             }
1852         }
1853         PermStateChangeScope scopeInfo;
1854         item->subscriber->GetScope(scopeInfo);
1855         if (scopeInfo.tokenIDs == targetTokenIDs && scopeInfo.permList == targetPermList) {
1856             ACCESSTOKEN_LOG_DEBUG(LABEL, "find subscriber in map");
1857             unregisterPermStateChangeInfo->subscriber = item->subscriber;
1858             batchPermStateChangeRegisters.emplace_back(item);
1859         }
1860     }
1861     if (!batchPermStateChangeRegisters.empty()) {
1862         return true;
1863     }
1864     return false;
1865 }
1866 
IsExistRegister(const napi_env env,const RegisterPermStateChangeInfo * registerPermStateChangeInfo)1867 bool NapiAtManager::IsExistRegister(const napi_env env, const RegisterPermStateChangeInfo* registerPermStateChangeInfo)
1868 {
1869     PermStateChangeScope targetScopeInfo;
1870     registerPermStateChangeInfo->subscriber->GetScope(targetScopeInfo);
1871     std::vector<AccessTokenID> targetTokenIDs = targetScopeInfo.tokenIDs;
1872     std::vector<std::string> targetPermList = targetScopeInfo.permList;
1873     std::lock_guard<std::mutex> lock(g_lockForPermStateChangeRegisters);
1874 
1875     for (const auto& item : g_permStateChangeRegisters) {
1876         PermStateChangeScope scopeInfo;
1877         item->subscriber->GetScope(scopeInfo);
1878 
1879         bool hasPermIntersection = false;
1880         // Special cases:
1881         // 1.Have registered full, and then register some
1882         // 2.Have registered some, then register full
1883         if (scopeInfo.permList.empty() || targetPermList.empty()) {
1884             hasPermIntersection = true;
1885         }
1886         for (const auto& PermItem : targetPermList) {
1887             if (hasPermIntersection) {
1888                 break;
1889             }
1890             auto iter = std::find(scopeInfo.permList.begin(), scopeInfo.permList.end(), PermItem);
1891             if (iter != scopeInfo.permList.end()) {
1892                 hasPermIntersection = true;
1893             }
1894         }
1895 
1896         bool hasTokenIdIntersection = false;
1897 
1898         if (scopeInfo.tokenIDs.empty() || targetTokenIDs.empty()) {
1899             hasTokenIdIntersection = true;
1900         }
1901         for (const auto& tokenItem : targetTokenIDs) {
1902             if (hasTokenIdIntersection) {
1903                 break;
1904             }
1905             auto iter = std::find(scopeInfo.tokenIDs.begin(), scopeInfo.tokenIDs.end(), tokenItem);
1906             if (iter != scopeInfo.tokenIDs.end()) {
1907                 hasTokenIdIntersection = true;
1908             }
1909         }
1910 
1911         if (hasTokenIdIntersection && hasPermIntersection &&
1912             CompareCallbackRef(env, item->callbackRef, registerPermStateChangeInfo->callbackRef, item->threadId_)) {
1913             return true;
1914         }
1915     }
1916     ACCESSTOKEN_LOG_DEBUG(LABEL, "cannot find subscriber in vector");
1917     return false;
1918 }
1919 
DeleteRegisterFromVector(const PermStateChangeScope & scopeInfo,const napi_env env,napi_ref subscriberRef)1920 void NapiAtManager::DeleteRegisterFromVector(const PermStateChangeScope& scopeInfo, const napi_env env,
1921     napi_ref subscriberRef)
1922 {
1923     std::vector<AccessTokenID> targetTokenIDs = scopeInfo.tokenIDs;
1924     std::vector<std::string> targetPermList = scopeInfo.permList;
1925     std::lock_guard<std::mutex> lock(g_lockForPermStateChangeRegisters);
1926     auto item = g_permStateChangeRegisters.begin();
1927     while (item != g_permStateChangeRegisters.end()) {
1928         PermStateChangeScope stateChangeScope;
1929         (*item)->subscriber->GetScope(stateChangeScope);
1930         if ((stateChangeScope.tokenIDs == targetTokenIDs) && (stateChangeScope.permList == targetPermList) &&
1931             CompareCallbackRef(env, (*item)->callbackRef, subscriberRef, (*item)->threadId_)) {
1932             ACCESSTOKEN_LOG_DEBUG(LABEL, "Find subscribers in vector, delete");
1933             delete *item;
1934             *item = nullptr;
1935             g_permStateChangeRegisters.erase(item);
1936             break;
1937         } else {
1938             ++item;
1939         }
1940     }
1941 }
1942 }  // namespace AccessToken
1943 }  // namespace Security
1944 }  // namespace OHOS
1945 
1946 EXTERN_C_START
1947 /*
1948  * function for module exports
1949  */
Init(napi_env env,napi_value exports)1950 static napi_value Init(napi_env env, napi_value exports)
1951 {
1952     ACCESSTOKEN_LOG_DEBUG(OHOS::Security::AccessToken::LABEL, "Register end, start init.");
1953 
1954     return OHOS::Security::AccessToken::NapiAtManager::Init(env, exports);
1955 }
1956 EXTERN_C_END
1957 
1958 /*
1959  * Module define
1960  */
1961 static napi_module g_module = {
1962     .nm_version = 1,
1963     .nm_flags = 0,
1964     .nm_filename = nullptr,
1965     .nm_register_func = Init,
1966     .nm_modname = "abilityAccessCtrl",
1967     .nm_priv = static_cast<void *>(nullptr),
1968     .reserved = {nullptr}
1969 };
1970 
1971 /*
1972  * Module register function
1973  */
AbilityAccessCtrlmoduleRegister(void)1974 extern "C" __attribute__((constructor)) void AbilityAccessCtrlmoduleRegister(void)
1975 {
1976     napi_module_register(&g_module);
1977 }
1978