当前位置: 首页 > 科技观察

Hi3516之SAMGR--SystemServiceFrameworkSubsystem-11-Client与客户端IPC通信

时间:2023-03-11 22:01:43 科技观察

更多内容请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.comThreadAa(即,serviceAa)inprocessA想要调用服务/功能接口。这个接口可能是进程A自己的线程Ab(即服务Ab)提供的,也可能是进程B的线程Bc(即服务Bc)提供的。如果是同一个进程的不同服务提供的接口,那么Aa只需要从自身进程的SamgrLiteImplg_samgrImpl中查询服务/特性名称就可以得到对应的IUnknown*iUnknown接口,因为是同一个虚拟地址空间同一个进程,所以可以跨线程直接调用。正如《系统服务框架子系统-4-面向服务架构的实现》中的测试程序所做的那样。即调用SAMGR_GetInstance()->GetDefaultFeatureApi(SERVICE_NAME)或SAMGR_GetInstance()->FeatureApi(SERVICE_NAME,FEATURE_NAME)查询接口。如果Aa要调用的服务/特性接口是由进程B提供的,那么首先Aa所在进程的SamgrLiteImplg_samgrImpl中肯定找不到这个服务,即serviceImpl=NULL:因此,交叉-processservices/features的调用,入口就是上面的SAMGR_FindServiceApi(service,feature)。结合我们的日志,搜索“%%%%%%%%%%%”这样的字符串,这是我标记的一个条目(其实搜索“SAMGR_FindServiceApi”也是类似的)。看日志:{[bundle_daemon_client]}Initialize:GetDefaultFeatureApi(bundle_daemon)这是“bundle_daemon_client”在初始化的时候,从自己进程的SamgrLiteImplg_samgrImpl中查询名为“bundle_daemon”的服务的DefaultFeatureApi。通过前后的日志,我们可以知道bundle_daemon_client的进程信息“pid[5]/uid[7]/(*)handle[61](*)”,5号进程是“foundation”,“bundle_daemon”服务由进程6提供。因此,“bundle_daemon”服务提供的接口将通过SAMGR_FindServiceApi(S[bundle_daemon],F[(null)])查询。SAMGR_FindServiceApi()及其辅助函数涉及到g_remoteRegister.clients字段,先了解一下。这是一个向量。这个进程的g_remoteRegister初始化的时候,这个vector也被配置了:g_remoteRegister.clients=VECTOR_Make((VECTOR_Key)SAMGR_GetSAName,(VECTOR_Compare)SAMGR_CompareSAName);vector的元素:data[x]是一个IUnknown*proxy类型的指针,指向一个客户端代理接口入口.iUnknown。通过这个指针可以转换回IClientProxy类对象,IClientEntry类对象,IDfaultClient类对象,然后通过IClientProxy类对象指针访问后续的Invoke函数,或者访问IClientHeader中的key,target等字段上面的header字段通过IDefaultClient类的对象指针。vector中的每个元素都记录了本进程EP调用的其他进程提供的服务接口相关的重要标识信息,比如name、handle、token等,以便下次调用时直接在这里查询得到这些信息,不需要再去samgrEP通过IPC再次查询。其展开图如下:SAMGR_FindServiceApi()的流程如下:我们看上面的日志。这是bundle_daemon_client第一次向SamgrEP查询FeatureAPI,但返回Thehandleis-1。根据下面的DbgParse_g_server信息,此时提供bundle_daemon服务的进程6还没有向samgeEP注册EP和Feature,所以samgrEP是无法自己找到的。看bundle_daemon_client第二次向samgrEP查询FeatureAPI。这次发现handle是38,token是0。也就是说第一步SAMGR_CreateIProxy()得到了SvcIdentityidentity={38,0,0},再往下处理,会得到一个完整有效的IDfaultClient对象,先将这个对象中的.iUnknown地址保存到g_remoteRegister.clients向量中,然后使用这个.iUnknown地址调用clientproxy()接口的Invoke,从而通过远程调用bundle_daemon服务工控机。Provider:Pid[6]/Uid[8]/handle[38]:bundle_daemon->(null)Consumer:Pid[5]/Uid[7]/Tid[53]从这两条日志可以看出,No.6进程的bundle_daemon服务是提供者,查询和使用这个服务的5号进程是消费者,也是面向服务架构的一种实现。再来看另一个更明显的跨进程调用服务的例子:第一个应用进程启动器的孵化和启动。登录搜索“AppAppAppApp”。这是5号进程打算通过app_manager调用7号进程提供的“appspawn”服务来孵化launcher应用。它得到“appspawn”的句柄74、令牌0和.iUnknown地址,并将该地址和相关的重要信息添加到自己的clientsvector中。接下来app_spawn_client调用上面的Invoke{0x249cc84c},这个Invoke{0x249cc84c}就是ProxyInvoke()函数,通过它把IPC消息发送给IpcMsgReceiver::handle[74],token[0],它的EP接收和处理这条消息,这就是上一节提到的IPC消息的Dispatch()和HandleIpc()的处理流程。经过消息的转发和处理,最终appspawn_service的Invoke()函数开始孵化launcher应用进程,桌面应用开始提供服务。跨进程服务接口调用到此结束。刚刚浏览了standard系统的//base/startup/appspawn_standard/目录,看了看README_zh,贴出下图。除了通信方式不同外,大体流程是一样的。更多信息请访问:Harmonyos.51cto.com,与华为官方合作打造的鸿蒙技术社区