Samgr_lite——如何注册一个服务?(以广播服务为例
有了前两篇的铺垫,那么本文章将正式讲解如何注册一个服务。这里贴上前两篇的链接,大家可以提前食用再往下阅读本文
SA框架下的基于Publish函数的广播机制
Samgr_lite——如何注册一个服务?(以广播服务为例)(序章)
话不多说开工!
1. 从broadcast服务开始说起
那么我们直接从源码开始
1.1 Init
初始化注册的代码只有一行:
没错!只有一行!鸿蒙就是这么硬核,但是别小看了一行代码,注册服务的功能的玄机就在这一行代码中
首先我们从SAMGR_GetInstance()看起
1.2 SAMGR_GetInstance()
函数返回的类型是SamgrLite,从samgr_lite.h中可以看到该结构体的定义
typedef struct SamgrLite{
BOOL (*RegisterService)(Service *service);
Service *(*UnregisterService)(const char *name);
BOOL (*RegisterFeature)(const char *serviceName, Feature *feature);
Feature *(*UnregisterFeature)(const char *serviceName, const char *featureName);
BOOL (*RegisterDefaultFeatureApi)(const char *service, IUnknown *publicApi);
IUnknown *(*UnregisterDefaultFeatureApi)(const char *service);
BOOL (*RegisterFeatureApi)(const char *service, const char *feature, IUnknown *publicApi);
IUnknown *(*UnregisterFeatureApi)(const char *service, const char *feature);
IUnknown *(*GetDefaultFeatureApi)(const char *service);
IUnknown *(*GetFeatureApi)(const char *serviceName, const char *feature);
int32 (*AddSystemCapability)(const char *sysCap);
BOOL (*HasSystemCapability)(const char *sysCap);
int32 (*GetSystemAvailableCapabilities)(char sysCaps[MAX_SYSCAP_NUM][MAX_SYSCAP_NAME_LEN], int32 *sysCapNum);
}
同样我们可以在samgr_lite.c中的init()函数中见到这些函数指针具体指向的那些函数
然后我们在SAMGR_GetInstance()中还能看到一个static g_samgrImpl它的类型为SamgrLiteImpl
在samgr_lite_inner.h中可以看到该结构体的定义:
struct SamgrLiteImpl {
SamgrLite vtbl;//用于实现samgrLite中的函数指针
MutexId mutex;//互斥锁序号
BootStatus status;//状态
Vector services;//服务向量
TaskPool *sharedPool[MAX_POOL_NUM];//任务线程池
};
那么我们也能够理解SAMGR_GetInstance()在具体干什么:
当g_samgrImpl没用初始化时,调用Init对g_samgrImpl结构体的各属性进行初始化赋值并返回g_samgrImpl.vtbl
这里简单阐明SamgrLiteImpl 各个属性的作用
- SamgrLite vtbl:通过init初始化后函数指针与对应的实现指针关联,就能够通过vtbl中的函数对service、feature和api进行注册、注销和获取API等操作
- MutexId mutex:互斥锁,保证多线程下共享数据的同步,它的实现取决于平台使用的内核,M核使用cmsis实现,A核使用posix(可移植操作系统接口)进行实现——从SAMGR_GetInstance()中我们也可以看到是根据SamgrLiteImpl中互斥锁是否为NULL来判断是否需要初始化,也可以说每一个SamgrLiteImpl对应唯一的mutexId
- BootStatus status:service启动的状态对应
- Vector services:samgr通过vector管理所有注册的子服务(通过samgrImpl来关联具体的service和feature)
- TaskPool *sharedPool[MAX_POOL_NUM] :为每个service创建的taskPool资源,通过GetTaskConfig()返回每个service运行起来的task参数配置
1.3 RegisterService()
看到该行初始化代码的后半段:SAMGR_GetInstance()给g_samgrImpl初始化后返回了vtbl并调用了其中的函数RegisterService
SAMGR_GetInstance()->RegisterService((Service *)&g_broadcastService);
传入的参数为g_broadcastService——其类型为BroadcastService,在broadcast_service.h中有其定义:
typedef struct BroadcastService BroadcastService;
struct BroadcastService {
INHERIT_SERVICE;
};
//service.h
#define INHERIT_SERVICE \
const char *(*GetName)(Service * service); \
BOOL (*Initialize)(Service * service, Identity identity); \
BOOL (*MessageHandle)(Service * service, Request * request); \
TaskConfig (*GetTaskConfig)(Service * service)
而service结构体同样实现了这四种函数指针——算是一种继承或者重载
所以传参的时候也可以使用类型转换将BroadcastService转换为Service类型
然后我们看向最重要的登记服务函数
服务流程:首先调用GetImplement返回一个samgr实例---->通过VECTOR_FindByKey匹配samgr已登记的service与新加入的服务是否重复——因为服务都是单例模式,所以这里需要查找---->找到(pos>=0说明存在该服务)则释放互斥锁终止服务登记---->没找到则检查最大服务支持---->调用SAMGR_CreateServiceImpl创建一个serviceImpl---->调用VECTOR_Add为新建的serviceImpl获取新的serviceId
实际到广播服务则是传入广播服务的g_broadcastService进入RegisterService(SAMGR_GetInstance只执行一次,如果起先已经存在g_samgrImpl则不需要再次初始化)为广播服务创建一个新的ServiceImpl并获取id添加到VECTOR管理队列中
之后就能够调用广播服务了
ps:这里还涉及了一个结构体serviceImpl我们留到下一篇博客结合服务初始化的三步走进行讲解
1.4 广播服务注册流程图
结合以上的分析和流程图我们大致分析了广播服务是如何进行初始化和注册的
2. 服务初始化的三步走
上面以广播服务的注册为例讲了服务的注册和登记,但是服务创建的完整流程需要分三步走
- 注册系统服务(service)
- 注册系统服务功能(feature)
- 通过samgr启动并初始化所有的系统服务和功能
具体的服务开启的过程留在续章接着展开