一、輸入系統的核心角色與分層架構
Android 輸入系統的本質是橋梁:一端連接硬件驅動產生的原始事件,另一端將事件精準派發給應用窗口。整個過程涉及三層架構和多個關鍵組件,可類比為 “快遞分揀系統”:
1. 硬件與內核層(源頭)
- 角色:當用戶觸摸屏幕或按下按鍵時,硬件驅動將事件寫入設備節點(如/dev/input),生成原始的內核事件(類似 “快遞包裹的原始數據”)。
- 技術實現:通過EventHub(事件樞紐)監聽設備路徑,使用epoll和inotify機制高效檢測事件變化和設備插拔。
系統內容:
驅動上報
struct RawEvent{
nsecs_t when;
nsecs_t readtime;
int32_t deviceId; 輸入設備唯一標識符
int32_t type; ?事件類型 如EV_KEY, EV_ABS
int32_t code; ?事件碼
int32_t value; 事件值
}
frameworks/native/services/inputflinger/reader/include/EventHub.h
2. Native 層(事件處理與分發)
InputReader(事件快遞員)?:
-
- 從EventHub讀取原始事件(如觸摸坐標、按鍵碼),按規則封裝為標準事件(如MotionEvent、KeyEvent)。
- 類比:將 “原始包裹數據” 解析為 “標準化快遞單”。
InputDispatcher(事件分揀員)?:
-
- 接收InputReader處理后的事件,結合窗口信息(如焦點窗口),將事件派發給對應的應用窗口。
- 類比:根據 “快遞單地址” 將包裹分揀到正確的配送路線。
InputManager(調度中心)?:
-
- 管理InputReader和InputDispatcher,創建并啟動它們的工作線程。
- 按鍵事件類型
RawEvent的 type ==EV_KEY:
rawEvent 的code 對應android的scanCode,
scanCode ?通過 ?Generic.kl 映射到android 的keycode。
frameworks/base/data/keyboards/Generic.kl
- 觸摸事件類型
RawEvent的type ==EV_ABS (絕對坐標事件)
在 Linux 輸入子系統(Input Subsystem)中,多點觸控(Multi-Touch)事件通過一系列以 ABS_MT_?開頭的絕對坐標類事件代碼(ABS 代表 Absolute Position)來描述每個觸摸點(Slot)的屬性。以下是你列出的各個 ABS_MT_?事件的詳細說明:
1. ABS_MT_SLOT
- 作用:標識當前操作的觸摸點槽位(Slot)。
多點觸控設備通過 “槽位” 機制管理多個觸摸點(類似數組索引),每個槽位對應一個獨立的觸摸點。當設備報告某個觸摸點的屬性時,需先通過 ABS_MT_SLOT?指明操作的是哪個槽位。 - 值范圍:通常從 0?開始遞增(如 0、1、2...),具體取決于設備支持的最大觸摸點數(如 5 點觸控則槽位為 0~4)。
2. ABS_MT_TRACKING_ID
- 作用:為每個觸摸點分配唯一的追蹤 ID,用于在觸摸點生命周期內(按下、移動、抬起)標識其身份。
- 當觸摸點按下時,系統分配一個非負整數 ID(如 1、2...);
- 當觸摸點抬起時,ID 會被重置為 -1(表示該槽位不再被占用)。
- 值范圍:
- 有效觸摸點:>= 0(如 1, 2);
- 無效 / 釋放的槽位:-1。
- 用途:區分不同觸摸點(即使槽位重用),例如:
- 槽位 0?先用于觸摸點 A(ID=1),抬起后 ID 重置為 -1;
- 新觸摸點 B 按下時,可能再次使用槽位 0,但分配新 ID=2。
通過 ID 可確保觸摸點的移動軌跡不會因槽位重用而混淆。
3. ABS_MT_TOUCH_MAJOR
- 作用:表示觸摸點接觸面積的主軸長度(橢圓的長軸,單位為像素或設備特定單位)。
可粗略理解為觸摸點的 “寬度” 或 “接觸區域大小”,例如手指按下時的接觸面積。 - 值范圍:通常為正整數,值越大表示接觸面積越大。
- 示例:手指輕輕觸摸時值為 20,用力按下時值為 30
4. ABS_MT_WIDTH_MAJOR
- 作用:表示觸摸點接觸面積的次軸長度(橢圓的長軸,單位與 ABS_MT_TOUCH_MAJOR?一致)。
在某些設備中,TOUCH_MAJOR?和 WIDTH_MAJOR?可能分別對應橢圓的長軸和短軸,用于描述觸摸點的形狀。 - 值范圍:正整數,通常與 ABS_MT_TOUCH_MAJOR?成比例。
5. ABS_MT_POSITION_X?和 ABS_MT_POSITION_Y
- 作用:
- ABS_MT_POSITION_X:觸摸點在屏幕坐標系中的 X 軸坐標(水平位置)。
- ABS_MT_POSITION_Y:觸摸點在屏幕坐標系中的 Y 軸坐標(垂直位置)。
- 坐標原點:通常為屏幕左上角(X=0, Y=0),向右 / 向下遞增。
- 單位:設備特定的邏輯單位(如像素、毫米等),需通過輸入子系統校準后映射到屏幕像素。
6. ABS_MT_PRESSURE
- 作用:表示觸摸點的壓力值,用于檢測觸摸力度(如手指按下的輕重)。
- 值為 0?時表示無壓力(觸摸點抬起);
- 值越大表示壓力越大。
- 值范圍:通常為 0?到設備支持的最大值(如 255、1024?等)。
- 用途:實現壓感功能,例如繪圖應用中根據壓力調整筆觸粗細。
3.EV_SYN(同步事件)??
- ??核心作用??:標記事件數據包的邊界,確保用戶空間程序能完整處理一組事件
· ???子類型??:
- ??SYN_REPORT??:表示當前數據包結束,觸發用戶空間處理累積事件(如鼠標移動后必須發送該事件完成坐標更新)
· ???SYN_DROPPED??:內核緩沖區溢出時通知用戶丟棄數據包并重新查詢設備狀態
· ???SYN_MT_REPORT??:多點觸控協議中分隔不同觸點的數據包(Type A協議使用)
· ???底層依賴??:驅動必須正確發送該事件,否則用戶空間無法識別事件邊界
4.EV_REL(相對坐標事件)??
- ??功能??:報告相對位移變化,適用于鼠標等設備
5.EV_SW(開關事件)??
- ??功能??:報告二進制狀態切換,如設備休眠/喚醒、蓋子開合等
6.EV_MSC(雜項事件)??
- ??功能??:處理無法歸類到其他類型的事件,如硬件特定狀態或補充信息
3. Java 層(系統服務與交互)
InputManagerService(IMS,總控中心)?:
-
- 作為 Android 系統服務(運行于system_server進程),通過 JNI 與 Native 層交互。
- 與窗口管理服務(WMS)同步窗口信息,為InputDispatcher提供派發依據(如哪個窗口當前可見)。
- 類比:“快遞總控中心”,協調底層分揀與上層應用的對接。
二、啟動流程詳解:從 IMS 初始化到線程啟動
IMS 的啟動伴隨system_server進程啟動,整個過程可分為對象創建和線程啟動兩個階段,涉及 Java 層、JNI 層和 Native 層的跨層調用。
1. 初始化階段:搭建組件鏈路
/ /Java層:IMS初始化(InputManagerService.java)inputManager = new InputManagerService(context);
步驟 1:創建 Java 層 IMS 對象
初始化mHandler,運行在 “android.display” 線程(負責處理 Java 層消息)。
通過nativeInit調用 JNI,進入 Native 層初始化。
// JNI層:nativeInit(com_android_server_input_InputManagerService.cpp)NativeInputManager* im = new NativeInputManager(...);
步驟 2:創建 NativeInputManager(JNI 橋梁)
持有 Java 層 IMS 對象的引用(mServiceObj),作為 Native 層與 Java 層交互的橋梁。
創建EventHub(監聽設備事件)和InputManager(管理讀寫線程)。
// Native層:InputManager構造(InputManager.cpp)
mDispatcher = new InputDispatcher(...); // 分揀員
mReader = new InputReader(...); // 快遞員
步驟 3:創建 InputDispatcher 和 InputReader
- InputDispatcher關聯NativeInputManager(獲取派發策略,如超時參數)。
- InputReader通過QueuedInputListener與InputDispatcher建立連接(事件傳遞的樞紐)。
2. 啟動階段:激活工作線程
inputManager.start(); // 調用nativeStart
·?啟動 Native 層線程
通過InputManager.start()啟動兩個核心線程:
- ·??InputReaderThread:循環調用EventHub.getEvents()讀取事件,交由InputReader處理。
- InputDispatcherThread:循環處理事件隊列,將事件派發給目標窗口。
·??關鍵線程分工:
- ·??android.display 線程(Java 層):處理 IMS 的消息(如配置變更、ANR 通知)。
- InputReaderThread(Native 層):專注讀取硬件事件,不阻塞其他操作。
- InputDispatcherThread(Native 層):專注事件派發,確保實時性。
。
三、事件如何從硬件傳到應用?
事件分發鏈:InputReader → InputDispatcher → 應用窗口
InputReader → InputDispatcher:
-
- 通過QueuedInputListener將封裝好的事件傳遞給InputDispatcher,存入mInboundQueue隊列。
InputDispatcher 派發事件:
-
- 從 WMS 獲取焦點窗口信息(通過 IMS 同步),確定事件目標窗口。
- 通過InputChannel(跨進程通信通道)將事件發送給應用的InputConsumer,最終由ViewRootImpl處理并傳遞給界面組件(如按鈕、文本框)。