diff --git a/frameworks/ets/ani/accesstoken/BUILD.gn b/frameworks/ets/ani/accesstoken/BUILD.gn index 296e2969ce1f22d127b80a1ff10dd204da5e507d..cd5ebb4008a9c9690e87b44e03908908b9e73273 100644 --- a/frameworks/ets/ani/accesstoken/BUILD.gn +++ b/frameworks/ets/ani/accesstoken/BUILD.gn @@ -31,7 +31,13 @@ ohos_shared_library("accesstoken_ani") { "${access_token_path}/interfaces/innerkits/token_callback/include", "${access_token_path}/frameworks/ets/ani/common/include", ] - sources = [ "src/ani_ability_access_ctrl.cpp" ] + sources = [ + "src/ani_ability_access_ctrl.cpp", + "src/ani_common.cpp", + "src/ani_request_global_switch_on_setting.cpp", + "src/ani_request_permission.cpp", + "src/ani_request_permission_on_setting.cpp", + ] deps = [ "${access_token_path}/frameworks/ets/ani/common:libani_common", diff --git a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets index b8c11cbb69e78788e9b54524dfec2e974daa5dde..0631672a23e5cd1492a11474bf81f2a8a30b8016 100644 --- a/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets +++ b/frameworks/ets/ani/accesstoken/ets/@ohos.abilityAccessCtrl.ets @@ -16,19 +16,28 @@ import { AsyncCallback, Callback, BusinessError } from '@ohos.base'; import { Permissions } from 'permissions'; import type _PermissionRequestResult from 'security.PermissionRequestResult'; -import Context from 'application.Context' -import hilog from '@ohos.hilog'; +import Context from 'application.Context'; function PARAM_ERROR_MSG(param: string, type: string): string { return `Parameter Error. The type of "${param}" must be ${type}.`; } export { Permissions }; - export type PermissionRequestResult = _PermissionRequestResult; -export default namespace abilityAccessCtrl { +class AsyncCallbackWrapper { + private wrapperCallback_: AsyncCallback = (err: BusinessError, data: T) => {} + + constructor(callback: AsyncCallback) { + this.wrapperCallback_ = callback; + } + invoke(err: BusinessError, data: T) : void { + this.wrapperCallback_(err, data); + } +} + +export default namespace abilityAccessCtrl { loadLibrary("accesstoken_ani.z"); export enum GrantStatus { PERMISSION_DENIED = -1, @@ -71,9 +80,9 @@ export default namespace abilityAccessCtrl { STS_ERROR_NOT_SYSTEM_APP = 202, STS_ERROR_PARAM_ILLEGAL = 401, STS_ERROR_SYSTEM_CAPABILITY_NOT_SUPPORT = 801, - } ; + }; function validateRequestParams(context: Context, permissionList: Array): void { - if (typeof context === "undefined" || context == null) { + if ((typeof context === "undefined") || (context == null)) { let err = new BusinessError(); err.code = STSErrorCode.STS_ERROR_PARAM_ILLEGAL; err.data = PARAM_ERROR_MSG("context", "UIAbility or UIExtension Context"); @@ -91,31 +100,31 @@ export default namespace abilityAccessCtrl { native function createAtManager(): AtManager; interface AtManager { checkAccessTokenExecute(tokenID: int, permissionName: Permissions): int; - requestPermissionsFromUserExecute( - context: Context, permissionList: Array): PermissionRequestResult; - requestPermissionOnSettingExecute(context: Context, permissionList: Array): Array; + requestPermissionsFromUserExecute(context: Context, permissionList: Array, + callback: AsyncCallbackWrapper): void; + requestPermissionOnSettingExecute(context: Context, + permissionList: Array, callback: AsyncCallbackWrapper>): void; + requestGlobalSwitchExecute( + context: Context, type: int, callback: AsyncCallbackWrapper): void; revokeUserGrantedPermissionExecute(tokenID: int, permissionName: Permissions, permissionFlags: int): void; getPermissionsStatusExecute(tokenID: int, permissionList: Array): Array; getVersionExecute(): int; getPermissionFlagsExecute(tokenID: int, permissionName: Permissions): int; setPermissionRequestToggleStatusExecute(permissionName: Permissions, status: int): void; getPermissionRequestToggleStatusExecute(permissionName: Permissions): int; + checkAccessTokenSync(tokenID: int, permissionName: Permissions): GrantStatus; verifyAccessTokenSync(tokenID: int, permissionName: Permissions): GrantStatus; checkAccessToken(tokenID: int, permissionName: Permissions): Promise; verifyAccessToken(tokenID: int, permissionName: Permissions): Promise; - requestPermissionsFromUser( context: Context, permissionList: Array, requestCallback: AsyncCallback): void; - requestPermissionsFromUser( context: Context, permissionList: Array): Promise; - requestPermissionOnSetting( - context: Context, - permissionList: Array): Promise>; - + context: Context, permissionList: Array): Promise>; + requestGlobalSwitch(context: Context, type: SwitchType): Promise; grantUserGrantedPermission( tokenID: int, permissionName: Permissions, @@ -123,33 +132,29 @@ export default namespace abilityAccessCtrl { callback: AsyncCallback): void; grantUserGrantedPermission( - tokenID: int, - permissionName: Permissions, + tokenID: int, + permissionName: Permissions, permissionFlags: int): Promise; revokeUserGrantedPermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise; - revokeUserGrantedPermission( tokenID: int, permissionName: Permissions, permissionFlags: int, callback: AsyncCallback): void; - getVersion(): Promise; - getPermissionsStatus(tokenID: int, permissionList: Array): Promise>; - getPermissionFlags(tokenID: int, permissionName: Permissions): Promise; - setPermissionRequestToggleStatus( permissionName: Permissions, status: PermissionRequestToggleStatus): Promise; - getPermissionRequestToggleStatus(permissionName: Permissions): Promise; } class AtManagerInner implements AtManager { native checkAccessTokenExecute(tokenID: int, permissionName: Permissions): int; - native requestPermissionsFromUserExecute( - context: Context, permissionList: Array): PermissionRequestResult; - native requestPermissionOnSettingExecute( - context: Context, permissionList: Array): Array; + native requestPermissionsFromUserExecute(context: Context, permissionList: Array, + callback: AsyncCallbackWrapper): void; + native requestPermissionOnSettingExecute(context: Context, + permissionList: Array, callback: AsyncCallbackWrapper>): void; + native requestGlobalSwitchExecute( + context: Context, type: int, callback: AsyncCallbackWrapper): void; native grantUserGrantedPermissionExecute(tokenID: int, permissionName: Permissions, permissionFlags: int): void; native revokeUserGrantedPermissionExecute( tokenID: int, permissionName: Permissions, permissionFlags: int): void; @@ -200,71 +205,73 @@ export default namespace abilityAccessCtrl { } requestPermissionsFromUser(context: Context, permissionList: Array, - callback:AsyncCallback): void { + requestCallback: AsyncCallback): void { validateRequestParams(context, permissionList); - let fun = async() => { - let work = new EAWorker(); - try { - let job = work.run(() : PermissionRequestResult => { - return new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList); - }) - let result = job.Await(); - work.join(); - let retError = new BusinessError(); - callback(retError, result as PermissionRequestResult); - } catch (err: BusinessError) { - work.join(); - 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(( + let p: Promise = new Promise(( resolve: (v: PermissionRequestResult) => void, reject: (error: BusinessError) => void) => { - let fun = async() => { - let work = new EAWorker(); - try { - let job = work.run((): PermissionRequestResult => { - return new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList); - }); - let result = job.Await(); - work.join(); - resolve(result as PermissionRequestResult); - } catch (err: BusinessError) { - work.join(); + let callbackWrap = new AsyncCallbackWrapper(( + err: BusinessError, data: PermissionRequestResult) => { + if (err.code == 0) { + resolve(data); + } else { reject(err); } - }; - fun(); + }); + taskpool.execute((): void => { + new AtManagerInner().requestPermissionsFromUserExecute(context, permissionList, callbackWrap); + }); }); return p; } requestPermissionOnSetting(context: Context, permissionList: Array): Promise> { validateRequestParams(context, permissionList); - let p = new Promise>(( + let p: Promise> = new Promise>(( resolve: (v: Array) => void, reject: (error: BusinessError) => void) => { - let func = async() => { - let work = new EAWorker(); - try { - let job = work.run>((): Array => { - return new AtManagerInner().requestPermissionOnSettingExecute(context, permissionList); - }); - let result = job.Await(); - work.join(); - resolve(result as Array); - } catch (err: BusinessError) { - work.join(); + let callbackWrap = new AsyncCallbackWrapper>(( + err: BusinessError, data: Array) => { + if (err.code == 0) { + resolve(data); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + new AtManagerInner().requestPermissionOnSettingExecute(context, permissionList, callbackWrap); + }); + }); + return p; + } + + requestGlobalSwitch(context: Context, type: SwitchType): Promise { + if ((typeof context === "undefined") || (context == null)) { + let err = new BusinessError(); + err.code = STSErrorCode.STS_ERROR_PARAM_ILLEGAL; + err.data = PARAM_ERROR_MSG("context", "UIAbility or UIExtension Context"); + throw err; + } + let p: Promise = new Promise(( + resolve: (v: boolean) => void, reject: (error: BusinessError) => void) => { + let callbackWrap = new AsyncCallbackWrapper(( + err: BusinessError, data: boolean) => { + if (err.code == 0) { + resolve(data); + } else { reject(err); } - }; - func(); + }); + taskpool.execute((): void => { + new AtManagerInner().requestGlobalSwitchExecute(context, type, callbackWrap); + }); }); return p; } @@ -278,7 +285,7 @@ export default namespace abilityAccessCtrl { callback(err, undefined); }, (err: Error): void => { callback(err as BusinessError, undefined); - }) + }); } grantUserGrantedPermission(tokenID: int, permissionName: Permissions, permissionFlags: int): Promise { @@ -291,7 +298,7 @@ export default namespace abilityAccessCtrl { resolve(undefined); }).catch((err: Error) : void => { reject(err as BusinessError); - }) + }); }); } @@ -305,7 +312,7 @@ export default namespace abilityAccessCtrl { resolve(undefined); }).catch((err: Error): void => { reject(err as BusinessError); - }) + }); }); } @@ -314,17 +321,17 @@ export default namespace abilityAccessCtrl { let job = taskpool.execute((): void => { new AtManagerInner().revokeUserGrantedPermissionExecute(tokenID, permissionName, permissionFlags); }); - job.then(()=>{ + job.then(() => { let err = new BusinessError(); callback(err, undefined); }, (err: Error): void=> { callback(err as BusinessError, undefined); - }) + }); } getVersion(): Promise { let p = new Promise(( - resolve: (v: int) => void, reject: (error: BusinessError) => void) =>{ + resolve: (v: int) => void, reject: (error: BusinessError) => void) => { let p1 = taskpool.execute((): int => { return new AtManagerInner().getVersionExecute() as int; }); @@ -337,8 +344,7 @@ export default namespace abilityAccessCtrl { return p; } - getPermissionsStatus( - tokenID: int, permissionList: Array): Promise> { + getPermissionsStatus(tokenID: int, permissionList: Array): Promise> { let p = new Promise>(( resolve: (v: Array) => void, reject: (error: BusinessError) => void) => { let p1 = taskpool.execute((): Array => { @@ -379,7 +385,7 @@ export default namespace abilityAccessCtrl { resolve(undefined); }).catch((err: Error): void => { reject(err as BusinessError); - }) + }); }); return p; } @@ -395,7 +401,7 @@ export default namespace abilityAccessCtrl { resolve(e as PermissionRequestToggleStatus); }).catch((err: Error): void => { reject(err as BusinessError); - }) + }); }); return p; } 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 e3ac10ad3ae2979840ef2c2b40e5e86137b04f23..adb316d0fe4d3c6d462453349fde69cf62e4f846 100644 --- a/frameworks/ets/ani/accesstoken/include/ani_ability_access_ctrl.h +++ b/frameworks/ets/ani/accesstoken/include/ani_ability_access_ctrl.h @@ -16,21 +16,8 @@ #ifndef ABILITY_ACCESS_CTRL_H #define ABILITY_ACCESS_CTRL_H -#include -#include -#include -#include - -#include "ability.h" -#include "ability_manager_client.h" #include "access_token.h" -#include "ani.h" #include "ani_error.h" -#include "permission_grant_info.h" -#include "token_callback_stub.h" -#include "ui_content.h" -#include "ui_extension_context.h" - namespace OHOS { namespace Security { namespace AccessToken { @@ -46,19 +33,8 @@ struct AtManagerAsyncContext { AtmResult result; }; -class AniContextCommon { -public: - static constexpr int32_t MAX_PARAMS_ONE = 1; - static constexpr int32_t MAX_PARAMS_TWO = 2; - static constexpr int32_t MAX_PARAMS_THREE = 3; - static constexpr int32_t MAX_PARAMS_FOUR = 4; - static constexpr int32_t MAX_LENGTH = 256; - static constexpr int32_t MAX_WAIT_TIME = 1000; - static constexpr int32_t VALUE_MAX_LEN = 32; -}; - struct PermissionParamCache { - long long sysCommitIdCache = PARAM_DEFAULT_VALUE; + int64_t sysCommitIdCache = PARAM_DEFAULT_VALUE; int32_t commitIdCache = PARAM_DEFAULT_VALUE; int32_t handle = PARAM_DEFAULT_VALUE; std::string sysParamCache; @@ -68,136 +44,6 @@ struct PermissionStatusCache { int32_t status; std::string paramValue; }; - -static PermissionParamCache g_paramCache; -std::map g_cache; - -struct RequestAsyncContext { - AccessTokenID tokenId = 0; - std::string bundleName; - bool needDynamicRequest = true; - 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; - bool uiAbilityFlag = false; - bool uiExtensionFlag = false; - bool uiContentFlag = false; - bool releaseFlag = false; - std::mutex loadlock; -#ifdef EVENTHANDLER_ENABLE - std::shared_ptr handler_ = nullptr; -#endif -}; - -class UIExtensionCallback { -public: - explicit UIExtensionCallback(const std::shared_ptr& reqContext); - ~UIExtensionCallback(); - void SetSessionId(int32_t sessionId); - void OnRelease(int32_t releaseCode); - void OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result); - void OnReceive(const OHOS::AAFwk::WantParams& request); - void OnError(int32_t code, const std::string& name, const std::string& message); - void OnRemoteReady(const std::shared_ptr& uiProxy); - void OnDestroy(); - void ReleaseHandler(int32_t code); - -private: - int32_t sessionId_ = 0; - std::shared_ptr reqContext_ = nullptr; -}; - -class AuthorizationResult : public Security::AccessToken::TokenCallbackStub { -public: - AuthorizationResult(std::shared_ptr& data) : data_(data) {} - virtual ~AuthorizationResult() override = default; - - virtual void GrantResultsCallback( - const std::vector& permissionList, const std::vector& grantResults) override; - virtual void WindowShownCallback() override; - -private: - std::shared_ptr data_ = nullptr; -}; - -class RequestAsyncInstanceControl { -public: - static bool AddCallbackByInstanceId(std::shared_ptr& asyncContext); - static void ExecCallback(int32_t id); - static void CheckDynamicRequest(std::shared_ptr& asyncContext, bool& isDynamic); - -private: - static std::map>> instanceIdMap_; - static std::mutex instanceIdMutex_; -}; - -struct ResultCallback { - std::vector permissions; - std::vector grantResults; - std::vector dialogShownResults; - std::shared_ptr data = nullptr; -}; - -struct RequestPermOnSettingAsyncContext { - AccessTokenID tokenId = 0; - AtmResult result; - PermissionGrantInfo info; - - std::vector permissionList; - napi_value requestResult = nullptr; - std::vector stateList; - - std::shared_ptr abilityContext; - std::shared_ptr uiExtensionContext; - bool uiAbilityFlag = false; - std::mutex loadlock; - -#ifdef EVENTHANDLER_ENABLE - std::shared_ptr handler_ = - std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); -#endif -}; - -class PermissonOnSettingUICallback { -public: - explicit PermissonOnSettingUICallback(ani_env* env, - const std::shared_ptr& reqContext); - ~PermissonOnSettingUICallback(); - void SetSessionId(int32_t sessionId); - void ReleaseHandler(int32_t code); - void OnRelease(int32_t releaseCode); - void OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result); - void OnReceive(const OHOS::AAFwk::WantParams& request); - void OnError(int32_t code, const std::string& name, const std::string& message); - void OnRemoteReady(const std::shared_ptr& uiProxy); - 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/include/ani_common.h b/frameworks/ets/ani/accesstoken/include/ani_common.h new file mode 100644 index 0000000000000000000000000000000000000000..0404544b11cd1063605f5c6cb078e9ceb214c793 --- /dev/null +++ b/frameworks/ets/ani/accesstoken/include/ani_common.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_ETS_ANI_COMMON_H +#define INTERFACES_ETS_ANI_COMMON_H + +#include "ability_context.h" +#include "ani.h" +#include "ani_base_context.h" +#include "ui_content.h" +#include "ui_extension_context.h" + +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); +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif /* INTERFACES_ETS_ANI_COMMON_H */ \ No newline at end of file diff --git a/frameworks/ets/ani/accesstoken/include/ani_request_global_switch_on_setting.h b/frameworks/ets/ani/accesstoken/include/ani_request_global_switch_on_setting.h new file mode 100644 index 0000000000000000000000000000000000000000..d8fb85cf10913174659041e3db097a5d708da23b --- /dev/null +++ b/frameworks/ets/ani/accesstoken/include/ani_request_global_switch_on_setting.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANI_REQUEST_GLOBAL_SWITCHN_ON_SETTING_H +#define ANI_REQUEST_GLOBAL_SWITCHN_ON_SETTING_H + +#include "access_token.h" +#include "ani.h" +#include "ani_common.h" +#include "ani_error.h" +#include "ani_utils.h" +#ifdef EVENTHANDLER_ENABLE +#include "event_handler.h" +#include "event_queue.h" +#endif +#include "permission_grant_info.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +typedef enum { + CAMERA = 0, + MICROPHONE = 1, + LOCATION = 2, +} SwitchType; + +struct RequestGlobalSwitchAsyncContext { + virtual ~RequestGlobalSwitchAsyncContext(); + AccessTokenID tokenId = 0; + AtmResult result; + PermissionGrantInfo info; + + int32_t instanceId = -1; + bool isDynamic = true; + bool switchStatus = false; + int32_t switchType = -1; + + std::shared_ptr abilityContext = nullptr; + std::shared_ptr uiExtensionContext = nullptr; + bool uiAbilityFlag = false; + 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 RequestGlobalSwitchAsyncInstanceControl { + 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 SwitchOnSettingUICallback { +public: + explicit SwitchOnSettingUICallback(const std::shared_ptr& reqContext); + ~SwitchOnSettingUICallback(); + void SetSessionId(int32_t sessionId); + void ReleaseHandler(int32_t code); + void OnRelease(int32_t releaseCode); + void OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result); + void OnReceive(const OHOS::AAFwk::WantParams& request); + void OnError(int32_t code, const std::string& name, const std::string& message); + void OnRemoteReady(const std::shared_ptr& uiProxy); + void OnDestroy(); + +private: + std::shared_ptr reqContext_ = nullptr; + int32_t sessionId_ = 0; +}; + +void RequestGlobalSwitchExecute([[maybe_unused]] ani_env* env, + [[maybe_unused]] ani_object object, ani_object aniContext, ani_int status, ani_object callback); +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif /* ANI_REQUEST_GLOBAL_SWITCHN_ON_SETTING_H */ diff --git a/frameworks/ets/ani/accesstoken/include/ani_request_permission.h b/frameworks/ets/ani/accesstoken/include/ani_request_permission.h new file mode 100644 index 0000000000000000000000000000000000000000..6b4cccf8c84b1aa48811674e5d29632e85822c4f --- /dev/null +++ b/frameworks/ets/ani/accesstoken/include/ani_request_permission.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANI_REQUEST_PERMISSION_H +#define ANI_REQUEST_PERMISSION_H + +#include +#include "access_token.h" +#include "ani.h" +#include "ani_common.h" +#include "ani_error.h" +#include "ani_utils.h" +#ifdef EVENTHANDLER_ENABLE +#include "event_handler.h" +#include "event_queue.h" +#endif +#include "permission_grant_info.h" +#include "token_callback_stub.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +struct RequestAsyncContext { + virtual ~RequestAsyncContext(); + AccessTokenID tokenId = 0; + std::string bundleName; + bool needDynamicRequest = true; + AtmResult result; + int32_t instanceId = -1; + std::vector permissionList; + std::vector grantResults; + std::vector permissionsState; + std::vector dialogShownResults; + std::vector permissionQueryResults; + std::vector errorReasons; + Security::AccessToken::PermissionGrantInfo info; + 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 { +public: + explicit UIExtensionCallback(const std::shared_ptr& reqContext); + ~UIExtensionCallback(); + void SetSessionId(int32_t sessionId); + void OnRelease(int32_t releaseCode); + void OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result); + void OnReceive(const OHOS::AAFwk::WantParams& request); + void OnError(int32_t code, const std::string& name, const std::string& message); + void OnRemoteReady(const std::shared_ptr& uiProxy); + void OnDestroy(); + void ReleaseHandler(int32_t code); + +private: + int32_t sessionId_ = 0; + std::shared_ptr reqContext_ = nullptr; +}; + +class AuthorizationResult : public Security::AccessToken::TokenCallbackStub { +public: + AuthorizationResult(std::shared_ptr& data) : data_(data) {} + virtual ~AuthorizationResult() override = default; + + virtual void GrantResultsCallback( + const std::vector& permissionList, const std::vector& grantResults) override; + virtual void WindowShownCallback() override; + +private: + std::shared_ptr data_ = nullptr; +}; + +class RequestAsyncInstanceControl { +public: + static void AddCallbackByInstanceId(std::shared_ptr& asyncContext); + static void ExecCallback(int32_t id); + static void CheckDynamicRequest(std::shared_ptr& asyncContext, bool& isDynamic); + +private: + static std::map>> instanceIdMap_; + static std::mutex instanceIdMutex_; +}; + +struct ResultCallback { + std::vector permissions; + std::vector grantResults; + std::vector dialogShownResults; + std::shared_ptr data = nullptr; +}; + +void RequestPermissionsFromUserExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_object aniContext, ani_array_ref permissionList, ani_object callback); +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif /* ANI_REQUEST_PERMISSION_H */ diff --git a/frameworks/ets/ani/accesstoken/include/ani_request_permission_on_setting.h b/frameworks/ets/ani/accesstoken/include/ani_request_permission_on_setting.h new file mode 100644 index 0000000000000000000000000000000000000000..5d73f58179d3378d0b2bff811cef19e706f70030 --- /dev/null +++ b/frameworks/ets/ani/accesstoken/include/ani_request_permission_on_setting.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANI_REQUEST_PERMISSION_ON_SETTING_H +#define ANI_REQUEST_PERMISSION_ON_SETTING_H + +#include "access_token.h" +#include "ani.h" +#include "ani_common.h" +#include "ani_error.h" +#include "ani_utils.h" +#ifdef EVENTHANDLER_ENABLE +#include "event_handler.h" +#include "event_queue.h" +#endif +#include "permission_grant_info.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +struct RequestPermOnSettingAsyncContext { + virtual ~RequestPermOnSettingAsyncContext(); + AccessTokenID tokenId = 0; + AtmResult result; + PermissionGrantInfo info; + + int32_t instanceId = -1; + bool isDynamic = true; + std::vector permissionList; + ani_object requestResult = nullptr; + std::vector stateList; + + std::shared_ptr abilityContext = nullptr; + std::shared_ptr uiExtensionContext = nullptr; + bool uiAbilityFlag = false; + 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(const std::shared_ptr& reqContext); + ~PermissonOnSettingUICallback(); + void SetSessionId(int32_t sessionId); + void ReleaseHandler(int32_t code); + void OnRelease(int32_t releaseCode); + void OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result); + void OnReceive(const OHOS::AAFwk::WantParams& request); + void OnError(int32_t code, const std::string& name, const std::string& message); + void OnRemoteReady(const std::shared_ptr& uiProxy); + void OnDestroy(); + +private: + std::shared_ptr reqContext_ = nullptr; + int32_t sessionId_ = 0; +}; + +void RequestPermissionOnSettingExecute([[maybe_unused]] ani_env* env, + [[maybe_unused]] ani_object object, ani_object aniContext, ani_array_ref permissionList, ani_object callback); +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif /* ANI_REQUEST_PERMISSION_ON_SETTING_H */ 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 a933ddda47c1c713b24f7bf756ea8707a775e849..95a56c4fd9a2a34ae0bff03fb5e9e5df6bb8920b 100644 --- a/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp +++ b/frameworks/ets/ani/accesstoken/src/ani_ability_access_ctrl.cpp @@ -16,759 +16,31 @@ #include "ani_ability_access_ctrl.h" #include -#include +#include +#include -#include "access_token.h" #include "access_token_error.h" #include "accesstoken_kit.h" #include "accesstoken_log.h" -#include "ani_base_context.h" -#include "ani_error.h" -#include "ani_utils.h" +#include "ani_request_global_switch_on_setting.h" +#include "ani_request_permission.h" +#include "ani_request_permission_on_setting.h" #include "hisysevent.h" #include "parameter.h" #include "permission_list_state.h" #include "permission_map.h" #include "token_setproc.h" -#include "want.h" namespace OHOS { 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; -const int32_t PERM_NOT_BELONG_TO_SAME_GROUP = 2; -const int32_t PERM_IS_NOT_DECLARE = 3; -const int32_t ALL_PERM_GRANTED = 4; -const int32_t PERM_REVOKE_BY_USER = 5; -std::condition_variable g_loadedCond; +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AniAbilityAccessCtrl" }; +constexpr int32_t VALUE_MAX_LEN = 32; std::mutex g_lockCache; - +static PermissionParamCache g_paramCache; +std::map g_cache; static constexpr const char* PERMISSION_STATUS_CHANGE_KEY = "accesstoken.permission.change"; - -const std::string PERMISSION_KEY = "ohos.user.grant.permission"; -const std::string PERMISSION_SETTING_KEY = "ohos.user.setting.permission"; -const std::string STATE_KEY = "ohos.user.grant.permission.state"; -const std::string RESULT_KEY = "ohos.user.grant.permission.result"; -const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType"; -const std::string UI_EXTENSION_TYPE = "sys/commonUI"; -const std::string ORI_PERMISSION_MANAGER_BUNDLE_NAME = "com.ohos.permissionmanager"; -const std::string TOKEN_KEY = "ohos.ability.params.token"; -const std::string CALLBACK_KEY = "ohos.ability.params.callback"; -const std::string WINDOW_RECTANGLE_LEFT_KEY = "ohos.ability.params.request.left"; -const std::string WINDOW_RECTANGLE_TOP_KEY = "ohos.ability.params.request.top"; -const std::string WINDOW_RECTANGLE_HEIGHT_KEY = "ohos.ability.params.request.height"; -const std::string WINDOW_RECTANGLE_WIDTH_KEY = "ohos.ability.params.request.width"; -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"; - -#define SETTER_METHOD_NAME(property) "" #property -#define ANI_AUTO_SIZE SIZE_MAX - -static void UpdateGrantPermissionResultOnly(const std::vector& permissions, - const std::vector& grantResults, std::shared_ptr& data, std::vector& newGrantResults) -{ - size_t size = permissions.size(); - 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.errorCode == AccessToken::RET_SUCCESS ? grantResults[i] : AccessToken::INVALID_OPER; - } - newGrantResults.emplace_back(result); - } -} - -static bool IsDynamicRequest(std::shared_ptr& asyncContext) -{ - if (asyncContext == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "asyncContext nullptr"); - return false; - } - std::vector permList; - for (const auto& permission : asyncContext->permissionList) { - AccessToken::PermissionListState permState; - permState.permissionName = permission; - permState.errorReason = SERVICE_ABNORMAL; - permState.state = AccessToken::INVALID_OPER; - permList.emplace_back(permState); - } - auto ret = AccessToken::AccessTokenKit::GetSelfPermissionsState(permList, asyncContext->info); - ACCESSTOKEN_LOG_INFO(LABEL, - "TokenID: %{public}d, bundle: %{public}s, uiExAbility: %{public}s, serExAbility: %{public}s.", - asyncContext->tokenId, asyncContext->info.grantBundleName.c_str(), asyncContext->info.grantAbilityName.c_str(), - asyncContext->info.grantServiceAbilityName.c_str()); - if (ret == AccessToken::FORBIDDEN_OPER) { - ACCESSTOKEN_LOG_ERROR(LABEL, "FORBIDDEN_OPER"); - for (auto& perm : permList) { - perm.state = AccessToken::INVALID_OPER; - perm.errorReason = PRIVACY_STATEMENT_NOT_AGREED; - } - } - for (const auto& permState : permList) { - ACCESSTOKEN_LOG_INFO(LABEL, "Permission: %{public}s: state: %{public}d, errorReason: %{public}d", - permState.permissionName.c_str(), permState.state, permState.errorReason); - asyncContext->permissionsState.emplace_back(permState.state); - asyncContext->dialogShownResults.emplace_back(permState.state == AccessToken::TypePermissionOper::DYNAMIC_OPER); - asyncContext->errorReasons.emplace_back(permState.errorReason); - } - if (permList.size() != asyncContext->permissionList.size()) { - ACCESSTOKEN_LOG_ERROR(LABEL, "permList.size: %{public}zu, permissionList.size: %{public}zu", permList.size(), - asyncContext->permissionList.size()); - return false; - } - return ret == AccessToken::TypePermissionOper::DYNAMIC_OPER; -} - -static OHOS::Ace::UIContent* GetUIContent(const std::shared_ptr& abilityContext, - std::shared_ptr& uiExtensionContext, bool uiAbilityFlag) -{ - OHOS::Ace::UIContent* uiContent = nullptr; - if (uiAbilityFlag) { - if (abilityContext == nullptr) { - return nullptr; - } - uiContent = abilityContext->GetUIContent(); - } else { - if (uiExtensionContext == nullptr) { - return nullptr; - } - uiContent = uiExtensionContext->GetUIContent(); - } - return uiContent; -} - -static void CreateUIExtensionMainThread(std::shared_ptr& asyncContext, - const OHOS::AAFwk::Want& want, const OHOS::Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks, - const std::shared_ptr& uiExtCallback) -{ - auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() { - OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, - asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); - if (uiContent == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - asyncContext->result.errorCode = AccessToken::RET_FAILED; - asyncContext->uiExtensionFlag = false; - asyncContext->loadlock.unlock(); - return; - } - - OHOS::Ace::ModalUIExtensionConfig config; - config.isProhibitBack = true; - int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config); - if (sessionId == 0) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Create component failed, sessionId is 0"); - asyncContext->result.errorCode = AccessToken::RET_FAILED; - asyncContext->uiExtensionFlag = false; - asyncContext->loadlock.unlock(); - return; - } - uiExtCallback->SetSessionId(sessionId); - }; -#ifdef EVENTHANDLER_ENABLE - if (asyncContext->handler_ != nullptr) { - asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread"); - } else { - task(); - } -#else - task(); -#endif -} - -static bool CreateServiceExtension(std::shared_ptr& asyncContext) -{ - if (!asyncContext->uiAbilityFlag) { - ACCESSTOKEN_LOG_ERROR(LABEL, "UIExtension ability can not pop service ablility window!"); - asyncContext->needDynamicRequest = false; - 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.errorCode = RET_FAILED; - return false; - } - OHOS::AAFwk::Want want; - want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantServiceAbilityName); - want.SetParam(PERMISSION_KEY, asyncContext->permissionList); - want.SetParam(STATE_KEY, asyncContext->permissionsState); - want.SetParam(TOKEN_KEY, asyncContext->abilityContext->GetToken()); - want.SetParam(CALLBACK_KEY, remoteObject); - - int32_t left; - int32_t top; - int32_t width; - int32_t height; - asyncContext->abilityContext->GetWindowRect(left, top, width, height); - want.SetParam(WINDOW_RECTANGLE_LEFT_KEY, left); - want.SetParam(WINDOW_RECTANGLE_TOP_KEY, top); - want.SetParam(WINDOW_RECTANGLE_WIDTH_KEY, width); - want.SetParam(WINDOW_RECTANGLE_HEIGHT_KEY, height); - want.SetParam(REQUEST_TOKEN_KEY, asyncContext->abilityContext->GetToken()); - int32_t ret = OHOS::AAFwk::AbilityManagerClient::GetInstance()->RequestDialogService( - want, asyncContext->abilityContext->GetToken()); - ACCESSTOKEN_LOG_INFO(LABEL, "Request end, ret: %{public}d, tokenId: %{public}d, permNum: %{public}zu", ret, - asyncContext->tokenId, asyncContext->permissionList.size()); - return true; -} - -static bool CreateUIExtension(std::shared_ptr& asyncContext) -{ - OHOS::AAFwk::Want want; - want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantAbilityName); - want.SetParam(PERMISSION_KEY, asyncContext->permissionList); - want.SetParam(STATE_KEY, asyncContext->permissionsState); - want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE); - - auto uiExtCallback = std::make_shared(asyncContext); - OHOS::Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = { - [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); }, - [uiExtCallback]( - int32_t resultCode, const OHOS::AAFwk::Want& result) { uiExtCallback->OnResult(resultCode, result); }, - [uiExtCallback](const OHOS::AAFwk::WantParams& receive) { uiExtCallback->OnReceive(receive); }, - [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]] const std::string& message) { - uiExtCallback->OnError(code, name, name); - }, - [uiExtCallback](const std::shared_ptr& uiProxy) { - uiExtCallback->OnRemoteReady(uiProxy); - }, - [uiExtCallback]() { uiExtCallback->OnDestroy(); }, - }; - CreateUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback); - return true; -} - -static void GetInstanceId(std::shared_ptr& asyncContext) -{ - auto task = [asyncContext]() { - OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, - asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); - if (uiContent == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - return; - } - asyncContext->uiContentFlag = true; - asyncContext->instanceId = uiContent->GetInstanceId(); - }; -#ifdef EVENTHANDLER_ENABLE - if (asyncContext->handler_ != nullptr) { - asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId"); - } else { - task(); - } -#else - task(); -#endif -} - -static ani_ref ConvertAniArrayString(ani_env* env, const std::vector& cArray) -{ - ani_size length = cArray.size(); - ani_array_ref aArrayRef = nullptr; - ani_class aStringcls = nullptr; - if (env->FindClass("Lstd/core/String;", &aStringcls) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString FindClass String failed"); - return nullptr; - } - ani_ref undefinedRef = nullptr; - if (ANI_OK != env->GetUndefined(&undefinedRef)) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString GetUndefined failed"); - return nullptr; - } - if (env->Array_New_Ref(aStringcls, length, undefinedRef, &aArrayRef) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString Array_New_Ref failed "); - return nullptr; - } - ani_string aString = nullptr; - for (ani_size i = 0; i < length; ++i) { - env->String_NewUTF8(cArray[i].c_str(), cArray[i].size(), &aString); - env->Array_Set_Ref(aArrayRef, i, aString); - } - ani_ref aRef = nullptr; - if (env->GlobalReference_Create(aArrayRef, &aRef) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString GlobalReference_Create failed "); - return nullptr; - } - return aRef; -} - -static ani_ref ConvertAniArrayInt(ani_env* env, const std::vector& cArray) -{ - ani_size length = cArray.size(); - ani_array_int aArrayInt = nullptr; - if (env->Array_New_Int(length, &aArrayInt) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayInt Array_New_Int failed "); - return nullptr; - } - for (ani_size i = 0; i < length; ++i) { - env->Array_SetRegion_Int(aArrayInt, i, length, &cArray[i]); - } - ani_ref aRef = nullptr; - if (env->GlobalReference_Create(aArrayInt, &aRef) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayInt GlobalReference_Create failed "); - return nullptr; - } - return aRef; -} - -static ani_ref ConvertAniArrayBool(ani_env* env, const std::vector& cArray) -{ - ani_size length = cArray.size(); - ani_array_boolean aArrayBool = nullptr; - if (env->Array_New_Boolean(length, &aArrayBool) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayBool Array_New_Boolean failed "); - return nullptr; - } - std::vector boolArray(length); - for (ani_size i = 0; i < length; ++i) { - boolArray[i] = cArray[i]; - } - for (ani_size i = 0; i < length; ++i) { - env->Array_SetRegion_Boolean(aArrayBool, i, length, &boolArray[i]); - } - ani_ref aRef = nullptr; - if (env->GlobalReference_Create(aArrayBool, &aRef) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayBool GlobalReference_Create failed "); - return nullptr; - } - return aRef; -} - -template -static inline bool CallSetter(ani_env* env, ani_class cls, ani_object object, const char* setterName, valueType value) -{ - ani_status status = ANI_ERROR; - ani_field fieldValue; - if (env->Class_FindField(cls, setterName, &fieldValue) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Class_FindField Fail %{public}d ", status); - return false; - } - if ((status = env->Object_SetField_Ref(object, fieldValue, value)) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Object_SetField_Ref Fail %{public}d ", status); - return false; - } - return true; -} - -static bool ProcessArrayString([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, - ani_array_ref arrayObj, std::vector& permissionList) -{ - ani_size length; - if (ANI_OK != env->Array_GetLength(arrayObj, &length)) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Array_GetLength FAILED"); - return false; - } - for (ani_size i = 0; i < length; i++) { - ani_ref stringEntryRef; - if (ANI_OK != env->Object_CallMethodByName_Ref( - arrayObj, "$_get", "I:Lstd/core/Object;", &stringEntryRef, static_cast(i))) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Object_CallMethodByName_Ref _get Failed"); - return false; - } - auto strEntryRef = ANIStringToStdString(env, static_cast(stringEntryRef)); - if (strEntryRef.empty()) { - return false; - } else { - permissionList.emplace_back(strEntryRef); - } - } - return true; -} - -static ani_object WrapResult(ani_env* env, std::shared_ptr& asyncContext) -{ - ani_status status = ANI_ERROR; - ani_class cls = nullptr; - if ((status = env->FindClass("Lsecurity/PermissionRequestResult/PermissionRequestResult;", &cls)) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass status %{public}d ", static_cast(status)); - return nullptr; - } - if (cls == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "null cls"); - return nullptr; - } - ani_method method = nullptr; - if ((status = env->Class_FindMethod(cls, "", ":V", &method)) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Class_FindMethod status %{public}d ", static_cast(status)); - return nullptr; - } - ani_object aObject = nullptr; - if ((status = env->Object_New(cls, method, &aObject)) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Object_New status %{public}d ", static_cast(status)); - return nullptr; - } - auto state = asyncContext->needDynamicRequest ? asyncContext->grantResults : asyncContext->permissionsState; - ani_ref strPermissions = ConvertAniArrayString(env, asyncContext->permissionList); - ani_ref intAuthResults = ConvertAniArrayInt(env, state); - ani_ref boolDialogShownResults = ConvertAniArrayBool(env, asyncContext->dialogShownResults); - ani_ref intPermissionQueryResults = ConvertAniArrayInt(env, asyncContext->permissionQueryResults); - if (strPermissions == nullptr || intAuthResults == nullptr || boolDialogShownResults == nullptr || - intPermissionQueryResults == nullptr) { - asyncContext->result.errorCode = RET_FAILED; - return nullptr; - } - if (!CallSetter(env, cls, aObject, SETTER_METHOD_NAME(permissions), strPermissions) || - !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(authResults), intAuthResults) || - !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(dialogShownResults), boolDialogShownResults) || - !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(errorReasons), intPermissionQueryResults)) { - asyncContext->result.errorCode = RET_FAILED; - return nullptr; - } - return aObject; -} - -static ani_object DealWithResult(ani_env* env, std::shared_ptr& asyncContext) -{ - ani_object resultObj = nullptr; - if (asyncContext->result.errorCode == RET_SUCCESS) { - resultObj = WrapResult(env, asyncContext); - } - if (asyncContext->result.errorCode != RET_SUCCESS) { - int32_t stsCode = BusinessErrorAni::GetStsErrorCode(asyncContext->result.errorCode); - BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode, asyncContext->result.errorMsg)); - return nullptr; - } - return resultObj; -} - -static void RequestResultsHandler(const std::vector& permissionList, - const std::vector& permissionStates, std::shared_ptr& data) -{ - if (data->result.errorCode != RET_SUCCESS) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Result is: %{public}d", data->result.errorCode); - data->result.errorCode = RET_FAILED; - } - std::vector newGrantResults; - UpdateGrantPermissionResultOnly(permissionList, permissionStates, data, newGrantResults); - if (newGrantResults.empty()) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResults empty"); - data->result.errorCode = RET_FAILED; - } - data->grantResults.assign(newGrantResults.begin(), newGrantResults.end()); - data->loadlock.unlock(); - g_loadedCond.notify_all(); -} - -static ani_status ConvertContext( - ani_env* env, const ani_object& aniContext, std::shared_ptr& asyncContext) -{ - auto context = OHOS::AbilityRuntime::GetStageModeContext(env, aniContext); - if (context == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetStageModeContext failed"); - return ANI_ERROR; - } - asyncContext->abilityContext = - OHOS::AbilityRuntime::Context::ConvertTo(context); - if (asyncContext->abilityContext != nullptr) { - auto abilityInfo = asyncContext->abilityContext->GetApplicationInfo(); - if (abilityInfo == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); - return ANI_ERROR; - } - asyncContext->uiAbilityFlag = true; - asyncContext->tokenId = abilityInfo->accessTokenId; - asyncContext->bundleName = abilityInfo->bundleName; - } else { - asyncContext->uiExtensionContext = - OHOS::AbilityRuntime::Context::ConvertTo(context); - if (asyncContext->uiExtensionContext == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertTo UIExtensionContext failed"); - return ANI_ERROR; - } - auto uiExtensionInfo = asyncContext->uiExtensionContext->GetApplicationInfo(); - if (uiExtensionInfo == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); - return ANI_ERROR; - } - asyncContext->tokenId = uiExtensionInfo->accessTokenId; - asyncContext->bundleName = uiExtensionInfo->bundleName; - } - return ANI_OK; -} - -static bool ParseRequestPermissionFromUser(ani_env* env, ani_object aniContext, ani_array_ref permissionList, - std::shared_ptr& asyncContext) -{ - if (ConvertContext(env, aniContext, asyncContext) != ANI_OK) { - 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, STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionList", "Array")); - return false; - } - return true; -} - -static bool RequestPermissionsFromUserProcess([[maybe_unused]] ani_env* env, - 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.errorCode == RET_SUCCESS)) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResults empty"); - asyncContext->result.errorCode = RET_FAILED; - } - return false; - } - 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); - } else { - lockFlag = CreateServiceExtension(asyncContext); - } - } else if (asyncContext->instanceId == -1) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Pop service extension dialog, instanceId is -1."); - lockFlag = 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); - 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); - } - } - 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) -{ - if (env == nullptr || permissionList == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "permissionList or env null"); - return nullptr; - } - std::shared_ptr asyncContext = std::make_shared(); - if (!ParseRequestPermissionFromUser(env, aniContext, permissionList, asyncContext)) { - return nullptr; - } -#ifdef EVENTHANDLER_ENABLE - asyncContext->handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); -#endif - 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); - std::string errMsg = GetErrorMessage( - STS_ERROR_INNER, "The specified context does not belong to the current application."); - BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, errMsg); - return nullptr; - } - if (!RequestPermissionsFromUserProcess(env, asyncContext)) { - return DealWithResult(env, asyncContext); - } - 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) -{ - auto task = [asyncContext, sessionId]() { - Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, - asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); - if (uiContent == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - asyncContext->result.errorCode = RET_FAILED; - return; - } - uiContent->CloseModalUIExtension(sessionId); - ACCESSTOKEN_LOG_INFO(LABEL, "Close end, sessionId: %{public}d", sessionId); - }; -#ifdef EVENTHANDLER_ENABLE - if (asyncContext->handler_ != nullptr) { - asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread"); - } else { - task(); - } -#else - task(); -#endif - ACCESSTOKEN_LOG_INFO(LABEL, "Instance id: %{public}d", asyncContext->instanceId); -} - -void RequestAsyncInstanceControl::ExecCallback(int32_t id) -{ - std::shared_ptr asyncContext = nullptr; - bool isDynamic = false; - { - std::lock_guard lock(instanceIdMutex_); - auto iter = RequestAsyncInstanceControl::instanceIdMap_.find(id); - if (iter == RequestAsyncInstanceControl::instanceIdMap_.end()) { - ACCESSTOKEN_LOG_ERROR(LABEL, "instanceIdMap_ empty"); - return; - } - while (!iter->second.empty()) { - asyncContext = iter->second[0]; - iter->second.erase(iter->second.begin()); - CheckDynamicRequest(asyncContext, isDynamic); - if (isDynamic) { - break; - } - } - if (iter->second.empty()) { - RequestAsyncInstanceControl::instanceIdMap_.erase(id); - } - } - bool lockFlag = true; - if (isDynamic) { - if (asyncContext->uiExtensionFlag) { - lockFlag = CreateUIExtension(asyncContext); - } else { - lockFlag = CreateServiceExtension(asyncContext); - } - } - if (!lockFlag) { - asyncContext->loadlock.unlock(); - } -} - -void RequestAsyncInstanceControl::CheckDynamicRequest( - std::shared_ptr& asyncContext, bool& isDynamic) -{ - asyncContext->permissionsState.clear(); - asyncContext->dialogShownResults.clear(); - if (!IsDynamicRequest(asyncContext)) { - RequestResultsHandler(asyncContext->permissionList, asyncContext->permissionsState, asyncContext); - return; - } - isDynamic = true; -} - -bool 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; - } - RequestAsyncInstanceControl::instanceIdMap_[asyncContext->instanceId] = {}; - bool lockFlag = true; - if (asyncContext->uiExtensionFlag) { - lockFlag = CreateUIExtension(asyncContext); - } else { - lockFlag = CreateServiceExtension(asyncContext); - } - return lockFlag; -} - -UIExtensionCallback::UIExtensionCallback(const std::shared_ptr& reqContext) -{ - this->reqContext_ = reqContext; -} - -UIExtensionCallback::~UIExtensionCallback() {} - -void UIExtensionCallback::SetSessionId(int32_t sessionId) -{ - this->sessionId_ = sessionId; -} - -void UIExtensionCallback::ReleaseHandler(int32_t code) -{ - { - std::lock_guard lock(g_lockFlag); - if (this->reqContext_->releaseFlag) { - ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed."); - return; - } - this->reqContext_->releaseFlag = true; - } - CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_); - this->reqContext_->result.errorCode = code; - 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); - this->reqContext_->permissionList = result.GetStringArrayParam(PERMISSION_KEY); - this->reqContext_->permissionsState = result.GetIntArrayParam(RESULT_KEY); - ReleaseHandler(0); -} - -void UIExtensionCallback::OnReceive(const OHOS::AAFwk::WantParams& receive) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "Called!"); -} - -void UIExtensionCallback::OnRelease(int32_t releaseCode) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "ReleaseCode is %{public}d", releaseCode); - ReleaseHandler(-1); -} - -void UIExtensionCallback::OnError(int32_t code, const std::string& name, const std::string& message) -{ - ACCESSTOKEN_LOG_INFO( - LABEL, "Code is %{public}d, name is %{public}s, message is %{public}s", code, name.c_str(), message.c_str()); - - ReleaseHandler(-1); -} - -void UIExtensionCallback::OnRemoteReady(const std::shared_ptr& uiProxy) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "Connect to UIExtensionAbility successfully."); -} - -void UIExtensionCallback::OnDestroy() -{ - ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed."); - ReleaseHandler(-1); -} - -void AuthorizationResult::GrantResultsCallback( - const std::vector& permissionList, const std::vector& grantResults) -{ - std::shared_ptr asyncContext = data_; - if (asyncContext == nullptr) { - return; - } - RequestResultsHandler(permissionList, grantResults, asyncContext); -} - -void AuthorizationResult::WindowShownCallback() -{ - std::shared_ptr asyncContext = data_; - if (asyncContext == nullptr) { - return; - } - OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, - asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); - if ((uiContent == nullptr) || !(asyncContext->uiContentFlag)) { - return; - } - RequestAsyncInstanceControl::ExecCallback(asyncContext->instanceId); } static ani_object CreateAtManager([[maybe_unused]] ani_env* env) @@ -801,7 +73,7 @@ static ani_object CreateAtManager([[maybe_unused]] ani_env* env) static std::string GetPermParamValue() { - long long sysCommitId = GetSystemCommitId(); + int64_t sysCommitId = GetSystemCommitId(); if (sysCommitId == g_paramCache.sysCommitIdCache) { ACCESSTOKEN_LOG_DEBUG(LABEL, "SysCommitId = %{public}lld", sysCommitId); return g_paramCache.sysParamCache; @@ -818,8 +90,8 @@ static std::string GetPermParamValue() int32_t currCommitId = static_cast(GetParameterCommitId(g_paramCache.handle)); if (currCommitId != g_paramCache.commitIdCache) { - char value[AniContextCommon::VALUE_MAX_LEN] = { 0 }; - auto ret = GetParameterValue(g_paramCache.handle, value, AniContextCommon::VALUE_MAX_LEN - 1); + char value[VALUE_MAX_LEN] = { 0 }; + auto ret = GetParameterValue(g_paramCache.handle, value, VALUE_MAX_LEN - 1); if (ret < 0) { ACCESSTOKEN_LOG_ERROR(LABEL, "Return default value, ret=%{public}d", ret); return "-1"; @@ -856,25 +128,22 @@ static void UpdatePermissionCache(AtManagerAsyncContext* asyncContext) } } -static ani_int CheckAccessTokenSync([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, - ani_int tokenID, ani_string permissionName) +static ani_int CheckAccessTokenExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_int aniTokenID, ani_string aniPermission) { if (env == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "nullptr env"); return AccessToken::PermissionState::PERMISSION_DENIED; } - if (tokenID == 0) { - std::string errMsg = GetErrorMessage(STS_ERROR_PARAM_INVALID, "The tokenID is 0."); - BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); - return AccessToken::PermissionState::PERMISSION_DENIED; - } - std::string stdPermissionName = ANIStringToStdString(env, static_cast(permissionName)); - if (stdPermissionName.empty() || stdPermissionName.length() > 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); + AccessTokenID tokenID = static_cast(aniTokenID); + std::string permissionName = ANIStringToStdString(env, static_cast(aniPermission)); + if ((!BusinessErrorAni::ValidateTokenIDdWithThrowError(env, tokenID)) || + (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName))) { + ACCESSTOKEN_LOG_ERROR(LABEL, "TokenId(%{public}u) or Permission(%{public}s) is invalid.", + tokenID, permissionName.c_str()); return AccessToken::PermissionState::PERMISSION_DENIED; } + auto* asyncContext = new (std::nothrow) AtManagerAsyncContext(); if (asyncContext == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "New struct fail."); @@ -882,452 +151,39 @@ static ani_int CheckAccessTokenSync([[maybe_unused]] ani_env* env, [[maybe_unuse } std::unique_ptr context {asyncContext}; asyncContext->tokenId = static_cast(tokenID); - asyncContext->permissionName = stdPermissionName; + asyncContext->permissionName = permissionName; static uint64_t selfTokenId = GetSelfTokenID(); if (asyncContext->tokenId != static_cast(selfTokenId)) { - asyncContext->grantStatus = AccessToken::AccessTokenKit::VerifyAccessToken(tokenID, stdPermissionName); + asyncContext->grantStatus = AccessToken::AccessTokenKit::VerifyAccessToken(tokenID, permissionName); return static_cast(asyncContext->grantStatus); } UpdatePermissionCache(asyncContext); - ACCESSTOKEN_LOG_INFO(LABEL, "CheckAccessTokenSync result : %{public}d", asyncContext->grantStatus); + ACCESSTOKEN_LOG_INFO(LABEL, "CheckAccessTokenExecute result : %{public}d", asyncContext->grantStatus); return static_cast(asyncContext->grantStatus); } -static ani_status GetContext( - ani_env* env, const ani_object& aniContext, std::shared_ptr& asyncContext) -{ - auto context = OHOS::AbilityRuntime::GetStageModeContext(env, aniContext); - if (context == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetStageModeContext failed"); - return ANI_ERROR; - } - asyncContext->abilityContext = - OHOS::AbilityRuntime::Context::ConvertTo(context); - if (asyncContext->abilityContext != nullptr) { - auto abilityInfo = asyncContext->abilityContext->GetApplicationInfo(); - if (abilityInfo == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); - return ANI_ERROR; - } - asyncContext->uiAbilityFlag = true; - asyncContext->tokenId = abilityInfo->accessTokenId; - } else { - asyncContext->uiExtensionContext = - OHOS::AbilityRuntime::Context::ConvertTo(context); - if (asyncContext->uiExtensionContext == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertTo UIExtensionContext failed"); - return ANI_ERROR; - } - auto uiExtensionInfo = asyncContext->uiExtensionContext->GetApplicationInfo(); - if (uiExtensionInfo == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); - return ANI_ERROR; - } - asyncContext->tokenId = uiExtensionInfo->accessTokenId; - } - return ANI_OK; -} - -static bool ParseRequestPermissionOnSetting(ani_env* env, ani_object& aniContext, ani_array_ref& permissionList, - std::shared_ptr& asyncContext) -{ - if (GetContext(env, aniContext, asyncContext) != ANI_OK) { - 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, STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionList", "Array")); - return false; - } - return true; -} - -static void StateToEnumIndex(int32_t state, ani_size& enumIndex) -{ - if (state == 0) { - enumIndex = 1; - } else { - enumIndex = 0; - } -} - -static ani_ref ReturnResult(ani_env* env, std::shared_ptr& asyncContext) -{ - ani_class arrayCls = nullptr; - if (env->FindClass("Lescompat/Array;", &arrayCls) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass name Lescompat/Array failed!"); - return nullptr; - } - - ani_method arrayCtor; - if (env->Class_FindMethod(arrayCls, "", "I:V", &arrayCtor) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass failed!"); - return nullptr; - } - - ani_object arrayObj; - if (env->Object_New(arrayCls, arrayCtor, &arrayObj, asyncContext->stateList.size()) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Object new failed!"); - return nullptr; - } - - const char* enumDescriptor = "L@ohos/abilityAccessCtrl/abilityAccessCtrl/GrantStatus;"; - ani_enum enumType; - if (env->FindEnum(enumDescriptor, &enumType) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass name %{public}s failed!", enumDescriptor); - return nullptr; - } - - ani_size index = 0; - for (const auto& state: asyncContext->stateList) { - ani_enum_item enumItem; - ani_size enumIndex = 0; - StateToEnumIndex(state, enumIndex); - if (env->Enum_GetEnumItemByIndex(enumType, enumIndex, &enumItem) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "GetEnumItemByIndex value %{public}u failed!", state); - break; - } - - if (env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", index, enumItem) != ANI_OK) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Object_CallMethodByName_Void $_set failed!"); - break; - } - index++; - } - - return arrayObj; -} - -static int32_t TransferToStsErrorCode(int32_t errorCode) -{ - int32_t stsCode = STS_OK; - switch (errorCode) { - case RET_SUCCESS: - stsCode = STS_OK; - break; - case REQUEST_REALDY_EXIST: - stsCode = STS_ERROR_REQUEST_IS_ALREADY_EXIST; - break; - case PERM_NOT_BELONG_TO_SAME_GROUP: - stsCode = STS_ERROR_PARAM_INVALID; - break; - case PERM_IS_NOT_DECLARE: - stsCode = STS_ERROR_PARAM_INVALID; - break; - case ALL_PERM_GRANTED: - stsCode = STS_ERROR_ALL_PERM_GRANTED; - break; - case PERM_REVOKE_BY_USER: - stsCode = STS_ERROR_PERM_REVOKE_BY_USER; - break; - default: - stsCode = STS_ERROR_INNER; - break; - } - ACCESSTOKEN_LOG_ERROR(LABEL, "Dialog error(%{public}d) stsCode(%{public}d).", errorCode, stsCode); - return stsCode; -} - -static ani_ref RequestPermissionOnSettingComplete( - ani_env* env, std::shared_ptr& asyncContext) -{ - if (asyncContext->result.errorCode == RET_SUCCESS) { - ani_ref result = ReturnResult(env, asyncContext); - if (result != nullptr) { - return result; - } - asyncContext->result.errorCode = RET_FAILED; - } - - int32_t stsCode = TransferToStsErrorCode(asyncContext->result.errorCode); - BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); - return nullptr; -} - -PermissonOnSettingUICallback::PermissonOnSettingUICallback(ani_env* env, - const std::shared_ptr& reqContext) -{ - this->env_ = env; - this->reqContext_ = reqContext; -} - -PermissonOnSettingUICallback::~PermissonOnSettingUICallback() -{} - -void PermissonOnSettingUICallback::SetSessionId(int32_t sessionId) -{ - this->sessionId_ = sessionId; -} - -static void CloseSettingModalUIExtensionMainThread(std::shared_ptr& asyncContext, - int32_t sessionId) -{ - auto task = [asyncContext, sessionId]() { - Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, - asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); - if (uiContent == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); - asyncContext->result.errorCode = RET_FAILED; - return; - } - uiContent->CloseModalUIExtension(sessionId); - ACCESSTOKEN_LOG_INFO(LABEL, "Close end, sessionId: %{public}d", sessionId); - }; -#ifdef EVENTHANDLER_ENABLE - if (asyncContext->handler_ != nullptr) { - asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread"); - } else { - task(); - } -#else - task(); -#endif -} - -void PermissonOnSettingUICallback::ReleaseHandler(int32_t code) -{ - { - std::lock_guard lock(this->lockReleaseFlag); - if (this->releaseFlag) { - ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed."); - return; - } - this->releaseFlag = true; - } - CloseSettingModalUIExtensionMainThread(this->reqContext_, this->sessionId_); - if (code == -1) { - this->reqContext_->result.errorCode = code; - } - this->reqContext_->loadlock.unlock(); - std::lock_guard lock(g_lockWindowFlag); - g_windowFlag = false; -} - -/* - * when UIExtensionAbility use terminateSelfWithResult - */ -void PermissonOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result) -{ - 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, listSize=%{public}zu.", - resultCode, this->reqContext_->stateList.size()); - ReleaseHandler(0); -} - -/* - * when UIExtensionAbility send message to UIExtensionComponent - */ -void PermissonOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "Called!"); -} - -/* - * when UIExtensionAbility disconnect or use terminate or process die - * releaseCode is 0 when process normal exit - */ -void PermissonOnSettingUICallback::OnRelease(int32_t releaseCode) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "ReleaseCode is %{public}d", releaseCode); - - ReleaseHandler(-1); -} - -/* - * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error - */ -void PermissonOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "Code is %{public}d, name is %{public}s, message is %{public}s", - code, name.c_str(), message.c_str()); - - ReleaseHandler(-1); -} - -/* - * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init, - * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy - */ -void PermissonOnSettingUICallback::OnRemoteReady(const std::shared_ptr& uiProxy) -{ - ACCESSTOKEN_LOG_INFO(LABEL, "Connect to UIExtensionAbility successfully."); -} - -/* - * when UIExtensionComponent destructed - */ -void PermissonOnSettingUICallback::OnDestroy() -{ - ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed."); - ReleaseHandler(-1); -} - -static void CreateSettingUIExtensionMainThread(std::shared_ptr& asyncContext, - const AAFwk::Want& want, const Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks, - const std::shared_ptr& uiExtCallback) -{ - auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() { - Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, - asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); - if (uiContent == nullptr) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to get ui content!"); - asyncContext->result.errorCode = RET_FAILED; - return; - } - - Ace::ModalUIExtensionConfig config; - config.isProhibitBack = true; - int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config); - ACCESSTOKEN_LOG_INFO(LABEL, "Create end, sessionId: %{public}d, tokenId: %{public}d.", - sessionId, asyncContext->tokenId); - if (sessionId == 0) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create component, sessionId is 0."); - asyncContext->result.errorCode = RET_FAILED; - return; - } - uiExtCallback->SetSessionId(sessionId); - }; -#ifdef EVENTHANDLER_ENABLE - if (asyncContext->handler_ != nullptr) { - asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread"); - } else { - task(); - } -#else - task(); -#endif -} - -static bool StartUIExtension(ani_env* env, 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); - Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = { - [uiExtCallback](int32_t releaseCode) { - uiExtCallback->OnRelease(releaseCode); - }, - [uiExtCallback](int32_t resultCode, const AAFwk::Want& result) { - uiExtCallback->OnResult(resultCode, result); - }, - [uiExtCallback](const AAFwk::WantParams& receive) { - uiExtCallback->OnReceive(receive); - }, - [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]] const std::string& message) { - uiExtCallback->OnError(code, name, name); - }, - [uiExtCallback](const std::shared_ptr& uiProxy) { - uiExtCallback->OnRemoteReady(uiProxy); - }, - [uiExtCallback]() { - uiExtCallback->OnDestroy(); - }, - }; - - { - std::lock_guard lock(g_lockWindowFlag); - if (g_windowFlag) { - ACCESSTOKEN_LOG_WARN(LABEL, "The request already exists."); - asyncContext->result.errorCode = REQUEST_REALDY_EXIST; - asyncContext->result.errorMsg = "The specified context does not belong to the current application."; - return false; - } - g_windowFlag = true; - } - CreateSettingUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback); - if (asyncContext->result.errorCode == RET_FAILED) { - { - std::lock_guard lock(g_lockWindowFlag); - g_windowFlag = false; - return false; - } - } - return true; -} - -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; - } - - std::shared_ptr asyncContext = - std::make_shared(); - if (!ParseRequestPermissionOnSetting(env, aniContext, permissionList, asyncContext)) { - return nullptr; - } - - 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); - std::string errMsg = GetErrorMessage( - STS_ERROR_INNER, "The specified context does not belong to the current application."); - BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, errMsg); - return nullptr; - } - asyncContext->loadlock.lock(); - bool flag = StartUIExtension(env, asyncContext); - if (!flag) { - asyncContext->loadlock.unlock(); - } - asyncContext->loadlock.lock(); - ani_ref result = RequestPermissionOnSettingComplete(env, asyncContext); - asyncContext->loadlock.unlock(); - return result; -} - -static bool IsPermissionFlagValid(uint32_t flag) -{ - return (flag == PermissionFlag::PERMISSION_USER_SET) || (flag == PermissionFlag::PERMISSION_USER_FIXED) || - (flag == PermissionFlag::PERMISSION_ALLOW_THIS_TIME); -}; - static void GrantUserGrantedPermissionExecute([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, - ani_int tokenID, ani_string aniPermissionName, ani_int permissionFlags) + ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) { if (env == nullptr) { return; } - std::string permissionName; - if (!AniParseString(env, aniPermissionName, permissionName)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionName", "Permissions")); + AccessTokenID tokenID = static_cast(aniTokenID); + std::string permissionName = ANIStringToStdString(env, static_cast(aniPermission)); + uint32_t permissionFlags = static_cast(aniFlags); + if ((!BusinessErrorAni::ValidateTokenIDdWithThrowError(env, tokenID)) || + (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName)) || + (!BusinessErrorAni::ValidatePermissionFlagWithThrowError(env, permissionFlags))) { + ACCESSTOKEN_LOG_ERROR(LABEL, "TokenId(%{public}u) or Permission(%{public}s) or flags(%{public}u)is invalid.", + tokenID, permissionName.c_str(), permissionFlags); return; } - if (permissionName.empty() || permissionName.size() > MAX_LENGTH) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PARAM_INVALID, - GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); - return; - } - if (!IsPermissionFlagValid(static_cast(permissionFlags))) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PARAM_INVALID, - GetErrorMessage(STSErrorCode::STS_ERROR_PARAM_INVALID)); - return; - } PermissionBriefDef def; - if (!GetPermissionBriefDef(permissionName, def)) { - BusinessErrorAni::ThrowError(env, STSErrorCode::STS_ERROR_PERMISSION_NOT_EXIST, - GetErrorMessage(STSErrorCode::STS_ERROR_PERMISSION_NOT_EXIST)); - return; - } - - if (def.grantMode != USER_GRANT || !GetPermissionBriefDef(permissionName, def)) { + if (!GetPermissionBriefDef(permissionName, def) || def.grantMode != USER_GRANT) { 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)); + BusinessErrorAni::ThrowError(env, STS_ERROR_PERMISSION_NOT_EXIST, errMsg); return; } @@ -1339,42 +195,33 @@ static void GrantUserGrantedPermissionExecute([[maybe_unused]] ani_env *env, [[m } static void RevokeUserGrantedPermissionExecute([[maybe_unused]] ani_env* env, - [[maybe_unused]] ani_object object, ani_int tokenID, ani_string permissionName, ani_int permissionFlags) + [[maybe_unused]] ani_object object, ani_int aniTokenID, ani_string aniPermission, ani_int aniFlags) { ACCESSTOKEN_LOG_INFO(LABEL, "RevokeUserGrantedPermission begin."); if (env == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "env null."); return; } - - std::string permissionNameString; - if (!AniParseString(env, permissionName, permissionNameString)) { - BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionName", "Permissions")); + AccessTokenID tokenID = static_cast(aniTokenID); + std::string permissionName = ANIStringToStdString(env, static_cast(aniPermission)); + uint32_t permissionFlags = static_cast(aniFlags); + if ((!BusinessErrorAni::ValidateTokenIDdWithThrowError(env, tokenID)) || + (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName)) || + (!BusinessErrorAni::ValidatePermissionFlagWithThrowError(env, permissionFlags))) { + ACCESSTOKEN_LOG_ERROR(LABEL, "TokenId(%{public}u) or Permission(%{public}s) or flags(%{public}u)is invalid.", + tokenID, permissionName.c_str(), permissionFlags); return; } - if (!IsPermissionFlagValid(static_cast (permissionFlags))) { - std::string errMsg = GetErrorMessage(STS_ERROR_PARAM_INVALID, "The permissionFlags is invalid."); - BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); - return; - } - - 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) { + if (!GetPermissionBriefDef(permissionName, def) || def.grantMode != USER_GRANT) { 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, errMsg); return; } - int32_t ret = AccessTokenKit::RevokePermission(tokenID, permissionNameString, permissionFlags); + int32_t ret = AccessTokenKit::RevokePermission(tokenID, permissionName, permissionFlags); if (ret != RET_SUCCESS) { int32_t stsCode = BusinessErrorAni::GetStsErrorCode(ret); BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); @@ -1400,28 +247,31 @@ static ani_int GetVersionExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] } static ani_ref GetPermissionsStatusExecute([[maybe_unused]] ani_env* env, - [[maybe_unused]] ani_object object, ani_int tokenID, ani_array_ref permissionList) + [[maybe_unused]] ani_object object, ani_int aniTokenID, ani_array_ref aniPermissionList) { ACCESSTOKEN_LOG_INFO(LABEL, "GetPermissionsStatusExecute begin."); - if ((env == nullptr) || (permissionList == nullptr)) { - ACCESSTOKEN_LOG_ERROR(LABEL, "permissionList or env null."); + if ((env == nullptr) || (aniPermissionList == nullptr)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "aniPermissionList or env null."); + return nullptr; + } + AccessTokenID tokenID = static_cast(aniTokenID); + if (!BusinessErrorAni::ValidateTokenIDdWithThrowError(env, tokenID)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "TokenId(%{public}u) is invalid.", tokenID); return nullptr; } - std::vector aniPermissionList; - if (!AniParseStringArray(env, permissionList, aniPermissionList)) { - BusinessErrorAni::ThrowParameterTypeError( - env, STS_ERROR_PARAM_ILLEGAL, GetParamErrorMsg("permissionList", "Array")); + std::vector permissionList; + if (!AniParseStringArray(env, aniPermissionList, permissionList)) { return nullptr; } - if (aniPermissionList.empty()) { - std::string errMsg = GetErrorMessage(STS_ERROR_INNER, "The permissionList is empty."); - BusinessErrorAni::ThrowError(env, STS_ERROR_INNER, GetErrorMessage(STS_ERROR_INNER)); + if (permissionList.empty()) { + BusinessErrorAni::ThrowError( + env, STS_ERROR_INNER, GetErrorMessage(STS_ERROR_INNER, "The permissionList is empty.")); return nullptr; } std::vector permList; - for (const auto& permission : aniPermissionList) { + for (const auto& permission : permissionList) { PermissionListState permState; permState.permissionName = permission; permState.state = INVALID_OPER; @@ -1429,13 +279,13 @@ static ani_ref GetPermissionsStatusExecute([[maybe_unused]] ani_env* env, } int32_t result = RET_SUCCESS; - std::vector permissionQueryResults; result = AccessTokenKit::GetPermissionsStatus(tokenID, permList); if (result != RET_SUCCESS) { int32_t stsCode = BusinessErrorAni::GetStsErrorCode(result); BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); return nullptr; } + std::vector permissionQueryResults; for (const auto& permState : permList) { permissionQueryResults.emplace_back(permState.state); } @@ -1444,25 +294,28 @@ static ani_ref GetPermissionsStatusExecute([[maybe_unused]] ani_env* env, } static ani_int GetPermissionFlagsExecute([[maybe_unused]] ani_env* env, - [[maybe_unused]] ani_object object, ani_int tokenID, ani_string aniPermissionName) + [[maybe_unused]] ani_object object, ani_int aniTokenID, ani_string aniPermissionName) { uint32_t flag = PERMISSION_DEFAULT_FLAG; if (env == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "Env is null"); return flag; } - std::string permissionName; - if (!AniParseString(env, aniPermissionName, permissionName)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionName", "Permissions")); + AccessTokenID tokenID = static_cast(aniTokenID); + std::string permissionName = ANIStringToStdString(env, static_cast(aniPermissionName)); + if ((!BusinessErrorAni::ValidateTokenIDdWithThrowError(env, tokenID)) || + (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName))) { + ACCESSTOKEN_LOG_ERROR(LABEL, "TokenId(%{public}u) or Permission(%{public}s) is invalid.", + tokenID, permissionName.c_str()); return flag; } + int32_t result = AccessTokenKit::GetPermissionFlag(tokenID, permissionName, flag); if (result != RET_SUCCESS) { ACCESSTOKEN_LOG_ERROR(LABEL, "result = %{public}d errcode = %{public}d", result, BusinessErrorAni::GetStsErrorCode(result)); - BusinessErrorAni::ThrowError(env, BusinessErrorAni::GetStsErrorCode(result), - GetErrorMessage(BusinessErrorAni::GetStsErrorCode(result))); + BusinessErrorAni::ThrowError( + env, BusinessErrorAni::GetStsErrorCode(result), GetErrorMessage(BusinessErrorAni::GetStsErrorCode(result))); } return flag; } @@ -1474,18 +327,15 @@ static void SetPermissionRequestToggleStatusExecute([[maybe_unused]] ani_env* en ACCESSTOKEN_LOG_ERROR(LABEL, "Env is null"); return; } - std::string permissionName; - if (!AniParseString(env, aniPermissionName, permissionName)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionName", "Permissions")); + std::string permissionName = ANIStringToStdString(env, static_cast(aniPermissionName)); + if (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Permission(%{public}s) is invalid.", permissionName.c_str()); return; } int32_t result = AccessTokenKit::SetPermissionRequestToggleStatus(permissionName, status, 0); if (result != RET_SUCCESS) { - ACCESSTOKEN_LOG_ERROR(LABEL, "result = %{public}d errcode = %{public}d", - result, BusinessErrorAni::GetStsErrorCode(result)); - BusinessErrorAni::ThrowError(env, BusinessErrorAni::GetStsErrorCode(result), - GetErrorMessage(BusinessErrorAni::GetStsErrorCode(result))); + BusinessErrorAni::ThrowError( + env, BusinessErrorAni::GetStsErrorCode(result), GetErrorMessage(BusinessErrorAni::GetStsErrorCode(result))); } return; } @@ -1498,18 +348,16 @@ static ani_int GetPermissionRequestToggleStatusExecute([[maybe_unused]] ani_env* ACCESSTOKEN_LOG_ERROR(LABEL, "Env is null"); return flag; } - std::string permissionName; - if (!AniParseString(env, aniPermissionName, permissionName)) { - BusinessErrorAni::ThrowParameterTypeError(env, STSErrorCode::STS_ERROR_PARAM_ILLEGAL, - GetParamErrorMsg("permissionName", "Permissions")); + std::string permissionName = ANIStringToStdString(env, static_cast(aniPermissionName)); + if (!BusinessErrorAni::ValidatePermissionWithThrowError(env, permissionName)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Permission(%{public}s) is invalid.", permissionName.c_str()); return flag; } + int32_t result = AccessTokenKit::GetPermissionRequestToggleStatus(permissionName, flag, 0); if (result != RET_SUCCESS) { - ACCESSTOKEN_LOG_ERROR(LABEL, "result = %{public}d errcode = %{public}d", - result, BusinessErrorAni::GetStsErrorCode(result)); - BusinessErrorAni::ThrowError(env, BusinessErrorAni::GetStsErrorCode(result), - GetErrorMessage(BusinessErrorAni::GetStsErrorCode(result))); + BusinessErrorAni::ThrowError( + env, BusinessErrorAni::GetStsErrorCode(result), GetErrorMessage(BusinessErrorAni::GetStsErrorCode(result))); } return flag; } @@ -1540,14 +388,11 @@ void InitAbilityCtrlFunction(ani_env *env) return; } std::array claMethods = { - ani_native_function { - "checkAccessTokenExecute", "ILstd/core/String;:I", reinterpret_cast(CheckAccessTokenSync) }, + ani_native_function { "checkAccessTokenExecute", nullptr, reinterpret_cast(CheckAccessTokenExecute) }, ani_native_function { "requestPermissionsFromUserExecute", - "Lapplication/Context/Context;Lescompat/Array;:Lsecurity/PermissionRequestResult/PermissionRequestResult;", - reinterpret_cast(RequestPermissionsFromUserExecute) }, + nullptr, reinterpret_cast(RequestPermissionsFromUserExecute) }, ani_native_function { "requestPermissionOnSettingExecute", - "Lapplication/Context/Context;Lescompat/Array;:Lescompat/Array;", - reinterpret_cast(RequestPermissionOnSettingExecute) }, + nullptr, reinterpret_cast(RequestPermissionOnSettingExecute) }, ani_native_function { "grantUserGrantedPermissionExecute", nullptr, reinterpret_cast(GrantUserGrantedPermissionExecute) }, ani_native_function { "revokeUserGrantedPermissionExecute", diff --git a/frameworks/ets/ani/accesstoken/src/ani_common.cpp b/frameworks/ets/ani/accesstoken/src/ani_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2d67c948e1d487281ce35fbc14a12b01c5744a8 --- /dev/null +++ b/frameworks/ets/ani/accesstoken/src/ani_common.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ani_common.h" +#include "accesstoken_log.h" +#include +namespace OHOS { +namespace Security { +namespace AccessToken { +namespace { +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AniAccessTokenCommon" }; +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) +{ + 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; +} + +OHOS::Ace::UIContent* GetUIContent(const std::shared_ptr& abilityContext, + std::shared_ptr& uiExtensionContext, bool uiAbilityFlag) +{ + OHOS::Ace::UIContent* uiContent = nullptr; + if (uiAbilityFlag) { + if (abilityContext == nullptr) { + return nullptr; + } + uiContent = abilityContext->GetUIContent(); + } else { + if (uiExtensionContext == nullptr) { + return nullptr; + } + uiContent = uiExtensionContext->GetUIContent(); + } + return uiContent; +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/accesstoken/src/ani_request_global_switch_on_setting.cpp b/frameworks/ets/ani/accesstoken/src/ani_request_global_switch_on_setting.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf765c1bd72e44f524f6e0b93cd00e7a2c3a6203 --- /dev/null +++ b/frameworks/ets/ani/accesstoken/src/ani_request_global_switch_on_setting.cpp @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ani_request_global_switch_on_setting.h" +#include "accesstoken_kit.h" +#include "accesstoken_log.h" +#include "token_setproc.h" +#include "want.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +std::map>> + RequestGlobalSwitchAsyncInstanceControl::instanceIdMap_; +std::mutex RequestGlobalSwitchAsyncInstanceControl::instanceIdMutex_; +namespace { +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AniRequestGlobalSwitch" }; +const std::string GLOBAL_SWITCH_KEY = "ohos.user.setting.global_switch"; +const std::string GLOBAL_SWITCH_RESULT_KEY = "ohos.user.setting.global_switch.result"; +const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code"; +const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType"; +const std::string UI_EXTENSION_TYPE = "sys/commonUI"; + +// error code from dialog +constexpr int32_t REQUEST_REALDY_EXIST = 1; +constexpr int32_t GLOBAL_TYPE_IS_NOT_SUPPORT = 2; +constexpr int32_t SWITCH_IS_ALREADY_OPEN = 3; +} +RequestGlobalSwitchAsyncContext::~RequestGlobalSwitchAsyncContext() +{ + 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( + ani_env* env, const ani_object& aniContext, std::shared_ptr& asyncContext) +{ + auto context = OHOS::AbilityRuntime::GetStageModeContext(env, aniContext); + if (context == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetStageModeContext failed"); + return ANI_ERROR; + } + asyncContext->abilityContext = + OHOS::AbilityRuntime::Context::ConvertTo(context); + if (asyncContext->abilityContext != nullptr) { + auto abilityInfo = asyncContext->abilityContext->GetApplicationInfo(); + if (abilityInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); + return ANI_ERROR; + } + asyncContext->uiAbilityFlag = true; + asyncContext->tokenId = abilityInfo->accessTokenId; + } else { + asyncContext->uiExtensionContext = + OHOS::AbilityRuntime::Context::ConvertTo(context); + if (asyncContext->uiExtensionContext == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertTo UIExtensionContext failed"); + return ANI_ERROR; + } + auto uiExtensionInfo = asyncContext->uiExtensionContext->GetApplicationInfo(); + if (uiExtensionInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); + return ANI_ERROR; + } + asyncContext->tokenId = uiExtensionInfo->accessTokenId; + } + return ANI_OK; +} + +static bool ParseRequestGlobalSwitch(ani_env* env, ani_object& aniContext, ani_int type, + 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(); + asyncContext->switchType = static_cast(type); + + if (GetContext(env, aniContext, asyncContext) != ANI_OK) { + BusinessErrorAni::ThrowParameterTypeError(env, STS_ERROR_PARAM_ILLEGAL, + GetParamErrorMsg("context", "UIAbility or UIExtension Context")); + 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 int32_t TransferToStsErrorCode(int32_t errCode) +{ + int32_t stsCode = STS_OK; + switch (errCode) { + case RET_SUCCESS: + stsCode = STS_OK; + break; + case REQUEST_REALDY_EXIST: + stsCode = STS_ERROR_REQUEST_IS_ALREADY_EXIST; + break; + case GLOBAL_TYPE_IS_NOT_SUPPORT: + stsCode = STS_ERROR_PARAM_INVALID; + break; + case SWITCH_IS_ALREADY_OPEN: + stsCode = STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN; + break; + default: + stsCode = STS_ERROR_INNER; + break; + } + ACCESSTOKEN_LOG_INFO(LABEL, "dialog error(%{public}d) stsCode(%{public}d).", errCode, stsCode); + return stsCode; +} + +SwitchOnSettingUICallback::SwitchOnSettingUICallback( + const std::shared_ptr& reqContext) +{ + this->reqContext_ = reqContext; +} + +SwitchOnSettingUICallback::~SwitchOnSettingUICallback() +{} + +void SwitchOnSettingUICallback::SetSessionId(int32_t sessionId) +{ + this->sessionId_ = sessionId; +} + +static void GlobalSwitchResultsCallbackUI(bool switchStatus, 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)); + ExecuteAsyncCallback( + env, reinterpret_cast(data->callbackRef), error, CreateBoolean(env, data->switchStatus)); + + if (!isSameThread && data->vm->DetachCurrentThread() != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "DetachCurrentThread failed!"); + } +} + +static void CloseModalUIExtensionMainThread(std::shared_ptr& asyncContext, + int32_t sessionId) +{ + auto task = [asyncContext, sessionId]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); + asyncContext->result.errorCode = RET_FAILED; + return; + } + uiContent->CloseModalUIExtension(sessionId); + ACCESSTOKEN_LOG_INFO(LABEL, "Close end, sessionId: %{public}d", sessionId); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread"); + } else { + task(); + } +#else + task(); +#endif +} + +void SwitchOnSettingUICallback::ReleaseHandler(int32_t code) +{ + { + std::lock_guard lock(this->reqContext_->lockReleaseFlag); + if (this->reqContext_->releaseFlag) { + ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed."); + return; + } + this->reqContext_->releaseFlag = true; + } + CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_); + if (code == -1) { + this->reqContext_->result.errorCode = code; + } + RequestGlobalSwitchAsyncInstanceControl::UpdateQueueData(this->reqContext_); + RequestGlobalSwitchAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId); + GlobalSwitchResultsCallbackUI(this->reqContext_->switchStatus, this->reqContext_); +} + +/* + * when UIExtensionAbility use terminateSelfWithResult + */ +void SwitchOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result) +{ + this->reqContext_->result.errorCode = result.GetIntParam(RESULT_ERROR_KEY, 0); + this->reqContext_->switchStatus = result.GetBoolParam(GLOBAL_SWITCH_RESULT_KEY, 0); + ACCESSTOKEN_LOG_INFO(LABEL, "ResultCode is %{public}d, errorCodeis %{public}d, switchStatus=%{public}d.", + resultCode, this->reqContext_->result.errorCode, this->reqContext_->switchStatus); + ReleaseHandler(0); +} + +/* + * when UIExtensionAbility send message to UIExtensionComponent + */ +void SwitchOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Called!"); +} + +/* + * when UIExtensionAbility disconnect or use terminate or process die + * releaseCode is 0 when process normal exit + */ +void SwitchOnSettingUICallback::OnRelease(int32_t releaseCode) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "ReleaseCode is %{public}d", releaseCode); + + ReleaseHandler(-1); +} + +/* + * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error + */ +void SwitchOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Code is %{public}d, name is %{public}s, message is %{public}s", + code, name.c_str(), message.c_str()); + + ReleaseHandler(-1); +} + +/* + * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init, + * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy + */ +void SwitchOnSettingUICallback::OnRemoteReady(const std::shared_ptr& uiProxy) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Connect to UIExtensionAbility successfully."); +} + +/* + * when UIExtensionComponent destructed + */ +void SwitchOnSettingUICallback::OnDestroy() +{ + ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed."); + ReleaseHandler(-1); +} + +static void CreateUIExtensionMainThread(std::shared_ptr& asyncContext, + const AAFwk::Want& want, const Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks, + const std::shared_ptr& uiExtCallback) +{ + auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to get ui content!"); + asyncContext->result.errorCode = RET_FAILED; + return; + } + + Ace::ModalUIExtensionConfig config; + config.isProhibitBack = true; + int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config); + ACCESSTOKEN_LOG_INFO(LABEL, "Create end, sessionId: %{public}d, tokenId: %{public}d.", + sessionId, asyncContext->tokenId); + if (sessionId == 0) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create component, sessionId is 0."); + asyncContext->result.errorCode = RET_FAILED; + return; + } + uiExtCallback->SetSessionId(sessionId); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread"); + } else { + task(); + } +#else + task(); +#endif +} + +static void CreateUIExtension( + const OHOS::AAFwk::Want &want, std::shared_ptr asyncContext) +{ + auto uiExtCallback = std::make_shared(asyncContext); + Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = { + [uiExtCallback](int32_t releaseCode) { + uiExtCallback->OnRelease(releaseCode); + }, + [uiExtCallback](int32_t resultCode, const AAFwk::Want& result) { + uiExtCallback->OnResult(resultCode, result); + }, + [uiExtCallback](const AAFwk::WantParams& receive) { + uiExtCallback->OnReceive(receive); + }, + [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]] const std::string& message) { + uiExtCallback->OnError(code, name, name); + }, + [uiExtCallback](const std::shared_ptr& uiProxy) { + uiExtCallback->OnRemoteReady(uiProxy); + }, + [uiExtCallback]() { + uiExtCallback->OnDestroy(); + }, + }; + + CreateUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback); +} + +static void StartUIExtension(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.globalSwitchAbilityName); + want.SetParam(GLOBAL_SWITCH_KEY, asyncContext->switchType); + 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 RequestGlobalSwitchAsyncInstanceControl::AddCallbackByInstanceId( + std::shared_ptr& asyncContext) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "InstanceId: %{public}d", asyncContext->instanceId); + { + 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; + } + // make sure id is in map to indicate a pop-up window is showing + instanceIdMap_[asyncContext->instanceId] = {}; + } + StartUIExtension(asyncContext); +} + +void RequestGlobalSwitchAsyncInstanceControl::UpdateQueueData( + const std::shared_ptr& reqContext) +{ + if ((reqContext->result.errorCode != RET_SUCCESS) || !(reqContext->switchStatus)) { + 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; + } + int32_t targetSwitchType = reqContext->switchType; + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + for (auto& asyncContext : iter->second) { + if (targetSwitchType == asyncContext->switchType) { + asyncContext->result.errorCode = reqContext->result.errorCode; + asyncContext->switchStatus = reqContext->switchStatus; + asyncContext->isDynamic = false; + } + } + } +} + +void RequestGlobalSwitchAsyncInstanceControl::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 RequestGlobalSwitchAsyncInstanceControl::CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic) +{ + isDynamic = asyncContext->isDynamic; + if (!isDynamic) { + ACCESSTOKEN_LOG_INFO(LABEL, "It does not need to request permission exsion"); + GlobalSwitchResultsCallbackUI(asyncContext->switchStatus, asyncContext); + return; + } +} + +void RequestGlobalSwitchExecute([[maybe_unused]] ani_env* env, + [[maybe_unused]] ani_object object, ani_object aniContext, ani_int type, ani_object callback) +{ + if (env == nullptr || callback == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "env or permissionList or callback is null."); + return; + } + + std::shared_ptr asyncContext = + std::make_shared(); + if (!ParseRequestGlobalSwitch(env, aniContext, type, callback, asyncContext)) { + return; + } + + ani_object result = CreateBoolean(env, false); + 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); + 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; + } + GetInstanceId(asyncContext); + RequestGlobalSwitchAsyncInstanceControl::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."); + } +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/accesstoken/src/ani_request_permission.cpp b/frameworks/ets/ani/accesstoken/src/ani_request_permission.cpp new file mode 100644 index 0000000000000000000000000000000000000000..451a5e6ba08241a698196a039631a2faf4abb04c --- /dev/null +++ b/frameworks/ets/ani/accesstoken/src/ani_request_permission.cpp @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ani_request_permission.h" + +#include +#include +#include +#include + +#include "ability_manager_client.h" +#include "accesstoken_kit.h" +#include "accesstoken_log.h" +#include "hisysevent.h" +#include "token_setproc.h" +#include "want.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +std::map>> RequestAsyncInstanceControl::instanceIdMap_; +std::mutex RequestAsyncInstanceControl::instanceIdMutex_; +namespace { +#define SETTER_METHOD_NAME(property) "" #property +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AniRequestPermissionFromUser" }; +std::mutex g_lockFlag; +constexpr const char* PERMISSION_KEY = "ohos.user.grant.permission"; +constexpr const char* STATE_KEY = "ohos.user.grant.permission.state"; +constexpr const char* RESULT_KEY = "ohos.user.grant.permission.result"; +constexpr const char* EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType"; +constexpr const char* UI_EXTENSION_TYPE = "sys/commonUI"; +constexpr const char* ORI_PERMISSION_MANAGER_BUNDLE_NAME = "com.ohos.permissionmanager"; +constexpr const char* TOKEN_KEY = "ohos.ability.params.token"; +constexpr const char* CALLBACK_KEY = "ohos.ability.params.callback"; +constexpr const char* WINDOW_RECTANGLE_LEFT_KEY = "ohos.ability.params.request.left"; +constexpr const char* WINDOW_RECTANGLE_TOP_KEY = "ohos.ability.params.request.top"; +constexpr const char* WINDOW_RECTANGLE_HEIGHT_KEY = "ohos.ability.params.request.height"; +constexpr const char* WINDOW_RECTANGLE_WIDTH_KEY = "ohos.ability.params.request.width"; +constexpr const char* REQUEST_TOKEN_KEY = "ohos.ability.params.request.token"; +} +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; + } +} + +template +static inline bool CallSetter(ani_env* env, ani_class cls, ani_object object, const char* setterName, valueType value) +{ + ani_status status = ANI_ERROR; + ani_field fieldValue; + if (env->Class_FindField(cls, setterName, &fieldValue) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Class_FindField Fail %{public}d, name: %{public}s.", + static_cast(status), setterName); + return false; + } + if ((status = env->Object_SetField_Ref(object, fieldValue, value)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_SetField_Ref Fail %{public}d, name: %{public}s.", + static_cast(status), setterName); + return false; + } + return true; +} + +static ani_object WrapResult(ani_env* env, std::shared_ptr& asyncContext) +{ + ani_status status = ANI_ERROR; + ani_class cls = nullptr; + if ((status = env->FindClass("Lsecurity/PermissionRequestResult/PermissionRequestResult;", &cls)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass status %{public}d ", static_cast(status)); + return nullptr; + } + if (cls == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "null cls"); + return nullptr; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(cls, "", ":V", &method)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Class_FindMethod status %{public}d ", static_cast(status)); + return nullptr; + } + ani_object aObject = nullptr; + if ((status = env->Object_New(cls, method, &aObject)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_New status %{public}d ", static_cast(status)); + return nullptr; + } + auto state = asyncContext->needDynamicRequest ? asyncContext->grantResults : asyncContext->permissionsState; + ani_ref strPermissions = ConvertAniArrayString(env, asyncContext->permissionList); + ani_ref intAuthResults = ConvertAniArrayInt(env, state); + ani_ref boolDialogShownResults = ConvertAniArrayBool(env, asyncContext->dialogShownResults); + ani_ref intPermissionQueryResults = ConvertAniArrayInt(env, asyncContext->permissionQueryResults); + if (strPermissions == nullptr || intAuthResults == nullptr || boolDialogShownResults == nullptr || + intPermissionQueryResults == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "1111111111111111"); + return nullptr; + } + if (!CallSetter(env, cls, aObject, SETTER_METHOD_NAME(permissions), strPermissions) || + !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(authResults), intAuthResults) || + !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(dialogShownResults), boolDialogShownResults) || + !CallSetter(env, cls, aObject, SETTER_METHOD_NAME(errorReasons), intPermissionQueryResults)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "333333333333"); + return nullptr; + } + return aObject; +} + +static void UpdateGrantPermissionResultOnly(const std::vector& permissions, + const std::vector& grantResults, + std::shared_ptr& data, + std::vector& newGrantResults) +{ + size_t size = permissions.size(); + for (size_t i = 0; i < size; i++) { + int32_t result = static_cast(data->permissionsState[i]); + if (data->permissionsState[i] == AccessToken::DYNAMIC_OPER) { + result = data->result.errorCode == AccessToken::RET_SUCCESS ? grantResults[i] : AccessToken::INVALID_OPER; + } + newGrantResults.emplace_back(result); + } +} + +static bool IsDynamicRequest(std::shared_ptr& asyncContext) +{ + if (asyncContext == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "asyncContext nullptr"); + return false; + } + std::vector permList; + for (const auto& permission : asyncContext->permissionList) { + AccessToken::PermissionListState permState; + permState.permissionName = permission; + permState.errorReason = SERVICE_ABNORMAL; + permState.state = AccessToken::INVALID_OPER; + permList.emplace_back(permState); + } + auto ret = AccessToken::AccessTokenKit::GetSelfPermissionsState(permList, asyncContext->info); + ACCESSTOKEN_LOG_INFO(LABEL, + "TokenID: %{public}d, bundle: %{public}s, uiExAbility: %{public}s, serExAbility: %{public}s.", + asyncContext->tokenId, asyncContext->info.grantBundleName.c_str(), asyncContext->info.grantAbilityName.c_str(), + asyncContext->info.grantServiceAbilityName.c_str()); + if (ret == AccessToken::FORBIDDEN_OPER) { + ACCESSTOKEN_LOG_ERROR(LABEL, "FORBIDDEN_OPER"); + for (auto& perm : permList) { + perm.state = AccessToken::INVALID_OPER; + perm.errorReason = PRIVACY_STATEMENT_NOT_AGREED; + } + } + for (const auto& permState : permList) { + ACCESSTOKEN_LOG_INFO(LABEL, "Permission: %{public}s: state: %{public}d, errorReason: %{public}d", + permState.permissionName.c_str(), permState.state, permState.errorReason); + asyncContext->permissionsState.emplace_back(permState.state); + asyncContext->dialogShownResults.emplace_back(permState.state == AccessToken::TypePermissionOper::DYNAMIC_OPER); + asyncContext->errorReasons.emplace_back(permState.errorReason); + } + if (permList.size() != asyncContext->permissionList.size()) { + ACCESSTOKEN_LOG_ERROR(LABEL, "permList.size: %{public}zu, permissionList.size: %{public}zu", permList.size(), + asyncContext->permissionList.size()); + return false; + } + return ret == AccessToken::TypePermissionOper::DYNAMIC_OPER; +} + +static void CreateUIExtensionMainThread(std::shared_ptr& asyncContext, + const OHOS::AAFwk::Want& want, const OHOS::Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks, + const std::shared_ptr& uiExtCallback) +{ + auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() { + OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); + asyncContext->result.errorCode = AccessToken::RET_FAILED; + asyncContext->uiExtensionFlag = false; + asyncContext->loadlock.unlock(); + return; + } + + OHOS::Ace::ModalUIExtensionConfig config; + config.isProhibitBack = true; + int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config); + if (sessionId == 0) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Create component failed, sessionId is 0"); + asyncContext->result.errorCode = AccessToken::RET_FAILED; + asyncContext->uiExtensionFlag = false; + asyncContext->loadlock.unlock(); + return; + } + uiExtCallback->SetSessionId(sessionId); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread"); + } else { + task(); + } +#else + task(); +#endif +} + +static void CreateServiceExtension(std::shared_ptr& asyncContext) +{ + if (!asyncContext->uiAbilityFlag) { + ACCESSTOKEN_LOG_ERROR(LABEL, "UIExtension ability can not pop service ablility window!"); + asyncContext->needDynamicRequest = false; + asyncContext->result.errorCode = RET_FAILED; + return; + } + OHOS::sptr remoteObject = new (std::nothrow) AuthorizationResult(asyncContext); + if (remoteObject == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Create window failed!"); + asyncContext->needDynamicRequest = false; + asyncContext->result.errorCode = RET_FAILED; + return; + } + OHOS::AAFwk::Want want; + want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantServiceAbilityName); + want.SetParam(PERMISSION_KEY, asyncContext->permissionList); + want.SetParam(STATE_KEY, asyncContext->permissionsState); + want.SetParam(TOKEN_KEY, asyncContext->abilityContext->GetToken()); + want.SetParam(CALLBACK_KEY, remoteObject); + + int32_t left = 0; + int32_t top = 0; + int32_t width = 0; + int32_t height = 0; + asyncContext->abilityContext->GetWindowRect(left, top, width, height); + want.SetParam(WINDOW_RECTANGLE_LEFT_KEY, left); + want.SetParam(WINDOW_RECTANGLE_TOP_KEY, top); + want.SetParam(WINDOW_RECTANGLE_WIDTH_KEY, width); + want.SetParam(WINDOW_RECTANGLE_HEIGHT_KEY, height); + want.SetParam(REQUEST_TOKEN_KEY, asyncContext->abilityContext->GetToken()); + int32_t ret = OHOS::AAFwk::AbilityManagerClient::GetInstance()->RequestDialogService( + want, asyncContext->abilityContext->GetToken()); + ACCESSTOKEN_LOG_INFO(LABEL, "Request end, ret: %{public}d, tokenId: %{public}d, permNum: %{public}zu", ret, + asyncContext->tokenId, asyncContext->permissionList.size()); +} + +static void CreateUIExtension(std::shared_ptr& asyncContext) +{ + OHOS::AAFwk::Want want; + want.SetElementName(asyncContext->info.grantBundleName, asyncContext->info.grantAbilityName); + want.SetParam(PERMISSION_KEY, asyncContext->permissionList); + want.SetParam(STATE_KEY, asyncContext->permissionsState); + want.SetParam(EXTENSION_TYPE_KEY, UI_EXTENSION_TYPE); + + auto uiExtCallback = std::make_shared(asyncContext); + OHOS::Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = { + [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); }, + [uiExtCallback]( + int32_t resultCode, const OHOS::AAFwk::Want& result) { uiExtCallback->OnResult(resultCode, result); }, + [uiExtCallback](const OHOS::AAFwk::WantParams& receive) { uiExtCallback->OnReceive(receive); }, + [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]] const std::string& message) { + uiExtCallback->OnError(code, name, name); + }, + [uiExtCallback](const std::shared_ptr& uiProxy) { + uiExtCallback->OnRemoteReady(uiProxy); + }, + [uiExtCallback]() { uiExtCallback->OnDestroy(); }, + }; + CreateUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback); +} + +static void GetInstanceId(std::shared_ptr& asyncContext) +{ + auto task = [asyncContext]() { + OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); + return; + } + asyncContext->uiContentFlag = true; + asyncContext->instanceId = uiContent->GetInstanceId(); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId"); + } else { + task(); + } +#else + task(); +#endif +} + +static void RequestResultsHandler(const std::vector& permissionList, + const std::vector& permissionStates, std::shared_ptr& data) +{ + std::vector newGrantResults; + UpdateGrantPermissionResultOnly(permissionList, permissionStates, data, newGrantResults); + if (newGrantResults.empty()) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResults empty"); + data->result.errorCode = RET_FAILED; + } + data->grantResults.assign(newGrantResults.begin(), newGrantResults.end()); + + 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( + ani_env* env, const ani_object& aniContext, std::shared_ptr& asyncContext) +{ + auto context = OHOS::AbilityRuntime::GetStageModeContext(env, aniContext); + if (context == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetStageModeContext failed"); + return ANI_ERROR; + } + asyncContext->abilityContext = + OHOS::AbilityRuntime::Context::ConvertTo(context); + if (asyncContext->abilityContext != nullptr) { + auto abilityInfo = asyncContext->abilityContext->GetApplicationInfo(); + if (abilityInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); + return ANI_ERROR; + } + asyncContext->uiAbilityFlag = true; + asyncContext->tokenId = abilityInfo->accessTokenId; + asyncContext->bundleName = abilityInfo->bundleName; + } else { + asyncContext->uiExtensionContext = + OHOS::AbilityRuntime::Context::ConvertTo(context); + if (asyncContext->uiExtensionContext == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertTo UIExtensionContext failed"); + return ANI_ERROR; + } + auto uiExtensionInfo = asyncContext->uiExtensionContext->GetApplicationInfo(); + if (uiExtensionInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); + return ANI_ERROR; + } + asyncContext->tokenId = uiExtensionInfo->accessTokenId; + asyncContext->bundleName = uiExtensionInfo->bundleName; + } + return ANI_OK; +} + +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.errorCode == RET_SUCCESS)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GrantResults empty"); + asyncContext->result.errorCode = RET_FAILED; + } + return; + } + + GetInstanceId(asyncContext); + 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) { + RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); + } else { + CreateServiceExtension(asyncContext); + } + } else if (asyncContext->instanceId == -1) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Pop service extension dialog, instanceId is -1."); + 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; + 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."); + RequestAsyncInstanceControl::AddCallbackByInstanceId(asyncContext); + } + } +} + +static bool ParseRequestPermissionFromUser(ani_env* env, ani_object aniContext, ani_array_ref permissionList, + 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(); + + 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 (!AniParaseArrayString(env, nullptr, permissionList, asyncContext->permissionList)) { + 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; +} + +void RequestPermissionsFromUserExecute([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_object aniContext, ani_array_ref permissionList, ani_object callback) +{ + if (env == nullptr || permissionList == nullptr || callback == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Parenv or permissionList or callback is null."); + return; + } + std::shared_ptr asyncContext = std::make_shared(); + if (!ParseRequestPermissionFromUser(env, aniContext, permissionList, callback, asyncContext)) { + return; + } + + 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); + + 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; + } + 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); +} + +static void CloseModalUIExtensionMainThread(std::shared_ptr& asyncContext, int32_t sessionId) +{ + auto task = [asyncContext, sessionId]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); + asyncContext->result.errorCode = RET_FAILED; + return; + } + uiContent->CloseModalUIExtension(sessionId); + ACCESSTOKEN_LOG_INFO(LABEL, "Close end, sessionId: %{public}d", sessionId); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread"); + } else { + task(); + } +#else + task(); +#endif + ACCESSTOKEN_LOG_INFO(LABEL, "Instance id: %{public}d", asyncContext->instanceId); +} + +void RequestAsyncInstanceControl::ExecCallback(int32_t id) +{ + std::shared_ptr asyncContext = nullptr; + bool isDynamic = false; + { + std::lock_guard lock(instanceIdMutex_); + auto iter = RequestAsyncInstanceControl::instanceIdMap_.find(id); + if (iter == RequestAsyncInstanceControl::instanceIdMap_.end()) { + 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); + if (isDynamic) { + break; + } + } + if (iter->second.empty()) { + ACCESSTOKEN_LOG_INFO(LABEL, "Id: %{public}d, map is empty", id); + RequestAsyncInstanceControl::instanceIdMap_.erase(id); + } + } + if (isDynamic) { + if (asyncContext->uiExtensionFlag) { + CreateUIExtension(asyncContext); + } else { + CreateServiceExtension(asyncContext); + } + } +} + +void RequestAsyncInstanceControl::CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic) +{ + asyncContext->permissionsState.clear(); + asyncContext->dialogShownResults.clear(); + if (!IsDynamicRequest(asyncContext)) { + RequestResultsHandler(asyncContext->permissionList, asyncContext->permissionsState, asyncContext); + return; + } + isDynamic = true; +} + +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; + } + RequestAsyncInstanceControl::instanceIdMap_[asyncContext->instanceId] = {}; + } + if (asyncContext->uiExtensionFlag) { + CreateUIExtension(asyncContext); + } else { + CreateServiceExtension(asyncContext); + } + return; +} + +UIExtensionCallback::UIExtensionCallback(const std::shared_ptr& reqContext) +{ + this->reqContext_ = reqContext; +} + +UIExtensionCallback::~UIExtensionCallback() {} + +void UIExtensionCallback::SetSessionId(int32_t sessionId) +{ + this->sessionId_ = sessionId; +} + +void UIExtensionCallback::ReleaseHandler(int32_t code) +{ + { + std::lock_guard lock(g_lockFlag); + if (this->reqContext_->releaseFlag) { + ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed."); + return; + } + this->reqContext_->releaseFlag = true; + } + CloseModalUIExtensionMainThread(this->reqContext_, this->sessionId_); + 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); + this->reqContext_->permissionList = result.GetStringArrayParam(PERMISSION_KEY); + this->reqContext_->permissionsState = result.GetIntArrayParam(RESULT_KEY); + ReleaseHandler(0); +} + +void UIExtensionCallback::OnReceive(const OHOS::AAFwk::WantParams& receive) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Called!"); +} + +void UIExtensionCallback::OnRelease(int32_t releaseCode) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "ReleaseCode is %{public}d", releaseCode); + ReleaseHandler(-1); +} + +void UIExtensionCallback::OnError(int32_t code, const std::string& name, const std::string& message) +{ + ACCESSTOKEN_LOG_INFO( + LABEL, "Code is %{public}d, name is %{public}s, message is %{public}s", code, name.c_str(), message.c_str()); + + ReleaseHandler(-1); +} + +void UIExtensionCallback::OnRemoteReady(const std::shared_ptr& uiProxy) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Connect to UIExtensionAbility successfully."); +} + +void UIExtensionCallback::OnDestroy() +{ + ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed."); + ReleaseHandler(-1); +} + +void AuthorizationResult::GrantResultsCallback( + 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); +} + +void AuthorizationResult::WindowShownCallback() +{ + std::shared_ptr asyncContext = data_; + if (asyncContext == nullptr) { + return; + } + OHOS::Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if ((uiContent == nullptr) || !(asyncContext->uiContentFlag)) { + return; + } + RequestAsyncInstanceControl::ExecCallback(asyncContext->instanceId); +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp b/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf1397fb2e8d2ccb59801a6971757f99677b4286 --- /dev/null +++ b/frameworks/ets/ani/accesstoken/src/ani_request_permission_on_setting.cpp @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ani_request_permission_on_setting.h" +#include "accesstoken_kit.h" +#include "accesstoken_log.h" +#include "token_setproc.h" +#include "want.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +std::map>> + RequestOnSettingAsyncInstanceControl::instanceIdMap_; +std::mutex RequestOnSettingAsyncInstanceControl::instanceIdMutex_; +namespace { +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AniRequestPermission" }; +constexpr int32_t REQUEST_REALDY_EXIST = 1; +constexpr int32_t PERM_NOT_BELONG_TO_SAME_GROUP = 2; +constexpr int32_t PERM_IS_NOT_DECLARE = 3; +constexpr int32_t ALL_PERM_GRANTED = 4; +constexpr int32_t PERM_NOT_REVOKE_BY_USER = 5; +const std::string PERMISSION_SETTING_KEY = "ohos.user.setting.permission"; +const std::string EXTENSION_TYPE_KEY = "ability.want.params.uiExtensionType"; +const std::string UI_EXTENSION_TYPE = "sys/commonUI"; +const std::string RESULT_ERROR_KEY = "ohos.user.setting.error_code"; +const std::string PERMISSION_RESULT_KEY = "ohos.user.setting.permission.result"; +} +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( + ani_env* env, const ani_object& aniContext, std::shared_ptr& asyncContext) +{ + auto context = OHOS::AbilityRuntime::GetStageModeContext(env, aniContext); + if (context == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetStageModeContext failed"); + return ANI_ERROR; + } + asyncContext->abilityContext = + OHOS::AbilityRuntime::Context::ConvertTo(context); + if (asyncContext->abilityContext != nullptr) { + auto abilityInfo = asyncContext->abilityContext->GetApplicationInfo(); + if (abilityInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); + return ANI_ERROR; + } + asyncContext->uiAbilityFlag = true; + asyncContext->tokenId = abilityInfo->accessTokenId; + } else { + asyncContext->uiExtensionContext = + OHOS::AbilityRuntime::Context::ConvertTo(context); + if (asyncContext->uiExtensionContext == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertTo UIExtensionContext failed"); + return ANI_ERROR; + } + auto uiExtensionInfo = asyncContext->uiExtensionContext->GetApplicationInfo(); + if (uiExtensionInfo == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetApplicationInfo failed"); + return ANI_ERROR; + } + asyncContext->tokenId = uiExtensionInfo->accessTokenId; + } + return ANI_OK; +} + +static bool ParseRequestPermissionOnSetting(ani_env* env, ani_object& aniContext, ani_array_ref& permissionList, + 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, STS_ERROR_PARAM_ILLEGAL, + GetParamErrorMsg("context", "UIAbility or UIExtension Context")); + return false; + } + if (!AniParaseArrayString(env, nullptr, permissionList, asyncContext->permissionList)) { + 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 void StateToEnumIndex(int32_t state, ani_size& enumIndex) +{ + if (state == 0) { + enumIndex = 1; + } else { + enumIndex = 0; + } +} + +static ani_object ReturnResult(ani_env* env, std::shared_ptr& asyncContext) +{ + ani_class arrayCls = nullptr; + if (env->FindClass("Lescompat/Array;", &arrayCls) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass name Lescompat/Array failed!"); + return nullptr; + } + + ani_method arrayCtor; + if (env->Class_FindMethod(arrayCls, "", "I:V", &arrayCtor) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass failed!"); + return nullptr; + } + + ani_object arrayObj; + if (env->Object_New(arrayCls, arrayCtor, &arrayObj, asyncContext->stateList.size()) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object new failed!"); + return nullptr; + } + + const char* enumDescriptor = "L@ohos/abilityAccessCtrl/abilityAccessCtrl/GrantStatus;"; + ani_enum enumType; + if (env->FindEnum(enumDescriptor, &enumType) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "FindClass name %{public}s failed!", enumDescriptor); + return nullptr; + } + + ani_size index = 0; + for (const auto& state: asyncContext->stateList) { + ani_enum_item enumItem; + ani_size enumIndex = 0; + StateToEnumIndex(state, enumIndex); + if (env->Enum_GetEnumItemByIndex(enumType, enumIndex, &enumItem) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "GetEnumItemByIndex value %{public}u failed!", state); + break; + } + + if (env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", index, enumItem) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_CallMethodByName_Void $_set failed!"); + break; + } + index++; + } + + return arrayObj; +} + +static int32_t TransferToStsErrorCode(int32_t errorCode) +{ + int32_t stsCode = STS_OK; + switch (errorCode) { + case RET_SUCCESS: + stsCode = STS_OK; + break; + case REQUEST_REALDY_EXIST: + stsCode = STS_ERROR_REQUEST_IS_ALREADY_EXIST; + break; + case PERM_NOT_BELONG_TO_SAME_GROUP: + stsCode = STS_ERROR_PARAM_INVALID; + break; + case PERM_IS_NOT_DECLARE: + stsCode = STS_ERROR_PARAM_INVALID; + break; + case ALL_PERM_GRANTED: + stsCode = STS_ERROR_ALL_PERM_GRANTED; + break; + case PERM_NOT_REVOKE_BY_USER: + stsCode = STS_ERROR_PERM_NOT_REVOKE_BY_USER; + break; + default: + stsCode = STS_ERROR_INNER; + break; + } + ACCESSTOKEN_LOG_INFO(LABEL, "Dialog error(%{public}d) stsCode(%{public}d).", errorCode, stsCode); + return stsCode; +} + +PermissonOnSettingUICallback::PermissonOnSettingUICallback( + const std::shared_ptr& reqContext) +{ + this->reqContext_ = reqContext; +} + +PermissonOnSettingUICallback::~PermissonOnSettingUICallback() +{} + +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) +{ + auto task = [asyncContext, sessionId]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Get ui content failed!"); + asyncContext->result.errorCode = RET_FAILED; + return; + } + uiContent->CloseModalUIExtension(sessionId); + ACCESSTOKEN_LOG_INFO(LABEL, "Close end, sessionId: %{public}d", sessionId); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:CloseModalUIExtensionMainThread"); + } else { + task(); + } +#else + task(); +#endif +} + +void PermissonOnSettingUICallback::ReleaseHandler(int32_t code) +{ + { + std::lock_guard lock(this->reqContext_->lockReleaseFlag); + if (this->reqContext_->releaseFlag) { + ACCESSTOKEN_LOG_WARN(LABEL, "Callback has executed."); + return; + } + this->reqContext_->releaseFlag = true; + } + CloseSettingModalUIExtensionMainThread(this->reqContext_, this->sessionId_); + if (code == -1) { + this->reqContext_->result.errorCode = code; + } + RequestOnSettingAsyncInstanceControl::UpdateQueueData(this->reqContext_); + RequestOnSettingAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId); + PermissionResultsCallbackUI(this->reqContext_->stateList, this->reqContext_); +} + +/* + * when UIExtensionAbility use terminateSelfWithResult + */ +void PermissonOnSettingUICallback::OnResult(int32_t resultCode, const AAFwk::Want& result) +{ + 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, errorCodeis %{public}d, listSize=%{public}zu.", + resultCode, this->reqContext_->result.errorCode, this->reqContext_->stateList.size()); + ReleaseHandler(0); +} + +/* + * when UIExtensionAbility send message to UIExtensionComponent + */ +void PermissonOnSettingUICallback::OnReceive(const AAFwk::WantParams& receive) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Called!"); +} + +/* + * when UIExtensionAbility disconnect or use terminate or process die + * releaseCode is 0 when process normal exit + */ +void PermissonOnSettingUICallback::OnRelease(int32_t releaseCode) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "ReleaseCode is %{public}d", releaseCode); + + ReleaseHandler(-1); +} + +/* + * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error + */ +void PermissonOnSettingUICallback::OnError(int32_t code, const std::string& name, const std::string& message) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Code is %{public}d, name is %{public}s, message is %{public}s", + code, name.c_str(), message.c_str()); + + ReleaseHandler(-1); +} + +/* + * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init, + * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy + */ +void PermissonOnSettingUICallback::OnRemoteReady(const std::shared_ptr& uiProxy) +{ + ACCESSTOKEN_LOG_INFO(LABEL, "Connect to UIExtensionAbility successfully."); +} + +/* + * when UIExtensionComponent destructed + */ +void PermissonOnSettingUICallback::OnDestroy() +{ + ACCESSTOKEN_LOG_INFO(LABEL, "UIExtensionAbility destructed."); + ReleaseHandler(-1); +} + +static void CreateSettingUIExtensionMainThread(std::shared_ptr& asyncContext, + const AAFwk::Want& want, const Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks, + const std::shared_ptr& uiExtCallback) +{ + auto task = [asyncContext, want, uiExtensionCallbacks, uiExtCallback]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext->abilityContext, + asyncContext->uiExtensionContext, asyncContext->uiAbilityFlag); + if (uiContent == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to get ui content!"); + asyncContext->result.errorCode = RET_FAILED; + return; + } + + Ace::ModalUIExtensionConfig config; + config.isProhibitBack = true; + int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config); + ACCESSTOKEN_LOG_INFO(LABEL, "Create end, sessionId: %{public}d, tokenId: %{public}d.", + sessionId, asyncContext->tokenId); + if (sessionId == 0) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create component, sessionId is 0."); + asyncContext->result.errorCode = RET_FAILED; + return; + } + uiExtCallback->SetSessionId(sessionId); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:CreateUIExtensionMainThread"); + } else { + task(); + } +#else + task(); +#endif +} + +static void CreateUIExtension( + const OHOS::AAFwk::Want &want, std::shared_ptr asyncContext) +{ + auto uiExtCallback = std::make_shared(asyncContext); + Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = { + [uiExtCallback](int32_t releaseCode) { + uiExtCallback->OnRelease(releaseCode); + }, + [uiExtCallback](int32_t resultCode, const AAFwk::Want& result) { + uiExtCallback->OnResult(resultCode, result); + }, + [uiExtCallback](const AAFwk::WantParams& receive) { + uiExtCallback->OnReceive(receive); + }, + [uiExtCallback](int32_t code, const std::string& name, [[maybe_unused]] const std::string& message) { + uiExtCallback->OnError(code, name, name); + }, + [uiExtCallback](const std::shared_ptr& uiProxy) { + uiExtCallback->OnRemoteReady(uiProxy); + }, + [uiExtCallback]() { + uiExtCallback->OnDestroy(); + }, + }; + + CreateSettingUIExtensionMainThread(asyncContext, want, uiExtensionCallbacks, uiExtCallback); +} + +static void StartUIExtension(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(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; + } + // make sure id is in map to indicate a pop-up window is showing + instanceIdMap_[asyncContext->instanceId] = {}; + } + 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; + } +} + +void RequestPermissionOnSettingExecute([[maybe_unused]] ani_env* env, + [[maybe_unused]] ani_object object, ani_object aniContext, ani_array_ref permissionList, ani_object callback) +{ + 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, 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); + 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; + } + 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."); + } +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/common/BUILD.gn b/frameworks/ets/ani/common/BUILD.gn index 66cbbd3aba1c1e0a2c0f6544fffe2b323461bde6..6ebcfa5145f1dfed04d00d08c7051ba53cf8e385 100644 --- a/frameworks/ets/ani/common/BUILD.gn +++ b/frameworks/ets/ani/common/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 Huawei Device Co., Ltd. +# Copyright (c) 2025 Huawei Device Co., Ltd. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at diff --git a/frameworks/ets/ani/common/ets/permissions.ets b/frameworks/ets/ani/common/ets/permissions.ets index c06103b9640f0ebf38d4c86f9e106cb2d5c2d8e5..e0a300419aa58dbff4d96fb2c160b462ab36e5d2 100644 --- a/frameworks/ets/ani/common/ets/permissions.ets +++ b/frameworks/ets/ani/common/ets/permissions.ets @@ -12,25 +12,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file Defines all permissions. - * @kit AbilityKit - */ - -/** - * Indicates permissions. - * - * @typedef { string } - * @syscap SystemCapability.Security.AccessToken - * @since 9 - */ - /** - * Indicates permissions. - * - * @typedef { string } - * @syscap SystemCapability.Security.AccessToken - * @atomicservice - * @since 11 - */ export type Permissions = string; \ No newline at end of file diff --git a/frameworks/ets/ani/common/ets/security/PermissionRequestResult.ets b/frameworks/ets/ani/common/ets/security/PermissionRequestResult.ets index ba08345a99963339afd0fba9f88a734e81d99a4a..a1ce477b782c41e9417ccf569636f1861d628f97 100644 --- a/frameworks/ets/ani/common/ets/security/PermissionRequestResult.ets +++ b/frameworks/ets/ani/common/ets/security/PermissionRequestResult.ets @@ -12,126 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file - * @kit AbilityKit - */ - -/** - * The result of requestPermissionsFromUser with asynchronous callback. - * - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @since 9 - */ -/** - * The result of requestPermissionsFromUser with asynchronous callback. - * - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @since 10 - */ -/** - * The result of requestPermissionsFromUser with asynchronous callback. - * - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @atomicservice - * @since 11 - */ export default class PermissionRequestResult { - /** - * The permissions passed in by the user. - * - * @type { Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @since 9 - */ - /** - * The permissions passed in by the user. - * - * @type { Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @since 10 - */ - /** - * The permissions passed in by the user. - * - * @type { Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @atomicservice - * @since 11 - */ permissions: Array = new Array(); - - /** - * The results for the corresponding request permissions. The value 0 indicates that a - * permission is granted, the value -1 indicates not, and the value 2 indicates the request is invalid. - * - * @type { Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @since 9 - */ - /** - * The results for the corresponding request permissions. The value 0 indicates that a - * permission is granted, the value -1 indicates not, and the value 2 indicates the request is invalid. - * - * @type { Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @since 10 - */ - /** - * The results for the corresponding request permissions. The value 0 indicates that a - * permission is granted, the value -1 indicates not, and the value 2 indicates the request is invalid. - * - * @type { Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @atomicservice - * @since 11 - */ - authResults: Array = new Array(); - - /** - * Specifies whether a dialog box is shown for each requested permission. - * The value true means that a dialog box is shown, and false means the opposite. - * - * @type { ?Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @atomicservice - * @since 12 - */ + authResults: Array = new Array(); dialogShownResults?: Array; - - /** - * Enumerates the return values of the permission request operation. - * 0 The operation is successful. - * 1 The permission name is invalid. - * 2 The requested permission has not been declared. - * 3 The conditions for requesting the permission are not met. - * 4 The user does not agree to the Privacy Statement. - * 5 The permission cannot be requested in a pop-up window. - * 12 The service is abnormal. - * - * @type { ?Array } - * @syscap SystemCapability.Security.AccessToken - * @stagemodelonly - * @crossplatform - * @atomicservice - * @since 18 - */ - errorReasons?: Array; + errorReasons?: Array; } \ No newline at end of file diff --git a/frameworks/ets/ani/common/include/ani_error.h b/frameworks/ets/ani/common/include/ani_error.h index 5343f927aec36c8ba024defb8431931370ff9a01..e47fe113372111c792d696a2f5c4493d246eada9 100644 --- a/frameworks/ets/ani/common/include/ani_error.h +++ b/frameworks/ets/ani/common/include/ani_error.h @@ -43,7 +43,7 @@ typedef enum { STS_ERROR_INNER, STS_ERROR_REQUEST_IS_ALREADY_EXIST = 12100010, STS_ERROR_ALL_PERM_GRANTED = 12100011, - STS_ERROR_PERM_REVOKE_BY_USER = 12100012, + STS_ERROR_PERM_NOT_REVOKE_BY_USER = 12100012, STS_ERROR_GLOBAL_SWITCH_IS_ALREADY_OPEN = 12100013, } STSErrorCode; @@ -53,7 +53,7 @@ struct AtmResult { }; std::string GetParamErrorMsg(const std::string& param, const std::string& errMsg); -std::string GetErrorMessage(uint32_t errCode, const std::string& extendMsg = ""); +std::string GetErrorMessage(int32_t errCode, const std::string& extendMsg = ""); class BusinessErrorAni { public: static ani_object CreateError(ani_env* env, ani_int code, const std::string& msg); @@ -62,6 +62,7 @@ public: static int32_t GetStsErrorCode(int32_t errCode); static bool ValidateTokenIDdWithThrowError(ani_env* env, AccessTokenID tokenID); static bool ValidatePermissionWithThrowError(ani_env* env, const std::string& permission); + static bool ValidatePermissionFlagWithThrowError(ani_env* env, uint32_t flag); private: static void ThrowError(ani_env* env, ani_object err); diff --git a/frameworks/ets/ani/common/include/ani_utils.h b/frameworks/ets/ani/common/include/ani_utils.h index d487ef64cbe2b42b37ede8fbed49f754e4b14f28..c1766592853643e9c0a9878b81a5be8b866130b8 100644 --- a/frameworks/ets/ani/common/include/ani_utils.h +++ b/frameworks/ets/ani/common/include/ani_utils.h @@ -55,6 +55,13 @@ bool AniIsCallbackRefEqual(ani_env* env, const ani_ref& compareRef, const ani_re bool& isEqual); bool AniFunctionalObjectCall(ani_env *env, const ani_fn_object& fn, ani_size size, ani_ref* argv, ani_ref& result); std::string ANIStringToStdString(ani_env* env, ani_string aniStr); +bool AniParaseArrayString([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_array_ref arrayObj, std::vector& permissionList); +ani_ref ConvertAniArrayBool(ani_env* env, const std::vector& cArray); +ani_ref ConvertAniArrayInt(ani_env* env, const std::vector& cArray); +ani_ref ConvertAniArrayString(ani_env* env, const std::vector& cArray); + +ani_object CreateBoolean(ani_env *env, ani_boolean value); } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/frameworks/ets/ani/common/src/ani_error.cpp b/frameworks/ets/ani/common/src/ani_error.cpp index d2d94bdd023707c84460529d871e9ec129049b7f..23b9b9719d7153e93f0a2bc840385489f0a9e09e 100644 --- a/frameworks/ets/ani/common/src/ani_error.cpp +++ b/frameworks/ets/ani/common/src/ani_error.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -33,7 +33,7 @@ static const std::unordered_map g_errorStringMap = { { 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_TERMINATE_FAIL, "Ui extension terminate failed." }, + { STS_ERROR_TERMINATE_FAIL, "UI extension terminate failed." }, { 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." }, @@ -45,7 +45,7 @@ static const std::unordered_map g_errorStringMap = { { STS_ERROR_INNER, "Common inner error." }, { STS_ERROR_REQUEST_IS_ALREADY_EXIST, "The request already exists." }, { STS_ERROR_ALL_PERM_GRANTED, "All permissions in the permission list have been granted." }, - { STS_ERROR_PERM_REVOKE_BY_USER, + { STS_ERROR_PERM_NOT_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." }, }; @@ -116,7 +116,7 @@ std::string GetParamErrorMsg(const std::string& param, const std::string& errMsg return msg; } -std::string GetErrorMessage(uint32_t errCode, const std::string& extendMsg) +std::string GetErrorMessage(int32_t errCode, const std::string& extendMsg) { auto iter = g_errorStringMap.find(errCode); if (iter != g_errorStringMap.end()) { @@ -213,6 +213,16 @@ bool BusinessErrorAni::ValidatePermissionWithThrowError(ani_env* env, const std: } return true; } + +bool BusinessErrorAni::ValidatePermissionFlagWithThrowError(ani_env* env, uint32_t flag) +{ + if (!DataValidator::IsPermissionFlagValid(flag)) { + std::string errMsg = GetErrorMessage(STS_ERROR_PARAM_INVALID, "The permissionFlags is invalid."); + BusinessErrorAni::ThrowError(env, STS_ERROR_PARAM_INVALID, errMsg); + return false; + } + return true; +} } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/frameworks/ets/ani/common/src/ani_utils.cpp b/frameworks/ets/ani/common/src/ani_utils.cpp index 0a6cf33d4755c0ddae61e8907c12cb8f232db542..ffa8f3b69dfa08975bdbee9f7521b9c05dace09b 100644 --- a/frameworks/ets/ani/common/src/ani_utils.cpp +++ b/frameworks/ets/ani/common/src/ani_utils.cpp @@ -21,6 +21,7 @@ namespace Security { namespace AccessToken { namespace { static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AccessTokenAniUtils" }; +constexpr const char* CLASSNAME_BOOLEAN = "Lstd/core/Boolean;"; } // namespace bool AniFindNameSpace(ani_env* env, const char* namespaceDescriptor, ani_namespace& out) @@ -79,10 +80,10 @@ bool AniGetEnumItemByIndex(ani_env* env, const ani_enum& aniEnum, ani_size index } -bool AniParseString(ani_env* env, const ani_string& ani_str, std::string& out) +bool AniParseString(ani_env* env, const ani_string& anistr, std::string& out) { ani_size strSize; - if (env->String_GetUTF8Size(ani_str, &strSize) != ANI_OK) { + if (env->String_GetUTF8Size(anistr, &strSize) != ANI_OK) { ACCESSTOKEN_LOG_ERROR(LABEL, "String_GetUTF8Size failed!"); return false; } @@ -90,7 +91,7 @@ bool AniParseString(ani_env* env, const ani_string& ani_str, std::string& out) std::vector buffer(strSize + 1); // +1 for null terminator char* utf8Buffer = buffer.data(); ani_size bytesWritten = 0; - if (env->String_GetUTF8(ani_str, utf8Buffer, strSize + 1, &bytesWritten) != ANI_OK) { + if (env->String_GetUTF8(anistr, utf8Buffer, strSize + 1, &bytesWritten) != ANI_OK) { ACCESSTOKEN_LOG_ERROR(LABEL, "String_GetUTF8 failed!"); return false; } @@ -104,34 +105,30 @@ bool AniParseString(ani_env* env, const ani_string& ani_str, std::string& out) return true; } -bool AniParseStringArray(ani_env* env, const ani_array_ref& ani_str_arr, std::vector& out) +bool AniParseStringArray(ani_env* env, const ani_array_ref& aniStrArr, std::vector& out) { ani_size size = 0; - if (env->Array_GetLength(ani_str_arr, &size) != ANI_OK) { + if (env->Array_GetLength(aniStrArr, &size) != ANI_OK) { ACCESSTOKEN_LOG_ERROR(LABEL, "Array_GetLength failed!"); return false; } for (ani_size i = 0; i < size; ++i) { ani_ref aniRef; - if (env->Array_Get_Ref(ani_str_arr, i, &aniRef) != ANI_OK) { + if (env->Array_Get_Ref(aniStrArr, i, &aniRef) != ANI_OK) { ACCESSTOKEN_LOG_ERROR(LABEL, "Array_Get_Ref failed!"); return false; } - std::string stdStr; - if (!AniParseString(env, static_cast(aniRef), stdStr)) { - return false; - } - + std::string stdStr = ANIStringToStdString(env, static_cast(aniRef)); out.emplace_back(stdStr); } return true; } -bool AniParseCallback(ani_env* env, const ani_ref& ani_callback, ani_ref& out) +bool AniParseCallback(ani_env* env, const ani_ref& aniCallback, ani_ref& out) { - if (env->GlobalReference_Create(ani_callback, &out) != ANI_OK) { + if (env->GlobalReference_Create(aniCallback, &out) != ANI_OK) { ACCESSTOKEN_LOG_ERROR(LABEL, "GlobalReference_Create failed!"); return false; } @@ -231,12 +228,7 @@ bool AniObjectSetPropertyByNameRef(ani_env* env, ani_object& object, const char bool IsCurrentThread(std::thread::id threadId) { - std::thread::id currentThread = std::this_thread::get_id(); - if (threadId != currentThread) { - ACCESSTOKEN_LOG_ERROR(LABEL, "Ani_ref can not be compared, different threadId."); - return false; - } - return true; + return threadId == std::this_thread::get_id(); } bool AniIsCallbackRefEqual(ani_env* env, const ani_ref& compareRef, const ani_ref& targetRref, std::thread::id threadId, @@ -283,6 +275,125 @@ std::string ANIStringToStdString(ani_env* env, ani_string aniStr) std::string content = std::string(utf8Buffer); return content; } + +ani_ref ConvertAniArrayString(ani_env* env, const std::vector& cArray) +{ + ani_size length = cArray.size(); + ani_array_ref aArrayRef = nullptr; + ani_class aStringcls = nullptr; + if (env->FindClass("Lstd/core/String;", &aStringcls) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString FindClass String failed"); + return nullptr; + } + ani_ref undefinedRef = nullptr; + if (ANI_OK != env->GetUndefined(&undefinedRef)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString GetUndefined failed"); + return nullptr; + } + if (env->Array_New_Ref(aStringcls, length, undefinedRef, &aArrayRef) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString Array_New_Ref failed "); + return nullptr; + } + ani_string aString = nullptr; + for (ani_size i = 0; i < length; ++i) { + env->String_NewUTF8(cArray[i].c_str(), cArray[i].size(), &aString); + env->Array_Set_Ref(aArrayRef, i, aString); + } + ani_ref aRef = nullptr; + if (env->GlobalReference_Create(aArrayRef, &aRef) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayString GlobalReference_Create failed "); + return nullptr; + } + return aRef; +} + +ani_ref ConvertAniArrayInt(ani_env* env, const std::vector& cArray) +{ + ani_size length = cArray.size(); + ani_array_int aArrayInt = nullptr; + if (env->Array_New_Int(length, &aArrayInt) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayInt Array_New_Int failed "); + return nullptr; + } + for (ani_size i = 0; i < length; ++i) { + env->Array_SetRegion_Int(aArrayInt, i, length, &cArray[i]); + } + ani_ref aRef = nullptr; + if (env->GlobalReference_Create(aArrayInt, &aRef) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayInt GlobalReference_Create failed "); + return nullptr; + } + return aRef; +} + +ani_ref ConvertAniArrayBool(ani_env* env, const std::vector& cArray) +{ + ani_size length = cArray.size(); + ani_array_boolean aArrayBool = nullptr; + if (env->Array_New_Boolean(length, &aArrayBool) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayBool Array_New_Boolean failed "); + return nullptr; + } + std::vector boolArray(length); + for (ani_size i = 0; i < length; ++i) { + boolArray[i] = cArray[i]; + } + for (ani_size i = 0; i < length; ++i) { + env->Array_SetRegion_Boolean(aArrayBool, i, length, &boolArray[i]); + } + ani_ref aRef = nullptr; + if (env->GlobalReference_Create(aArrayBool, &aRef) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertAniArrayBool GlobalReference_Create failed "); + return nullptr; + } + return aRef; +} + +bool AniParaseArrayString([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, + ani_array_ref arrayObj, std::vector& permissionList) +{ + ani_size length; + if (ANI_OK != env->Array_GetLength(arrayObj, &length)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Array_GetLength FAILED"); + return false; + } + for (ani_size i = 0; i < length; i++) { + ani_ref stringEntryRef; + if (ANI_OK != env->Object_CallMethodByName_Ref( + arrayObj, "$_get", "I:Lstd/core/Object;", &stringEntryRef, static_cast(i))) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Object_CallMethodByName_Ref _get Failed"); + return false; + } + auto strEntryRef = ANIStringToStdString(env, static_cast(stringEntryRef)); + if (strEntryRef.empty()) { + return false; + } else { + permissionList.emplace_back(strEntryRef); + } + } + return true; +} + +ani_object CreateBoolean(ani_env *env, ani_boolean value) +{ + ani_class persionCls; + ani_status status = ANI_ERROR; + if ((status = env->FindClass(CLASSNAME_BOOLEAN, &persionCls)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "status : %{public}d", static_cast(status)); + return nullptr; + } + ani_method personInfoCtor; + if ((status = env->Class_FindMethod(persionCls, "", "Z:V", &personInfoCtor)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "status : %{public}d", static_cast(status)); + return nullptr; + } + ani_object personInfoObj; + if ((status = env->Object_New(persionCls, personInfoCtor, &personInfoObj, value)) != ANI_OK) { + ACCESSTOKEN_LOG_ERROR(LABEL, "status : %{public}d", static_cast(status)); + return nullptr; + } + return personInfoObj; +} } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/frameworks/ets/ani/privacy/BUILD.gn b/frameworks/ets/ani/privacy/BUILD.gn index 0d7a756ad9a7549c8c62c5c99dac704df4947a4d..9c44be7822822ad8c4ed0a9b791b8d188823517c 100644 --- a/frameworks/ets/ani/privacy/BUILD.gn +++ b/frameworks/ets/ani/privacy/BUILD.gn @@ -41,6 +41,7 @@ ohos_shared_library("privacy_ani") { external_deps = [ "hilog:libhilog", + "ipc:ipc_single", "runtime_core:ani", "runtime_core:libarkruntime", ] diff --git a/frameworks/ets/ani/privacy/src/privacy_manager.cpp b/frameworks/ets/ani/privacy/src/privacy_manager.cpp index 7e828ab504db4681b7010f4e50847009ca824a63..bd6409808dbf3e5de1d01ee1321ae168fffcc188 100644 --- a/frameworks/ets/ani/privacy/src/privacy_manager.cpp +++ b/frameworks/ets/ani/privacy/src/privacy_manager.cpp @@ -385,13 +385,7 @@ void PermActiveStatusPtr::ActiveStatusChangeCallback(ActiveChangeResponse& activ static bool ParseInputToRegister(const ani_string& aniType, const ani_array_ref& aniArray, const ani_ref& aniCallback, RegisterPermActiveChangeContext* context, bool isReg) { - std::string type; // type: the first parameter is string - if (!AniParseString(context->env, aniType, type)) { - BusinessErrorAni::ThrowParameterTypeError( - context->env, STS_ERROR_PARAM_INVALID, GetParamErrorMsg("type", "string")); - return false; - } - + std::string type = ANIStringToStdString(context->env, static_cast(aniType)); std::vector permList; // permissionList: the second parameter is Array if (!AniParseStringArray(context->env, aniArray, permList)) { BusinessErrorAni::ThrowParameterTypeError( @@ -646,8 +640,7 @@ static void StopUsingPermissionExecute( auto retCode = PrivacyKit::StopUsingPermission(tokenID, permission, pid); if (retCode != RET_SUCCESS) { - int32_t stsCode = GetStsErrorCode(retCode); - BusinessErrorAni::ThrowError(env, stsCode, GetErrorMessage(stsCode)); + BusinessErrorAni::ThrowError(env, retCode, GetErrorMessage(GetStsErrorCode(retCode))); } }