商提供不同的链接库,只要符合RIL层的框架即可。而当前的链接库中最主要的就是就是reference-ril.c和atchannel.c文件。
而reference库需要完成两个任务:
1、将eventLoop中的命令通过AT发送给Modem;
2、构建一个readerLoop循环,接受Modem消息,并根据消息的不同(URC和非URC)将消息返回给eventLoop(非URC消息)或者直接发送给RILJ(URC消息)。
我们先看readerLoop构建过程(发送AT的过程在文档的最后一章介绍):
2.1、reference中readerLoop建立和循环过程
在这一步中,需要完成reference的初始化,并且打开的ReaderLoop循环。 @reference-ril.c
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) {
//开启ril的线程,入口函数是mainLoop
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); //把ril的回调函数返回出来 return &s_callbacks; }
我们来看入口函数:
static void * mainLoop(void *param) {
//初始化AT通道的关闭方法和超时方法 at_set_on_reader_closed(onATReaderClosed); at_set_on_timeout(onATTimeout); for (;;) {
//打开AT并把处理URC消息的方法onUnsolicited传进去 ret = at_open(fd, onUnsolicited);
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); waitForClose();
} }
上面可以看到,不仅打开了AT通道,而且还设置了超时方法。当前线程在打开AT通道后,在waitForClose中阻塞等待,如果AT通道在检测超时后,将会主动的关闭当前的AT通道,此时将会激活waitForClose中的阻塞线程,然后waitForClose将会返回。而一旦waitForClose函数返回,将会再次进入for循环,重新打开AT通道。 我们主要跟踪AT通道打开的过程,以及事件的处理流程: @atchannel.c
int at_open(int fd, ATUnsolHandler h) {
//URC消息的处理方式:onUnsolicited() @reference-ril.c s_fd = fd;
//创建线程读取AT命令并处理Modem发过来的信息 ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr); }
看一下read线程的入口函数readerLoop: static void *readerLoop(void *arg) {
for (;;) { //读取命令 line = readline();
if(isSMSUnsolicited(line)) { if (s_unsolHandler != NULL) { //URC消息可以直接发送给RILJ s_unsolHandler (line1, line2); } } else {
processLine(line); }
}
//关闭read onReaderClosed(); return NULL; }
上面的readerLoop就是在不断侦测Modem上报的消息,然后根据是否是URC消息来采用不同的处理方式。至于具体的判断依据,在两个地方可以体现:1、通过isSMSUnsolicited判断(如果以CMT/CDS/CBM开头则判断成立);2、也可以在processLine中判断(这是主要的判断依据)。
我们简要说一下processLine判断URC消息的依据。我们知道,如果不是URC消息,那么就是我们主动发送的请求,Modem是作为回应给我们发的消息,而在我们给Modem发送消息时,会注册各种的回调函数和用于放
置Modem返回值的指针sp_response。而如果是URC消息,那么就没有回调函数,而且sp_response是为空,reference
正是通过判断sp_response的内容来达到区分URC消息的目的。
在processLine中对于不同的消息有不同的处理流程: static void processLine(const char *line) {
if (sp_response == NULL) { //URC消息处理 handleUnsolicited(line);
} else if (isFinalResponseSuccess(line)) { //非URC消息处理 sp_response->success = 1; //发送回应消息给EventLoop handleFinalResponse(line); } else switch (s_type) { case NO_RESULT: case NUMERIC: //非URC消息处理
if (sp_response->p_intermediates == NULL && isdigit(line[0])
) {
addIntermediate(line); } else {
/* either we already have an intermediate response or the line doesn't begin with a digit */ handleUnsolicited(line); } break; } }
可以看到,URC消息是通过handleUnsolicited处理的,而非URC消息有两个地方处理。下面分别介绍两种处理方式:
2.2、URC消息处理流程
我们看URC消息的处理函数: @atchannel.c
static void handleUnsolicited(const char *line) {
s_unsolHandler(line, NULL); }
这里的s_unsolHandler来自于at_open时的参数,也就是reference-ril.c中的onUnsolicited: @reference-ril.c
static void onUnsolicited (const char *s, const char *sms_pdu) {
if (strStartsWith(s, \ //时区改变
RIL_onUnsolicitedResponse (RIL_UNSOL_NITZ_TIME_RECEIVED,response, strlen(response)); } else if (strStartsWith(s,\
|| strStartsWith(s,\ || strStartsWith(s,\ || strStartsWith(s,\ ) {
//通话状态改变
RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); } else if (strStartsWith(s,\ //网络注册状态改变
RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,NULL, 0); } else if (strStartsWith(s, \ //新短信通知
RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_NEW_SMS,sms_pdu, strlen(sms_pdu)); } else if (strStartsWith(s, \ //短信报告
RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,sms_pdu, strlen(sms_pdu));
} else if (strStartsWith(s, \
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); } }
可以看出,URC消息的处理流程基本上就是根据命令头的不同将其转化为不同的命令索引,然后调用RIL_onUnsolicitedResponse函数,而RIL_onUnsolicitedResponse的实现:
#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
说明这个函数调用的是s_rilenv变量的OnUnsolicitedResponse方法。那么s_rilenv是哪里初始化的呢? 我们在rild.c中的main函数中对reference库初始化时是这样的形式: funcs = rilInit(&s_rilEnv, argc, rilArgv);
上面的初始化过程将s_rilEnv全局变量传递给了reference,然后在reference-ril.c内部将这个值传给了s_rilenv,而s_rilEnv的各个处理函数是在ril.cpp中实现的。