想了解更多内容,源应用请访问:
和华为官方合作共建的码解鸿蒙技术社区
https://harmonyos.51cto.com
安全子系统为OpenHarmony提供有效保护应用和用户数据的能力。
主要功能: 系统安全、析之系统数据安全、安全应用安全等;
目前开源功能: 应用完整性保护、权限应用权限管理、管理设备认证、源应用密钥管理服务、码解数据分级保护;
应用权限管理: 为程序框架子系统提供权限管理功能,析之系统并且为上层应用提供权限申请和授权状态查询接口。安全
本文将介绍标准系统下安全子系统应用权限管理部分如何在系统内适配及实现,权限尽力深入细节部分。管理
OpenHarmony中应用和系统服务均运行在独立的源应用沙箱中,进程空间和程序数据都是码解相互隔离的,以保护应用数据的析之系统安全性;但是运行在独立沙箱中的服务或应用同时需要对外提供一些API以实现所需功能,其他独立沙箱中的应用在跨进程访问这些API时,需要系统提供一种权限管理机制对这些API的访问者进行授权。
应用权限管理提供了权限定义机制,允许系统服务和应用为自己的敏感API定义新的权限,其他应用必须申请此权限才能访问此敏感API;
应用权限管理提供了权限申请机制,允许应用申请权限,这些权限由系统或者其他应用定义,服务器租用权限申请通过后就能访问这个权限相关的系统或其他应用提供的敏感API;
应用权限管理也为用户提供了一些必须的功能,方便用户查看和管理权限授予情况。
应用权限管理模块是以SystemAbility的形式对外提供能力的,在分布式任务调度子系统中safwk组件定义OpenHarmony中SystemAbility的实现方法,并提供启动、注册等接口实现。
实现一个SystemAbility需要六个步骤:
1)定义该服务对外提供的能力集合函数
namespace OHOS { class IListenAbility : public IRemoteBroker { public: virtual int AddVolume(int volume) = 0; public: enum { ADD_VOLUME = 1, }; public: DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.test.IListenAbility"); }; }2) 定义客户端通信代码XXXProxy
namespace OHOS { class ListenAbilityProxy : public IRemoteProxy<IListenAbility> { public: int AddVolume(int volume); explicit ListenAbilityProxy(const sptr<IRemoteObject>& impl) : IRemoteProxy<IListenAbility>(impl) { } private: static inline BrokerDelegator<ListenAbilityProxy> delegator_; }; } // namespace OHOS3) 定义服务端通信代码XXXStub
namespace OHOS { int32_t ListenAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel &reply, MessageOption &option) { switch (code) { case ADD_VOLUME: { return reply.WriteInt32(AddVolume(data.ReadInt32())); } default: return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } } }4)SystemAbility的实现类
namespace { constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001800, "SA_TST"}; } REGISTER_SYSTEM_ABILITY_BY_ID(ListenAbility, DISTRIBUTED_SCHED_TEST_LISTEN_ID, true); ListenAbility::ListenAbility(int32_t saId, bool runOnCreate) : SystemAbility(saId, runOnCreate) { HiLog::Info(LABEL, ":%s called", __func__); HiLog::Info(LABEL, "ListenAbility()"); } ListenAbility::~ListenAbility() { HiLog::Info(LABEL, "~ListenAbility()"); } int ListenAbility::AddVolume(int volume) { pid_t current = getpid(); HiLog::Info(LABEL, "ListenAbility::AddVolume volume = %d, pid = %d.", volume, current); return (volume + 1); } void ListenAbility::OnDump() { } void ListenAbility::OnStart() { HiLog::Info(LABEL, "ListenAbility::OnStart()"); HiLog::Info(LABEL, "ListenAbility:%s called:-----Publish------", __func__); bool res = Publish(this); if (res) { HiLog::Error(LABEL, "ListenAbility: res == false"); } HiLog::Info(LABEL, "ListenAbility:%s called:AddAbilityListener_OS_TST----beg-----", __func__); AddSystemAbilityListener(DISTRIBUTED_SCHED_TEST_OS_ID); HiLog::Info(LABEL, "ListenAbility:%s called:AddAbilityListener_OS_TST----end-----", __func__); HiLog::Info(LABEL, "ListenAbility:%s called:StopAbility_OS_TST----beg-----", __func__); StopAbility(DISTRIBUTED_SCHED_TEST_OS_ID); HiLog::Info(LABEL, "ListenAbility:%s called:StopAbility_OS_TST----end-----", __func__); return; } void ListenAbility::OnStop() {5)SystemAbility配置
以c++实现的SA必须配置相关System Ability的profile配置文件才会完成SA的加载注册逻辑,否则没有编写profile配置的System Ability不会完成注册。配置方法如下:
在子系统的根目录新建一个以sa_profile为名的文件夹;然后在此文件夹中新建两个文件:一个以serviceId为前缀的xml文件;另外一个为BUILD.gn文件
<?xml version="1.0" encoding="UTF-8"?> <info> <process>listen_test</process> <systemability> <name>serviceid</name> <libpath>/system/lib64/liblistentest.z.so</libpath> <run-on-create>true</run-on-create> <distributed>false</distributed> <dump-level>1</dump-level> </systemability> </info>BUILD.gn:
import("//build/ohos/sa_profile/sa_profile.gni") ohos_sa_profile("xxx_sa_profile") { sources = [ "serviceid.xml" ] subsystem_name = "distributedschedule" }6)rc配置文件
rc配置文件为linux提供的native进程拉起策略,为手机在开机启动阶段由init进程解析配置的rc文件进行拉起
service listen_test /system/bin/sa_main /system/profile/listen_test.xml class z_core user system group system shell seclabel u:r:xxxx:s0标准系统用户程序框架子系统提供权限管理基础校验能力,不对三方app开放,并提供如下API。亿华云计算
IPermissionManager:内部接口类
PermissionManagerProxy:IPC请求的代理类
PermissionManagerStub:IPC请求服务类
PermissionManagerClient:应用权限管理客户类
PermissionKit:组件对外接口类,真正对外提供STATIC接口函数
PermissionManagerService:应用权限功能服务类,调用PermissionStateManager和PermissionDefinitionManager
PermissionStateManager:真正的应用权限管理功能实现
PermissionDefinitionManager:真正的应用权限管理功能实现
标准系统下应用权限管理功能是基于SAMgr管理框架实现,如何配置SAMgr框架见基础知识介绍,如果想学习更多细节参见SAMgr相关学习,这里专注于应用权限管理功能部分,并对代码逻辑关键节点进行分析和展示。
应用权限管理组件通过PermissionKit类以单例模式对外提供接口,PermissionKit类内部接口函数则调用PermissionManagerClient类,PermissionManagerClient则通过调用GetSystemAbility函数获取向SAMgr注册过的代理类单例PermissionManagerProxy。
代码如下:
sptr<IPermissionManager> PermissionManagerClient::GetProxy() const { auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (sam == nullptr) { PERMISSION_LOG_DEBUG(LABEL, "%{ public}s: GetSystemAbilityManager is null", __func__); return nullptr; } // 获取Proxy auto permissionSa = sam->GetSystemAbility(IPermissionManager::SA_ID_PERMISSION_MANAGER_SERVICE); if (permissionSa == nullptr) { PERMISSION_LOG_DEBUG(LABEL, "%{ public}s: GetSystemAbility %{ public}d is null", __func__, IPermissionManager::SA_ID_PERMISSION_MANAGER_SERVICE); return nullptr; } auto proxy = iface_cast<IPermissionManager>(permissionSa); if (proxy == nullptr) { PERMISSION_LOG_DEBUG(LABEL, "%{ public}s: iface_cast get null", __func__); return nullptr; } return proxy; }在获取代理类PermissionManagerProxy后,PermissionManagerProxy内部不同功能接口函数会调用SendRequest函数发起IPC请求服务。
示例代码如下(删去省略部分):
int PermissionManagerProxy::VerifyPermission( const std::string& bundleName, const std::string& permissionName, int userId) { // 省略部分 ..................... // 发送请求服务 int32_t requestResult = remote->SendRequest( static_cast<uint32_t>(IPermissionManager::InterfaceCode::VERIFY_PERMISSION), data, reply, option); if (requestResult != NO_ERROR) { PERMISSION_LOG_ERROR(LABEL, "%{ public}s send request fail, result: %{ public}d", __func__, requestResult); return PERMISSION_NOT_GRANTED; } int32_t result = reply.ReadInt32(); PERMISSION_LOG_DEBUG(LABEL, "%{ public}s get result from server data = %{ public}d", __func__, result); return result; }其中接口类IPermissionManager中定义了IPC通信的请求码。
示例代码如下(删去省略部分):
class IPermissionManager : public IRemoteBroker { public: static const int SA_ID_PERMISSION_MANAGER_SERVICE = 3501; DECLARE_INTERFACE_DESCRIPTOR(u"ohos.security.permission.IPermissionManager"); virtual int VerifyPermission(const std::string& bundleName, const std::string& permissionName, int userId) = 0; // 省略部分 ................................ // 请求码 enum class InterfaceCode { VERIFY_PERMISSION = 0xff01, CAN_REQUEST_PERMISSION = 0xff02, GRANT_USER_GRANTED_PERMISSION = 0xff03, GRANT_SYSTEM_GRANTED_PERMISSION = 0xff04, REVOKE_USER_GRANTED_PERMISSION = 0xff05, REVOKE_SYSTEM_GRANTED_PERMISSION = 0xff06, ADD_USER_GRANTED_REQ_PERMISSIONS = 0xff07, ADD_SYSTEM_GRANTED_REQ_PERMISSIONS = 0xff08, REMOVE_USER_GRANTED_REQ_PERMISSIONS = 0xff09, REMOVE_SYSTEM_GRANTED_REQ_PERMISSIONS = 0xff10, ADD_DEF_PERMISSIONS = 0xff11, REMOVE_DEF_PERMISSIONS = 0xff12, GET_DEF_PERMISSION = 0xff13, }; };PermissionManagerService类则由于继承了PermissionManagerStub,会在接口函数OnRemoteRequest函数接收到代理PermissionManagerProxy通过IPC通信发送的不同请求,进而进行处理。
示例代码如下:
int32_t PermissionManagerStub::OnRemoteRequest( uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option) { PERMISSION_LOG_INFO(LABEL, "%{ public}s called, code: %{ public}d", __func__, code); std::u16string descriptor = data.ReadInterfaceToken(); if (descriptor != IPermissionManager::GetDescriptor()) { PERMISSION_LOG_ERROR(LABEL, "get unexpect descriptor: %{ public}s", Str16ToStr8(descriptor).c_str()); return RET_FAILED; } switch (code) { case static_cast<uint32_t>(IPermissionManager::InterfaceCode::VERIFY_PERMISSION): VerifyPermissionInner(data, reply); break; case static_cast<uint32_t>(IPermissionManager::InterfaceCode::CAN_REQUEST_PERMISSION): CanRequestPermissionInner(data, reply); break; case static_cast<uint32_t>(IPermissionManager::InterfaceCode::GRANT_USER_GRANTED_PERMISSION): GrantUserGrantedPermissionInner(data, reply); break; // 省略部分 ....... default: return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } return NO_ERROR; }最终PermissionManagerService则调用PermissionStateManager和PermissionDefinitionManager类所提供的函数做具体的功能实现。
当今设备安全问题已经越来越引起不同行业的重视,OpenHarmney安全子系统作为系统基础能力之一对开发设备的安全性尤为重要,对系统框架开发来说很有必要学习其内部原理并对代码结构深入了解,本文档抛砖引玉介绍了标准系统下应用权限管理的相关逻辑框架,后续随着学习的站群服务器深入将不断完善对安全子系统的解读。
想了解更多内容,请访问:
和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com