深入理解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;
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值