From 89f9e00c2e418b31561539c93ab82e4092c7b4b3 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Sat, 14 Jun 2025 15:48:33 +0800 Subject: [PATCH] ON/OFF_RegisterPermState_0614 Signed-off-by: zhangzezhong --- .../ets/@ohos.abilityAccessCtrl.ets | 50 +- .../include/ani_ability_access_ctrl.h | 36 ++ .../src/ani_ability_access_ctrl.cpp | 486 ++++++++++++++++++ frameworks/ets/ani/common/include/ani_utils.h | 3 + frameworks/ets/ani/common/src/ani_utils.cpp | 38 ++ 5 files changed, 612 insertions(+), 1 deletion(-) diff --git a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets index b8c11cbb6..28c54e01d 100644 --- a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets +++ b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets @@ -72,6 +72,13 @@ export default namespace abilityAccessCtrl { STS_ERROR_PARAM_ILLEGAL = 401, STS_ERROR_SYSTEM_CAPABILITY_NOT_SUPPORT = 801, } ; + + class PermissionStateChangeInfoInner implements PermissionStateChangeInfo { + change: PermissionStateChangeType; + tokenID: int; + permissionName: Permissions; + } + function validateRequestParams(context: Context, permissionList: Array): void { if (typeof context === "undefined" || context == null) { let err = new BusinessError(); @@ -142,6 +149,24 @@ export default namespace abilityAccessCtrl { permissionName: Permissions, status: PermissionRequestToggleStatus): Promise; getPermissionRequestToggleStatus(permissionName: Permissions): Promise; + + on(type: 'selfPermissionStateChange', permissionList: Array, + callback: Callback): void; + + on(type: 'permissionStateChange', tokenIDList: Array, permissionList: Array, + callback: Callback): void; + + off(type: 'selfPermissionStateChange', permissionList: Array, + callback?: Callback): void; + + off(type: 'permissionStateChange', tokenIDList: Array, permissionList: Array, + callback: Callback): void; + + onExcute(type: string, tokenIDList: Array, permissionList: Array, + callback: Callback): void; + + offExcute(type: string, tokenIDList: Array, permissionList: Array, + callback?: Callback): void; } class AtManagerInner implements AtManager { @@ -158,7 +183,10 @@ export default namespace abilityAccessCtrl { native getPermissionFlagsExecute(tokenID: int, permissionName: Permissions): int; native setPermissionRequestToggleStatusExecute(permissionName: Permissions, status: int): void; native getPermissionRequestToggleStatusExecute(permissionName: Permissions): int; - + native onExcute(type: string, tokenIDList: Array, permissionList: Array, + callback: Callback): void; + native offExcute(type: string, tokenIDList: Array, permissionList: Array, + callback?: Callback): void; verifyAccessTokenSync(tokenID: int, permissionName: Permissions): GrantStatus { let result = this.checkAccessTokenExecute(tokenID, permissionName); return result as GrantStatus; @@ -399,5 +427,25 @@ export default namespace abilityAccessCtrl { }); return p; } + + function on(type: 'selfPermissionStateChange', permissionList: Array, + callback: Callback): void{ + new AtManagerInner().onExcute('selfPermissionStateChange', [], permissionList, callback); + } + + function on(type: 'permissionStateChange', tokenIDList: Array, permissionList: Array, + callback: Callback): void{ + new AtManagerInner().onExcute('permissionStateChange', tokenIDList, permissionList, callback); + } + + function off(type: 'selfPermissionStateChange', permissionList: Array, + callback?: Callback): void{ + new AtManagerInner().offExcute('selfPermissionStateChange', [], permissionList, callback); + } + + function off(type: 'permissionStateChange', tokenIDList: Array, permissionList: Array, + callback?: Callback): void{ + new AtManagerInner().offExcute('permissionStateChange', tokenIDList, permissionList, callback); + } } } diff --git a/frameworks/ets/ani/accesstoken/include/ani_ability_access_ctrl.h b/frameworks/ets/ani/accesstoken/include/ani_ability_access_ctrl.h index e3ac10ad3..e1ebb34dd 100644 --- a/frameworks/ets/ani/accesstoken/include/ani_ability_access_ctrl.h +++ b/frameworks/ets/ani/accesstoken/include/ani_ability_access_ctrl.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "ability.h" #include "ability_manager_client.h" @@ -27,6 +28,7 @@ #include "ani.h" #include "ani_error.h" #include "permission_grant_info.h" +#include "perm_state_change_callback_customize.h" #include "token_callback_stub.h" #include "ui_content.h" #include "ui_extension_context.h" @@ -196,6 +198,40 @@ struct PermissonOnSettingResultCallback { std::shared_ptr data = nullptr; }; +class RegisterPermStateChangeScopePtr : public std::enable_shared_from_this, + public PermStateChangeCallbackCustomize { +public: + explicit RegisterPermStateChangeScopePtr(const PermStateChangeScope& subscribeInfo); + ~RegisterPermStateChangeScopePtr() override; + void PermStateChangeCallback(PermStateChangeInfo& result) override; + void SetCallbackRef(const ani_ref& ref); + void SetValid(bool valid); + void SetEnv(ani_env* env); + + void SetVm(ani_vm* vm); + void SetThreadId(const std::thread::id threadId); +private: + bool valid_ = true; + std::mutex validMutex_; + ani_env* env_ = nullptr; + + ani_vm* vm_ = nullptr; + std::thread::id threadId_; + ani_ref ref_ = nullptr; +}; + +struct RegisterPermStateChangeInf { + ani_env* env = nullptr; + ani_ref callbackRef = nullptr; + int32_t errCode = RET_SUCCESS; + std::string permStateChangeType; + std::thread::id threadId; + std::shared_ptr subscriber = nullptr; + std::vector permissionList; + std::vector tokenIdList; + PermStateChangeScope scopeInfo; +}; + std::map>> RequestAsyncInstanceControl::instanceIdMap_; std::mutex RequestAsyncInstanceControl::instanceIdMutex_; } // namespace AccessToken diff --git a/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp b/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp index a933ddda4..f952824b2 100644 --- a/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp +++ b/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp @@ -35,6 +35,11 @@ namespace OHOS { namespace Security { namespace AccessToken { +constexpr const char* PERM_STATE_CHANGE_FIELD_TOKEN_ID = "tokenID"; +constexpr const char* PERM_STATE_CHANGE_FIELD_PERMISSION_NAME = "permissionName"; +constexpr const char* PERM_STATE_CHANGE_FIELD_CHANGE = "change"; +std::mutex g_lockForPermStateChangeRegisters; +std::vector g_permStateChangeRegisters; std::mutex g_lockFlag; std::mutex g_lockWindowFlag; bool g_windowFlag = false; @@ -69,7 +74,176 @@ const std::string PERMISSION_RESULT_KEY = "ohos.user.setting.permission.result"; #define SETTER_METHOD_NAME(property) "" #property #define ANI_AUTO_SIZE SIZE_MAX +static const char* REGISTER_PERMISSION_STATE_CHANGE_TYPE = "permissionStateChange"; +static const char* REGISTER_SELF_PERMISSION_STATE_CHANGE_TYPE = "selfPermissionStateChange"; +RegisterPermStateChangeScopePtr::RegisterPermStateChangeScopePtr(const PermStateChangeScope& subscribeInfo) + : PermStateChangeCallbackCustomize(subscribeInfo) +{} + +RegisterPermStateChangeScopePtr::~RegisterPermStateChangeScopePtr() +{ + if (vm_ == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "vm is nullptr;"); + return; + } + + bool isSameThread = (threadId_ == std::this_thread::get_id()); + ani_env* env; + if (isSameThread) { + env = env_; + } else { + ani_option interopEnabled {"--interop=disable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + } + + if (ref_ != nullptr) { + env->GlobalReference_Delete(ref_); + ref_ = nullptr; + } + + if (!isSameThread) { + vm_->DetachCurrentThread(); + } +} + +void RegisterPermStateChangeScopePtr::SetEnv(ani_env* env) +{ + env_ = env; +} + +void RegisterPermStateChangeScopePtr::SetCallbackRef(const ani_ref& ref) +{ + ref_ = ref; +} + +void RegisterPermStateChangeScopePtr::SetValid(bool valid) +{ + std::lock_guard lock(validMutex_); + valid_ = valid; +} + +void RegisterPermStateChangeScopePtr::SetVm(ani_vm* vm) +{ + vm_ = vm; +} + +void RegisterPermStateChangeScopePtr::SetThreadId(const std::thread::id threadId) +{ + threadId_ = threadId; +} + + +static bool GenerateAniClassAndObject(ani_env* env, ani_class& aniClass, ani_object& aniObject) +{ + const char* classDescriptor = "L@ohos/abilityAccessCtrl/abilityAccessCtrl/PermissionStateChangeInfoInner;"; + if (!AniFindClass(env, classDescriptor, aniClass)) { + return false; + } + + const char* methodDescriptor = ""; + const char* signature = nullptr; + if (!AniNewClassObject(env, aniClass, methodDescriptor, signature, aniObject)) { + return false; + } + + return true; +} + + +static bool SetStringProperty(ani_env* env, ani_object& aniObject, const char* propertyName, const std::string in) +{ + ani_string aniString; + if (!AniNewString(env, in, aniString)) { + return false; + } + + if (!AniObjectSetPropertyByNameRef(env, aniObject, propertyName, aniString)) { + return false; + } + + return true; +} + +static bool SetEnumProperty(ani_env* env, ani_object& aniObject, const char* enumDescription, const char* propertyName, + ani_size index) +{ + ani_enum_item aniEnumItem; + if (!AniNewEnumIteam(env, enumDescription, index, aniEnumItem)) { + return false; + } + + if (!AniObjectSetPropertyByNameRef(env, aniObject, propertyName, aniEnumItem)) { + return false; + } + + return true; +} + + +static void ConvertPermStateChangeInfo(ani_env* env, const PermStateChangeInfo& result, ani_object& aniObject) +{ + // class implements from interface should use property, independent class use field + ani_class aniClass; + if (!GenerateAniClassAndObject(env, aniClass, aniObject)) { + return; + } + + // set tokenID: int + if (!AniObjectSetPropertyByNameInt(env, aniObject, PERM_STATE_CHANGE_FIELD_TOKEN_ID, + static_cast(result.tokenID))) { + return; + } + + // set permissionName: string + if (!SetStringProperty(env, aniObject, PERM_STATE_CHANGE_FIELD_PERMISSION_NAME, result.permissionName)) { + return; + } + + // set activeStatus: PermissionActiveStatus + ani_size index = result.permStateChangeType; + const char* activeStatusDes = "L@ohos/abilityAccessCtrl/abilityAccessCtrl/PermissionStateChangeType;"; + if (!SetEnumProperty(env, aniObject, activeStatusDes, PERM_STATE_CHANGE_FIELD_CHANGE, index)) { + return; + } + +} + +void RegisterPermStateChangeScopePtr::PermStateChangeCallback(PermStateChangeInfo& PermStateChangeInfo) +{ + if (vm_ == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "vm is nullptr;"); + return; + } + + ani_option interopEnabled {"--interop=disable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + ani_env* env; + if (vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "AttachCurrentThread failed!"); + return; + } + ani_fn_object fnObj = reinterpret_cast(ref_); + if (fnObj == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Reinterpret_cast failed!"); + return; + } + + ani_object aniObject; + ConvertPermStateChangeInfo(env, PermStateChangeInfo, aniObject); + + std::vector args; + args.emplace_back(aniObject); + ani_ref result; + if (!AniFunctionalObjectCall(env, fnObj, args.size(), args.data(), result)) { + return; + } + if (vm_->DetachCurrentThread() != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "DetachCurrentThread failed!"); + return; + } +} static void UpdateGrantPermissionResultOnly(const std::vector& permissions, const std::vector& grantResults, std::shared_ptr& data, std::vector& newGrantResults) { @@ -1514,6 +1688,316 @@ static ani_int GetPermissionRequestToggleStatusExecute([[maybe_unused]] ani_env* return flag; } +static bool ParseInputToRegister(const ani_string& aniType, const ani_array_ref& aniId, const ani_array_ref& aniArray, + const ani_ref& aniCallback, RegisterPermStateChangeInf* context, bool isReg) +{ + std::string type; + if (!AniParseString(context->env, aniType, type)) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg("type", "string")); + return false; + } + if ((type != REGISTER_SELF_PERMISSION_STATE_CHANGE_TYPE) && (type != REGISTER_PERMISSION_STATE_CHANGE_TYPE)) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg("type", "string")); + return false; + } + + context->permStateChangeType = type; + context->threadId = std::this_thread::get_id(); + + PermStateChangeScope scopeInfo; + std::string errMsg; + if (type == REGISTER_PERMISSION_STATE_CHANGE_TYPE) { + if(!AniParseAccessTokenIDArray(context->env, aniId, scopeInfo.tokenIDs)) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg("tokenIDList", "Array")); + return false; + } + }else if (type == REGISTER_SELF_PERMISSION_STATE_CHANGE_TYPE) { + scopeInfo.tokenIDs = {GetSelfTokenID()}; + } + if (!AniParseStringArray(context->env, aniArray, scopeInfo.permList)) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg("permissionNameList", "Array")); + return false; + } + + bool hasCallback = true; + if (!isReg) { + bool isUndefined = true; + if (!AniIsRefUndefined(context->env, aniCallback, isUndefined)) { + BusinessErrorAni::ThrowError( + context->env, STS_ERROR_PARAM_INVALID, GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); + return false; + } + hasCallback = !isUndefined; + } + + ani_ref callback = nullptr; + if (hasCallback) { + if (!AniParseCallback(context->env, aniCallback, callback)) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg( + "callback", "Callback")); + return false; + } + } + + ani_vm* vm; + if (context->env->GetVM(&vm) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetVM failed!"); + return false; + } + std::sort(scopeInfo.tokenIDs.begin(), scopeInfo.tokenIDs.end()); + std::sort(scopeInfo.permList.begin(), scopeInfo.permList.end()); + context->callbackRef = callback; + context->scopeInfo.tokenIDs = scopeInfo.tokenIDs; + context->scopeInfo.permList = scopeInfo.permList; + context->subscriber = std::make_shared(scopeInfo); + context->subscriber->SetVm(vm); + context->subscriber->SetEnv(context->env); + context->subscriber->SetCallbackRef(callback); + std::shared_ptr *subscriber = + new (std::nothrow) std::shared_ptr( + context->subscriber); + if (subscriber == nullptr) { + return false; + } + return true; + +} + +static bool IsExistRegister(const RegisterPermStateChangeInf* context) +{ + PermStateChangeScope targetScopeInfo; + context->subscriber->GetScope(targetScopeInfo); + std::vector targetTokenIDs = targetScopeInfo.tokenIDs; + std::vector targetPermList = targetScopeInfo.permList; + std::lock_guard lock(g_lockForPermStateChangeRegisters); + + for (const auto& item : g_permStateChangeRegisters) { + PermStateChangeScope scopeInfo; + item->subscriber->GetScope(scopeInfo); + + bool hasPermIntersection = false; + // Special cases: + // 1.Have registered full, and then register some + // 2.Have registered some, then register full + if (scopeInfo.permList.empty() || targetPermList.empty()) { + hasPermIntersection = true; + } + for (const auto& PermItem : targetPermList) { + if (hasPermIntersection) { + break; + } + auto iter = std::find(scopeInfo.permList.begin(), scopeInfo.permList.end(), PermItem); + if (iter != scopeInfo.permList.end()) { + hasPermIntersection = true; + } + } + + bool hasTokenIdIntersection = false; + + if (scopeInfo.tokenIDs.empty() || targetTokenIDs.empty()) { + hasTokenIdIntersection = true; + } + for (const auto& tokenItem : targetTokenIDs) { + if (hasTokenIdIntersection) { + break; + } + auto iter = std::find(scopeInfo.tokenIDs.begin(), scopeInfo.tokenIDs.end(), tokenItem); + if (iter != scopeInfo.tokenIDs.end()) { + hasTokenIdIntersection = true; + } + } + bool isEqual = true; + if (!AniIsCallbackRefEqual(context->env, item->callbackRef, context->callbackRef, item->threadId, isEqual)) { + return true; + } + if (hasPermIntersection && hasTokenIdIntersection && isEqual) { + return true; + } + } + return false; +} + +static void RegisterPermStateChangeCallback([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_string aniType, ani_array_ref aniId, ani_array_ref aniArray, ani_ref callback) +{ + if (env == nullptr) { + BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, GetErrorMessage(STSErrorCode::STS_ERROR_INNER)); + return; + } + + RegisterPermStateChangeInf* registerPermStateChangeInf = new (std::nothrow) RegisterPermStateChangeInf(); + if (registerPermStateChangeInf == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to allocate memory for RegisterPermStateChangeInf!"); + BusinessErrorAni::ThrowError(env, STS_ERROR_OUT_OF_MEMORY, GetErrorMessage( + STSErrorCode::STS_ERROR_OUT_OF_MEMORY)); + return; + } + registerPermStateChangeInf->env = env; + std::unique_ptr callbackPtr {registerPermStateChangeInf}; + if (!ParseInputToRegister(aniType, aniId, aniArray, callback, registerPermStateChangeInf, true)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ParseInputToRegister false."); + return; + } + + if (IsExistRegister(registerPermStateChangeInf)) { + ACCESSTOKEN_LOG_ERROR(LABEL, + "Subscribe failed. The current subscriber has existed or Reference_StrictEquals failed!"); + if ( registerPermStateChangeInf->permStateChangeType == REGISTER_SELF_PERMISSION_STATE_CHANGE_TYPE) { + BusinessErrorAni::ThrowError( + env, STSErrorCode::STS_ERROR_NOT_USE_TOGETHER, GetErrorMessage(STSErrorCode::STS_ERROR_NOT_USE_TOGETHER)); + } else { + BusinessErrorAni::ThrowError( + env, STSErrorCode::STS_ERROR_NOT_USE_TOGETHER, GetErrorMessage(STSErrorCode::STS_ERROR_NOT_USE_TOGETHER)); + } + return; + } + + int32_t result; + if (registerPermStateChangeInf->permStateChangeType == REGISTER_PERMISSION_STATE_CHANGE_TYPE) { + result = AccessTokenKit::RegisterPermStateChangeCallback(registerPermStateChangeInf->subscriber); + } else { + result = AccessTokenKit::RegisterSelfPermStateChangeCallback(registerPermStateChangeInf->subscriber); + } + if (result != RET_SUCCESS) { + ACCESSTOKEN_LOG_ERROR(LABEL, "RegisterPermStateChangeCallback failed"); + int32_t stsCode = BusinessErrorAni::GetStsErrorCode(result); + BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); + return; + } + + { + std::lock_guard lock(g_lockForPermStateChangeRegisters); + g_permStateChangeRegisters.emplace_back(registerPermStateChangeInf); + ACCESSTOKEN_LOG_ERROR(LABEL, "Add g_PermStateChangeRegisters.size = %{public}zu",g_permStateChangeRegisters.size()); + } + callbackPtr.release(); + return; +} + +static bool IsRefUndefined(ani_env* env, const ani_ref& ref) +{ + bool isUndef = false; + if (!AniIsRefUndefined(env, ref, isUndef)) { + return false; + } + return isUndef; +} + +static bool FindAndGetSubscriberInVector(RegisterPermStateChangeInf* unregisterPermStateChangeInf, + std::vector& batchPermStateChangeRegisters) +{ + ACCESSTOKEN_LOG_ERROR(LABEL, "FindAndGetSubscriberInVector In."); + std::lock_guard lock(g_lockForPermStateChangeRegisters); + std::vector targetTokenIDs = unregisterPermStateChangeInf->scopeInfo.tokenIDs; + std::vector targetPermList = unregisterPermStateChangeInf->scopeInfo.permList; + bool callbackEqual; + ani_ref callbackRef = unregisterPermStateChangeInf->callbackRef; + bool isUndef = IsRefUndefined(unregisterPermStateChangeInf->env, unregisterPermStateChangeInf->callbackRef); + + for (const auto& item : g_permStateChangeRegisters) { + if (isUndef) { + // batch delete currentThread callback + ACCESSTOKEN_LOG_INFO(LABEL, "Callback is nullptr."); + callbackEqual = IsCurrentThread(item->threadId); + } else { + ACCESSTOKEN_LOG_INFO(LABEL, "Compare callback."); + if (!AniIsCallbackRefEqual(unregisterPermStateChangeInf->env, callbackRef, unregisterPermStateChangeInf->callbackRef, + item->threadId, callbackEqual)) { + continue; + } + } + + PermStateChangeScope scopeInfo; + item->subscriber->GetScope(scopeInfo); + if (scopeInfo.tokenIDs == targetTokenIDs && scopeInfo.permList == targetPermList) { + unregisterPermStateChangeInf->subscriber = item->subscriber; + batchPermStateChangeRegisters.emplace_back(item); + } + } + if (!batchPermStateChangeRegisters.empty()) { + return true; + } + return false; +} + +static void DeleteRegisterFromVector(const RegisterPermStateChangeInf* context) +{ + std::vector targetTokenIDs = context->scopeInfo.tokenIDs; + std::vector targetPermList = context->scopeInfo.permList; + std::lock_guard lock(g_lockForPermStateChangeRegisters); + bool callbackEqual; + auto item = g_permStateChangeRegisters.begin(); + while (item != g_permStateChangeRegisters.end()) { + PermStateChangeScope stateChangeScope; + (*item)->subscriber->GetScope(stateChangeScope); + if ((stateChangeScope.tokenIDs == targetTokenIDs) && (stateChangeScope.permList == targetPermList) && + AniIsCallbackRefEqual(context->env, (*item)->callbackRef, context->callbackRef, (*item)->threadId, callbackEqual)) { + delete *item; + *item = nullptr; + g_permStateChangeRegisters.erase(item); + break; + } else { + ++item; + } + } +} + +static void UnregisterPermStateChangeCallback([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_string aniType, ani_array_ref aniId, ani_array_ref aniArray, ani_ref callback) +{ + ACCESSTOKEN_LOG_ERROR(LABEL, "UnregisterPermStateChangeCallback In."); + if (env == nullptr) { + BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, GetErrorMessage(STSErrorCode::STS_ERROR_INNER)); + return; + } + + RegisterPermStateChangeInf* context = new (std::nothrow) RegisterPermStateChangeInf(); + if (context == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to allocate memory for UnRegisterPermStateChangeInf!"); + BusinessErrorAni::ThrowError(env, STS_ERROR_OUT_OF_MEMORY, GetErrorMessage( + STSErrorCode::STS_ERROR_OUT_OF_MEMORY)); + return; + } + context->env = env; + std::unique_ptr callbackPtr {context}; + + if (!ParseInputToRegister(aniType, aniId, aniArray, callback, context, false)) { + return; + } + + std::vector batchPermStateChangeRegisters; + if (!FindAndGetSubscriberInVector(context, batchPermStateChangeRegisters)) { + ACCESSTOKEN_LOG_ERROR(LABEL, + "Unsubscribe failed. The current subscriber does not exist or Reference_StrictEquals failed!"); + if ( context->permStateChangeType == REGISTER_SELF_PERMISSION_STATE_CHANGE_TYPE) { + BusinessErrorAni::ThrowError( + env, STSErrorCode::STS_ERROR_NOT_USE_TOGETHER, GetErrorMessage(STSErrorCode::STS_ERROR_NOT_USE_TOGETHER)); + } else { + BusinessErrorAni::ThrowError( + env, STSErrorCode::STS_ERROR_PARAM_INVALID, GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); + } + return; + } + for (const auto& item : batchPermStateChangeRegisters) { + PermStateChangeScope scopeInfo; + item->subscriber->GetScope(scopeInfo); + int32_t result; + if (context->permStateChangeType == REGISTER_PERMISSION_STATE_CHANGE_TYPE) { + result = AccessTokenKit::UnRegisterPermStateChangeCallback(item->subscriber); + } else { + result = AccessTokenKit::UnRegisterSelfPermStateChangeCallback(item->subscriber); + } + if (result == RET_SUCCESS) { + DeleteRegisterFromVector(item); + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "UnregisterPermStateChangeCallback failed"); + int32_t stsCode = BusinessErrorAni::GetStsErrorCode(result); + BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); + return; + } + } + return; +} void InitAbilityCtrlFunction(ani_env *env) { if (env == nullptr) { @@ -1561,6 +2045,8 @@ void InitAbilityCtrlFunction(ani_env *env) nullptr, reinterpret_cast(SetPermissionRequestToggleStatusExecute) }, ani_native_function{ "getPermissionRequestToggleStatusExecute", nullptr, reinterpret_cast(GetPermissionRequestToggleStatusExecute) }, + ani_native_function { "onExcute", nullptr, reinterpret_cast(RegisterPermStateChangeCallback) }, + ani_native_function { "offExcute", nullptr, reinterpret_cast(UnregisterPermStateChangeCallback) }, }; if (ANI_OK != env->Class_BindNativeMethods(cls, claMethods.data(), claMethods.size())) { ACCESSTOKEN_LOG_ERROR(LABEL, "Cannot bind native methods to %{public}s", className); diff --git a/frameworks/ets/ani/common/include/ani_utils.h b/frameworks/ets/ani/common/include/ani_utils.h index d487ef64c..4d7d89547 100644 --- a/frameworks/ets/ani/common/include/ani_utils.h +++ b/frameworks/ets/ani/common/include/ani_utils.h @@ -37,6 +37,9 @@ bool AniParseString(ani_env* env, const ani_string& ani_str, std::string& out); bool AniParseStringArray(ani_env* env, const ani_array_ref& ani_str_arr, std::vector& out); bool AniParseCallback(ani_env* env, const ani_ref& ani_callback, ani_ref& out); bool AniIsRefUndefined(ani_env* env, const ani_ref& ref); +bool AniIsRefUndefined(ani_env* env, const ani_ref& ref, bool& isUndefined); +bool AniParseUint32(ani_env* env, const ani_int& aniInt, uint32_t& out); +bool AniParseAccessTokenIDArray(ani_env* env, const ani_array_ref& array, std::vector& out); bool AniNewString(ani_env* env, const std::string in, ani_string& out); bool AniNewEnumIteam(ani_env* env, const char* enumDescriptor, ani_size index, ani_enum_item& out); diff --git a/frameworks/ets/ani/common/src/ani_utils.cpp b/frameworks/ets/ani/common/src/ani_utils.cpp index 0a6cf33d4..166f1eb62 100644 --- a/frameworks/ets/ani/common/src/ani_utils.cpp +++ b/frameworks/ets/ani/common/src/ani_utils.cpp @@ -78,6 +78,44 @@ bool AniGetEnumItemByIndex(ani_env* env, const ani_enum& aniEnum, ani_size index return true; } +bool AniParseUint32(ani_env* env, const ani_ref& aniInt, uint32_t& out) +{ + ani_int tmp; + ani_status status; + if ((status = env->Object_CallMethodByName_Int(static_cast(aniInt), "unboxed", nullptr, &tmp)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_CallMethodByName_Int failed! %{public}d" , status); + return false; + } + + out = static_cast(tmp); + return true; +} + +bool AniParseAccessTokenIDArray(ani_env* env, const ani_array_ref& array, std::vector& out) +{ + ani_size size; + if (env->Array_GetLength(array, &size) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Array_GetLength failed!"); + return false; + } + + for (ani_size i = 0; i < size; ++i) { + ani_ref elementRef; + if (env->Array_Get_Ref(array, i, &elementRef) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Array_Get_Ref failed at index %{public}zu!", i); + return false; + } + uint32_t value; + if (!AniParseUint32(env, elementRef, value)) { + return false; + } + if(value == 0) { + return false; + } + out.emplace_back(value); + } + return true; +} bool AniParseString(ani_env* env, const ani_string& ani_str, std::string& out) { -- Gitee