hardware/ril/rild/rild.c
main函數
-----> dlHandle = dlopen(rilLibPath, RTLD_NOW);
-----> RIL_startEventLoop();
-----> rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
-----> funcs = rilInit(&s_rilEnv, argc, rilArgv);
-----> RIL_register(funcs);
該函數主要是載入so文件,然後調用so文件的RIL_Init函數,該函數的作用是使得rild和so文件互相註冊回調函數,它把RIL_Env註冊給so,同時返回RIL_RadioFunctions,使得rild得到一組函數指針,RIL_RadioFunctions和RIL_Env的結構如下:
//so文件交給ril調用的api
typedef struct {
int version; /* set to RIL_VERSION */
RIL_RequestFunc onRequest;
RIL_RadioStateRequest onStateRequest;
RIL_Supports supports;
RIL_Cancel onCancel;
RIL_GetVersion getVersion;
} RIL_RadioFunctions;
//ril交給so文件調用的callback函數,用於通知某個事件
struct RIL_Env {
void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
void *response, size_t responselen);
void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,
size_t datalen);
void (*RequestTimedCallback) (RIL_TimedCallback callback,
void *param, const struct timeval *relativeTime);
};
static struct RIL_Env s_rilEnv = {
RIL_onRequestComplete,
RIL_onUnsolicitedResponse,
RIL_requestTimedCallback
};
RIL_startEventLoop函數
hardware/ril/libril/ril.cpp
RIL_startEventLoop(void)該函數啓動eventLoop進程
--->eventLoop(void *param)
-----> ril_event_init();
-----> ret = pipe(filedes);
-----> s_fdWakeupRead = filedes[0];
s_fdWakeupWrite = filedes[1];
----->ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL);
rilEventAddWakeup (&s_wakeupfd_event);
-------->void ril_event_add(struct ril_event * ev) //add event to watch_table and rfds read set
-------->static void triggerEvLoop()
----------->void ril_event_loop()
for (;;) {
----->calcNextTimeout//獲取timer_list第一個節點的timeout減去當前時間的差值作爲select的timeout時間
-----> n = select(nfds, &rfds, NULL, NULL, ptv);//等待讀事件或者超時
----->processTimeouts//把timer_list中的超時節點取出來放到pending_list中
----->processReadReadies//把watch_table中所有讀事件置位的節點取出來放到pending_list中
----->firePending//觸發pending_list中的事件
}
首先要說明的是ril_event結構,它的定義如下,該結構定義了rild的基本事件,其中fd表示一個讀事件,timeout表示一個超時時間,在觸發讀事件或者超時到期後,將會調用func回調函數,這就是ril_event_loop循環所做的事情。
struct ril_event {
struct ril_event *next;
struct ril_event *prev;
int fd;
int index;
bool persist;
struct timeval timeout;
ril_event_cb func;
void *param;
};
ril_event_init
對幾個重要的結構進行了初始化,readFds讀事件FD_SET,timer_list超時列表,pending_list是一個臨時列表,watch_table是所有ril_event的列表
void ril_event_init()
{
MUTEX_INIT();
FD_ZERO(&readFds);
init_list(&timer_list);
init_list(&pending_list);
memset(watch_table, 0, sizeof(watch_table));
}
RIL_register (const RIL_RadioFunctions *callbacks)
-----> s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);設備路徑是//dev/socket/rild,屬性名是ANDROID_SOCKET_rild
ret = listen(s_fdListen, 4);
ril_event_set (&s_listen_event, s_fdListen, false,//這個事件在觸發回調函數後,會被刪除,如果需要再次觸發,需要重新加入事件
listenCallback, NULL);
rilEventAddWakeup (&s_listen_event);
//把rild-debug加入到讀事件列表中
s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
ret = listen(s_fdDebug, 4);
ril_event_set (&s_debug_event, s_fdDebug, true,
debugCallback, NULL);
rilEventAddWakeup (&s_debug_event);
該函數主要就是加入監聽事件,用於監聽Phone Process的連接
listenCallback
在發生listen的callback的時候,連接會被加入到讀事件列表中,同時監聽事件會從讀事件列表中刪除,這樣就不會有新的連接進來,在連接退出的時候,監聽事件會被重新加入進來
-----> s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
------> err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);//這裏所做的檢查是隻接受來自PHONE_PROCESS("radio")進程的連接
------> p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
------> ril_event_set (&s_commands_event, s_fdCommand, 1,//這個事件會一直存在於讀事件列表中
processCommandsCallback, p_rs);//
rilEventAddWakeup (&s_commands_event);//把得到的連接加入到read列表中
processCommandsCallback
void processCommandsCallback(int fd, short flags, void *param)
這個fd即是連接對應的fd,s_fdCommand,param即爲listenCallback中生成的p_rs,p_rs的類型是struct RecordStream,它有一段8k的內存用於從fd中讀取數據,數據的格式是長度加內容
for (;;) {
ret = record_stream_get_next(p_rs, &p_record, &recordlen);每次從RecordStream中讀取到的內容稱爲一個record,其格式爲request+參數
processCommandBuffer(p_record, recordlen);
-----> 讀取record中的request和token
p.setData((uint8_t *) buffer, buflen);
status = p.readInt32(&request);
status = p.readInt32 (&token);
//建立RequestInfo,並把它加入到s_pendingRequests鏈表中
pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
pRI->token = token;
pRI->pCI = &(s_commands[request]);//s_commands是一個列表,定義在ril_commands.h中
pRI->p_next = s_pendingRequests;
s_pendingRequests = pRI;
//dispatch函數會根據不同的request類型,在調用s_callbacks.onRequest函數時傳入不同的參數,該函數就是向so文件發送請求.
pRI->pCI->dispatchFunction(p, pRI);
}
我們返回去再去看main函數,在調用RIL_startEventLoop函數啓動了eventLoop線程後,該線程由於沒有事件發生,由select函數導致處於休眠狀態。在調用RIL_register函數之後,加入了監聽事件,在Phone進程連接進來後,eventLoop將處於等待Phone進程的命令狀態,在接收到命令之後,會調用dispatchFunction,向so文件發送請求,在後面的分析中,我們知道,實際上就是發送AT命令,也就是說發送AT命令是運行在eventLoop線程上的。
綜上所述,Phone進程和Rild進程通過socket進行通信,它們之間的數據被稱爲RecordStream,rild和so互相註冊回調函 數,rild調用so的RIL_RadioFunctions函數來發送請求,so通過RIL_Env中的函數指針通知rild,請求的響應 (solicit),或者異步事件的發生(unsolicit)。
-----> s_rilenv = env;//保存rild的env
-----> s_dev_path = optarg;//在模擬器上so使用ttyS0,即串口與模塊通信
-----> ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);//啓動一個線程
mainLoop
for (;;) {
fd = open (s_device_path, O_RDWR);//打開s_device_path設備,即ttyS0設備
s_closed = 0
ret = at_open(fd, onUnsolicited);//onUnsolicited會在readerLoop線程中調用
-----> s_fd = fd;
-----> s_unsolHandler = h;
-----> ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);//啓動一個新的線程
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);//在rild的eventLoop線程中,執行initializeCallback
sleep(1);
waitForClose();//等待s_state_cond條件,該函數一旦退出,那將導致重新初始化
-----> while (s_closed == 0) {
pthread_cond_wait(&s_state_cond, &s_state_mutex);
}
}
#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)
RIL_onRequestComplete
用於在rild發送的請求有響應的時候,回調該函數通知rild
RIL_onUnsolicitedResponse
用於底層有異步事件發生的時候,回調該函數通知rild
RIL_requestTimedCallback
用於請求eventLoop執行一個超時回調
這三個函數指針都是rild註冊給so的,他們分別對應ril.cpp中的
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen)
該函數會調用sendResponse函數,這個函數會把response通過socket,以Record的格式發送給Phone Process,該函數運行在eventLoop線程上,特別主要,該函數調用了checkAndDequeueRequestInfo函數,該函數將會檢查請求是否在pending隊列中,如果在的話,則將其刪除,因爲已經收到該請求的響應了。
void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
size_t datalen)
該函數會調用sendResponse函數,這個函數會把response通過socket,以Record的格式發送給Phone Process,該函數運行在eventLoop線程上
RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime)
該函數會在eventLoop中加入一個超時事件
在mainLoop中就調用了RIL_requestTimedCallback函數,它將會導致initializeCallback函數被調用
initializeCallback
static void initializeCallback(void *param)
at_handshake();
-----> err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT,NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
-----> err = writeline (command);
-----> err = pthread_cond_wait(&s_commandcond, &s_commandmutex);//等待s_commandcond條件,在readerLoop線程中讀到OK響應的時候,該條件會置位
at_send_command
-----> err = at_send_command_full_nolock(command, type,
responsePrefix, smspdu,
timeoutMsec, pp_outResponse);
。。。
該函數會調用一系列的at_send_command,發送一系列的AT command
readerLoop
mainLoop中啓動了新的線程,該線程是讀取at command的response
static void *readerLoop(void *arg)
{
for (;;) {
line = readline();
if(isSMSUnsolicited(line)) {
line1 = strdup(line);
line2 = readline();
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2);
}
} else {
processLine(line);
}
}
onReaderClosed();
return NULL;
}
至此,我們對整個AT command的發送和接收,就比較清楚了,rild的eventLoop調用RIL_RadioFunctions.onRequest發送請求,該函數實際上是so中的onRequest函數,它最終調用了at_send_command_full_nolock函數發送AT command,並進入休眠狀態,等待響應。另外一個讀線程readerLoop不斷讀取底層通過ttyS0發來的數據,在確認收到響應後,將喚醒eventLoop線程,繼續後面的請求。
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);
s_type = type;
s_responsePrefix = responsePrefix;
s_smsPDU = smspdu;
sp_response = at_response_new();
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 /*USE_NP*/
} else {
err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
}
if (err == ETIMEDOUT) {
err = AT_ERROR_TIMEOUT;
goto error;
}
}
if (pp_outResponse == NULL) {
at_response_free(sp_response);
} else {
/* line reader stores intermediate responses in reverse order */
reverseIntermediates(sp_response);
*pp_outResponse = sp_response;
}
sp_response = NULL;
if(s_readerClosed > 0) {
err = AT_ERROR_CHANNEL_CLOSED;
goto error;
}
err = 0;
error:
clearPendingCommand();
return err;
}
該函數是一個阻塞函數,它運行在rild的eventLoop線程中,它指定了條件等待的超時時間,在正常情況下,如果在等待時間內,條件滿足,也就是讀 線程讀到了響應,那麼at命令發送成功。如果等待超時,則要進行超時處理,即clearPendingCommand(),在mainLoop中調用了 at_set_on_timeout(onATTimeout),clearPendingCommand會調用該函數
static void onATTimeout()
{
LOGI("AT channel timeout; closing\n");
at_close();//該函數將導致readerLoop線程退出
s_closed = 1;
/* FIXME cause a radio reset here */
setRadioState (RADIO_STATE_UNAVAILABLE);//s_closed和s_state_cond置位將導致mainLoop中的WaitForClose函數退出,繼而導致重新初始化reader線程
}
void at_close()
{
if (s_fd >= 0) {
close(s_fd);
}
s_fd = -1;
pthread_mutex_lock(&s_commandmutex);
s_readerClosed = 1;
pthread_cond_signal(&s_commandcond);
pthread_mutex_unlock(&s_commandmutex);
/* the reader thread should eventually die */
}
在mainLoop中的at_set_on_reader_closed函數,也是爲了防止ttyS0讀取失敗,意外發生,此時也會導致讀線程重新初始化
at_set_on_reader_closed(onATReaderClosed)
static void onATReaderClosed()
{
LOGI("AT channel closed\n");
at_close();
s_closed = 1;
setRadioState (RADIO_STATE_UNAVAILABLE);
}