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