RILD
来源:互联网 发布:手机淘宝 卖家中心 编辑:程序博客网 时间:2024/05/21 09:32
三、 ReaderLooper()
ReaderLooper主要用来监听Modem上发信息
RIL需要加载一个AT相关的reference-ril.so的动态链接库。之所以使用 库的形式,就是考虑到每个厂商使用的Modem不同,我们没法用统一的接口去向底层负责,因此使用库的形式。这样一来,不同的Modem厂商提供不同的链接库,只要符合RIL层的框架即可。
3.1 ReadLoop预备知识
3.1.1 ReferenceRIL初始化入口
前面在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都拥有对方的回调,从而能够是他们之间进行双向通信。
下面来看看这两个包含回调函数的结构体。
3.1.2 LibRIL回调(RIL_Env)
其结构体定义为:
//@mtk_ril.hstruct 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.cppstatic struct RIL_Env s_rilEnv = { RIL_onRequestComplete, //请求完成,向上反馈结果 RIL_onUnsolicitedResponse, //UNSOL信息反馈 RIL_requestTimedCallback, RIL_onRequestAck#ifdef MTK_RIL ,RIL_requestProxyTimedCallback ,RIL_queryMyChannelId ,RIL_queryMyProxyIdByThread#endif};
3.1.3 ReferenceRIL回调(RIL_RadioFunctions)
其结构体定义为:
//@mtk_ril.htypedef 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.cstatic const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion};
3.2 RIL_Init执行流程
创建线程执行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;}
3.2.1 mainloop()
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(); }}
3.2.2 at_open()
打开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。如下分析。
3.2.3 UNSOL消息处理
对不同类型的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.cstatic 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.cint 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.cvoid 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 intsendResponse (Parcel &p, RIL_SOCKET_ID socket_id) { printResponse; return sendResponseRaw(p.data(), p.dataSize(), socket_id);}static intsendResponseRaw (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);}
3.2.4 SOL消息处理
针对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()
函数。当然后面的的整体流程分析中也会再拿出来说明。
3.3 总结
ReaderLooper主要的功能就是读取并处理Modem上发的消息,这些消息总体分为UNSOL和SOL消息,然后针对这两种类型的消息,分别做不同的处理,最终的结果都是会通过LibRIL上发给RILJ。
- rild
- rild
- RILD
- RILD
- RILD
- RILD
- RILD
- RILD
- RILD
- RILD
- rild 术语
- rild进程
- Introduction to Android RILD
- Rild层代码分析
- rild 源码分析
- Android RILD学习
- Android Rild 概述
- Android电话系统rild
- python 的xml解析
- php、nginx 两个分开的容器相连连不上的问题总结
- FreeRTOS在STM32F4上移植
- js之二级伸缩栏目+多选框+开关门
- 竖式问题
- RILD
- MII 类型接口介绍
- Struts2的下载安装
- css的伪类
- C#委托
- 爬取58上的大量二手数据并保存在MongoDB中
- 魔高道涨-互联网作弊与反作弊
- yii文件下载
- 【Java集合源码剖析】HashMap源码剖析