註:這個分析是很久之前做的了,用於分析的代碼是Android 2.1 Eclair。在最新的Android 4.x中,Input相關的代碼已經發生了一些變化。在Android 2.1中,Input相關的代碼分散在/frameworks/base/libs/ui/和/frameworks/base/service/java/com/android/server/目錄中。在Android 4.x中,這些代碼被集中到了/frameworks/base/services/input/
和
/frameworks/base/services/java/com/android/server/input/。同時,一些檔案的名字和內容也發生了變化,比如Android 2.1中的KeyInputQueue的Java層與JNI層的檔案,在Android 4.x中已經被InputManager所取代;EventHub.cpp的內容發生了一定的變化。但是以下分析依然有有助於研究Android 4.x中的鍵盤輸入事件如何轉換成Android Media Button事件的,其中的關鍵入口是EventHub。從EventHub入手,往上層分析代碼就可以追蹤到Android
InputManager中的Input Event處理過程;往下層分析可以就能夠抵達Linux Input Device。
中藍色的是Native code,綠色的是Java code。最頂上的Thread: InputDeviceReader是整個Input過程的控制中心(在Android 4.x中,這個thread在InputManager.cpp中)。這個thread通過EventHub::getEvent()來讀Linux的/dev/input目錄下的Input Devices,從而得到硬體的key input。基於一個與每個Input Device關聯的key layout map,key input會被map成Android能夠識別的Key
Code,比如一個AVRCP Input Device的key input值200就會被map成MEDIA_PLAY。
需要注意的是,在EventHub::getEvnet()讀Input Devices之前,需要判斷Devices是否已經被開啟。如果沒有就需要去調用EventHub::openPlatformInput()去掃描/dev/input/下有哪些裝置,然後開啟這些裝置並載入它們各自的key layout map(/frameworks/base/data/keyboards/ 中的*.kl檔案就是用於定義key layout map的,其中的AVRCP.kl就定義了Bluetooth AVRCP Input
Device的key layout map。在Android Device的root fs中,這些.kl檔案會被放在/system/usr/keylayout/目錄)。這些被開啟的裝置的file descriptor和device_t指標會分別儲存在mFDs和mDevices中。
InputDeviceReader Thread得到Key Code之後,會交給Java層的代碼來處理。最終由PhoneWindowManager.java中的interceptKeyTq()建立一個ACTION_MEDIA_BUTTON intent廣播出去。(在Android 4.x中,最後一步廣播MEDIA BUTTON的動作也是在PhoneWindowManager.java中,由interceptKeyBeforeQueueing()來實現的。interceptKeyBeforeQueueing()就是Android
2.1中的interceptKeyTq().)
最後說一下建立ACRCP Input Device的函數調用過程。在/external/bluetooth/bluz/audio/control.c中,avctp_connect_cb()->init_uinput()->uinput_create()。需要注意的是,這個建立過程僅僅適用於Android 4.2之前的版本。從Android 4.2開始,Android就用Broadcom的Bluetooth stack替換了Bluez。