Android GSM驅動模組(rild)詳細分析(一)基本架構及初始化

來源:互聯網
上載者:User

 

Android GSM驅動模組(rild)詳細分析(一)基本架構及初始化
熊貓哥哥 發表於IT168和Opendroid 轉載請註明

Android的RIL驅動模組, 在hardware/ril目錄下,一共分rild,libril.so以及librefrence_ril.so三個部分,另有一 radiooptions可供自動或手動調試使用。都依賴於include目錄中ril.h標頭檔。目前cupcake分支上帶的是gsm的支援,另有一 cdma分支,這裡分析的是gsm驅動。

GSM模組,由於Modem的曆史原因,AP一直是通過基於串口的AT命令與BB互動。包括到了目前的一些edge或3g模組,或像omap這類ap,bp整合的晶片,已經使用了USB或其他等高速匯流排通訊,但大多仍然使用類比串口機制來使用AT命令。這裡的RIL(Radio Interface Layer)層,主要也就是基於AT命令的操作,如發命令,response解析等。(gprs等傳輸會用到的MUX協議等在這裡並沒有包含,也暫不作介紹。)

以下是詳細分析,因為篇幅原因,會以連載形式發布出來(大概3篇),本文主要涉及基本架構和初始化的內容:

首先介紹一下rild與libril.so以及librefrence_ril.so的關係:
1. rild:
僅實現一main函數作為整個ril層的進入點,負責完成初始化。
2. libril.so:
與 rild結合相當緊密,是其共用庫,編譯時間就已經建立了這一關係。組成部分為ril.cpp,ril_event.cpp。libril.so駐留在 rild這一守護進程中,主要完成同上層通訊的工作,接受ril請求並傳遞給librefrence_ril.so, 同時把來自librefrence_ril.so的反饋回傳給調用進程。

3. librefrence_ril.so:
rild通過手動的dlopen方式載入,結合稍微鬆散,這也是因為librefrence.so主要負責跟Modem硬體通訊的緣故。這樣做更方便替換或修改以適配更多的Modem種類。它轉換來自libril.so的請求為AT命令,同時監控Modem的反饋資訊,並傳遞迴libril.so。在初始化時, rild通過符號RIL_Init擷取一組函數指標並以此與之建立聯絡。

4. radiooptions:
radiooptiongs通過擷取啟動參數, 利用socket與rild通訊,可供調試時配置Modem參數。

接下來分析初始化流程:
主入口是rild.c中的main函數,主要完成三個任務:
1. 開啟libril.so中的event機制, 在RIL_startEventLoop中,是最核心的由多路I/O驅動的訊息迴圈。
2. 初始化librefrence_ril.so,也就是跟硬體或類比硬體modem通訊的部分(後面統一稱硬體), 通過RIL_Init函數完成。
3. 通過RIL_Init擷取一組函數指標RIL_RadioFunctions, 並通過RIL_register完成註冊,並開啟接受上層命令的socket通道。

首先看第一個任務:
也就是RIL_startEventLoop函數。RIL_startEventLoop在ril.cpp中實現, 它的主要目的是通過pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL)建立一個dispatch線程,進入點在eventLoop. 而eventLoop中,會調ril_event.cpp中的ril_event_loop()函數,建立起訊息(event)隊列機制。

我們來仔細看看這一訊息佇列的機制,這些代碼都在ril_event.cpp中。
void ril_event_init();
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);

void ril_event_add(struct ril_event * ev);
void ril_timer_add(struct ril_event * ev, struct timeval * tv);
void ril_event_del(struct ril_event * ev);
void 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結構,與一個fd控制代碼綁定(可以是檔案,socket,管道等),並且帶一個func指標去執行指定的操作。
具體流程是: ril_event_init完成後,通過ril_event_set來配置一新ril_event,並通過ril_event_add排入佇列之中(實際通常用rilEventAddWakeup來添加),add會把隊列裡所有ril_event的fd,放入一個fd集合readFds中。這樣 ril_event_loop能通過一個多工I/O的機制(select)來等待這些fd, 如果任何一個fd有資料寫入,則進入分析流程processTimeouts(),processReadReadies(&rfds,
n),firePending()。 後文會詳細分析這些流程。
另外我們可以看到, 在進入ril_event_loop之前, 已經掛入了一s_wakeupfd_event, 通過pipe的機制實現的, 這個event的目的是可以在一些情況下,能內部喚醒ril_event_loop的多工阻塞,比如一些帶timeout的命令timeout到期的時候。

至此第一個任務分析完畢,這樣便建立起了基於event隊列的訊息迴圈,稍後便可以接受上層發來的的請求了(上層請求的event對象建立,在第三個任務中)。

接下來看第二個任務:
這個任務的入口是RIL_Init, RIL_Init首先通過參數擷取硬體介面的裝置檔案或類比硬體介面的socket. 接下來便新開一個線程繼續初始化, 即mainLoop。

mainLoop的主要任務是建立起與硬體的通訊,然後通過read方法阻塞等待硬體的主動上報或響應。
在註冊一些基礎回調(timeout,readerclose)後,mainLoop首先開啟硬體裝置檔案,建立起與硬體的通訊,s_device_path和s_port是前面擷取的裝置路徑參數,將其開啟(兩者可以同時開啟並擁有各自的reader,這裡也很容易添加雙卡雙待等支援)。

接下來通過at_open函數建立起這一裝置檔案上的reader等待迴圈,這也是通過建立一個線程完成, ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr),進入點readerLoop。

AT命令都是以\r\n或\n\r的分行符號來作為分隔字元的,所以readerLoop是 line驅動的,除非出錯,逾時等,否則會讀到一行完整的響應或主動上報,才會返回。這個迴圈跑起來以後,我們基本的AT響應機制已經建立了起來。它的具體分析,包括at_open中掛接的ATUnsolHandler, 我們都放到後面分析response的連載文章裡去。

有了響應的機制(當然,能與硬體通訊也已經可以發請求了),通過RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0),跑到initializeCallback中,執行一些Modem的初始化命令,主要都是AT命令的方式。發AT命令的流程,我們放到後面分析request的連載文章裡。這裡可以看到,主要是一些參數配置,以及網路狀態的檢查等。

至此第二個任務分析完畢,硬體已經可以訪問了。

最後是第三個任務:
第三個任務是由RIL_Init的傳回值開始的,這是一個RIL_RadioFunctions結構的指標。
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;
其中最重要的是onRequest域,上層來的請求都由這個函數進行映射後轉換成對應的AT命令發給硬體。
rild通過RIL_register註冊這一指標。
RIL_register中要完成的另外一個任務,就是開啟前面提到的跟上層通訊的socket介面(s_fdListen是主介面,s_fdDebug供調試時使用)。
然後將這兩個socket介面使用任務一中實現的機制進行註冊(僅列出s_fdListen)
ril_event_set (&s_listen_event, s_fdListen, false,
                listenCallback, NULL);
rilEventAddWakeup (&s_listen_event);
這樣將兩個socket加到任務一中建立起來多工I/O的檢查控制代碼集合中,一旦有上層來的(調試)請求,event機制便能響應處理了。
到這裡啟動流程已經分析完畢。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.