从factory到GetFeatureApi和SAMGR_GetRemoteIdentity
上一篇简单提到了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的实现,能够自由的实现类型转换来获取特定结构体中信息,提取该信息用于任务处理或者再次封装进行通信,以此来实现进程间数据的交换和进程内的任务流转