OpenHarmony源碼解析之安全子系統(tǒng) (應用權限管理)
1.簡介
安全子系統(tǒng)為OpenHarmony提供有效保護應用和用戶數(shù)據(jù)的能力。
主要功能: 系統(tǒng)安全、數(shù)據(jù)安全、應用安全等;
目前開源功能: 應用完整性保護、應用權限管理、設備認證、密鑰管理服務、數(shù)據(jù)分級保護;
應用權限管理: 為程序框架子系統(tǒng)提供權限管理功能,并且為上層應用提供權限申請和授權狀態(tài)查詢接口。
本文將介紹標準系統(tǒng)下安全子系統(tǒng)應用權限管理部分如何在系統(tǒng)內(nèi)適配及實現(xiàn),盡力深入細節(jié)部分。
1.1 OpenHarmony 架構圖

1.2 安全子系統(tǒng)

1.3 應用權限管理
OpenHarmony中應用和系統(tǒng)服務均運行在獨立的沙箱中,進程空間和程序數(shù)據(jù)都是相互隔離的,以保護應用數(shù)據(jù)的安全性;但是運行在獨立沙箱中的服務或應用同時需要對外提供一些API以實現(xiàn)所需功能,其他獨立沙箱中的應用在跨進程訪問這些API時,需要系統(tǒng)提供一種權限管理機制對這些API的訪問者進行授權。
應用權限管理提供了權限定義機制,允許系統(tǒng)服務和應用為自己的敏感API定義新的權限,其他應用必須申請此權限才能訪問此敏感API;
應用權限管理提供了權限申請機制,允許應用申請權限,這些權限由系統(tǒng)或者其他應用定義,權限申請通過后就能訪問這個權限相關的系統(tǒng)或其他應用提供的敏感API;
應用權限管理也為用戶提供了一些必須的功能,方便用戶查看和管理權限授予情況。

2.基礎知識
2.1 代碼結構
- /base/security/permission
- ├── frameworks # 基礎設施層
- │ └── permission_standard # 標準系統(tǒng)權限管理基礎設施層
- ├── interfaces # 接口層
- │ ├── innerkits # 內(nèi)部接口層
- │ │ ├── permission_lite # 輕量系統(tǒng)、小型系統(tǒng)權限管理內(nèi)部接口層
- │ │ └── permission_standard # 標準系統(tǒng)權限管理內(nèi)部接口層
- │ └── kits # 外部接口層
- │ ├── permission_lite # 輕量系統(tǒng)、小型系統(tǒng)權限管理外部接口層
- │ └── permission_standard # 標準系統(tǒng)權限管理外部接口層
- └── services # 服務層
- ├── permission_lite # 輕量系統(tǒng)、小型系統(tǒng)權限管理服務層
- └── permission_standard # 標準系統(tǒng)權限管理服務層
2.2 SystemAbility
應用權限管理模塊是以SystemAbility的形式對外提供能力的,在分布式任務調(diào)度子系統(tǒng)中safwk組件定義OpenHarmony中SystemAbility的實現(xiàn)方法,并提供啟動、注冊等接口實現(xiàn)。
實現(xiàn)一個SystemAbility需要六個步驟:
1)定義該服務對外提供的能力集合函數(shù)
- 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 OHOS
3) 定義服務端通信代碼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的實現(xiàn)類
- 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++實現(xiàn)的SA必須配置相關System Ability的profile配置文件才會完成SA的加載注冊邏輯,否則沒有編寫profile配置的System Ability不會完成注冊。配置方法如下:
在子系統(tǒng)的根目錄新建一個以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
2.3 接口說明
標準系統(tǒng)用戶程序框架子系統(tǒng)提供權限管理基礎校驗能力,不對三方app開放,并提供如下API。
3.內(nèi)部實現(xiàn)
3.1 類間關系
IPermissionManager:內(nèi)部接口類
PermissionManagerProxy:IPC請求的代理類
PermissionManagerStub:IPC請求服務類
PermissionManagerClient:應用權限管理客戶類
PermissionKit:組件對外接口類,真正對外提供STATIC接口函數(shù)
PermissionManagerService:應用權限功能服務類,調(diào)用PermissionStateManager和PermissionDefinitionManager
PermissionStateManager:真正的應用權限管理功能實現(xiàn)
PermissionDefinitionManager:真正的應用權限管理功能實現(xiàn)
3.2 內(nèi)部邏輯
標準系統(tǒng)下應用權限管理功能是基于SAMgr管理框架實現(xiàn),如何配置SAMgr框架見基礎知識介紹,如果想學習更多細節(jié)參見SAMgr相關學習,這里專注于應用權限管理功能部分,并對代碼邏輯關鍵節(jié)點進行分析和展示。
應用權限管理組件通過PermissionKit類以單例模式對外提供接口,PermissionKit類內(nèi)部接口函數(shù)則調(diào)用PermissionManagerClient類,PermissionManagerClient則通過調(diào)用GetSystemAbility函數(shù)獲取向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內(nèi)部不同功能接口函數(shù)會調(diào)用SendRequest函數(shù)發(fā)起IPC請求服務。
示例代碼如下(刪去省略部分):
- int PermissionManagerProxy::VerifyPermission(
- const std::string& bundleName, const std::string& permissionName, int userId)
- {
- // 省略部分
- .....................
- // 發(fā)送請求服務
- 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,會在接口函數(shù)OnRemoteRequest函數(shù)接收到代理PermissionManagerProxy通過IPC通信發(fā)送的不同請求,進而進行處理。
示例代碼如下:
- 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則調(diào)用PermissionStateManager和PermissionDefinitionManager類所提供的函數(shù)做具體的功能實現(xiàn)。
4.總結
當今設備安全問題已經(jīng)越來越引起不同行業(yè)的重視,OpenHarmney安全子系統(tǒng)作為系統(tǒng)基礎能力之一對開發(fā)設備的安全性尤為重要,對系統(tǒng)框架開發(fā)來說很有必要學習其內(nèi)部原理并對代碼結構深入了解,本文檔拋磚引玉介紹了標準系統(tǒng)下應用權限管理的相關邏輯框架,后續(xù)隨著學習的深入將不斷完善對安全子系統(tǒng)的解讀。