From fca62efd30ee5f189081b5b2fe0466c309ea28fe Mon Sep 17 00:00:00 2001 From: xia-bubai Date: Mon, 14 Jul 2025 14:52:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96reqeustpermissionsfromuser=20?= =?UTF-8?q?and=20requestpermissionsOnSetting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: xia-bubai --- .../ets/@ohos.abilityAccessCtrl.ets | 112 ++- .../accesstoken/include/ability_access_ctrl.h | 65 +- .../accesstoken/src/ability_access_ctrl.cpp | 660 ++++++++++++------ frameworks/ets/ani/common/include/ani_error.h | 12 +- frameworks/ets/ani/common/include/ani_utils.h | 1 + frameworks/ets/ani/common/src/ani_error.cpp | 80 +-- frameworks/ets/ani/common/src/ani_utils.cpp | 17 + .../ani/privacy/ets/@ohos.privacyManager.ets | 4 +- 8 files changed, 574 insertions(+), 377 deletions(-) diff --git a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets index 575731294..91d48cc3d 100644 --- a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets +++ b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets @@ -27,6 +27,18 @@ export { Permissions }; export type PermissionRequestResult = _PermissionRequestResult; +class AsyncCallbackWrapper { + private wrapperCallback_: AsyncCallback = (err: BusinessError | null, data: T | undefined) => {} + + constructor(callback: AsyncCallback) { + this.wrapperCallback_ = callback; + } + + invoke(err: BusinessError, data: T) : void { + this.wrapperCallback_(err, data); + } +} + export default namespace abilityAccessCtrl { loadLibrary("accesstoken_ani.z"); @@ -128,9 +140,8 @@ export default namespace abilityAccessCtrl { verifyAccessTokenSync(tokenID: int, permissionName: Permissions): GrantStatus; - requestPermissionsFromUserExecute( - context: Context, - permissionList: Array):PermissionRequestResult; + requestPermissionsFromUserExecute(context: Context, permissionList: Array, + callback: AsyncCallbackWrapper): void; requestPermissionsFromUser( context: Context, @@ -142,9 +153,8 @@ export default namespace abilityAccessCtrl { context: Context, permissionList: Array): Promise; - requestPermissionOnSettingExecute( - context: Context, - permissionList: Array): Array; + requestPermissionOnSettingExecute(context: Context, + permissionList: Array, callback: AsyncCallbackWrapper>): void; requestPermissionOnSetting( context: Context, @@ -216,74 +226,60 @@ export default namespace abilityAccessCtrl { return p; } - native requestPermissionsFromUserExecute(context: Context, - permissionList: Array): PermissionRequestResult; + native requestPermissionsFromUserExecute(context: Context, permissionList: Array, + callback: AsyncCallbackWrapper): void; requestPermissionsFromUser(context: Context, permissionList: Array, - callback:AsyncCallback): void { + requestCallback: AsyncCallback): void { validateRequestParams(context, permissionList); - let fun = async() => { - try { - let work = new EAWorker(); - let job = work.run(() : PermissionRequestResult => { - return new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList); - }) - let result = job.Await(); - let retError = new BusinessError(); - callback(retError, result as PermissionRequestResult); - } catch (err: BusinessError) { - const defaultResult: PermissionRequestResult = {}; - callback(err, defaultResult); - } - }; - fun(); + let callbackWrap = new AsyncCallbackWrapper(requestCallback); + taskpool.execute((): void => { + new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList, callbackWrap); + }); } requestPermissionsFromUser(context: Context, permissionList: Array): Promise { validateRequestParams(context, permissionList); - - let p = new Promise((resolve: (v: PermissionRequestResult) => - void, reject: (error: BusinessError) => void) => { - let fun = async() => { - try { - let work = new EAWorker(); - let job = work.run((): PermissionRequestResult => { - return new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList); - }); - let result = job.Await(); - resolve(result as PermissionRequestResult); - } catch (err: BusinessError) { - reject(err); + let p: Promise = new Promise(( + resolve: (v: PermissionRequestResult) => void, reject: (error: BusinessError) => void) => { + let callbackWrap = new AsyncCallbackWrapper(( + err: BusinessError | null, data: PermissionRequestResult | undefined) => { + if (err?.code == 0) { + if (data !== undefined) { + resolve(data); + } + } else { + reject(err as BusinessError); } - }; - fun(); + }); + taskpool.execute((): void => { + new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList, callbackWrap); + }); }); return p; } - native requestPermissionOnSettingExecute( - context: Context, - permissionList: Array): Array; + native requestPermissionOnSettingExecute(context: Context, + permissionList: Array, callback: AsyncCallbackWrapper>): void; - requestPermissionOnSetting(context: Context, permissionList: Array): - Promise> { + requestPermissionOnSetting(context: Context, permissionList: Array): Promise> { validateRequestParams(context, permissionList); - let p = new Promise>((resolve: (v: Array) => - void, reject: (error: BusinessError) => void) => { - let func = async() => { - try { - let work = new EAWorker(); - let job = work.run>((): Array => { - return new AtManagerInner().requestPermissionOnSettingExecute(context, permissionList); - }); - let result = job.Await(); - resolve(result as Array); - } catch (err: BusinessError) { - reject(err); + let p: Promise> = new Promise>(( + resolve: (v: Array) => void, reject: (error: BusinessError) => void) => { + let callbackWrap = new AsyncCallbackWrapper>(( + err: BusinessError | null, data: Array | undefined) => { + if (err?.code == 0) { + if (data !== undefined) { + resolve(data); + } + } else { + reject(err as BusinessError); } - }; - func(); + }); + taskpool.execute((): void => { + new AtManagerInner().requestPermissionOnSettingExecute(context, permissionList, callbackWrap); + }); }); return p; } diff --git a/frameworks/ets/ani/accesstoken/include/ability_access_ctrl.h b/frameworks/ets/ani/accesstoken/include/ability_access_ctrl.h index a59e24264..0fbdb4189 100644 --- a/frameworks/ets/ani/accesstoken/include/ability_access_ctrl.h +++ b/frameworks/ets/ani/accesstoken/include/ability_access_ctrl.h @@ -81,29 +81,33 @@ static PermissionParamCache g_paramCache; std::map g_cache; struct RequestAsyncContext { + virtual ~RequestAsyncContext(); AccessTokenID tokenId = 0; std::string bundleName; bool needDynamicRequest = true; - int32_t result = RET_SUCCESS; + AtmResult result; int32_t instanceId = -1; std::vector permissionList; std::vector grantResults; std::vector permissionsState; - ani_object requestResult = nullptr; std::vector dialogShownResults; std::vector permissionQueryResults; std::vector errorReasons; Security::AccessToken::PermissionGrantInfo info; - std::shared_ptr abilityContext; - std::shared_ptr uiExtensionContext; + std::shared_ptr abilityContext = nullptr; + std::shared_ptr uiExtensionContext = nullptr; bool uiAbilityFlag = false; bool uiExtensionFlag = false; bool uiContentFlag = false; bool releaseFlag = false; - std::mutex loadlock; #ifdef EVENTHANDLER_ENABLE std::shared_ptr handler_ = nullptr; #endif + std::thread::id threadId; + ani_vm* vm = nullptr; + ani_env* env = nullptr; + ani_object callback = nullptr; + ani_ref callbackRef = nullptr; }; class UIExtensionCallback { @@ -139,7 +143,7 @@ private: class RequestAsyncInstanceControl { public: - static bool AddCallbackByInstanceId(std::shared_ptr& asyncContext); + static void AddCallbackByInstanceId(std::shared_ptr& asyncContext); static void ExecCallback(int32_t id); static void CheckDynamicRequest(std::shared_ptr& asyncContext, bool& isDynamic); @@ -156,31 +160,49 @@ struct ResultCallback { }; struct RequestPermOnSettingAsyncContext { + virtual ~RequestPermOnSettingAsyncContext(); AccessTokenID tokenId = 0; - int32_t result = RET_SUCCESS; + AtmResult result; PermissionGrantInfo info; - int32_t resultCode = -1; + int32_t instanceId = -1; + bool isDynamic = true; std::vector permissionList; - napi_value requestResult = nullptr; - int32_t errorCode = -1; + ani_object requestResult = nullptr; std::vector stateList; - std::shared_ptr abilityContext; - std::shared_ptr uiExtensionContext; + std::shared_ptr abilityContext = nullptr; + std::shared_ptr uiExtensionContext = nullptr; bool uiAbilityFlag = false; - std::mutex loadlock; + bool releaseFlag = false; + std::mutex lockReleaseFlag; #ifdef EVENTHANDLER_ENABLE std::shared_ptr handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); #endif + std::thread::id threadId; + ani_vm* vm = nullptr; + ani_env* env = nullptr; + ani_object callback = nullptr; + ani_ref callbackRef = nullptr; +}; + +class RequestOnSettingAsyncInstanceControl { + public: + static void AddCallbackByInstanceId(std::shared_ptr& asyncContext); + static void ExecCallback(int32_t id); + static void CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic); + static void UpdateQueueData(const std::shared_ptr& asyncContext); + private: + static std::map>> instanceIdMap_; + static std::mutex instanceIdMutex_; }; class PermissonOnSettingUICallback { public: - explicit PermissonOnSettingUICallback(ani_env* env, - const std::shared_ptr& reqContext); + explicit PermissonOnSettingUICallback(const std::shared_ptr& reqContext); ~PermissonOnSettingUICallback(); void SetSessionId(int32_t sessionId); void ReleaseHandler(int32_t code); @@ -192,22 +214,9 @@ public: void OnDestroy(); private: - ani_env* env_; std::shared_ptr reqContext_ = nullptr; int32_t sessionId_ = 0; - - std::mutex lockReleaseFlag; - bool releaseFlag = false; }; - -struct PermissonOnSettingResultCallback { - int32_t jsCode; - std::vector stateList; - std::shared_ptr data = nullptr; -}; - -std::map>> RequestAsyncInstanceControl::instanceIdMap_; -std::mutex RequestAsyncInstanceControl::instanceIdMutex_; } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/frameworks/ets/ani/accesstoken/src/ability_access_ctrl.cpp b/frameworks/ets/ani/accesstoken/src/ability_access_ctrl.cpp index 73dba25bd..61373a01d 100644 --- a/frameworks/ets/ani/accesstoken/src/ability_access_ctrl.cpp +++ b/frameworks/ets/ani/accesstoken/src/ability_access_ctrl.cpp @@ -37,7 +37,6 @@ namespace Security { namespace AccessToken { std::mutex g_lockFlag; std::mutex g_lockWindowFlag; -bool g_windowFlag = false; static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AniAbilityAccessCtrl" }; constexpr int32_t MAX_LENGTH = 256; constexpr int32_t REQUEST_REALDY_EXIST = 1; @@ -62,9 +61,58 @@ const std::string WINDOW_RECTANGLE_WIDTH_KEY = "ohos.ability.params.request.widt const std::string REQUEST_TOKEN_KEY = "ohos.ability.params.request.token"; const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code"; const std::string PERMISSION_RESULT_KEY = "ohos.user.setting.permission.result"; +constexpr const char* WRAPPER_CLASS_NAME = "L@ohos/abilityAccessCtrl/AsyncCallbackWrapper;"; +constexpr const char* INVOKE_METHOD_NAME = "invoke"; #define SETTER_METHOD_NAME(property) "" #property +static bool ExecuteAsyncCallback(ani_env* env, ani_object callback, ani_object error, ani_object result) +{ + if (env == nullptr || callback == nullptr || error == nullptr || result == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Invalid paramter."); + return false; + } + ani_status status = ANI_ERROR; + ani_class clsCall {}; + + if ((status = env->FindClass(WRAPPER_CLASS_NAME, &clsCall)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass failed, error=%{public}d.", static_cast(status)); + return false; + } + ani_method method = {}; + if ((status = env->Class_FindMethod( + clsCall, INVOKE_METHOD_NAME, "L@ohos/base/BusinessError;Lstd/core/Object;:V", &method)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Class_FindMethod failed, error=%{public}d.", static_cast(status)); + return false; + } + + status = env->Object_CallMethod_Void(static_cast(callback), method, error, result); + if (status != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_CallMethod_Void failed, error=%{public}d.", static_cast(status)); + return false; + } + return true; +} + +RequestAsyncContext::~RequestAsyncContext() +{ + if (vm == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "VM is nullptr."); + return; + } + bool isSameThread = IsCurrentThread(threadId); + ani_env* curEnv = isSameThread ? env : GetCurrentEnv(vm); + if (curEnv == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetCurrentEnv failed."); + return; + } + + if (callbackRef != nullptr) { + curEnv->GlobalReference_Delete(callbackRef); + callbackRef = nullptr; + } +} + static void UpdateGrantPermissionResultOnly(const std::vector& permissions, const std::vector& grantResults, std::shared_ptr& data, std::vector& newGrantResults) { @@ -72,7 +120,7 @@ static void UpdateGrantPermissionResultOnly(const std::vector& perm for (size_t i = 0; i < size; i++) { int result = static_cast(data->permissionsState[i]); if (data->permissionsState[i] == AccessToken::DYNAMIC_OPER) { - result = data->result == AccessToken::RET_SUCCESS ? grantResults[i] : AccessToken::INVALID_OPER; + result = data->result.errorCode == AccessToken::RET_SUCCESS ? grantResults[i] : AccessToken::INVALID_OPER; } newGrantResults.emplace_back(result); } @@ -146,9 +194,8 @@ static void CreateUIExtensionMainThread(std::shared_ptr& as asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); if (uiContent == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - asyncContext->result = AccessToken::RET_FAILED; + asyncContext->result.errorCode = AccessToken::RET_FAILED; asyncContext->uiExtensionFlag = false; - asyncContext->loadlock.unlock(); return; } @@ -157,9 +204,8 @@ static void CreateUIExtensionMainThread(std::shared_ptr& as int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config); if (sessionId == 0) { ACCESSTOKEN_LOG_ERROR(LABEL, "Create component failed, sessionId is 0"); - asyncContext->result = AccessToken::RET_FAILED; + asyncContext->result.errorCode = AccessToken::RET_FAILED; asyncContext->uiExtensionFlag = false; - asyncContext->loadlock.unlock(); return; } uiExtCallback->SetSessionId(sessionId); @@ -180,14 +226,14 @@ static bool CreateServiceExtension(std::shared_ptr& asyncCo if (!asyncContext->uiAbilityFlag) { ACCESSTOKEN_LOG_ERROR(LABEL, "UIExtension ability can not pop service ablility window!"); asyncContext->needDynamicRequest = false; - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; return false; } OHOS::sptr remoteObject = new (std::nothrow) AuthorizationResult(asyncContext); if (remoteObject == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "Create window failed!"); asyncContext->needDynamicRequest = false; - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; return false; } OHOS::AAFwk::Want want; @@ -263,6 +309,15 @@ static void GetInstanceId(std::shared_ptr& asyncContext) #endif } +static bool AniParseCallback(ani_env* env, const ani_ref& aniCallback, ani_ref& out) +{ + if (env->GlobalReference_Create(aniCallback, &out) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GlobalReference_Create failed!"); + return false; + } + return true; +} + static ani_ref ConvertAniArrayString(ani_env* env, const std::vector& cArray) { ani_size length = cArray.size(); @@ -438,37 +493,30 @@ static ani_object WrapResult(ani_env* env, std::shared_ptr& return aObject; } -static ani_object DealWithResult(ani_env* env, std::shared_ptr& asyncContext) -{ - ani_object resultObj = nullptr; - if (asyncContext->result == RET_SUCCESS) { - resultObj = WrapResult(env, asyncContext); - } - if (asyncContext->result != RET_SUCCESS) { - int32_t stsCode = BusinessErrorAni::GetStsErrorCode(asyncContext->result); - BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); - return nullptr; - } - return resultObj; -} - static void RequestResultsHandler(const std::vector& permissionList, const std::vector& permissionStates, std::shared_ptr& data) { - int32_t result; - if (data->result != RET_SUCCESS) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Result is: %{public}d", data->result); - result = RET_FAILED; - } - std::vector newGrantResults; + std::vector newGrantResults; UpdateGrantPermissionResultOnly(permissionList, permissionStates, data, newGrantResults); if (newGrantResults.empty()) { ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResults empty"); - result = RET_FAILED; + data->result.errorCode = RET_FAILED; } data->grantResults.assign(newGrantResults.begin(), newGrantResults.end()); - data->loadlock.unlock(); - g_loadedCond.notify_all(); + + bool isSameThread = IsCurrentThread(data->threadId); + ani_env* env = isSameThread ? data->env : GetCurrentEnv(data->vm); + if (env == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetCurrentEnv failed."); + return; + } + int32_t stsCode = BusinessErrorAni::GetStsErrorCode(data->result.errorCode); + ani_object error = BusinessErrorAni::CreateError(env, stsCode, GetErrorMessage(stsCode, data->result.errorMsg)); + ani_object result = WrapResult(env, data); + ExecuteAsyncCallback(env, reinterpret_cast(data->callbackRef), error, result); + if (!isSameThread && data->vm->DetachCurrentThread() != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "DetachCurrentThread failed!"); + } } static ani_status ConvertContext( @@ -508,100 +556,119 @@ static ani_status ConvertContext( return ANI_OK; } -static bool ParseRequestPermissionFromUser(ani_env* env, ani_object aniContext, ani_array_ref permissionList, - std::shared_ptr& asyncContext) +static bool ParseRequestPermissionFromUser(ani_env* env, ani_object aniContext, ani_array_ref aniPermissionList, + ani_object callback, std::shared_ptr& asyncContext) { - if (ConvertContext(env, aniContext, asyncContext) != ANI_OK) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, + ani_vm* vm; + ani_status status = env->GetVM(&vm); + if (status != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetVM failed, error=%{public}d.", static_cast(status)); + return false; + } + asyncContext->vm = vm; + asyncContext->env = env; + asyncContext->callback = callback; + asyncContext->threadId = std::this_thread::get_id(); + + status = ConvertContext(env, aniContext, asyncContext); + if (status != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertContext failed, error=%{public}d.", static_cast(status)); + BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL, GetParamErrorMsg("context", "UIAbility or UIExtension Context")); return false; } if (!ProcessArrayString(env, nullptr, permissionList, asyncContext->permissionList)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, + BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL, GetParamErrorMsg("permissionList", "Array")); return false; } + if (!AniParseCallback(env, reinterpret_cast(callback), asyncContext->callbackRef)) { + return false; + } +#ifdef EVENTHANDLER_ENABLE + asyncContext->handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); +#endif return true; } -static bool RequestPermissionsFromUserProcess([[maybe_unused]] ani_env* env, - std::shared_ptr& asyncContext) +static void RequestPermissionsFromUserProcess(std::shared_ptr& asyncContext) { if (!IsDynamicRequest(asyncContext)) { ACCESSTOKEN_LOG_ERROR(LABEL, "It does not need to request permission"); asyncContext->needDynamicRequest = false; - if ((asyncContext->permissionsState.empty()) && (asyncContext->result == STSErrorCode::STS_OK)) { + if ((asyncContext->permissionsState.empty()) && (asyncContext->result.errorCode == RET_SUCCESS)) { ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResults empty"); - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; } - return false; + return; } + GetInstanceId(asyncContext); - asyncContext->loadlock.lock(); - bool lockFlag = false; if (asyncContext->info.grantBundleName == ORI_PERMISSION_MANAGER_BUNDLE_NAME) { ACCESSTOKEN_LOG_INFO( LABEL, "Pop service extension dialog, uiContentFlag=%{public}d", asyncContext->uiContentFlag); if (asyncContext->uiContentFlag) { - lockFlag = RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); + RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); } else { - lockFlag = CreateServiceExtension(asyncContext); + CreateServiceExtension(asyncContext); } } else if (asyncContext->instanceId == -1) { ACCESSTOKEN_LOG_ERROR(LABEL, "Pop service extension dialog, instanceId is -1."); - lockFlag = CreateServiceExtension(asyncContext); + CreateServiceExtension(asyncContext); HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQUEST_PERMISSIONS_FROM_USER", HiviewDFX::HiSysEvent::EventType::BEHAVIOR, "BUNDLENAME", asyncContext->bundleName.c_str(), "UIEXTENSION_FLAG", false); } else { ACCESSTOKEN_LOG_INFO(LABEL, "Pop ui extension dialog"); asyncContext->uiExtensionFlag = true; - lockFlag = RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); + RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::ACCESS_TOKEN, "REQUEST_PERMISSIONS_FROM_USER", HiviewDFX::HiSysEvent::EventType::BEHAVIOR, "BUNDLENAME", asyncContext->bundleName, "UIEXTENSION_FLAG", false); if (!asyncContext->uiExtensionFlag) { ACCESSTOKEN_LOG_WARN(LABEL, "Pop uiextension dialog fail, start to pop service extension dialog."); - lockFlag = RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); + RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); } } - if (!lockFlag) { - asyncContext->loadlock.unlock(); - } - return true; } -static ani_object RequestPermissionsFromUserExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, - ani_object aniContext, ani_array_ref permissionList) +void RequestPermissionsFromUserExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_object aniContext, ani_array_ref aniPermissionList, ani_object callback) { - if (env == nullptr || permissionList == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "permissionList or env null"); - return nullptr; + if (env == nullptr || aniPermissionList == nullptr || callback == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Parenv or aniPermissionList or callback is null."); + return; } std::shared_ptr asyncContext = std::make_shared(); - if (!ParseRequestPermissionFromUser(env, aniContext, permissionList, asyncContext)) { - return nullptr; + if (!ParseRequestPermissionFromUser(env, aniContext, aniPermissionList, callback, asyncContext)) { + return; } -#ifdef EVENTHANDLER_ENABLE - asyncContext->handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); -#endif - bool errTokenID = true; + static AccessTokenID selfTokenID = static_cast(GetSelfTokenID()); if (selfTokenID != asyncContext->tokenId) { ACCESSTOKEN_LOG_ERROR( LABEL, "The context tokenID: %{public}d, selfTokenID: %{public}d.", asyncContext->tokenId, selfTokenID); - asyncContext->result = RET_FAILED; - errTokenID = false; + + ani_ref nullRef = nullptr; + env->GetNull(&nullRef); + ani_object result = reinterpret_cast(nullRef); + ani_object error = BusinessErrorAni::CreateError(env, STS_ERROR_INNER, GetErrorMessage(STS_ERROR_INNER, + "The specified context does not belong to the current application.")); + ExecuteAsyncCallback(env, callback, error, result); + return; } - if (!RequestPermissionsFromUserProcess(env, asyncContext) || !errTokenID) { - return DealWithResult(env, asyncContext); + RequestPermissionsFromUserProcess(asyncContext); + if (asyncContext->needDynamicRequest) { + return; } + + int32_t stsCode = BusinessErrorAni::GetStsErrorCode(asyncContext->result.errorCode); + ani_object error = BusinessErrorAni::CreateError( + env, stsCode, GetErrorMessage(stsCode, asyncContext->result.errorMsg)); + ani_object result = WrapResult(env, asyncContext); + ExecuteAsyncCallback(env, callback, error, result); ACCESSTOKEN_LOG_INFO(LABEL, "uiExtensionFlag: %{public}d, uiContentFlag: %{public}d, uiAbilityFlag: %{public}d ", asyncContext->uiExtensionFlag, asyncContext->uiContentFlag, asyncContext->uiAbilityFlag); - asyncContext->loadlock.lock(); - auto resultObj = DealWithResult(env, asyncContext); - asyncContext->loadlock.unlock(); - return resultObj; } static void CloseModalUIExtensionMainThread(std::shared_ptr& asyncContext, int32_t sessionId) @@ -611,7 +678,7 @@ static void CloseModalUIExtensionMainThread(std::shared_ptr asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); if (uiContent == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; return; } uiContent->CloseModalUIExtension(sessionId); @@ -637,10 +704,11 @@ void RequestAsyncInstanceControl::ExecCallback(int32_t id) std::lock_guard lock(instanceIdMutex_); auto iter = RequestAsyncInstanceControl::instanceIdMap_.find(id); if (iter == RequestAsyncInstanceControl::instanceIdMap_.end()) { - ACCESSTOKEN_LOG_ERROR(LABEL, "instanceIdMap_ empty"); + ACCESSTOKEN_LOG_ERROR(LABEL, "Id: %{public}d not existed.", id); return; } while (!iter->second.empty()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); asyncContext = iter->second[0]; iter->second.erase(iter->second.begin()); CheckDynamicRequest(asyncContext, isDynamic); @@ -649,20 +717,17 @@ void RequestAsyncInstanceControl::ExecCallback(int32_t id) } } if (iter->second.empty()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map is empty", id); RequestAsyncInstanceControl::instanceIdMap_.erase(id); } } - bool lockFlag = true; if (isDynamic) { if (asyncContext->uiExtensionFlag) { - lockFlag = CreateUIExtension(asyncContext); + CreateUIExtension(asyncContext); } else { - lockFlag = CreateServiceExtension(asyncContext); + CreateServiceExtension(asyncContext); } } - if (!lockFlag) { - asyncContext->loadlock.unlock(); - } } void RequestAsyncInstanceControl::CheckDynamicRequest( @@ -677,22 +742,23 @@ void RequestAsyncInstanceControl::CheckDynamicRequest( isDynamic = true; } -bool RequestAsyncInstanceControl::AddCallbackByInstanceId(std::shared_ptr& asyncContext) +void RequestAsyncInstanceControl::AddCallbackByInstanceId(std::shared_ptr& asyncContext) { - std::lock_guard lock(instanceIdMutex_); - auto iter = RequestAsyncInstanceControl::instanceIdMap_.find(asyncContext->instanceId); - if (iter != RequestAsyncInstanceControl::instanceIdMap_.end()) { - RequestAsyncInstanceControl::instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext); - return true; + { + std::lock_guard lock(instanceIdMutex_); + auto iter = RequestAsyncInstanceControl::instanceIdMap_.find(asyncContext->instanceId); + if (iter != RequestAsyncInstanceControl::instanceIdMap_.end()) { + RequestAsyncInstanceControl::instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext); + return; + } + RequestAsyncInstanceControl::instanceIdMap_[asyncContext->instanceId] = {}; } - RequestAsyncInstanceControl::instanceIdMap_[asyncContext->instanceId] = {}; - bool lockFlag = true; if (asyncContext->uiExtensionFlag) { - lockFlag = CreateUIExtension(asyncContext); + CreateUIExtension(asyncContext); } else { - lockFlag = CreateServiceExtension(asyncContext); + CreateServiceExtension(asyncContext); } - return lockFlag; + return; } UIExtensionCallback::UIExtensionCallback(const std::shared_ptr& reqContext) @@ -718,11 +784,12 @@ void UIExtensionCallback::ReleaseHandler(int32_t code) this->reqContext_->releaseFlag = true; } CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_); - this->reqContext_->result = code; + this->reqContext_->result.errorCode = code; + ACCESSTOKEN_LOG_ERROR(LABEL, "ReleaseHandler errorCode: %{public}d", + this->reqContext_->result.errorCode); RequestAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId); RequestResultsHandler(this->reqContext_->permissionList, this->reqContext_->permissionsState, this->reqContext_); } - void UIExtensionCallback::OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result) { ACCESSTOKEN_LOG_INFO(LABEL, "ResultCode is %{public}d", resultCode); @@ -762,12 +829,13 @@ void UIExtensionCallback::OnDestroy() } void AuthorizationResult::GrantResultsCallback( - const std::vector& permissionList, const std::vector& grantResults) + const std::vector& permissionList, const std::vector& grantResults) { std::shared_ptr asyncContext = data_; if (asyncContext == nullptr) { return; } + ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResultsCallback"); RequestResultsHandler(permissionList, grantResults, asyncContext); } @@ -852,18 +920,18 @@ static void UpdatePermissionCache(AtManagerAsyncContext* asyncContext) if (iter != g_cache.end()) { std::string currPara = GetPermParamValue(); if (currPara != iter->second.paramValue) { - asyncContext->result = + asyncContext->grantStatus = AccessToken::AccessTokenKit::VerifyAccessToken(asyncContext->tokenId, asyncContext->permissionName); - iter->second.status = asyncContext->result; + iter->second.status = asyncContext->grantStatus; iter->second.paramValue = currPara; ACCESSTOKEN_LOG_DEBUG(LABEL, "Param changed currPara %{public}s", currPara.c_str()); } else { - asyncContext->result = iter->second.status; + asyncContext->grantStatus = iter->second.status; } } else { - asyncContext->result = + asyncContext->grantStatus = AccessToken::AccessTokenKit::VerifyAccessToken(asyncContext->tokenId, asyncContext->permissionName); - g_cache[asyncContext->permissionName].status = asyncContext->result; + g_cache[asyncContext->permissionName].status = asyncContext->grantStatus; g_cache[asyncContext->permissionName].paramValue = GetPermParamValue(); ACCESSTOKEN_LOG_DEBUG( LABEL, "G_cacheParam set %{public}s", g_cache[asyncContext->permissionName].paramValue.c_str()); @@ -878,14 +946,14 @@ static ani_int CheckAccessTokenSync([[maybe_unused]] ani_env* env, [[maybe_unuse return AccessToken::PermissionState::PERMISSION_DENIED; } if (tokenID == 0) { - BusinessErrorAni::ThrowError( - env, STSErrorCode::STS_ERROR_PARAM_INVALID, GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); - return AccessToken::PermissionState::PERMISSION_DENIED; + std::string errMsg = GetErrorMessage(STS_ERROR_PARAM_INVALID, "The tokenID is 0."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); } std::string stdPermissionName = ANIUtils_ANIStringToStdString(env, static_cast(permissionName)); if (stdPermissionName.empty() || stdPermissionName.length() > MAX_LENGTH) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PARAM_INVALID, - GetParamErrorMsg("permissionName", "Permissions")); + std::string errMsg = GetErrorMessage( + STS_ERROR_PARAM_INVALID, "The permissionName is empty or exceeds 256 characters."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); return AccessToken::PermissionState::PERMISSION_DENIED; } auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(); @@ -898,12 +966,31 @@ static ani_int CheckAccessTokenSync([[maybe_unused]] ani_env* env, [[maybe_unuse asyncContext->permissionName = stdPermissionName; static uint64_t selfTokenId = GetSelfTokenID(); if (asyncContext->tokenId != static_cast(selfTokenId)) { - asyncContext->result = AccessToken::AccessTokenKit::VerifyAccessToken(tokenID, stdPermissionName); - return static_cast(asyncContext->result); + asyncContext->grantStatus = AccessToken::AccessTokenKit::VerifyAccessToken(tokenID, stdPermissionName); + return static_cast(asyncContext->grantStatus); } UpdatePermissionCache(asyncContext); - ACCESSTOKEN_LOG_INFO(LABEL, "CheckAccessTokenSync result : %{public}d", asyncContext->result); - return static_cast(asyncContext->result); + ACCESSTOKEN_LOG_INFO(LABEL, "CheckAccessTokenExecute result : %{public}d", asyncContext->grantStatus); + return static_cast(asyncContext->grantStatus); +} + +RequestPermOnSettingAsyncContext::~RequestPermOnSettingAsyncContext() +{ + if (vm == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "VM is nullptr."); + return; + } + bool isSameThread = IsCurrentThread(threadId); + ani_env* curEnv = isSameThread ? env : GetCurrentEnv(vm); + if (curEnv == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetCurrentEnv failed."); + return; + } + + if (callbackRef != nullptr) { + curEnv->GlobalReference_Delete(callbackRef); + callbackRef = nullptr; + } } static ani_status GetContext( @@ -941,19 +1028,36 @@ static ani_status GetContext( return ANI_OK; } -static bool ParseRequestPermissionOnSetting(ani_env* env, ani_object& aniContext, ani_array_ref& permissionList, - std::shared_ptr& asyncContext) +static bool ParseRequestPermissionOnSetting(ani_env* env, ani_object& aniContext, ani_array_ref& aniPermissionList, + ani_object callback, std::shared_ptr& asyncContext) { + ani_vm* vm; + ani_status status = env->GetVM(&vm); + if (status != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetVM failed, error=%{public}d.", static_cast(status)); + return false; + } + asyncContext->vm = vm; + asyncContext->env = env; + asyncContext->callback = callback; + asyncContext->threadId = std::this_thread::get_id(); + if (GetContext(env, aniContext, asyncContext) != ANI_OK) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, + BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL, GetParamErrorMsg("context", "UIAbility or UIExtension Context")); return false; } if (!ProcessArrayString(env, nullptr, permissionList, asyncContext->permissionList)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionList", "Array")); + BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL, + GetParamErrorMsg("permissionList", "Array")); + return false; + } + if (!AniParseCallback(env, reinterpret_cast(callback), asyncContext->callbackRef)) { return false; } +#ifdef EVENTHANDLER_ENABLE + asyncContext->handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); +#endif return true; } @@ -973,7 +1077,7 @@ static void StateToEnumIndex(int32_t state, ani_size& enumIndex) } } -static ani_ref ReturnResult(ani_env* env, std::shared_ptr& asyncContext) +static ani_object ReturnResult(ani_env* env, std::shared_ptr& asyncContext) { ani_class arrayCls = nullptr; if (env->FindClass("Lescompat/Array;", &arrayCls) != ANI_OK) { @@ -1020,56 +1124,39 @@ static ani_ref ReturnResult(ani_env* env, std::shared_ptr& asyncContext) -{ - if (asyncContext->result == RET_SUCCESS) { - ani_ref result = ReturnResult(env, asyncContext); - if (result != nullptr) { - return result; - } - asyncContext->errorCode = RET_FAILED; - } - - int32_t stsCode = TransferToStsErrorCode(asyncContext->errorCode); - BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); - return nullptr; -} - -PermissonOnSettingUICallback::PermissonOnSettingUICallback(ani_env* env, +PermissonOnSettingUICallback::PermissonOnSettingUICallback( const std::shared_ptr& reqContext) { - this->env_ = env; this->reqContext_ = reqContext; } @@ -1081,6 +1168,26 @@ void PermissonOnSettingUICallback::SetSessionId(int32_t sessionId) this->sessionId_ = sessionId; } +static void PermissionResultsCallbackUI( + const std::vector stateList, std::shared_ptr& data) +{ + bool isSameThread = IsCurrentThread(data->threadId); + ani_env* env = isSameThread ? data->env : GetCurrentEnv(data->vm); + if (env == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetCurrentEnv failed."); + return; + } + + int32_t stsCode = TransferToStsErrorCode(data->result.errorCode); + ani_object error = BusinessErrorAni::CreateError(env, stsCode, GetErrorMessage(stsCode, data->result.errorMsg)); + ani_object result = ReturnResult(env, data); + ExecuteAsyncCallback(env, reinterpret_cast(data->callbackRef), error, result); + + if (!isSameThread && data->vm->DetachCurrentThread() != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "DetachCurrentThread failed!"); + } +} + static void CloseSettingModalUIExtensionMainThread(std::shared_ptr& asyncContext, int32_t sessionId) { @@ -1089,7 +1196,7 @@ static void CloseSettingModalUIExtensionMainThread(std::shared_ptruiExtensionContext, asyncContext->uiAbilityFlag); if (uiContent == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; return; } uiContent->CloseModalUIExtension(sessionId); @@ -1109,24 +1216,20 @@ static void CloseSettingModalUIExtensionMainThread(std::shared_ptr lock(this->lockReleaseFlag); - if (this->releaseFlag) { + std::lock_guard lock(this->reqContext_->lockReleaseFlag); + if (this->reqContext_->releaseFlag) { ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed."); return; } - this->releaseFlag = true; + this->reqContext_->releaseFlag = true; } CloseSettingModalUIExtensionMainThread(this->reqContext_, this->sessionId_); if (code == -1) { - this->reqContext_->errorCode = code; + this->reqContext_->result.errorCode = code; } - int32_t stsCode = TransferToStsErrorCode(this->reqContext_->errorCode); - if (stsCode != STSErrorCode::STS_OK) { - this->reqContext_->result = RET_FAILED; - } - this->reqContext_->loadlock.unlock(); - std::lock_guard lock(g_lockWindowFlag); - g_windowFlag = false; + RequestOnSettingAsyncInstanceControl::UpdateQueueData(this->reqContext_); + RequestOnSettingAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId); + PermissionResultsCallbackUI(this->reqContext_->stateList, this->reqContext_); } /* @@ -1134,10 +1237,10 @@ void PermissonOnSettingUICallback::ReleaseHandler(int32_t code) */ void PermissonOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result) { - this->reqContext_->errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0); + this->reqContext_->result.errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0); this->reqContext_->stateList = result.GetIntArrayParam(PERMISSION_RESULT_KEY); - ACCESSTOKEN_LOG_INFO(LABEL, "ResultCode is %{public}d, errorCode=%{public}d, listSize=%{public}zu.", - resultCode, this->reqContext_->errorCode, this->reqContext_->stateList.size()); + ACCESSTOKEN_LOG_INFO(LABEL, "ResultCode is %{public}d, errorCodeis %{public}d, listSize=%{public}zu.", + resultCode, this->reqContext_->result.errorCode, this->reqContext_->stateList.size()); ReleaseHandler(0); } @@ -1198,7 +1301,7 @@ static void CreateSettingUIExtensionMainThread(std::shared_ptruiExtensionContext, asyncContext->uiAbilityFlag); if (uiContent == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to get ui content!"); - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; return; } @@ -1209,7 +1312,7 @@ static void CreateSettingUIExtensionMainThread(std::shared_ptrtokenId); if (sessionId == 0) { ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create component, sessionId is 0."); - asyncContext->result = RET_FAILED; + asyncContext->result.errorCode = RET_FAILED; return; } uiExtCallback->SetSessionId(sessionId); @@ -1225,16 +1328,10 @@ static void CreateSettingUIExtensionMainThread(std::shared_ptr& asyncContext) +static void CreateUIExtension( + const OHOS::AAFwk::Want &want, std::shared_ptr asyncContext) { - AccessTokenKit::GetPermissionManagerInfo(asyncContext->info); - - OHOS::AAFwk::Want want; - want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.permStateAbilityName); - want.SetParam(PERMISSION_SETTING_KEY, asyncContext->permissionList); - want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE); - - auto uiExtCallback = std::make_shared(env, asyncContext); + auto uiExtCallback = std::make_shared(asyncContext); Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = { [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); @@ -1256,58 +1353,198 @@ static bool StartUIExtension(ani_env* env, std::shared_ptr& asyncContext) +{ + AccessTokenKit::GetPermissionManagerInfo(asyncContext->info); + ACCESSTOKEN_LOG_INFO(LABEL, "bundleName: %{public}s, permStateAbilityName: %{public}s.", + asyncContext->info.grantBundleName.c_str(), asyncContext->info.permStateAbilityName.c_str()); + OHOS::AAFwk::Want want; + want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.permStateAbilityName); + want.SetParam(PERMISSION_SETTING_KEY, asyncContext->permissionList); + want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE); + CreateUIExtension(want, asyncContext); +} + + +static void GetInstanceId(std::shared_ptr& asyncContext) +{ + auto task = [asyncContext]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); + return; + } + asyncContext->instanceId = uiContent->GetInstanceId(); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId"); + } else { + task(); + } +#else + task(); +#endif + ACCESSTOKEN_LOG_INFO(LABEL, "Instance id: %{public}d", asyncContext->instanceId); +} + +void RequestOnSettingAsyncInstanceControl::AddCallbackByInstanceId( + std::shared_ptr& asyncContext) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "InstanceId: %{public}d", asyncContext->instanceId); { - std::lock_guard lock(g_lockWindowFlag); - if (g_windowFlag) { - ACCESSTOKEN_LOG_WARN(LABEL, "The request already exists."); - asyncContext->result = RET_FAILED; - asyncContext->errorCode = REQUEST_REALDY_EXIST; - return false; + std::lock_guard lock(instanceIdMutex_); + auto iter = instanceIdMap_.find(asyncContext->instanceId); + // id is existed mean a pop window is showing, add context to waiting queue + if (iter != instanceIdMap_.end()) { + ACCESSTOKEN_LOG_INFO(LABEL, "InstanceId: %{public}d has existed.", asyncContext->instanceId); + instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext); + return; } - g_windowFlag = true; + // make sure id is in map to indicate a pop-up window is showing + instanceIdMap_[asyncContext->instanceId] = {}; } - CreateSettingUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback); - if (asyncContext->result == RET_FAILED) { - { - std::lock_guard lock(g_lockWindowFlag); - g_windowFlag = false; + StartUIExtension(asyncContext); +} + +bool static CheckPermList(std::vector permList, std::vector tmpPermList) +{ + if (permList.size() != tmpPermList.size()) { + ACCESSTOKEN_LOG_ERROR( + LABEL, "Perm list size not equal, CurrentPermList size: %{public}zu.", tmpPermList.size()); + return false; + } + + for (const auto& item : permList) { + auto iter = std::find_if(tmpPermList.begin(), tmpPermList.end(), [item](const std::string& perm) { + return item == perm; + }); + if (iter == tmpPermList.end()) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Different permission lists."); return false; } } return true; } +void RequestOnSettingAsyncInstanceControl::UpdateQueueData( + const std::shared_ptr& reqContext) +{ + if (reqContext->result.errorCode != RET_SUCCESS) { + ACCESSTOKEN_LOG_INFO(LABEL, "The queue data does not need to be updated."); + return; + } + for (const int32_t item : reqContext->stateList) { + if (item != PERMISSION_GRANTED) { + ACCESSTOKEN_LOG_INFO(LABEL, "The queue data does not need to be updated"); + return; + } + } + + { + std::lock_guard lock(instanceIdMutex_); + int32_t id = reqContext->instanceId; + auto iter = instanceIdMap_.find(id); + if (iter == instanceIdMap_.end()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d not existed.", id); + return; + } + std::vector permList = reqContext->permissionList; + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + for (auto& asyncContext : iter->second) { + std::vector tmpPermList = asyncContext->permissionList; + if (CheckPermList(permList, tmpPermList)) { + asyncContext->result.errorCode = reqContext->result.errorCode; + asyncContext->stateList = reqContext->stateList; + asyncContext->isDynamic = false; + } + } + } +} + +void RequestOnSettingAsyncInstanceControl::ExecCallback(int32_t id) +{ + std::shared_ptr asyncContext = nullptr; + bool isDynamic = false; + { + std::lock_guard lock(instanceIdMutex_); + auto iter = instanceIdMap_.find(id); + if (iter == instanceIdMap_.end()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d not existed.", id); + return; + } + while (!iter->second.empty()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + asyncContext = iter->second[0]; + iter->second.erase(iter->second.begin()); + CheckDynamicRequest(asyncContext, isDynamic); + if (isDynamic) { + break; + } + } + if (iter->second.empty()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map is empty", id); + instanceIdMap_.erase(id); + } + } + if (isDynamic) { + StartUIExtension(asyncContext); + } +} + +void RequestOnSettingAsyncInstanceControl::CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic) +{ + isDynamic = asyncContext->isDynamic; + if (!isDynamic) { + ACCESSTOKEN_LOG_INFO(LABEL, "It does not need to request permission exsion"); + PermissionResultsCallbackUI(asyncContext->stateList, asyncContext); + return; + } +} + static ani_ref RequestPermissionOnSettingExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_object aniContext, ani_array_ref permissionList) { - if (env == nullptr || permissionList == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "permissionList or env null"); - return nullptr; + if (env == nullptr || permissionList == nullptr || callback == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "env or permissionList or callback is null."); + return; } std::shared_ptr asyncContext = std::make_shared(); - - if (!ParseRequestPermissionOnSetting(env, aniContext, permissionList, asyncContext)) { - return nullptr; + if (!ParseRequestPermissionOnSetting(env, aniContext, permissionList, callback, asyncContext)) { + return; } + ani_ref nullRef = nullptr; + env->GetNull(&nullRef); + ani_object result = reinterpret_cast(nullRef); static AccessTokenID selfTokenID = static_cast(GetSelfTokenID()); if (selfTokenID != asyncContext->tokenId) { ACCESSTOKEN_LOG_ERROR(LABEL, "The context tokenID %{public}d is not same with selfTokenID %{public}d.", asyncContext->tokenId, selfTokenID); - ThrowError(env, RET_FAILED); - return nullptr; + ani_object error = + BusinessErrorAni::CreateError(env, STS_ERROR_PARAM_INVALID, GetErrorMessage(STS_ERROR_PARAM_INVALID, + "The specified context does not belong to the current application.")); + ExecuteAsyncCallback(env, callback, error, result); + return; } - asyncContext->loadlock.lock(); - bool flag = StartUIExtension(env, asyncContext); - if (!flag) { - asyncContext->loadlock.unlock(); + GetInstanceId(asyncContext); + RequestOnSettingAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); + ACCESSTOKEN_LOG_INFO(LABEL, "Start to pop ui extension dialog"); + + if (asyncContext->result.errorCode != RET_SUCCESS) { + int32_t stsCode = TransferToStsErrorCode(asyncContext->result.errorCode); + ani_object error = BusinessErrorAni::CreateError( + env, stsCode, GetErrorMessage(stsCode, asyncContext->result.errorMsg)); + ExecuteAsyncCallback(env, callback, error, result); + ACCESSTOKEN_LOG_WARN(LABEL, "Failed to pop uiextension dialog."); } - asyncContext->loadlock.lock(); - ani_ref result = RequestPermissionOnSettingComplete(env, asyncContext); - asyncContext->loadlock.unlock(); - return result; } static bool IsPermissionFlagValid(uint32_t flag) @@ -1333,20 +1570,23 @@ static void RevokeUserGrantedPermissionExecute([[maybe_unused]] ani_env* env, } if (!IsPermissionFlagValid(static_cast (permissionFlags))) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PARAM_INVALID, - GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); + std::string errMsg = GetErrorMessage(STS_ERROR_PARAM_INVALID, "The permissionFlags is invalid."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); return; } - if (permissionNameString.size() > MAX_LENGTH || permissionNameString.empty()) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PARAM_INVALID, - GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); + if (permissionNameString.empty() || permissionNameString.size() > MAX_LENGTH) { + std::string errMsg = GetErrorMessage( + STS_ERROR_PARAM_INVALID, "The permissionName is empty or exceeds 256 characters."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); return; } PermissionBriefDef def; if (!GetPermissionBriefDef(permissionNameString, def) || def.grantMode != USER_GRANT) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PERMISSION_NOT_EXIST, - GetErrorMessage(STSErrorCode::STS_ERROR_PERMISSION_NOT_EXIST)); + std::string errMsg = GetErrorMessage(STS_ERROR_PERMISSION_NOT_EXIST, + "The specified permission does not exist or is not a user_grant permission."); + BusinessErrorAni::ThrowError( + env, STS_ERROR_PERMISSION_NOT_EXIST, GetErrorMessage(STS_ERROR_PERMISSION_NOT_EXIST)); return; } @@ -1385,14 +1625,14 @@ static ani_ref GetPermissionsStatusExecute([[maybe_unused]] ani_env* env, } std::vector aniPermissionList; if (!AniParseStringArray(env, permissionList, aniPermissionList)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionList", "Array")); + BusinessErrorAni::ThrowParameterTypeError( + env, STS_ERROR_PARAM_ILLEGAL, GetParamErrorMsg("permissionList", "Array")); return nullptr; } if (aniPermissionList.empty()) { - BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, GetErrorMessage(STS_ERROR_INNER)); - return nullptr; + std::string errMsg = GetErrorMessage(STS_ERROR_INNER, "The permissionList is empty."); + BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, GetErrorMessage(STS_ERROR_INNER)); } std::vector permList; @@ -1457,10 +1697,10 @@ ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result) ani_native_function { "checkAccessTokenANI", "ILstd/core/String;:I", reinterpret_cast(CheckAccessTokenSync) }, ani_native_function { "requestPermissionsFromUserExecute", - "Lapplication/Context/Context;Lescompat/Array;:Lsecurity/PermissionRequestResult/PermissionRequestResult;", + nullptr, reinterpret_cast(RequestPermissionsFromUserExecute) }, ani_native_function { "requestPermissionOnSettingExecute", - "Lapplication/Context/Context;Lescompat/Array;:Lescompat/Array;", + nullptr, reinterpret_cast(RequestPermissionOnSettingExecute) }, ani_native_function { "revokeUserGrantedPermissionExecute", nullptr, diff --git a/frameworks/ets/ani/common/include/ani_error.h b/frameworks/ets/ani/common/include/ani_error.h index d698fd7bf..d8fc49028 100644 --- a/frameworks/ets/ani/common/include/ani_error.h +++ b/frameworks/ets/ani/common/include/ani_error.h @@ -45,16 +45,18 @@ typedef enum { STS_ERROR_PERM_REVOKE_BY_USER = 12100012, STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN = 12100013, } STSErrorCode; + +struct AtmResult { + int32_t errorCode = 0; + std::string errorMsg = ""; +}; + std::string GetParamErrorMsg(const std::string& param, const std::string& errMsg); -std::string GetErrorMessage(uint32_t errCode); +std::string GetErrorMessage(uint32_t errCode, const std::string& extendMsg = ""); class BusinessErrorAni { public: static ani_object CreateError(ani_env* env, ani_int code, const std::string& msg); - static ani_object CreateCommonError(ani_env* env, int32_t err, const std::string& errMsg = ""); - static ani_object CreateEnumError(ani_env* env, const std::string& parameter, const std::string& enumClass); - static void ThrowTooFewParametersError(ani_env* env, int32_t err); static void ThrowParameterTypeError(ani_env* env, int32_t err, const std::string& errMsg); - static void ThrowEnumError(ani_env* env, const std::string& parameter, const std::string& errMsg); static void ThrowError(ani_env* env, int32_t err, const std::string& errMsg = ""); static int32_t GetStsErrorCode(int32_t errCode); diff --git a/frameworks/ets/ani/common/include/ani_utils.h b/frameworks/ets/ani/common/include/ani_utils.h index 1a937980b..859b857d0 100644 --- a/frameworks/ets/ani/common/include/ani_utils.h +++ b/frameworks/ets/ani/common/include/ani_utils.h @@ -54,6 +54,7 @@ bool IsCurrentThread(std::thread::id threadId); bool AniIsCallbackRefEqual(ani_env* env, const ani_ref& compareRef, const ani_ref& targetRref, std::thread::id threadId, bool& isEqual); bool AniFunctionalObjectCall(ani_env *env, const ani_fn_object& fn, ani_size size, ani_ref* argv, ani_ref& result); +ani_env* GetCurrentEnv(ani_vm* vm); void DeleteReference(ani_env* env, ani_ref& ref); } // namespace AccessToken } // namespace Security diff --git a/frameworks/ets/ani/common/src/ani_error.cpp b/frameworks/ets/ani/common/src/ani_error.cpp index 0f8d42f6b..8803c7a6f 100644 --- a/frameworks/ets/ani/common/src/ani_error.cpp +++ b/frameworks/ets/ani/common/src/ani_error.cpp @@ -27,19 +27,14 @@ static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN } // namespace constexpr const int32_t RET_SUCCESS = 0; constexpr const char* BUSINESS_ERROR_CLASS = "L@ohos/base/BusinessError;"; -constexpr const char* ERR_MSG_PARAM_NUMBER_ERROR = - "BusinessError 401: Parameter error. The number of parameters is incorrect."; -constexpr const char* ERR_MSG_ENUM_EROOR = "Parameter error. The value of $ is not a valid enum $."; -constexpr const char* ERR_MSG_BUSINESS_ERROR = "BusinessError $: "; -constexpr const char* ERR_MSG_PARAM_TYPE_ERROR = "Parameter error. The errMsg of $ must be $."; static const std::unordered_map g_errorStringMap = { { STS_ERROR_PERMISSION_DENIED, "Permission denied." }, { STS_ERROR_NOT_SYSTEM_APP, "Not system app." }, { STS_ERROR_SYSTEM_CAPABILITY_NOT_SUPPORT, "Not support system capability." }, { STS_ERROR_START_ABILITY_FAIL, "Start grant ability failed." }, - { STS_ERROR_BACKGROUND_FAIL, "Ui extension turn background failed." }, + { STS_ERROR_BACKGROUND_FAIL, "UI extension turn background failed." }, { STS_ERROR_TERMINATE_FAIL, "Ui extension terminate failed." }, - { STS_ERROR_PARAM_INVALID, "Invalid parameter $." }, + { STS_ERROR_PARAM_INVALID, "Invalid parameter." }, { STS_ERROR_TOKENID_NOT_EXIST, "The specified token id does not exist." }, { STS_ERROR_PERMISSION_NOT_EXIST, "The specified permission does not exist." }, { STS_ERROR_NOT_USE_TOGETHER, "The API is not used in pair with others." }, @@ -53,7 +48,6 @@ static const std::unordered_map g_errorStringMap = { { STS_ERROR_PERM_REVOKE_BY_USER, "The permission list contains the permission that has not been revoked by the user." }, { STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN, "The specific global switch is already open." }, - { STS_ERROR_PARAM_ILLEGAL, ERR_MSG_PARAM_TYPE_ERROR }, }; void BusinessErrorAni::ThrowError(ani_env* env, int32_t err, const std::string& errMsg) @@ -122,13 +116,13 @@ std::string GetParamErrorMsg(const std::string& param, const std::string& errMsg return msg; } -std::string GetErrorMessage(uint32_t errCode) +std::string GetErrorMessage(uint32_t errCode, const std::string& extendMsg) { auto iter = g_errorStringMap.find(errCode); if (iter != g_errorStringMap.end()) { - return iter->second; + return iter->second + (extendMsg.empty() ? "" : ("" + extendMsg)); } - std::string errMsg = "Unknown error, errCode + " + std::to_string(errCode) + "."; + std::string errMsg = "Unknown error, errCode " + std::to_string(errCode) + "."; return errMsg; } @@ -137,73 +131,11 @@ void BusinessErrorAni::ThrowParameterTypeError(ani_env* env, int32_t err, const if (env == nullptr) { return; } - ani_object error = CreateCommonError(env, err, errMsg); - ThrowError(env, error); -} - -void BusinessErrorAni::ThrowTooFewParametersError(ani_env* env, int32_t err) -{ - if (env == nullptr) { - return; - } - ThrowError(env, err, ERR_MSG_PARAM_NUMBER_ERROR); -} -ani_object BusinessErrorAni::CreateCommonError(ani_env* env, int32_t err, const std::string& errMsg) -{ - if (env == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "env is nullptr"); - return nullptr; - } - std::string errMessage = ERR_MSG_BUSINESS_ERROR; - auto iter = errMessage.find("$"); - if (iter != std::string::npos) { - errMessage = errMessage.replace(iter, 1, std::to_string(err)); - } - if (g_errorStringMap.find(err) != g_errorStringMap.end()) { - errMessage += g_errorStringMap.at(err); - } - iter = errMessage.find("$"); - if (iter != std::string::npos) { - iter = errMessage.find("$"); - if (iter != std::string::npos) { - errMessage = errMessage.replace(iter, 1, errMsg); - } - } - return CreateError(env, err, errMessage); -} - -void BusinessErrorAni::ThrowEnumError(ani_env* env, const std::string& parameter, const std::string& errMsg) -{ - if (env == nullptr) { - return; - } - ani_object error = CreateEnumError(env, parameter, errMsg); + ani_object error = CreateError(env, err, errMsg); ThrowError(env, error); } -ani_object BusinessErrorAni::CreateEnumError(ani_env* env, const std::string& parameter, const std::string& enumClass) -{ - if (env == nullptr) { - return nullptr; - } - std::string errMessage = ERR_MSG_BUSINESS_ERROR; - auto iter = errMessage.find("$"); - if (iter != std::string::npos) { - errMessage = errMessage.replace(iter, 1, std::to_string(STS_ERROR_PARAM_ILLEGAL)); - } - errMessage += ERR_MSG_ENUM_EROOR; - iter = errMessage.find("$"); - if (iter != std::string::npos) { - errMessage = errMessage.replace(iter, 1, parameter); - iter = errMessage.find("$"); - if (iter != std::string::npos) { - errMessage = errMessage.replace(iter, 1, enumClass); - } - } - return CreateError(env, STS_ERROR_PARAM_ILLEGAL, errMessage); -} - void BusinessErrorAni::ThrowError(ani_env* env, ani_object err) { if (err == nullptr) { diff --git a/frameworks/ets/ani/common/src/ani_utils.cpp b/frameworks/ets/ani/common/src/ani_utils.cpp index 0078798b2..dbb8eb727 100644 --- a/frameworks/ets/ani/common/src/ani_utils.cpp +++ b/frameworks/ets/ani/common/src/ani_utils.cpp @@ -272,6 +272,23 @@ void DeleteReference(ani_env* env, ani_ref& ref) ref = nullptr; } } + +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/ets/@ohos.privacyManager.ets b/frameworks/ets/ani/privacy/ets/@ohos.privacyManager.ets index f91c45fe6..d6217ae52 100644 --- a/frameworks/ets/ani/privacy/ets/@ohos.privacyManager.ets +++ b/frameworks/ets/ani/privacy/ets/@ohos.privacyManager.ets @@ -103,7 +103,7 @@ export default namespace privacyManager { if (typeof permissionName !== "string") { let err = new BusinessError(); err.code = STSErrorCode.STS_ERROR_PARAM_ILLEGAL; - err.data = PARAM_ERROR_MSG("permissionName", "string"); + err.data = PARAM_ERROR_MSG("permissionName", "Permissions"); throw err; } @@ -126,7 +126,7 @@ export default namespace privacyManager { if (typeof permissionName !== "string") { let err = new BusinessError(); err.code = STSErrorCode.STS_ERROR_PARAM_ILLEGAL; - err.data = PARAM_ERROR_MSG("permissionName", "string"); + err.data = PARAM_ERROR_MSG("permissionName", "Permissions"); throw err; } let optionsLocal: AddPermissionUsedRecordOptionsInner = { usedType: PermissionUsedType.NORMAL_TYPE }; -- Gitee