message.c分析
我们知道smagr是鸿蒙系统M核和A核系统服务开发框架,message是其中的消息机制,主要是为了实现提供消息交流的API。
背后的结构体支撑
1.Identity用来唯一标识服务或者一个特征
主要是里面有各种信息的id,可以唯一的标识、服务、还有队列信息
struct Identity {
/** Service ID */
int16 serviceId;
/** Feature ID */
int16 featureId;
/** Message queue ID */
MQueueId queueId;
};
2.定义request的结构体
这个主要是存储请求,通过iunknown接口发送到feature接口
struct Request {
/** Message ID */
int16 msgId;
/** Data length */
int16 len;
/** Data content */
void *data;
/** Message value, which is defined by developers */
uint32 msgValue; //请求里面有消息内容
};
3.定义响应
它的作用应该就是用于在服务或特性的消息处理功能处理请求后发送响应。
struct Response {
/** Data content */
void *data;
/** Data length */
int16 len;
};
4.exchange的type
这个主要是消息对应的情况
enum ExchangeType {
MSG_EXIT = -1,
MSG_NON = 0,
MSG_CON = 1,
MSG_ACK = 2,
MSG_SYNC = 3,
MSG_DIRECT = 4,
};
5.Exchange结构体
这里是将req,rsp等结构体整体封装,还加入了一个消息的处理函数。
struct Exchange {
Identity id; /**< 目标服务或特性标识The target service or feature identity. */
Request request;
Response response;
short type;
Handler handler; /**< async 响应或立即请求回调函数
uint32 *sharedRef; /**< 用于共享请求和响应以节省内存
};
代码部分
1.相关宏定义
#undef LOG_TAG
#undef LOG_DOMAIN
#define LOG_TAG "Samgr" # 日志标记
#define LOG_DOMAIN 0xD001800 #日志域名
#define DONT_WAIT 0
#define WAIT_FOREVER (-1) //两个数字用来表示等待
2.请求发送函数SAMGR_SendRequest
函数功能:实现请求的发送
函数原理:将请求信息当作一个元素,写进指定队列来存储
//发送请求函数
int32 SAMGR_SendRequest(const Identity *identity, const Request *request, Handler handler)
{
if (request == NULL || identity == NULL) {
return EC_INVALID;
}
//检查参数
Exchange exchange = {
*identity, *request, {
NULL, 0}, MSG_NON, handler, NULL};
exchange.id.queueId = NULL;
if (handler != NULL) {
//handler是这里的回调函数
exchange.id.queueId = SAMGR_GetCurrentQueueID();
exchange.type = MSG_CON;
}
//
return QUEUE_Put(identity->queueId, &exchange, 0, DONT_WAIT);
//这里的返回部分是一个函数,实现消息的入队列。这里就是将请求发送存储进队列中
}
3.发送响应SAMGR_SendResponse
函数参数
- request:一个客户端发出的请求
- response:该请求对应的回复和响应
函数功能:在队列中匹配请求,进行对应的响应。将responce和对应的request进行关联,实现请求和响应的一一对应
//发送接口的响应
int32 SAMGR_SendResponse(const Request *request, const Response *response)
{
// we need send the default the con message or not?
if (request == NULL) {
return EC_INVALID;
}
//先检查相应参数
Exchange *exchange = GET_OBJECT(request, Exchange, request);
//定义exchange,并初始化实现数据类型的转化
if (exchange->type != MSG_CON) {
return EC_INVALID;
}
//检查exchange里面的回调函数,响应或立即请求回调函数
if (exchange->handler == NULL) {
return EC_SUCCESS;
}
exchange->type = MSG_ACK;
exchange->response.data = NULL;
exchange->response.len = 0;
//初始化相关变量
//把exchange各个属性进行复制,把response数据域赋值
if (response != NULL) {
//初始化成功的话就讲response写进exchange,这里的响应是函数传进去的
exchange->response = *response;
}
// If there is no task queue, we will call the response processor in current task.
if (exchange->id.queueId == NULL) {
exchange->handler(&exchange->request, &exchange->response);
//处理当前请求
return EC_SUCCESS;
}
// Send back to the origin to process the task.
int32 ret = SharedSend(exchange->id.queueId, exchange, 1);
//将信息发送回队列进行处理
if (ret != EC_SUCCESS) {
//返回成功后,就执行handler函数,将需求对应的响应进行连接。实现请求和请求对应响应的关联
exchange->handler(&exchange->request, &exchange->response);
(void)FreeReference(exchange);
//功能实现后释放对exchange变量的引用
}
return EC_SUCCESS;
}
4.实现消息的接收SAMGR_MsgRecv
函数参数:
- queneID:队列的id,就是消息存放的位置
- interMsg:消息的指针,用来存放消息信息,是一个8位整型数字指针
- size:消息空间的大小
函数功能:实现消息的接收
函数原理:该函数就是实现消息接收,就是将消息数组当作一个空间,基于pop函数将元素出队
//message的接收
int32 SAMGR_MsgRecv(MQueueId queueId, uint8 *interMsg, uint32 size)
{
if (queueId == NULL || interMsg == NULL || size == 0) {
return EC_INVALID;
}
if (memset_s(interMsg, size, 0x00, size) != EOK) {
return EC_FAILURE;
}
return QUEUE_Pop(queueId, interMsg, 0, WAIT_FOREVER);
}
5.message释放
函数功能:就是实现message的free,清除exchange的
int32 SAMGR_FreeMsg(Exchange *exchange)
{
if (!FreeReference(exchange)) {
return EC_SUCCESS;
}
if (exchange->request.len > 0) {
SAMGR_Free(exchange->request.data);
exchange->request.data = NULL;
}
if (exchange->response.len > 0) {
SAMGR_Free(exchange->response.data);
exchange->response.data = NULL;
}
return EC_SUCCESS;
}
6.SendSharedRequest函数
函数功能:发送共享请求,这里就是有一端客户端发送一个共享的request,这里实现共享。
函数原理:函数就是基于exchange变量里面的shareRef变量,来判断是否有剩余内存可以实现共享,函数的返回值就是最后的exchange->shareRef变量,来判断是否要共用一个请求进行处理来节省内存
//发送共享请求
uint32 *SAMGR_SendSharedRequest(const Identity *identity, const Request *request, uint32 *token, Handler handler)
{
if (identity == NULL || request == NULL) {
return NULL;
}
//检查参数
Exchange exchange = {
*identity, *request, {
NULL, 0}, MSG_NON, handler, token};
exchange.type = (handler == NULL) ? MSG_NON : MSG_CON;
//根据handler的值来选择type的值
exchange.id.queueId = NULL;
int32 err = SharedSend(identity->queueId, &exchange, 0);
if (err != EC_SUCCESS) {
HILOG_ERROR(HILOG_MODULE_SAMGR, "SharedSend [%p] failed(%d)!", identity->queueId, err);
(void)FreeReference(&exchange);
}
return exchange.sharedRef;
}
7. SAMGR_SendSharedRequest
函数功能:向特性线程发送调用者的请求和响应。直接调用处理程序来处理请求和响应,而不使用消息处理函数。此函数用于为{@link Broadcast}服务发布主题,以广播消息。
函数原理:这里涉及到一个引用变量,如果调用该函数该变量就会+1
参数解释:
- id:指向请求和响应发送到的服务或特性id的指针。
- request :指示请求的指针。
- resp:指示指向响应的指针
- ref:引用计数
- handler :指示处理请求和响应的功能。该参数不能为空
函数返回值表示是否处理成功请求
int32 SAMGR_SendSharedDirectRequest(const Identity *id, const Request *req, const Response *resp, uint32 **ref,
Handler handler)
{
if (handler == NULL || ref == NULL) {
return EC_INVALID;
}
//检查对应参数
Exchange exchange = {
0};
if (req != NULL) {
exchange.request = *req;
}
//将函数传入请求进行存入exchange
if (resp != NULL) {
exchange.response = *resp;
}
exchange.handler = handler;
exchange.sharedRef = *ref;
exchange.type = MSG_DIRECT;
exchange.id = *id;
exchange.id.queueId = NULL;
//初始化相关属性变量
int32 err = SharedSend(id->queueId, &exchange, 0);
if (err != EC_SUCCESS) {
HILOG_ERROR(HILOG_MODULE_SAMGR, "SharedSend [%p] failed(%d)!", id->queueId, err);
//记录错误日志
(void)FreeReference(&exchange);
}
*ref = exchange.sharedRef;
return err;
//返回一个状态码,判断是否实现功能
}
8.SAMGR_SendResponseByIdentity
**函数功能:**在处理原始请求后向指定的服务或特性发送响应。
**函数原理:**这个函数被调用来在处理一个服务的{@link MessageHandle}或一个特性的{@link OnMessage}的请求后发送一个响应。
可自定义该功能,实现不同类型服务的分阶段启动。 \n
参数解释:
- id:指向服务或特性ID的指针。响应被发送到服务或特性的线程进行处理
- request :指示请求的指针。
- resp:指示指向响应的指针
//基于identity来发送接口的响应
int32 SAMGR_SendResponseByIdentity(const Identity *id, const Request *request, const Response *response)
{
// we need send the default the con message or not?
if (request == NULL || id == NULL) {
return EC_INVALID;
}
Exchange *exchange = GET_OBJECT(request, Exchange, request);
if (exchange->type == MSG_NON) {
return EC_INVALID;
}//non属性的type
exchange->id.queueId = id->queueId;
return SAMGR_SendResponse(request, response);
}
9.SharedSend
函数功能: 实现共享信息的发送
如果msg数据和响应是NULL,我们就直接复制,不需要共享消息。
static int32 SharedSend(MQueueId queueId, Exchange *exchange, int initRef)
{
/* if the msg data and response is NULL, we just direct copy, no need shared the message. */
if ((exchange->request.data == NULL || exchange->request.len <= 0) &&
(exchange->response.data == NULL || exchange->response.len <= 0)) {
return QUEUE_Put(queueId, exchange, 0, DONT_WAIT);
}
//查看请求和响应数组的空间是否合法(是否为空,长度是否为0)
/* 1.add reference */
MUTEX_GlobalLock();//执行加锁,对要操作的的数据进行加锁,防止其他进程的调用
if (exchange->sharedRef == NULL) {
exchange->sharedRef = (uint32*)SAMGR_Malloc(sizeof(uint32));
//shareRef用来共享请求,实现内存的节省
if (exchange->sharedRef == NULL) {
如果该变量为空,就说明这个没有多余可用内存
MUTEX_GlobalUnlock();
return EC_NOMEMORY;
}
*(exchange->sharedRef) = initRef;//申请空间后对其进行初始化
}
(*(exchange->sharedRef))++;
MUTEX_GlobalUnlock();
return QUEUE_Put(queueId, exchange, 0, DONT_WAIT);
//最后将exchange写进队列中,实现分享
}
10.对空间引用的释放
函数功能:释放一些不需要的空间,基于变量needfree和shareRef
//释放引用
static BOOL FreeReference(Exchange *exchange)
{
if (exchange == NULL) {
return FALSE;
}
BOOL needFree = TRUE;
/* 1. check the shared reference */
MUTEX_GlobalLock();
if (exchange->sharedRef != NULL) {
if (*(exchange->sharedRef) > 0) {
(*(exchange->sharedRef))--;
}
if (*(exchange->sharedRef) > 0) {
needFree = FALSE;
}
}
//检查参数shareRef,来确认是否共享内存
MUTEX_GlobalUnlock();
//释放对数据的加锁
if (needFree) {
SAMGR_Free(exchange->sharedRef);
//释放shareRef对应的空间
exchange->sharedRef = NULL; //将该属性清空
}
return needFree;
//这个needfree表示是否需要释放,因为shareref变量里面加了两次,所以执行--操作后大于零说明还有剩余空间还得执行free操作
}
感谢阅读,欢迎交流和指正