SA服务框架——客户端和服务端代理proxy的构建相关


上一篇简单提到了factory中关于客户端proxy的创建,本篇将从factory出发探讨服务端和客户端的proxy机制

这里附上上篇代码的链接:
SA服务框架——factory相关

首先从代码的解读中我们可以大致知道proxy的实质就是一系列IUnknown类型或子类的结构体,通过结构体的属性或函数来实现代理的功能

1. 服务端代理

首先来看到服务端代理相关代码

1.1 SamgrServer

首先拆解一下该结构体:
我们重点关注 INHERIT_IPROXY_ENTRY(SamgrProxy)

struct SamgrServer {
    INHERIT_SERVICE;
    INHERIT_IPROXY_ENTRY(SamgrProxy);
    Identity identity;
    Endpoint *samgr;
    MutexId mtx;
    SAStore store;
    IpcAuthInterface *ipcAuth;
    MutexId sysCapMtx;
    Vector sysCapabilitys;
};
#define INHERIT_SERVICE                                          \
    const char *(*GetName)(Service * service);                   \
    BOOL (*Initialize)(Service * service, Identity identity);    \
    BOOL (*MessageHandle)(Service * service, Request * request); \
    TaskConfig (*GetTaskConfig)(Service * service)

#define INHERIT_IPROXY_ENTRY(T) INHERIT_IUNKNOWNENTRY(T)

//实际上是将SamgrProxy 作为类型传入得到SamgrProxy iUnknown
#define INHERIT_IUNKNOWNENTRY(T) \
    uint16 ver;                   \
    int16 ref;                   \
    T iUnknown

//实际上是三个iunknown的指针函数和一个重要的invoke函数
struct SamgrProxy {
    INHERIT_SERVER_IPROXY;
};

//服务代理的功能在invoke函数中体现
#define INHERIT_SERVER_IPROXY \
        INHERIT_IUNKNOWN; \
        int32 (*Invoke)(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply)

#define INHERIT_IUNKNOWN                                                   \
    int (*QueryInterface)(IUnknown *iUnknown, int version, void **target); \
    int (*AddRef)(IUnknown *iUnknown);                                     \
    int (*Release)(IUnknown *iUnknown)

而这个invoke函数就是服务端代理的唤醒

1.2 g_server

而服务代理的初始化就在g_server的初始化中:
在这里插入图片描述


服务端的代理较为简单,只使用了一个invoke函数,而客户端的代理较为复杂涉及以下几个函数

2. 客户端代理

2.1 GetFactory

上一篇讲解中也涉及了该函数,主要是根据所给service和feature名字从g_factories查找相应factory返回
在这里插入图片描述

2.2 SAMGR_CreateIClient

仍然是factory中的函数用于获取对应factory并调用creator进行proxy的创建
在这里插入图片描述

2.3 SAMGR_CreateIProxy

该函数封装了上述的CreateIClient完成了客户端代理的创建并返回IUnknown类型的entry
在这里插入图片描述
函数流程:
1. 调用QueryIdentity解析context中的内容并将身份信息包括handle封装入identity中
2. 调用SAMGR_CreateIClient创建客户代理实例返回一个实例IDefaultClient

IDefaultClient结构体:

struct IDefaultClient {
    struct IClientHeader {
    SaName key;
    SvcIdentity target;
    uint32 deadId;
    const IpcContext *context;
	};
    struct IClientEntry {
    uint16 ver;                   
    int16 ref;                   
    IClientProxy iUnknown //int (*Invoke)(IClientProxy *proxy, int funcId, IpcIo *request, IOwner owner, INotify notify);
    int (*QueryInterface)(IUnknown *iUnknown, int version, void **target); 
    int (*AddRef)(IUnknown *iUnknown);                                     
    int (*Release)(IUnknown *iUnknown)
	};
};

分为两个部分一个是header封装了关键信息包括:

  • saName key:封装了服务和feature的字符串名
  • SvcIdentity target:用于封装QueryIdentity解析的identity信息
  • uint32 deadId:终止id
  • const IpcContext *context:保存ipc的context

第二部分是entry——也就是proxy的核心函数invoke函数所在

3. 初始化client->header,其中调用了函数RegisterDeathCallback和OnServiceExit初始化deadId

4. 初始化entry,将函数ProxyInvoke赋给entry->Invoke唤醒客户端接收ipc消息,而该invoke函数被消息处理的线程所调用

通过对IDefaultClient的初始化完成,完成对于客户端代理的完整建立


下面是对客户代理的应用函数

2.4 SAMGR_FindServiceApi

/*
函数功能:根据所给参数从g_remoteRegister.clients中寻找对应的proxy(serviceApi)
函数参数:service:服务名字符串;feature:feature名字符串
函数返回:返回得到的proxy(ServiceApi)
*/
IUnknown *SAMGR_FindServiceApi(const char *service, const char *feature)
{
    if (service == NULL) {
        return NULL;
    }
    //创建一个g_remoteRegister的Endpoint作为进程通信的客户终端
    InitializeRegistry();
    SaName key = {service, feature};
    // the proxy already exits.
    //通过key返回在vector中对应的位置
    int index = VECTOR_FindByKey(&g_remoteRegister.clients, &key);
    //存在则直接返回
    if (index != INVALID_INDEX) {
        return VECTOR_At(&g_remoteRegister.clients, index);
    }
    //不存在则新建一个客户代理
    IUnknown *proxy = SAMGR_CreateIProxy(g_remoteRegister.endpoint->context, service, feature);
    if (proxy == NULL) {
        return NULL;
    }
    //再一次坚持是否存在
    MUTEX_Lock(g_remoteRegister.mtx);
    index = VECTOR_FindByKey(&g_remoteRegister.clients, &key);
    //存在则将刚创建的释放返回存在的proxy
    if (index != INVALID_INDEX) {
        MUTEX_Unlock(g_remoteRegister.mtx);
        proxy->Release(proxy);
        return VECTOR_At(&g_remoteRegister.clients, index);
    }
    //不存在则添加proxy入clients
    VECTOR_Add(&g_remoteRegister.clients, proxy);
    MUTEX_Unlock(g_remoteRegister.mtx);
    HILOG_INFO(HILOG_MODULE_SAMGR, "Create remote sa proxy[%p]<%s, %s>!",
               proxy, service, feature);
    return proxy;
}

该函数的主要功能在于根据service和feature名称字符串在g_remoteRegister.clients中返回一个服务Api也就是代理proxy,如果不存在则调用SAMGR_CreateIProxy创建并返回

这里有一个小疑惑:在创建proxy之前调用了一次VECTOR_FindByKey进行过一次查询,但是在创建后再一次对原来的g_remoteRegister.clients进行VECTOR_FindByKey,过程中并没有其他干扰,为什么前后需要两次确认?

后来看到第二次确认前加了互斥锁——进行临界资源调用时需要加互斥锁,以求数据同步,所以我猜测这里的两次确认是为了多进程状态下,防止其他进程对公共资源进行修改,所以需要加锁在创建proxy后再对g_remoteRegister.clients进行一次查找,防止其在创建proxy的时期该服务在g_remoteRegister.clients中被添加,防止反复添加

2.5 SAMGR_GetRemoteIdentity

该函数也调用了SAMGR_FindServiceApi,用于得到远端服务的结构,从而获取context中的identity
在这里插入图片描述
函数流程:
1. 调用SAMGR_FindServiceApi返回了一个iunknown接口
2. 如果能直接调用QueryInterface将其进行类型转换(变为IClientProxy类型),不能则直接返回无效的identity表示获取无效
3. 转换成功则创建一个新IDefaultClient实例将其中的header.target作为identity返回
(原本存入了ipcContext中的identity)


2.6 GetFeatureApi

函数里面调用了SAMGR_FindServiceApi

该函数是SamgrLiteImpl中属性SamgrLite中实现的十三个函数之一

从函数名可以知道该函数时为了获取featureApi的但是为什么会调用SAMGR_FindServiceApi呢?我们看代码
在这里插入图片描述
从代码中可以看到,当不存在服务名对应的serviceImpl时,就根据所给serviceName和feature在g_remoteRegister.clients中寻找对应的proxy(不存在则调用SAMGR_CreateIProxy进行创建)

如果存在serviceImpl则从featureImpl中获取对应iunknown,不存在则返回serviceImpl中的默认Api

也就是说如果服务和feature没有提供相应的代理——也就是Api,则会自动创建一个proxy作为客户端代理。

3. 总结

至此,服务端和客户端的代理机制大致介绍完毕,可以看到服务端和客户端都是通过一个结构体来控制proxy的创建,都实现了iunknown;其最重要的函数都是唤醒函数invoke;但是客户端的属性中需要包含更多的内容用于通信,而且也有更多的相关函数进行具体操作。

在代码中可以看到所谓API就是类似接口,在SA中就是iunknown的实现,能够自由的实现类型转换来获取特定结构体中信息,提取该信息用于任务处理或者再次封装进行通信,以此来实现进程间数据的交换和进程内的任务流转

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国家一级假勤奋研究牲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值