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—>startListenadd 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。

原创粉丝点击