### **概述**
在Android應用程序中,有一類特殊的消息,是專門負責與用戶進行交互的,它們就是觸摸屏和鍵盤等輸入事件。觸摸屏和鍵盤事件是統一由系統輸入管理器InputManager進行分發的。也就是說,InputManager負責從硬件接收輸入事件,然后再將接收到的輸入事件分發當前激活的窗口處理。此外,InputManager也能接收模擬的輸入事件,用來模擬用戶觸摸和點擊等事件。當前激活的窗口所運行在的線程接收到InputManager分發過來的輸入事件之后,會將它們封裝成輸入消息,然后交給當前獲得焦點的控件處理。
主要講Android應用程序輸入事件的分發和處理過程,主要涉及到輸入管理InputManager、輸入事件監控線程InputReader、輸入事件分發線程InputDispatcher,以及應用程序主線程消息循環。
* Android輸入系統概述
* 輸入管理器的啟動過程
* 輸入通道的注冊過程
* 輸入事件的分發過程
* 軟鍵盤輸入事件的分發過程
#### **Android輸入系統概述**
**輸入管理器框架**

**輸入管理器與應用程序通過輸入通道交互**

**輸入通道**

> 注:mFd指向的是一個socket
#### **輸入管理器的啟動過程**
**由System Server創建和啟動**

注:inputManager.setWindowManagerCallbacks:設置回調,例如用來截獲輸入事件
**創建InputManagerService**

**創建NativeInputManager**

**創建InputManager、InputReader和InputDispatcher,以及InputReaderThread、 InputDispatcherThread**

**啟動InputManagerService**

**啟動NativeInputManager**

**啟動InputManager**

**啟動InputDispatcher**
**InputDispatcher.dispatchOnce**

> 注:InputDispatcher負責分發IO事件,IO事件分為兩種類型。一種普通的輸入事件,另一種是輸入設備本身的事件,例如,輸入設備配置發生改變事件。普通的輸入事件由dispatchOnceInnerLocked處理,輸入設備事件由runCommandsLockedInterruptible處理。InputDispatcher本身也維護著兩個隊列,一個是mInboundQueue,保存的是普通的輸入事件,另一個是mCommandQueue,保存的是輸入設備事件。
**啟動InputReader**
* **InputReaderThread.threadLoop**

* **InputReader.loopOnce**

> 注:mNextTimeout:振動設備是按照一定的頻率來進行的,這個頻率就可以通過設置mNextTimeout來獲得
* **EventHub.getEvents**

* **EventHub.scanDevicesLocked**

> 注:虛擬鍵盤:設備不一定有鍵盤,但是程序在測試的時候時候需要模擬鍵盤輸入,這時候模擬的鍵盤輸入就看作是從虛擬鍵盤發出的。EventHub只存一定會存在虛擬鍵盤。
* **EventHub.scanDirLocked**

> 注:可以用getevent –i命令來查看/dev/input目錄下各個文件所對應的輸入設備信息
* **EventHub.openDeviceLocked**

> 注:Key Map Configuraton File和Configuration File:保存在/system/usr或者/data/system/devices目錄下
#### **輸入通道的注冊過程**
**Activity窗口的組成**

> 注:InputChannel是在應用程序請求WMS創建一個Activity窗口時創建的,也就是調用ViewRootImpl.setView開始創建的,在這個過程中,也會同時注冊InputChannel,包括Server端InputChannel和客戶端InputChannel
**創建InputChannel **
* **ViewRootImpl.setView**

> 注:mInputQueueCallback不等于null表示由view自己來接管輸入事件,否則的話就由ViewRootImpl來接管
* **Session.addToDisplay**

* **WMS.addWindow**

* **InputChannel.openInputChannelPair**

* **nativeOpenInputChannelPair**

* **InputChannel::openInputChannelPair**

**注冊Server端InputChannel**

> 注:win.mInputWindowHandle:窗口句柄,用來描述窗口的大小和位置等信息
* **IMS.registerInputChannel**

* **nativeRegisterInputChannel**

* **NativeInputManager.registerInputChannel**

* **InputDispatcher.registerInputChannel**

* **Looper.addFd**


**更新當前激活窗口**

* **WMS.updateFoucsedWindowLocked**

> 注:computeFocusedWindowLocked:從窗口堆棧從上到下搜索,如果它的宿主App是當前Focused的App,那么它就是Focused窗口。Focused App在窗口切換時已經確定
* **WMS. finishUpdateFocusedWindowAfterAssignLayersLocked**

* **InputMonitor.setInputFocusLw**

> 注:這里傳進來的參數updateInputWindows的值等于false,不會馬上調用updateInputWindowsLw來更新窗口,但是接下來新的窗口請求WMS進行layout時,就會調用updateInputWindowsLw來更新窗口
* **InputMonitor. updateInputWindowsLw**

>注: universeBackground:類型為TYPE_UNIVERSE_BACKGROUND的窗口
> TYPE_UNIVERSE_BACKGROUND的窗口:Behind the universe of the real windows, in multiuser systems shows on all users’windows
* **InputManagerService.setInputWindows**

* **nativeSetInputWindows**

* **NativeInputManager.setInputWindows**

* **InputDispatcher.setInputWindows**

**注冊Client端InputChannel**

* **new WindowInputEventReceiver **

* **new InputEventReceiver **

* **nativeInit**

* **NativeInputEventReceiver.initialize**

> 注:IO事件發生時, NativeInputEventReceriver::handleEvent將被調用
#### **輸入事件的分發過程**
**輸入事件處理框架**

**InputReader獲得輸入事件**
* **InputReader獲得輸入事件--EventHub.getEvents**

* **InputReader獲得輸入事件 – InputReader.loopOnce **

* **InputReader獲得輸入事件 – InputReader.processEventsLocked **

* **InputReader獲得輸入事件 – InputReader.processEventsForDeviceLocked**

* **InputReader獲得輸入事件—InputDevice.process**

* **InputReader獲得輸入事件—KeyboardInputMapper.process**

* **InputReader獲得輸入事件—KeyboardInputMapper.processKey**

* **InputReader獲得輸入事件—InputDispatcher.notifyKey**

* **InputReader獲得輸入事件—InputDispatcher. enqueueInboundKeyLocked**

**InputDispatcher分發鍵盤事件**
* **InputDispatcher分發鍵盤事件 – InputDispatcher. dispatchOnceInnerLocked**

* **InputDispatcher分發鍵盤事件 – InputDispatcher. dispatchKeyLocked**

> 注:
> HOME鍵會被PhoneWindowManager的成員函數interceptKeyBeforeDispatching攔載,切換至Home App,這是通過post一個command到InputDispatcher的Command Queue去執行實現的
> findFocusedWindowTargetsLocked – 會調用checkInjectionPermission來檢查當前處理的鍵盤事件是否是注入的,如果是的話,再檢查注入者是否有權限。注入事件的時候也會做權限檢查。
> 注入輸入事件:
> 1. InputManagerService.injectInputEvent
> 2. InputDispatcher::injectInputEvent
> findFocusedWindowTargetsLocked還會檢查上次分發給Target Window的輸入事件是否已經有5s內處理完成,沒有處理完成的話就會產生一個ANR Command,并且post到InputDispatcher的Command Queue去執行,最終的ANR窗口是通過mPolicy來通知AMS彈出的
* **InputDispatcher分發鍵盤事件 – InputDispatcher.dispatchMotionLocked**

* **InputDispatcher分發鍵盤事件-- InputDispatcher.dispatchEventLocked**

* **InputDispatcher分發鍵盤事件-- InputDispatcher.prepareDispatchCycleLocked**

> 注:標志位的解釋參見InputDispatcher.h
* **InputDispatcher分發鍵盤事件-- InputDispatcher.startDispatchCycleLocked**

* **InputDispatcher分發鍵盤事件—InputPublisher.publishKeyEvent**

* **InputDispatcher分發鍵盤事件— InputChannel::sendMessage**

**App獲得鍵盤事件**
* **App獲得鍵盤事件— NativeInputEventReceiver.handleEvent**

>注: 應用程序可以通過InputEventReceiver.nativeConsumeBatchedInputEvents來批量處理InputDispatcher分發過來的輸入事件
* **App獲得鍵盤事件—NativeInputEventReceiver.consumeEvents**

>注: InputConsumer.consumer的返回值等于WOULD_BLOCK時表示當前沒有發生輸入事件,這時候就會開始批量處理剛才緩存起來的輸入事件
* **App獲得鍵盤事件—InputComsumer.consume**

> 注:AMOTION_EVENT_ACTION_MOVE和AMOTION_EVENT_ACTION_HOVER_MOVE類型的事件會被緩存起來批量處理
* **App獲得鍵盤事件—InputChannel.receiveMessage**

* **App獲得鍵盤事件—InputEventReceiver.dispatchInputEvent**

* **App獲得鍵盤事件—WindowInputEventReceiver.onInputEvent**

* **App獲得鍵盤事件—ViewRootImpl.enqueueInputEvent**

**App獲得鍵盤事件—ViewRootImpl. scheduleProcessInputEvents**

* **App獲得鍵盤事件—ViewRootImpl. doProcessInputEvents**

* **App獲得鍵盤事件—ViewRootImpl. deliverInputEvent**

* **App獲得鍵盤事件—ViewRootImpl. deliverKeyEvent**

* **App獲得鍵盤事件—InputMethodCallback. finishedEvent**

* **App獲得鍵盤事件—ViewRootImpl.dispatchImeFinishedEvent**

* **App獲得鍵盤事件—ViewRootImpl. handleImeFinishedEvent**

* **App獲得鍵盤事件—ViewRootImpl. deliverKeyEventPostIme**

* **App獲得鍵盤事件—DecorView. dispatchKeyEvent**

>注: getCallback返回的Callback接口指向當前Activity
> PhoneWindow.onKeyDown和PhoneWindow.onKeyUp會對MENU和BACK等實體鍵進行處理,對MENU鍵的處理對應于openPanel的實現,對BACK鍵的處理對應于closePanel的實現
* **App獲得鍵盤事件—Activity.dispatchKeyEvent**

> 注:getWindow獲得的是一個PhoneWindow
* **App獲得鍵盤事件—PhoneWindow.superDispatchKeyEvent**

>注: DecorView.dispatchKeyEvent將KeyEvent分發給當前獲得焦點的View處理
**在App中,依次獲得鍵盤事件的順序**
* View(Pre Input Method)
* Input Method
* View(Post Input Method)
* Activity
* Phone Window(處理MENU、BACK等按鍵)
**HOME按鍵被PhoneWindowManager攔截,直接切換至Home App**
**TextView、輸入法和輸入法管理器的關系**

**輸入法通過InputConnection.commitText分發過來的字符被封裝成一個類型為FLAG_DELIVER_POST_IME的KeyEvent**
**在ViewRootImpl中,類型為FLAG_DELIVER_POST_IME的KeyEvent不用經過輸入法處理,而直接通過deliverKeyEventPostIme分發給View Hierarchy處理**
**deliverKeyEventPostIme的處理過程與實體 鍵經過輸入法處理后的過程是一樣的**
* View
* Activity
* Phone Window
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析