InputManagerService (IMS)
intro
在 Android 系統中,使用者與設備互動的最直接方式就是輸入事件 (Input Event),包含觸控 (TouchEvent)、按鍵 (KeyEvent)、以及其他輸入裝置(滑鼠、手寫筆、遊戲控制器等)。
而這些輸入事件的核心控制者,就是 InputManagerService (IMS)。
如果說 AMS 管理應用程式的生命週期,WMS 管理視窗的呈現,那麼 IMS 就是 "負責將使用者的操作轉換成系統可以理解並分發給應用的事件" 。
Input 系統整體架構
在 Android 中,輸入事件的處理流程可以分為 四個層次:
- 硬體層 (Hardware)
- 包含觸控螢幕、鍵盤、滑鼠、感測器等輸入裝置
- 事件會先送到 Linux Kernel Input Subsystem
- 核心層 (Kernel)
- 使用 evdev 驅動 將硬體事件封裝為 input_event 結構
- 事件會被寫入 /dev/input/* 節點
- Native Layer
- Android 提供 InputReader 與 InputDispatcher
- 這部分由 native C++ 層的 InputManager 實作
- 負責事件的讀取、封裝、分發
- 系統服務層 (System Server)
- InputManagerService (IMS) 作為 Java 層代理
- 與 WMS / AMS 協作,決定事件最終應該交給哪個視窗或 Activity
輸入架構示意圖:
[User Touch/Key]
│
▼
[Hardware Device] → [Linux Kernel Input Subsystem] → [/dev/input/*]
│
▼
[InputReader (Native)] → [InputDispatcher (Native)]
│
▼
[InputManagerService (Java)]
│
▼
[WMS / AMS] → [應用程式 View / Activity]
InputManagerService 的啟動與角色
- 啟動過程
IMS 與其他系統服務一樣,由 SystemServer 在開機時初始化:
inputManager = new InputManagerService(context);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
在此過程中:
- 初始化 Native InputManager → 建立 InputReader 與 InputDispatcher
- 啟動輸入線程 → 開始監聽 /dev/input/*
- 註冊到 ServiceManager → 讓其他服務(例如 WMS)可以與之交互
- IMS 的角色
IMS 主要扮演兩個角色:
- 事件橋樑:把 Kernel Input Event 轉換成 Android 的 KeyEvent / MotionEvent
- 分發協調者:根據 WMS 提供的窗口焦點資訊,決定事件應該送往哪個應用
輸入事件的流轉路徑
下面我們分別以 觸控事件 (TouchEvent) 和 按鍵事件 (KeyEvent) 來解析。
- TouchEvent 流程
步驟 1:硬體輸入
- 使用者手指觸碰螢幕,觸控控制器將訊號轉換為電壓變化
步驟 2:Kernel 層處理
- 驅動程式透過 evdev,將事件上報到 /dev/input/eventX
步驟 3:InputReader 讀取事件
- Native InputReader 從 /dev/input/* 讀取 raw event
- 將其轉換為 MotionEvent
步驟 4:InputDispatcher 分發事件
- InputDispatcher 查詢 焦點視窗 (Focus Window)
- 將事件投遞給對應的 Window
步驟 5:IMS 與 WMS 協作
- IMS 透過 Binder 請求 WMS,確認哪個視窗有焦點
- 一旦確定,事件會送到應用程序對應的 InputChannel
步驟 6:應用層處理
- ViewRootImpl 透過 InputChannel 接收事件
- 分發至 DecorView → ViewGroup → View 的事件分發機制
TouchEvent 流程示意圖:
Touch → /dev/input/eventX → InputReader
→ MotionEvent → InputDispatcher
→ IMS → 查詢 WMS 確定焦點視窗
→ InputChannel → ViewRootImpl
→ Activity → View 分發 (dispatchTouchEvent)
- KeyEvent 流程
KeyEvent 的處理流程與 TouchEvent 類似,差別在於事件類型:
步驟 1:硬體輸入
- 使用者按下實體鍵盤或虛擬按鍵
步驟 2:Kernel 層處理
- 驅動程式上報 key code 與按鍵狀態 (down / up)
步驟 3:InputReader 封裝事件
- 封裝為 KeyEvent
步驟 4:InputDispatcher 分發
- 查詢 WMS 確認當前焦點視窗
- 投遞給應用
步驟 5:應用層處理
- Activity.dispatchKeyEvent() → View.dispatchKeyEvent()
- 最終傳遞到 onKeyDown / onKeyUp
KeyEvent 流程示意圖:
Key → /dev/input/eventX → InputReader
→ KeyEvent → InputDispatcher
→ IMS → WMS 確認焦點視窗
→ InputChannel → Activity
→ dispatchKeyEvent → onKeyDown/onKeyUp
IMS 與 WMS 的協作
輸入事件的分發,離不開 WindowManagerService (WMS) 的協助。
- 為何需要 WMS?
因為輸入事件必須交給「正確的視窗」。
- 若使用者觸控 A 應用 → 事件應交給 A 的視窗
- 若 A 被 B 覆蓋(Dialog 或浮動視窗)→ 事件應交給 B
- IMS 與 WMS 協作流程
- InputDispatcher 準備分發事件
- 向 WMS 查詢目前焦點視窗
- WMS 回覆「哪個 Window 有 Input Focus」
- IMS 將事件投遞給該 Window 對應的 InputChannel
IMS(InputDispatcher) → 查詢 → WMS
← 回覆焦點視窗
IMS → 投遞事件至 InputChannel
questions
- TouchEvent 流程從硬體到 View.onTouchEvent()?
硬體輸入 → Kernel /dev/input → InputReader → MotionEvent
InputDispatcher → IMS → 查詢 WMS → 投遞 InputChannel
ViewRootImpl → DecorView → ViewGroup → View.dispatchTouchEvent → onTouchEvent
- KeyEvent 是如何傳遞到 Activity 的?
硬體事件 → Kernel → InputReader → KeyEvent
InputDispatcher → IMS → WMS → InputChannel
ViewRootImpl → Activity.dispatchKeyEvent → onKeyDown/onKeyUp
- 多點觸控 (Multi-Touch) 如何處理?
- InputReader 會把多個 pointer 的座標包裝在同一個 MotionEvent
- View 層可透過 MotionEvent.getPointerCount()、getX(i)、getY(i) 取得多點資訊
- 為什麼某些情況下事件會丟失?
- 應用未處於 foreground,WMS 判斷無焦點
- InputDispatcher 分發超時 (ANR)
- InputChannel 被關閉
summary
- InputManagerService (IMS) 是 Android 輸入系統的核心服務,扮演著事件「橋樑」與「分發協調者」的角色。
- 它與 InputReader / InputDispatcher 負責從 Kernel 讀取並分發事件
- 與 WMS 協作,決定事件應該送往哪個視窗
- 事件會抵達應用程式的 View 層,由開發者透過 dispatchTouchEvent / onTouchEvent / dispatchKeyEvent 來處理