往期知识点记录:
- 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(一)
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(二)
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(三)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(一)
- 持续更新中……
一、前言
本系列分析的代码位于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🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请看下图提示: