Samgr_lite——如何注册一个服务?
由于上一篇博文讲的是broadcast服务的广播publish机制,所以本篇博文就以broadcast service为例简单谈谈自己的看法,不妥之处还望观众老爷批评指正
这里贴上上一篇博文的链接,方便大家更加清晰地把握整个脉络
SA框架下的基于Publish函数的广播机制
本篇文章主要讲一些准备工作,比如SA框架的一些知识和一些结构体的准备和consumer、subscriber、provider、samgr之间的关系,下一篇文章将从代码剖析如何在系统中注册一个服务
1. SA框架简介
SA框架又称系统服务框架(system ability framework)是为了屏蔽不同硬件架构,不同的平台资源和不同运行状态等软硬件差异而提供的同一的系统服务开发框架
据RISC-V、Cortex-M、Cortex-A不同硬件平台,分为两种平硬件平台,以下简称M核、A核
- M核:处理器架构为Cortex-M或同等处理能力的硬件平台,系统内存一般低于512KB,无文件系统或者仅提供一个可有限使用的轻量级文件系统,遵循CMSIS接口规范
- A核:处理器架构为Cortex-A或同等处理能力的硬件平台,内存资源大于512KB,文件系统完善,可存储大量数据,遵循POSIX接口规范
系统服务框架基于面向服务的架构,提供了服务开发、服务子功能开发、对外接口开发以及多服务共进程、进程间服务调用等开发能力
针对硬件平台的能力不同:
- M核:包含服务开发、服务的子功能开发、对外接口的开发以及多服务共进程的开发框架
- A核:在M核能力基础之上,包含了进程间服务调用、进程间服务调用权限控制、进程间服务接口开发等更高级的开发能力
SA框架的几大特点:
- 同一使用C开发
- 同一使用iunknown接口,消息同一由其传入服务中
- M核依赖bootstrap服务,在系统启动函数中调用HOS_SystemInit()函数
- A核系统依赖samgr库,在main函数中调用SAMGR_Bootstrap()函数——而该函数也是服务初始化的入口,后文会提到
- SA主要用于后台运行任务,不提供用户交互界面
- service是单例的,在一个设备上,相同的service只会存在一个实例,当多个ability公用该实例时,只有当所有绑定的ability都退出后,service才能够退出
首先我们来探究一些关键的结构体和定义
2. 服务的结构体准备
2.1 consumer
Consumer作用:用于接受对应topic的事件并进行数据传输
struct Consumer{
const Identity *identity;
//函数指针用于定义consumer如何处理事件或发布topic
//origin:请求的数据
void (*Notify)(Consumer *consumer, const Topic *topic, const Request *origin);
//函数指针实现两个consumer的比较
BOOL (*Equal)(const Consumer *current, const Consumer *other);
}
//每个consumer有三个id作为身份认证
struct Identity {
/** Service ID */
int16 serviceId;
/** Feature ID */
int16 featureId;
/** Message queue ID */
MQueueId queueId;
};
然后我们可以看到ConsumerNode——在上一篇博客中我们也可以知道广播时是对一个链表中的consumer进行信息广播,而该链表中的结点便是ConsumerNode
typedef struct ConsumerNode {
//用于操作的链表
UTILS_DL_LIST node;
//每个consumer的实际信息存储
Consumer *consumer;
} ConsumerNode;
结构体Relation保存了每个consumer结点对应的topic
typedef struct Relation {
UTILS_DL_LIST node;//relation的结点
ConsumerNode callbacks;//consumer结点
Topic topic;//对应的topic
} Relation;
2.2 subscriber&provider
然后就是发布内容和提供广播的subscriber和provider
//仅封装一个函数指针
struct Provider{
//根据某topic进行publish事件与数据
BOOL (*Publish)(IUnknown *iUnknown, const Topic *topic, uint8 *data, int16 len);
//iUnknown:指定pubsub feature扩展接口
}
对应的方法在pub_sub_implement.c中被实现
相当于数据和topic的扩展接口,更方便的对consumer和topic进行操作
struct Subscriber{
//用于添加特定topic到广播服务
int (*AddTopic)(IUnknown *iUnknown, const Topic *topic);
//为指定的consumer订阅指定topic
int (*Subscribe)(IUnknown *iUnknown, const Topic *topic, Consumer *consumer);
//修改特定topic对应的consumer
Consumer *(*ModifyConsumer)(IUnknown *iUnknown, const Topic *topic, Consumer *old, Consumer *current);
//为consumer退订对应的topic
Consumer *(*Unsubscribe)(IUnknown *iUnknown, const Topic *topic, const Consumer *consumer);
}
对应的四个方法在pub_sub_implement.c中也被实现
2.3 PubSubInterface
将subscriber&provider封装入该结构体中成为一个整体
struct PubSubInterface {
INHERIT_IUNKNOWN;//定义了iunknown最基本的三个函数
Subscriber subscriber;
Provider provider;
};
在iunknown.h中define了INHERIT_IUNKNOWN
对应的功能可以看上一篇文章中对于iunknown的解读,这里不再赘述
#define INHERIT_IUNKNOWN \
int (*QueryInterface)(IUnknown *iUnknown, int version, void **target); \
int (*AddRef)(IUnknown *iUnknown); \
int (*Release)(IUnknown *iUnknown)
2.4 PubSubFeature
定义了获取relation的方法和relations链表以及feature的四个”继承“方法
struct PubSubFeature {
//feature的继承实现(四个函数指针)
INHERIT_FEATURE;
//GetRelation函数指针用于获取在list中与给定topic相同的relation
Relation *(*GetRelation)(PubSubFeature *feature, const Topic *topic);
//互斥锁id,通过id进行互斥锁的获取保证数据的同步
MutexId mutex;
//relations
Relation relations;
//同样有三个feature作为pubsubFeature的身份认证
Identity identity;
};
INHERIT_FEATURE定义在feature.h中
#define INHERIT_FEATURE \
const char *(*GetName)(Feature *feature); \
void (*OnInitialize)(Feature *feature, Service *parent, Identity identity); \
void (*OnStop)(Feature *feature, Identity identity); \
BOOL (*OnMessage)(Feature *feature, Request *request)
这里define的四个函数指针刚好对应了pub_sub_feature.c中实现的四个函数
GetRelation()函数
这里有一个有意思的地方,在getRelation函数中,list是从&feature->relations.node中取得,而我们从结构体中看relations的类型也是relation,所以relation内部应该是建立了链表的(才能进行循环),但是在结构体中我们看到的只有两个node——UTILS_DL_LIST和consumer——可能就是这两个结点另有玄机,由于代码的不全,这里只是大胆推测结点肯定是通过某种逻辑进行连接使得每个consumer的信息上链能够操作——具体操作还需另寻材料分析
2.5 PubSubImplement
可以看到最后的implement包括了iunknown接口和feature的
typedef struct PubSubImplement {
INHERIT_IUNKNOWNENTRY(PubSubInterface);
PubSubFeature *feature;
} PubSubImplement;
INHERIT_IUNKNOWNENTRY
//iunknown的入口define
#define INHERIT_IUNKNOWNENTRY(T) \
uint16 ver; \
int16 ref; \
T iUnknown
注意这里的iUnknown的类型为T——也就是PubSubInterface(包括subscriber和provider)
在广播服务中使用的实例结构体就是PubSubImplement
3. 面向服务的架构
最后给一张关于consumer、subscriber和provider三者的关系图
服务的注册和初始化将在下一篇文章中探究