ReaderLooper主要用来监听Modem上发信息
RIL需要加载一个AT相关的reference-ril.so的动态链接库。之所以使用 库的形式,就是考虑到每个厂商使用的Modem不同,我们没法用统一的接口去向底层负责,因此使用库的形式。这样一来,不同的Modem厂商提供不同的链接库,只要符合RIL层的框架即可。
前面在RILC层函数入口提到RILD会加载reference库来初始化ReferenceRIL,如下:
rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
dlsym(dlHandle, "RIL_Init");
funcs = rilInit(&s_rilEnv, argc, rilArgv);
我们来看看:
第一行为从库为加载RIL_Init函数。
第二行有很值得分析的地方,主要有三点:
1. 执行rilInit()函数(即RIL_Init)创建ReadLoop,这点在后面会详细讨论。
2. s_rilEnv,这是一个包含LibRIL回调函数的结构体,将其传入ReferenceRL后,使得ReferenceRIL能够调用LibRIL的函数向其通信。
3. funcs,这是一个包含ReferenceRIL回调函数的结构体,其从ReferenceRIL返回给LibRIL,使得LibRIL能够调用ReferenceRIL的函数向其通信。
如上2,3点使得LibRIL和ReferenceRIL都拥有对方的回调,从而能够是他们之间进行双向通信。
下面来看看这两个包含回调函数的结构体。
其结构体定义为:
//@mtk_ril.h
struct RIL_Env {
/**
* "t" is parameter passed in on previous call to RIL_Notification
* routine.
*
* If "e" != SUCCESS, then response can be null/is ignored
*
* "response" is owned by caller, and should not be modified or
* freed by callee
*
* RIL_onRequestComplete will return as soon as possible
*/
void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
void *response, size_t responselen);
#if defined(ANDROID_MULTI_SIM)
/**
* "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
* "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
*
* "data" is owned by caller, and should not be modified or freed by callee
*/
void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id);
#else
/**
* "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
* "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
*
* "data" is owned by caller, and should not be modified or freed by callee
*/
void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen);
#endif
/**
* Call user-specifed "callback" function on on the same thread that
* RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies
* a relative time value at which the callback is invoked. If relativeTime is
* NULL or points to a 0-filled structure, the callback will be invoked as
* soon as possible
*/
void (*RequestTimedCallback) (RIL_TimedCallback callback,
void *param, const struct timeval *relativeTime);
/**
* "t" is parameter passed in on previous call RIL_Notification routine
*
* RIL_onRequestAck will be called by vendor when an Async RIL request was received
* by them and an ack needs to be sent back to java ril.
*/
void (*OnRequestAck) (RIL_Token t);
#if defined(MTK_RIL) || defined(C2K_RIL)
/**
* Same propose as RequestTimedCallback but executed in proxy thread
*/
void (*RequestProxyTimedCallback) (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime, int proxyId);
/**
* Query Context from RIL_Token
*/
RILChannelId (*QueryMyChannelId) (RIL_Token t);
/**
* Query current proxy according to thread
*/
int (*QueryMyProxyIdByThread)();
#endif
};
结构体变量在rild.cpp中定义,其函数在ril.cpp中实现
//@rild.cpp
static struct RIL_Env s_rilEnv = {
RIL_onRequestComplete, //请求完成,向上反馈结果
RIL_onUnsolicitedResponse, //UNSOL信息反馈
RIL_requestTimedCallback,
RIL_onRequestAck
#ifdef MTK_RIL
,RIL_requestProxyTimedCallback
,RIL_queryMyChannelId
,RIL_queryMyProxyIdByThread
#endif
};
其结构体定义为:
//@mtk_ril.h
typedef struct {
int version; //当前链接库的版本信息
RIL_RequestFunc onRequest; //用于Event侧向动态库发起请求
RIL_RadioStateRequest onStateRequest; //得到当前库的状态
RIL_Supports supports; //查询是否支持某个命令
RIL_Cancel onCancel; //取消一个Event的处理
RIL_GetVersion getVersion; //得到版本号
#ifdef C2K_RIL
RIL_ReportSocketConn reportRILDConn;
#endif
} RIL_RadioFunctions;
其中除了version之外,如RIL_RequestFunc都是函数指针类型。
这些函数的实现与结构体变量定义在ril_callbacks.c:
// ril_callbacks.c
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
创建线程执行mainloop函数
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv){
s_rilenv = env;
...
//异常判断
...
//创建线程执行mainloop函数
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
//返回回调函数
return &s_callbacks;
}
mainloop中循环打开AT通道获取数据
static void *mainLoop(void *param){
//readloop关闭时回调函数
at_set_on_reader_closed(onATReaderClosed);
//readloop超时时回调函数
at_set_on_timeout(onATTimeout);
//初始化channel
initRILChannels();
fd = -1;
while (fd < 0) {
//与AT通道有关的Context信息,包括FD标识符
RILChannelCtx * p_channel;
...
for (i=0; i < getSupportChannels(); i ++){
//可以有多个at通道,(针对多卡的情况?)
p_channel = getChannelCtxbyId(i);
//打开fd对应的AT通道,并将UNSOL处理方法onUnsolicited传入
ret = at_open(p_channel->fd,onUnsolicited, p_channel);
}
//阻塞线程
/*
AT通道在检测超时后,将会主动的关闭当前的AT通道,此时将会激活waitForClose中的阻塞线程
然后waitForClose将会返回
而一旦waitForClose函数返回,将会再次进入for循环,重新打开AT通道。
*/
waitForClose();
}
}
打开AT通道,就是创建线程去读fd内容,读到的内容一般交给processline来处理。
processline区分UNSOL和SOL消息分别进行处理,这里注意判断UNSOL和SOL消息的依据,一般都是通过prefix来判断。
int at_open(int fd, ATUnsolHandler h)
{
...
//at通道文件句柄,这里赋给全局变量
s_fd = fd;
//UNSOL信息处理函数,这里赋给全局变量
s_unsolHandler = h;
...
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
...
return 0;
}
static void *readerLoop(void *arg)
{
for (;;) {
const char * line;
//从AT通道文件句fd中中读一行,如果超时,返回NULL
line = readline();
//如果没读到东西,break
if (line == NULL) {
break;
}
if(isSMSUnsolicited(line)) {
//对于SMS UNSOL消息的处理,注意这个s_unsolHandler是在at_open中传入的函数参数。
s_unsolHandler (line1, line2);
free(line1);
} else {
//大部分消息在这里处理
processLine(line);
}
}
//读AT通道结束时的回调
onReaderClosed();
return NULL;
}
static void processLine(const char *line)
{
//sp_response为NULL,表示为USOL消息
//sp_response下面再讨论
if (sp_response == NULL) {
/* no command pending */
handleUnsolicited(line);
} else if (isFinalResponseSuccess(line)) {
//对于SOL消息的处理
sp_response->success = 1;
handleFinalResponse(line);
}
...
pthread_mutex_unlock(&s_commandmutex);
}
上面的readerLoop在对Modem返回数据进行处理是分两条线:
1. 短信相关UNSOL处理
2. 普通UNSOL处理
Android手机接收到Modem发出有线短信的AT命令,其文本格式非常固定,共有两行line1和line2,因此它可以直接在第一个分支做特殊处理;而调用processLine()函数处理普通AT命令,其中包括了多种处理方式,最典型的如SINGLELINE,MULTILINE和NO_RESULT等,虽然处理方式不同,但他们最终会调用handleUnsolicited。如下分析。
对不同类型的UNSOL进行分类处理
static void handleUnsolicited(const char *line)
{
if (s_unsolHandler != NULL) {
//s_unsolHandler来自at_open的参数,即为onUnsolicited函数,其实现在ril_callbacks.c中
s_unsolHandler(line, NULL);
}
}
//@ril_callbacks.c
static void onUnsolicited(const char *s, const char *sms_pdu, void *pChannel)
{
char *line = NULL;
int urcToMalLength = 0;
int err;
RIL_RadioState radioState = sState;
RILChannelCtx *p_channel = (RILChannelCtx *)pChannel;
//从RILChannelCtx获取Radio状态
if (RIL_SOCKET_2 == getRILIdByChannelCtx(p_channel)) {
radioState = sState2;
} else if (RIL_SOCKET_3 == getRILIdByChannelCtx(p_channel)) {
radioState = sState3;
} else if (RIL_SOCKET_4 == getRILIdByChannelCtx(p_channel)) {
radioState = sState4;
}
//如果RIL状态不可用,,返回
...
//不同类型的UNSOL信息的处理,这些函数主要是通过s信息的皮prefix来判定不同的消息类型
if (!(rilNwUnsolicited(s, sms_pdu, p_channel) ||
rilCcUnsolicited(s, sms_pdu, p_channel) ||
rilSsUnsolicited(s, sms_pdu, p_channel) ||
rilSmsUnsolicited(s, sms_pdu, p_channel) ||
rilStkUnsolicited(s, sms_pdu, p_channel) ||
rilOemUnsolicited(s, sms_pdu, p_channel) ||
rilDataUnsolicited(s, sms_pdu, p_channel) ||
rilSimUnsolicited(s, sms_pdu, p_channel) ||
rilPhbUnsolicited(s, sms_pdu, p_channel)))
RLOGE("Unhandled unsolicited result code: %s\n", s);
}
针对上面的每种分类的UNSOL,都有对应的文件定义其处理方式,以便于解耦
上面以NetWork类型的UNSOL为例,其处理函数定义在mtk_ril/ril_nw.c中。
最终这些经过解析的UNSOL信息都会调用RIL_UNSOL_RESPONSE
而RIL_UNSOL_RESPONSE
通过宏定义到LibRIL的RIL_onUnsolicitedResponse((a), (b), (c))
因此这些UNSOL信息最终传递到了LibRIL中
//@ril_nw.c
int rilNwUnsolicited(const char *s, const char *sms_pdu, RILChannelCtx* p_channel)
{
RIL_SOCKET_ID rid = getRILIdByChannelCtx(p_channel);
//通过prefix判断是否为网络状态信息的UNSOL
if (strStartsWith(s, "+CREG:") || strStartsWith(s, "+CGREG:") || strStartsWith(s, "+PSBEARER:") || strStartsWith(s, "+CEREG:"))
{
onNetworkStateChanged((char*) s,rid);
return 1;
}
...
}
//@ril_nw.c
void onNetworkStateChanged(char *urc, const RIL_SOCKET_ID rid){
//解析UNSOL信息参数urc,构建网上传递的信息
//针对Voice NewtWork状态和PS NewtWork状态,调用LibRIL回调函数往上传
if (is_cs == 1){
RIL_UNSOL_RESPONSE (RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
responseStr, sizeof(responseStr), rid);
}else{
RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED,
&stat, sizeof(stat), rid);
}
}
最后在LibRIL中,将数据进行打包,发送给RILJ
void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen, RIL_SOCKET_ID socket_id){
unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
//通过unsolResponse获取对应的返回类型
if (unsolResponse >= RIL_LOCAL_GSM_UNSOL_VENDOR_BASE) {
unsolResponseIndex = unsolResponse - RIL_LOCAL_GSM_UNSOL_VENDOR_BASE;
wakeType = s_mtk_local_urc_commands[unsolResponseIndex].wakeType;
}
else if (unsolResponse >= RIL_UNSOL_VENDOR_BASE) {
unsolResponseIndex = unsolResponse - RIL_UNSOL_VENDOR_BASE;
//s_mtk_unsolResponses是UnsolResponseInfo类型的数组
wakeType = s_mtk_unsolResponses[unsolResponseIndex].wakeType;
}
else
{
wakeType = s_unsolResponses[unsolResponseIndex].wakeType;
}
...
//正对不同类型进行处理
switch (wakeType) {
case WAKE_PARTIAL:
grabPartialWakeLock();
shouldScheduleTimeout = true;
break;
case DONT_WAKE:
default:
// No wake lock is grabed so don't set timeout
shouldScheduleTimeout = false;
break;
}
...
Parcel p;
...
if (unsolResponse >= RIL_LOCAL_GSM_UNSOL_VENDOR_BASE) {
//调用对应UnsolResponseInfo的处理函数进行处理,将数据写入Parcel
ret = s_mtk_local_urc_commands[unsolResponseIndex]
.responseFunction(p, const_cast<void*>(data), datalen);
}
else if (unsolResponse >= RIL_UNSOL_VENDOR_BASE) {
ret = s_mtk_unsolResponses[unsolResponseIndex]
.responseFunction(p, const_cast<void*>(data), datalen);
} else
{
ret = s_unsolResponses[unsolResponseIndex]
.responseFunction(p, const_cast<void*>(data), datalen);
}
...
//针对不同标识的UNSOL进行Parcel加工处理
...
//发送到RILJ中
ret = sendResponse(p, soc_id);
}
static int
sendResponse (Parcel &p, RIL_SOCKET_ID socket_id) {
printResponse;
return sendResponseRaw(p.data(), p.dataSize(), socket_id);
}
static int
sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_ID socket_id) {
//从Socket连接参数的数组中获取Socket的FD
int fd = s_ril_param_socket[socket_id].fdCommand;
...
//将数据长度这个整数转换为适合Socket 传输的字节顺序
header = htonl(dataSize);
//先发送数据大小
ret = blockingWrite(fd, (void *)&header, sizeof(header));
//再发送数据,将信息写入Socket传到RILJ
//这个fd是在RIL_register—>startListenadd listen Event,在EventLoop中监听获取
ret = blockingWrite(fd, data, dataSize);
}
针对SOL消息的处理,相对于UNSOL稍稍复杂一点.
在3.3.2中,可以看到,最终是使用了handleFinalResponse()函数来进行SOL消息的处理:
static void processLine(const char *line, RILChannelCtx *p_channel){
...
//将数据封装到p_channel->p_response->p_intermediates中
addIntermediate(line, p_channel);
...
//设置成功标志位
p_response->success = 1;
//处理数据返回
handleFinalResponse(line, p_channel);
}
static void handleFinalResponse(const char *line, RILChannelCtx *p_channel)
{
//将数据放入p_channel->p_response->finalResponse
ATResponse *p_response = p_channel->p_response;
p_response->finalResponse = strdup(line);
//唤醒s_commandcond线程,使其脱离阻塞状态
pthread_cond_signal(&p_channel->commandcond);
}
handleFinalResponse()函数只是把返回的结果放到了finalResponse结构中,为什么会到这里就结束了呢?难道是有其他地方在一直监控这个变量,当它不为NULL时,就表示了返回结果?答案时肯定的。
对于一条SOL消息,必定对应了一条request,在request向Modem发送了请求会后会在循环中检测p_channel->p_response的状态,在对应SOL消息未返回之前,一直为NULL,当handleFinalResponse函数将返回值写入p_response之后,就会跳出循环开始读取p_response数据。
详见的执行流程可以参考atchannel.c的at_send_command_full_nolock()
函数。当然后面的的整体流程分析中也会再拿出来说明。
ReaderLooper主要的功能就是读取并处理Modem上发的消息,这些消息总体分为UNSOL和SOL消息,然后针对这两种类型的消息,分别做不同的处理,最终的结果都是会通过LibRIL上发给RILJ。