From b9f647715029f7725dcf6873eec7b3229b8654cb Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Wed, 25 Jun 2025 23:41:42 +0800 Subject: [PATCH] ON_OFF_0625 Signed-off-by: zhangzezhong --- .../ets/@ohos.abilityAccessCtrl.ets | 44 ++ .../ets/ani/accesstoken/include/ani_common.h | 1 - .../include/ani_request_permission.h | 34 ++ .../src/ani_ability_access_ctrl.cpp | 437 ++++++++++++++++++ .../ets/ani/accesstoken/src/ani_common.cpp | 16 - frameworks/ets/ani/common/include/ani_utils.h | 3 + frameworks/ets/ani/common/src/ani_utils.cpp | 56 +++ .../ets/ani/privacy/src/privacy_manager.cpp | 10 +- 8 files changed, 575 insertions(+), 26 deletions(-) diff --git a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets index c42ad5617..c1bf2f105 100644 --- a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets +++ b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets @@ -81,6 +81,12 @@ 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(); @@ -112,6 +118,11 @@ export default namespace abilityAccessCtrl { getPermissionFlagsExecute(tokenID: int, permissionName: Permissions): int; setPermissionRequestToggleStatusExecute(permissionName: Permissions, status: int): void; getPermissionRequestToggleStatusExecute(permissionName: Permissions): int; + RequestAppPermOnSettingExecute(tokenID: int): undefined; + onExcute(type: string, tokenIDList: Array, permissionList: Array, + callback: Callback): void; + offExcute(type: string, tokenIDList: Array, permissionList: Array, + callback?: Callback): void; requestAppPermOnSettingExecute(tokenID: int): void; checkAccessTokenSync(tokenID: int, permissionName: Permissions): GrantStatus; @@ -147,6 +158,14 @@ export default namespace abilityAccessCtrl { permissionName: Permissions, status: PermissionRequestToggleStatus): Promise; getPermissionRequestToggleStatus(permissionName: Permissions): Promise; requestPermissionOnApplicationSetting(tokenID: int): 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; } class AtManagerInner implements AtManager { @@ -165,6 +184,11 @@ export default namespace abilityAccessCtrl { native getPermissionFlagsExecute(tokenID: int, permissionName: Permissions): int; native setPermissionRequestToggleStatusExecute(permissionName: Permissions, status: int): void; native getPermissionRequestToggleStatusExecute(permissionName: Permissions): int; + native RequestAppPermOnSettingExecute(tokenID: int): undefined; + native onExcute(type: string, tokenIDList: Array, permissionList: Array, + callback: Callback): void; + native offExcute(type: string, tokenIDList: Array, permissionList: Array, + callback?: Callback): void; native requestAppPermOnSettingExecute(tokenID: int): void; verifyAccessTokenSync(tokenID: int, permissionName: Permissions): GrantStatus { @@ -429,5 +453,25 @@ export default namespace abilityAccessCtrl { }); return p; } + + on(type: 'selfPermissionStateChange', permissionList: Array, + callback: Callback): void { + new AtManagerInner().onExcute('selfPermissionStateChange', [], permissionList, callback); + } + + on(type: 'permissionStateChange', tokenIDList: Array, permissionList: Array, + callback: Callback): void { + new AtManagerInner().onExcute('permissionStateChange', tokenIDList, permissionList, callback); + } + + off(type: 'selfPermissionStateChange', permissionList: Array, + callback?: Callback): void { + new AtManagerInner().offExcute('selfPermissionStateChange', [], permissionList, callback); + } + + 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_common.h b/frameworks/ets/ani/accesstoken/include/ani_common.h index 0404544b1..61284c998 100644 --- a/frameworks/ets/ani/accesstoken/include/ani_common.h +++ b/frameworks/ets/ani/accesstoken/include/ani_common.h @@ -25,7 +25,6 @@ namespace OHOS { namespace Security { namespace AccessToken { -ani_env* GetCurrentEnv(ani_vm* vm); bool ExecuteAsyncCallback(ani_env* env, ani_object callback, ani_object error, ani_object result); OHOS::Ace::UIContent* GetUIContent(const std::shared_ptr& abilityContext, std::shared_ptr& uiExtensionContext, bool uiAbilityFlag); diff --git a/frameworks/ets/ani/accesstoken/include/ani_request_permission.h b/frameworks/ets/ani/accesstoken/include/ani_request_permission.h index 6b4cccf8c..cfcbfcf3a 100644 --- a/frameworks/ets/ani/accesstoken/include/ani_request_permission.h +++ b/frameworks/ets/ani/accesstoken/include/ani_request_permission.h @@ -15,6 +15,7 @@ #ifndef ANI_REQUEST_PERMISSION_H #define ANI_REQUEST_PERMISSION_H +#include #include #include "access_token.h" #include "ani.h" @@ -26,6 +27,7 @@ #include "event_queue.h" #endif #include "permission_grant_info.h" +#include "perm_state_change_callback_customize.h" #include "token_callback_stub.h" namespace OHOS { @@ -113,6 +115,38 @@ struct ResultCallback { void RequestPermissionsFromUserExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_object aniContext, ani_array_ref permissionList, ani_object callback); + +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; + PermStateChangeScope scopeInfo; +}; } // namespace AccessToken } // namespace Security } // namespace OHOS 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 f54d106cd..1d73ec51d 100644 --- a/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp +++ b/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp @@ -42,6 +42,136 @@ static PermissionParamCache g_paramCache; std::map g_cache; static constexpr const char* PERMISSION_STATUS_CHANGE_KEY = "accesstoken.permission.change"; } +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; +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 = isSameThread ? env_ : GetCurrentEnv(vm_); + + 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 SetStringProperty(ani_env* env, ani_object& aniObject, const char* propertyName, const std::string in) +{ + ani_string aniString = CreateAniString(env, in); + if (env->Object_SetPropertyByName_Ref(aniObject, propertyName, aniString) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_SetPropertyByName_Ref failed!"); + return false; + } + + return true; +} + +static void transPermStateChangeTypeToAniInt(const int32_t permStateChangeType, ani_size& index) +{ + index = static_cast(permStateChangeType); + return; +} + +static void ConvertPermStateChangeInfo(ani_env* env, const PermStateChangeInfo& result, ani_object& aniObject) +{ + // class implements from interface should use property, independent class use field + aniObject = CreateClassObject(env, "L@ohos/abilityAccessCtrl/abilityAccessCtrl/PermissionStateChangeInfoInner;"); + if (aniObject == nullptr) { + return; + } + + // set tokenId: int32_t + SetIntProperty(env, aniObject, PERM_STATE_CHANGE_FIELD_TOKEN_ID, static_cast(result.tokenID)); + + // set permissionName: Permissions + SetStringProperty(env, aniObject, PERM_STATE_CHANGE_FIELD_PERMISSION_NAME, result.permissionName); + + // set permStateChangeType: int32_t + ani_size index; + transPermStateChangeTypeToAniInt(result.permStateChangeType, index); + const char* activeStatusDes = "L@ohos/abilityAccessCtrl/abilityAccessCtrl/PermissionStateChangeType;"; + SetEnumProperty( + env, aniObject, activeStatusDes, PERM_STATE_CHANGE_FIELD_CHANGE, static_cast(index)); +} + +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 ani_object CreateAtManager([[maybe_unused]] ani_env* env) { @@ -375,6 +505,311 @@ static void RequestAppPermOnSettingExecute([[maybe_unused]] ani_env* env, } } +static bool SetupPermissionSubscriber( + RegisterPermStateChangeInf* context, const PermStateChangeScope& scopeInfo, const ani_ref& callback) +{ + ani_vm* vm; + if (context->env->GetVM(&vm) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetVM failed!"); + return false; + } + + auto sortedTokenIDs = scopeInfo.tokenIDs; + auto sortedPermList = scopeInfo.permList; + std::sort(sortedTokenIDs.begin(), sortedTokenIDs.end()); + std::sort(sortedPermList.begin(), sortedPermList.end()); + + context->callbackRef = callback; + context->scopeInfo.tokenIDs = sortedTokenIDs; + context->scopeInfo.permList = sortedPermList; + context->subscriber = std::make_shared(scopeInfo); + context->subscriber->SetVm(vm); + context->subscriber->SetEnv(context->env); + context->subscriber->SetCallbackRef(callback); + + return true; +} + +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 = ParseAniString(context->env, aniType); + if (type.empty()) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg( + "type", "permissionStateChange or selfPermissionStateChange")); + 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", "type is invalid")); + 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()}; + } + scopeInfo.permList = ParseAniStringVector(context->env, aniArray); + bool hasCallback = true; + if (!isReg) { + hasCallback = !(AniIsRefUndefined(context->env, aniCallback)); + } + + ani_ref callback = nullptr; + if (hasCallback) { + if (!AniParseCallback(context->env, aniCallback, callback)) { + BusinessErrorAni::ThrowError(context->env, STS_ERROR_PARAM_ILLEGAL, GetParamErrorMsg( + "callback", "Callback")); + return false; + } + } + + return SetupPermissionSubscriber(context, scopeInfo, callback); +} + +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!"); + 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_PARAM_INVALID, GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); + } + 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_INFO( + LABEL, "Add g_PermStateChangeRegisters.size = %{public}zu", g_permStateChangeRegisters.size()); + } + callbackPtr.release(); + return; +} + +static bool FindAndGetSubscriberInVector(RegisterPermStateChangeInf* unregisterPermStateChangeInf, + std::vector& batchPermStateChangeRegisters) +{ + ACCESSTOKEN_LOG_DEBUG(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 = AniIsRefUndefined(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); + auto item = g_permStateChangeRegisters.begin(); + while (item != g_permStateChangeRegisters.end()) { + PermStateChangeScope stateChangeScope; + (*item)->subscriber->GetScope(stateChangeScope); + bool callbackEqual = true; + if (!AniIsCallbackRefEqual( + context->env, (*item)->callbackRef, context->callbackRef, (*item)->threadId, callbackEqual)) { + continue; + } + if (!callbackEqual) { + continue; + } + + if ((stateChangeScope.tokenIDs == targetTokenIDs) && (stateChangeScope.permList == targetPermList)) { + 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_DEBUG(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!"); + 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) { @@ -421,6 +856,8 @@ void InitAbilityCtrlFunction(ani_env *env) nullptr, reinterpret_cast(GetPermissionRequestToggleStatusExecute) }, ani_native_function{ "requestAppPermOnSettingExecute", nullptr, reinterpret_cast(RequestAppPermOnSettingExecute) }, + 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/accesstoken/src/ani_common.cpp b/frameworks/ets/ani/accesstoken/src/ani_common.cpp index f2d67c948..33de4a56b 100644 --- a/frameworks/ets/ani/accesstoken/src/ani_common.cpp +++ b/frameworks/ets/ani/accesstoken/src/ani_common.cpp @@ -23,22 +23,6 @@ static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN constexpr const char* WRAPPER_CLASS_NAME = "L@ohos/abilityAccessCtrl/AsyncCallbackWrapper;"; constexpr const char* INVOKE_METHOD_NAME = "invoke"; } // namespace -ani_env* GetCurrentEnv(ani_vm* vm) -{ - if (vm == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Vm is nullptr."); - return nullptr; - } - ani_env* env = nullptr; - ani_option interopEnabled {"--interop=enable", nullptr}; - ani_options aniArgs {1, &interopEnabled}; - if (vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env) != ANI_OK) { - if (vm->GetEnv(ANI_VERSION_1, &env) != ANI_OK) { - return nullptr; - } - } - return env; -} bool ExecuteAsyncCallback(ani_env* env, ani_object callback, ani_object error, ani_object result) { diff --git a/frameworks/ets/ani/common/include/ani_utils.h b/frameworks/ets/ani/common/include/ani_utils.h index 0df6d144d..8c7b6222b 100644 --- a/frameworks/ets/ani/common/include/ani_utils.h +++ b/frameworks/ets/ani/common/include/ani_utils.h @@ -34,6 +34,8 @@ bool AniClassFindField(ani_env* env, const ani_class& aniClass, const std::strin bool AniParseCallback(ani_env* env, const ani_ref& ani_callback, ani_ref& out); bool AniIsRefUndefined(ani_env* env, const ani_ref& ref); +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 GetBoolProperty(ani_env* env, const ani_object& object, const std::string& property, bool& value); bool GetIntProperty(ani_env* env, const ani_object& object, const std::string& property, int32_t& value); @@ -72,6 +74,7 @@ ani_object CreateArrayObject(ani_env* env, uint32_t length); ani_ref CreateAniArrayBool(ani_env* env, const std::vector& cArray); ani_ref CreateAniArrayInt(ani_env* env, const std::vector& cArray); ani_ref CreateAniArrayString(ani_env* env, const std::vector& cArray); +ani_env* GetCurrentEnv(ani_vm* vm); // delete ref of GlobalReference_Create void DeleteReference(ani_env* env, ani_ref& ref); diff --git a/frameworks/ets/ani/common/src/ani_utils.cpp b/frameworks/ets/ani/common/src/ani_utils.cpp index 7e73acfb7..53842ea3a 100644 --- a/frameworks/ets/ani/common/src/ani_utils.cpp +++ b/frameworks/ets/ani/common/src/ani_utils.cpp @@ -61,6 +61,45 @@ bool AniClassFindField(ani_env* env, const ani_class& aniClass, const char *fiel 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; +} std::vector ParseAniStringVector(ani_env* env, const ani_array_ref& aniStrArr) { @@ -570,6 +609,23 @@ bool SetEnumProperty(ani_env* env, ani_object& aniObject, } return true; } + +ani_env* GetCurrentEnv(ani_vm* vm) +{ + if (vm == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Vm is nullptr."); + return nullptr; + } + ani_env* env = nullptr; + ani_option interopEnabled {"--interop=enable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + if (vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env) != ANI_OK) { + if (vm->GetEnv(ANI_VERSION_1, &env) != ANI_OK) { + return nullptr; + } + } + return env; +} } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/frameworks/ets/ani/privacy/src/privacy_manager.cpp b/frameworks/ets/ani/privacy/src/privacy_manager.cpp index 2aa9f3c80..9aadcd341 100644 --- a/frameworks/ets/ani/privacy/src/privacy_manager.cpp +++ b/frameworks/ets/ani/privacy/src/privacy_manager.cpp @@ -133,16 +133,8 @@ PermActiveStatusPtr::~PermActiveStatusPtr() 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=enable", nullptr}; - ani_options aniArgs {1, &interopEnabled}; - vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); - } + ani_env* env = isSameThread ? env_ : GetCurrentEnv(vm_); if (ref_ != nullptr) { env->GlobalReference_Delete(ref_); -- Gitee