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