Android觸摸事件的傳遞(二)--輸入系統(tǒng)InputManagerService

了解更多,移步Android觸摸事件傳遞機(jī)制系列詳解

1 概述

  1. 當(dāng)用戶觸摸屏幕或者按鍵操作,首次觸發(fā)的是硬件驅(qū)動,驅(qū)動收到事件后,將該相應(yīng)事件寫入到輸入設(shè)備節(jié)點, 這便產(chǎn)生了最原生態(tài)的內(nèi)核事件。
  2. 接著,輸入系統(tǒng)取出原生態(tài)的事件,經(jīng)過層層封裝后成為KeyEvent或者MotionEvent;
  3. 最后,交付給相應(yīng)的目標(biāo)窗口(Window)來消費該輸入事件??梢?,輸入系統(tǒng)在整個過程起到承上啟下的銜接作用。

2 Input模塊的主要組成:

  1. Native層的InputReader負(fù)責(zé)從EventHub取出事件并處理,再交給InputDispatcher;
  2. Native層的InputDispatcher接收來自InputReader的輸入事件,并記錄WMS的窗口信息,用于派發(fā)事件到合適的窗口
  3. Java層的InputManagerService跟WMS交互,WMS記錄所有窗口信息,并同步更新到IMS,為InputDispatcher正確派發(fā)事件到ViewRootImpl提供保障;

3 整體框架類圖

InputManagerService作為system_server中的重要服務(wù),繼承于IInputManager.Stub, 作為Binder服務(wù)端,那么Client位于InputManager的內(nèi)部通過IInputManager.Stub.asInterface()獲取Binder代理端,C/S兩端通信的協(xié)議是由IInputManager.aidl來定義的。

input_binder.jpg

圖解:

  • InputManagerService位于Java層的InputManagerService.java文件;
    a. 其成員mPtr指向Native層的NativeInputManager對象;
  • NativeInputManager位于Native層的com_android_server_input_InputManagerService.cpp文件;
    a. 其成員mServiceObj指向Java層的IMS對象;
    b. 其成員mLooper是指“android.display”線程的Looper;
  • InputManager位于libinputflinger中的InputManager.cpp文件;
    a. InputDispatcherInputReader的成員變量mPolicy都是指NativeInputManager對象;
    b. InputReader的成員mQueuedListener,數(shù)據(jù)類型為QueuedInputListener;通過其內(nèi)部成員變量mInnerListener指向InputDispatcher對象; 這便是InputReaderInputDispatcher交互的中間樞紐。

4 啟動調(diào)用棧(流程)

IMS服務(wù)是伴隨著system_server進(jìn)程的啟動而啟動,整個調(diào)用過程:

InputManagerService(初始化)
    nativeInit
        NativeInputManager
            EventHub
            InputManager
                InputDispatcher
                    Looper
                InputReader
                    QueuedInputListener
                InputReaderThread
                InputDispatcherThread
IMS.start(啟動)
    nativeStart
        InputManager.start
            InputReaderThread->run
            InputDispatcherThread->run

整個過程首先創(chuàng)建如下對象:NativeInputManager,EventHub,InputManagerInputDispatcher,InputReader,InputReaderThread,InputDispatcherThread。 接著便是啟動兩個工作線程InputReader,InputDispatcher

5 IMS啟動過程

private void startOtherServices() {
    //1. 初始化IMS對象
    inputManager = new InputManagerService(context);
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
    ...
    //將InputMonitor對象保持到IMS對象
    inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
    //2
    inputManager.start();
}

通過上述代碼接下,分InputManagerService初始化和InputManagerService的啟動來寫。

6 InputManagerService初始化

6.1 構(gòu)造方法

創(chuàng)建InputManagerService對象--構(gòu)造方法:[-> InputManagerService.java]

public InputManagerService(Context context) {
     this.mContext = context;
     // 運行在線程"android.display"
     this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
     ...

     //初始化native對象
     mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
     LocalServices.addService(InputManagerInternal.class, new LocalService());
 }

6.2 構(gòu)造方法中調(diào)用nativeInit

[-> com_android_server_input_InputManagerService.cpp]

static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    //獲取native消息隊列
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    ...
    //創(chuàng)建Native的InputManager【見小節(jié)2.3】
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im); //返回Native對象的指針
}

6.3 nativeInit中創(chuàng)建NativeInputManager

[-> com_android_server_input_InputManagerService.cpp]

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();
    mContextObj = env->NewGlobalRef(contextObj); //上層IMS的context
    mServiceObj = env->NewGlobalRef(serviceObj); //上層IMS對象
    ...
    sp<EventHub> eventHub = new EventHub(); // 創(chuàng)建EventHub對象【見小節(jié)2.4】
    mInputManager = new InputManager(eventHub, this, this); // 創(chuàng)建InputManager對象
}

6.4 NativeInputManager中創(chuàng)建EventHub

[-> EventHub.cpp]

EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
    //創(chuàng)建epoll
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    mINotifyFd = inotify_init();
    //此處DEVICE_PATH為"/dev/input",監(jiān)聽該設(shè)備路徑
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    //添加INotify到epoll實例
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    int wakeFds[2];
    result = pipe(wakeFds); //創(chuàng)建管道

    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];

    //將pipe的讀和寫都設(shè)置為非阻塞方式
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

    eventItem.data.u32 = EPOLL_ID_WAKE;
    //添加管道的讀端到epoll實例
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
    ...
}

該方法主要功能:

  • 初始化INotify(監(jiān)聽”/dev/input”),并添加到epoll實例
  • 創(chuàng)建非阻塞模式的管道,并添加到epoll;

6.5 NativeInputManager中創(chuàng)建InputManager

[-> InputManager.cpp]

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    //創(chuàng)建InputDispatcher對象
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    //創(chuàng)建InputReader對象
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

InputDispatcherInputReadermPolicy成員變量都是指NativeInputManager對象。

6.6 InputManager中創(chuàng)建InputDispatcher

[-> InputDispatcher.cpp]

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
    //創(chuàng)建Looper對象
    mLooper = new Looper(false);

    mKeyRepeatState.lastKeyEntry = NULL;
    //獲取分發(fā)超時參數(shù)
    policy->getDispatcherConfiguration(&mConfig);
}

該方法主要工作:

  • 創(chuàng)建屬于自己線程的Looper對象;
  • 超時參數(shù)來自于IMS,參數(shù)默認(rèn)值keyRepeatTimeout= 500,keyRepeatDelay = 50。

6.7 InputManager中創(chuàng)建InputReader

[-> InputReader.cpp]

InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    // 創(chuàng)建輸入監(jiān)聽對象
    mQueuedListener = new QueuedInputListener(listener);
    {
        AutoMutex _l(mLock);
        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    }
}

此處mQueuedListener的成員變量mInnerListener便是InputDispatcher對象。 InputManager創(chuàng)建完InputDispatcherInputReader對象, 接下里便是調(diào)用initialize初始化。

6.8 InputManager中初始化initialize

InputManager創(chuàng)建完InputDispatcher和InputReader對象, 接下里便是調(diào)用initialize初始化。
[-> InputManager.cpp]

void InputManager::initialize() {
    //創(chuàng)建線程“InputReader”
    mReaderThread = new InputReaderThread(mReader);
    //創(chuàng)建線程”InputDispatcher“
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
        Thread(/*canCallJava*/ true), mReader(reader) {
}

InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
        Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}

初始化的主要工作就是創(chuàng)建兩個能訪問Java代碼的native線程。

  • 創(chuàng)建線程“InputReader”
  • 創(chuàng)建線程”InputDispatcher“

整個的InputManagerService對象初始化過程并完成,接下來便是調(diào)用其start方法。

7 IMS.start

[-> InputManagerService.java]

public void start() {
    // 啟動native對象[見小節(jié)2.10]
    nativeStart(mPtr);

    Watchdog.getInstance().addMonitor(this);

    //注冊觸摸點速度和是否顯示功能的觀察者
    registerPointerSpeedSettingObserver();
    registerShowTouchesSettingObserver();

    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
        }
    }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

    updatePointerSpeedFromSettings(); //更新觸摸點的速度
    updateShowTouchesFromSettings(); //是否在屏幕上顯示觸摸點
}

7.1 start中調(diào)用nativeStart

[-> com_android_server_input_InputManagerService.cpp]

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    //此處ptr記錄的便是NativeInputManager
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // [見小節(jié)7.2]
    status_t result = im->getInputManager()->start();
    ...
}

7.2 InputManager.start

[InputManager.cpp]

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

該方法的主要功能是啟動兩個線程:

  • 啟動線程“InputReader”
  • 啟動線程”InputDispatcher“

8 總結(jié)

分層視角:

  1. Java層InputManagerService:采用android.display線程處理Message.
  2. JNI的NativeInputManager:采用android.display線程處理Message,以及創(chuàng)建EventHub。
  3. Native的InputManager:創(chuàng)建InputReaderThreadInputDispatcherThread兩個線程

主要功能:

  • IMS服務(wù)中的成員變量mPtr記錄Native層的NativeInputManager對象;
  • IMS對象的初始化過程的重點在于native初始化,分別創(chuàng)建了以下對象:
    NativeInputManager;
    EventHub, InputManager;
    InputReader,InputDispatcher;
    InputReaderThread,InputDispatcherThread
  • IMS啟動過程的主要功能是啟動以下兩個線程:
    InputReader:從EventHub取出事件并處理,再交給InputDispatcher
    InputDispatcher:接收來自InputReader的輸入事件,并派發(fā)事件到合適的窗口。

從整個啟動過程,可知有system_server進(jìn)程中有3個線程跟Input輸入系統(tǒng)息息相關(guān),分別是android.display, InputReader,InputDispatcher

  • InputDispatcher線程:屬于Looper線程,會創(chuàng)建屬于自己的Looper,循環(huán)分發(fā)消息;
  • InputReader線程:通過getEvents()調(diào)用EventHub讀取輸入事件,循環(huán)讀取消息;
  • android.display線程:屬于Looper線程,用于處理Java層的IMS.InputManagerHandler和JNI層的NativeInputManager中指定的MessageHandler消息;
事件分發(fā)1.png

參考

Android系統(tǒng)源碼分析-事件收集
Android 輸入系統(tǒng)(一)InputManagerService
Input系統(tǒng)—啟動篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,983評論 25 709
  • 沉悶的空氣,像陰暗的囚籠 靜謐的氛圍,像審訊的牢房 人們都低沉著原本高傲的頭顱,向著罪惡的王冠屈服。 原本跳動的心...
    流年已盡閱讀 579評論 3 2
  • 我們都是赤條條的來到這個世,是從什么時候開始,人與人之間有了那么多的天差地別?~ 不得不說,當(dāng)我們第一聲啼哭后,被...
    minnameng閱讀 271評論 0 2
  • 今年已經(jīng)88歲的公公,依然堅持每天寫字一小時,開始再拿起毛筆寫字,是在公公退休幾年后的事兒,從此斷斷續(xù)續(xù)二十余年,...
    灰玫瑰汪然閱讀 186評論 0 3

友情鏈接更多精彩內(nèi)容