深入理解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;
}