Android RIL學習

1.Android RIL概念

Android RIL是基於telephony 服務和raido 硬件層的抽象層。Androidrild庫是介於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.cppmain函數,讀取rild.libpathrild.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 rilril庫之間的聯繫。獲取init.rc中建立的兩個socket(rild,rild-debug),進行偵聽,並加入消息事件循環中(s_tid_dispatch負責輪詢分發)

 

4.RIL的事件機制

 

 

ril_event.h/cpplinux常用的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的線程將執行事件分發的任務。因爲在addremove操作中有mutex進行保護,所以這個事件機制支持重入。

rild的初始化中,會執行RIL_startEventLoop,啓動s_tid_dispatch線程來進行事件輪詢,所以其它的地方只要考慮事件的增加和刪除就可以了。

全局搜索ril_event_set,就可以知道在rild上都有什麼事件在跑了。

1)      S_listen_event(s_fdListen,listenCallback):名爲rildsocket(init.rc建立的),主要用來監聽上層的(RIL-JAVA)客戶端連接請求,建立socket連接(s_fdCommand),並新增s_commands_event來監聽s_fdCommand

2)      s_commands_event(s_fdCommand,ProcessCommandsCallback):listen的時候建立的socket,用來從客戶端接收StreamRecord(實際上就是Dial,HangRIL指令),使用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的通訊分成兩種:1Solicited commandsRIL lib發起的主動調用,比如撥號2)Unsolicited responses:從baseband過來的通知消息,比如新短信到來。前者在類似協議上的request-confirm機制,後者類似Indication-response機制。

 

5.1 Solicited Commands

 

 

1)   RIL.javaFrameWorkTelephony服務的提供者,是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節所述,此時rildJAVA上層建立的sockets_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.cat_send_command來發送at命令。

10) 調用RIL_onRequestComplete立即迴應調用者,不管調用成功還是失敗。這時候會調用rild的回調函數RIL_onRequestComplete,該回調在RIL_Init的時候註冊,在ril.cpp中實現。

11) RIL_onRequestComplete中組裝響應,調用sendResponse

12) 調用sendResponseRaw

13) 往和JAVA上層建立的socket中寫數據。

14) JAVARIL.java中,會起一個RILReceiver線程來接收數據。

15) RILReceiver接收到的消息,調用RILreadRilMessage讀取數據。然後調用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.conUnsolicited)。

4)    ril.h定義了一系列宏,對應各個Unsolicited response,從RIL_UNSOL_RESPONSE_BASE開始。ril_unsol_commands.h中每個unsolicited repsonse對應一個處理函數。RIL_UNSOL_CALL_STATE_CHANGED對應responseVoid,封裝返回給JAVA層的消息。

5)    調用sendResponses_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,

                                       10 - END_CALL


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章