OpenHarmony轻量系统服务管理|进程间通信的客户端代理详解(二)

100 篇文章 1 订阅
100 篇文章 0 订阅

往期知识点记录:

函数实现详解

减少引用数
//将指定对象的引用数减一,若引用数变为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🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>