Service、Feature和FeatureApi的初始化
在正篇留了个尾巴,就是讲解整个系统服务的初始化,从这篇开始展开
首先回顾下一个服务启动的三步走:
- 注册系统服务service
- 注册系统服务能力feature
- 通过samgr启动并初始化所有的服务
前一篇我们以broadcast服务为例讲解了如何注册系统服务service,那么注册系统服务能力feature的内容我们在这篇展开
这里贴上该系列前三篇的链接,方便同学们阅读:
SA框架下的基于Publish函数的广播机制
Samgr_lite——如何注册一个服务?(以广播服务为例)(序章)
Samgr_lite——如何注册一个服务?(以广播服务为例)(正篇)
开始正篇!
1. 注册系统服务service
首先把上一篇漏掉的部分在续章中补上
1.1 结构体ServiceImpl
上一篇讲了管理整个服务的SamgrLiteImpl类型的g_samgrImpl。具体需要管理什么呢?——就是系统service和feature和用户自定义的APP service和feature。而对每个系统或者APP服务进行管理的对象就是ServiceImpl
首先我们看看该结构体长什么样:
在g_samgrImpl全局变量的services Vector中记录了每个服务实例ServiceImpl的指针,并不直接记录和管理service和feature本身,在函数RegisterService中我们可以看到:
调用函数VECTOR_Add完成两件事:
- 首先将serviceImpl的指针存入g_samgrImpl.services.data[i]中,然后返回对应的index
- 将返回的index存入serviceImpl.serviceId作为后面取出serviceImpl的一个id属性
然后我们看回ServiceImpl中包含的属性:
- Service*service :指向当前ServiceImpl对应的具体service对象
这里出现的Service我们在讲述BroadcastService的时候提到过,这是所有service的服务,每个系统服务或者用户自定义的服务都需要继承其初始化的四个指针函数(在广播服务中提过)
struct Service{
const char *(*GetName)(Service * service);
BOOL (*Initialize)(Service * service, Identity identity);
BOOL (*MessageHandle)(Service * service, Request * request);
TaskConfig (*GetTaskConfig)(Service * service)
}
而其他结构体继承时,使用#define INHERIT_SERVICE,将四个函数指针加入服务结构体中并编写函数进行函数实现——实现类似Java的interface的实现或者说是Java抽象函数的实现(不知道这样形容恰不恰当)——也能算是在C中实现C++对象继承的类似功能
- IUnknown *defaultApi :继承IUnknown结构的service或者feature,都会有对应的三个接口函数指针
//简单阐明三个函数指针的用途
struct IUnkonwn{
//实现父类指针导具体子类对象service/feature指针的类型转换,获取子类提供的功能和服务
int (*QueryInterface)(IUnknown *iUnknown, int version, void **target);
//记录service/feature的引用数量
int (*AddRef)(IUnknown *iUnknown);
//释放对应的IUnknown接口
int (*Release)(IUnknown *iUnknown)
}
细致的三个函数指针的实现在iunknown.c中,后面有机会再详细展开
- TaskPool *taskPool:我们可以回想起在g_samgrImpl的属性中也有TaskPool的创建,关于任务池创建和类型、g_samgrImpl和serviceImpl的TaskPool的关系的阐明我们放在后续讲解中
- Vector features:每一个service会对应0个、1个或者多个feature,feature需要依赖service才能运行,但是这里仅仅是使用Vector来管理feature,类似g_samgrImpl通过Vector管理serviceImpl是一个道理,后面利用broadcast服务的pubsubfeature的注册为例讲解feature注册时会再次回顾这个机制
- int16 serviceId:在上面RegisterService中可以看到serviceId记录的是serviceImpl对象指针保存在g_samgrImpl.services.data中的index
- uint8 inited:对应了三个状态:
SVC_INIT表示初始化
SVC_IDIE表示空闲中
SVC_BUSY表示service正在处理消息事件 - Operations ops:保存了一些状态信息
需要注意的是这里的step实际上是整个系统的bootStatus
而这些状态也对应了整个服务的三个步骤:系统服务的注册---->用户APP服务的注册---->SAMGR启动所有服务初始化
BOOT_SYS状态对应了系统服务的注册
BOOT_APP状态对应了用户APP服务的注册
BOOT_DYNAMIC对那个了SMAGR启动所有服务的初始化状态
中间的WAIT的状态是一个过渡态
每个阶段的任务完成后对应的系统状态就会切换,直到进入BOOT_DYNAMIC状态,就进入一个平稳运行的状态
1.2 SAMGR_CreateServiceImpl
上一篇重点讲解了RegisterService的逻辑,而忽略了serviceImpl函数,上面提到了serviceImpl的结构体,所以这里也顺带对源代码进行解析
具体逻辑比较简单清晰——就是一些属性的初始化,注释在代码中给出
2. 注册系统服务能力feature
然后讲完service的注册后,我们以broadcast的feature:PubsubFeature的注册和初始化为例,讲解service中feature的注册
2.1 g_broadcastFeature
跟service类似,也有一个全局变量用于管理broadcast的feature,里面将五个函数指针初始化指向五个函数
2.2 g_pubSubImplement
PubSubImplement类型的全局变量g_pubSubImplement
其具体的初始化在pub_sub_implement.c中:
细心的同学可以发现这里注册的Publish就是第一篇文章中解析的Publish函数
由此我们可以推断出service的部分能力是通过feature来实现的——比如broadcast服务的广播服务能力就是通过PubSubImplement内的PubSubFeature中的Publish进行实现
接下来正式进入feature的登记和初始化过程
2.3 Init()
函数功能:PubSubFeature的注册
函数流程:
1.首先将全局变量g_broadcastFeature引入用feature指向它
2. 对于relation属性进行初始化---->给feature的互斥锁进行初始化
3. SAMGR_GetInstance()->RegisterFeature进行feature的登记(这里的SAMGR_GetInstance用于返回GetImplement()->vtbl)
4. 通过BCE_CreateInstance将新建的g_broadcastFeature加入g_pubSubImplement并使用apiEntry指向
5. 最后RegisterFeatureApi进行featureApi的登记和初始化
2.4 BCE_CreateInstance
这个函数比较简单:将传入的PubSubFeature添加到全局的g_pubSubImplement.feature中并返回g_pubSubImplement
这里有一个细节:传入的feature类型不是创建的PubSubFeature类型,而是Feature——相当于做了个强制类型转换——类似于父类指针能够指向子类对象,子类对象强制转换为父类对象
2.5 RegisterFeature
2.5.1 RegisterFeature()
函数功能:进行feature的注册
函数流程:
1.首先通过IsInvalidFeature判断feature是否存在,存在则无需注册返回false
2. 调用GetService返回参数serviceName对应的serviceImpl
3. 调用DEFAULT_GetFeature判断返回的serviceImpl是否存在所给的feature,存在则不需要注册
4. 最后调用DEFAULT_AddFeature通过featureImpl建立起feature和serviceImpl的联系
2.5.2 DEFAULT_AddFeature
函数功能:根据所给的serviceImpl和featureName通过Vector的操作返回FeatureImpl
2.6 RegisterFeatureApi
函数功能:featureApi的注册
以broadcast的feature为例
函数流程:
1.首先通过IsInvalidIUnknown判断传入的publicApi(对于broadcast的featureApi来说传入的是GET_IUNKNOWN(apiEntry)其中apiEntry是PubSubImplement类型)是否实现了iunknown的三个函数指针所需要的函数,没有实现则返回false
2. 通过GetService得到serviceName对应的serviceImpl
3. 当传入的feature参数为NULL时(有些服务没有feature),则将传入的publicApi赋给serviceImpl->defaultApi,没有feature则通过服务实体来提供API能力
4. 存在feature则通过DEFAULT_GetFeature得到featureImpl
5. 最后通过SAMGR_AddInterface将featureImpl->iUnknown = publicApi
这里需要注意的是从init传入的最后一个参数:
形参是:IUnknown *publicApi
实参是:GET_IUNKNOWN(*apiEntry) 原来的类型是PubSubImplement
所以猜想GET_IUNKNOWN()应该是一类类型提取或者转换的函数将其他类型转变为IUnknown
2.7 feature注册流程图
下面放上以上分析的图解供读者参考
3. 注册service和feature的些许总结
- 必须先注册初始化service才能注册初始化对应的feature
- service通过全局变量g_samgrImpl管理所有的ServiceImpl,一个服务对应一个ServiceImpl,一个ServiceImpl对应一个service结构体
- 一个ServiceImpl对应0个、1个或多个feature
- g_samgrImpl中的Vector中通过Vector管理所有的服务和feature,通过Vector的操作函数,能够根据name或id取得ServiceImpl和FeatureImpl,再对具体的service和feature进行相应的操作
- 注册初始化feature的时候还需要注册初始化featureApi
- 有feature的service可以通过feature来提供服务——比如broadcast服务通过PubSubFeature实现Publish服务
由于篇幅原因三步走的最后一步留在终章展开!