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

100 篇文章 2 订阅
100 篇文章 0 订阅

往期知识点记录:

一、前言

本系列分析的代码位于distributedschedule_samgr_lite\samgr_endpoint\source\endpoint.c

二、宏定义及数据结构

//定义主endpoint的通信地址
#define SAMGR_HANDLE 0
#define SAMGR_TOKEN 0
#define SAMGR_COOKIE 0
#define MAX_DATA_LEN 0x100  //最大数据长度
#define MIN_DATA_LEN 0x40   //最小数据长度
//资源类型
typedef enum ResourceID {
    RES_ENDPOINT,       //表示endpoint资源类型
    RES_FEATURE,        //表示feature资源类型
    RES_SYSCAP,         //表示syscap资源类型
    RES_BUTT,
} ResourceID;
//操作类型
typedef enum OptionID {
    OP_GET,         //获取
    OP_POST,        //发布
    OP_PUT,         //添加
    OP_DELETE,      //删除
    OP_ALL,         //获取所有
} OptionID;
typedef struct Endpoint Endpoint;
//函数指针,指向注册endpoint地址的方法
typedef int (*RegisterEndpoint)(const IpcContext *context, SvcIdentity *identity);
typedef struct Router
{
    SaName saName;       //标识服务名称和功能名称
    Identity identity;   //标识服务名称、功能名称和消息队列
    IServerProxy *proxy; //进程间通信的服务端代理接口
    PolicyTrans *policy; //访问策略
    uint32 policyNum;    //访问策略的总数
} Router;
//当前进程和其他进程间通信的通信端点
struct Endpoint {
    const char *name;       //端点名称
    IpcContext *context;    //ipc上下文
    Vector routers;         //routers中保存的是router对象,作为当前进程中服务和功能与其他进程间通信的桥梁,充当查找指定服务时的路由功能
    ThreadId boss;          //主线程,用于接收其他进程发出的消息
    uint32 deadId;
    int running;            //true or false
    SvcIdentity identity;   //身份标识,作为通信地址
    RegisterEndpoint registerEP;//指向注册通信端点函数的指针
    TokenBucket bucket;         //令牌桶,作为消息接收和处理的流控机制
};
typedef struct Router
{
    SaName saName;       //标识服务名称和功能名称
    Identity identity;   //标识服务名称、功能名称和消息队列
    IServerProxy *proxy; //进程间通信的服务端代理接口
    PolicyTrans *policy; //访问策略
    uint32 policyNum;    //访问策略的总数
} Router;

三、函数实现详解

创建endpoint
/*
    函数功能:创建endpoint
    函数参数:@name:endpoint的name
             @register:注册endpoint地址的函数
    函数描述:为当前进程创建一个IPC通信端点endpoint,用于跨进程间通信。
*/
Endpoint *SAMGR_CreateEndpoint(const char *name, RegisterEndpoint registry)
{
    //创建endpoint
    Endpoint *endpoint = SAMGR_Malloc(sizeof(Endpoint));
    if (endpoint == NULL)
    {
        return NULL;
    }
    //对endpoint初始化
    endpoint->deadId = INVALID_INDEX;
    //打开本进程这一端的IPC通信通道,若IpcContext不存在则创建。OpenLiteIpc()函数实际上返回的是true或者false。
    //true代表当前进程的IpcContext已准备好,false代表创建失败
    endpoint->context = OpenLiteIpc(LITEIPC_DEFAULT_MAP_SIZE);
    //通信端点的主线程,用于接收其他进程发送的消息
    endpoint->boss = NULL;
    //创建初始化的vector,指定获取键值和键值比较的函数
    endpoint->routers = VECTOR_Make((VECTOR_Key)GetIServerProxy, (VECTOR_Compare)CompareIServerProxy);
    //通信端点的名称
    endpoint->name = name;
    //标识是否启用
    endpoint->running = FALSE;
    //endpoint的身份标识,作为endpoint的地址,此时均为初始值
    endpoint->identity.handle = (uint32_t)INVALID_INDEX;
    endpoint->identity.token = (uint32_t)INVALID_INDEX;
    endpoint->identity.cookie = (uint32_t)INVALID_INDEX;
    //指向注册通信端点的函数指针,若registry == NULL,则是其他endpoint向主endpoint注册地址,否则为registry代表的注册方式
    endpoint->registerEP = (registry == NULL) ? RegisterRemoteEndpoint : registry;
    //初始化Bucket
    TB_InitBucket(&endpoint->bucket, MAX_BUCKET_RATE, MAX_BURST_RATE);
    return endpoint;
}
向通信端点添加router
/*
    函数功能:向endpoint添加router
    函数参数:@endpoint:当前进程的通信端点,IPC通信的交互点
             @saName:由servicename和featurename组成的标识
             @id:由servicename、featurename和queueid组成的标识
             @proxy:代理接口
    函数返回:添加成功 返回router的下标,添加失败返回EC_INVALID or EC_NOMEMORY or EC_FAILURE
    函数描述:将指定的router添加到当前进程通信端点endpoint的routers中。
             若该router已存在,则返回对应的下标。若不存在则创建并初始化后添加到routers集合中并返回下标。
             注:当endpoint的routers中存在对象时,会为endpoint创建一个专门接收和分发其他进程发来的消息。
             在进程间通信,由endpoint操作共享内存完成,将消息获取到进程中后,再分发到当前进程的其他线程中处理。
*/
int SAMGR_AddRouter(Endpoint *endpoint, const SaName *saName, const Identity *id, IUnknown *proxy)
{
    //参数检查
    if (endpoint == NULL || id == NULL || proxy == NULL || saName == NULL)
    {
        return EC_INVALID;
    }
    IServerProxy *serverProxy = NULL;
    //查询指定版本的IUnknown接口的子类对象
    proxy->QueryInterface(proxy, SERVER_PROXY_VER, (void *)&serverProxy);
    if (serverProxy == NULL)
    {
        return EC_INVALID;
    }
    //以proxy作为键值,查询routers中是否存在指定的router,并返回下标
    int index = VECTOR_FindByKey(&endpoint->routers, proxy);
    //找到该router对象
    if (index != INVALID_INDEX)
    {
        //释放对IUnknown接口的引用
        serverProxy->Release((IUnknown *)serverProxy);
        //返回下标
        return index;
    }
    //该router对象不存在,则创建
    Router *router = SAMGR_Malloc(sizeof(Router));
    if (router == NULL)
    {
        //记录日志,内存不足
        HILOG_ERROR(HILOG_MODULE_SAMGR, "Memory is not enough! Identity<%d, %d, %p>",
                    id->serviceId, id->featureId, id->queueId);
        return EC_NOMEMORY;
    }
    //记录服务和特性的标识
    router->saName = *saName;
    //记录同一进程内的服务、特性和消息队列的标识
    router->identity = *id;
    //服务端代理
    router->proxy = serverProxy;
    router->policy = NULL;
    router->policyNum = 0;
    //将router添加到vector中
    index = VECTOR_Add(&endpoint->routers, router);
    if (index == INVALID_INDEX)
    {
        //添加失败,释放资源
        SAMGR_Free(router);
        return EC_FAILURE;
    }
    //启动监听程序,即创建一个主线程,用于接收消息
    Listen(endpoint);
    return index;
}

写在最后

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

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值