Android中,RILD是RIL(Radio Interface Layer) Deamon的簡稱。簡單的說它下面承接GSM/GPRS Modem(電話通信模塊),上面接電話應用相關的Java庫(telephony internal)。telephony internal通過socket將請求發(fā)送給RILD的消息循環(huán),消息循環(huán)則將請求轉(zhuǎn)發(fā)給底層通信模塊(直接調(diào)用底層的庫)來實現(xiàn)對通信模塊功能的調(diào) 用。反之,當通信模塊有類似于來電的消息時,也會通過RILD的回調(diào),將信息包裝成消息,發(fā)送到RILD的消息循環(huán)中去處理,最后再通過socket回送 給telephony internal,以便通知上層。整體結(jié)構(gòu)參見如下:

消息循環(huán)(ril_event_loop()函數(shù)內(nèi))位于單獨的線程中,用來處理三種消息,分別對應三個不同的隊列,面對的是三種不同的需求:
1.定時列表(timer_list): 此隊列中的消息主要用于處理一些延時的操作。比如:從飛信模式切換到通信模式(實際上就是打開通信模塊)時,若SIM卡未準備好,那么需要延續(xù)一段時間再檢查是否準備好,此時就要將消息扔至此隊列。
2.偵聽列表(watch_list): 此隊列中的消息一是作為socket的服務端,用來偵聽客戶端的請求;另一個是作為本進程的其它線程(如:檢查通信模塊來電消息的線程)傳遞過來的消息。
3.掛起列表(pending_list): 之所以叫掛起,實際上指的是在處理上面兩中類型的消息時,并不真正的處理消息體,而是將符合條件的消息丟到本隊列中。由于消息附帶處理函數(shù),所以在處理本隊列的消息時,直接觸發(fā)即可。
消息循環(huán)所要做的事就是先等待某個時間間隔(定時消息要求的)或者是客戶端(socket或通訊模塊的消息)的請求,然后再按次序處理上面三個對列中的消息。
下面還是通過源代碼來分析消息循環(huán)的處理過程。
ril_event指代的是消息,它的數(shù)據(jù)結(jié)構(gòu)如下:
- struct ril_event *next; // 下一個消息
- struct ril_event *prev; // 前一個消息
- int fd; // 開始我以為這里有可能是socket描述符或pipe描述符,但實際上它還被用作消息的回調(diào)函數(shù)的參數(shù)?
- int index; // 偵聽列表(watch_list)中的索引,偵聽列表采用的數(shù)組而不是鏈表
- bool persist; // 是否常駐偵聽列表(watch_list)中。若常駐,則當被轉(zhuǎn)到pending_list中時,不刪除。
- struct timeval timeout; // 超時,這個為一個時間點。在處理定時消息時,用于和當前的時間比較,以確定是否處理該消息。
- ril_event_cb func; // 回調(diào)。此消息對應的處理函數(shù)。
- void *param; // 回調(diào)參數(shù)。
三種消息列表的定義如下:
- static struct ril_event * watch_table[MAX_FD_EVENTS]; // 偵聽列表
- static struct ril_event timer_list; // 定時列表
- static struct ril_event pending_list; // 掛起列表
初始化過程還是要從rild的main入口開始分析起,位于文件hardware/ril/rild/rild.c。簡單期間,只介紹本文相關的部分。 main()函數(shù)會調(diào)用函數(shù)RIL_register(),然后會調(diào)用RIL_startEventLoop()。 RIL_startEventLoop()中會創(chuàng)建線程eventLoop,這個實際上就是rild的消息循環(huán)所在的線程。
- ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
eventLoop()首先會進行初始化:
然后,會通過pipe()函數(shù)創(chuàng)建管道。pipe()函數(shù)會創(chuàng)建一對文件描述符,一個用于讀,另一個用于寫。都被記錄在全局變量中。它實際上是用來發(fā)送定時消息的,后面會介紹。
- ret = pipe(filedes);
- // ......
- s_fdWakeupRead = filedes[0]; // 消息循環(huán)中偵聽
- s_fdWakeupWrite = filedes[1]; // 用于通知消息循環(huán)定義消息已發(fā)送
最后一步就是進入消息循環(huán):
- // Only returns on error
- ril_event_loop();
ril_event_loop()中,每次循環(huán)都主要做三件事:
1.初始化。主要是獲取要等待的描述符,以及獲取超時信息,以便能夠及時處理定時消息。
2.等待。等待socket客戶端有新的消息,或一定的時間間隔,之后處理定時消息。
3.依次處理三種類型的消息。
下面分別敘述之。先是獲取要等待的描述符,這里為什么要這么做呢?我的理解是在添加新的消息時,有可能會修改全局的描述符列表。也就是說,全局的描述符列表有可能在本次循環(huán)的處理過程中發(fā)生變化。
- // make local copy of read fd_set
- memcpy(&rfds, &readFds, sizeof(fd_set));
接下來,就是計算select()函數(shù)的超時參數(shù)。select的最后一個參數(shù)代表超時。若為NULL,則select死等;若為0,則select立即返回;若大于0,則限制了select最長的等待時間。
- if (-1 == calcNextTimeout(&tv)) { // 獲取超時參數(shù),若失敗則返回-1。
- // 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;
- }
calcNextTimeout()函數(shù)先是判斷超時消息的列表是否為空,為空則返回-1;
- // Sorted list, so calc based on first node
- if (tev == &timer_list) {
- // no pending timers
- return -1;
- }