成鵬致遠|2013-10-25node
1.linux輸入子系統設備是基於平臺設備機制的,因此先回顧平臺設備機制,主要回顧後面用獲得的東西linux
1.申請主設備號
2.建立cdev->將cdev掛載到系統設備哈希鏈表中,同時生成inode節點
3.建立device->將device與剛生成的inode節點關聯起來,爲上層調用提供接口app
2.註冊輸入子系統設備框架
1.建立一個設備類class
2.申請主設備號
3.建立cdev->將cdev掛載到系統設備哈希鏈表中,同時生成inode節點
4.建立input_device->將input_device與剛生成的inode節點關聯起來,爲事件驅動層提供接口ide
1.註冊設備支持輸入事件類型(type)->【這個後面會用到】
2.註冊設備支持輸入事件編碼
3.生成/dev/input_device函數
5.當input_device與input_hander匹配成功oop
1.生成/dev/input*
2.上層應用經過主設備號打開/dev/input,經過次設備號打開/dev/input_device編碼
3.輸入子系統部分函數spa
1.read函數->讀【後面會用到】
2.write函數->寫【後面會用到】
3.event函數->上報事件【後面會用到】線程
1.Android事件處理系統是怎麼捕捉到輸入事件的?
2.Android上層應用是怎麼捕捉到輸入事件的?
3.Android上層應用捕捉到輸入事件是怎麼響應的?
1.Activity啓動流程:onCreate()->onStart()->onResume()->Activity Running
【Q1】:爲何onStart()後不直接Running,要插入一個onResume(),在onResume()中系統做了什麼事情?
<A1>:在onResume()中,系統會爲該Activity建立一個ViewRoot!
【Q2】:這個ViewRoot有什麼用?它作了哪些事情?這個後面解答
1.Activity運行時,用戶點擊觸摸屏操做->{事件產生}
1.點擊觸摸屏,必然會調用觸摸屏驅動->{事件輸入}
【Q3】:事件傳遞過程?->{事件傳遞}
<A3>:如下全部步驟!
1.Android上層應用調用Framework層的JNI本地方法->{事件消息傳遞到JNI層}
1.實現JNI層方法,填充本地方法映射表,實現提供Android上層應用的接口
2.生成so動態連接庫文件,adb push到/system/lib目錄下
2.JNI本地方法調用HAL層(硬件抽象層:中間件)方法->{事件消息傳遞到HAL層}
1.JNI層經過指定ID獲得HAL模塊實例,而後調用HAL層函數
2.生成so動態連接庫文件,adb push到/system/lib/hw目錄下
3.HAL經過系統調用write進入內核層->{事件消息傳遞到內核}
1.copy_from_user()取得用戶層數據
2.調用input_device.write->{(1.1.2):事件消息傳遞到驅動層}
------------------------------------------------------------------------------------------
4.輸入設備驅動獲取事件,調用event函數->{(1.1.3)}
5.事件處理層根據事件類型進行上報->{事件消息傳遞到內核事件處理層}
1.調用input_event(device,type,code,value)->{【type】後面會用到}
6.到事件處理層時,內核會喚醒read函數->{(1.1.1):事件消息傳遞到內核層}
1.經過copy_to_user()將內核數據傳遞到用戶空間->{事件消息傳遞到用戶空間}
【Q4】:read函數被誰調用的?
7.事件消息被Android的事件處理系統捕捉到->{事件消息傳遞到Android事件處理系統}
1.Android事件處理系統將這個消息發送到Android應用層
【Q5】:事件消息在Android事件處理系統中是怎麼傳遞的?
8.Android上層獲取事件消息,根據事件類型(3.1.1.5.1:type)響應上層View相應回調函數
9.Android界面UI更新->{事件響應}
1.Android事件處理系統做爲一個黑盒子,暫時略過
2.切入到項目解讀:×××遠程遙控器
1.客戶端APK
1.數據採集->{此數據必須與Linux輸入子系統兼容,這樣才能達到欺騙系統的目的}
2.數據傳遞
2.服務端APK->{實現二個虛擬設備(虛擬鍵盤設備與虛擬鼠標設備}
1.接收數據
2.將數據傳送到虛擬設備
3.虛擬設備上報事件,欺騙系統輸入事件發生
【Q5】:事件消息在Android事件處理系統中是怎麼傳遞的?
<A5>:看看Android的事件處理系統
1.緊接着3.1.1.7,事件消息傳遞到Android事件處理系統
2.在Android開機時,系統服務(System Server)會初始化Android窗口管理服務(WindowManagerService)
3.WMS服務會初始化InputManager(InputManager是Framework層的一個C++類,負責管理全部的輸入事件的捕獲與轉發)
1.在InputManager構造函數中,會初始化事件處理系統中最重要的三個類(InputReader/InputDispatcher/EventHub)
2.而後初始化InputManager(InputManager.initialize()),產生兩個線程(InputReaderThread/InputDispatcherThread,分別負責事件捕獲與事件轉發)
3.InputReaderThread線程工做->{解決問題1:Android事件處理系統是怎麼捕捉到輸入事件的}
1.調用InputReader::loopOnce(),在InputReader類中,已經實現looper機制,循環操做
1.調用EventHub::getEvent()函數
1.調用Epoll_wait()函數
1.在Epoll_wait()函數中,會去循環讀取全部的/dev/input設備,一旦有事件產生,就會被此函數捕捉到
【Q6】:Android事件處理系統與/dev/input設備是如何關聯起來的
【A6】:EventHub::Device <---->/dev/input,一一對應關係
2.當有事件發生時,Android事件處理系統會調用read函數->{系統調用,從內核層拿到事件消息}
【Q4】:read函數被誰調用的?
<A4>:read函數是InputReader調用的
2.將從內核層讀取到的事件消息(input_event)保存到RawEvent中
2.根據事件類型(input_event.type)調用相應的消息轉換器(InputMapper)
1.Android系統目前支持5種事件消息(翻滑蓋/軌跡球/多點觸摸/單點觸摸/鍵盤)
3.InputReader::InputDevice::inputMapper將RawEvent事件轉換成對應的Notifyargs
1.InputMapper將RawEvent事件轉換成對應的Notifyargs類
2.將Notifyargs加入到InputRead::QueueListener::argsQueue隊列中
4.調用InputReader::QueueListener::flush()函數,處理隊列中的事件消息
5.調用Notifyargs::notify函數,將事件消息轉換成對應的EventEntry再轉交給InputDispatcher
1.對事件進行預處理
1.判斷是否丟棄此事件消息
1.丟棄,則直接返回
2.不丟棄
2.獲取當前Activity對應的Connection對象->(這個後面再講)
2.將對應的EventEntry加入到InputDispatcher::OutBoundQueue隊列中
【Q7】:在Notifyargs是怎麼獲取InputDispatcher實例的
<A7>:在初始化InputRead::QueueListener::argsQueue隊列時,將InputDispatcher對象傳遞過來了
6.喚醒InputDispatcher::pollOnce()函數
4.InputDispatcherThread線程工做
1.調用InputDispatcher::loopOnce(),在InputDispatcher類中,一樣實現looper機制,循環操做
1.調用pollOnce()函數,輪詢InputDispatcher::OutBoundQueue隊列
1.隊列中的有事件消息
2.被Notifyargs::notify()函數喚醒
2.調用對應的InputDispatcher::dispach函數
1.從InputDispatcher::OutBoundQueue隊列中取得EventEntry對象
2.將EventEntry對象轉換成DispatchEntry對象
3.將DispatchEntry對象加入到InputChannel::Connection::outboundQueue隊列中
【Q8】:這個InputChannel::Connection對象是從哪裏來的?有什麼用?
【Q9】:如今InputDispatcher獲得了轉換後的事件消息,即將要發出去,可是往哪裏發?
<A9>:要解決這個問題,須要回到【Q2】
4.【Q2】:ViewRoot有什麼用?它作了哪些事情?->{解決問題2:Android上層應用是怎麼捕捉到輸入事件的?}
<A2>:1.首先,ViewRoot是一個Hander,與當前Activity綁在一塊兒的
2.ViewRoot有一個重要的做用:與WMS通訊,完成整個GUI窗口系統的繪製
3.建立ViewRoot的時候作了哪些事情?如今來解決問題2:Android上層應用是怎麼捕捉到輸入事件的?
1.由前面分析知道,Android的事件輸入來自InputManager,因此ViewRoot須要與InputManager通訊
【Q10】:ViewRoot怎麼與InputManager通訊並取得事件消息?
<A10>:ViewRoot與InputManager之間有一個共享內存(ShareMemory)
1.InputManager::InputDispatcher將最後的事件消息發送到共享內存(ShareMemory)中
2.ViewRoot在知道有事件消息到來時,就去共享內存(ShareMemory)中取此事件消息
【Q11】1.ViewRoot怎麼知道有事件消息到來?
<A11>:1.ViewRoot與InputManager是經過管道通訊的機制來傳遞消息的
1.在建立ViewRoot後,會建立兩個InputChannel類對象
1.其中一個InputChannel對象註冊到NativeInputQueue中,與ViewRoot綁在一塊兒
【Q12】這個NativeInputQueue是用來幹什麼的?
<A12>:這個NativeInputQueue是Android系統用來維護事件接收的,由於同一時刻,會有不少Activity在等待事件輸入
2.另外一個InputChannel對象註冊到InputManager類對象中
2.同時會申請上面用到的的共享內存
3.InputChannel類主要封裝管道描述符和共享內存的描述符等信息
1.在ViewRoot與InputManager中各註冊了一個InputChannel類對象,其中各有兩個管道描述符
1.兩個InputChannel對象中都包含一個讀和一個寫描述符
2.因此在ViewRoot與InputManager以前完成了全雙工的通訊【後面會用到】
【Q13】:在Android中,每建立一個Activity,就會建立一個ViewRoot,因此也會建立一個InputChannel對象,那Android系統怎麼來區分這些Activity?
<A13>:還記得【Q8】嗎,兩個問題一塊兒解決:InputChannel::Connection對象是從哪裏來的?有什麼用?
1.爲了區分不一樣的Activity,NativeInputQueue類中定義了一個子類Connection
2.在註冊InputChannel對象時,每一個InputChannel對象中都建立了一個Connection對象
1.因此ViewRoot中的每一個InputChannel與InputManager中的InputChannel都包含一個Connection對象
2.這個Connection對象標識了不一樣的Activity
4.到如今咱們就能夠回到【Q9】了
5.【Q9】:如今InputDispatcher獲得了轉換後的事件消息,即將要發出去,可是往哪裏發?
<A9>:1.由上面的分析,咱們知道如今須要將事件消息發送給ViewRoot
1.調用InputChannel::Connection::inputPublisher.publishMotionEvent函數將事件消息發送到共享內存(ShareMemory)
2.InputChannel對象向寫管道發送一個dispatch信息
6.如今工做就該轉移到ViewRoot這邊了
【Q14】:在NativeInputQueue中有不少InputChannel對象,究竟哪一個InputChannel的管道會收到信息?
<A14>:還記得【Q13】嗎,InputManager的InputChannel對象是由ViewRoot建立後註冊過去的
1.在每一個註冊的InputChannel對象中,都包含了一個Connection對象
2.InputManager的InputChannel對象的Connection對象<--->NativeInputQueue中的InputChannel對象的Connection對象,是一一對應的關係
3.因此與InputDispatcher中Connection對象相對應的那個Connection對象將收到管道信息
1.相應的InputChannel對象的Connection對象收到管道信息
2.調用InputChannel::Connection::inputConsumer到共享內存(ShareMemory)中取得事件消息
3.InputChannel再向寫管道中發一個信息,表示此事件已經取得
4.而後InputManager中的InputChannel將會收到管道消息,再繼續進行下一輪事件處理
7.到此爲止,事件消息已經傳遞到NativeInputQueue中的InputChannel對象中
1.由前面分析,NativeInputQueue中的每一個InputChannel對象都對應一個Activity
2.NativeInputQueue中InputChannel對象是在ViewRoot建立以後建立的,也就是咱們的Activity啓動以前
【Q15】:如今Activity關聯的InputChannel對象拿到的這個事件消息,可是怎麼處理呢?如今咱們就來回答問題3:Android上層應用捕捉到輸入事件是怎麼響應的?
<A15>:這個須要回到ViewRoot端InputChannel對象註冊的時候,也就是【Q11】的位置
1.ViewRoot端InputChannel對象在向NativeInputQueue註冊時,須要註冊3個參數
1.其中有一個參數就是ViewRoot的成員變量InputHandler
1.InputHandler就是事件的處理函數,也就是所謂的回調函數
2.傳遞它的做用主要是明確當前ViewRoot的事件處理函數
3.當InputChannel對象取得事件後,就會去調用ViewRoot的InputHandler函數-{到此爲止,事件消息就傳遞迴了Android應用層}
【Q16】:這個回調函數究竟是什麼?
<A17>:這個回調函數大多被Android系統實現成抽象函數
1.在咱們的×××遠程遙控器的客戶端,就重寫了對應的方法,用來獲取咱們須要的數據,好比onScroll/onLongPress等