往期知识点记录:
- 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(一)
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(二)
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(三)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(一)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(二)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(三)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(四)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(五)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(六)
- OpenHarmony轻量系统服务管理|客户代理的工厂模式机制详解
- OpenHarmony轻量系统服务管理|进程间通信的客户端代理详解(一)
- OpenHarmony轻量系统服务管理|进程间通信的客户端代理详解(二)
- 持续更新中……
函数实现详解
减少引用数
//将指定对象的引用数减一,若引用数变为0,需要负责回收资源
static int Release(IUnknown *proxy)
{
MUTEX_Lock(g_mutex);
//将proxy对象的引用数减一
int ref = IUNKNOWN_Release(proxy);
MUTEX_Unlock(g_mutex);
if (ref != 0) {
//若当前对象引用数不为0,则返回引用数
return ref;
}
//当前对象的引用数为0,需要回收相应的资源
//获取代理接口的IDefaultClient成员
IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
//根据service和feature获取factory对象,然后调用该对象的销毁器,销毁其下属的iClient
int ret = SAMGR_ReleaseIClient(client->header.key.service, client->header.key.feature, client);
if (ret == EC_NOHANDLER) {
//调用销毁器失败,直接释放资源
SAMGR_Free(client);
return EC_SUCCESS;
}
return ret;
}
客户端代理的处理函数
/*
函数功能:负责客户端代理请求消息的发送和响应消息的接收
函数参数:@proxy:客户端代理
@funcId:指定调用的服务端处理函数
@request:待发送的请求消息
@owner:请求消息的创建者
@notify:响应消息的处理者
函数描述:将客户端代理创建的请求消息发送给指定的服务和功能。
若notify为NULL则不需要接收响应消息,若notify不为NULL则需要接收响应消息。
notify将响应消息转发给对应的客户端代理。
*/
static int ProxyInvoke(IClientProxy *proxy, int funcId, IpcIo *request, IOwner owner, INotify notify)
{
if (proxy == NULL) {
return EC_INVALID;
}
//获取代理接口的IDefaultClient成员
IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
//获取头部信息
IClientHeader *header = &client->header;
if (header->target.handle == INVALID_INDEX) {
//目标的访问地址是无效的,需要重新获取访问地址
header->target = QueryIdentity(header->context, header->key.service, header->key.feature);
if (header->target.handle == INVALID_INDEX) {
//重新查询后还是无效,则返回EC_INVALID
return EC_INVALID;
}
//查询成功,注册死亡回调函数
(void)RegisterDeathCallback(header->context, header->target, OnServiceExit, header, &header->deadId);
}
//构建响应消息体
IpcIo reply;
void *replyBuf = NULL;
/*
LITEIPC_FLAG_DEFAULT 发送并且服务端需要响应
LITEIPC_FLAG_ONEWAY 仅发送消息
*/
//若notify不为NULL,则指定flag为LITEIPC_FLAG_DEFAULT,发送并且服务端需要响应。notify接收响应消息并转发给响应的owner
IpcFlag flag = (notify == NULL) ? LITEIPC_FLAG_ONEWAY : LITEIPC_FLAG_DEFAULT;
//从当前进程的endpoint向目标的地址发送请求消息
int ret = Transact(header->context, header->target, funcId, request, &reply, flag, (uintptr_t *)&replyBuf);
if (ret != LITEIPC_OK) {//发送失败
//解除死亡的回调函数
(void)UnregisterDeathCallback(header->target, header->deadId);
//清除访问地址信息,返回EC_FAILURE
header->deadId = INVALID_INDEX;
header->target.handle = INVALID_INDEX;
header->target.token = INVALID_INDEX;
header->target.cookie = INVALID_INDEX;
return EC_FAILURE;
}
//请求消息发送成功
//判断notify是否为NULL,用于接收响应消息,并转发给对应的请求消息创建者
if (notify != NULL) {
/*
owner表示接收响应数据的客户端代理,也是请求消息的创建者
*/
//通知owner处理响应消息
notify(owner, ret, &reply);
}
if (replyBuf != NULL) {//资源回收
FreeBuffer(header->context, replyBuf);
}
return ret;
}
断开服务的回调函数
/*
函数功能:断开连接后回收资源
函数参数:@context:IPC通信上下文
@ipcMsg:消息IO
@data:数据缓冲区
@argv:客户端代理,由调用者指定
函数描述:与服务断开连接时触发的回调函数,负责回收持有的资源。
*/
static int OnServiceExit(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv)
{
(void)data;
//获取头部
IClientHeader *header = (IClientHeader *)argv;
//解除死亡回调函数
(void)UnregisterDeathCallback(header->target, header->deadId);
#ifdef __LINUX__
BinderRelease(context, header->target.handle);
#endif
//清空,置为无效值
header->deadId = INVALID_INDEX;
header->target.handle = INVALID_INDEX;
header->target.token = INVALID_INDEX;
header->target.cookie = INVALID_INDEX;
if (ipcMsg != NULL) {
//回收资源
FreeBuffer(header->context, ipcMsg);
}
HILOG_ERROR(HILOG_MODULE_SAMGR, "Miss the remote service<%u, %u>!", header->target.handle, header->target.token);
return EC_SUCCESS;
}
获取服务和功能的访问地址
/*
函数功能:查询指定服务和功能的访问地址
函数参数:@context:IPC通信的上下文
@service:服务名称
@feature:功能名称
函数返回:查询成功 返回指定服务和功能的访问地址,查询失败 返回无效的访问地址
函数描述:通过当前进程endpoint的ipc上下文向主endpoint发起查询指定服务和功能的请求。
若查询成功,主endpoint向本进程发送包含服务和功能的访问地址的响应信息。通过这个访问地址,就可以进行服务间的跨进程交互。
若查询失败,则访问地址是无效值。
*/
static SvcIdentity QueryIdentity(const IpcContext *context, const char *service, const char *feature)
{
//构建请求消息结构体
IpcIo req;
uint8 data[MAX_DATA_LEN];
//初始化,将req与data缓冲区关联
IpcIoInit(&req, data, MAX_DATA_LEN, 0);
//请求的资源类型为FEATURE
IpcIoPushUint32(&req, RES_FEATURE);
//操作为GET,查询操作
IpcIoPushUint32(&req, OP_GET);
//将消息放入共享内存,先push字符串长度,再push服务名称
IpcIoPushString(&req, service);
//push一个bool值,标识feature是否为NULL
IpcIoPushBool(&req, feature == NULL);
if (feature != NULL) {
//不为NULL,则先push字符串长度,再push功能名称
IpcIoPushString(&req, feature);
}
//将service和feature的信息放入共享内存完毕
//构建响应消息体
IpcIo reply;
//响应消息接收缓冲区
void *replyBuf = NULL;
//指定主endpoint的标识
SvcIdentity samgr = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
//向主endpoint发送消息,并接收响应
int ret = Transact(context, samgr, INVALID_INDEX, &req, &reply, LITEIPC_FLAG_DEFAULT, (uintptr_t *)&replyBuf);
//若失败 ret=EC_FAILURE,若成功 则读取响应消息
ret = (ret != LITEIPC_OK) ? EC_FAILURE : IpcIoPopInt32(&reply);
//初始化目标的访问地址,此时为无效值
SvcIdentity target = {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX};
if (ret == EC_SUCCESS) {//向主endpoint发送查询请求成功,并收到响应消息
//读取reply中的数据,获取SvcIdentity值,是指定服务和功能的访问地址
SvcIdentity *svc = IpcIoPopSvc(&reply);
if (svc != NULL) {
#ifdef __LINUX__
/*
在完整代码1.1.1的文件目录foundation\communication\ipc_lite\frameworks\liteipc\src\liteipc_adapter.c中
对BinderAcquire的实现如下:
int32_t BinderAcquire(const IpcContext* context, uint32_t handle)
{
return LITEIPC_OK;
}
*/
BinderAcquire(svc->ipcContext, svc->handle);
#endif
//更新目标的访问地址
target = *svc;
}
}
if (ret == EC_PERMISSION) {
//没有权限
HILOG_INFO(HILOG_MODULE_SAMGR, "Cannot Access<%s, %s> No Permission!", service, feature);
}
//释放资源
if (replyBuf != NULL) {
FreeBuffer(context, replyBuf);
}
return target;
}
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请看下图提示: