天天看點

Android系統--輸入系統(十六)APP跟輸入系統建立聯系_InputChannel和Connection

Android系統--輸入系統(十六)APP跟輸入系統建立聯系_InputChannel和Connection

0. 核心:socketpair機制

1. 回顧Dispatch處理過程:

1.1 放入隊列前稍加處理

  • 分類:Global Key/System Key/User Key
  • 處理緊急事件(比如來電的時候按下音量鍵靜音)

1.2 InputReader線程将讀到的輸入事件稍加處理後放入mInboundQueue隊列中,接着喚醒Dispatch線程

1.3 Dispatch從mInboundQueue隊列中将輸入事件取出,并稍加處理。

  • 對于Global Key/System Key按鍵處理:放入mCommandQueue隊列中,依次處理,處理之後就release
  • 對于User Key,放入隊列:查找目标APP,得到Connection,放入其OutBoundQueue隊列中,稍後取出處理

2. 引入--如何找出目标應用程式,輸入系統和應用程式如何建立聯系?

PC和安卓系統都是運作着多個應用程式,但是隻有螢幕最前面的應用程式才可以接收到輸入事件,誰來告訴輸入事件哪個是運作在螢幕最前面的應用程式呢?

2.1 引入WindowServiceManager視窗管理服務

  • 對于每一個應用程式,WindowServiceManager都有一個結構體WindowSate來表示該應用程式。假設新啟動一個APP,通過binder通信,調用addToDisplay,會導緻AddWindow被調用,AddWindow建立了WindowSate表示該應用程式,接着建立一個socketpair得到兩個檔案句柄fd0和fd1,fd1直接傳回給應用程式,fd0将其封裝為InputChannel類,一方面InputChannel會放進該APPWindowState中,另外一方面,他會将InputChannel注冊給InputDispatch。

2.2 Dispatch線程

  • InputDispatch線程中裡面有KeyedVector包含含有多個connection,這些connection可以通過注冊實作,建立一個connection(含有InputChannel,InputChannel含有檔案句柄fd),将建立好的connection放入Vector當中。
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd;                

2.3 引入connection

  • 對于每一個能夠接受輸入事件應用程式,在InputDispatch當中都有一個connection。假設還有一個應用程式APP,在WindowServiceManager中也有一個WindowState,在InputDispatch中也有一個對應的connection,放入Vector容器中,在connection中含有InputChannel和fd,其中fd來自Socketpair的fd0,另外一個fd1通過Binder通信傳回給APP4。這樣子InputDispatch線程想把輸入事件發送給APP時候,先要找出目前在螢幕最前面的應用程式,然後從vector容器中找到他的connection,然後将資料寫入fd當中既可。

2.4 總結

  • Dispatch線程從輸入事件中讀到資料後,可以通過Vector當中找出某個connection,把輸入事件放入fd當中,另外一個應用程式可以從另外一個檔案句柄中得到輸入事件,将得到的檔案句柄封裝為InputChannel,再封裝為WindowInputEventReceiver,最後把fd放入Looper中,使用Epoll機制查詢等待資料,具體可以見下面關系圖。

2.5 補充

  • InputReader線程、InputDispatch線程和WindowServiceManager都處于System程序當中,故這三個線程可以直接通信不需要Binder介入,而APP如果想跟這三個線程通信則需要通過Binder機制來實作或者通過事先建立好的Socketpair再通過Binder将檔案句柄傳回給APP,故其檔案句柄可能發生變化。
    Android系統--輸入系統(十六)APP跟輸入系統建立聯系_InputChannel和Connection

3. APP獲得SocketPair的fd過程分析

  • 發起addToDisplay的操作
    ViewRootImpl.java
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);                
  • 導緻同檔案下的onTransact被調用
    IWindowSession.java
  • 根據code值調用本地的addToDisplay
    IWindowSession.java
- 得到兩個檔案句柄
           
Session.java
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
    outContentInsets, outInputChannel);
}                
WindowManagerService.java
- 把fd1寫給InputChanne
           
WindowManagerService.java
  • 根據_arg6的傳回結果,把fd寫給Binder驅動程式
    IWindowSession.java
- 最終調用該函數把fd寫入bind驅動中
           
android_view_InputChannel.cpp
  • 遠端操作之後,從驅動程式讀出fd
- 從Binder驅動中讀出fd
           
android_view_InputChannel.cpp
int rawFd = parcel->readFileDescriptor();
int dupFd = dup(rawFd);                

4. 具體調用過程時序圖

具體源碼可以根據下面的時序圖進行具體分析。注:引用韋東山老師

Android系統--輸入系統(十六)APP跟輸入系統建立聯系_InputChannel和Connection

轉載于:https://www.cnblogs.com/lkq1220/p/7211235.html