Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往 原创 精华

发布于 2021-7-3 08:51
浏览
1收藏

Hi3516的SAMGR--系统服务框架子系统-11

Client与Client的IPC来往

liangkz 2021.07.03

 

Note:log见前文《Hi3516的SAMGR--系统服务框架子系统-8-client EP的注册》的附件。

 

进程A中的线程Aa(也就是service Aa)想要调用某个service/feature的接口,这个接口可能是进程A自己的线程Ab(也就是service Ab)提供的,也可能是进程B的线程Bc(也就是service Bc)提供的。

如果是同进程的不同服务提供的接口,那Aa只需要向自己进程的SamgrLiteImpl g_samgrImpl查询service/feature名字就可以拿到对应的IUnknown *iUnknown接口,因为是同进程内的相同虚拟地址空间,所以可以直接跨线程调用。如《系统服务框架子系统-4-面向服务架构的实现》中的测试程序所做的那样。

也就是通过调用

SAMGR_GetInstance()->GetDefaultFeatureApi(SERVICE_NAME)       或者

SAMGR_GetInstance()->FeatureApi(SERVICE_NAME,FEATURE_NAME)

来查询接口。

 

如果Aa想调用的service/feature接口是B进程提供的,那首先这个service,肯定在Aa所在进程的SamgrLiteImpl g_samgrImpl里面是找不到记录的,也就是serviceImpl = NULL:

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

所以,跨进程的服务/特性的调用,入口就在上面的SAMGR_FindServiceApi(service, feature)。

 

结合我们的log,搜索一下“%%%%%%%%%%%”这样一个字符串,这是我标记的一处入口(实际上搜索“SAMGR_FindServiceApi”也差不多)。

看一下log:

{[bundle_daemon_client]} Initialize: GetDefaultFeatureApi(bundle_daemon)

这是“bundle_daemon_client”在Initialize的时候,向自己所在进程的SamgrLiteImpl g_samgrImpl查询名字为“bundle_daemon”的服务的DefaultFeatureApi。

通过前后的log,我们可以知道bundle_daemon_client所在进程的信息“pid[ 5]/uid[ 7]/(*)handle[61](*)”,5号进程是“foundation”,而“bundle_daemon”服务是6号进程提供的。

所以会通过SAMGR_FindServiceApi(S[bundle_daemon],F[(null)])来查询“bundle_daemon”服务提供的接口。

 

SAMGR_FindServiceApi()及其辅助函数,涉及到了g_remoteRegister.clients 这个字段,我们先来理解一下。

这是一个向量,在本进程的 g_remoteRegister 初始化的时候,也对这个向量做了配置:

g_remoteRegister.clients =  VECTOR_Make((VECTOR_Key)SAMGR_GetSAName,  (VECTOR_Compare)SAMGR_CompareSAName);

向量的element:data[x]是一个IUnknown *proxy类型的指针,指向的是一个客户端代理的接口entry.iUnknown,通过这个指针,可以转换回IClientProxy类对象、IClientEntry类对象、IDefaultClient类对象,再通过IClientProxy类对象指针去访问后面的Invoke函数,或者通过IDefaultClient类对象指针去访问上面的IClientHeader header字段内的key、target等字段。

向量中每一个element,记录了本进程EP调用过的别的进程提供的服务接口相关的重要身份信息如名字、handle、token等,这样下次再调用的时候,直接在这里查询就能获得这些信息,不需要再次通过IPC去向samgr EP查询了,它的展开图如下:

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

SAMGR_FindServiceApi()的流程如下:

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

我们接着上面的log往下看一下,

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

这是第一次bundle_daemon_client 向samgr EP查询FeatureAPI,但是返回的 handle 是 -1,从接下来的DbgParse_g_server的信息来看,这个时候提供bundle_daemon服务的6号进程,还没有向samge EP注册EP和Feature,所以samgr EP自己也查不到。

 

再看第二次bundle_daemon_client 向samgr EP查询FeatureAPI,这回查到了,handle是38,token是0,也就是说,SAMGR_CreateIProxy()的第一步,拿到了SvcIdentity identity= {38, 0, 0},跟着接下来的流程跑,就会得到一个完整有效的IDefaultClient对象,把这个对象中的 .iUnknown 地址先保存到g_remoteRegister.clients 向量中去,然后通过这个.iUnknown 地址,就可以调用客户端代理的Invoke()接口,从而再通过IPC去远程调用bundle_daemon服务了。

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

Privider: Pid[6]/Uid[8]/handle[38]:bundle_daemon -> (null)

Consumer: Pid[5]/Uid[7]/Tid[53]

从这两句log可以看出,6号进程的bundle_daemon 服务是provider,查询并使用该服务的5号进程是consumer,这也是面向服务的架构的一种实现。

 

我们再看另外一个更明显的跨进程调用服务的例子:第一个应用进程launcher的孵化启动。

Log搜索“AppAppAppApp”,这是5号进程通过app_manager准备调用7号进程提供的“appspawn”服务来孵化launcher应用,它拿到了“appspawn”的handle 74、token 0和.iUnknown地址,并把该地址以及相关的重要信息添加到自己的clients向量中。

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

接下来app_spawn_client调用上面的Invoke{0x249cc84c},这个Invoke{0x249cc84c}就是ProxyInvoke()函数,通过它发送IPC消息给IpcMsg Rceiver::handle[74],token[0],让它的EP收到和处理该消息,这就到了上一小节提到的Dispatch()和HandleIpc()对IPC消息的处理流程了。

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

经过消息的转发和处理,最后是appspawn_service的Invoke()函数开始孵化launcher应用进程,桌面应用开始提供服务。

跨进程的服务接口调用到此结束。

 

刚好刚才去浏览标准系统的 //base/startup/appspawn_standard/目录,看了一下README_zh,看到下面这张图就贴过来了,除了通信方式不一样之外,大体流程是一样的。

Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往-开源基础软件社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-7-3 08:54:42修改
2
收藏 1
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐