1. 程式人生 > >深入理解Android Telephony 之RILD機制分析

深入理解Android Telephony 之RILD機制分析

RILD負責modem和RILJ端的通訊,資訊分兩種:unsolicited和solicited,前者是由modem主動上報的,諸如時區更新、通話狀態、網路狀態等訊息,後者是RILJ端發請求並需要modem反饋的資訊。RILJ與RILD之間的通訊由主執行緒s_tid_dispatch負責監聽,讀取和分發,RILD與modem之間的通訊由s_tid_mainloop和s_tid_reader負責寫入和讀取。
先看看目錄,以android 7.0為例,RILD目錄位於../hardware/ril,包括:
include —- 各種標頭檔案定義,其中include/telephony/ril.h定義了135個RIL_REQUEST_XXX和45個RIL_UNSOL_XXX的巨集定義,前者用於RILD向modem傳送的請求訊息id,後者用於由modem直接推送給RILD的訊息id。
libril—-主要定義訊息分發主執行緒和RILJ與RILD之間的socket監聽
librilutils—-輔助類
reference-ril—-顧名思義,這個目錄中的類有參考作用,因為整個RILD架構中,RILD與modem之間設計以庫的形式載入,這個在RILD在初始化時能看到,這樣就方便廠商定製
rild—-RILD的入口

深入理解Android Telephony之RILD的啟動 一文中看到,RILD通過rc載入,系統啟動RILD的入口就到了rild.c中的main()函式,main主要做了三件事:
1、開啟ril外部庫,即廠商定製庫;
2、啟動事件分發主執行緒;
3、呼叫廠商庫中的介面進行初始化:使用RIL_Init初始化RILD與modem的通訊執行緒,使用RIL_register註冊RILD與RILJ之間的socket,啟動通訊執行緒。

int main(int argc, char **argv) {
......
//開啟libreference-ril.so
dlHandle = dlopen(rilLibPath, RTLD_NOW);
//建立主執行緒s_tid_dispatch,用來監聽RILJ下發到socket的訊息並分發。監聽的原理是每個socket都註冊上監聽事件,然後把事件塞到s_tid_dispatch,一旦socket中有訊息,s_tid_dispatch讀到之後就觸發事件的回撥
RIL_startEventLoop(); //載入動態庫,地址傳給rilInit rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **)) dlsym(dlHandle, "RIL_Init"); ... rilUimInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **)) dlsym(dlHandle, "RIL_SAP_Init"
); //使用rilInit 初始化RIL,s_rilEnv是個靜態回撥陣列 funcs = rilInit(&s_rilEnv, argc, rilArgv); // RIL_register(funcs); }

看看主執行緒s_tid_dispatch,事件迴圈eventLoop–>ril_event_loop, watch_table,timer_list,pending_list三者為訊息佇列。

static struct ril_event * watch_table[MAX_FD_EVENTS];
static struct ril_event timer_list;
static struct ril_event pending_list;

RIL_startEventLoop(void) {
    //標誌s_tid_dispatch執行緒是否建立成功並啟動
    s_started = 0;
   //建立執行緒,eventLoop是執行緒建立後的回撥函式,其中會把s_started置為1
    int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
    //如果執行緒尚未建立成功,進入死迴圈等待
    while (s_started == 0) {
        pthread_cond_wait(&s_startupCond, &s_startupMutex);
    }
......
}

static void *
eventLoop(void *param) {
//s_tid_dispatch執行緒建立成功
    s_started = 1;
......
//定義匿名管道
    ret = pipe(filedes);
......
    s_fdWakeupRead = filedes[0];
    s_fdWakeupWrite = filedes[1];
    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
                processWakeupCallback, NULL);

    rilEventAddWakeup (&s_wakeupfd_event);
    ril_event_loop();
......
}

一、看看RILD是如何通過socket讀取RILJ下發的訊息
以s_wakeupfd_event為例:
1、首先封裝一個事件,使用ril_event_set

void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)
{
    memset(ev, 0, sizeof(struct ril_event));
    ev->fd = fd;
    ev->index = -1;
    ev->persist = persist;
    ev->func = func;
    ev->param = param;
    fcntl(fd, F_SETFL, O_NONBLOCK);
}

2、把事件新增到訊息佇列中,使用rilEventAddWakeup,其中分兩小步

static void rilEventAddWakeup(struct ril_event *ev) {
    ril_event_add(ev);
    triggerEvLoop();
}

第一步ril_event_add把事件加到訊息佇列,第二步使用triggerEvLoop觸發事件迴圈

void ril_event_add(struct ril_event * ev)
{
    MUTEX_ACQUIRE();
    for (int i = 0; i < MAX_FD_EVENTS; i++) {
        if (watch_table[i] == NULL) {
            watch_table[i] = ev;
            ev->index = i;
            dump_event(ev);
            FD_SET(ev->fd, &readFds);
            if (ev->fd >= nfds) nfds = ev->fd+1;
            break;
        }
    }
    MUTEX_RELEASE();
}

ril_event_add就是把事件新增到watch_table中,最大可接納8個事件,然後把事件檔案描述符新增到readFds檔案描述符集合中,nfds是當前readFds中的檔案描述符總數。
triggerEvLoop就是往管道中寫入空字元,來喚醒執行緒s_tid_dispatch,噹噹前執行緒不是s_tid_dispatch時,就需要喚醒s_tid_dispatch。

static void triggerEvLoop() {
    int ret;
    if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
         do {
            ret = write (s_fdWakeupWrite, " ", 1);
         } while (ret < 0 && errno == EINTR);
    }
}

3、s_tid_dispatch被喚醒,迴圈體ril_event_loop肯定的執行了

void ril_event_loop()
{
    for (;;) {
        //把readFds檔案描述符集合拷貝到本地rfds中
        memcpy(&rfds, &readFds, sizeof(fd_set));
        //看看timer_list中有沒有定時事件,如果沒有,ptv 賦值為空,傳到select中,那麼select將處於阻塞狀態
        if (-1 == calcNextTimeout(&tv)) {
            ptv = NULL;
        } else {
           //如果timer_list中有定時事件,那麼select將處於定時阻塞狀態,時間到了,不管檔案描述符集合rfds中是否有檔案可讀,select都要返回
            ptv = &tv;
        }
//關於select的介紹可以參考http://www.cnblogs.com/moonvan/archive/2012/05/26/2518881.html
        n = select(nfds, &rfds, NULL, NULL, ptv);
......
//如果select處於非阻塞狀態了,則繼續往下走,那如果select一直處於阻塞狀態呢?看這裡是必須有定時事件,是否有可能一直沒有定時事件,這樣timer_list為空,而watch_table中的事件一直就處理不了?
//把定時事件從timer_list放到pending_list
    processTimeouts();
    //如過n大於0,表示rfds中有檔案讀狀態發生改變了(通過FD_ISSET來識別),則把watch_table中的事件放到pending_list
    processReadReadies(&rfds, n);
        //timer_list和watch_table中的事件都放到pending_list之後,遍歷pending_list中的事件並呼叫其回撥。rilEventAddWakeup事件則是回撥processWakeupCallback函式
        firePending();
    }
}

static void firePending()
{
    struct ril_event * ev = pending_list.next;
    while (ev != &pending_list) {
        struct ril_event * next = ev->next;
        removeFromList(ev);
//回撥事件處理方法
        ev->func(ev->fd, 0, ev->param);
        ev = next;
    }
}

接著看RIL_Init,主執行緒建立好之後,從庫中動態載入RIL_Init函式,地址賦給rilInit。看看大體流程:

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
//回撥方法陣列
    s_rilenv = env;
......
//建立s_tid_mainloop執行緒,執行緒迴圈體為mainLoop
    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
    return &s_callbacks;
}

static void *
mainLoop(void *param __unused)
{
......
    for (;;) {
        fd = -1;
        while  (fd < 0) {
            ......
        s_closed = 0;
//fd是讀寫檔案描述符,如果讀取到unsolicited型別命令,則回撥onUnsolicited,後面再看at_open具體做什麼
        ret = at_open(fd, onUnsolicited);
        RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
...
    }
}

RIL_Init的第一個引數是指向RIL_Env 的指標,實參是定義在rild.c中的s_rilEnv。

struct RIL_Env {
//solicited型別命令請求完成的回撥函式指標
    void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
                           void *response, size_t responselen);
//unsolicited型別命令應答函式指標
#if defined(ANDROID_MULTI_SIM)
    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id);
#else
    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen);
#endif
//計時請求的超時回撥函式指標
    void (*RequestTimedCallback) (RIL_TimedCallback callback,
                                   void *param, const struct timeval *relativeTime);
};

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

引數傳入後,直接賦給reference-ril.c的靜態變數s_rilenv ,只在下面的巨集定義中使用到s_rilenv 。

#ifdef RIL_SHLIB
static const struct RIL_Env *s_rilenv;
#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
#endif

RIL_Init返回一個RIL_RadioFunctions型別結構體地址&s_callbacks

static const RIL_RadioFunctions s_callbacks = {
    RIL_VERSION,
    onRequest,
    currentState,
    onSupports,
    onCancel,
    getVersion
};
typedef struct {
    int version;       //RIL的版本號
    RIL_RequestFunc onRequest; //請求的函式指標
    RIL_RadioStateRequest onStateRequest;  //請求當前的radio狀態
    RIL_Supports supports; //判斷是否支援當前的請求
    RIL_Cancel onCancel; //取消當前請求
    RIL_GetVersion getVersion; //獲取當前RIL版本號
} RIL_RadioFunctions;

RIL_Init的返回值作為引數傳入RIL_register 中,然後拷貝到變數s_callbacks,s_callbacks主要在下面的巨集定義用到。

#if defined(ANDROID_MULTI_SIM)
#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c), (d))
#define CALL_ONREQUEST(a, b, c, d, e) s_callbacks.onRequest((a), (b), (c), (d), (e))
#define CALL_ONSTATEREQUEST(a) s_callbacks.onStateRequest(a)
#else
#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c))
#define CALL_ONREQUEST(a, b, c, d, e) s_callbacks.onRequest((a), (b), (c), (d))
#define CALL_ONSTATEREQUEST(a) s_callbacks.onStateRequest()
#endif

RIL_register 是在RILJ和RILD之間定義socket,支援幾張卡,就定義幾個socket,最多四個。每個socket有個事件監聽器fdListen,監聽事件丟入到s_tid_dispatch執行緒中,事件的回撥是listenCallback。一旦RILJ通過socket寫入一個命令,s_tid_dispatch執行緒的迴圈處理ril_event_loop會呼叫註冊的回撥方法listenCallback對命令進行預處理,並把預處理結果又寫入到s_tid_dispatch中,同時註冊回撥為processCommandsCallback, ril_event_loop又執行回撥processCommandsCallback,processCommandsCallback中呼叫processCommandBuffer,而processCommandsCallback中最終呼叫dispatchFunction。

extern "C" void
RIL_register (const RIL_RadioFunctions *callbacks) {
......
    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
  //這裡支援幾張卡就定義幾個socket param,並註冊監聽
    s_ril_param_socket = {
                        RIL_SOCKET_1,             /* socket_id */
                        -1,                       /* fdListen */
                        -1,                       /* fdCommand */
                        PHONE_PROCESS,            /* processName */
                        &s_commands_event,        /* commands_event */
                        &s_listen_event,          /* listen_event */
                        processCommandsCallback,  /* processCommandsCallback */
                        NULL                      /* p_rs */
                        };

    startListen(RIL_SOCKET_1, &s_ril_param_socket);
//類似地可定義RIL_SOCKET_2、RIL_SOCKET_3、RIL_SOCKET_4的引數並註冊監聽
......
}

static void startListen(RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) {
  ......
//在主執行緒中新增event,一旦RILJ通過socket寫入事件,回撥listenCallback
    ril_event_set (socket_listen_p->listen_event, fdListen, false,
                listenCallback, socket_listen_p);
    rilEventAddWakeup (socket_listen_p->listen_event);
}

瞭解了s_tid_dispatch執行緒的原理,這裡可以直接看回調了。

static void listenCallback (int fd, short flags, void *param) {
...
    SocketListenParam *p_info = (SocketListenParam *)param;
    if(RIL_SAP_SOCKET == p_info->type) {
        listenParam = (MySocketListenParam *)param;
        sapSocket = listenParam->socket;
    }
......
    if(NULL == sapSocket) {
        processName = PHONE_PROCESS;
    } else {
        processName = BLUETOOTH_PROCESS;
    }
//從相應的socket讀取命令
    fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);
......
    err = getsockopt(fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
//如果不是radio socket,也不是bluetooth radio,則不處理命令
    if (!is_phone_socket) {
        RLOGE("RILD must accept socket from %s", processName);
        close(fdCommand);
......
        return;
    }
    ret = fcntl(fdCommand, F_SETFL, O_NONBLOCK);

    if(NULL == sapSocket) {
        p_info->fdCommand = fdCommand;
        p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
        p_info->p_rs = p_rs;
//獲取到socket中的資訊之後,再把具體的命令事件add到s_tid_dispatch執行緒中處理,回撥processCommandsCallback
        ril_event_set (p_info->commands_event, p_info->fdCommand, 1,
        p_info->processCommandsCallback, p_info);
        rilEventAddWakeup (p_info->commands_event);
//RIL_onUnsolicitedResponse傳送ril connected和radio state changed等,推送ril connected訊息會把ril的版本號帶給RILJ,也就是說,每次讀到socket中有資訊從RILJ到RILD,則應答RIL_UNSOL_RIL_CONNECTED和RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED資訊給RILJ,如果時區資料有更新,也推送上去
        onNewCommandConnect(p_info->socket_id);
    } else {
......
    }
}

static void onNewCommandConnect(RIL_SOCKET_ID socket_id) {
    int rilVer = s_callbacks.version;
    RIL_UNSOL_RESPONSE(RIL_UNSOL_RIL_CONNECTED,
                                    &rilVer, sizeof(rilVer), socket_id);
    RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
                                    NULL, 0, socket_id);
    if (s_lastNITZTimeData != NULL) {
        sendResponseRaw(s_lastNITZTimeData, s_lastNITZTimeDataSize, socket_id);

        free(s_lastNITZTimeData);
        s_lastNITZTimeData = NULL;
    }
......
}

接著看p_info->commands_event事件的回撥processCommandsCallback

static void processCommandsCallback(int fd, short flags, void *param) {
    SocketListenParam *p_info = (SocketListenParam *)param;

    for (;;) {
        ret = record_stream_get_next(p_rs, &p_record, &recordlen);
        if (ret == 0 && p_record == NULL) {
            break;
        } else if (ret < 0) {
            break;
        } else if (ret == 0) { /* && p_record != NULL */
//處理命令
            processCommandBuffer(p_record, recordlen, p_info->socket_id);
        }
    }
    if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
//處理完了則關閉對應的檔案,並從watch_event中刪除這個命令的事件
        close(fd);
        p_info->fdCommand = -1;
        ril_event_del(p_info->commands_event);
        record_stream_free(p_rs);
        rilEventAddWakeup(&s_listen_event);
        onCommandsSocketClosed(p_info->socket_id);
    }
    }
}

static int
processCommandBuffer(void *buffer, size_t buflen, RIL_SOCKET_ID socket_id) {
......
//這裡就呼叫ril_commands.h中諸如dispatchVoid的方法。在ril_commands.h中,定義了各種命令的dispatch方法和response方法,那麼哪裡呼叫response方法呢?
    pRI->pCI->dispatchFunction(p, pRI);
    return 0;
}

//以{RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}為例,
static void
dispatchVoid (Parcel& p, RequestInfo *pRI) {
    clearPrintBuf;
    printRequest(pRI->token, pRI->pCI->requestNumber);
    CALL_ONREQUEST(pRI->pCI->requestNumber, NULL, 0, pRI, pRI->socket_id);
}
CALL_ONREQUEST在ril.cpp中定義巨集,實際呼叫s_callbacks中的onRequest
#define CALL_ONREQUEST(a, b, c, d, e) s_callbacks.onRequest((a), (b), (c), (d), (e))
s_callbacks在RIL_register 中由傳入的引數賦值,這個引數值是RIL_Init方法的返回值,實質就是reference-ril.c中的
static const RIL_RadioFunctions s_callbacks = {
    RIL_VERSION,
    onRequest,
    currentState,
    onSupports,
    onCancel,
    getVersion
};

根據RIL_RadioFunctions的定義,s_callbacks.onRequest指向onRequest方法:

static void
onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
    ......
    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;
            }
//呼叫命令response方法,將結果上報給RILJ
            RIL_onRequestComplete(t, result, p_buffer, buffer_size);
            freeCardStatus(p_card_status);
            break;
        }
......
}

二、看看RILD是如何把資料傳給modem的
getCardStatus中呼叫getSIMStatus獲取sim狀態,getSIMStatus中呼叫at_send_command_singleline並傳入具體的AT命令引數和處理結果的返回地址&p_response。

static SIM_Status
getSIMStatus()
{
    ATResponse *p_response = NULL;
......
    err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
}

接著的呼叫流程是:at_send_command_singleline–》at_send_command_full–》at_send_command_full_nolock–》writeline,也就是說,RILD最終通過writeline把資料寫到了管道中,然後就等待管道的資料更新,更新了就把結果傳給p_response

static int at_send_command_full_nolock (const char *command, ATCommandType type,
                    const char *responsePrefix, const char *smspdu,
                    long long timeoutMsec, ATResponse **pp_outResponse)
{
......
    err = writeline (command);
//開闢一個接受modem反饋的資料塊
    sp_response = at_response_new();
//迴圈等待modem把資料寫入到fd中,s_tid_reader執行緒把fd中的資料讀出來之後,寫入到sp_response->finalResponse,併發出條件訊號s_commandcond,s_readerClosed被置為1,迴圈終止
    while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
        if (timeoutMsec != 0) {
#ifdef USE_NP
            err = pthread_cond_timeout_np(&s_commandcond, &s_commandmutex, timeoutMsec);
#else
            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
#endif
        } else {
            err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
        }

        if (err == ETIMEDOUT) {
            err = AT_ERROR_TIMEOUT;
            goto error;
        }
    }
//把讀取到的資料sp_response交給引數pp_outResponse
    if (pp_outResponse == NULL) {
        at_response_free(sp_response);
    } else {
        reverseIntermediates(sp_response);
        *pp_outResponse = sp_response;
    }
......
    return err;
}

static int writeline (const char *s)
{
......
    while (cur < len) {
        do {
//s_fd在at_open時傳入,整個寫操作是在s_tid_mainloop執行緒中進行
            written = write (s_fd, s + cur, len - cur);
        } while (written < 0 && errno == EINTR);
......
    }
//寫入結束符
    do {
        written = write (s_fd, "\r" , 1);
    } while ((written < 0 && errno == EINTR) || (written == 0));

    return 0;
}

三、看看RILD是如何從modem中讀取資料的。
前文的RIL_Init中,定義了執行緒s_tid_mainloop,執行緒的迴圈體mainLoop呼叫at_open(fd, onUnsolicited)開啟通道,在at_open中,又建立s_tid_reader執行緒,執行緒的迴圈體中呼叫readline從s_fd中讀取。

int at_open(int fd, ATUnsolHandler h)
{
//傳入的at命令讀寫通道儲存到s_fd,unsolicited命令的回撥處理儲存到s_unsolHandler
    s_fd = fd;
    s_unsolHandler = h;
    s_readerClosed = 0;
......
//建立s_tid_reader讀取fd的執行緒,建立成功呼叫readerLoop
    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
    return 0;
}

static void *readerLoop(void *arg)
{
    for (;;) {
        const char * line;
        line = readline();
        if(isSMSUnsolicited(line)) {
......
//如果是簡訊,呼叫onUnsolicited
            if (s_unsolHandler != NULL) {
                s_unsolHandler (line1, line2);
            }
        } else {
            processLine(line);
        }
    }
......
    return NULL;
}

static void processLine(const char *line)
{
    pthread_mutex_lock(&s_commandmutex);

    if (sp_response == NULL) {
       //處理unsolicited訊息
        handleUnsolicited(line);
    } else if (isFinalResponseSuccess(line)) {
        sp_response->success = 1;
//處理solicited訊息
        handleFinalResponse(line);
    }
......
}

static void handleFinalResponse(const char *line)
{
//把結果寫入到sp_response->finalResponse,然後發出條件訊號s_commandcond,這個條件是在at_send_command_full_nolock中會使用到
    sp_response->finalResponse = strdup(line);
    pthread_cond_signal(&s_commandcond);
}

static const char *readline()
{
......
        do {
//writeline中,向s_fd寫入資料,readline中讀取資料
            count = read(s_fd, p_read,
                            MAX_AT_RESPONSE - (p_read - s_ATBuffer));
        } while (count < 0 && errno == EINTR);

    return ret;
}

static void onUnsolicited (const char *s, const char *sms_pdu)
{
......
//如果是時區命令
    if (strStartsWith(s, "%CTZV:")) {

        if (err != 0) {
            RLOGE("invalid NITZ line %s\n", s);
        } else {
            RIL_onUnsolicitedResponse (
                RIL_UNSOL_NITZ_TIME_RECEIVED,
                response, strlen(response));
        }
//來電等命令
    } else if (strStartsWith(s,"+CRING:")
                || strStartsWith(s,"RING")
                || strStartsWith(s,"NO CARRIER")
                || strStartsWith(s,"+CCWA")
    ) {
        RIL_onUnsolicitedResponse (
            RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
            NULL, 0);
#ifdef WORKAROUND_FAKE_CGEV
        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
#endif /* WORKAROUND_FAKE_CGEV */
    }else if {
......
}
......
}

RIL_onUnsolicitedResponse是定義在reference-ril.c的巨集,指向s_rilenv->OnUnsolicitedResponse,而s_rilenv是在RIL_Init中初始化的,實質指向rild.c中的s_rilEnv ,這樣RIL_onUnsolicitedResponse最終呼叫RIL_onUnsolicitedResponse。

#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)

四、接著要看看RILD如何把請求結果反饋給RILJ
RILD得到modem的資料後,就回調到了RIL_onRequestComplete

extern "C" void
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
//獲取相應的socket通道
    int fd = s_ril_param_socket.fdCommand;
    size_t errorOffset;
    RIL_SOCKET_ID socket_id = RIL_SOCKET_1;

    pRI = (RequestInfo *)t;
    socket_id = pRI->socket_id;
......
#endif
......
    if (pRI->cancelled == 0) {
     ......
        if (response != NULL) {
            ret = pRI->pCI->responseFunction(p, response, responselen);
......
        }
......
//sendResponse呼叫sendResponseRaw
        sendResponse(p, socket_id);
    }

done:
    free(pRI);
}

static int
sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_ID socket_id) {
//獲取socket 1的檔案描述符
    int fd = s_ril_param_socket.fdCommand;
......
//資料最大8K
    if (dataSize > MAX_COMMAND_BYTES) {
        return -1;
    }
//寫頭,寫資料
    ret = blockingWrite(fd, (void *)&header, sizeof(header));
    ret = blockingWrite(fd, data, dataSize);
}
//最終把資料寫入到相應的socket中
static int
blockingWrite(int fd, const void *buffer, size_t len) {
......
    while (writeOffset < len) {
        ssize_t written;
        do {
//往相應的socket中寫入資料
            written = write (fd, toWrite + writeOffset,
                                len - writeOffset);
        } while (written < 0 && ((errno == EINTR) || (errno == EAGAIN)));
......
    return 0;
}