OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(五)

往期知识点记录:

函数实现详解

endpoint主线程运行的消息接收函数
//先对接收器进行初始化,注册相应的回调函数。然后循环接收消息并下发到消息处理函数
static void *Receive(void *argv)
{
    //获取传递的endpoint对象
    Endpoint *endpoint = (Endpoint *)argv;
    if (endpoint == NULL || endpoint->registerEP == NULL)
    {
        //endpoint为NULL或endpoint的地址注册函数为NULL,则返回NULL
        return NULL;
    }
    int ret = EC_INVALID;
    uint8 retry = 0;
    //注册endpoint的地址,若不成功 允许重试MAX_RETRY_TIMES
    while (retry < MAX_RETRY_TIMES)
    {
        //根据当前endpoint的属性调用不同的地址注册函数。
        //endpoint分为两类,一类是主通信端点,另一类是从通信端点。其他从端点都需要向主端点注册自己的地址,并由主端点进行维护。
        //若当前endpoint是主通信端点,则向自己注册地址identity,调用RegisterSamgrEndpoint函数
        //若当前endpoint是从通信端点,则需要向主端点注册自己的地址信息identity,调用RegisterRemoteEndpoint函数
        ret = endpoint->registerEP(endpoint->context, &endpoint->identity);
        if (ret == EC_SUCCESS)
        {
            //注册成功
            SvcIdentity samgr = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
            //解除死亡的回调函数,当主Endpoint的回调函数运行状态为false并且usedflag为true
            (void)UnregisterDeathCallback(samgr, endpoint->deadId);
            //向主endpoint注册死亡回调函数
            (void)RegisterDeathCallback(endpoint->context, samgr, OnSamgrServerExit, endpoint, &endpoint->deadId);
            break; //注册成功,结束while循环
        }
        //注册不成功,重试发起注册
        ++retry;
        sleep(RETRY_INTERVAL);
    }
    //多次重试均失败,记录错误日志并退出
    if (ret != EC_SUCCESS)
    {
        HILOG_FATAL(HILOG_MODULE_SAMGR, "Register endpoint<%s>, handle<%u> failed! will exit to recover!",
                    endpoint->name, endpoint->identity.handle);
        exit(-ret);
    }
    //注册成功,标记为启用状态
    endpoint->running = TRUE;
    //若当前endpoint不是主endpoint
    if (endpoint->identity.handle != SAMGR_HANDLE)
    {
        //注册endpoint的Feature,返回注册失败的个数
        int remain = RegisterRemoteFeatures(endpoint);
        HILOG_INFO(HILOG_MODULE_SAMGR, "Register endpoint<%s> and iunknown finished! remain<%d> iunknown!",
                   endpoint->name, remain);
    }
    //启动循环,循环读取ipc中的消息,并将消息分发到对应的线程
    StartLoop(endpoint->context, Dispatch, endpoint);
    return NULL;
}
消息分发函数
/*
    函数功能:分发消息,将endpoint接收到的消息转发到指定服务处理
    函数参数:@context:IPC上下文
             @ipcMsg:接收消息的缓冲区
             @data:IPC的IO控制,指向ipcMsg中消息的数据区域
             @argv:endpoint信息
    函数功能:本函数有一个承上启下的作用,从endpoint上获取其他进程向本进程发送的消息,消息通过共享内存从其他进程进入当前进程后,
             再将消息通过线程间通信的方式(这里使用的是消息队列),发给相应的服务和功能去处理。
*/
static int Dispatch(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv)
{
    //参数检查
    if (argv == NULL || ipcMsg == NULL)
    {
        return EC_INVALID;
    }
    //获取endpoint对象
    Endpoint *endpoint = (Endpoint *)argv;
    uint32_t token = (uint32_t)INVALID_INDEX;
    //从ipc消息中获取token值
    GetToken(ipcMsg, &token);
    //检测是否繁忙,进行流控
    if (TB_CheckMessage(&endpoint->bucket) == BUCKET_BUSY)
    {
        HILOG_WARN(HILOG_MODULE_SAMGR, "Flow Control <%u> is NULL", token);
        goto ERROR;
    }
    //获取指定下标的元素,这里的token即router的下标
    Router *router = VECTOR_At(&endpoint->routers, token);
    if (router == NULL)
    {
        HILOG_ERROR(HILOG_MODULE_SAMGR, "Router <%s, %u> is NULL", endpoint->name, token);
        goto ERROR;
    }
    //初始化响应消息
    Response resp = {0};
    //endpoint信息作为响应
    resp.data = endpoint;
    //初始化请求信息
    Request request = {0};
    //ipcMsg和token作为请求
    request.msgId = token;
    request.data = ipcMsg;
    request.msgValue = INVALID_INDEX;
    //获取ipcMsg的code值赋给msgValue
    GetCode(ipcMsg, &request.msgValue);
#ifdef LITE_LINUX_BINDER_IPC
    //若宏定义LITE_LINUX_BINDER_IPC存在,则调用HandleIpc处理IPC消息
    HandleIpc(&request, &resp);
#else
    //若宏定义LITE_LINUX_BINDER_IPC不存在
    uint32 *ref = NULL;
    //发送消息类型为MSG_DIRECT的exchange对象,直接调用处理程序来处理请求和响应,而不使用消息处理函数。
    int ret = SAMGR_SendSharedDirectRequest(&router->identity, &request, &resp, &ref, HandleIpc);
    if (ret != EC_SUCCESS)
    {
        //发送失败,记录日志
        HILOG_ERROR(HILOG_MODULE_SAMGR, "Router[%u] Service<%d, %d, %p> is busy",
                    token, router->identity.serviceId, router->identity.featureId, router->identity.queueId);
        goto ERROR;
    }
#endif
    return EC_SUCCESS;
ERROR:
    //错误处理函数,负责回收资源
    if (ipcMsg != NULL)
    {
        FreeBuffer(endpoint->context, ipcMsg);
    }
    return EC_INVALID;
}
endpoint断开连接的回调函数
/*
    函数功能:endpoint与SamgrServer断开连接的回调函数
    函数参数:@context:ipc上下文
             @ipcMsg:ipc消息
             @data:数据缓冲区
             @argv:endpoint
    函数描述:当与samgr service断开时,触发回调函数。
             首先清除当前持有的资源,然后重新向主endpoint发起注册,直到注册成功。
             再注册死亡回调函数和endpoint下所有的feature
*/
static int OnSamgrServerExit(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv)
{
    (void)data;
    //记录退出日志
    HILOG_ERROR(HILOG_MODULE_SAMGR, "Disconnect to samgr server!");
    //获取endpoint
    Endpoint *endpoint = (Endpoint *)argv;
    //参数检查
    if (endpoint == NULL || endpoint->registerEP == NULL)
    {
        return EC_FAILURE;
    }
    if (ipcMsg != NULL)
    {
        //若ipcmsg不是指向NULL,则释放ipcmsg指向的资源
        FreeBuffer(endpoint->context, ipcMsg);
    }
    //获取当前endpoint中router的个数
    int size = VECTOR_Size(&endpoint->routers);
    int i;
    //遍历所有的router
    for (i = 0; i < size; i++)
    {
        //获取router对象
        Router *router = VECTOR_At(&endpoint->routers, i);
        if (router == NULL)
        {
            continue;
        }
        //释放每一个router绑定的policy
        SAMGR_Free(router->policy);
        router->policy = NULL;
        router->policyNum = 0;
    }
    SvcIdentity old = endpoint->identity;
    //循环注册,向主Endpoint注册当前的Endpoint信息,直到注册成功
    while (endpoint->registerEP(endpoint->context, &endpoint->identity) != EC_SUCCESS)
    {
        //记录日志,注册失败
        HILOG_ERROR(HILOG_MODULE_SAMGR, "Reconnect to samgr server failed!");
        //重试时间间隔
        sleep(RETRY_INTERVAL);
    }
    //注册成功
    SvcIdentity new = endpoint->identity;
    //新的endpoint的身份标识要和旧的一致
    if (old.handle != new.handle || old.cookie != new.cookie || old.token != new.token)
    {
        HILOG_ERROR(HILOG_MODULE_SAMGR, "Samgr server identity error!");
        exit(-1);
    }
    //设置主endpoint的地址
    SvcIdentity identity = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
    //解除死亡的回调函数,当主Endpoint的回调函数运行状态为false并且usedflag为true
    (void)UnregisterDeathCallback(identity, endpoint->deadId);
    //注册死亡回调函数
    (void)RegisterDeathCallback(endpoint->context, identity, OnSamgrServerExit, endpoint, &endpoint->deadId);
    //重新注册endpoint下的Feature,返回注册失败的个数
    int remain = RegisterRemoteFeatures(endpoint);
    HILOG_INFO(HILOG_MODULE_SAMGR, "Reconnect and register finished! remain<%d> iunknown!", remain);
    return EC_SUCCESS;
}

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值