往期知识点记录:
- 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(一)
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(二)
- OpenHarmony轻量系统服务管理|系统功能的存储机制详解(三)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(一)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(二)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(三)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(四)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(五)
- OpenHarmony轻量系统服务管理|进程间通信的核心机制详解(六)
- 持续更新中……
函数实现详解
IPC消息处理函数
//IPC消息处理函数,需要对用户鉴权,从request和response中解析内容
static void HandleIpc(const Request *request, const Response *response)
{
//获取ipcMsg
void *ipcMsg = (void *)request->data;
//获取endpoint
Endpoint *endpoint = (Endpoint *)response->data;
//msgId中存储的是下标,根据下标获取router
Router *router = VECTOR_At(&endpoint->routers, request->msgId);
if (ipcMsg == NULL)
{
return;
}
//参数检查
if (router == NULL || router->proxy == NULL || router->proxy->Invoke == NULL)
{
//回收资源
FreeBuffer(endpoint->context, ipcMsg);
HILOG_ERROR(HILOG_MODULE_SAMGR, "Invalid IPC router<%p>!", router);
return;
}
//获取ipcMsg中的uid
uid_t uid = GetCallingUid(ipcMsg);
//对当前用户鉴权
if ((strcmp(router->saName.service, SAMGR_SERVICE) != 0) &&
!JudgePolicy(uid, (const PolicyTrans *)(router->policy), router->policyNum))
{
//条件1:service不属于主endpoint
//条件2:uid不属于policy中的合法值,即policy中不包含当前的uid
//此用户无权限,释放资源
FreeBuffer(endpoint->context, ipcMsg);
HILOG_ERROR(HILOG_MODULE_SAMGR, "Consumer uid<%d> has no permission to access<%s, %d, %d>!",
uid, router->saName.service, router->identity.serviceId, router->identity.featureId);
return;
}
//此用户有权限
//构建消息
IpcIo req;
IpcIoInitFromMsg(&req, ipcMsg);
IpcIo reply;
uint8 data[IPC_IO_DATA_MAX];
IpcIoInit(&reply, data, IPC_IO_DATA_MAX, MAX_OBJECT_NUM);
//解析服务端收到的IPC消息
router->proxy->Invoke(router->proxy, request->msgValue, ipcMsg, &req, &reply);
uint32_t flag = 0;
//获取ipcMsg的标识
GetFlag(ipcMsg, &flag);
if (flag == LITEIPC_FLAG_DEFAULT)
{
//发送reply消息
SendReply(endpoint->context, ipcMsg, &reply);
}
else
{
//回收资源
FreeBuffer(endpoint->context, ipcMsg);
}
}
注册服务和功能的访问地址
/*
函数功能:注册并获取指定服务和功能的访问地址
函数参数:@context:当前进程的IPC通信端点
@saName:标识指定服务和功能
@saInfo:服务和功能的访问地址
@policy:服务和功能的访问策略
@policyNum:访问策略总数
函数描述:首先构建向主endpoint发送feature资源请求的消息体,包含请求的服务名、功能名和token值。
然后处理主endpoint发回的响应消息,从响应消息中获取主endpoint为服务和功能生成的访问地址和访问策略。返回给RegisterIdentity的调用者
*/
static int RegisterIdentity(const IpcContext *context, const SaName *saName, SvcIdentity *saInfo,
PolicyTrans **policy, uint32 *policyNum)
{
//定义请求结构
IpcIo req;
uint8 data[MAX_DATA_LEN];
//ipc初始化,将req与data缓冲区关联起来
IpcIoInit(&req, data, MAX_DATA_LEN, 0);
//将消息放入共享内存,内容为RES_FEATURE,资源类型feature
IpcIoPushUint32(&req, RES_FEATURE);
//将消息放入共享内存,内容为OP_PUT操作
IpcIoPushUint32(&req, OP_PUT);
//将字符串消息放入共享内存,首先存储字符串的长度,再拷贝字符串的内容。内容为saName->service
IpcIoPushString(&req, saName->service);
//将消息放入共享内存,标识feature是否为NULL
IpcIoPushBool(&req, saName->feature == NULL);
if (saName->feature != NULL)
{
//feature不为NULL,则将feature放入共享内存,先存储feature的长度,再拷贝feature的内容
IpcIoPushString(&req, saName->feature);
}
//将router在routers中的下标token值放入共享内存中
IpcIoPushUint32(&req, saInfo->token);
//定义响应消息结构
IpcIo reply;
void *replyBuf = NULL;
//设置主endpoint的地址
SvcIdentity samgr = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
//LITEIPC_FLAG_DEFAULT表示发送和响应
//LITEIPC_FLAG_ONEWAY表示只发送
//向主endpoint发送注册feature的请求消息,数据在req中,响应由reply和replyBuf接收。Transact即SendRequest函数
int ret = Transact(context, samgr, INVALID_INDEX, &req, &reply, LITEIPC_FLAG_DEFAULT, (uintptr_t *)&replyBuf);
ret = -ret;
if (ret == LITEIPC_OK)
{
//从reply中读取消息
ret = IpcIoPopInt32(&reply);
}
if (ret == EC_SUCCESS)
{
//从reply中读取主endpoint返回给当前进程的Svcindentity,更新saInfo的信息
saInfo = IpcIoPopSvc(&reply);
//从reply中获取该服务下指定功能的访问策略信息
GetRemotePolicy(&reply, policy, policyNum);
}
if (replyBuf != NULL)
{
//回收资源
FreeBuffer(context, replyBuf);
}
return ret;
}
注册feature
//注册Feature,返回注册失败的个数
static int RegisterRemoteFeatures(Endpoint *endpoint)
{
int nums = 0;
//获取router个数
int size = VECTOR_Size(&endpoint->routers);
int i;
SvcIdentity identity;
//遍历router
for (i = 0; i < size; ++i)
{
//根据下标返回指定router
Router *router = VECTOR_At(&endpoint->routers, i);
if (router == NULL)
{
continue;
}
identity.handle = endpoint->identity.handle;
//token值即router在routers集合中的下标
identity.token = i;
//注册并获取指定服务和功能的访问地址
int ret = RegisterIdentity(endpoint->context, &(router->saName), &identity, &(router->policy),
&(router->policyNum));
if (ret == EC_SUCCESS)
{
//注册成功
++nums;
}
HILOG_DEBUG(HILOG_MODULE_SAMGR, "RegisterRemoteFeatures<%s, %s> ret:%d",
router->saName.service, router->saName.feature, ret);
}
//返回注册失败的个数
return VECTOR_Num(&endpoint->routers) - nums;
}
注册endpoint
/*
函数功能:向主Endpoint注册当前的Endpoint信息
函数参数:@context:IPC通信的上下文
@identity:本端进程的地址标识
函数返回:注册成功 返回EC_SUCCESS,注册失败 返回EC_FAILURE
函数描述:向主endpoint注册当前进程的endpoint信息,通过共享内存的方式,发送注册endpoint的请求。
若注册成功,主endpoint会发送响应给当前进程的endpoint,响应消息包含了handle。该handle作为当前进程通信地址identity的一部分。
若注册失败,会重试MAX_RETRY_TIMES次数,等待主endpoint就绪。多次重试均失败则返回EC_FAILURE。
*/
static int RegisterRemoteEndpoint(const IpcContext *context, SvcIdentity *identity)
{
//定义请求消息结构
IpcIo req;
//数据段
uint8 data[MAX_DATA_LEN];
//初始化请求消息
IpcIoInit(&req, data, MAX_DATA_LEN, 0);
//将消息放入共享内存,内容为RES_ENDPOINT,即当前消息为注册endpoint的请求
IpcIoPushUint32(&req, RES_ENDPOINT);
//消息类型OP_POST
IpcIoPushUint32(&req, OP_POST);
uint8 retry = 0;
//若主endpoint未就绪,最大重试次数为MAX_RETRY_TIMES
while (retry < MAX_RETRY_TIMES)
{
++retry;
//定义响应消息结构
IpcIo reply;
//响应消息的缓冲区
void *replyBuf = NULL;
//设置主Endpoint的标识信息
SvcIdentity samgr = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
//发送消息
//LITEIPC_FLAG_DEFAULT表示发送和响应
//LITEIPC_FLAG_ONEWAY表示只发送
//向主endpoint发送注册endpoint的请求消息,数据在req中,响应由reply和replyBuf接收。Transact即SendRequest函数
int err = Transact(context, samgr, INVALID_INDEX, &req, &reply, LITEIPC_FLAG_DEFAULT, (uintptr_t *)&replyBuf);
if (err == LITEIPC_OK)
{//消息发送完毕
//获取主Endpoint返回的handle
identity->handle = IpcIoPopUint32(&reply);
if (replyBuf != NULL)
{
//释放内存
FreeBuffer(context, replyBuf);
}
if (identity->handle == (uint32)INVALID_INDEX)
{
//返回的handle无效,即主Endpoint未就绪,重试
continue;
}
return EC_SUCCESS;
}
//睡眠间隔时间
sleep(RETRY_INTERVAL);
}
return EC_FAILURE;
}
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请看下图提示: