1.Android RIL概念
Android RIL是基於telephony 服務和raido 硬件層的抽象層。Android的rild庫是介於HAL接口與baseband modem之間,它提供了語音、數據、短信、SIM卡管理以及STK應用的功能。它把標準的 GSM27.007中常用的如dial這些做主動請求的操作稱之爲request,一共75個;另外一類GSM模塊主動上報的例如信號強度、基站信息等, 稱之爲unsolicited response,一共17個。開發模式上,需要針對不同的GSM模塊進行不同的GSM驅動開發,公用的部分google做 好了,特定的部分需要自己去定製。如下是Android RIL架構圖。
2.代碼結構
Android2.2中,RIL的代碼在hardware目錄下,主要包括libril,include,rild,reference-ril,reference-cdma-sms四個目錄,編譯後生成rild應用程序(守護進程,放在target device的/system/bin下),libril.so(RIL動態鏈接庫,放在device的/system/lib目錄下)和libreference-ril.so(RIL參考庫,放在device的/system/lib下)。
3.RIL初始化
1) Init.rc執行rild,並創建兩個socket:/dev/socket/rild和/dev/socket/rild-debug
service ril-daemon /system/bin/rild
socket rild stream 660 root radio
socket rild stream 660 radio system
2) 進入rild.cpp的main函數,讀取rild.lib的path和rild.libargs系統屬性,確定廠商的RIL庫和初始化參數。
3) 執行RIL_startEventLoop開啓事件隊列,進行事件監聽。這個函數會建立s_tid_dispatch線程。
4) 加載廠商的RIL庫,調用RIL_Init初始化RIL,建立s_tid_mainloop線程。在該線程主循環中會調用at_open建立另一個線程s_tid_reader。
5) 調用RIL_register建立vender ril和ril庫之間的聯繫。獲取init.rc中建立的兩個socket(rild,rild-debug),進行偵聽,並加入消息事件循環中(s_tid_dispatch負責輪詢分發)。
4.RIL的事件機制
ril_event.h/cpp對linux常用的select機制進行了簡單封裝,實現多路複用,以及事件到處理函數的映射。通過閱讀rid_event.h的代碼就可以理解這個機制所要提供的功能。
ril_event是個帶有鏈表行爲的結構體,而且是雙向鏈表,它的主要成員是fd(要輪詢的IO,文件,管道,socket等),func(處理事件的回調)。
typedef void (*ril_event_cb)(int fd, short events, void *userdata);
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;
};
提供了六個接口:
// Initialize internal data structs
void ril_event_init();
// Initialize an event
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);
// Add event to watch list
void ril_event_add(struct ril_event * ev);
// Add timer event
void ril_timer_add(struct ril_event * ev, struct timeval * tv);
// Remove event from watch list
void ril_event_del(struct ril_event * ev);
// Event loop
void ril_event_loop();
使用之前調用ril_event_init,增加一個io的時候首先初始化事件ril_event_set,然後加入到列表ril_event_add,輪詢用ril_event_loop,邏輯非常清晰。關鍵是在ril_event_set的時候把fd和回調對應上。timer理論上不屬於io操作,所以沒有所謂的fd,增加timer事件用ril_timer_add,其它的類似,本質上還是事件與回調的對應機制。
至於實現細節,完全可以不關心,有興趣的話就看代碼,很簡單,搞清楚readFDS,watch_list,timer_list,pending_list就差不多了。
從這個機制上看,調用event_loop的線程將執行事件分發的任務。因爲在add,remove操作中有mutex進行保護,所以這個事件機制支持重入。
在rild的初始化中,會執行RIL_startEventLoop,啓動s_tid_dispatch線程來進行事件輪詢,所以其它的地方只要考慮事件的增加和刪除就可以了。
全局搜索ril_event_set,就可以知道在rild上都有什麼事件在跑了。
1) S_listen_event(s_fdListen,listenCallback):名爲rild的socket(init.rc建立的),主要用來監聽上層的(RIL-JAVA)客戶端連接請求,建立socket連接(s_fdCommand),並新增s_commands_event來監聽s_fdCommand。
2) s_commands_event(s_fdCommand,ProcessCommandsCallback):listen的時候建立的socket,用來從客戶端接收StreamRecord(實際上就是Dial,Hang等RIL指令),使用ProcessCommandBuffer處理數據。
3) s_debug_event(s_fdDebug,debugCallback):名爲rild-debug,調試用的request&response通道,用於radiooptions這個調試工具。
4) s_wakeupfd_event(s_fdWakeupRead,processWakeupCallback):無名管道。僅僅爲了開始時wake up這個事件輪詢。
5) timer event
5.RIL的交互流程
RIL的通訊分成兩種:1)Solicited commands:RIL lib發起的主動調用,比如撥號2)Unsolicited responses:從baseband過來的通知消息,比如新短信到來。前者在類似協議上的request-confirm機制,後者類似Indication-response機制。
5.1 Solicited Commands
1) RIL.java是FrameWork中Telephony服務的提供者,是Java中電話系統的起點,在這個文件的RIL class中封裝了RIL所提供的command,實現了CommandsInterface。
getIccCardStatus
supplyIccPin
supplyIccPuk
changeIccPin
changeBarringPassword
getCurrentCalls
getDataCallList
dial
……
2) 以dial爲例,首先調用RILRequest.obtain打包請求,然後再調用RIL::send將消息發送到RILSender的消息隊列中。
3) RILSender是個handler類,會在handleMessage中處理髮送消息請求。它會將消息發送到同“RIL”成功建立的socket中。
4) 如6.4節所述,此時rild和JAVA上層建立的socket爲s_fdCommand。通過事件輪詢機制輪詢到有數據來臨的時候,會調用processCommandsCallback來處理數據。
5) 調用processCommandBuffer。
6) 在ProcessCommandBuffer中,通過ril_commands.h裏面的消息及函數映射,對應於RIL_REQUEST_DIAL的函數爲dispatchDial。
7) 在dispatchDial中,調用RIL_Register註冊的函數onRequest,也就是reference-ril.c中的onRequest。
8) 調用requestDial。
9) 調用atchannel.c的at_send_command來發送at命令。
10) 調用RIL_onRequestComplete立即迴應調用者,不管調用成功還是失敗。這時候會調用rild的回調函數RIL_onRequestComplete,該回調在RIL_Init的時候註冊,在ril.cpp中實現。
11) 在RIL_onRequestComplete中組裝響應,調用sendResponse。
12) 調用sendResponseRaw。
13) 往和JAVA上層建立的socket中寫數據。
14) JAVA層RIL.java中,會起一個RILReceiver線程來接收數據。
15) RILReceiver接收到的消息,調用RIL的readRilMessage讀取數據。然後調用proce***esponse處理數據。
16) 調用processSolicited。
5.2 Unsolicited Response
1) 在RIL_Init中傳入參數s_device_path,是同modem通訊的設備路徑,一般是串口(ttyS),在模擬器中,用qemud 的socket模擬。
2) RIL_init啓動s_tid_mainloop,用於打開通信信道(比如串口,或者模擬器的qemu socket),並啓動s_tid_reader接收消息。
3) S_tid_reader線程從at channel收到Unsolicited reponses,調用Unsolicited handler(在at_open的時候指定爲reference-ril.c的onUnsolicited)。
4) ril.h定義了一系列宏,對應各個Unsolicited response,從RIL_UNSOL_RESPONSE_BASE開始。ril_unsol_commands.h中每個unsolicited repsonse對應一個處理函數。RIL_UNSOL_CALL_STATE_CHANGED對應responseVoid,封裝返回給JAVA層的消息。
5) 調用sendResponse給s_fdCommand發消息。
6) JAVA層的RILReceiver收到消息,調用proce***esponse。
7) 對應於Unsolicited response,調用processUnsolicited。
6.Radiooptions
這是一個調試程序,可以在控制檯啓動這個程序,在不開啓ui的情況下,調試ril。
# radiooptions
Usage: radiooptions [option] [extra_socket_args]
0 - RADIO_RESET,
1 - RADIO_OFF,
2 - UNSOL_NETWORK_STATE_CHANGE,
3 - QXDM_ENABLE,
4 - QXDM_DISABLE,
5 - RADIO_ON,
6 apn- SETUP_PDP apn,
7 - DEACTIVE_PDP,
8 number - DIAL_CALL number,
9 - ANSWER_CALL,