Android輸入系統(一)輸入事件傳遞流程和InputManagerService的誕生

本文首發於微信公衆號「劉望舒」
原文連接 : Android輸入系統的事件傳遞流程和IMS的誕生html

相關文章
解析WMS系列
View體系系列前端

前言

不少同窗可能會認爲輸入系統是否是和View的事件分發有些關聯,確實是有些關聯,只不過View事件分發只能算是輸入系統事件傳遞的一部分。這個系列講的輸入系統主要是咱們不常接觸的,但仍是須要去了解的那部分。java

1. 輸入事件傳遞流程的組成部分

輸入系統是外界與Android設備交互的基礎,僅憑輸入系統是沒法完成輸入事件傳遞的,所以須要輸入系統和Android系統的其餘成員來共同完成事件傳遞。輸入系統事件傳遞須要通過如下幾個部分。 android

輸入事件傳遞流程能夠大體的分爲三個部分,分別是輸入系統部分、WMS處理部分和View處理部分。下面分別對這幾個部分進行簡單的介紹。微信

輸入系統部分

輸入系統部分主要又分爲輸入子系統和InputManagerService組成(如下簡稱IMS),在Android中還有一個IMS(IP Multimedia Subsystem)意爲爲IP多媒體子系統,不要搞混了。 Android的輸入設備有不少種,好比屏幕、鍵盤、鼠標、遊戲手柄、操縱桿等等,其中應用開發接觸最多的屏幕。當輸入設備可用時,Linux內核會在/dev/input中建立對應的設備節點。 用戶操做這些輸入設備時會產生各類事件好比按鍵事件、觸摸事件、鼠標事件等。 輸入事件所產生的原始信息會被Linux內核中的輸入子系統採集,原始信息由Kernel space的驅動層一直傳遞到User space的設備節點。函數

Android提供了getevent和sendevent兩個工具幫助開發者從設備節點讀取輸入事件和寫入輸入事件。 工具

IMS所作的工做就是監聽/dev/input下的全部的設備節點,當設備節點有數據時會將數據進行加工處理並找到合適的Window,將輸入事件派發給它。oop

WMS處理部分

Android解析WindowManagerService(一)WMS的誕生這篇文章中我講過WMS的職責有四種,以下圖所示。 ui

WMS的職責之一就是輸入系統的中轉站,WMS做爲Window的管理者,會配合IMS將輸入事件交由合適的Window來處理。this

View處理部分

View處理部分應該是你們最熟悉的了,通常狀況下,輸入事件最終會交由View來處理,應用開發者就能夠經過一些回調方法輕鬆獲得這個事件的封裝類並對其進行處理,好比onTouchEvent(MotionEvent ev)方法。關於View體系能夠查看View體系這一系列文章。

2. IMS的誕生

輸入事件傳遞流程的組成部分咱們已經瞭解了,本系列主要講解輸入系統部分中IMS對輸入事件的處理,在這以前咱們須要瞭解IMS的誕生。

2.1 SyetemServer處理部分

與AMS、WMS、PMS同樣,IMS的在SyetemServer進程中被建立的,SyetemServer進程用來建立系統服務,不瞭解它的能夠查看 Android系統啓動流程(三)解析SyetemServer進程啓動過程 這篇文章。 從SyetemServer的入口方法main方法開始講起,以下所示。 frameworks/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {
       new SystemServer().run();
   }
複製代碼

main方法中只調用了SystemServer的run方法,以下所示。 frameworks/base/services/java/com/android/server/SystemServer.java

private void run() {
  ...
    try {
        traceBeginAndSlog("StartServices");
        //啓動引導服務
        startBootstrapServices();//1
        //啓動核心服務
        startCoreServices();//2
        //啓動其餘服務
        startOtherServices();//3
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        traceEnd();
    }
    ...
}
複製代碼

在註釋1中的startBootstrapServices方法中用SystemServiceManager啓動了ActivityManagerService、PowerManagerService、PackageManagerService等服務。在註釋2處的startCoreServices方法中則啓動了DropBoxManagerService、BatteryService、UsageStatsService和WebViewUpdateService。註釋3處的startOtherServices方法中啓動了CameraService、AlarmManagerService、VrManagerService等服務。這些服務的父類均爲SystemService。從註釋一、二、3的方法能夠看出,官方把系統服務分爲了三種類型,分別是引導服務、核心服務和其餘服務,其中其餘服務是一些非緊要和一些不須要當即啓動的服務。這些系統服務總共有100多個,咱們熟知的AMS和PMS屬於引導服務,WMS屬於其餘服務。 本文要講的IMS屬於其餘服務,這裏列出其餘服務以及它們的做用,見下表。

其餘服務 做用
CameraService 攝像頭相關服務
AlarmManagerService 全局定時器管理服務
InputManagerService 管理輸入事件
WindowManagerService 窗口管理服務
VrManagerService VR模式管理服務
BluetoothService 藍牙管理服務
NotificationManagerService 通知管理服務
DeviceStorageMonitorService 存儲相關管理服務
LocationManagerService 定位管理服務
AudioService 音頻相關管理服務
... ....

查看啓動其餘服務的註釋3處的startOtherServices方法。 frameworks/base/services/java/com/android/server/SystemServer.java

private void startOtherServices() {
  ...
            inputManager = new InputManagerService(context);//1
            traceEnd();
            traceBeginAndSlog("StartWindowManagerService");
            // WMS needs sensor service ready
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
            mSensorServiceStart = null;
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());//2
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
            traceEnd();
 ...           

 }
複製代碼

註釋1處建立了IMS,註釋2處執行了WMS的main方法,其內部會建立WMS。須要注意的是,main方法的其中一個參數就是註釋1處建立的IMS,在本地第1節中咱們知道WMS是輸入系統的中轉站,其內部包含了IMS引用並不意外。緊接着將WMS和IMS添加到ServiceManager中進行統一的管理。

2.2 InputManagerService構造方法

咱們接着來查看IMS的構造方法。 frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());//1
        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());//2

        ...
    }
複製代碼

註釋1處用android.display線程的Looper建立了InputManagerHandler,這樣InputManagerHandler會運行在android.display線程,android.display線程是系統共享的單例前臺線程,這個線程內部執行了WMS的建立,具體見 Android解析WindowManagerService(一)WMS的誕生這篇文章。 註釋2處調用了nativeInit方法,很明顯是要經過JNI調用Navive方法。 frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());//1
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}
複製代碼

註釋1處建立了NativeInputManager,最後會調用reinterpret_cast運算符將NativeInputManager指針強制轉換並返回(從新解釋比特位)。NativeInputManager的構造函數以下所示。 frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    ...
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}
複製代碼

NativeInputManager構造函數中建立了EventHub和InputManager,EventHub經過Linux內核的INotify與Epoll機制監聽設備節點,經過EventHub的getEvent函數讀取設備節點的增刪事件和原始輸入事件,本系列後續文章會詳細介紹EventHub。InputManager的構造函數以下所示。 frameworks/native/services/inputflinger/InputManager.cpp

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
複製代碼

InputManager構造函數中建立了InputReader和InputDispatcher,InputReader會不斷循環讀取EventHub中的原始輸入事件,將這些原始輸入事件進行加工後交由InputDispatcher,InputDispatcher中保存了WMS中的全部Window信息(WMS會將窗口的信息實時的更新到InputDispatcher中),這樣InputDispatcher就能夠將輸入事件派發給合適的Window。InputReader和InputDispatcher都是耗時操做,所以在initialize函數中建立了供它們運行的線程InputReaderThread和InputDispatcherThread。 InputManagerService構造方法描繪了以下的IMS簡圖。

從上面的簡圖能夠看出來,IMS主要的工做都在Native層中,這些內容會在本系列的後續文章進行介紹。

感謝
《深刻理解Android》卷3
《深刻理解Android內核設計思想》
blog.csdn.net/u013604527/…
www.cnblogs.com/deng-tao/p/…


分享大前端、Java和前沿技術,關注職業發展和行業動態。

相關文章
相關標籤/搜索