Android Input 子系统初探
Android系統基于Linux內核實現,內核作為整個操作系統的核心,對下,它負責整個硬件的驅動、實現對硬件器件的控制管理;對上,它提供各種系統所需的核心功能。Android系統支持的輸入設備較多,如按鍵、觸摸屏、手柄等,面對種類繁雜的輸入設備,內核通過抽象化的方式來使得各輸入設備的的核心處理流程統一化,細節處理流程差異化(通過不同類型的回調實現),這就是Input子系統所要完成的內容,總結來說,它在內核中主要作用為:
規范化Input Device的定義方式及其數據的上報格式;
規范化Input Handler的定義方式及其需要實現的回調;
為Input Device和Input Handler提供核心服務;
提供標準化用戶空間接口;
圖1 Input事件處理整體框圖
整體的Input事件處理框圖如圖1所示,本文主要圍繞這張圖來詳述Input子系統的各個方面,如定義、初始化、注冊匹配、事件傳遞、與用戶空間的交互等。介于本人理解有限,如有敘述不當的地方,還請諒解指出。
一.Input子系統相關定義
在前序內容中,我們提前用到了Input Device、Input Handler等名詞,但還沒有進行相關的解釋說明。本節的內容旨在了解Input子系統中幾個重要的結構體定義,以便于Input子系統的后續介紹。
1.?Input_dev
struct input_dev用來抽象所有的輸入設備,由于不同的輸入設備上報的事件或形式存在差異,抽象的input_dev必然需要包含差異的內容,形成一種x+(y1、y2、y3..)的方式(其中,x為所有輸入設備共有的成員,y1/y2/y3為輸入設備差異化成員),所以在實際的特定輸入設備驅動開發工作中,只需要填充部分成員即可完成input_dev的定義。詳細的成員定義說明如下:
2.?Input_handler
struct input_handler用于抽象事件處理,不同的輸入設備對應的事件處理方式會存在差異,linux內核抽象該結構體保證input事件的處理流程一致,具體的實現部分通過input_handler的函數指針回調完成,主要包括匹配、建立連接、事件傳遞/過濾等,具體的成員說明如下:
3.?Input_handle
在抽象input_dev和input_handler之后,我們知道一個input_dev上報的事件可以被多個input_handler接收處理,一個input_handler也可以處理多個input_dev上報的事件,這樣多個input_dev和多個input_handler之間可能會形成交織的網狀(如下圖2)。在這種情況下,需要一個橋梁來搭建兩者之間的聯系,兩邊的函數調用都可以通過這個“中介”進行,input_handle就是這個橋梁。
圖2 device與handler示意圖
Input_handle的定義比較簡單,各成員說明如下:
二.Input子系統相關流程
主要流程包括input core初始化、input設備注冊、input_handler注冊、input設備與input_handler匹配、input事件傳遞。
1.?input core初始化
Input core通過sybsys_initcall注冊設定啟動等級,保證其初始化會早于input設備和input_handler的注冊(module_init方式注冊),在初始化過程中主要完成:
1)input類注冊;
2)Proc文件創建,主要用于input_handler和devices信息查看;
3)注冊字符設備,主設備號為13;
2.?input_dev注冊
一般而言,Input設備驅動需要完成設備的控制和響應上報,其中響應上報是通過注冊的input_dev來完成,所以input_dev的注冊需要在input設備驅動的初始化過程中調用input_register_device完成,input_register_device執行的過程說明如下:
3.?input_handler注冊
Input handler的注冊相對于input設備的注冊更為簡單,在填充struct input_handler后,直接調用input_register_handler完成handler的注冊,input_register_handler的處理流程如下:
4.?input_handler與input_dev匹配
Input_handler與input_dev的注冊最終都會調用input_attach_handler完成自己與“相親對象”的配對,配對完成后input_dev、input_handler、input_handle之間的關系如圖3所示,設備驅動和事件處理層驅動都可以通過自身訪問到input_handle,然后通過input_handle訪問到自己的“對象”,具體的匹配代碼說明如下:
圖3 input_handle與owner關系圖
當handler中match回調沒有實現時只用根據input_dev中的id與input_handler中id_table包含的id進行匹配,如evdev_handler匹配所有Input設備,故所有的input設備都可以通過dev/input/event*路徑獲取原始上報數據。
在匹配成功后會調用connect回調,舉例evdev_handler中的connect內容如下:
5.?Input事件傳遞
不同的input設備上報的input事件的格式不同,比如觸摸屏上報input事件時一般需要上報手指的id、x坐標、y坐標等信息(如圖4為B協議報點格式, A協議報點無需上報id,會在inputReader中重新分配)。
圖4 觸摸屏報點事件格式
每一個事件上報都是通過input_event接口來完成,在判定事件類型是否支持后,主要是調用input_handle_event來完成:
該接口中,首先根據type、code判定該事件的disposition,當disposition為INPUT_PASS_TO_DEVICE時,將該事件傳遞給input_dev設備自身的event函數處理;當disposition為INPUT_PASS_TO_HANDLERS時,即將該事件傳遞給事件處理層處理,此處一般是將所有的事件存儲在dev的vals數組中(此處,在disposition為INPUT_SLOT時表明上次處理的點與本次不同,故多添加一個ABS_MT_SLOT事件);當disposition為INPUT_FLUSH時或者傳遞的事件達到數組的極限時才將事件傳遞給事件處理層處理( input_sync時,disposition才能取得INPUT_FLUSH這個值)。
input_get_disposition函數是將根據type和code判定事件的disposition,此處只關心EV_SYN、EV_KEY、EV_ABS事件。EV_KEY事件中當設置了按鍵自動重發時的value值為2,!!test_bit(code, dev->key) != !!value語句中都進行了兩次取反操作是為了避免出現0、1之外的數據,如果本次上報的按鍵事件與上次不同才會進行上報給事件處理層(dev->key保存了最近按鍵事件的所有狀態),否則不予處理。
在收到sync事件或者event buffer size接近最大值時開始同步事件,此時傳遞的為一包事件,input_pass_values接口主要是尋找input_dev設備對應的handle處理存儲的數據,另外設置的輸入設備支持EV_REP事件,則會在此處設置定時器自動重發按鍵事件(按鍵值為2)。
所有的input設備都會和evdev_handler匹配,此處假設匹配的handler為evdev_handler,則events指向的函數為evdev_events:
evdev_pass_values只是將傳過來的所有事件存儲在client->buffer中;kill_fasync函數用于發送通知事件,告訴上層client->buffer中有數據可以讀了。
6.?Input事件傳遞給用戶空間
當應用層或框架層調用read函數讀取/dev/input/event*文件時,會調用evdev_read返回數據,其中event_fetch_next_event是判斷client->buffer這個循環緩沖區中的頭尾指針是否相等(相等時buffer中沒有數據),不相等時取出一個input_event類型的事件放入到event中;input_event_to_user函數是將此事件copy到應用層,input_event_size函數是用來獲取一個input_event事件的大小,循環復制client->buffer中的事件到應用層的buffer中。
上層誰會來打開文件讀這些事件?一種是getevent工具,另外一種是android框架層的inputflinger服務,其主要會創建InputReader和InputDispatcher兩個線程。InputReader負責與底層的事件打交道,其先通過eventHub讀取所有的事件, 然后通過設備屬性或事件特征找到對應的mapper處理將底層事件轉換為android設計的事件類型;InputDispatcher負責與窗口打交道,將收到的事件派發給對應注冊的窗口。
參考文獻
1.?https://www.cnblogs.com/lifexy/p/7542989.html
2.?https://blog.csdn.net/qq_39937242/article/details/82631165
推薦閱讀:
? ??專輯|Linux文章匯總
? ??專輯|程序人生
? ??專輯|C語言
嵌入式Linux
微信掃描二維碼,關注我的公眾號?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Android Input 子系统初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Activiti6 下载安装
- 下一篇: Activiti学习记录 Activit