揭露Client和Server之间联动机制的本质和消息处理的幕后黑手

前情回顾

在上一期博客中我们介绍了server和client EP的IPC来往流程,其中流程主要分为三个步骤:

  1. Dispatch()接收消息,然后转发消息
  2. HandleIpc()对消息进行处理
  3. 最后由消息接收者EP通过调用token指定的router->proxy->invoke()来处理

那么今天我们来简单介绍一下所谓的router->proxy->invoke()接口究竟是何物,并且以它为引子继续介绍其中的来往流程。

干货满满,可直接食用

震惊!router->proxy->invoke()的本质竟然是它!

我查阅了许多在鸿蒙开发领域的大佬的博客,最后苦思冥想,得出了一个结论:
由于router->proxy->invoke()接口主要存在于服务端和客户端之间,而对应我们的中介处——samgr而言,这个router->proxy->invoke(),就是g_server.Invoke()
没错,就是在很久之前的博客中我们提到的一个函数封装,具体详情可以查看博客:服务端那些事儿

static SamgrServer g_server = {
    .GetName = GetName, //获得函数名
    .Initialize = Initialize,   //初始化
    .GetTaskConfig = GetTaskConfig, //定义服务的任务配置
    .MessageHandle = MessageHandle, //处理服务消息
    SERVER_IPROXY_IMPL_BEGIN,   //定义服务器代理类的默认初始化的开始。
        //此宏用于开发服务器代理类,可以继承此宏以减少代码量并防止类定义不一致。

    .Invoke = Invoke,   //从客户端向IServerProxy发送IPC消息
    IPROXY_END,
};

那么问题来了,这两者是如何对应到一起的呢?

在反复对比研究了几位华为工程师发表的博客后,在所有知识串起来的一刹那,我感觉整个人都达到了融会贯通,天人合一的境界!
我们先看下面这部分的初始化操作代码,它是g_server里最重要的部分:

static BOOL Initialize(Service *service, Identity identity) //初始化服务和身份的功能
{
    SamgrServer *server = (SamgrServer *)service;
    server->identity = identity;
    SaName saName = {SAMGR_SERVICE, NULL};
    SAMGR_AddRouter(server->samgr, &saName, &server->identity, GET_IUNKNOWN(*server));//添加路由器
    return TRUE;
}

在初始化中有一个add router的操作,所以他的流程应该是这样的:

  1. g_server首先通过SAMGR_AddRouter函数添加router,在添加router时,我们要注意该函数所用的第四个参数,也就是GET_IUNKNOWN(*server),这个参数的功能就是用来获取g_server的 iUnknown 字段的地址,并且以此地址为该函数的proxy参数。
  2. 然后通过这个参数来实现查询接口的功能,也就是在QueryInterface()时,实际上执行的是 IUNKNOWN_QueryInterface(),结果就是会把 IUnknown 类型的proxy(第一个参数),重新下转换成IUnknownEntry类型的指针entry。
  3. 该指针的用途就是判断它的版本entry->ver是否符合要求,在符合要求的前提下,才能调用它的引用entry->ref+1,然后返回proxy给第三个参数(void*) serverProxy,再经过类型转换到IServerProxy *serverProxy。从而实现从router→proxy=serverProxy的过程。

于是乎,走了一遍流程之后我们发现,其中大部分的信息都对应起来了,在其他的进程中的EP内的router,都会以类似的方式将Invoke函数映射起来,同时也是以这种方式进行调用的。

文字的描述看起来似乎有些让人难以理解,所以下面我用一个较为简洁的流程图描述了上述过程:
在这里插入图片描述
搞清楚了Client、Server、Samgr中的相关对应函数后,我们也了解到了在g_server.Invoke()函数内是通过对IPC发送过来的参数作为分类参数,以此选择对应的函数来分别做处理。

探究!挖出Client与Server之间消息处理的幕后黑手

不知道大家是否还记得我曾经提到的几个Proc函数,没错,他们就是最后的黑老大!

在samgr_server.c文件中,有好几个Proc函数,他们分别对应EP中的不同功能:

  • 对EP注册类消息,调用ProcEndpoint()来处理
  • 对Feature类消息,调用ProcFeature()来处理,又分为注册和查询两种,通过参数分别调用ProcPutFeatur()和ProcGetFeature()来处理。
  • 对于SysCap类的IPC消息,调用ProcSysCap()来处理,分为三类:添加一项SysCap、获取一项SysCap、获取所有SysCap。分别对应的三个函数为ProcAddSysCap()、ProcGetSysCap()、ProcGetAllSysCap()。

相关函数的功能和构建细节,可以查阅我之前的博客:
服务端的那些事儿(2)

在这里呢我大致介绍一下该机制对于Feature类消息的处理:

  1. 首先呢,在注册Feature消息的IPC发送端,在client EP启动和注册过程中,通过调用SAMGR_ProcPolicy()或者RegisterRemoteFeatures()来向samgr EP注册Feature
  2. 查询Feature消息的IPC发送端,是在尝试使用别的 进程/EP提供的服务/功能 前,先向samgr EP查询并获取Feature接口,才能去使用。

下期预告

不出意外的话,下一期的博客应该就是最后的总结,我将对我在系统框架中整理的模块内容进行一个梳理。

欲知后事如何,且听下回分解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值