Android IMS原理解析

???????針對平時工作中出現(xiàn)的問題,學(xué)習(xí)了一下Input處理機(jī)制,對在觸摸屏幕或按鍵后事件傳到應(yīng)用進(jìn)行處理整個過程有了一個大概的了解,將這段時間的所學(xué)所得在此記錄一下。
???????IMS原理涉及的知識點(diǎn)比較多,為了方便閱讀,總共分為六篇文章:
???????Android IMS原理解析之InputReader
???????Android IMS原理解析之InputDispatcher
???????Android IMS原理解析之InputChannel
???????Android IMS原理解析之processEvent
???????Android IMS原理解析之dispatchEvent

Android輸入系統(tǒng)

簡介

???????輸入事件的源頭是位于dev/input/下的設(shè)備節(jié)點(diǎn),即:當(dāng)我們觸摸屏幕或按鍵后會在該節(jié)點(diǎn)下生成數(shù)據(jù),而輸入系統(tǒng)的終點(diǎn)是由WMS管理的某個窗口。
???????最初的輸入事件為內(nèi)核生成的原始事件,而最終交付給窗口的則是KeyEvent或MotionEvent對象。
???????Android輸入系統(tǒng)的主要工作是讀取設(shè)備節(jié)點(diǎn)中的原始事件,將其加工封裝,然后派發(fā)給一個指定的窗口以及窗口中的控件。這個過程由InputManagerService系統(tǒng)服務(wù)為核心的多個參與者共同完成。


輸入系統(tǒng)參與者.png

核心成員

1.Linux內(nèi)核

???????接受輸入設(shè)備的中斷,并將原始事件的輸入寫入設(shè)備節(jié)點(diǎn)中;

2.設(shè)備節(jié)點(diǎn)

???????作為內(nèi)核和IMS的橋梁,將原始事件的數(shù)據(jù)暴露給用戶空間,以便IMS可以從中讀取事件;

3.InputManagerService

???????Android系統(tǒng)服務(wù),它分為java層和native層兩部分;java層負(fù)責(zé)與WMS通信,native層則是InputReader和InputDispatcher兩個輸入系統(tǒng)關(guān)鍵組件的運(yùn)行容器;

4.EventHub

???????直接訪問所有的設(shè)備節(jié)點(diǎn)。它通過一個名為getEvent()的函數(shù)將所有輸入系統(tǒng)相關(guān)的待處理的底層事件返回給使用者。這些事件包括原始輸入事件、設(shè)備節(jié)點(diǎn)的增刪等;

5.InputReader

???????IMS中的關(guān)鍵組件之一,它運(yùn)行于一個獨(dú)立的線程中,負(fù)責(zé)管理輸入設(shè)備的列表與配置,以及進(jìn)行輸入事件的加工處理。它通過其線程循環(huán)不斷地通過getEvents()函數(shù)從EventHub中將事件取出并進(jìn)行處理。對于設(shè)備節(jié)點(diǎn)的增刪事件,它會更新輸入設(shè)備列表與配置。對于原始輸入事件,InputReader對其進(jìn)行翻譯、組裝、封裝為包含更多信息、更具可讀性的輸入事件,然后交給InputDispatcher進(jìn)行派發(fā);

6.InputReaderPolicy

???????它為InputReader的事件加工處理提供一些策略配置,例如鍵盤布局信息等;

7.InputDispatcher

???????IMS中的另一個關(guān)鍵組件,它也運(yùn)行于一個獨(dú)立的線程中。InputDispatcher中保管了來自WMS的所有窗口的信息,其收到來自InputReader的輸入事件后,會在其保管的窗口中尋找合適的窗口,并將事件派發(fā)給此窗口;

8.InputDispatcherPolicy

???????它為InputDispatcher的派發(fā)過程提供策略控制。例如截取某些特定的輸入事件用作特殊用途,或者阻止將某些事件派發(fā)給目標(biāo)窗口。一個典型的例子就是HOME鍵被InputDispatcherPolicy截取到PhoneWindowManager中進(jìn)行處理,并阻止窗口收到HOME鍵按下的事件;

9.WMS

???????不是輸入系統(tǒng)的一員,但它對InputDispatcher的正常工作起到重要作用。當(dāng)新建窗口時,WMS為新窗口和IMS創(chuàng)建了事件傳遞所用的通道。另外,WMS還將所有窗口的信息,包括窗口的可點(diǎn)擊區(qū)域,焦點(diǎn)窗口等信息,實(shí)時的更新到IMS的InputDispatcher中,使得InputDispatcher可以正確地將事件派發(fā)到指定的窗口;

10.ViewRootImpl

???????對某些窗口,如壁紙窗口、SurfaceView的窗口來說,窗口就是輸入事件派發(fā)的終點(diǎn)。而對其他的activity、對話框等使用了Android控件系統(tǒng)的窗口來說,輸入事件的終點(diǎn)是控件View。ViewRootImpl將窗口所接收的輸入事件沿著控件樹將事件派發(fā)給感興趣的控件;

總結(jié)

???????內(nèi)核將原始事件寫入設(shè)備節(jié)點(diǎn)中,InputReader不斷地通過EventHub將原始事件取出來并翻譯加工成Android輸入事件,然后交給InputDispatcher。InputDispatcher根據(jù)WMS提供的窗口信息將事件交給合適的窗口。窗口的ViewRootImpl對象再沿著控件樹將事件派發(fā)給感興趣的控件。控件對其收到的事件做出響應(yīng),更新自己的畫面、執(zhí)行特定的動作。所有這些參與者以IMS為核心,構(gòu)建Android輸入體系。

IMS啟動及構(gòu)成

???????IMS分為java和native兩部分,其啟動過程是從java部分的初始化開始,進(jìn)而完成native部分的初始化;
???????同其他核心服務(wù)一樣,IMS運(yùn)行在system_server進(jìn)程里面,在startOtherServices()里面啟動:

private void startOtherServices() {
     .......
     .......
     traceBeginAndSlog("StartInputManagerService");
     inputManager = new InputManagerService(context);
     traceEnd();

     traceBeginAndSlog("StartInputManager");
     inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
     inputManager.start();
     traceEnd();
     .......
     ......
}

???????通過啟動邏輯可以看到,在創(chuàng)建完IMS實(shí)例后,先執(zhí)行了setWindowManagerCallbacks然后執(zhí)行了start(),接下來進(jìn)入InputManagerService源碼中一起看一下內(nèi)部實(shí)現(xiàn)邏輯:

private static native long nativeInit(InputManagerService service,
            Context context, MessageQueue messageQueue);
private static native void nativeStart(long ptr);

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

    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

    ......
}

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

    .......
}

//該方法設(shè)置了callbacks,后續(xù)native層的callback最終會調(diào)用到這里
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
    mWindowManagerCallbacks = callbacks;
}

???????在構(gòu)造方法內(nèi),執(zhí)行了nativeInit(),在start()中執(zhí)行了nativeStart(),以上兩個方法都是native方法,具體的邏輯是在native層實(shí)現(xiàn)的,對應(yīng)的類路徑為:base/services/core/jni/com_android_server_input_InputManagerService.cpp,接下來先一起看一下nativeInit():

nativeInit()
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());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

???????在nativeInit方法內(nèi)部,創(chuàng)建了NativeInputManager對象:

class NativeInputManager : public virtual RefBase,
    public virtual InputReaderPolicyInterface,
    public virtual InputDispatcherPolicyInterface,
    public virtual PointerControllerPolicyInterface {
    ......
    ......
}

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);
    .......
    .......

    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

???????可以看到,NativeInputManager繼承了InputReaderPolicyInterface、InputDispatcherPolicyInterface等,后續(xù)會講到,然后回到構(gòu)造方法,在構(gòu)造方法內(nèi)部,先創(chuàng)建了EventHub,然后創(chuàng)建InputManager,并將自身和EventHub實(shí)例作為參數(shù)傳入,再看一下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);
}

???????在實(shí)例化InputManager時,會創(chuàng)建InputDispatcher,然后創(chuàng)建InputReader,并把eventHub和mDispatcher作為參數(shù)傳入,參數(shù)dispatcherPolicy和readerPolicy的實(shí)現(xiàn)都是NativeInputManager及參數(shù)mDispatcher,在后續(xù)事件傳遞過程中會用到,接下來會講;然后執(zhí)行了initialize(),分別創(chuàng)建了InputReader運(yùn)行的線程InputReaderThread和InputDispatcher運(yùn)行的線程InputDispatcherThread;
???????總結(jié)一下:在執(zhí)行nativeInit()后,會創(chuàng)建NativeInputManager對象,然后在NativeInputManager內(nèi)部創(chuàng)建了EventHub和InputManager對象,接著在InputManager內(nèi)部創(chuàng)建了InputReader和InputDispatcher對象,并創(chuàng)建了InputReaderThread和InputDispatcherThread,用一張圖概況一下:

IMS主要構(gòu)成.png

???????Java層IMS的主要工作是為InputReaderPolicy和InputDispatcherPolicy提供實(shí)現(xiàn),以及與Android系統(tǒng)服務(wù)進(jìn)行協(xié)作,最主要的就是WMS;
???????NativeInputManager位于IMS的jni層,負(fù)責(zé)native層的組件與java層的IMS的相互通信,同時它為主要工作是為InputReader和InputDispatcher提供策略請求接口InputReaderPolicyInterface和InputDispatcherPolicyInterface,策略請求被它轉(zhuǎn)發(fā)為Java層的IMS,由IMS最終確定;
???????InputManager由NativeInputManager創(chuàng)建,是InputReader和InputDispatcher的運(yùn)行容器,并創(chuàng)建了InputReaderThread和InputDispatcherThread分別承載InputReader和InputDispatcher的運(yùn)行;

nativeStart()

???????接著上面分析,在執(zhí)行nativeInit()后,會執(zhí)行nativeStart():

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

???????可以看到,實(shí)際上是調(diào)用InputManager的start()方法:

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

???????在start()內(nèi)部,啟動了InputReader運(yùn)行的線程InputReaderThread和InputDispatcher運(yùn)行的線程InputDispatcherThread;
???????system_server在啟動IMS時,執(zhí)行的流程如圖所示:


image.png
Thread運(yùn)行

???????當(dāng)兩個線程啟動后,InputReader在其線程循環(huán)中不斷地從EventHub中抽取原始輸入事件,進(jìn)行加工處理后將加工所得的事件放入InputDispatcher的派發(fā)隊(duì)列中;InputDispatcher則在其線程循環(huán)中將派發(fā)隊(duì)列中的事件取出,查找合適的窗口,將事件寫入窗口的事件接收管道中;窗口事件接收線程的Looper從管道中將事件取出,交由事件處理函數(shù)進(jìn)行事件響應(yīng)。


處理流程.png
成員關(guān)系

???????從上面的分析可以看到,在創(chuàng)建IMS時,涉及到許多類,先將關(guān)系整理如下,接下來通過功能詳細(xì)分析:

IMS成員關(guān)系.png

???????接下來從事件讀取開始分析,對應(yīng)文章為:Android IMS原理解析之InputReader

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容