五、一个完整的过程
一个完整的过程包括以下四个步骤:
1、Eventloop接收RILJ的请求,并负责把请求发送给reference库:RILJ –> Eventloop –> reference
2、reference负责把命令转化为AT命令,然后发送给Modem:reference –> Modem
3、reference通过readerLoop得到Modem回应后把数据返回给Eventloop: Modem—>ReaderLoop
4、Eventloop再把数据返回给RILJ:ReaderLoop—>LibRIL–>RILJ
此处以RILJ获取SimStatus的request为例说明。
先来一张总的流程图:
5.1 RILJ –> Eventloop –> reference
总览如下:
Step1:为EventLoop的fd_listen监听到RILJ发送去request信息
Step2:使用fd_listen创建fdCommand句柄以及Event监听Socket流
Step3:中处理fdCommand流,获取到request和token。并找到对应CommandInfo
Step4:调用CommandInfo中对应dispatchFunction封装构建RequestInfo
Step5:调用ReferenceRIL中onRequest函数向ReferenceRIL发起请求
5.1.2 Step1
RILJ向RILC发送获取CardStatus的消息
@Override
public void
getIccCardStatus(Message result) {
//Note: This RIL request has not been renamed to ICC,
// but this request is also valid for SIM and RUIM
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
5.1.3 Step2
上面说到创建了包含Socket句柄的Event来监听RILJ发送来的信息,的那个fd_Listen监听到新信息时,会在EventLoop中触发Event的回调函数,此处Event的回调函数为listenCallback(),下面来看下如何接收和处理RILJ的信息。
static void listenCallback (int fd, short flags, void *param) {
/*
从s_fdListen侦听套接字得到s_fdCommand流套接字
accept()接受一个客户端的连接请求,并返回一个新的套接字。
所谓“新的”就是说这个套接字与socket()返回的用于监听和接受客户端的连接请求的套接字不是同一个套接字。
与本次接受的客户端的通信是通过在这个新的套接字上发送和接收数据来完成的。
可以将s_fdListen理解为服务器的侦听端口,fdCommand为端口侦听到信息后创建的信息流
*/
fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);
//获取当前命令的参数
err = getsockopt(fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
//设置fdCommand为非阻塞
ret = fcntl(fdCommand, F_SETFL, O_NONBLOCK);
//将fdCommand放入SocketListenParam
p_info->fdCommand = fdCommand;
//使用fdCommand构建一个RecordStream,此流用来读数据
p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
//将其放入SocketListenParam中
p_info->p_rs = p_rs;
//使用fdCommand构建commands_event,回调函数为SocketListenParam内的processCommandsCallback
//注意到这里persist参数为true,所以需要手动删除Event。
ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
p_info->processCommandsCallback, p_info);
//添加Event并激活EventLoop
rilEventAddWakeup (p_info->commands_event);
//发送URC消息,通知RILJ状态发生改变
onNewCommandConnect(p_info->socket_id);
}
从以上可知, listenCallback中主要干了两件事:
1. 首先使用fd_Listen创建了一个流套接字(fdCommand)用来接收信息,并使用fdCommand构建了一个RecordStream和一个Event。不难想到,这个Event的回调函数要来读取这个fdCommand所传递的信息,这写信息会从RecordStream中读取出来。这个Event的回调函数为processCommandsCallback(),在4.3.2分析。
2. 调用 onNewCommandConnect回调函数,给予RILJ通知反馈,其主要逻辑如下。
static void onNewCommandConnect(RIL_SOCKET_ID socket_id) {
//给RILJ发送URC消息,RIL连接成功
RIL_UNSOL_RESPONSE(RIL_UNSOL_RIL_CONNECTED,
&rilVer, sizeof(rilVer), socket_id);
//给RILJ发送URC消息,告诉RILJ,Radio状态改变了
RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
NULL, 0, socket_id);
}
5.1.2 Step3
在此函数中,开始读取和处理RILJ发送的消息:
static void processCommandsCallback(int fd, short flags, void *param) {
RecordStream *p_rs;
void *p_record;
size_t recordlen;
int ret;
SocketListenParam *p_info = (SocketListenParam *)param;
//校验
assert(fd == p_info->fdCommand);
//这里获取到了上一步的RecordStream
p_rs = p_info->p_rs;
for (;;) {
/* loop until EAGAIN/EINTR, end of stream, or other error */
//从RecordStream中读数据放入p_record,成功返回0
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
if (ret == 0 && p_record == NULL) {