Rild是Init進程啓動的一個本地服務,這個本地服務並無使用Binder之類的通信手段,而是採用了socket通信這種方式。RIL(Radio Interface Layer) linux
Android給出了一個ril實現框架。因爲Android開發者使用的Modem是不同的,各類指令格式,初始化序列均可能不同,GSM和CDMA就差異更大了,因此爲了消除這些差異,Android設計者將ril作了一個抽象,使用一個虛擬電話的概念。這個虛擬電話對象就是GSMPhone(CDMAPhone),Phon對象所提供的功能協議,以及要求下層的支撐環境都有一個統一的描述,這個底層描述的實現就是靠RIL來完成適配。 數組
Andoid將RIL層分爲兩個代碼空間:RILD管理框架,AT相關的xxxril.so動態連接庫。將RIL獨立成一個動態連接庫的好處就是Android系統適應不一樣的Modem,不一樣的Mode能夠有一個獨立的Ril與之對應。從這個層面上看,Rild更可能是一個管理框架。 框架
而ril是具體的AT指令合成者和應答解析者。從最基本的功能來說,ril創建了一個偵聽Socket,等待客戶端的鏈接,而後從該鏈接上讀取RIL-Java成傳遞來的命令並轉化成AT指令發送到Modem。並等待Modem的迴應,而後將結果經過套接口傳回到Ril-Java層。下圖是Ril-D的基本框架: socket
下面的數據流傳遞描述圖表描述了RIL-JAVA層發出一個電話指令的5 步曲。 函數
在AT通信的過程當中有兩類響應:一種是請求後給出應答,一種是通知類,即爲不請自來的,例如短信通知達到,咱們稱該類通知爲URC。在Rild中URC和通常的Response是分開處理的,概念上URC由handleUnsolicited@Atchannel.c處理,而Response由handleFinalResponse來處理。 oop
Rild管理的真正精髓在ril.cpp,ril_event.cpp中,在研究的過程當中,能夠看到設計者在抽象上所下的功夫,設計得很優美。Event Loop的基本工做就是等待在事件端口(串口,Socket),一旦有數據到達就根據登記的Event回調函數進行處理。如今來看Ril設計者是如何創建一套管理框架來完成這些工做的? spa
Event對象構成:(fd,index,persist,func,param) 翻譯
fd | 事件相關設備句柄。例如對於串口數據事件,fd就是相關串口的設備句柄 |
index | |
persist | 若是是保持的,則不從watch_list中刪除。 |
func | 回調事件處理函數 |
param | 回調時參數 |
爲了統一管理事件,Android使用了三個隊列:watch_list,timer_list,pending_list,並使用了一個設備句柄池readFDS。 設計
readFDS:是Linux的fd_set,readFDS保存了Rild中全部的設備文件句柄,以便利用select函數統一的完成事件的偵聽。 對象
watch_list:監測時間隊列。須要檢測的事件都放入到該隊列中。
timer_list:timer隊列
pending_list:待處理事件隊列,事件已經觸發,須要所回調處理的事件。
事件隊列隊列的操做:ril_event_add,ril_event_del, ril_timer_add
在添加操做中,有兩個動做:
(1) 加入到watch_list
(2) 將句柄加入到readFDS事件句柄池。
咱們知道對於Linux設備來說,咱們可使用select函數等待在FDS上,只要FDS中記錄的設備有數據到來,select就會設置相應的標誌位並返回。readFDS記錄了全部的事件相關設備句柄。readFDS中句柄是在在AddEvent加入的。全部的事件偵聽都是創建在linux的select readFDS基礎上。
ril_event_loop 利用select等待在readFDS(fd_set)上,當select設備有數據時,ril_event_loop會從select返回,在watch_list中相應的Event放置到pend_list,若是Event是持久性的則不從watch_list中刪除。而後ril_event_loop遍歷pengding_list處理Event事件,發起事件回調函數。
上面分析了ril-d的框架,在該框架上跑的事件有什麼
(1)s_listen_event- (s_fdListen,listenCallback)
listenCallback處理函數,
接收客戶端鏈接:s_fdCommand=accepte(..)
添加s_commands_event()
從新創建s_listen_event,等待下一次鏈接
(2) s_command_event(s_fdCommand,ProcessCommandsCallback)
從fdCommand Socket鏈接中讀取StreamRecord
使用ProcessCommandBufer處理數據
s_listen_event在大的功能上處理客戶端鏈接(Ril-JAVA層發起的connect),並創建s_commands_event去處理Socket鏈接發來的Ril命令。ProcessCommandBufer實際上包含了Ril指令的下行過程。
RIL_JAVA傳遞的命令格式:Parcel ,由命令號,令牌,內容組成。RIL_JAVA到達RIL_C時轉爲構建本地RequestInfo,並將被翻譯成具體的AT指令。因爲每條AT命令的參數是不一樣的,因此對不一樣的AT指令,有不一樣的轉換函數,在此Android設計在這裏作了一個抽象,作了一個分發框架,經過命令號,利用sCommand數組,得到該命令的處理函數。
sComand[]={
<...>
}
sComand 存在於Ril_command.h中。
&sComand[]=
<
{RIL_REQUEST_GET_IMEI, dispatchVoid, responseString},
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
{….}
>
dispatchXxx函數通常都放在在Reference-ril.c中,Reference-ril.c這個就是咱們須要根據不一樣的Modem來修改的文件。
send_at_command是同步的,命令發送後,send_at_command將等待在s_commandcond,直到有sp_response->finalResponse。
Read loop是解決的問題是:解析從Modem發過來的迴應。若是遇到URC則經過handleUnsolicited上報的RIL_JAVA。若是是命令的應答,則經過handleFinalResponse通知send_at_command有應答結果。
對於URC,Rild一樣使用一個抽象數組@Ril.CPP.
static UnsolResponseInfo s_unsolResponses[] = {
#include "ril_unsol_commands.h"
};
並利用RIL_onUnsolicitedResponse將URC向上層發送。