前言
換工作在即,也有了難得的一段空閑時間做下總結。接下來計划分別介紹下Android的Sensor/Touch/Camera/Binder的Software架構,如果還有時間就總結下kernel。
Sensor屬於Android相對簡單的一個模塊,但麻雀雖小,五臟俱全,以此來作為切入點對理解整個Android系統有很大幫助。必須要說的是,Android系統的整體架構並不適用於所有模塊,每個模塊都有各自的特殊性,請不要一開始就把某些介紹當作公式。
1、Sensor架構試用范圍
很多模塊都可以稱為Sensor,Touch是一種Sensor,Camera也可以理解為一種Sensor。但這里介紹的Sensor架構並不適用於Touch和Camera,所使用的主要包含下面幾類Sensor。
Category |
Components |
Motion Sensors |
Accelerameter/ Gravity/ Gyroscope/ Rotation Vector/… |
Environmental Sensors |
ALS/ Pressure/… |
Position Sensors |
Orientation/ Mag/… |
這幾類器件有幾個相似的特點,產生的數據量少,實時性較強,構造相對簡單。
2、整體架構
首先從整體上,Sensor的架構可以用下圖來解釋。
有些分法把SensorService歸為Framework的一部分,但這里為了凸顯出Service的重要性單獨分為一層。
Sensor的整體邏輯非常清晰,一個控制流(藍色向下箭頭),一個數據流(紅色向上箭頭)。控制主要包括開關Sensor,設置Sensor的采樣頻率,數據流則是數據從驅動到應用的整個過程。
3、初始化
系統初始化過程中,SensorService和HAL層(硬件抽象層)會進行初始化操作。SensorService連接着Framework和HAL,它采用動態鏈接加載HAL層模塊(HAL層以so共享文件的形式存在)。
//動態鏈接的匹配 hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&mSensorModule); //Service |
struct sensors_module_t my_hal = { common: { … id: SENSORS_HARDWARE_MODULE_ID, … }, get_sensors_list: …, }; //HAL |
一句話概括該過程的目的就是,經過動態鏈接,Service可以調用HAL層的函數,方便將控制傳遞至HAL層,也可以從HAL獲取數據。完成該動作后,Service調用my_hal內的open函數。HAL可以在open動作中完成初始化,如檢測系統中存在的Sensor,保存每個Sensor的信息,維護一個所有的Sensor的列表。
HAL初始化后,Service即可調用get_sensors_list獲取系統所支持的所有Sensor。某些物理Sensor組合后,可以虛擬出其他Sensor,Service也會針對虛擬Sensor做處理,這部分暫不介紹。
一句話總結,與HAL建立聯系(動態鏈接),HAL初始化(open),獲取Sensor信息(get_sensors_list)。
4、控制流
控制,一是開關,二是頻率,Android默認支持四種采樣頻率。
名稱 |
頻率 |
SENSOR_DELAY_FASTEST |
器件的最大采樣頻率 |
SENSOR_DELAY_GAME |
50HZ |
SENSOR_DELAY_UI |
30HZ |
SENSOR_DELAY_NORMAL |
5HZ |
除了這四種頻率以外,用戶也可以指定一個特定頻率。控制的流程如下。
控制從APP注冊監聽器開始,熟悉面向對象程序設計的童鞋應該可以猜得到這是一個觀察者設計模式,實際上也確實如此。注冊監聽器的直接操作就是enable和setDelay兩個操作(unregisterListener則對應disable操作),Service與APP並不是執行在同一個進程內的,Framework傳遞來的控制需要通過進程通信傳遞至Service,使用的就是Binder(Binder幾乎貫穿了Android系統的各個模塊,后面介紹)。Service是唯一的,APP可以有無限個,Service為它們服務。這樣設計的原因顯而易見——保證單一控制:硬件是唯一的(比如某一個加速度Sensor),對它的控制也應該是唯一的,不應該由各APP單獨控制。比如enable操作,如果已經有APP打開了設備,那么只需要將引用計數增加1即可,並不會真正的觸發驅動的操作;disable操作,如果引用計數大於1,說明當前除了該APP,還有其他使用者,那么也不會觸發驅動的操作。
Service與HAL層屬於同一個進程,Service調用HAL層的函數,HAL找到對應的文件節點,根據不同的目的寫入不同的值來觸發驅動的操作。驅動根據得到的指令,讀寫設定好的寄存器控制流就得到了最終的落實。
一句話總結,應用開啟控制流,層層傳遞,最終讀寫寄存器。
5、數據流
數據由硬件產生,最終被應用使用,流程如下圖。
驅動負責收集數據(中斷或者輪詢模式),通過input子系統(也有部分廠商選擇使用IIO)上報數據。HAL層使用poll監控input節點,數據到來后poll返回,然后讀取數據。Service部分有一個線程,該線程可以理解為一個循環,不斷地poll HAL層的數據。收到數據后,Service會做一些處理(比如計算虛擬Sensor的數據),之后則通過socket將數據發送至APP進程。APP收到數據后,遍歷當前已經注冊的listener,通知它們,觀察者模式完成。
與控制流相同,數據流依然是一個Service對應多個APP,Service會將數據發送到多個APP。
說到這里,有個地方可以優化下。目前Service收到數據后,會通知所有的已經注冊了listener的APP,這個過程並不是沒有代價的,除了正常的執行代碼外,還涉及了進程通信。如果給APP添加一個感興趣的Sensor類型的列表(bitmap也可),只有列表內的Sensor的數據到來才會通知該APP進程,會高效的多。
6、各層次介紹
形象一點講,整個Sensor的軟件架構就像是水泵抽水灌溉。Service扮演電機的角色,它不斷的產生抽水的動力,並將水輸送至目的地(APP),驅動扮演泵的角色,它負責完成抽水的必要准備並抽水,HAL則很像是連接電機和泵的管道。
driver可以邏輯上分為三部分,如下圖。一部分支持它本身的功能,i2c讀寫,中斷或者輪詢處理。第二部分為sysfs文件節點,接受HAL層傳遞下來的操作,通過i2c讀寫完成任務。第三部分為input子系統(注意,該處為Linux內核的input子系統,並不是Android的input系統),負責數據上報。
一句話,driver的任務就是正常工作,完成控制操作,產生數據。
HAL層的作用一是屏蔽硬件差異,二是傳遞控制和數據。
SensorService本身就是一個線程(Thread為其父類),不出意外它循環地執行threadLoop(Android的機制),該函數一方面負責poll數據,一方面得到數據后處理,發送。
到了Framework,問題就簡單了,簡單的函數調用(最多涉及到jni)。
本文僅闡釋了整個框架,並未羅列出詳細的代碼,希望給出一個全局的介紹。
博客得來終覺淺,只因碼上才能見真知。若有任何疑問或者希望下一篇博客的內容介紹哪部分請直接留言或發郵件至郵箱(我的用戶名@onesixthree郵箱)。