|
|
|
|
公众号矩阵

OpenHarmony源码解析之安全子系统 (应用权限管理)

本文将介绍标准系统下安全子系统应用权限管理部分如何在系统内适配及实现,尽力深入细节部分。

作者:周永峰来源:鸿蒙社区|2021-11-18 10:28

想了解更多内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

1.简介

安全子系统为OpenHarmony提供有效保护应用和用户数据的能力。

主要功能: 系统安全、数据安全、应用安全等;

目前开源功能: 应用完整性保护、应用权限管理、设备认证、密钥管理服务、数据分级保护;

应用权限管理: 为程序框架子系统提供权限管理功能,并且为上层应用提供权限申请和授权状态查询接口。

本文将介绍标准系统下安全子系统应用权限管理部分如何在系统内适配及实现,尽力深入细节部分。

1.1 OpenHarmony 架构图

OpenHarmony 源码解析之安全子系统 (应用权限管理) -鸿蒙HarmonyOS技术社区

1.2 安全子系统

OpenHarmony 源码解析之安全子系统 (应用权限管理) -鸿蒙HarmonyOS技术社区

1.3 应用权限管理

OpenHarmony中应用和系统服务均运行在独立的沙箱中,进程空间和程序数据都是相互隔离的,以保护应用数据的安全性;但是运行在独立沙箱中的服务或应用同时需要对外提供一些API以实现所需功能,其他独立沙箱中的应用在跨进程访问这些API时,需要系统提供一种权限管理机制对这些API的访问者进行授权。

应用权限管理提供了权限定义机制,允许系统服务和应用为自己的敏感API定义新的权限,其他应用必须申请此权限才能访问此敏感API;

应用权限管理提供了权限申请机制,允许应用申请权限,这些权限由系统或者其他应用定义,权限申请通过后就能访问这个权限相关的系统或其他应用提供的敏感API;

应用权限管理也为用户提供了一些必须的功能,方便用户查看和管理权限授予情况。

OpenHarmony 源码解析之安全子系统 (应用权限管理) -鸿蒙HarmonyOS技术社区

2.基础知识

2.1 代码结构

  1. /base/security/permission 
  2. ├── frameworks # 基础设施层 
  3. │ └── permission_standard # 标准系统权限管理基础设施层 
  4. ├── interfaces # 接口层 
  5. │ ├── innerkits # 内部接口层 
  6. │ │ ├── permission_lite # 轻量系统、小型系统权限管理内部接口层 
  7. │ │ └── permission_standard # 标准系统权限管理内部接口层 
  8. │ └── kits # 外部接口层 
  9. │ ├── permission_lite # 轻量系统、小型系统权限管理外部接口层 
  10. │ └── permission_standard # 标准系统权限管理外部接口层 
  11. └── services # 服务层 
  12. ├── permission_lite # 轻量系统、小型系统权限管理服务层 
  13. └── permission_standard # 标准系统权限管理服务层 

2.2 SystemAbility

应用权限管理模块是以SystemAbility的形式对外提供能力的,在分布式任务调度子系统中safwk组件定义OpenHarmony中SystemAbility的实现方法,并提供启动、注册等接口实现。

实现一个SystemAbility需要六个步骤:

1)定义该服务对外提供的能力集合函数

  1. namespace OHOS { 
  2. class IListenAbility : public IRemoteBroker { 
  3. public
  4.     virtual int AddVolume(int volume) = 0; 
  5.  
  6. public
  7.     enum { 
  8.         ADD_VOLUME = 1, 
  9.     }; 
  10. public
  11.     DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.test.IListenAbility"); 
  12. }; 

2) 定义客户端通信代码XXXProxy

  1. namespace OHOS { 
  2. class ListenAbilityProxy : public IRemoteProxy<IListenAbility> { 
  3. public
  4.     int AddVolume(int volume); 
  5.  
  6.     explicit ListenAbilityProxy(const sptr<IRemoteObject>& impl) 
  7.         : IRemoteProxy<IListenAbility>(impl) 
  8.     { 
  9.     } 
  10.  
  11. private: 
  12.     static inline BrokerDelegator<ListenAbilityProxy> delegator_; 
  13. }; 
  14. } // namespace OHOS 

3) 定义服务端通信代码XXXStub

  1. namespace OHOS { 
  2. int32_t ListenAbilityStub::OnRemoteRequest(uint32_t code, 
  3.     MessageParcel& data, MessageParcel &reply, MessageOption &option
  4.     switch (code) { 
  5.         case ADD_VOLUME: { 
  6.             return reply.WriteInt32(AddVolume(data.ReadInt32())); 
  7.         } 
  8.         default
  9.             return IPCObjectStub::OnRemoteRequest(code, data, reply, option); 
  10.     } 

4)SystemAbility的实现类

  1. namespace { 
  2. constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0xD001800, "SA_TST"}; 
  3.  
  4. REGISTER_SYSTEM_ABILITY_BY_ID(ListenAbility, DISTRIBUTED_SCHED_TEST_LISTEN_ID, true); 
  5.  
  6. ListenAbility::ListenAbility(int32_t saId, bool runOnCreate) : SystemAbility(saId, runOnCreate) 
  7.     HiLog::Info(LABEL, ":%s called", __func__); 
  8.     HiLog::Info(LABEL, "ListenAbility()"); 
  9.  
  10. ListenAbility::~ListenAbility() 
  11.     HiLog::Info(LABEL, "~ListenAbility()"); 
  12.  
  13. int ListenAbility::AddVolume(int volume) 
  14.     pid_t current = getpid(); 
  15.     HiLog::Info(LABEL, "ListenAbility::AddVolume volume = %d, pid = %d.", volume, current); 
  16.     return (volume + 1); 
  17.  
  18. void ListenAbility::OnDump() 
  19.  
  20. void ListenAbility::OnStart() 
  21.     HiLog::Info(LABEL, "ListenAbility::OnStart()"); 
  22.     HiLog::Info(LABEL, "ListenAbility:%s called:-----Publish------", __func__); 
  23.     bool res = Publish(this); 
  24.     if (res) { 
  25.         HiLog::Error(LABEL, "ListenAbility: res == false"); 
  26.     } 
  27.     HiLog::Info(LABEL, "ListenAbility:%s called:AddAbilityListener_OS_TST----beg-----", __func__); 
  28.     AddSystemAbilityListener(DISTRIBUTED_SCHED_TEST_OS_ID); 
  29.     HiLog::Info(LABEL, "ListenAbility:%s called:AddAbilityListener_OS_TST----end-----", __func__); 
  30.  
  31.     HiLog::Info(LABEL, "ListenAbility:%s called:StopAbility_OS_TST----beg-----", __func__); 
  32.     StopAbility(DISTRIBUTED_SCHED_TEST_OS_ID); 
  33.     HiLog::Info(LABEL, "ListenAbility:%s called:StopAbility_OS_TST----end-----", __func__); 
  34.     return
  35.  
  36. void ListenAbility::OnStop() 

5)SystemAbility配置

以c++实现的SA必须配置相关System Ability的profile配置文件才会完成SA的加载注册逻辑,否则没有编写profile配置的System Ability不会完成注册。配置方法如下:

在子系统的根目录新建一个以sa_profile为名的文件夹;然后在此文件夹中新建两个文件:一个以serviceId为前缀的xml文件;另外一个为BUILD.gn文件

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <info> 
  3.     <process>listen_test</process> 
  4.     <systemability> 
  5.     <name>serviceid</name
  6.     <libpath>/system/lib64/liblistentest.z.so</libpath> 
  7.     <run-on-create>true</run-on-create
  8.     <distributed>false</distributed> 
  9.     <dump-level>1</dump-level
  10. </systemability> 
  11. </info> 

BUILD.gn:

  1. import("//build/ohos/sa_profile/sa_profile.gni"
  2. ohos_sa_profile("xxx_sa_profile") { 
  3.     sources = [ 
  4.         "serviceid.xml" 
  5.     ] 
  6.     subsystem_name = "distributedschedule" 

6)rc配置文件

rc配置文件为linux提供的native进程拉起策略,为手机在开机启动阶段由init进程解析配置的rc文件进行拉起

  1. service listen_test /system/bin/sa_main /system/profile/listen_test.xml 
  2.     class z_core 
  3.     user system 
  4.     group system shell 
  5.     seclabel u:r:xxxx:s0 

2.3 接口说明

标准系统用户程序框架子系统提供权限管理基础校验能力,不对三方app开放,并提供如下API。

3.内部实现

3.1 类间关系

IPermissionManager:内部接口类

PermissionManagerProxy:IPC请求的代理类

PermissionManagerStub:IPC请求服务类

PermissionManagerClient:应用权限管理客户类

PermissionKit:组件对外接口类,真正对外提供STATIC接口函数

PermissionManagerService:应用权限功能服务类,调用PermissionStateManager和PermissionDefinitionManager

PermissionStateManager:真正的应用权限管理功能实现

PermissionDefinitionManager:真正的应用权限管理功能实现

3.2 内部逻辑

标准系统下应用权限管理功能是基于SAMgr管理框架实现,如何配置SAMgr框架见基础知识介绍,如果想学习更多细节参见SAMgr相关学习,这里专注于应用权限管理功能部分,并对代码逻辑关键节点进行分析和展示。

应用权限管理组件通过PermissionKit类以单例模式对外提供接口,PermissionKit类内部接口函数则调用PermissionManagerClient类,PermissionManagerClient则通过调用GetSystemAbility函数获取向SAMgr注册过的代理类单例PermissionManagerProxy。

代码如下:

  1. sptr<IPermissionManager> PermissionManagerClient::GetProxy() const 
  2.     auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 
  3.     if (sam == nullptr) { 
  4.         PERMISSION_LOG_DEBUG(LABEL, "%{public}s: GetSystemAbilityManager is null", __func__); 
  5.         return nullptr; 
  6.     } 
  7.     // 获取Proxy 
  8.     auto permissionSa = sam->GetSystemAbility(IPermissionManager::SA_ID_PERMISSION_MANAGER_SERVICE); 
  9.     if (permissionSa == nullptr) { 
  10.         PERMISSION_LOG_DEBUG(LABEL, "%{public}s: GetSystemAbility %{public}d is null", __func__, 
  11.             IPermissionManager::SA_ID_PERMISSION_MANAGER_SERVICE); 
  12.         return nullptr; 
  13.     } 
  14.  
  15.     auto proxy = iface_cast<IPermissionManager>(permissionSa); 
  16.     if (proxy == nullptr) { 
  17.         PERMISSION_LOG_DEBUG(LABEL, "%{public}s: iface_cast get null", __func__); 
  18.         return nullptr; 
  19.     } 
  20.     return proxy; 

在获取代理类PermissionManagerProxy后,PermissionManagerProxy内部不同功能接口函数会调用SendRequest函数发起IPC请求服务。

示例代码如下(删去省略部分):

  1. int PermissionManagerProxy::VerifyPermission( 
  2.     const std::string& bundleName, const std::string& permissionName, int userId) 
  3.     // 省略部分 
  4.     ..................... 
  5.     // 发送请求服务 
  6.     int32_t requestResult = remote->SendRequest( 
  7.         static_cast<uint32_t>(IPermissionManager::InterfaceCode::VERIFY_PERMISSION), data, reply, option); 
  8.     if (requestResult != NO_ERROR) { 
  9.         PERMISSION_LOG_ERROR(LABEL, "%{public}s send request fail, result: %{public}d", __func__, requestResult); 
  10.         return PERMISSION_NOT_GRANTED; 
  11.     } 
  12.  
  13.     int32_t result = reply.ReadInt32(); 
  14.     PERMISSION_LOG_DEBUG(LABEL, "%{public}s get result from server data = %{public}d", __func__, result); 
  15.     return result; 

其中接口类IPermissionManager中定义了IPC通信的请求码。

示例代码如下(删去省略部分):

  1. class IPermissionManager : public IRemoteBroker { 
  2. public
  3.     static const int SA_ID_PERMISSION_MANAGER_SERVICE = 3501; 
  4.  
  5.     DECLARE_INTERFACE_DESCRIPTOR(u"ohos.security.permission.IPermissionManager"); 
  6.  
  7.     virtual int VerifyPermission(const std::string& bundleName, const std::string& permissionName, int userId) = 0; 
  8.     // 省略部分 
  9.     ................................ 
  10.     // 请求码 
  11.     enum class InterfaceCode { 
  12.         VERIFY_PERMISSION = 0xff01, 
  13.         CAN_REQUEST_PERMISSION = 0xff02, 
  14.         GRANT_USER_GRANTED_PERMISSION = 0xff03, 
  15.         GRANT_SYSTEM_GRANTED_PERMISSION = 0xff04, 
  16.         REVOKE_USER_GRANTED_PERMISSION = 0xff05, 
  17.         REVOKE_SYSTEM_GRANTED_PERMISSION = 0xff06, 
  18.         ADD_USER_GRANTED_REQ_PERMISSIONS = 0xff07, 
  19.         ADD_SYSTEM_GRANTED_REQ_PERMISSIONS = 0xff08, 
  20.         REMOVE_USER_GRANTED_REQ_PERMISSIONS = 0xff09, 
  21.         REMOVE_SYSTEM_GRANTED_REQ_PERMISSIONS = 0xff10, 
  22.         ADD_DEF_PERMISSIONS = 0xff11, 
  23.         REMOVE_DEF_PERMISSIONS = 0xff12, 
  24.         GET_DEF_PERMISSION = 0xff13, 
  25.     }; 
  26. }; 

PermissionManagerService类则由于继承了PermissionManagerStub,会在接口函数OnRemoteRequest函数接收到代理PermissionManagerProxy通过IPC通信发送的不同请求,进而进行处理。

示例代码如下:

  1. int32_t PermissionManagerStub::OnRemoteRequest( 
  2.     uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option
  3.     PERMISSION_LOG_INFO(LABEL, "%{public}s called, code: %{public}d", __func__, code); 
  4.     std::u16string descriptor = data.ReadInterfaceToken(); 
  5.     if (descriptor != IPermissionManager::GetDescriptor()) { 
  6.         PERMISSION_LOG_ERROR(LABEL, "get unexpect descriptor: %{public}s", Str16ToStr8(descriptor).c_str()); 
  7.         return RET_FAILED; 
  8.     } 
  9.     switch (code) { 
  10.         case static_cast<uint32_t>(IPermissionManager::InterfaceCode::VERIFY_PERMISSION): 
  11.             VerifyPermissionInner(data, reply); 
  12.             break; 
  13.         case static_cast<uint32_t>(IPermissionManager::InterfaceCode::CAN_REQUEST_PERMISSION): 
  14.             CanRequestPermissionInner(data, reply); 
  15.             break; 
  16.         case static_cast<uint32_t>(IPermissionManager::InterfaceCode::GRANT_USER_GRANTED_PERMISSION): 
  17.             GrantUserGrantedPermissionInner(data, reply); 
  18.             break; 
  19.         // 省略部分 
  20.         ....... 
  21.  
  22.         default
  23.             return IPCObjectStub::OnRemoteRequest(code, data, reply, option); 
  24.     } 
  25.     return NO_ERROR; 

最终PermissionManagerService则调用PermissionStateManager和PermissionDefinitionManager类所提供的函数做具体的功能实现。

4.总结

当今设备安全问题已经越来越引起不同行业的重视,OpenHarmney安全子系统作为系统基础能力之一对开发设备的安全性尤为重要,对系统框架开发来说很有必要学习其内部原理并对代码结构深入了解,本文档抛砖引玉介绍了标准系统下应用权限管理的相关逻辑框架,后续随着学习的深入将不断完善对安全子系统的解读。

想了解更多内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

【编辑推荐】

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区
  2. HarmonyOS Sample 之 Pasteboard 分布式粘贴板
  3. 通过电竞快览应用学ArkUI
  4. HarmonyOS Codelabs之Js2JavaCodegen JSFA调用PA工具
  5. HarmonyOS ArkUI之仿微信朋友圈图片预览
  6. HarmonyOS ArkUI之仿微信图片选择
【责任编辑:jianghua TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+更多

带你轻松入门 RabbitMQ

带你轻松入门 RabbitMQ

轻松入门RabbitMQ
共4章 | loong576

56人订阅学习

数据湖与数据仓库的分析实践攻略

数据湖与数据仓库的分析实践攻略

助力现代化数据管理:数据湖与数据仓库的分析实践攻略
共3章 | 创世达人

14人订阅学习

云原生架构实践

云原生架构实践

新技术引领移动互联网进入急速赛道
共3章 | KaliArch

42人订阅学习

视频课程+更多

强哥带你学习k8s

强哥带你学习k8s

讲师:周玉强5467人学习过

Python自动化办公

Python自动化办公

讲师:张同乐28920人学习过

企业实战:中级篇之 MDT批量部署 Win10 Win7

企业实战:中级篇之 MDT批量部署 Win10 Win7

讲师:莫振华16197人学习过

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO官微