下面看第二個關鍵函數RIL_Init。這個函數必須由動態庫實現,對于下面這個例子來說,它將由RefRil庫實現,這個函數定義在Reference_ril.c中:
**Reference_ril.c**
~~~
pthread_t s_tid_mainloop;//看來又會創建一個線程
//動態庫必須實現的RIL_Init函數。
const RIL_RadioFunctions *RIL_Init(const structRIL_Env *env,
int argc, char **argv)
{
intret;
int fd= -1;
intopt;
pthread_attr_t attr;
s_rilenv = env; //將外部傳入的env保存為s_rilenv。
......//一些參數處理,不必管它
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//創建一個工作線程mainLoop
ret =pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
/*
s_callbacks也為一個結構體
staticconst RIL_RadioFunctions s_callbacks = {
RIL_VERSION, //RIL的版本
onRequest, //下面是一些函數指針
currentState,
onSupports,
onCancel,
getVersion
};
*/
return&s_callbacks;
}
~~~
RefRil的RIL_Init函數比較簡單,主要有三項工作要做:
- 保存Rild傳入的RIL_Env結構體。
- 創建一個叫mainLoop的工作線程。
- 返回一個RIL_RadioFunctions的結構體。
上面的RIL_Env和RIL_RadioFunctions結構體,就是Rild架構中用來隔離通用代碼和廠商相關代碼的接口。先來看RIL_RadioFunctions,這個結構體由廠商的動態庫實現,它的代碼如下:
~~~
//函數指針定義
typedef void (*RIL_RequestFunc) (int request,void *data,
size_tdatalen, RIL_Token t);
typedef RIL_RadioState(*RIL_RadioStateRequest)();
typedef int (*RIL_Supports)(int requestCode);
typedef void (*RIL_Cancel)(RIL_Token t);
typedef void (*RIL_TimedCallback) (void *param);
typedef const char * (*RIL_GetVersion) (void);
typedef struct {
intversion; //RIL的版本
//通過這個接口可向BP提交一個請求,注意這個函數的返回值為空,這是為什么?
RIL_RequestFunc onRequest;
RIL_RadioStateRequest onStateRequest;//查詢BP的狀態
RIL_Supports supports;
RIL_CancelonCancel;
//查詢動態庫的版本,RefRil庫中該函數的實現將返回字符串”android reference-ril 1.0”
RIL_GetVersion getVersion;
} RIL_RadioFunctions;
~~~
對于上面的結構體,應重點關注函數onRequest,它被Rild用來向動態庫提交一個請求,也就是說,AP向BP發送請求的接口就是它,但是這個函數卻沒有返回值,那么該請求的執行結果是怎么得到的呢?
這里不賣關子,直接告訴大家。Rild架構中最大的特點就是采用了異步請求/處理的方式。這種方式和異步I/O有異曲同工之妙。那么什么是異步請求/處理呢?它的執行流程如下:
- Rild通過onRequest向動態庫提交一個請求,然后返回去做自己的事情。
- 動態庫處理這個請求,請求的處理結果通過回調接口通知。
這種異步請求/處理的流程和酒店的MorningCall服務很類似,具體相似之處如下所示:
- 在前臺預約了一個Morning Call,這好比向酒店提交了一個請求。預約完后,就可以放心地做自己的事情了。
- 酒店登記了這個請求,記錄是哪個房間申請的服務,然后由酒店安排工作人員值班,這些都是酒店對這個請求的處理,作為房客則無須知道處理細節。
- 第二天早上,約好的時間一到,酒店給房客打電話,房客就知道這個請求被處理了。為了檢查一下賓館服務的效果,最好是拿表看看接到電話的時間是不是之前預約的時間。
這時,讀者對異步請求/處理機制或許有了一些直觀的感受。那么,動態庫是如何通知請求的處理結果的呢?這里用到了另外一個接口RIL_Env結構,它的定義如下所示:
**Ril.h**
~~~
struct RIL_Env {
//動態庫完成一個請求后,通過下面這個函數通知處理結果,其中第一個參數標明是哪個請求
//的處理結果
void(*OnRequestComplete)(RIL_Token t, RIL_Errno e,
void *response,size_t responselen);
//動態庫用于進行unsolicited Response通知的函數
void(*OnUnsolicitedResponse)(int unsolResponse, const void *data,
size_t datalen);
//給Rild提交一個超時任務
void*(*RequestTimedCallback) (RIL_TimedCallback callback,
void *param,const struct timeval *relativeTime);
//從Rild的超時任務隊列中移除一個任務
void(*RemoveTimedCallback) (void *callbackInfo);
};
~~~
結合圖9-7和上面的分析可以發現,Rild在設計時將請求的應答接口和動態庫的通知接口都放在了RIL_Env結構體中。
關于Rild和動態庫的交互接口就分析到這里。相信讀者已經明白其中的原理了。下面來看RefRil庫創建的工作線程mainLoop。
1. 工作線程mainLoop的分析
RefRil庫的RIL_Init函數會創建一個工作線程mainLoop,其代碼如下所示:
**Reference_Ril.c**
~~~
static void *
mainLoop(void *param)
{
intfd;
intret;
......
/*
為AT模塊設置一些回調函數,AT模塊用來和BP交互,對于RefRil庫來說,AT模塊就是對
串口設備通信的封裝,這里統稱為AT模塊。
*/
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for(;;) {
fd= -1;
//下面這個while循環的目的是為了得到串口設備的文件描述符,我們省略其中的一些內容
while (fd < 0) {
if (s_port > 0) {
fd = socket_loopback_client(s_port, SOCK_STREAM);
} else if (s_device_socket) {
if (!strcmp(s_device_path, "/dev/socket/qemud")) {
......
} else if (s_device_path != NULL) {
fd = open (s_device_path, O_RDWR);
if ( fd >= 0 && !memcmp( s_device_path,"/dev/ttyS", 9 ) ) {
struct termios ios;
tcgetattr( fd, &ios );
ios.c_lflag = 0;
tcsetattr( fd, TCSANOW,&ios );
}
}
......
}
s_closed = 0;
//①打開AT模塊,傳入一個回調函數onUnsolicited
ret = at_open(fd, onUnsolicited);
......
//②下面這個函數向Rild提交一個超時任務,該任務的處理函數是initializeCallback
RIL_requestTimedCallback(initializeCallback,NULL, &TIMEVAL_0);
sleep(1);
/*
如果AT模塊被關閉,則waitForClose返回,但是該線程并不會退出,而是從for循環那
開始重新執行一次。所以這個mainLoop工作線程是用來監控AT模塊的,一旦它被關閉,就
需要重新打開。也就是說不允許AT模塊被關閉。
*/
waitForClose();
......
}
}
~~~
可以看到,mainLoop的工作其實就是初始化AT模塊,并監控AT模塊,一旦AT模塊被關閉,那么mainLoop就要重新打開并初始化它。這幾項工作主要由at_open和超時任務的處理函數initializeCallback完成。
(1)at_open分析
來看at_open這個函數,其代碼如下所示:
**Atchannle.c**
~~~
int at_open(int fd, ATUnsolHandler h)
{
//at_open的第一個參數是一個代表串口設備的文件描述符。
intret;
pthread_t tid;
pthread_attr_t attr;
s_fd =fd;
s_unsolHandler = h;
s_readerClosed = 0;
s_responsePrefix = NULL;
s_smsPDU = NULL;
sp_response = NULL;
......//和電源管理相關的操作
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//創建一個工作線程readerLoop,這個線程的目的就是從串口設備讀取數據
ret =pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
......
return0;
}
~~~
at_open函數會另外創建一個工作線程readerLoop,從名字上看,它會讀取串口設備。下面來看它的工作,代碼如下所示:
**Atchannle.c**
~~~
static void *readerLoop(void *arg)
{
for(;;) {
const char * line;
line = readline(); //從串口設備讀取數據
......
if(isSMSUnsolicited(line)) {
char *line1;
const char *line2;
line1 = strdup(line);
line2 = readline();
if (line2 == NULL) {
break;
}
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2);//調用回調,處理SMS的通知
}
free(line1);
}else {
//處理接收到的數據,也就是根據line中的AT指令調用不同的回調
processLine(line);
}
......//電源管理相關
//這個線程退出前會調用通過at_set_on_reader_closed設置的回調函數,以通知
//AT模塊關閉
onReaderClosed();
returnNULL;
}
~~~
readerLoop工作線程比較簡單,就是從串口設備中讀取數據,然后進行處理。這些數據有可能是solicited response,也有可能是unsolicited response,具體的處理函數我們在后續的實例分析中再來介紹,下面我們看第二個函數RIL_requestTimedCallback。
(2)initializeCallback的分析
在分析initializeCallback函數前,我們先看看RefRil向Rild提交超時任務的RIL_requestTimedCallback函數,它其實是一個宏,不過這個宏比較簡單,就是封裝了RIL_Env結構體中對RequestTimedCallback函數的調用,代碼如下所示:
~~~
#define RIL_requestTimedCallback(a,b,c) \
s_rilenv->RequestTimedCallback(a,b,c)
//向Rild提交一個超時處理函數
~~~
下面我們看看Rild實現的這個RequestTimedCallback函數,代碼如下所示。
**Ril.cpp**
~~~
extern "C" void *
RIL_requestTimedCallback (RIL_TimedCallbackcallback, void *param,
const structtimeval *relativeTime) {
returninternalRequestTimedCallback (callback, param, relativeTime);
}
/*
調用internalRequestTimedCallback,其實就是構造一個Ril_event事件然后加入到
timer_list,并觸發event_loop工作線程執行
*/
static UserCallbackInfo * internalRequestTimedCallback(
RIL_TimedCallback callback, void *param,
const structtimeval *relativeTime)
{
structtimeval myRelativeTime;
UserCallbackInfo *p_info;
p_info= (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
p_info->p_callback = callback;
p_info->userParam = param;
if(relativeTime == NULL) {
memset (&myRelativeTime, 0, sizeof(myRelativeTime));
} else{
memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
}
ril_event_set(&(p_info->event), -1, false, userTimerCallback,p_info);
//將該任務添加到timer_list中去
ril_timer_add(&(p_info->event), &myRelativeTime);
triggerEvLoop(); //觸發eventLoop線程
returnp_info;
}
~~~
從上面的代碼可知,RIL_requestTimedCallback函數就是向eventLoop提交一個超時任務,這個任務的處理函數則為initialCallback,下面直接來看該函數的內容,如下所示。
**Reference_ril.c**
~~~
static void initializeCallback(void *param)
{
/*
這個函數就是通過發送一些AT指令來初始化BP中的無線通信Modem,不同的modem可能有
不同的AT指令。這里僅列出部分代碼。
*/
ATResponse *p_response = NULL;
interr;
setRadioState (RADIO_STATE_OFF);
at_handshake();
......
err =at_send_command("AT+CREG=2", &p_response);
......
at_response_free(p_response);
at_send_command("AT+CGREG=1", NULL);
at_send_command("AT+CCWA=1", NULL);
......
if(isRadioOn() > 0) {
setRadioState (RADIO_STATE_SIM_NOT_READY);
}
......
}
~~~
2. RIL_Init的總結
RIL_Init函數由動態庫提供,以上面RefRil庫的代碼為參考,這個函數執行完后,將完成RefRil庫的幾項重要工作,它們是:
- 創建一個mainLoop工作線程,mainLoop線程的任務是初始化AT模塊,并監控AT模塊,一旦AT模塊被關閉,則會重新初始化AT模塊。
- AT模塊內部會創建一個工作線程readerLoop,該線程的作用是從串口設備中讀取信息,也就是直接和BP打交道。
- mainLoop通過向Rild提交超時任務,完成了對Modem的初始化工作。
在Rild的main函數中還剩下最后一個關鍵函數RIL_register沒有分析了,下面來看看它。
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結