OpenHarmony 源码解析之安全子系统 (应用权限管理)
Posted HarmonyOS技术社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenHarmony 源码解析之安全子系统 (应用权限管理)相关的知识,希望对你有一定的参考价值。
作者:周永峰
1 简介
安全子系统为OpenHarmony提供有效保护应用和用户数据的能力。
主要功能: 系统安全、数据安全、应用安全等;
目前开源功能: 应用完整性保护、应用权限管理、设备认证、密钥管理服务、数据分级保护;
应用权限管理: 为程序框架子系统提供权限管理功能,并且为上层应用提供权限申请和授权状态查询接口。
本文将介绍标准系统下安全子系统应用权限管理部分如何在系统内适配及实现,尽力深入细节部分。
1.1 OpenHarmony 架构图
1.2 安全子系统
1.3 应用权限管理
OpenHarmony中应用和系统服务均运行在独立的沙箱中,进程空间和程序数据都是相互隔离的,以保护应用数据的安全性;但是运行在独立沙箱中的服务或应用同时需要对外提供一些API以实现所需功能,其他独立沙箱中的应用在跨进程访问这些API时,需要系统提供一种权限管理机制对这些API的访问者进行授权。
- 应用权限管理提供了权限定义机制,允许系统服务和应用为自己的敏感API定义新的权限,其他应用必须申请此权限才能访问此敏感API;
- 应用权限管理提供了权限申请机制,允许应用申请权限,这些权限由系统或者其他应用定义,权限申请通过后就能访问这个权限相关的系统或其他应用提供的敏感API;
- 应用权限管理也为用户提供了一些必须的功能,方便用户查看和管理权限授予情况。
2 基础知识
2.1 代码结构
/base/security/permission
├── frameworks # 基础设施层
│ └── permission_standard # 标准系统权限管理基础设施层
├── interfaces # 接口层
│ ├── innerkits # 内部接口层
│ │ ├── permission_lite # 轻量系统、小型系统权限管理内部接口层
│ │ └── permission_standard # 标准系统权限管理内部接口层
│ └── kits # 外部接口层
│ ├── permission_lite # 轻量系统、小型系统权限管理外部接口层
│ └── permission_standard # 标准系统权限管理外部接口层
└── services # 服务层
├── permission_lite # 轻量系统、小型系统权限管理服务层
└── permission_standard # 标准系统权限管理服务层
2.2 SystemAbility
应用权限管理模块是以SystemAbility的形式对外提供能力的,在分布式任务调度子系统中safwk组件定义OpenHarmony中SystemAbility的实现方法,并提供启动、注册等接口实现。
实现一个SystemAbility需要六个步骤:
1)定义该服务对外提供的能力集合函数
```c++
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**
```c++
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 OHOS
3) 定义服务端通信代码XXXStub
```c++
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的实现类**
```c++
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文件
serviceid.xml:
```html/xml
<?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:
```html/xml
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文件进行拉起
```html/xml
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
### 2.3 接口说明
标准系统用户程序框架子系统提供权限管理基础校验能力,不对三方app开放,并提供如下API
| 接口名 | 说明 |
| ------------------------------------------------------------ | ---------------------------------- |
| int VerifyPermission(const string& bundleName, const string& permissionName, int userId) | 校验应用是否已授予对应的权限 |
| bool CanRequestPermission(const string& bundleName, const string& permissionName, int userId) | 判断应用是否需要弹框申请权限 |
| int GrantUserGrantedPermission(const string& bundleName, const string& permissionName, int userId) | 授予应用对应的user_grant权限 |
| int GrantSystemGrantedPermission(const string& bundleName, const string& permissionName) | 授予应用对应的system_grant权限 |
| int RevokeUserGrantedPermission(const string& bundleName, const string& permissionName, int userId) | 撤销应用对应的user_grant权限 |
| int RevokeSystemGrantedPermission(const string& bundleName, const string& permissionName) | 撤销应用对应的system_grant权限 |
| int AddUserGrantedReqPermissions(const string& bundleName, const std::vector<string>& permList, int userId) | 添加应用申请的user_grant权限 |
| int AddSystemGrantedReqPermissions(const string& bundleName, const std::vector<string>& permList) | 添加应用申请的system_grant权限 |
| int RemoveUserGrantedReqPermissions(const string& bundleName, int userId) | 移除应用申请的所有user_grant权限 |
| int RemoveSystemGrantedReqPermissions(const string& bundleName) | 移除应用申请的所有system_grant权限 |
| int AddDefPermissions(const std::vector<PermissionDef>& permList) | 添加应用定义的权限 |
| int GetDefPermission(const string& permissionName, PermissionDef& permissionDefResult) | 获取指定权限名的权限定义信息 |
## 3 内部实现
### 3.1 类间关系
![16353220571.png](https://s4.51cto.com/images/blog/202111/23110455_619c5a579ebc489312.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
IPermissionManager:内部接口类
PermissionManagerProxy:IPC请求的代理类
PermissionManagerStub:IPC请求服务类
PermissionManagerClient:应用权限管理客户类
PermissionKit:组件对外接口类,真正对外提供STATIC接口函数
PermissionManagerService:应用权限功能服务类,调用PermissionStateManager和PermissionDefinitionManager
PermissionStateManager:真正的应用权限管理功能实现
PermissionDefinitionManager:真正的应用权限管理功能实现
### 3.2 内部逻辑
标准系统下应用权限管理功能是基于[SAMgr](https://gitee.com/openharmony/distributedschedule_samgr?_from=gitee_search)管理框架实现,如何配置SAMgr框架见基础知识介绍,如果想学习更多细节参见SAMgr相关学习,这里专注于应用权限管理功能部分,并对代码逻辑关键节点进行分析和展示。
应用权限管理组件通过PermissionKit类以单例模式对外提供接口,PermissionKit类内部接口函数则调用PermissionManagerClient类,PermissionManagerClient则通过调用GetSystemAbility函数获取向SAMgr注册过的代理类单例PermissionManagerProxy。
代码如下:
```c++
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请求服务。
示例代码如下(删去省略部分):
```c++
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通信的请求码
示例代码如下(删去省略部分):
```c++
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通信发送的不同请求,进而进行处理。
示例代码如下:
```c++
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类所提供的函数做具体的功能实现。
## 4 总结
当今设备安全问题已经越来越引起不同行业的重视,OpenHarmony安全子系统作为系统基础能力之一对开发设备的安全性尤为重要,对系统框架开发来说很有必要学习其内部原理并对代码结构深入了解,本文档抛砖引玉介绍了标准系统下应用权限管理的相关逻辑框架,后续随着学习的深入将不断完善对安全子系统的解读。
更多原创内容请关注:[开鸿 HarmonyOS 学院](https://harmonyos.51cto.com/column/59)
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
[想了解更多关于鸿蒙的内容,请访问:](https://harmonyos.51cto.com/#bkwz)
[51CTO和华为官方战略合作共建的鸿蒙技术社区](https://harmonyos.51cto.com/#bkwz)
https://harmonyos.51cto.com/#bkwz
::: hljs-center
![21_9.jpg](https://s2.51cto.com/images/20210924/1632469265578939.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
:::
以上是关于OpenHarmony 源码解析之安全子系统 (应用权限管理)的主要内容,如果未能解决你的问题,请参考以下文章
OpenHarmony 源码解析之DFX子系统-Hiview(上)
OpenHarmony 源码解析之多模输入子系统(事件派发流程)
OpenHarmony 源码解析之DFX子系统-标准系统接口使用说明
OpenHarmony ACE源码解析之JavaScript运行环境初始