[文章]Hi3516的SAMGR--系统服务框架子系统-11-Client与Client的IPC来往

阅读量0
0
2
文章转载自:liangkz

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:



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

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

看一下log:
  1. {[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 初始化的时候,也对这个向量做了配置:
  1. 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查询了,它的展开图如下:



SAMGR_FindServiceApi()的流程如下:




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



这是第一次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服务了。



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向量中。




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



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

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

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



回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友