b、判断是否已经把所有有效数据传输完毕:isFinalResponseSuccess //结束符
static const char * s_finalResponsesSuccess[] = { \ \ }; //判断
static int isFinalResponseSuccess(const char *line) {
size_t i;
for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) { if (strStartsWith(line, s_finalResponsesSuccess[i])) { return 1; } } return 0; }
c、发送数据给Event侧,取消Event侧阻塞的线程:handleFinalResponse static void handleFinalResponse(const char *line) {
//把回应消息返回给eventLoop
sp_response->finalResponse = strdup(line);
//发信号给s_commandcond线程,使其脱离阻塞状态 pthread_cond_signal(&s_commandcond); }
三、一个完整的过程
经过上面的eventLoop和readerLoop过程分析,我们分别对eventLoop的机制和readerLoop中两种消息的处理有个大致的了解,但是还有一些问题我们没有解决,比如:
1、eventLoop所构建的循环如何接收RILJ的消息?又如何通过reference将消息发送到Modem? 2、上面说道reference接收到非URC消息后需要通知eventLoop读取消息,具体怎么通知eventLoop的? 这些问题将在这一节中详细说明。我们用一个完整的数据流来把两个loop串起来。而一个完整的数据流应该包括以下四个步骤:
1、Eventloop接收RILJ的请求,并负责把请求发送给reference库:Eventloop--->reference 2、reference负责把命令转化为AT命令,然后发送给Modem:reference--->Modem
3、reference通过readerLoop得到Modem回应后把数据返回给Eventloop: Modem--->ReaderLoop 4、Eventloop再把数据返回给RILJ:ReaderLoop--->Eventloop 下面我们就分别介绍这4个步骤的详细流程。
3.1、Eventloop把RILJ命令发送给reference库
我们再次回到RILC层的入口处,前面两节介绍了Eventloop和reference,接下来就是RIL_register的入口: @rild.c
int main(int argc, char **argv) {
//搭建EventLoop循环 RIL_startEventLoop();
//对reference动态库进行初始化 funcs = rilInit(&s_rilEnv, argc, rilArgv);
//注册reference 的回调函数 RIL_register(funcs); }
上面看到,当我们调用reference的初始化函数(也就是RIL_Init)后,将会得到一个RIL_RadioFunctions类型的返回值:
@reference-ril.c
static const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion };
这个变量的类型为: typedef struct {
int version; //当前链接库的版本信息
RIL_RequestFunc onRequest; //用于Event侧向动态库发起请求 RIL_RadioStateRequest onStateRequest; //得到当前库的状态 RIL_Supports supports; //查询是否支持某个命令 RIL_Cancel onCancel; //取消一个Event的处理 RIL_GetVersion getVersion; //得到版本号 } RIL_RadioFunctions;
这些成员函数中最重要的是onRequest,当我们在Event侧向reference库发起请求时,就是用的这个入口函数。而我们将用这个对象去完成注册的过程。 @ril.cpp
//将reference中的回调函数注册给RIL的框架 void RIL_register (const RIL_RadioFunctions *callbacks) { //把返回值传给s_callbacks(全局变量)
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
//#define SOCKET_NAME_RIL \ 打开RILC与RILJ之间的Socket通道
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); ret = listen(s_fdListen, 4);
//用这个Socket通道句柄创建一个Event
ril_event_set (&s_listen_event, s_fdListen, false, listenCallback, NULL);
//添加到Eventloop中
rilEventAddWakeup (&s_listen_event); }
在上面的注册函数中主要完成了两个任务:1、将我们从reference得到的回调函数callbacks传递给一个全局变量s_callbacks;2、打开Socket通道并添加句柄到Eventloop中。对于第二个任务,我们看到在注册的过程中,通过android_get_control_socket的方法打开了RILJ与RILC之间的Socket通道,而且这个通道的文件句柄为s_fdListen(全局变量),并用这个通道的句柄构建一个Event,然后添加到Eventloop中。并且为这个Event注册了的回调函数listenCallback。
经过上面的过程,就在RILJ与EventLoop之间建立了沟通的渠道。
还记得我们在Eventloop中提到如果检测到句柄池中的某个句柄有新数据的话,就会调用将timer_list和watch_table中的Event放入pending_list中,然后调用当前Event的回调函数: @ril_event.cpp static void firePending() {
struct ril_event * ev = pending_list.next; while (ev != &pending_list) {
struct ril_event * next = ev->next; removeFromList(ev);
//这里的func就是listenCallback ev->func(ev->fd, 0, ev->param); ev = next; } }
对于RILJ中过来的Event,我们注册的回调函数是listenCallback: @ril.cpp
static void listenCallback (int fd, short flags, void *param) {
//从s_fdListen侦听套接字得到s_fdCommand(RILJ与RILC之间的流套接字) s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
//得到当前命令的选项值
err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
//对文件描述符s_fdCommand进行控制,当前是设置其非阻塞模式 ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK);
//再次把当前命令放入Eventloop
ril_event_set (&s_commands_event, s_fdCommand, 1, processCommandsCallback, p_rs); rilEventAddWakeup (&s_commands_event);
//发送URC消息,通知RIL状态发生改变 onNewCommandConnect(); }
上面的过程分为2步:1、把当前消息重新发送到Eventloop;2、发送URC消息,通知RILJ(RIL状态改变了)。我们先来看一下第二个过程:
static void onNewCommandConnect() { //给RILJ发送URC消息,RIL连接成功
RIL_onUnsolicitedResponse(RIL_UNSOL_RIL_CONNECTED, &rilVer, sizeof(rilVer));
//给RILJ发送URC消息,告诉RILJ,Radio状态改变了
RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);