Hi3516的SAMGR--系统服务框架子系统-9-samgr EP的注册 原创 精华
Hi3516的SAMGR--系统服务框架子系统-9
samgr EP的注册
liangkz 2021.07.02
接下来我们看一下管理者g_server(包含samgr EP)的启动和对外提供服务的过程。
而foundation进程作为一个client,向管理者g_server注册的过程,与前文《系统服务框架子系统-8-client EP的注册》的完全一致,只是service和feature多了很多。
这次我们在分析流程的同时,对着log来验证(log文件也在前文-8附件中),由于任务调度的原因,log会有点交叉,稍显混乱,但同一个service/feature的log,在时间线上的先后顺序是没问题的,可以通过关键字搜索过滤出来。
SamgrServer g_server 在samgr_server.c文件内,是全局唯一的管理者服务对象,foundation进程依赖的一大堆service和feature中就包括了它,foundation进程跑main之前,先跑完它所依赖的所有service和feature的Init,跑到samgr_server.c的SYS_SERVICE_INIT(InitializeRegistry)时:
可以将其粗略分成4部分:
[4-1] SASTORA_Init(&g_server.store) 这是一个链表+向量的结构,后面详细讲,暂时也没打印log。
[4-2] g_server.samgr = SAMGR_CreateEndpoint("samgr", RegisterSamgrEndpoint),为g_server创建一个EP,因为这个EP很特殊,就是知名EP,要放在这里来创建,但还没开始“向自己注册自己”。
[4-3] RegisterService((Service *)&g_server),向本进程(foundation)的g_samgrImpl 注册服务。
[4-4] 创建Vector sysCapabilitys,调用ParseSysCap()来读取和分析“/etc/system_capability.json”文件,将系统的Capabilitys,按格式添加到Vector sysCapabilitys中去。“/etc/system_capability.json”文件是“//foundation/distributedschedule/samgr_lite/config/system_capability.json”文件的副本。
跑的log如下:
接下来就是等foundation进程跑main()函数,调用SAMGR_Bootstrap()去为它依赖的所有service(包括samgr)创建线程和消息队列:
在foundation依赖的所有service中(甚至整个用户态下的所有线程中),只有samgr线程的任务优先级别是PRI_BUTT-1 = 38这个级别的:
TaskConfig config = {LEVEL_HIGH, PRI_BUTT - 1, 0x400, 20, SINGLE_TASK};
看看PRI_BUTT的定义就知道了,通信相关的线程(即各个EP中的boss线程),优先级都已经PRI_ABOVE_NORMAL了,而samgr是通信的关键节点,它的优先级更高,都已经接近“Upper limit of the priority”,这也反映出通信效率在鸿蒙系统中至高的地位。
前文“线程/进程间通信模型”中说到的线程只有0到31个级别,数字越小,优先级别越高,这里怎么有超过31的级别,并且数字越大,优先级别越高呢?
“SAMGR_LINUX_ADAPTER”定义在 //foundation/distributedschedule/samgr_lite/samgr/adapter/BUILD.gn :
if (ohos_kernel_type == "linux") {
defines += [ "SAMGR_LINUX_ADAPTER" ]
}
原来上面定义的TaskPriority是用Linux内核的标准系统所使用的线程优先级别定义,而用LiteOS_A内核的小型系统,则会做一次转换,使用0到31这种级别来表示线程优先级,经过这样的转换,小型系统中的samgr的线程优先级是1,仍然是非常高级别的(更高级别的0级,可能是内核的什么线程,我没再往下深挖了)。
所以,samgr服务的task被创建出来之后,会优先得到系统的调度,去跑它的初始化,也就是要去跑DEFAULT_Initialize()的流程了:
四步,因为“NO Feature”,所以只跑前两步,但是第1步跑的samgr service的 Initialize() 函数有点特别:
它比别的service的Initialize()函数多跑了一个SAMGR_AddRouter(......,GET_IUNKNOWN(*server)),需要特别注意第四个参数:GET_IUNKNOWN(*server),这个参数可以保证proxy符合要求,确保这个router能够正确添加到管理者g_server->samgr这个EP的Vector routers里面去。
SAMGR_AddRouter()里面经过确保条件满足,将router添加到Vector routers里面去之后就Listen(endpoint),这是知名EP的第一个(也是唯一的一个)router,所以会创建一个boss线程,然后跑Receive()入口。因为线程调度的原因,Receive()的流程稍晚一点点去跑,也是内外两层while循环,但是因为内层执行的registerEP函数指针指向的是RegisterSamgrEndpoint(),也就是samgr EP向自己注册自己,所以非常快就OK了:
这个时候,g_server的知名EP,是这个样子的:
因为是知名EP,且没有Feature,Receive()的第3步也跳过,直接就StartLoop了,这就开始接收早于它的其他EP(ipc client)的IPC注册消息了,由Dispatch()函数进行下一步处理(后面会进一步分析),所以接下来的log中,你可以看到:
先前先跑起来向知名EP注册自己的client EP,经过若干次的 retry之后,终于注册上了,成功拿到了自己的handle。
回到samgr的DEFAULT_Initialize()流程第二步:
DEFAULT_Initialize_samgr->RegServiceApi(ServiceImpl->defaultApi[0])
实际调用的是:
SAMGR_RegisterServiceApi(......,ServiceImpl->defaultApi)
这里的defaultApi是 NULL 的,原因与前文中Broadcast服务的defaultApi为NULL是一样的。
三步流程中,第1步,初始化了foundation进程自己的g_remoteRegister,也为它创建了client EP,这个EP就是普通的client EP,也就是foundation进程自己对外进行IPC的通信终端,与上面的虽然也同在foundation进程内的server EP,是不一样的,看前文《线程/进程间通信模型》的图就明白了。
三步流程中,第2步,因为defaultApi是 NULL 的,会添加router失败,也就不会为client EP创建boss线程了,需要等后面的service成功添加第一个router的时候,才会创建boss线程。
接下来就是foundation进程的其它service,通过各自的消息队列收到Init消息,通过
[samgr_lite] HandleInitRequest: Initing_Service......
来跑各自的DEFAULT_Initialize()流程了,与client EP的注册流程完全一致,只不过是这个进程的service/feature很多,经过系统的调度之后,打印出来的log会有一些交叉,分析起来会有一点杂乱,不过通过搜索关键字来过滤一下,流程也是很清晰可证的。