Physical Address:
ChongQing,China.
WebSite:

OpenHarmony中SAMGR服务框架简介。
最近在开发鸿蒙座舱的过程中,原本以为其整个系统只是基于AOSP进行魔改,提供除ART之外的容器运行能力。但仔细研究了一下其系统服务的实现机制,发现其系统服务的管理存在独立于安卓原生ServiceManager之外的一套框架,即SAMGR。需要说明的是,OpenHarmony本身适配多种系统(A核对应标准系统,M核对应轻量系统),在本文中所对应的为标准系统。
在安卓系统中,系统服务框架基于ServiceManager。以Native服务为例,要注册发布一个服务涉及到启动配置(rc)、以及代码上的继承实现。通常分为以下几步:
//rc配置
service evs_app /system/bin/evs_app
class hal
priority -20
user automotive_evs
group automotive_evs
disabled
on late-init
start evs_app
//代码实现
1.Main函数中配置binder线程池
hardware::configureRpcThreadpool(5, /*willjoin*/ false);
2.Main函数中初始化binder通信基础
sp<ProcessState> proc(ProcessState::self());
3.Main函数中获取ServiceManager,与ServiceManager建立连接
sp<IServiceManager> sm = defaultServiceManager();
4.Main函数中进行服务发布
xxxxService::instantiate();
5.启动与加入线程池
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
而在OpenHarmony系统中,系统服务框架为SAMGR,也就是SystemAbility Manager。其与安卓系统的ServiceManager存在很大的区别,主要的差异点包括:
1.开发者不再需要实现Main函数,服务启动统一由sa_mian进行加载
2.开发者需要实现固定的接口,并将其编译为共享库,sa_main将通过dlopen的方式进行加载
3.每个服务都需要额外的配置文件,sa_main负责解析并依据配置进行启动
在鸿蒙系统的SAMGR服务框架中,服务实现的逻辑其实与安卓有相似之处,通过继承公有类的方式重载实现自身的逻辑。具体实现细节参考如下:
头文件实现:
//MyService.h
//以下头文件来自于OpenHarmony OS
#include "singleton.h"
#include "iremote_object.h"
#include "system_ability.h"
#include "ipc_object_stub.h"
class MyService : public OHOS::SystemAbility, public OHOS::IPCObjectStub, public OHOS::IRemoteObject::DeathRecipient, public OHOS::DelayedRefSingleton< MyService >
{
//构造函数&虚构函数
MyService(int32_t systemAbilityId = 5002, bool runOnCreate = true);
virtual ~ MyService ();
//单例实现
static MyService& GetInstance()
{
return DelayedRefSingleton< MyService>::GetInstance();
}
//继承自公有类的接口
std::string GetClassName() override;
void OnDump() override;
//服务启动
void OnStart() override;
//服务终止
void OnStop() override;
void OnRemoteDied(const OHOS::wptr<OHOS::IRemoteObject> &object) override;
}
源文件实现:
//MyService.cpp
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <linux/audit.h>
#include "log.h"
#include "MyService.h"
#define LOG_TAG " MyService"
using namespace std;
using namespace OHOS;
// Static function for pthread
static void* InitThreadFunc(void* arg)
{
MyService* self = static_cast< MyService*>(arg);
self->init();
return nullptr;
}
//构造函数
//需要注意这里的systemAbilityId与xml中配置的需要保持一致
MyService::MyService(int32_t systemAbilityId, bool runOnCreate) : SystemAbility(systemAbilityId, runOnCreate), IPCObjectStub(OHOS::to_utf16("MyService"))
{
HILOGI(LOG_TAG, " MyService constructor called, saId=%{public}d, runOnCreate=%{public}d", systemAbilityId, runOnCreate);
}
//析构函数
MyService::~ MyService()
{
}
//重要,必须实现
std::string MyService::GetClassName()
{
return "MyService";
}
void MyService::OnDump()
{
HILOGI(LOG_TAG, "MyService OnDump");
}
void MyService::init(void)
{
HILOGI(LOG_TAG, "MyService::init() called, entering loop");
while(1)
{
//服务循环体
}
}
void MyService::OnStart()
{
OHOS::SystemAbility::OnStart();
sptr<OHOS::IRemoteObject> remoteObject = this;
bool result = Publish(remoteObject);
if (!result) {
HILOGE(LOG_TAG, " MyService start failed! Publish returned false");
return;
}
// Start init() in a separate thread to avoid blocking OnStart()
pthread_t threadId;
int ret = pthread_create(&threadId, nullptr, InitThreadFunc, this);
if (ret != 0) {
HILOGE(LOG_TAG, "Failed to create init thread, error: %{public}d", ret);
} else {
HILOGI(LOG_TAG, "Init thread created successfully");
pthread_detach(threadId);
}
}
//重载实现onStop
void MyService::OnStop()
{
HILOGI(LOG_TAG, " MyService OnStop");
OHOS::SystemAbility::OnStop();
}
//重载实现onRemoteDied
Void MyService::OnRemoteDied(const OHOS::wptr<OHOS::IRemoteObject> &object)
{
(void)object;
HILOGW(LOG_TAG, "OnRemoteDied.");
}
// Register SystemAbility when library is loaded
// This is called automatically when the library is loaded by sa_main
REGISTER_SYSTEM_ABILITY_BY_ID(MyService, 5002, true);
在服务配置上,SAMGR还需要一份配置文件,以便让sa_main在启动阶段知道加载对应的共享库。在OHOS系统中,这份配置文件以xml形式存在,放置在/system/profile/目录下,其内容大体如下(注:不同OpenHarmony版本存在差异):
<?xml version="1.0" encoding="utf-8"?>
<info>
<process>vhssrv</process>
<loadlibs>
<libpath>libvhssrv.z.so</libpath>
</loadlibs>
<systemability>
<name>2654</name>
<libpath>libvhssrv.z.so</libpath>
<run-on-create>true</run-on-create>
<distributed>false</distributed>
<dump-level>1</dump-level>
</systemability>
</info>
在这份xml配置中,process标签用于表明该服务的进程名,libpath标签用于表明sa_main启动服务时需要加载的动态库,而SystemAbility标签则用于对该系统服务进行更细致的控制。
<name>标签用于表明该SA ID,这是SystemAbility服务中的唯一ID标识;该ID在我们实现服务时需要匹配;
<libpath>标签用于表明该SA的动态库路径;
<run-on-create>标签用于表明该SA是否自启动,true即代表需要自启动,false则无需自启动;
<distributed>标签用于表明该SA是否支持分布式访问;
<dump-level>标签用于配置管理和调试权限;
同时,我们在rc启动配置中需要对sa_main的启动进行显式说明,如下所示:
service sai-daemon /system/bin/sa_main /system/profile/sai_daemon.xml
class core
user root
group root
seclabel u:r:su:s0
这里sai-daemon服务,就是通过sa_main读取/system/profile/sai_daemon.xml中的配置,从而将服务注册到SAMGR中。
当我们的服务启动后,我们如何在其他的进程中(Client)获取该服务并建立连接呢。
简单来说,Client可使用 SystemAbilityManagerClient 获取 SystemAbilityManager 实例,然后调用 GetSystemAbility 获取服务的代理对象(IRemoteObject)。
#include "isystem_ability_manager.h"
#include "if_system_ability_manager.h"
#include "iservice_registry.h"
// 1. 获取 SystemAbilityManager 单例实例
sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (sam == nullptr) {
// 处理获取失败逻辑
return;
}
// 2. 指定想要获取的 SA 的 ID (例如:SAMPLE_SERVICE_ID)
int32_t systemAbilityId = 1234;
// 3. 向 SAMGR 获取服务代理对象
sptr<IRemoteObject> remoteObject = sam->GetSystemAbility(systemAbilityId);
if (remoteObject == nullptr) {
// 处理找不到服务逻辑
return;
}
// 4. 将 remoteObject 转换为具体的服务代理类(如 ISampleService)
// sptr<ISampleService> serviceProxy = iface_cast<ISampleService>(remoteObject);