天天看點

Android Framework 輸入子系統(03)輸入系統架構

該系列文章總綱連結:專題分綱目錄 Android Framework 輸入子系統

本章關鍵點總結 & 說明:

Android Framework 輸入子系統(03)輸入系統架構

本章節 導圖主要關注➕ IMS 架構部分即可,通過啟動過程的分析捋清楚 輸入子系統的架構:就是一個從kernel中斷,産生事件,/dev/input目錄下檔案變化,到讀取資料,再到派發資料,最後到處理資料這樣完整的流程。

1 IMS(InputManagerService)簡介

下面這張圖(《深入了解Android 卷III》)很清楚的描述了輸入子系統的整體架構:

Android Framework 輸入子系統(03)輸入系統架構

說明:輸入事件的源頭是位于/dev/input/下的裝置節點,輸入系統的終點是由WMS管理的某個視窗。Android輸入系統的主要工作是讀取裝置節點中原始事件,加工封裝後派發給一個特定的視窗以及視窗中的控件。接下來針對圖中幾個子產品進行說明:

子產品 簡介說明
Linux核心 接受輸入裝置中斷,将原始事件資料寫入到裝置節點
裝置節點 IMS可以從中讀取事件
InputManagerService 分為Java層和Native層兩部分,Java層負責與WMS的通信;Native層是InputReader和InputDispatcher兩個輸入系統關鍵元件的運作容器。
EventHub 直接通路所有的裝置節點。通過一個名為getEvents()的函數将所有輸入系統相關的待處理底層事件傳回給使用者。
InputReader 運作于獨立線程,負責管理輸入裝置的清單與配置,以及進行輸入事件的加工處理。通過線程循環不斷地通過getEvents()函數從EventHub中将事件取出并進行處理。對于裝置節點的增删事件,它會更新輸入裝置清單于配置。對于原始輸入事件,InputReader對其進行翻譯、組裝、封裝為包含了更多資訊、更具可讀性的輸入事件,然後交給InputDispatcher進行派發。
InputReaderPolicy 為InputReader事件加工處理提供政策配置。
InputDispatcher 是IMS中的另一個關鍵元件。它也運作于一個獨立的線程中。InputDispatcher中保管了來自WMS的所有視窗的資訊,收到來自InputReader的輸入事件後,會尋找合适的視窗,将事件派發給它。
InputDispatcherPolicy 它為InputDispatcher的派發過程提供政策控制。
WMS 對InputDispatcher的正常工作起到了至關重要的作用。建立視窗時,WMS為新視窗和IMS建立了事件傳遞所用的通道。另外,WMS還将所有視窗的資訊,包括視窗的可點選區域,焦點視窗等資訊,實時地更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派發到指定的視窗。
ViewRootImpl 對于某些視窗,如桌面視窗、SurfaceView的視窗來說,視窗即是輸入事件派發的終點。而對于其他的如Activity、對話框等使用了Android控件系統的視窗來說,輸入事件的終點是控件(View)。ViewRootImpl将視窗所接收到的輸入事件沿着控件樹将事件派發給對應的控件。

流程總結:核心将原始事件寫入到裝置節點中,InputReader不斷地通過EventHub将原始事件取出來并加工成Android輸入事件,交給InputDispatcher。InputDispatcher根據WMS提供的視窗資訊将事件交給合适的視窗。視窗的ViewRootImpl對象再沿着控件樹将事件派發給感興趣的控件。控件對其收到的事件作出響應,更新自己的畫面、執行特定的動作。

2 IMS(InputManagerService)啟動流程分析

Android的輸入子系統是在InputManagerService中啟動的,而InputManagerService是在system_server中啟動的。接下來從SystemServer的啟動開始逐漸分析:

//systemserver->startOtherServices
private void startOtherServices() {
    //...
    inputManager = new InputManagerService(context);//關鍵點1
    wm = WindowManagerService.main(context, inputManager,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
            !mFirstBoot, mOnlyCore);

    ServiceManager.addService(Context.WINDOW_SERVICE, wm);
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

    inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
    inputManager.start();//關鍵點2
    //...
}           

從這裡開始 關注 ➕InputManagerService的構造器和線程啟動執行兩個部分。

2.1 InputManagerService構造器深入分析

構造器代碼如下:

public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        //調用nativeInit來執行C++層的初始化操作
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
           

這裡關注nativeInit的實作,代碼如下:(對應檔案 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;
    }
    //構造一個NativeInputManagera對象
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}           

這裡建立一個NativeInputManager的執行個體,并将其作為傳回值儲存在InputManagerService 中的mPtr字段裡,繼續分析NativeInputManager的構造器,代碼如下:

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    }
    //構造一個EventHub對象,傳遞給InputManager
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}
           

這裡繼續分析關鍵對象InputManager,代碼如下:

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();
}           

這裡建立了InputDispatcher對象 用于分發輸入事件,同時建立了一個InputReader對象 用于從EventHub中讀取輸入事件。同時這裡繼續分析initialize方法,代碼如下:

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

這裡建立了一個InputReaderThread和InputDispatcherThread對象,前面構造器中建立的InputReader是通過InputReaderThread來讀取輸入事件,而InputDispatcher實際通過InputDispatcherThread來分發輸入事件。下圖(《深入了解Android 卷III》)很清楚描述了輸入子系統的整體架構,如下所示:

Android Framework 輸入子系統(03)輸入系統架構

InputManager的建立過程分别為InputReader與InputDispatcher建立了線程,IMS的各成員準備就緒。

2.2 InputManagerService線程啟動分析

線程啟動是從這裡開始:

inputManager.start();           

繼續分析,代碼如下:

public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);
        //...
    }
           

繼續分析nativeStart,代碼如下:

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    status_t result = im->getInputManager()->start();
}           

實際調用了InputManager的start函數,繼續分析,代碼如下:

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    //...
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    //...
    return OK;
}           

InputManager啟動了一個InputReaderThread和InputDispatcherThread來讀取和分發輸入消息,調用它們的run方法後,會進入threadLoop函數(隻要threadLoop函數傳回true,該函數就會循環執行)。後面章節 會單獨從讀取事件、派發事件角度來解讀兩個線程。

這裡start()函數的功能就是啟動這兩個線程,使得InputReader于InputDispatcher開始工作。當兩個線程啟動後,InputReader在其線程循環中不斷地從EventHub中讀取輸入事件,加工處理後将事件放入InputDispatcher的派發發隊列中,InputDispatcher線上程循環中将派發隊列中的事件取出,查找合适視窗,将事件寫入。視窗事件接收線程的Looper從管道中将事件取出,交由事件處理函數進行事件響應。過程如下圖所示:(《深入了解Android 卷III》)

Android Framework 輸入子系統(03)輸入系統架構

3 總結 IMS各成員關系(《深入了解Android 卷III》)

Android Framework 輸入子系統(03)輸入系統架構

該圖很好的诠釋了IMS相關類的 成員關系,左邊是Reader子系統,右邊是 Dispatcher子系統。而接下來的兩節主要針對兩個子系統Reader和Dispatcher進行更加詳細的分析。

下一篇: smart pointer