Android RILD 处理流程

Android电话系统框架

      在android系统中rild运行在AP上,AP上的应用通过ril发送AT指令给BP,BP接收到信息后通过rild传送给AP。AP与BP之间有两种通信方式:

     1.Solicited  Response: AP向BP发起请求,BP给AP发送回复,该类型的AT指令及其回调函数以数组的形式存在Ril_commands.h文件中:

{数组中的索引号,请求回调函数,响应回调函数}

    {0, NULL},                   //none
    {RIL_REQUEST_GET_SIM_STATUS, radio::getIccCardStatusResponse},
    {RIL_REQUEST_ENTER_SIM_PIN, radio::supplyIccPinForAppResponse},
    ......

 

     2.unSolicited Response : BP主动给AP发送事件,该类型的AT指令及其回调函数以数组的形式存放在
ril_unsol_commands.h 文件中 : 

{数组中的索引号,响应回调函数,类型}

    {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL},
    {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL},
    {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio::networkStateChangedInd, WAKE_PARTIAL},
    ......

 

不同手机厂商使用的AT命令完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。

通信结构:

Android RILD 处理流程_第1张图片

RIL模块由rild守护进程,libril.so,librefrence.so三部分组成 : 
     1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过Ril_register()函数注册到libril.so库中,其源码结构如下 : 
Android RILD 处理流程_第2张图片

       2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息发给调用进程,源码结构如下所示:
Android RILD 处理流程_第3张图片

     3.librefrence_ril.so是有各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libri.so的请求为AT命令,同时监听Modem的反馈信息给libril.so

Android RILD 处理流程_第4张图片

    Android的电话系统主要分三个部分,java层的各种电话相关应用,java层的Phone Service ,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:

Android RILD 处理流程_第5张图片

 

Android电话系统设计框架图 : 


Android RILD 处理流程_第6张图片

      由于Android开发使用的Modem不一样的,各种指令格式; 初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态连接库.os文件,Rild是具体的AT指令合成者和应答解析者。

Android电话系统代码结构图:

Android RILD 处理流程_第7张图片

 

RILD框架设计

       在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务于modem的交互,在java层实现电话的客户端,这里主要介绍电话系统的服务端RILD进程,RILD的设计框架图:

Android RILD 处理流程_第8张图片

 

RIL源码分析

在kernel启动完成后,将启动第一个应用进程Init进程,init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动。 
Android启动流程大致如下:Android RILD 处理流程_第9张图片

RILD进程入口函数分析时序图:

Android RILD 处理流程_第10张图片

 

代码这里进入一个main方法

int main(int argc, char **argv) {
    // vendor ril lib path either passed in as -l parameter, or read from rild.libpath property
    const char *rilLibPath = NULL;
    // ril arguments either passed in as -- parameter, or read from rild.libargs property
    char **rilArgv;
    // handle for vendor ril lib
    void *dlHandle;

    // Vendor RIL接口函数
    // Pointer to ril init function in vendor ril
    const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
    // Pointer to sap init function in vendor ril
    const RIL_RadioFunctions *(*rilUimInit)(const struct RIL_Env *, int, char **);
    const char *err_str = NULL;

    // functions returned by ril init function in vendor ril
    const RIL_RadioFunctions *funcs;
    // lib path from rild.libpath property (if it's read)
    char libPath[PROPERTY_VALUE_MAX];
    // flat to indicate if -- parameters are present
    unsigned char hasLibArgs = 0;

    int i;
    // ril/socket id received as -c parameter, otherwise set to 0
    const char *clientId = NULL;

    RLOGD("**RIL Daemon Started**");
    RLOGD("**RILd param count=%d**", argc);

    initWithMmapSize();
    umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    //rild启动无参数 
    for (i = 1; i < argc ;) {
        if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
            rilLibPath = argv[i + 1];
            i += 2;
        } else if (0 == strcmp(argv[i], "--")) {
            i++;
            hasLibArgs = 1;
            break;
        } else if (0 == strcmp(argv[i], "-c") &&  (argc - i > 1)) {
            clientId = argv[i+1];
            i += 2;
        } else {
            usage(argv[0]);
        }
    }

    if (clientId == NULL) {
        clientId = "0";
    } else if (atoi(clientId) >= MAX_RILDS) {
        RLOGE("Max Number of rild's supported is: %d", MAX_RILDS);
        exit(0);
    }
    if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) {
        snprintf(ril_service_name, sizeof(ril_service_name), "%s%s", ril_service_name_base,
                 clientId);
    }

    if (rilLibPath == NULL) {
        //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径
        if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
            // No lib sepcified on the command line, and nothing set in props.
            // Assume "no-ril" case.
            goto done;
        } else {
            rilLibPath = libPath;
        }
    }
    //从指定路径加载RILD可执行文件
    dlHandle = dlopen(rilLibPath, RTLD_NOW);

    if (dlHandle == NULL) {
        RLOGE("dlopen failed: %s", dlerror());
        exit(EXIT_FAILURE);
    }
    // 启动LIBRIL的事件处理线程
    RIL_startEventLoop();
    //Vendor RIL初始化函数,返回一个RIL_RadioFunctions   通过dlsym定位到需要执行的函数指针
    rilInit =
        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
        dlsym(dlHandle, "RIL_Init");

    if (rilInit == NULL) {
        RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
        exit(EXIT_FAILURE);
    }

    dlerror(); // Clear any previous dlerror
    rilUimInit =
        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
        dlsym(dlHandle, "RIL_SAP_Init");
    err_str = dlerror();
    if (err_str) {
        RLOGW("RIL_SAP_Init not defined or exported in %s: %s\n", rilLibPath, err_str);
    } else if (!rilUimInit) {
        RLOGW("RIL_SAP_Init defined as null in %s. SAP Not usable\n", rilLibPath);
    }

    if (hasLibArgs) {
        rilArgv = argv + i - 1;
        argc = argc -i + 1;
    } else {
        static char * newArgv[MAX_LIB_ARGS];
        static char args[PROPERTY_VALUE_MAX];
        rilArgv = newArgv;
        //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径
        property_get(LIB_ARGS_PROPERTY, args, "");
        argc = make_argv(args, rilArgv);
    }

    rilArgv[argc++] = "-c";
    rilArgv[argc++] = (char*)clientId;
    RLOGD("RIL_Init argc = %d clientId = %s", argc, rilArgv[argc-1]);

    // Make sure there's a reasonable argv[0]
    rilArgv[0] = argv[0];

    //reference-ril.so初始化 处理客户端请求的模块reference-ril.c
    //s_rilEnv建立应答回调机制
    //返回处理请求的相关接口
    funcs = rilInit(&s_rilEnv, argc, rilArgv);
    RLOGD("RIL_Init rilInit completed");
    //将RIL_RadioFunctions注册LIBRIL中
    RIL_register(funcs);

    RLOGD("RIL_Init RIL_register completed");

    if (rilUimInit) {
        RLOGD("RIL_register_socket started");
        RIL_register_socket(rilUimInit, RIL_SAP_SOCKET, argc, rilArgv);
    }

    RLOGD("RIL_register_socket completed");

done:

    rilc_thread_pool();

    RLOGD("RIL_Init starting sleep loop");
    while (true) {
        sleep(UINT32_MAX);
    }
}

RILD初始化主要处理了三件事 : 
1 . 加载Vendor RIL的代码,并对其进行初始化操作,将LIBRIL的接口RIL_Env传递给Vendor RIL ,用于回调;
2 . 开始RIL事件处理线程
3 . 将Vendor RIL的接口注册到LIBRIL中,这样LIBRIL就可以将消息发给Vendor RIL了
4 . 从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so           库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到,到libril.so库中,建立起libril.so库与libreference-         ril.so库通信桥梁

这里的    dlopen() 是一个强大的库函数。该函数将打开一个新库,并把它装入内存。

 

接下来我们看启动事件循环处理

接下来看RIL_startEventLoop()  这个方法是启动LIBRIL的事件处理线程,建立多路I/O驱动机制的消息列队,用来接收上层发出的命令以及往Modem发送AT指令的工作,是整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop

接下来看一下代码 : hardware\ril\libril\ril.cpp
查看  RIL_startEventLoop  

extern "C" void RIL_startEventLoop(void) {
    /* spin up eventLoop thread and wait for it to get started */
    s_started = 0;
    pthread_mutex_lock(&s_startupMutex);

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    //创建一个工作线程,eventLoop  eventLoop函数才是真正开始启动事件处理线程的地方
    int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
    if (result != 0) {
        RLOGE("Failed to create dispatch thread: %s", strerror(result));
        goto done;
    }
     //确保函数返回前eventLoop线程启动运行
    while (s_started == 0) {
        pthread_cond_wait(&s_startupCond, &s_startupMutex);
    }

done:
    pthread_mutex_unlock(&s_startupMutex);
}



static void * eventLoop(void *param) {
    int ret;
    int filedes[2];
    //初始化事件队列
    ril_event_init();

    pthread_mutex_lock(&s_startupMutex);

    s_started = 1;
    pthread_cond_broadcast(&s_startupCond);

    pthread_mutex_unlock(&s_startupMutex);

    ret = pipe(filedes);

    if (ret < 0) {
        RLOGE("Error in pipe() errno:%d", errno);
        return NULL;
    }
    // 用于监听wakeup事件的pipe端口
    s_fdWakeupRead = filedes[0];
    s_fdWakeupWrite = filedes[1];

    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
    //设置线程唤醒事件,唤醒时,回调processWakeupCallback函数
    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
                processWakeupCallback, NULL);

    rilEventAddWakeup (&s_wakeupfd_event);

    // Only returns on error  // 真正干活的函数
    ril_event_loop();
    RLOGE ("error in event_loop_base errno:%d", errno);
    // kill self to restart on error
    kill(0, SIGKILL);

    return NULL;
}
  • RILD初始化vendor RIL之后,将返回的RIL_RadioFunctions返回给RILD,RILD接着将其注册到LIBRIL中:
struct ril_event {
    struct ril_event *next;
    struct ril_event *prev;

    int fd;//文件句柄
    int index;//该事件在监控表中的索引
    bool persist;//如果是保持的,则不从watch_list 中删除
    struct timeval timeout;//任务执行时间
    ril_event_cb func;//回调事件处理函数
    void *param;//回调时参数
};

在Rild进程中的几个重要事件有
在RILD中定义了三个事件队列,用于处理不同的事件:

//事件监控队列
static struct ril_event * watch_table[MAX_FD_EVENTS];
//定时事件队列
static struct ril_event timer_list;
//处理事件队列
static struct ril_event pending_list;//待处理事件队列,事件已经触发,需要所回调处理的事件

添加事件

1.添加Wakeup 事件

static void rilEventAddWakeup(struct ril_event *ev) {
    ril_event_add(ev);//向监控表watch_table添加一个s_wakeupfd_event事件
    triggerEvLoop();//向管道s_fdWakeupWrite中写入之来触发事件循环
}
// Add event to watch list
void ril_event_add(struct ril_event * ev)
{
    dlog("~~~~ +ril_event_add ~~~~");
    MUTEX_ACQUIRE();
    for (int i = 0; i < MAX_FD_EVENTS; i++) {//遍历监控表watch_table
        if (watch_table[i] == NULL) { //从监控表中查找空闲的索引,然后把该任务加入到监控表中
            watch_table[i] = ev;//向监控表中添加事件
            ev->index = i;//事件的索引设置为在监控表中的索引
            dlog("~~~~ added at %d ~~~~", i);
            dump_event(ev);
            FD_SET(ev->fd, &readFds);//将添加的事件对应的句柄添加到句柄池readFds中
            if (ev->fd >= nfds) nfds = ev->fd+1;//修改句柄最大值  
            dlog("~~~~ nfds = %d ~~~~", nfds);
            break;
        }
    }
    MUTEX_RELEASE();
    dlog("~~~~ -ril_event_add ~~~~");
}

2.添加定时事件

// Add timer event
void ril_timer_add(struct ril_event * ev, struct timeval * tv)
{
    dlog("~~~~ +ril_timer_add ~~~~");
    MUTEX_ACQUIRE();

    struct ril_event * list;
    if (tv != NULL) {
        // add to timer list
        list = timer_list.next;
        ev->fd = -1; // make sure fd is invalid

        struct timeval now;
        getNow(&now);
        timeradd(&now, tv, &ev->timeout);

        // keep list sorted
        while (timercmp(&list->timeout, &ev->timeout, < )
                && (list != &timer_list)) {
            list = list->next;
        }
        // list now points to the first event older than ev
        addToList(ev, list);
    }

    MUTEX_RELEASE();
    dlog("~~~~ -ril_timer_add ~~~~");
}

触发事件

static void triggerEvLoop() {
    int ret;
    if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //如果当前线程ID不等于事件分发线程eventLoop的线程ID  
        /* trigger event loop to wakeup. No reason to do this,
         * if we're in the event loop thread */
         do {
            ret = write (s_fdWakeupWrite, " ", 1);//向管道写端写入值1来触发eventLoop事件循环  
         } while (ret < 0 && errno == EINTR);
    }
}

处理事件

void ril_event_loop(){
    int n;
    fd_set rfds;
    struct timeval tv;
    struct timeval * ptv;

    for (;;) {

        // make local copy of read fd_set
        memcpy(&rfds, &readFds, sizeof(fd_set));
        if (-1 == calcNextTimeout(&tv)) {
            // no pending timers; block indefinitely
            dlog("~~~~ no timers; blocking indefinitely ~~~~");
            ptv = NULL;
        } else {
            dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
            ptv = &tv;
        }
        //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。
        //readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。
        printReadies(&rfds);
        n = select(nfds, &rfds, NULL, NULL, ptv);
        printReadies(&rfds);
        dlog("~~~~ %d events fired ~~~~", n);
        if (n < 0) {
            if (errno == EINTR) continue;

            RLOGE("ril_event: select error (%d)", errno);
            // bail?
            return;
        }

        // Check for timeouts
        processTimeouts();//从timer_list中查询执行时间已到的事件,并添加到pending_list中
        // Check for read-ready
        processReadReadies(&rfds, n);//从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除
        // Fire away
        firePending(); //遍历pending_list,调用事件处理回调函数处理所有事件  
    }
}

在eventLoop工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:

Android RILD 处理流程_第11张图片

首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。

1.超时事件查询

static void processTimeouts(){
    dlog("~~~~ +processTimeouts ~~~~");
    MUTEX_ACQUIRE();
    struct timeval now;
    struct ril_event * tev = timer_list.next;
    struct ril_event * next;

    getNow(&now);//获取当前时间
    // walk list, see if now >= ev->timeout for any events

    dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
    //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list
    while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
        // Timer expired
        dlog("~~~~ firing timer ~~~~");
        next = tev->next;
        removeFromList(tev); //从timer_list中移除事件
        addToList(tev, &pending_list);//将事件添加到pending_list
        tev = next;
    }
    MUTEX_RELEASE();
    dlog("~~~~ -processTimeouts ~~~~");
}

2.可读事件查询

static void processReadReadies(fd_set * rfds, int n){
    dlog("~~~~ +processReadReadies (%d) ~~~~", n);
    MUTEX_ACQUIRE();
    //遍历watch_table数组,根据select返回的句柄n查找对应的事件
    for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
        struct ril_event * rev = watch_table[i]; //得到相应的事件
        if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
            addToList(rev, &pending_list); //将该事件添加到pending_list中
            if (rev->persist == false) {//如果该事件不是持久事件还要从watch_table中移除
                removeWatch(rev, i);
            }
            n--;
        }
    }

    MUTEX_RELEASE();
    dlog("~~~~ -processReadReadies (%d) ~~~~", n);
}

3.事件处理

static void firePending(){
    dlog("~~~~ +firePending ~~~~");
    struct ril_event * ev = pending_list.next;
    while (ev != &pending_list) {//遍历pending_list链表,处理链表中的所有事件
        struct ril_event * next = ev->next;
        removeFromList(ev);//将处理完的事件从pending_list中移除
        ev->func(ev->fd, 0, ev->param);//调用事件处理的回调函数
        ev = next;
    }
    dlog("~~~~ -firePending ~~~~");
}

 

RIL_Env定义

hardware\ril\include\telephony\ril.h

struct RIL_Env {
     //动态库完成请求后通知处理结果的接口
    void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
                           void *response, size_t responselen);
#if defined(ANDROID_MULTI_SIM)
    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id);
#else
     //动态库unSolicited Response通知接口
    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen);
#endif
    //向Rild提交一个超时任务的接口
    void (*RequestTimedCallback) (RIL_TimedCallback callback,
                                   void *param, const struct timeval *relativeTime);
    void (*OnRequestAck) (RIL_Token t);
};

hardware\ril\rild\rild.c
s_rilEnv变量定义:

static struct RIL_Env s_rilEnv = {
    RIL_onRequestComplete,
    RIL_onUnsolicitedResponse,
    RIL_requestTimedCallback,
    RIL_onRequestAck
};

在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数

 

1.RIL_onRequestComplete

extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
    RequestInfo *pRI;
    int ret;
    RIL_SOCKET_ID socket_id = RIL_SOCKET_1;

    pRI = (RequestInfo *)t;

    if (!checkAndDequeueRequestInfoIfAck(pRI, false)) {
        RLOGE ("RIL_onRequestComplete: invalid RIL_Token");
        return;
    }

    socket_id = pRI->socket_id;
#if VDBG
    RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id));
#endif

    if (pRI->local > 0) {
        // Locally issued command...void only!
        // response does not go back up the command socket
        RLOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));

        free(pRI);
        return;
    }

    appendPrintBuf("[%04d]< %s",
        pRI->token, requestToString(pRI->pCI->requestNumber));

    if (pRI->cancelled == 0) {
        int responseType;
        if (s_callbacks.version >= 13 && pRI->wasAckSent == 1) {
            // If ack was already sent, then this call is an asynchronous response. So we need to
            // send id indicating that we expect an ack from RIL.java as we acquire wakelock here.
            responseType = RESPONSE_SOLICITED_ACK_EXP;
            grabPartialWakeLock();
        } else {
            responseType = RESPONSE_SOLICITED;
        }

        // there is a response payload, no matter success or not.
#if VDBG
        RLOGE ("Calling responseFunction() for token %d", pRI->token);
#endif

        pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) socket_id);
        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
        assert(rwlockRet == 0);

        ret = pRI->pCI->responseFunction((int) socket_id,
                responseType, pRI->token, e, response, responselen);

        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
        assert(rwlockRet == 0);
    }
    free(pRI);
}

通过调用responseXXX将底层响应传给客户进程

2.RIL_onUnsolicitedResponse

extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                                size_t datalen)
#endif{
    int unsolResponseIndex;
    int ret;
    bool shouldScheduleTimeout = false;
    RIL_SOCKET_ID soc_id = RIL_SOCKET_1;

#if defined(ANDROID_MULTI_SIM)
    soc_id = socket_id;
#endif


    if (s_registerCalled == 0) {
        // Ignore RIL_onUnsolicitedResponse before RIL_register
        RLOGW("RIL_onUnsolicitedResponse called before RIL_register");
        return;
    }

    unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;

    if ((unsolResponseIndex < 0)
        || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
        RLOGE("unsupported unsolicited response code %d", unsolResponse);
        return;
    }

    // Grab a wake lock if needed for this reponse,
    // as we exit we'll either release it immediately
    // or set a timer to release it later.
    switch (s_unsolResponses[unsolResponseIndex].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;
    }

    appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));

    int responseType;
    if (s_callbacks.version >= 13
                && s_unsolResponses[unsolResponseIndex].wakeType == WAKE_PARTIAL) {
        responseType = RESPONSE_UNSOLICITED_ACK_EXP;
    } else {
        responseType = RESPONSE_UNSOLICITED;
    }

    pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) soc_id);
    int rwlockRet;

    if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
        // get a write lock in caes of NITZ since setNitzTimeReceived() is called
        rwlockRet = pthread_rwlock_wrlock(radioServiceRwlockPtr);
        assert(rwlockRet == 0);
        radio::setNitzTimeReceived((int) soc_id, android::elapsedRealtime());
    } else {
        rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
        assert(rwlockRet == 0);
    }

    ret = s_unsolResponses[unsolResponseIndex].responseFunction(
            (int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast(data),
            datalen);

    rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
    assert(rwlockRet == 0);

    if (s_callbacks.version < 13) {
        if (shouldScheduleTimeout) {
            UserCallbackInfo *p_info = internalRequestTimedCallback(wakeTimeoutCallback, NULL,
                    &TIMEVAL_WAKE_TIMEOUT);

            if (p_info == NULL) {
                goto error_exit;
            } else {
                // Cancel the previous request
                if (s_last_wake_timeout_info != NULL) {
                    s_last_wake_timeout_info->userParam = (void *)1;
                }
                s_last_wake_timeout_info = p_info;
            }
        }
    }

#if VDBG
    RLOGI("%s UNSOLICITED: %s length:%zu", rilSocketIdToString(soc_id),
            requestToString(unsolResponse), datalen);
#endif

    if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
        // Unfortunately, NITZ time is not poll/update like everything
        // else in the system. So, if the upstream client isn't connected,
        // keep a copy of the last NITZ response (with receive time noted
        // above) around so we can deliver it when it is connected

        if (s_lastNITZTimeData != NULL) {
            free(s_lastNITZTimeData);
            s_lastNITZTimeData = NULL;
        }

        s_lastNITZTimeData = calloc(datalen, 1);
        if (s_lastNITZTimeData == NULL) {
            RLOGE("Memory allocation failed in RIL_onUnsolicitedResponse");
            goto error_exit;
        }
        s_lastNITZTimeDataSize = datalen;
        memcpy(s_lastNITZTimeData, data, datalen);
    }

    // Normal exit
    return;

error_exit:
    if (shouldScheduleTimeout) {
        releaseWakeLock();
    }
}

这个函数处理modem从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。

 

3.RIL_requestTimedCallback

extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
                                const struct timeval *relativeTime) {
    internalRequestTimedCallback (callback, param, relativeTime);
}


static UserCallbackInfo * internalRequestTimedCallback (RIL_TimedCallback callback, void *param,const struct timeval *relativeTime){
    struct timeval myRelativeTime;
    UserCallbackInfo *p_info;

    p_info = (UserCallbackInfo *) calloc(1, sizeof(UserCallbackInfo));
    if (p_info == NULL) {
        RLOGE("Memory allocation failed in internalRequestTimedCallback");
        return p_info;

    }

    p_info->p_callback = callback;
    p_info->userParam = param;

    if (relativeTime == NULL) {
        /* treat null parameter as a 0 relative time */
        memset (&myRelativeTime, 0, sizeof(myRelativeTime));
    } else {
        /* FIXME I think event_add's tv param is really const anyway */
        memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
    }

    ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);

    ril_timer_add(&(p_info->event), &myRelativeTime);

    triggerEvLoop();
    return p_info;
}

RIL_RadioFunctions定义

客户端向Rild发送请求的接口,由各手机厂商实现。
hardware\ril\include\telephony\ril.h 

typedef struct {
    int version;        /* set to RIL_VERSION */   //Rild版本
    RIL_RequestFunc onRequest;                     //AP请求接口
    RIL_RadioStateRequest onStateRequest;          //BP状态查询
    RIL_Supports supports;
    RIL_Cancel onCancel;
    RIL_GetVersion getVersion;                     //动态库版本 
} RIL_RadioFunctions;

变量定义:

static const RIL_RadioFunctions s_callbacks = {
    RIL_VERSION,
    onRequest,
    currentState,
    onSupports,
    onCancel,
    getVersion
};

在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数

1.onRequest

static void onRequest (int request, void *data, size_t datalen, RIL_Token t){
    ATResponse *p_response;
    int err;

    RLOGD("onRequest: %s", requestToString(request));

    /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
     * when RADIO_STATE_UNAVAILABLE.
     */
    if (sState == RADIO_STATE_UNAVAILABLE
        && request != RIL_REQUEST_GET_SIM_STATUS
    ) {
        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
        return;
    }

    /* Ignore all non-power requests when RADIO_STATE_OFF
     * (except RIL_REQUEST_GET_SIM_STATUS)
     */
    if (sState == RADIO_STATE_OFF) {
        switch(request) {
            case RIL_REQUEST_BASEBAND_VERSION:
            case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
            case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
            case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
            case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
            case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
            case RIL_REQUEST_CDMA_SUBSCRIPTION:
            case RIL_REQUEST_DEVICE_IDENTITY:
            case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
            case RIL_REQUEST_GET_ACTIVITY_INFO:
            case RIL_REQUEST_GET_CARRIER_RESTRICTIONS:
            case RIL_REQUEST_GET_CURRENT_CALLS:
            case RIL_REQUEST_GET_IMEI:
            case RIL_REQUEST_GET_MUTE:
            case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
            case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
            case RIL_REQUEST_GET_RADIO_CAPABILITY:
            case RIL_REQUEST_GET_SIM_STATUS:
            case RIL_REQUEST_NV_RESET_CONFIG:
            case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
            case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
            case RIL_REQUEST_QUERY_TTY_MODE:
            case RIL_REQUEST_RADIO_POWER:
            case RIL_REQUEST_SET_BAND_MODE:
            case RIL_REQUEST_SET_CARRIER_RESTRICTIONS:
            case RIL_REQUEST_SET_LOCATION_UPDATES:
            case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
            case RIL_REQUEST_SET_TTY_MODE:
            case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
            case RIL_REQUEST_STOP_LCE:
            case RIL_REQUEST_VOICE_RADIO_TECH:
                // Process all the above, even though the radio is off
                break;

            default:
                // For all others, say NOT_AVAILABLE because the radio is off
                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
                return;
        }
    }

    switch (request) {
        case RIL_REQUEST_GET_SIM_STATUS: {
            RIL_CardStatus_v6 *p_card_status;
            char *p_buffer;
            int buffer_size;

            int result = getCardStatus(&p_card_status);
            if (result == RIL_E_SUCCESS) {
                p_buffer = (char *)p_card_status;
                buffer_size = sizeof(*p_card_status);
            } else {
                p_buffer = NULL;
                buffer_size = 0;
            }
            RIL_onRequestComplete(t, result, p_buffer, buffer_size);
            freeCardStatus(p_card_status);
            break;
        }
        case RIL_REQUEST_GET_CURRENT_CALLS:
            requestGetCurrentCalls(data, datalen, t);
            break;
        case RIL_REQUEST_DIAL:
            requestDial(data, datalen, t);
            break;
        case RIL_REQUEST_HANGUP:
            requestHangup(data, datalen, t);
            break;
        case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
        case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
        case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
        case RIL_REQUEST_CONFERENCE:
        case RIL_REQUEST_UDUB:
             requestCallSelection(data, datalen, t, request);
             break;
        case RIL_REQUEST_ANSWER:
            at_send_command("ATA", NULL);

#ifdef WORKAROUND_ERRONEOUS_ANSWER
            s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */

            if (getSIMStatus() != SIM_READY) {
                RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
            } else {
                // Success or failure is ignored by the upper layer here.
                // It will call GET_CURRENT_CALLS and determine success that way.
                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            }
            break;

        case RIL_REQUEST_SEPARATE_CONNECTION:
            {
                char  cmd[12];
                int   party = ((int*)data)[0];

                if (getSIMStatus() == SIM_ABSENT) {
                    RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
                    return;
                }
                // Make sure that party is in a valid range.
                // (Note: The Telephony middle layer imposes a range of 1 to 7.
                // It's sufficient for us to just make sure it's single digit.)
                if (party > 0 && party < 10) {
                    sprintf(cmd, "AT+CHLD=2%d", party);
                    at_send_command(cmd, NULL);
                    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
                } else {
                    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
                }
            }
            break;

        case RIL_REQUEST_SIGNAL_STRENGTH:
            requestSignalStrength(data, datalen, t);
            break;
        case RIL_REQUEST_VOICE_REGISTRATION_STATE:
        case RIL_REQUEST_DATA_REGISTRATION_STATE:
            requestRegistrationState(request, data, datalen, t);
            break;
        case RIL_REQUEST_OPERATOR:
            requestOperator(data, datalen, t);
            break;
        case RIL_REQUEST_RADIO_POWER:
            requestRadioPower(data, datalen, t);
            break;
        case RIL_REQUEST_DTMF: {
            char c = ((char *)data)[0];
            char *cmd;
            asprintf(&cmd, "AT+VTS=%c", (int)c);
            at_send_command(cmd, NULL);
            free(cmd);
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;
        }
        case RIL_REQUEST_SEND_SMS:
        case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
            requestSendSMS(data, datalen, t);
            break;
        case RIL_REQUEST_CDMA_SEND_SMS:
            requestCdmaSendSMS(data, datalen, t);
            break;
        case RIL_REQUEST_IMS_SEND_SMS:
            requestImsSendSMS(data, datalen, t);
            break;
        case RIL_REQUEST_SIM_OPEN_CHANNEL:
            requestSimOpenChannel(data, datalen, t);
            break;
        case RIL_REQUEST_SIM_CLOSE_CHANNEL:
            requestSimCloseChannel(data, datalen, t);
            break;
        case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
            requestSimTransmitApduChannel(data, datalen, t);
            break;
        case RIL_REQUEST_SETUP_DATA_CALL:
            requestSetupDataCall(data, datalen, t);
            break;
        case RIL_REQUEST_DEACTIVATE_DATA_CALL:
            requestDeactivateDataCall(t);
            break;
        case RIL_REQUEST_SMS_ACKNOWLEDGE:
            requestSMSAcknowledge(data, datalen, t);
            break;

        case RIL_REQUEST_GET_IMSI:
            p_response = NULL;
            err = at_send_command_numeric("AT+CIMI", &p_response);

            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS,
                    p_response->p_intermediates->line, sizeof(char *));
            }
            at_response_free(p_response);
            break;

        case RIL_REQUEST_GET_IMEI:
            p_response = NULL;
            err = at_send_command_numeric("AT+CGSN", &p_response);

            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS,
                    p_response->p_intermediates->line, sizeof(char *));
            }
            at_response_free(p_response);
            break;

        case RIL_REQUEST_SIM_IO:
            requestSIM_IO(data,datalen,t);
            break;

        case RIL_REQUEST_SEND_USSD:
            requestSendUSSD(data, datalen, t);
            break;

        case RIL_REQUEST_CANCEL_USSD:
            if (getSIMStatus() == SIM_ABSENT) {
                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
                return;
            }
            p_response = NULL;
            err = at_send_command_numeric("AT+CUSD=2", &p_response);

            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS,
                    p_response->p_intermediates->line, sizeof(char *));
            }
            at_response_free(p_response);
            break;

        case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
            if (getSIMStatus() == SIM_ABSENT) {
                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
            } else {
                at_send_command("AT+COPS=0", NULL);
            }
            break;

        case RIL_REQUEST_DATA_CALL_LIST:
            requestDataCallList(data, datalen, t);
            break;

        case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
            requestQueryNetworkSelectionMode(data, datalen, t);
            break;

        case RIL_REQUEST_OEM_HOOK_RAW:
            // echo back data
            RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
            break;


        case RIL_REQUEST_OEM_HOOK_STRINGS: {
            int i;
            const char ** cur;

            RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);


            for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
                    i > 0 ; cur++, i --) {
                RLOGD("> '%s'", *cur);
            }

            // echo back strings
            RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
            break;
        }

        case RIL_REQUEST_WRITE_SMS_TO_SIM:
            requestWriteSmsToSim(data, datalen, t);
            break;

        case RIL_REQUEST_DELETE_SMS_ON_SIM: {
            char * cmd;
            p_response = NULL;
            asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
            err = at_send_command(cmd, &p_response);
            free(cmd);
            if (err < 0 || p_response->success == 0) {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            }
            at_response_free(p_response);
            break;
        }

        case RIL_REQUEST_ENTER_SIM_PIN:
        case RIL_REQUEST_ENTER_SIM_PUK:
        case RIL_REQUEST_ENTER_SIM_PIN2:
        case RIL_REQUEST_ENTER_SIM_PUK2:
        case RIL_REQUEST_CHANGE_SIM_PIN:
        case RIL_REQUEST_CHANGE_SIM_PIN2:
            requestEnterSimPin(data, datalen, t);
            break;

        case RIL_REQUEST_IMS_REGISTRATION_STATE: {
            int reply[2];
            //0==unregistered, 1==registered
            reply[0] = s_ims_registered;

            //to be used when changed to include service supporated info
            //reply[1] = s_ims_services;

            // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
            reply[1] = s_ims_format;

            RLOGD("IMS_REGISTRATION=%d, format=%d ",
                    reply[0], reply[1]);
            if (reply[1] != -1) {
                RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
            } else {
                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
            }
            break;
        }

        case RIL_REQUEST_VOICE_RADIO_TECH:
            {
                int tech = techFromModemType(TECH(sMdmInfo));
                if (tech < 0 )
                    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
                else
                    RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
            }
            break;
        case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
            requestSetPreferredNetworkType(request, data, datalen, t);
            break;

        case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
            requestGetPreferredNetworkType(request, data, datalen, t);
            break;

        case RIL_REQUEST_GET_CELL_INFO_LIST:
            requestGetCellInfoList(data, datalen, t);
            break;

        case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
            requestSetCellInfoListRate(data, datalen, t);
            break;

        case RIL_REQUEST_GET_HARDWARE_CONFIG:
            requestGetHardwareConfig(data, datalen, t);
            break;

        case RIL_REQUEST_SHUTDOWN:
            requestShutdown(t);
            break;

        case RIL_REQUEST_QUERY_TTY_MODE:
            requestGetTtyMode(data, datalen, t);
            break;

        case RIL_REQUEST_GET_RADIO_CAPABILITY:
            requestGetRadioCapability(data, datalen, t);
            break;

        case RIL_REQUEST_GET_MUTE:
            requestGetMute(data, datalen, t);
            break;

        case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
        case RIL_REQUEST_ALLOW_DATA:
        case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
        case RIL_REQUEST_SET_CLIR:
        case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
        case RIL_REQUEST_SET_BAND_MODE:
        case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
        case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
        case RIL_REQUEST_SET_LOCATION_UPDATES:
        case RIL_REQUEST_SET_TTY_MODE:
        case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            break;

        case RIL_REQUEST_BASEBAND_VERSION:
            requestCdmaBaseBandVersion(request, data, datalen, t);
            break;

        case RIL_REQUEST_DEVICE_IDENTITY:
            requestDeviceIdentity(request, data, datalen, t);
            break;

        case RIL_REQUEST_CDMA_SUBSCRIPTION:
            requestCdmaSubscription(request, data, datalen, t);
            break;

        case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
            requestCdmaGetSubscriptionSource(request, data, datalen, t);
            break;

        case RIL_REQUEST_START_LCE:
        case RIL_REQUEST_STOP_LCE:
        case RIL_REQUEST_PULL_LCEDATA:
            if (getSIMStatus() == SIM_ABSENT) {
                RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
            } else {
                RIL_onRequestComplete(t, RIL_E_LCE_NOT_SUPPORTED, NULL, 0);
            }
            break;

        case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
                requestCdmaGetRoamingPreference(request, data, datalen, t);
            } else {
                RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
            }
            break;

        case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
                requestCdmaSetSubscriptionSource(request, data, datalen, t);
            } else {
                // VTS tests expect us to silently do nothing
                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            }
            break;

        case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
                requestCdmaSetRoamingPreference(request, data, datalen, t);
            } else {
                // VTS tests expect us to silently do nothing
                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            }
            break;

        case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
                requestExitEmergencyMode(data, datalen, t);
            } else {
                // VTS tests expect us to silently do nothing
                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
            }
            break;

        default:
            RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
            RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
            break;
    }
}

对每一个RIL_REQUEST_XXX请求转化成相应的ATcommand,发送给modem,然后睡眠等待,当收到ATcommand的最终响应后,线程被唤醒,将响应传给客户端进程。

2.currentState

static RIL_RadioState currentState(){
    return sState;
}

3.onSupports

static int onSupports (int requestCode __unused){
    //@@@ todo

    return 1;
}

4.onCancel

static void onCancel (RIL_Token t __unused){
    //@@@todo

}

5.getVersion

static const char * getVersion(void){
    return "android reference-ril 1.0";
}

 

注册RIL_Env接口

Android RILD 处理流程_第12张图片

        由于各手机厂商的AT指令差异,因此与modem交互层需要各手机厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现。
 

RIL_Init的主要任务:

1. 向librefrence.so注册libril.so提供的接口RIL_Env;

2. 创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;

3. 当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;

4. 创建一个readLoop工作线程,用于从AT串口中读取数据;

5.返回librefrence.so提供的接口RIL_RadioFunctions;

hardware\ril\reference-ril\reference-ril.c

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
    int ret;
    int fd = -1;
    int opt;
    pthread_attr_t attr;

    s_rilenv = env;//将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv

    while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
        switch (opt) {
            case 'p':
                s_port = atoi(optarg);
                if (s_port == 0) {
                    usage(argv[0]);
                    return NULL;
                }
                RLOGI("Opening loopback port %d\n", s_port);
            break;

            case 'd':
                s_device_path = optarg;
                RLOGI("Opening tty device %s\n", s_device_path);
            break;

            case 's':
                s_device_path   = optarg;
                s_device_socket = 1;
                RLOGI("Opening socket %s\n", s_device_path);
            break;

            case 'c':
                RLOGI("Client id received %s\n", optarg);
            break;

            default:
                usage(argv[0]);
                return NULL;
        }
    }

    if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
        usage(argv[0]);
        return NULL;
    }

    sMdmInfo = calloc(1, sizeof(ModemInfo));
    if (!sMdmInfo) {
        RLOGE("Unable to alloc memory for ModemInfo");
        return NULL;
    }
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    //创建一个mainLoop线程  
    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
    //将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks  
    return &s_callbacks;
}

 

mainLoop工作线程是用来初始化并监控AT模块的,一旦AT模块被关闭,就自动打开。

static void * mainLoop(void *param __unused){
    int fd;
    int ret;

    AT_DUMP("== ", "entering mainLoop()", -1 );
    //为AT模块设置回调函数
    at_set_on_reader_closed(onATReaderClosed);
    at_set_on_timeout(onATTimeout);

    for (;;) {
        fd = -1;
        while  (fd < 0) {//获得串口AT模块的设备文件描述符
            if (isInEmulator()) {
                fd = qemu_pipe_open("pipe:qemud:gsm");
            } else if (s_port > 0) {
                fd = socket_network_client("localhost", s_port, SOCK_STREAM);
            } else if (s_device_socket) {
                fd = socket_local_client(s_device_path,
                                         ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
                                         SOCK_STREAM);
            } else if (s_device_path != NULL) {
                fd = open (s_device_path, O_RDWR);
                if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
                    /* disable echo on serial ports */
                    struct termios  ios;
                    tcgetattr( fd, &ios );
                    ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
                    tcsetattr( fd, TCSANOW, &ios );
                }
            }

            if (fd < 0) {
                perror ("opening AT interface. retrying...");
                sleep(10);
                /* never returns */
            }
        }

        s_closed = 0;
        //打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄
        ret = at_open(fd, onUnsolicited);

        if (ret < 0) {
            RLOGE ("AT error %d on at_open\n", ret);
            return 0;
        }
        //向Rild提交超时任务
        RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);

        // Give initializeCallback a chance to dispatched, since
        // we don't presently have a cancellation mechanism
        sleep(1);
        //如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞  
        waitForClose();
        RLOGI("Re-opening after close");
    }
}

1.打开AT模块

通过at_open打开文件描述符为fd的AT串口设备,并注册回调函数ATUnsolHandler 
 

int at_open(int fd, ATUnsolHandler h){
    int ret;
    pthread_t tid;
    pthread_attr_t attr;

    s_fd = fd;
    s_unsolHandler = h;
    s_readerClosed = 0;

    s_responsePrefix = NULL;
    s_smsPDU = NULL;
    sp_response = NULL;

    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    //创建readerLoop工作线程,该线程用于从串口读取数据  
    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);

    if (ret < 0) {
        perror ("pthread_create");
        return -1;
    }
    return 0;
}

2.添加定时事件RIL_requestTimedCallback

//向Rild提交超时任务
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);

向定时事件队列中添加一个定时事件,该事件的处理函数为initializeCallback,用于发送一些AT指令来初始化BP的modem。

3.readLoop工作线程

Read loop 解析从Modem 发过来的回应。如果遇到URC 则通过handleUnsolicited 上报的RIL_JAVA。如果是命令的应答,则通过handleFinalResponse 通知send_at_command 有应答结果。
 

Android RILD 处理流程_第13张图片

 

static void *readerLoop(void *arg __unused){
    for (;;) {
        const char * line;

        line = readline();

        if (line == NULL) {
            break;
        }

        if(isSMSUnsolicited(line)) {//判断是否是SMS 通知
            char *line1;
            const char *line2;

            // The scope of string returned by 'readline()' is valid only
            // till next call to 'readline()' hence making a copy of line
            // before calling readline again.
            line1 = strdup(line);
            line2 = readline();

            if (line2 == NULL) {
                free(line1);
                break;
            }

            if (s_unsolHandler != NULL) {
                s_unsolHandler (line1, line2);//回调通知SMS
            }
            free(line1);
        } else {
            processLine(line);//处理接收到的数据,根据line中的指令调用不同的回调函数  
        }
    }

    onReaderClosed();

    return NULL;
}

注册RIL_RadioFunctions接口

hardware\ril\libril\ril.cpp

extern "C" void RIL_register(const RIL_RadioFunctions *callbacks) {
    RLOGI("SIM_COUNT: %d", SIM_COUNT);
    //版本验证
    if (callbacks == NULL) {
        RLOGE("RIL_register: RIL_RadioFunctions * null");
        return;
    }
    if (callbacks->version < RIL_VERSION_MIN) {
        RLOGE("RIL_register: version %d is to old, min version is %d",
             callbacks->version, RIL_VERSION_MIN);
        return;
    }

    RLOGE("RIL_register: RIL version %d", callbacks->version);

    if (s_registerCalled > 0) {
        RLOGE("RIL_register has been called more than once. "
                "Subsequent call ignored");
        return;
    }
    //将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中
    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));

    s_registerCalled = 1;

    RLOGI("s_registerCalled flag set, %d", s_started);
    // Little self-check

    for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
        assert(i == s_commands[i].requestNumber);//序号验证
    }

    for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
        assert(i + RIL_UNSOL_RESPONSE_BASE
                == s_unsolResponses[i].requestNumber);
    }

    radio::registerService(&s_callbacks, s_commands);
    RLOGI("RILHIDL called registerService");
}

打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback函数,创建单独线程监视并处理所有事件源。

1.客户端连接处理

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Android RILD 处理流程)