(2)RIL简析(高通)——消息处理
2016-08-23 16:28
183 查看
RIL如何启动及初始化?
RILJ的消息如何传递和被处理?
event table的定义
requested event的处理函数
ril_event的管理
RIL_REQEUST执行结果的返回
RIL_UNSOL类型消息的上报
一个消息处理的具体例子——SETUP_DATA_CALL
如何添加一个RIL消息和对应的处理函数?
当然,无论是REQUEST还是UNSOL_RESPONSE都会带参数,因此还需定义消息对应的结构体,例如RADIO_STATE的结构体:
通过搜索,发现ril_commands.h中还有定义RIL_REQUEST的数组元素,字面意思来看,明显是消息处理入口和返回的函数入口:
ril.cpp居然直接引入了这些定义,所有消息和对应的函数都存在s_commands数组里了:
那么,这些消息对应的函数是怎样被匹配并对应执行的呢?下一节。
既然这些消息是上层下发的,那么RIL就是通过socket来接收到消息。先回顾下socket监听是怎样建立的,应该就能找到消息处理的入口。
上一篇有讲到,RIL_register有监听RILD socket的代码:
startListen函数获取到socket的fd,初始化event并加入到eventloop,回调为listenCallback:
listenCallback再次向eventloop加入event,这次event的persistence值为1,回调为processCommandsCallback:
event的persistence值为1,ev->fd会一直存在于readFds集合,eventloop因此会持续监听socket。persist值的实际逻辑后面再来讲。
继续先看看processCommandsCallback这个函数跟event的处理有没有关系,一看果然没让我失望:
消息处理的地方就在processCommandBuffer,使用ID匹配到对应的s_commands成员,调用对应的处理函数。
消息定义、监听和分发消息的地方都找到了,接下来再看看ril_event_loop有哪些具体的处理:
select返回值后,执行了3个函数:processTimeouts()/processReadReadies(&rfds, n)/firePending(),挨个看。
processTimeouts()检查timer_list是否有超时项,如果有则加入到pending_list:
processReadReadies 从watch_table获取到对应的event,并加入到pending_list。
之前讲到event的persistence值,正是在processReadReadies里面用到,作用是控制event是否在触发后从watch_table移除,rild socket的监听设置persistence=1,因此其fd不会在这个被移除掉。
firePending()将event从pending_list移除出去,并调用ev->func执行消息处理:
ev->func对应什么函数?
还记得前面设置rild socket监听的时候,event参数是:
ev->func就是processCommandsCallback,没错,接着就是从s_commands里面找到对应的event:
然后dispatchFunction:
responseSetupDataCall处理完成继续将数据传到下一个函数dispatchStrings
后面就是执行qcril onRequest函数,每个消息具体处理都有所不同,这里先作抛砖引玉。
至于上面提及的watch_table、pending_list还有对这些list的操作addToList等等,他们作用是什么,接着下一节来说。
ril_event.cpp里面有3个与ril_event有关的list,还有4个list的操作函数:
addToList,加入一个event,ril_event通过链表方式保存:
watch_table是ril_event类型的数组,ril_event有fd和callback等字段,可见watch_table只是作为保存“监听器”之用,而真正要被处理的消息是在callback函数中从fd stream读取,个人觉得ril_event的命名有点不太准确了:
pending_list是即将回调(ev->func)的ril_event 列表,可以理解成被触发的监听器列表,ril_event处理后会从pending_list移除掉。
timer_list 设置了timeout的ril_event列表,从processTimeouts()函数可看出,超时的ril_event都会加进pending_list。
小结:
ril_event作用相当于监听器,并非实际的事件;
存在于watchtable中的ril_event提供了读写event的fd和callback函数,是事件处理的入口;
pending_list负责存放即将被处理的ril_event。
回想ril_commands.h里的定义:
responseSetupDataCall应该就是用来返回结果的,对应函数入口是responseFunction
来搜索下调用responseFunction的地方
上一篇文章提过,RIL_onRequestComplete函数是s_rilEnv 的一个成员,RIL_init第一个参数就是s_rilEnv,可以推测是提供给qcril做回调函数之用:
查找到OnRequestComplete的调用者是qcril.c 的qmi_ril_fw_send_request_response_epilog函数
找到了返回结果的地方,继续寻找返回数据的地方,既然监听到消息时是从fd读取出来消息,那么返回数据应该就是往fd写入数据。
回头再继续看pRI->pCI->responseFunction,还是以RIL_REQUEST_SETUP_DATA_CALL为例:
responseSetupDataCall调用了responseDataCallList,只是往parcel里面增加数据,并没有在这里向fd写入数据
函数返回到RIL_onRequestComplete,最后调用的函数是sendResponse,这里就是返回数据的地方:
小结:
qcril.c完成处理后,调用RIL_onRequestComplete返回处理结果;
responseFunction将数据写入parcel;
RIL_onRequestComplete调用sendResponse,向socket的fd写入数据,返回到上层。
RIL_UNSOL对应关系定义在ril_unsol_commands.h中,并存到s_unsolResponses数组:
类似于CommandInfo结构体,UnsolResponseInfo结构体也有responseFunction,但没有dispatchFunction。RIL_onUnsolicitedResponse会调用responseFunction处理parcel的数据,然后通过sendResponse返回数据到上层
调用这个RIL_onUnsolicitedResponse还是在qcril.c,qcril_send_unsol_response_epilog函数中:
小结:
Unsolicited消息上报的路径类似于RIL_REQUEST,只是调用的函数不一样。
总结下:
本篇主要分析了RIL消息接收(RIL_REQUEST)和上报(RIL_UNSOL_RESPONSE),消息处理函数,还有eventloop中监听和分发的逻辑等代码。RILJ部分代码比较清晰好理解,有机会后面再补充。
下一篇具体分析一下SETUP_DATA_CALL是如何建立一个数据连接的。
RILJ的消息如何传递和被处理?
event table的定义
requested event的处理函数
ril_event的管理
RIL_REQEUST执行结果的返回
RIL_UNSOL类型消息的上报
一个消息处理的具体例子——SETUP_DATA_CALL
如何添加一个RIL消息和对应的处理函数?
event table的定义
RIL所有的EVENT都定义在Ril.h中,有以RIL_REQUEST和RIL_UNSOL_RESPONSE开头的消息,前者代表主动请求,后者一般是上报的消息,例如下面这2个:#define RIL_REQUEST_SETUP_DATA_CALL 27
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
当然,无论是REQUEST还是UNSOL_RESPONSE都会带参数,因此还需定义消息对应的结构体,例如RADIO_STATE的结构体:
typedef enum { RADIO_STATE_OFF = 0, /* Radio explictly powered off (eg CFUN=0) */ RADIO_STATE_UNAVAILABLE = 1, /* Radio unavailable (eg, resetting or not booted) */ /* States 2-9 below are deprecated. Just leaving them here for backward compatibility. */ RADIO_STATE_SIM_NOT_READY = 2, /* Radio is on, but the SIM interface is not ready */ RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3, /* SIM PIN locked, PUK required, network personalization locked, or SIM absent */ RADIO_STATE_SIM_READY = 4, /* Radio is on and SIM interface is available */ RADIO_STATE_RUIM_NOT_READY = 5, /* Radio is on, but the RUIM interface is not ready */ RADIO_STATE_RUIM_READY = 6, /* Radio is on and the RUIM interface is available */ RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7, /* RUIM PIN locked, PUK required, network personalization locked, or RUIM absent */ RADIO_STATE_NV_NOT_READY = 8, /* Radio is on, but the NV interface is not available */ RADIO_STATE_NV_READY = 9, /* Radio is on and the NV interface is available */ RADIO_STATE_ON = 10 /* Radio is on */ } RIL_RadioState;
通过搜索,发现ril_commands.h中还有定义RIL_REQUEST的数组元素,字面意思来看,明显是消息处理入口和返回的函数入口:
{RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}
ril.cpp居然直接引入了这些定义,所有消息和对应的函数都存在s_commands数组里了:
ril.cpp typedef struct { int requestNumber; void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI); int (*responseFunction) (Parcel &p, void *response, size_t responselen); } CommandInfo; static CommandInfo s_commands[] = { #include "ril_commands.h" };
那么,这些消息对应的函数是怎样被匹配并对应执行的呢?下一节。
requested event的处理
我们要看消息是如何被处理的,先从消息的监听入手,就应该能找到对应的处理函数了。既然这些消息是上层下发的,那么RIL就是通过socket来接收到消息。先回顾下socket监听是怎样建立的,应该就能找到消息处理的入口。
上一篇有讲到,RIL_register有监听RILD socket的代码:
ril.cpp::RIL_register /* Initialize socket1 parameters */ s_ril_param_socket = { RIL_SOCKET_1, /* socket_id */ -1, /* fdListen */ -1, /* fdCommand */ PHONE_PROCESS, /* processName */ &s_commands_event, /* commands_event */ &s_listen_event, /* listen_event */ processCommandsCallback, NULL /* p_rs */ startListen(RIL_SOCKET_1, &s_ril_param_socket);
startListen函数获取到socket的fd,初始化event并加入到eventloop,回调为listenCallback:
fdListen = android_get_control_socket(socket_name); ret = listen(fdListen, 4); socket_listen_p->fdListen = fdListen; ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p); rilEventAddWakeup (socket_listen_p->listen_event);
listenCallback再次向eventloop加入event,这次event的persistence值为1,回调为processCommandsCallback:
Ril::listenCallback() //persist值为1,eventloop会一直监听这个fd ril_event_set (p_info->commands_event, p_info->fdCommand, 1, p_info->processCommandsCallback, p_info); rilEventAddWakeup (p_info->commands_event);
event的persistence值为1,ev->fd会一直存在于readFds集合,eventloop因此会持续监听socket。persist值的实际逻辑后面再来讲。
继续先看看processCommandsCallback这个函数跟event的处理有没有关系,一看果然没让我失望:
ril::processCommandsCallback(int fd, short flags, void *param) { for (;;) { //从fd读取数据,应该是event的数据 ret = record_stream_get_next(p_rs, &p_record, &recordlen); if (ret == 0 && p_record == NULL) { /* end-of-stream */ break; } else if (ret < 0) { break; } else if (ret == 0) { /* && p_record != NULL */ //数据传入这个函数,继续深入 processCommandBuffer(p_record, recordlen, p_info->socket_id); } } } //分发消息 ril::processCommandBuffer(void *buffer, size_t buflen, RIL_SOCKET_ID socket_id) { Parcel p; status_t status; int32_t request; int32_t token; RequestInfo *pRI; int ret; /* Hook for current context */ /* pendingRequestsMutextHook refer to &s_pendingRequestsMutex */ pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex; /* pendingRequestsHook refer to &s_pendingRequests */ RequestInfo** pendingRequestsHook = &s_pendingRequests; p.setData((uint8_t *) buffer, buflen); status = p.readInt32(&request); status = p.readInt32 (&token); pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); pRI->token = token; pRI->pCI = &(s_commands[request]); //获取消息对应的结构体成员 pRI->socket_id = socket_id; pRI->p_next = *pendingRequestsHook; pRI->pCI->dispatchFunction(p, pRI); //分发消息到对应的消息 }
消息处理的地方就在processCommandBuffer,使用ID匹配到对应的s_commands成员,调用对应的处理函数。
消息定义、监听和分发消息的地方都找到了,接下来再看看ril_event_loop有哪些具体的处理:
ril_event.cpp void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { //make local copy of read fd_set memcpy(&rfds, &readFds, sizeof(fd_set)); if (-1 == calcNextTimeout(&tv)) { // no pending timers; block indefinitely ptv = NULL; } else { ptv = &tv; } //select轮询fd_set集合IO状态 n = select(nfds, &rfds, NULL, NULL, ptv); if (n < 0) { if (errno == EINTR) continue; return; } // Check for timeouts processTimeouts(); // Check for read-ready processReadReadies(&rfds, n); // Fire away firePending(); } }
select返回值后,执行了3个函数:processTimeouts()/processReadReadies(&rfds, n)/firePending(),挨个看。
processTimeouts()检查timer_list是否有超时项,如果有则加入到pending_list:
static void processTimeouts() { struct timeval now; struct ril_event * tev = timer_list.next; struct ril_event * next; getNow(&now); while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { // Timer expired next = tev->next; //移除event removeFromList(tev); //将event加入pending_list addToList(tev, &pending_list); tev = next; } }
processReadReadies 从watch_table获取到对应的event,并加入到pending_list。
static void processReadReadies(fd_set * rfds, int n) { for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { struct ril_event * rev = watch_table[i]; if (rev != NULL && FD_ISSET(rev->fd, rfds)) { addToList(rev, &pending_list); if (rev->persist == false) { removeWatch(rev, i); } n--; } } }
之前讲到event的persistence值,正是在processReadReadies里面用到,作用是控制event是否在触发后从watch_table移除,rild socket的监听设置persistence=1,因此其fd不会在这个被移除掉。
firePending()将event从pending_list移除出去,并调用ev->func执行消息处理:
static void firePending() { struct ril_event * ev = pending_list.next; while (ev != &pending_list) { struct ril_event * next = ev->next; removeFromList(ev); ev->func(ev->fd, 0, ev->param); ev = next; } }
ev->func对应什么函数?
还记得前面设置rild socket监听的时候,event参数是:
ril_event_set (p_info->commands_event, p_info->fdCommand, 1, p_info->processCommandsCallback, p_info);
ev->func就是processCommandsCallback,没错,接着就是从s_commands里面找到对应的event:
pRI->pCI->dispatchFunction(p, pRI);
然后dispatchFunction:
{RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}
responseSetupDataCall处理完成继续将数据传到下一个函数dispatchStrings
#define CALL_ONREQUEST(a, b, c, d, e) s_callbacks.onRequest((a), (b), (c), (d), (e)) static void dispatchStrings (Parcel &p, RequestInfo *pRI) { CALL_ONREQUEST(pRI->pCI->requestNumber, pStrings, datalen, pRI, pRI->socket_id); }
后面就是执行qcril onRequest函数,每个消息具体处理都有所不同,这里先作抛砖引玉。
至于上面提及的watch_table、pending_list还有对这些list的操作addToList等等,他们作用是什么,接着下一节来说。
ril_event的管理
在eventloop里面实际操作的是几个ril_event结构体数组和指针,来看看究竟用途是什么。ril_event.cpp里面有3个与ril_event有关的list,还有4个list的操作函数:
static struct ril_event * watch_table[MAX_FD_EVENTS]; static struct ril_event timer_list; static struct ril_event pending_list; static void addToList(struct ril_event * ev, struct ril_event * list); static void removeFromList(struct ril_event * ev); static void removeWatch(struct ril_event * ev, int index); void ril_timer_add(struct ril_event * ev, struct timeval * tv);
addToList,加入一个event,ril_event通过链表方式保存:
static void addToList(struct ril_event * ev, struct ril_event * list) { ev->next = list; ev->prev = list->prev; ev->prev->next = ev; list->prev = ev; dump_event(ev); } //将ril_event移除 static void removeFromList(struct ril_event * ev) { ev->next->prev = ev->prev; ev->prev->next = ev->next; ev->next = NULL; ev->prev = NULL; }
watch_table是ril_event类型的数组,ril_event有fd和callback等字段,可见watch_table只是作为保存“监听器”之用,而真正要被处理的消息是在callback函数中从fd stream读取,个人觉得ril_event的命名有点不太准确了:
ril_event.h struct ril_event { struct ril_event *next; struct ril_event *prev; int fd; int index; bool persist; struct timeval timeout; ril_event_cb func; void *param; };
pending_list是即将回调(ev->func)的ril_event 列表,可以理解成被触发的监听器列表,ril_event处理后会从pending_list移除掉。
timer_list 设置了timeout的ril_event列表,从processTimeouts()函数可看出,超时的ril_event都会加进pending_list。
小结:
ril_event作用相当于监听器,并非实际的事件;
存在于watchtable中的ril_event提供了读写event的fd和callback函数,是事件处理的入口;
pending_list负责存放即将被处理的ril_event。
RIL_REQEUST执行结果的返回
消息处理完成,如何返回结果呢?回想ril_commands.h里的定义:
{RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}
responseSetupDataCall应该就是用来返回结果的,对应函数入口是responseFunction
typedef struct { int requestNumber; void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI); int(*responseFunction) (Parcel &p, void *response, size_t responselen); } CommandInfo;
来搜索下调用responseFunction的地方
ril.cpp RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { RequestInfo *pRI; int ret; int fd = s_ril_param_socket.fdCommand; size_t errorOffset; RIL_SOCKET_ID socket_id = RIL_SOCKET_1; pRI = (RequestInfo *)t; if (pRI->cancelled == 0) { Parcel p; p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); errorOffset = p.dataPosition(); p.writeInt32 (e); if (response != NULL) { //pRI->pCI->responseFunction并获得返回值 ret = pRI->pCI->responseFunction(p, response, responselen); /* if an error occurred, rewind and mark it */ //写入返回值到parcel if (ret != 0) { p.setDataPosition(errorOffset); p.writeInt32 (ret); } } //返回parcel sendResponse(p, socket_id); } }
上一篇文章提过,RIL_onRequestComplete函数是s_rilEnv 的一个成员,RIL_init第一个参数就是s_rilEnv,可以推测是提供给qcril做回调函数之用:
rild.c static struct RIL_Env s_rilEnv = { RIL_onRequestComplete, RIL_onUnsolicitedResponse, RIL_requestTimedCallback };
ril.h struct RIL_Env { void (*OnRequestComplete)(RIL_Token t, RIL_Errno e, void *response, size_t responselen); void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id); void (*RequestTimedCallback) (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime); };
查找到OnRequestComplete的调用者是qcril.c 的qmi_ril_fw_send_request_response_epilog函数
if (token && !qcril_is_internal_token(token)) { qcril_response_api[ instance_id ]->OnRequestComplete( token, resp_cause, resp_data, resp_data_len ); }
找到了返回结果的地方,继续寻找返回数据的地方,既然监听到消息时是从fd读取出来消息,那么返回数据应该就是往fd写入数据。
回头再继续看pRI->pCI->responseFunction,还是以RIL_REQUEST_SETUP_DATA_CALL为例:
{RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}
responseSetupDataCall调用了responseDataCallList,只是往parcel里面增加数据,并没有在这里向fd写入数据
static int responseDataCallList(Parcel &p, void *response, size_t responselen) { RIL_Data_Call_Response_v11 *p_cur = (RIL_Data_Call_Response_v11 *) int i; for (i = 0; i < num; i++) { p.writeInt32((int)p_cur[i].status); p.writeInt32(p_cur[i].suggestedRetryTime); p.writeInt32(p_cur[i].cid); p.writeInt32(p_cur[i].active); writeStringToParcel(p, p_cur[i].type); writeStringToParcel(p, p_cur[i].ifname); writeStringToParcel(p, p_cur[i].addresses); writeStringToParcel(p, p_cur[i].dnses); writeStringToParcel(p, p_cur[i].gateways); writeStringToParcel(p, p_cur[i].pcscf); p.writeInt32(p_cur[i].mtu); } }
函数返回到RIL_onRequestComplete,最后调用的函数是sendResponse,这里就是返回数据的地方:
static int sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_ID socket_id) { int fd = s_ril_param_socket.fdCommand; int ret; uint32_t header; header = htonl(dataSize); ret = blockingWrite(fd, (void *)&header, sizeof(header)); ret = blockingWrite(fd, data, dataSize); }
小结:
qcril.c完成处理后,调用RIL_onRequestComplete返回处理结果;
responseFunction将数据写入parcel;
RIL_onRequestComplete调用sendResponse,向socket的fd写入数据,返回到上层。
RIL_UNSOL_RESPONSE
这是一条RIL_UNSOL_RESPONSE消息:{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
RIL_UNSOL对应关系定义在ril_unsol_commands.h中,并存到s_unsolResponses数组:
ril.cpp static UnsolResponseInfo s_unsolResponses[] = { #include "ril_unsol_commands.h" }; //UnsolResponseInfo结构体 typedef struct { int requestNumber; int (*responseFunction) (Parcel &p, void *response, size_t responselen); WakeType wakeType; } UnsolResponseInfo;
类似于CommandInfo结构体,UnsolResponseInfo结构体也有responseFunction,但没有dispatchFunction。RIL_onUnsolicitedResponse会调用responseFunction处理parcel的数据,然后通过sendResponse返回数据到上层
ril.cpp void RIL_onUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen){ Parcel p; p.writeInt32 (RESPONSE_UNSOLICITED); p.writeInt32 (unsolResponse); ret = s_unsolResponses[unsolResponseIndex] .responseFunction(p, const_cast<void*>(data), datalen); ret = sendResponse(p, soc_id); }
调用这个RIL_onUnsolicitedResponse还是在qcril.c,qcril_send_unsol_response_epilog函数中:
qcril.c if ( param_ptr->instance_id < QCRIL_MAX_INSTANCE_ID ) { qcril_response_api[ param_ptr->instance_id ]->OnUnsolicitedResponse( param_ptr->response_id, param_ptr->resp_pkt, param_ptr->resp_len ); }
小结:
Unsolicited消息上报的路径类似于RIL_REQUEST,只是调用的函数不一样。
总结下:
本篇主要分析了RIL消息接收(RIL_REQUEST)和上报(RIL_UNSOL_RESPONSE),消息处理函数,还有eventloop中监听和分发的逻辑等代码。RILJ部分代码比较清晰好理解,有机会后面再补充。
下一篇具体分析一下SETUP_DATA_CALL是如何建立一个数据连接的。
相关文章推荐
- 处理鼠标离开窗口的消息 (WM_MOUSELEAVE)
- C++BUILDER非可视组件的消息处理技巧
- C#的消息处理方法
- 自定义消息的处理
- 定制控件消息处理函数
- 处理客户端弹出消息的三种方法
- Delphi的消息处理
- 使用单独的命令处理类来处理命令消息(适用于有很多命令处理函数的对象,以及共享命令处理函数)
- 摆脱在每个命令消息处理函数中的TRY和CATCH
- C#开发WINDOWS应用程序时消息的处理
- Delphi中的消息钩子函数和Windows子类处理 入门篇
- VB与VC混合编程中处理消息的方法
- C++ BUILDER 消息处理的深入探索
- MFC动态创建控件的消息处理
- WIN32汇编: 6.处理键盘消息
- DELPHI中的消息处理机制
- 关于捕获VCL没有处理的Windows消息
- 关于c#中的消息处理函数和vc中的消息处理函数区别
- MFC动态创建控件的消息处理
- 关于c#中的消息处理函数和vc中的消息处理函数区别(引自ucucf的专栏)