Android input events 輸入系統(tǒng)

前言

本文代碼基于 Android 12 脊串。

概述

Android 的事件輸入可以簡化為三部分:

  1. 物理輸入設(shè)備 -> InputDispatcher
  2. InputDispatcher -> ViewRootImpl
  3. ViewRootImpl 事件派發(fā)

物理輸入設(shè)備 -> InputDispatcher

這一部分主要有三個流程:

  1. 物理輸入設(shè)備 -> 標準的 Linux 輸入事件
  2. 標準的 Linux 輸入事件 -> Android 輸入事件
  3. Android 輸入事件 -> Android 顯示器上的窗口

物理輸入設(shè)備 -> 標準的 Linux 輸入事件

這一部分主要由 Linux 內(nèi)核中的輸入設(shè)備驅(qū)動程序完成:
物理設(shè)備生成輸入事件信號后匆光,會由設(shè)備固件編碼成設(shè)備特有的事件信號撑教,并傳輸給 Linux 系統(tǒng)则吟,再由 Linux 內(nèi)核中的輸入設(shè)備驅(qū)動程序解碼成標準的 Linux 輸入事件格式垦垂。

標準的 Linux 輸入事件 -> Android 輸入事件

這一部分主要由 Android InputReader 實現(xiàn):
Android EventHub 組件會打開與每個輸入設(shè)備關(guān)聯(lián)的 evdev 驅(qū)動程序并從 Linux 內(nèi)核中讀取這些標準的輸入事件痹升,再由 Android InputReader 組件根據(jù)設(shè)備類別解碼成 Android 定義的事件阿迈。

Android 輸入事件 -> Android 顯示器上的窗口

該部分主要由 Android InputDispatcher 組件完成:
Android InputReader 會把生成的 Android 輸入事件流發(fā)送給 InputDispatcher 攻谁,然后由 InputDispatcher 將這些事件轉(zhuǎn)發(fā)給對應(yīng)的窗口稚伍。

如圖:


輸入管道

根據(jù)物理輸入設(shè)備的不同,Android 輸入事件主要分為 KeyEvent 和 MotionEvent 戚宦。


MotionEvent && KeyEvent

所以用來上傳 KeyEvent 的設(shè)備有物理鍵盤設(shè)備个曙、DPad 等。而上傳 MotionEvent 的設(shè)備有顯示屏設(shè)備受楼、鼠標垦搬、手寫筆等。

InputDispatcher -> ViewRootImpl

InputDispatcher 是怎么把事件轉(zhuǎn)發(fā)給對應(yīng)的窗口呢艳汽?
答:app 在向系統(tǒng)添加窗口時猴贰,會和系統(tǒng)進程建立 socket 連接,系統(tǒng)進程將 service 端的 socket 傳送到 InputDispatcher 河狐,把 client 端的 socket 返回給 app 米绕。當事件到達時,InputDispatcher 找到此時具有焦點的窗口馋艺,通過 socket 把事件發(fā)送該 socket 栅干。

如圖:
InputDispatcher -> ViewRootImpl

在此過程中,socket 會被封裝成 InputChannel :


InputChannel

設(shè)置 InputChannel 的流程:


設(shè)置 InputChannel

可以看到捐祠,在添加窗口時碱鳞,IMS 向 linux 系統(tǒng)請求創(chuàng)建一對 socket 并封裝成 InputChannel ,server 端的留在 InputDispatcher 雏赦,client 端的傳送給 app 端的 ViewRootImpl 劫笙。因此 events 可以直接從 InputDispatcher 分發(fā)給對應(yīng)的 ViewRootImpl 芙扎。
簡述:
InputDispatcher 和 窗口通過 InputChannel 交互

那剩下就是如何找到合適的窗口(ViewRootImp)派發(fā)事件?
答:InputDispatcher 保存了系統(tǒng)中每個窗口 layer 的信息填大,包括這個窗口是否可見戒洼、是否可以接收輸入事件、是否聚焦等允华。在事件派發(fā)時圈浇,只要找到當前聚焦的窗口的 InputChannel 并通過它發(fā)給目標窗口即可。而窗口的信息由 WMS 通過 InputMonitor 更新到 InputDispatcher 中靴寂。如圖:


WMS -> InputMonitor -> InputDispatcher 設(shè)置 InputWindowHandle

其中聚焦的信息封裝在 FocusRequest 中:
FocusRequest

其流程可概括為:
設(shè)置 focused app 和 window 流程

具體流程為:
設(shè)置 focused window

總結(jié)磷蜀,InputDispatcher 和 ViewRootImpl 之間的交互過程如圖:


InputDispatcher ViewRootImpl 事件交互

具體流程為:


InputDispatcher 事件派發(fā)

ViewRootImpl 事件派發(fā)

窗口是怎么把事件轉(zhuǎn)發(fā)給正確的 view 呢?
答:ViewRootImpl 封裝了一系列的 InputStage 來處理輸入事件百炬,這些 InputStage 組成鏈式結(jié)構(gòu)褐隆,如果上一個節(jié)點的 InputStage 沒處理則傳給下個節(jié)點處理。在 InputStage 中通過事件類型來區(qū)分怎么處理剖踊,一般來說 Listener 比 View 先處理庶弃。如,事件為 KeyEvent 時德澈,OnKeyListener 先處理歇攻,再是 View 處理 onKeyDown、onKeyUp 等梆造。
簡要概括流程為:


app 分配 input event 流程

其中 InputStage 的處理順序為:


ViewRootImp InputStage 處理順序

事件類型分為:
事件類型

以 pointer 事件和 key 事件為例其具體流程如下:
ViewRootImpl 派發(fā)事件流程

總結(jié)

簡要概述一下 Android 事件的流程就是:

  1. Linux 內(nèi)核中的輸入設(shè)備驅(qū)動程序?qū)⑽锢磔斎朐O(shè)備產(chǎn)生的輸入信號轉(zhuǎn)換成標準 Linux 輸入事件格式缴守;
  2. Android EventHub 組件打開與每個輸入設(shè)備關(guān)聯(lián)的 evdev 驅(qū)動程序,并從 Linux 內(nèi)核中讀取已轉(zhuǎn)成標準 Linux 輸入事件格式的輸入信號镇辉,再通過 Android 的 InputReader 組件轉(zhuǎn)碼成 Android 事件輸入流并發(fā)送給 InputDispatcher屡穗。
  3. InputDispatcher 將事件通過 socket 發(fā)送給系統(tǒng)當前聚焦的窗口。
  4. 窗口將事件派發(fā)給需要處理這個事件的 view摊聋,如 Touch Event 派發(fā)給當前 window 中管轄觸摸點 [x,y] 的最小的可接收事件的 View 鸡捐,而 Key Event 派發(fā)給當前窗口中聚焦的 View 栈暇。

參考

Android 官方:輸入
《深入理解 Android 內(nèi)核設(shè)計思想》上麻裁,著:林學(xué)森
Android 官方代碼

原創(chuàng)文章,歡迎轉(zhuǎn)載源祈,但請注明出處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煎源,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子香缺,更是在濱河造成了極大的恐慌手销,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件图张,死亡現(xiàn)場離奇詭異锋拖,居然都是意外死亡诈悍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門兽埃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侥钳,“玉大人,你說我怎么就攤上這事柄错∠隙幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵售貌,是天一觀的道長给猾。 經(jīng)常有香客問我,道長颂跨,這世上最難降的妖魔是什么敢伸? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮恒削,結(jié)果婚禮上详拙,老公的妹妹穿的比我還像新娘。我一直安慰自己蔓同,他們只是感情好饶辙,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著斑粱,像睡著了一般弃揽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上则北,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天矿微,我揣著相機與錄音,去河邊找鬼尚揣。 笑死涌矢,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的快骗。 我是一名探鬼主播娜庇,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼方篮!你這毒婦竟也來了名秀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤藕溅,失蹤者是張志新(化名)和其女友劉穎匕得,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巾表,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡汁掠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年略吨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片考阱。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晋南,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出羔砾,到底是詐尸還是另有隱情负间,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布姜凄,位于F島的核電站政溃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏态秧。R本人自食惡果不足惜董虱,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望申鱼。 院中可真熱鬧愤诱,春花似錦、人聲如沸捐友。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匣砖。三九已至科吭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間猴鲫,已是汗流浹背对人。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拂共,地道東北人牺弄。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像宜狐,于是被迫代替她去往敵國和親势告。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容