diff --git a/interfaces/kits/accesstoken/napi/include/napi_atmanager.h b/interfaces/kits/accesstoken/napi/include/napi_atmanager.h index 167e816c95b74db111d3727f2a08908c293b7b12..07352e0910ec82b3195f41751f18464b14e47cc8 100644 --- a/interfaces/kits/accesstoken/napi/include/napi_atmanager.h +++ b/interfaces/kits/accesstoken/napi/include/napi_atmanager.h @@ -19,9 +19,13 @@ #include #include #include +#include +#include "access_token.h" +#include "accesstoken_kit.h" #include "napi/native_api.h" #include "napi/native_node_api.h" +#include "perm_state_change_callback_customize.h" namespace OHOS { namespace Security { @@ -32,9 +36,61 @@ const int VALUE_BUFFER_SIZE = 256; const int ASYNC_CALL_BACK_VALUES_NUM = 2; const int VERIFY_OR_FLAG_INPUT_MAX_VALUES = 2; const int GRANT_OR_REVOKE_INPUT_MAX_VALUES = 4; +const size_t ARGS_SIZE_ONE = 1; +const size_t ARGS_SIZE_TWO = 2; +const size_t ARGS_SIZE_FOUR = 4; +const int PARAM0 = 0; +const int PARAM1 = 1; +const int PARAM2 = 2; +const int PARAM3 = 3; + +enum PermStateChangeType { + PERMISSION_REVOKED_OPER = 0, + PERMISSION_GRANTED_OPER = 1, +}; static thread_local napi_ref atManagerRef_; const std::string ATMANAGER_CLASS_NAME = "atManager"; +class RegisterPermStateChangeScopePtr : public PermStateChangeCallbackCustomize { +public: + explicit RegisterPermStateChangeScopePtr(const PermStateChangeScope &subscribeInfo); + ~RegisterPermStateChangeScopePtr(); + void PermStateChangeCallback(PermStateChangeInfo& result); + void SetEnv(const napi_env &env); + void SetCallbackRef(const napi_ref &ref); +private: + napi_env env_ = nullptr; + napi_ref ref_ = nullptr; +}; + +struct RegisterPermStateChangeWorker { + napi_env env = nullptr; + napi_ref ref = nullptr; + PermStateChangeInfo result; + RegisterPermStateChangeScopePtr *subscriber = nullptr; +}; + + +struct RegisterPermStateChangeInfo { + napi_env env = nullptr; + napi_async_work work = nullptr; + napi_ref callbackRef = nullptr; + std::string permStateChangeType; + PermStateChangeScope scopeInfo; + AccessTokenKit *accessTokenKit = nullptr; + std::shared_ptr subscriber = nullptr; +}; + +struct UnregisterPermStateChangeInfo { + napi_env env = nullptr; + napi_async_work work = nullptr; + napi_ref callbackRef = nullptr; + size_t argc; + std::string permStateChangeType; + PermStateChangeScope scopeInfo; + AccessTokenKit *accessTokenKit = nullptr; + std::shared_ptr subscriber = nullptr; +}; struct AtManagerAsyncContext { napi_env env = nullptr; @@ -75,6 +131,20 @@ private: static void GetPermissionFlagsExcute(napi_env env, void *data); static void GetPermissionFlagsComplete(napi_env env, napi_status status, void *data); static void SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName); + + static void ParseInputToRegister(const napi_env env, napi_value (&argv)[ARGS_SIZE_FOUR], std::string &type, + napi_ref &callback, std::vector& tokenIDs, std::vector& permList); + static napi_value RegisterPermStateChangeCallback(napi_env env, napi_callback_info cbinfo); + static void RegisterPermStateChangeExcute(napi_env env, void *data); + static void RegisterPermStateChangeComplete(napi_env env, napi_status status, void *data); + static void ParseInputToUnregister(const napi_env env, const size_t &argc, + const napi_value (&argv)[ARGS_SIZE_FOUR], std::string &type, napi_ref &callback, + std::vector& tokenIDs, std::vector& permList); + static napi_value UnregisterPermStateChangeCallback(napi_env env, napi_callback_info cbinfo); + static void UnregisterPermStateChangeExcuteCB(napi_env env, void *data); + static void UnregisterPermStateChangeCompletedCB(napi_env env, napi_status status, void *data); + static void FindRegisterInMap(std::shared_ptr &subscriber, + UnregisterPermStateChangeInfo *unregisterPermStateChangeInfo, bool &isFind); }; } // namespace AccessToken } // namespace Security diff --git a/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp b/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp index a74f44ccc758463b49c647b33e686631b6922ae8..a9add93e134cd6f593b65ec41f4160eefbca6d23 100644 --- a/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp +++ b/interfaces/kits/accesstoken/napi/src/napi_atmanager.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -27,12 +28,183 @@ namespace OHOS { namespace Security { namespace AccessToken { +std::mutex g_lockForPermStateChangeRegisters; +std::map> g_PermStateChangeRegisters; namespace { static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AccessTokenAbilityAccessCtrl" }; + +static napi_value WrapVoidToJS(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_get_null(env, &result)); + return result; +}; + +static std::vector ParseStringArray(const napi_env env, const napi_value value) +{ + std::vector res; + uint32_t length = 0; + + napi_get_array_length(env, value, &length); + napi_value valueArray; + for (uint32_t i = 0; i < length; i++) { + napi_get_element(env, value, i, &valueArray); + char valueChar[ VALUE_BUFFER_SIZE ] = { 0 }; + size_t resultout; + napi_get_value_string_utf8(env, valueArray, valueChar, + VALUE_BUFFER_SIZE + 1, &resultout); // get string + res.emplace_back(std::string(valueChar)); + } + return res; +}; + +static std::vector ParseAccessTokenIDArray(const napi_env env, const napi_value value) +{ + std::vector res; + uint32_t length = 0; + napi_get_array_length(env, value, &length); + napi_value valueArray; + for (uint32_t i = 0; i < length; i++) { + napi_get_element(env, value, i, &valueArray); + AccessTokenID result; + napi_get_value_uint32(env, valueArray, &result); + res.emplace_back(result); + } + return res; +}; + +static void ConvertPermStateChangeInfo(napi_env env, napi_value value, const PermStateChangeInfo result) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "ConvertPermStateChangeInfo"); + napi_value type = nullptr; + napi_create_int32(env, result.PermStateChangeType, &type); + napi_set_named_property(env, value, "change", type); + napi_value tokenId = nullptr; + napi_create_int32(env, result.tokenID, &tokenId); + napi_set_named_property(env, value, "tokenID", tokenId); + napi_value permissionName = nullptr; + napi_create_string_utf8(env, result.permissionName.c_str(), + NAPI_AUTO_LENGTH, &permissionName); + napi_set_named_property(env, value, "permissionName", permissionName); +}; + +static bool CompareScopeInfo(const PermStateChangeScope &scopeInfo, + const std::vector& tokenIDs, const std::vector& permList) +{ + std::vector targetTokenIDs = scopeInfo.tokenIDs; + std::vector targetPermList = scopeInfo.permList; + if (targetTokenIDs.size() != tokenIDs.size() || targetPermList.size() != permList.size()) { + return false; + } + std::sort(targetTokenIDs.begin(), targetTokenIDs.end()); + std::sort(targetPermList.begin(), targetPermList.end()); + for (size_t i = 0; i < tokenIDs.size(); i++) { + if (targetTokenIDs[i] != tokenIDs[i]) { + return false; + } + if (targetPermList[i] != permList[i]) { + return false; + } + } + return true; +} + +static void UvQueueWorkPermStateChanged(uv_work_t *work, int status) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "UvQueueWorkPermStateChanged begin"); + if (work == nullptr || work->data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "work == nullptr || work->data == nullptr"); + return; + } + RegisterPermStateChangeWorker *registerPermStateChangeData = + reinterpret_cast(work->data); + napi_value result[ARGS_SIZE_ONE] = {nullptr}; + napi_create_array(registerPermStateChangeData->env, &result[PARAM0]); + ConvertPermStateChangeInfo(registerPermStateChangeData->env, result[PARAM0], registerPermStateChangeData->result); + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value resultout = nullptr; + napi_get_undefined(registerPermStateChangeData->env, &undefined); + + bool isFound = false; + { + std::lock_guard lock(g_lockForPermStateChangeRegisters); + for (auto registersInstance : g_PermStateChangeRegisters) { + for (auto item : registersInstance.second) { + if (item->subscriber.get() == registerPermStateChangeData->subscriber) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "subscriber is found"); + isFound = true; + break; + } + } + } + } + if (isFound) { + napi_get_reference_value(registerPermStateChangeData->env, registerPermStateChangeData->ref, &callback); + } else { + ACCESSTOKEN_LOG_DEBUG(LABEL, "subscriber is not found"); + } + NAPI_CALL_RETURN_VOID(registerPermStateChangeData->env, + napi_call_function(registerPermStateChangeData->env, + undefined, callback, ARGS_SIZE_ONE, &result[PARAM0], &resultout)); + ACCESSTOKEN_LOG_DEBUG(LABEL, "UvQueueWorkPermStateChanged end"); + delete registerPermStateChangeData; + registerPermStateChangeData = nullptr; + delete work; +}; } // namespace +RegisterPermStateChangeScopePtr::RegisterPermStateChangeScopePtr(const PermStateChangeScope &subscribeInfo) + : PermStateChangeCallbackCustomize(subscribeInfo) +{} + +RegisterPermStateChangeScopePtr::~RegisterPermStateChangeScopePtr() +{} + +void RegisterPermStateChangeScopePtr::PermStateChangeCallback(PermStateChangeInfo& result) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "PermStateChangeCallback"); + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(env_, &loop); + if (loop == nullptr) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "loop instance is nullptr"); + return; + } + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "insufficient memory for work!"); + return; + } + + RegisterPermStateChangeWorker *registerPermStateChangeWorker = + new (std::nothrow) RegisterPermStateChangeWorker(); + + if (registerPermStateChangeWorker == nullptr) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "insufficient memory for RegisterPermStateChangeWorker!"); + delete work; + return; + } + registerPermStateChangeWorker->env = env_; + registerPermStateChangeWorker->ref = ref_; + registerPermStateChangeWorker->result = result; + registerPermStateChangeWorker->subscriber = this; + work->data = reinterpret_cast(registerPermStateChangeWorker); + uv_queue_work(loop, work, [](uv_work_t *work) {}, UvQueueWorkPermStateChanged); + ACCESSTOKEN_LOG_DEBUG(LABEL, "PermStateChangeCallback end"); +} + +void RegisterPermStateChangeScopePtr::SetEnv(const napi_env &env) +{ + env_ = env; +} + +void RegisterPermStateChangeScopePtr::SetCallbackRef(const napi_ref &ref) +{ + ref_ = ref; +} + void NapiAtManager::SetNamedProperty(napi_env env, napi_value dstObj, const int32_t objValue, const char *propName) { napi_value prop = nullptr; @@ -54,7 +226,9 @@ napi_value NapiAtManager::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("verifyAccessTokenSync", VerifyAccessTokenSync), DECLARE_NAPI_FUNCTION("grantUserGrantedPermission", GrantUserGrantedPermission), DECLARE_NAPI_FUNCTION("revokeUserGrantedPermission", RevokeUserGrantedPermission), - DECLARE_NAPI_FUNCTION("getPermissionFlags", GetPermissionFlags) + DECLARE_NAPI_FUNCTION("getPermissionFlags", GetPermissionFlags), + DECLARE_NAPI_FUNCTION("on", RegisterPermStateChangeCallback), + DECLARE_NAPI_FUNCTION("off", UnregisterPermStateChangeCallback), }; napi_value cons = nullptr; @@ -70,8 +244,15 @@ napi_value NapiAtManager::Init(napi_env env, napi_value exports) SetNamedProperty(env, GrantStatus, PERMISSION_DENIED, "PERMISSION_DENIED"); SetNamedProperty(env, GrantStatus, PERMISSION_GRANTED, "PERMISSION_GRANTED"); + napi_value permStateChangeType = nullptr; + napi_create_object(env, &permStateChangeType); + + SetNamedProperty(env, permStateChangeType, PERMISSION_REVOKED_OPER, "PERMISSION_REVOKED_OPER"); + SetNamedProperty(env, permStateChangeType, PERMISSION_GRANTED_OPER, "PERMISSION_GRANTED_OPER"); + napi_property_descriptor exportFuncs[] = { DECLARE_NAPI_PROPERTY("GrantStatus", GrantStatus), + DECLARE_NAPI_PROPERTY("PermStateChangeType", permStateChangeType), }; napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs); @@ -550,6 +731,276 @@ napi_value NapiAtManager::GetPermissionFlags(napi_env env, napi_callback_info in return result; } + +void NapiAtManager::ParseInputToRegister(const napi_env env, + napi_value (&argv)[ARGS_SIZE_FOUR], std::string &type, napi_ref &callback, + std::vector& tokenIDs, std::vector& permList) +{ + napi_valuetype valueType = napi_undefined; + ACCESSTOKEN_LOG_DEBUG(LABEL, "ParseInputToRegister begin."); + napi_typeof(env, argv[PARAM0], &valueType); + if (valueType == napi_string) { + char typeName[ VALUE_BUFFER_SIZE ] = { 0 }; + size_t result; + napi_get_value_string_utf8(env, argv[PARAM0], typeName, + VALUE_BUFFER_SIZE + 1, &result); // get typeName + type = std::string(typeName); + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "argv[PARAM0] type matching failed"); + return; + } + tokenIDs = ParseAccessTokenIDArray(env, argv[PARAM1]); // get tokenIDs + permList = ParseStringArray(env, argv[PARAM2]); // get permList + napi_typeof(env, argv[PARAM3], &valueType); // get PARAM[3] type + if (valueType == napi_function) { + napi_create_reference(env, argv[PARAM3], 1, &callback); // get callback + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "argv[PARAM3] type matching failed"); + return; + } +} + +void NapiAtManager::RegisterPermStateChangeExcute(napi_env env, void *data) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "napi_create_async_work running"); + RegisterPermStateChangeInfo *registerPermStateChangeInfo = + reinterpret_cast(data); + (*registerPermStateChangeInfo->subscriber).SetEnv(env); + (*registerPermStateChangeInfo->subscriber).SetCallbackRef(registerPermStateChangeInfo->callbackRef); + int errCode = AccessTokenKit::RegisterPermStateChangeCallback(registerPermStateChangeInfo->subscriber); + ACCESSTOKEN_LOG_DEBUG(LABEL, "error code is %{public}d", errCode); + if (errCode != RET_FAILED) { + std::lock_guard lock(g_lockForPermStateChangeRegisters); + g_PermStateChangeRegisters[registerPermStateChangeInfo->accessTokenKit].emplace_back( + registerPermStateChangeInfo); + ACCESSTOKEN_LOG_DEBUG(LABEL, "g_PermStateChangeRegisters->second.size = %{public}zu", + g_PermStateChangeRegisters[registerPermStateChangeInfo->accessTokenKit].size()); + } + ACCESSTOKEN_LOG_INFO(LABEL, "error code is %{public}d", errCode); +} + +void NapiAtManager::RegisterPermStateChangeComplete(napi_env env, napi_status status, void *data) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "napi_create_async_work complete"); + + RegisterPermStateChangeInfo *registerPermStateChangeInfo = + reinterpret_cast(data); + napi_delete_async_work(env, registerPermStateChangeInfo->work); + ACCESSTOKEN_LOG_DEBUG(LABEL, "RegisterPermStateChangeComplete end"); +} + +napi_value NapiAtManager::RegisterPermStateChangeCallback(napi_env env, napi_callback_info cbInfo) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "RegisterPermStateChangeCallback begin."); + size_t argc = ARGS_SIZE_FOUR; + napi_value argv[ARGS_SIZE_FOUR] = {nullptr}; + napi_value thisVar = nullptr; + napi_ref callback = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, NULL)); // cnInfo -> argv + std::string type; + std::vector tokenIDs; + std::vector permList; + ParseInputToRegister(env, argv, type, callback, tokenIDs, permList); + RegisterPermStateChangeInfo *registerPermStateChangeInfo = + new (std::nothrow) RegisterPermStateChangeInfo(); + if (registerPermStateChangeInfo == nullptr) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "insufficient memory for subscribeCBInfo!"); + return WrapVoidToJS(env); + } + registerPermStateChangeInfo->env = env; + registerPermStateChangeInfo->work = nullptr; + registerPermStateChangeInfo->callbackRef = callback; + registerPermStateChangeInfo->permStateChangeType = type; + PermStateChangeScope scopeInfo; + scopeInfo.tokenIDs = tokenIDs; + scopeInfo.permList = permList; + registerPermStateChangeInfo->scopeInfo = scopeInfo; + registerPermStateChangeInfo->subscriber = std::make_shared(scopeInfo); + AccessTokenKit *accessTokenKitInfo = nullptr; + napi_unwrap(env, thisVar, reinterpret_cast(&accessTokenKitInfo)); + registerPermStateChangeInfo->accessTokenKit = accessTokenKitInfo; + napi_value resource = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "RegisterPermStateChangeCallback", NAPI_AUTO_LENGTH, &resource)); + NAPI_CALL(env, napi_create_async_work(env, + nullptr, + resource, + RegisterPermStateChangeExcute, + RegisterPermStateChangeComplete, + reinterpret_cast(registerPermStateChangeInfo), + ®isterPermStateChangeInfo->work)); + napi_queue_async_work(env, registerPermStateChangeInfo->work); + return WrapVoidToJS(env); +} + +void NapiAtManager::ParseInputToUnregister(const napi_env env, const size_t &argc, + const napi_value (&argv)[ARGS_SIZE_FOUR], std::string &type, napi_ref &callback, + std::vector& tokenIDs, std::vector& permList) +{ + napi_valuetype valueType = napi_undefined; + ACCESSTOKEN_LOG_DEBUG(LABEL, "ParseInputToUnregister begin."); + napi_typeof(env, argv[PARAM0], &valueType); + if (valueType == napi_string) { + char typeName[ VALUE_BUFFER_SIZE ] = { 0 }; + size_t result; + napi_get_value_string_utf8(env, argv[PARAM0], typeName, + VALUE_BUFFER_SIZE + 1, &result); // get typeName + type = std::string(typeName); + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "argv[PARAM0] type matching failed"); + return; + } + tokenIDs = ParseAccessTokenIDArray(env, argv[PARAM1]); // get tokenIDs + permList = ParseStringArray(env, argv[PARAM2]); // get permList + if (argc >= ARGS_SIZE_FOUR) { + napi_typeof(env, argv[PARAM3], &valueType); // get PRARM[3] type + if (valueType == napi_function) { + napi_create_reference(env, argv[PARAM3], 1, &callback); // get callback + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "argv[PARAM3] type matching failed"); + return; + } + } +} + +void NapiAtManager::UnregisterPermStateChangeExcuteCB(napi_env env, void *data) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "napi_create_async_work running"); + UnregisterPermStateChangeInfo *unregisterPermStateChangeInfo = + reinterpret_cast(data); + auto subscriber = unregisterPermStateChangeInfo->subscriber; + (*subscriber).SetEnv(env); + (*subscriber).SetCallbackRef(unregisterPermStateChangeInfo->callbackRef); + int errCode = AccessTokenKit::UnRegisterPermStateChangeCallback(subscriber); + ACCESSTOKEN_LOG_DEBUG(LABEL, "error code is %{public}d", errCode); +} + +void NapiAtManager::UnregisterPermStateChangeCompletedCB(napi_env env, napi_status status, void *data) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "UnregisterPermStateChangeCompletedCB begin"); + UnregisterPermStateChangeInfo *unregisterPermStateChangeInfo = + reinterpret_cast(data); + if (unregisterPermStateChangeInfo->argc >= ARGS_SIZE_FOUR) { + napi_value results[ARGS_SIZE_ONE] = {nullptr}; + napi_value result = nullptr; + napi_get_null(env, &result); + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_value resultout = nullptr; + napi_value callback = nullptr; + napi_get_reference_value(env, unregisterPermStateChangeInfo->callbackRef, &callback); + results[PARAM0] = result; + NAPI_CALL_RETURN_VOID(env, + napi_call_function(env, undefined, callback, ARGS_SIZE_ONE, &results[PARAM0], &resultout)); + } + if (unregisterPermStateChangeInfo->callbackRef != nullptr) { + napi_delete_reference(env, unregisterPermStateChangeInfo->callbackRef); + } + napi_delete_async_work(env, unregisterPermStateChangeInfo->work); + { + std::vector tokenIDs = unregisterPermStateChangeInfo->scopeInfo.tokenIDs; + std::vector permList = unregisterPermStateChangeInfo->scopeInfo.permList; + std::sort(tokenIDs.begin(), tokenIDs.end()); + std::sort(permList.begin(), permList.end()); + std::lock_guard lock(g_lockForPermStateChangeRegisters); + auto subscribers = g_PermStateChangeRegisters.find(unregisterPermStateChangeInfo->accessTokenKit); + if (subscribers != g_PermStateChangeRegisters.end()) { + auto it = subscribers->second.begin(); + while (it != subscribers->second.end()) { + if (CompareScopeInfo((*it)->scopeInfo, tokenIDs, permList)) { + napi_delete_reference(env, (*it)->callbackRef); + ACCESSTOKEN_LOG_DEBUG(LABEL, "Find subscribers in map, tokenId = %{public}d", + (*it)->scopeInfo.tokenIDs[0]); + it = subscribers->second.erase(it); + break; + } else { + ++it; + } + } + if (subscribers->second.empty()) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "No subscriberInfo in the vector, erase the map."); + g_PermStateChangeRegisters.erase(subscribers); + } + } + } + delete unregisterPermStateChangeInfo; + unregisterPermStateChangeInfo = nullptr; +} + +napi_value NapiAtManager::UnregisterPermStateChangeCallback(napi_env env, napi_callback_info cbInfo) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "UnregisterPermStateChangeCallback begin."); + size_t argc = ARGS_SIZE_FOUR; + napi_value argv[ARGS_SIZE_FOUR] = {nullptr}; + napi_value thisVar = nullptr; + napi_ref callback = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, NULL)); + std::string type; + std::vector tokenIDs; + std::vector permList; + ParseInputToUnregister(env, argc, argv, type, callback, tokenIDs, permList); + + UnregisterPermStateChangeInfo *unregisterPermStateChangeInfo = + new (std::nothrow) UnregisterPermStateChangeInfo(); + if (unregisterPermStateChangeInfo == nullptr) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "insufficient memory for subscribeCBInfo!"); + return WrapVoidToJS(env); + } + AccessTokenKit *accessTokenKitInfo = nullptr; + napi_unwrap(env, thisVar, reinterpret_cast(&accessTokenKitInfo)); + unregisterPermStateChangeInfo->accessTokenKit = accessTokenKitInfo; + unregisterPermStateChangeInfo->callbackRef = callback; + unregisterPermStateChangeInfo->permStateChangeType = type; + unregisterPermStateChangeInfo->argc = argc; + PermStateChangeScope scopeInfo; + scopeInfo.tokenIDs = tokenIDs; + scopeInfo.permList = permList; + unregisterPermStateChangeInfo->scopeInfo = scopeInfo; + bool isFind = false; + std::shared_ptr subscriber; + FindRegisterInMap(subscriber, unregisterPermStateChangeInfo, isFind); + if (!isFind) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "Unsubscribe failed. The current subscriber does not exist"); + return WrapVoidToJS(env); + } + ACCESSTOKEN_LOG_DEBUG(LABEL, "The current subscriber exist"); + unregisterPermStateChangeInfo->subscriber = subscriber; + napi_value resource = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, "RegisterPermStateChangeCallback", NAPI_AUTO_LENGTH, &resource)); + NAPI_CALL(env, napi_create_async_work(env, + nullptr, + resource, + UnregisterPermStateChangeExcuteCB, + UnregisterPermStateChangeCompletedCB, + reinterpret_cast(unregisterPermStateChangeInfo), + &(unregisterPermStateChangeInfo->work))); + napi_queue_async_work(env, unregisterPermStateChangeInfo->work); + return WrapVoidToJS(env); +} + +void NapiAtManager::FindRegisterInMap(std::shared_ptr &subscriber, + UnregisterPermStateChangeInfo *unregisterPermStateChangeInfo, bool &isFind) +{ + ACCESSTOKEN_LOG_DEBUG(LABEL, "FindRegisterInMap begin."); + std::lock_guard lock(g_lockForPermStateChangeRegisters); + std::vector tokenIDs = unregisterPermStateChangeInfo->scopeInfo.tokenIDs; + std::vector permList = unregisterPermStateChangeInfo->scopeInfo.permList; + std::sort(tokenIDs.begin(), tokenIDs.end()); + std::sort(permList.begin(), permList.end()); + for (auto registerInstance : g_PermStateChangeRegisters) { + if (registerInstance.first == unregisterPermStateChangeInfo->accessTokenKit) { + for (auto item : registerInstance.second) { + PermStateChangeScope scopeInfo; + item->subscriber->GetScope(scopeInfo); + if (CompareScopeInfo(scopeInfo, tokenIDs, permList)) { + ACCESSTOKEN_LOG_DEBUG(LABEL, "find subscriber in map"); + subscriber = item->subscriber; + isFind = true; + break; + } + } + } + } +} } // namespace AccessToken } // namespace Security } // namespace OHOS