Android的輸入設備,最經常使用的就是 觸摸屏和按鍵 了。固然還有其餘方式,好比遊戲手柄,好比支持OTG設備,則能夠連接鼠標、鍵盤等。
那麼這些設備的操做 是如何傳遞到系統 並 控制界面的呢?系統如何知道是如何知道點擊了某個界面按鈕,按了某個按鍵,知道交給哪一個應用處理的?
該篇主要介紹這些,即 輸入事件從生成(存於設備節點中) 傳遞到目標View的過程。 在進入輸入事件傳遞機制以前,首先了解一個東西---設備節點。
html
當有輸入事件時,Linux內核會將事件數據寫入 設備節點 中,供上層讀取最終傳遞到具體的View中。 該備節點 位於/dev/input/。java
與事件相關的設備信息位於:/proc/bus/input/devices。
下面是一部分,大體瞭解下。Name對應的Handlers注意下。android
//查看全部事件相關設備信息 $ adb shell cat /proc/bus/input/devices I: Bus=0019 Vendor=0000 Product=0000 Version=0000 N: Name="ACCDET" P: Phys= S: Sysfs=/devices/virtual/input/input0 U: Uniq= H: Handlers=event0 B: PROP=0 B: EV=23 B: KEY=40 0 0 0 0 0 0 0 0 0 0 0 0 10 0 c0000 0 0 0 B: SW=d4 I: Bus=0019 Vendor=2454 Product=6500 Version=0010 N: Name="mtk-kpd" P: Phys= S: Sysfs=/devices/platform/10010000.kp/input/input1 U: Uniq= H: Handlers=event1 B: PROP=0 B: EV=3 B: KEY=1000000 0 0 0 0 0 0 0 0 1c0000 0 0 0 ...
經過設備的getevent命令,能夠查看輸入事件的信息。redis
//獲取輸入事件,這裏是按了下電源鍵 $ adb shell getevent add device 1: /dev/input/event0 name: "ACCDET" add device 2: /dev/input/event2 name: "sf-keys" add device 3: /dev/input/event3 name: "mtk-tpd" add device 4: /dev/input/event1 name: "mtk-kpd" /dev/input/event1: 0001 0074 00000001 /dev/input/event1: 0000 0000 00000000 /dev/input/event1: 0001 0074 00000000 /dev/input/event1: 0000 0000 00000000 //從/proc/bus/input/devices獲取到要關注的設備的節點,能夠單獨獲取 //下面是獲取也是按的電源鍵獲取到的 $ adb shell getevent /dev/input/event1 0001 0074 00000001 0000 0000 00000000 0001 0074 00000000 0000 0000 00000000 //多瞭解參數,這個-l就很清楚了 //-l: label event types and names in plain text $ adb shell getevent -l /dev/input/event1 EV_KEY KEY_POWER DOWN EV_SYN SYN_REPORT 00000000 EV_KEY KEY_POWER UP EV_SYN SYN_REPORT 00000000
上面列出的3種,第一種沒有參數 獲取全部輸入事件。加上 -l參數 的結果就很清晰了。
事件類型: 0001 即 EV_KEY,按鍵
事件代碼: 0074 即 KEY_POWER,電源鍵
事件的值: 00000001 即 DOWN,按下;00000000 即 UP,擡起。shell
/dev/input/event1: 0001 0074 00000001 就是 電源鍵按下了。
/dev/input/event1: 0001 0074 00000000 就是 電源鍵擡起了。session
注意:這裏的值 都是 16進制的。app
觸摸屏幕也同樣:socket
//觸摸屏幕截取 /dev/input/event3: EV_ABS ABS_MT_TOUCH_MAJOR 0000001e /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID 00000000 /dev/input/event3: EV_ABS ABS_MT_POSITION_X 000001b5 /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 000001e1 /dev/input/event3: EV_SYN SYN_MT_REPORT 00000000 /dev/input/event3: EV_SYN SYN_REPORT 00000000
輸入事件 設備節點也是可寫的,經過sendevent可模擬用戶輸入。
但 sendevent 的參數是 十進制。async
格式:sendevent <設備節點> <事件類型> <事件代碼> <事件的值>ide
因此getevent中,電源按下/擡起的:事件類型即1,事件代碼即116,事件的值即1/0。
//電源鍵按下 $ adb shell sendevent /dev/input/event1 1 116 1 //電源鍵擡起 $ adb shell sendevent /dev/input/event1 1 116 0 //由上述getevent我的理解,0 0 0上報後生效,同按一次電源鍵操做 $ adb shell sendevent /dev/input/event1 0 0 0
該篇也是基於Android10的代碼分析。 該篇寫時後期調整過幾回標題編號,若是文中有參考的編號不對應,請指出。下面圖片因爲博客顯示不是原圖,可能部分不清晰,能夠單獨查看圖片原圖。
文章很長,但分的3個模塊比較清晰,能夠根據須要查看。
好,這裏正式開始了。
下面是畫的一張圖,即本章的大體內容。也是方便本身查閱,主要介紹了 輸入事件是如何從 設備節點中 傳遞到具體的View的。
整篇文章比較長,須要耐心。事件傳遞的過程 與 WMS關係比較密切,如有須要能夠先參考:Android10_原理機制系列_Activity窗口添加到WMS過程 和 Android10_原理機制系列_Window介紹及WMS的啓動過程。
如有不對,歡迎指出:
說明:
輸入事件的傳遞過程,如概述中所述,這裏分紅了3個部分來講明。
下面來具體看看。
咱們從IMS(InputManagerService)的建立和啓動開始看。
IMS是在SystemServer的 startOtherServices() 方法中啓動。(以前總結了AMS/PMS/WMS等,這裏相似)
//SystemServer.java private void startOtherServices() { WindowManagerService wm = null; InputManagerService inputManager = null; try { //參考1.1,建立IMS對象 inputManager = new InputManagerService(context); wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore, new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager); //註冊服務:"input" ServiceManager.addService(Context.INPUT_SERVICE, inputManager, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL); //參考1.4,設置回調 inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback()); //參考1.5, 啓動 inputManager.start(); } final InputManagerService inputManagerF = inputManager; mActivityManagerService.systemReady(() -> { try { if (inputManagerF != null) { inputManagerF.systemRunning(); } } }, BOOT_TIMINGS_TRACE_LOG); }
SystemServer中 關於IMS主要看3個內容:
先看IMS的構造方法:
//InputManagerService.java public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor { private static native long nativeInit(InputManagerService service, Context context, MessageQueue messageQueue); public InputManagerService(Context context) { this.mContext = context; //建立了InputManagerHandler,其Looper是DisplayThead的Looper this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); //進入native,並返回了mPtr mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class, new LocalService()); } private final class InputManagerHandler extends Handler { public InputManagerHandler(Looper looper) { super(looper, null, true /*async*/); } } }
看到 this.mHandler 的Looper 是 DisplayThread的Looper。 這個Looper的消息隊列 做爲參數 傳入到 nativeInit() 方法中。關於Looper,若是不太瞭解,也能夠參考:Android10_原理機制系列_Android消息機制(Handler)詳述
下面進入 nativeInit() 。
//com_android_server_input_InputManagerService.cpp static const JNINativeMethod gInputManagerMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J", (void*) nativeInit }, } static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); ... //建立NativeInputManager NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); //system/core/libutils/RefBase.cpp查看 im->incStrong(0); //返回給IMS,IMS後續會用到。IMS保存在mPtr。 return reinterpret_cast<jlong>(im); } //com_android_server_input_InputManagerService.cpp //NativeInputManager的構造方法: NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) { //建立InputManager mInputManager = new InputManager(this, this); defaultServiceManager()->addService(String16("inputflinger"), mInputManager, false); }
這裏看到,nativeInit() 中建立NativeInputManager。 返回給IMS的是 reinterpret_cast<jlong>(im)
,這是某種轉換,能夠看做是將NativeInputManager返回給了java層。
NativeInputManager中又建立了 InputManager。接着看InputManager的建立:
//InputManager.cpp InputManager::InputManager( const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { //建立InputDispatcher mDispatcher = new InputDispatcher(dispatcherPolicy); mClassifier = new InputClassifier(mDispatcher); //建立InputReader mReader = createInputReader(readerPolicy, mClassifier); //建立了兩個線程 InputReaderThread和InputDispatcherThread initialize(); } void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } //InputReaderFactory.cpp sp<InputReaderInterface> createInputReader( const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) { //EventHub做爲參數 傳入InputReader return new InputReader(new EventHub(), policy, listener); }
上述代碼,能夠看到,InputManager中基本都是建立操做,建立了InputDispatcher、InputClassifier、InputReader、EventHub、InputReaderThread、InputDispatcherThread。
下面會逐步看到他們的做用 以及如何運行的。 這裏先簡單說明下其中幾個主要的部分, 先有個大體瞭解。
EventHub:建立InputReader時 能夠看到先建立了EventHub做爲參數。
EventHub 經過Linux內核的INotify與Epoll機制 監聽設備,可直接訪問 設備節點。經過 getEvents() 方法 讀取設備節點的原始輸入事件 數據。
關於 EventHub的建立 這裏不討論了,這裏只需簡單瞭解它上面一點就能夠了。它涉及內核和一些機制,暫時我也還不熟悉,哈哈。
InputReader:負責輸入事件的獲取。在獨立線程(InputReaderThread)中 循環執行,有如下幾個功能:
功能1-經過 EventHub 不斷 獲取設備節點的 原始輸入數據 。
功能2-而後 進行加工處理後 交由 InputDispatcher分派 。
功能3-它還有 管理 輸入設備列表和配置 。
InputDispatcher:負責輸入事件的派發。在獨立線程(InputDispatcherThread)中運行,其保存有WMS的全部窗口信息。
在接收到 InputReader 的輸入事件後,會在窗口信息中找到合適的 窗口 並 派發消息。
InputReaderThread、InputDispatcherThread:由於InputReader 和 InputDispatcher都是耗時操做,所以建立 單獨線程 來運行他們。這就是他們運行的線程。
建立完成後,他們是如何聯繫 並 運行的?
這個下面從 InputReaderThread和InputDispatcherThread兩個線程的運行起來 理一下就能夠大體瞭解。
這裏從InputReaderThread的運行開始介紹。
關於InputReaderThread和InputDispatcherThread 是如何運行起來,如何執行的threadLoop() ,後面也介紹了,請參考1.5
這裏從 InputReaderThread::threadLoop() 開始跟蹤:
//InputReaderBase.cpp bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } //InputReader.cpp void InputReader::loopOnce() { ... //獲取事件 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { //處理輸入事件,參考1.2.2 processEventsLocked(mEventBuffer, count); } ... } // release lock // Send out a message that the describes the changed input devices. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. //將事件 推送給 InputDispatcher 進行處理。參考1.2.2.3 mQueuedListener->flush(); ... }
線程 運行起來後,會執行threadLoop,這裏返回true,會循環執行該threadLoop方法。
threadLoop中調用 loopOnce,經過3步將消息 發送到InputDispatcher:
看下處理輸入事件的方法:processEventsLocked()
//InputReader.cpp void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } //處理 真正的輸入事件,參考 1.2.2.2 processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { //處理 設備增長、刪除、掃描更新。參考1.2.2.1 switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; ... } } count -= batchSize; rawEvent += batchSize; } }
前面講了InputReader有3個功能,這裏能夠看到功能2和3:對輸入事件進行加工處理後 交由InputDispatcher;對輸入設備 列表的管理和配置。先看功能3,在看功能2。
先看下功能3:對輸入設備 列表的管理和配置。
這裏以增長設備 爲例,看下addDeviceLocked():
//InputReader.cpp void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); return; } InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); //建立InputDevice InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); device->configure(when, &mConfig, 0); device->reset(when); ... //加入mDevices mDevices.add(deviceId, device); ... } //mDevices 和 InputDevice定義(截取部分) //InputReader.h class InputReader : public InputReaderInterface { KeyedVector<int32_t, InputDevice*> mDevices; } class InputDevice { int32_t mId;//經過mId從EventHub中找到對應的輸入設備 std::vector<InputMapper*> mMappers;//處理上報的事件 }
這裏建立了一個InputDevice,而後將其加入到mDevices。mDevices 中保存了 設備的id 以及 對應的InputDevice。
EventHub 中也有個 mDevices,保存了 設備的id 和 對應的Device信息。 以下(截取部分):
//EventHub.h class EventHub : public EventHubInterface { KeyedVector<int32_t, Device*> mDevices; struct Device { Device* next; int fd; // may be -1 if device is closed //設備節點 的文件句柄 const int32_t id; const std::string path; const InputDeviceIdentifier identifier; //記錄設備信息,設備的名稱、供應商、型號等等 std::unique_ptr<TouchVideoDevice> videoDevice; uint32_t classes; std::unique_ptr<VirtualKeyMap> virtualKeyMap; KeyMap keyMap; } }
看下 建立InputDevice的過程,createDeviceLocked():
//InputReader.cpp InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { //建立InputDevice InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes); // External devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { device->setExternal(true); } // Keyboard-like devices. ... if (keyboardSource != 0) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } return device; } void InputDevice::addMapper(InputMapper* mapper) { mMappers.push_back(mapper); }
建立了InputDevice後,進行一些設置。值得關注的是 一個InputDevice保存了多個 InputMapper,這些InputMapper保存在mMappers。
簡單理一下:InputReader添加設備,首先建立了一個InputDevice,而後加入到mDevices中。而根據設備類型,能夠建立多個InputMapper,這多個InputMapper保存在InputDevice中的mMappers中。
接着看功能2,對輸入事件進行處理 processEventsForDeviceLocked() :
//InputReader.cpp void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); //最終根據deviceId得到設備對應的InputDevice InputDevice* device = mDevices.valueAt(deviceIndex); //事件交由 對應InputDevice處理。rawEvents是一組事件,能夠注意下來源。 device->process(rawEvents, count); } //InputReader.cpp void InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved. For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { ... if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { mDropUntilNextSync = false; ... } ... } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); mDropUntilNextSync = true; reset(rawEvent->when); } else { //將InputDvices對象中的mMappers依次取出來,調用process()進行處理 for (InputMapper* mapper : mMappers) { mapper->process(rawEvent); } } --count; } }
InputReader 得到某設備相關一組事件,而後找到對應InputDevice進行處理,執行 InputDevice::process()
。
InputDevice則將InputDvices對象中的mMappers依次取出來,調用process()進行處理。各個 InputMapper 對事件進行判斷,如果屬於本身處理的類型 再進行不一樣的處理。
下面 以鍵盤事件 爲例說明,則InputMapper是KeyboardInputMapper:
//InputReader.cpp void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { int32_t scanCode = rawEvent->code; int32_t usageCode = mCurrentHidUsage; mCurrentHidUsage = 0; if (isKeyboardOrGamepadKey(scanCode)) { //處理事件,這裏即處理按鍵的方法 processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); } break; } ... } } //InputReader.cpp //內核上報的掃描碼(scanCode),轉換成Android系統使用的按鍵碼(keyCode),重構NotifyArgs,加入 mArgsQueue隊列 void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) { int32_t keyCode; int32_t keyMetaState; uint32_t policyFlags; ... //重構args NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); //插入到 mArgsQueue 隊列中 getListener()->notifyKey(&args); }
這個處理過程 主要是 封裝各個參數,從新構形成 NotifyKeyArgs ,而後 將構造的 NotifyKeyArgs對象加入 mArgsQueue隊列。
加入到 mArgsQueue的過程, getListener()->notifyKey(&args):
//InputReader.cpp InputListenerInterface* InputReader::ContextImpl::getListener() { return mReader->mQueuedListener.get(); } InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : ... { mQueuedListener = new QueuedInputListener(listener); } //InputListener.cpp QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : mInnerListener(innerListener) { } void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { mArgsQueue.push_back(new NotifyKeyArgs(*args));//push_back() 在Vector尾部插入 } //InputListener.h class QueuedInputListener : public InputListenerInterface { std::vector<NotifyArgs*> mArgsQueue; };
在1.1中 建立InputReader時已經知道(能夠回去看下),InputReader中的lister是InputClassifier對象,因此 QueuedInputListener中的innerListener 也就是 InputClassifier。
到這裏再理一下:事件先交由了對應的InputDevice,而後找對處理該事件類型的InputMapper 進行處理。InputMapper 將事件等信息 構造了NotifyArgs,而後加入到了mArgsQueue中。
看 InputReader::loopOnce() 的最後一句:mQueuedListener->flush();
//InputListener.cpp void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); //依次從mArgsQueue中取出NotifyArgs for (size_t i = 0; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; //mInnerListener是InputClassifier,上面(1.2.2.2最後)已經特地指出 args->notify(mInnerListener); delete args; } mArgsQueue.clear(); }
如註釋所說。接着看 args->notif(),接下來都是以鍵盤事件爲例:
//NotifyArgs是全部args的超類。 以鍵盤爲例,args即NotifyKeyArgs void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const { listener->notifyKey(this); } //InputManager.cpp InputManager::InputManager( const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mClassifier = new InputClassifier(mDispatcher); } //InputClassifier.cpp //mListener是InputDispatcher InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {} void InputClassifier::notifyKey(const NotifyKeyArgs* args) { // pass through mListener->notifyKey(args); }
很清楚列出了,這裏的mListener即InputDispatcher。因此最終走到了 InputDispatcher::notifyKey():
//InputDispatcher.cpp void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { ... int32_t keyCode = args->keyCode; //Meta + Backspace -> generate BACK; Meta + Enter -> generate HOME accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; event.initialize(args->deviceId, args->source, args->displayId, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime, args->eventTime); android::base::Timer t; //mPolicy是NativeInputManager,最終回調到PhoneWindowManager的同名方法。參考1.2.2.4 mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); ... bool needWake; { // acquire lock mLock.lock(); ... KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, args->displayId, policyFlags, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); } } bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); //entry加入到mInboundQueue mInboundQueue.enqueueAtTail(entry); ... return needWake; }
最終,輸入事件 由InputReader 獲取處理後,傳遞到InputDispatcher,封裝成EventEntry並加入mInboundQueue 隊列了。
注意上面 InputDispatcher::notifyKey
中有 mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
這句話,對PhoneWindowManager有過了解的,應該比較清楚。
這裏就是 policy攔截的 比較常見的一處,從這最終回調 的是 PhoneWindowManager中的方法。
這個大體看下,這裏mPolicy即 NativeInputManager ,因此直接看NativeInputManager::interceptKeyBeforeQueueing()
:
//com_android_server_input_InputManagerService.cpp void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { ... wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeQueueing, keyEventObj, policyFlags); ... } //InputManagerService.java private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); }
這個跟蹤 就是執行了IMS中的interceptKeyBeforeQueueing()方法。
最終是如何調用到 PhoneWindowManager 中的方法的?
這裏的mWindowManagerCallbacks是 wms中建立的InputManagerCallback對象。這個如何來的 參考1.4。
因此 mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
即:
//InputManagerCallback.java public InputManagerCallback(WindowManagerService service) { mService = service; } @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); }
這裏的mService.mPolicy就是PhoneWindowManager對象,在WMS建立時設置的。因此最終 回調的 PhoneWindowManager 中的 interceptKeyBeforeQueueing() 方法。 PhoneWindowManager 是 WindowManagerPolicy 的實現類。
前面講到,輸入事件 在InputDispatcher中 封裝成EventEntry並加入mInboundQueue 隊列了。接着看 InputDispatcher是如何繼續處理 派發的。
如同InputReaderThread中介紹,這裏直接看threadLoop()。
//frameworks/native/services/inputflinger/InputDispatcher.cpp bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true; } void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock std::scoped_lock _l(mLock); mDispatcherIsAlive.notify_all(); // Run a dispatch loop if there are no pending commands. // The dispatch loop might enqueue commands to run afterwards. //若mCommandQueue爲空 if (!haveCommandsLocked()) { //參考1.3.1 dispatchOnceInnerLocked(&nextWakeupTime); } // Run all pending commands if there are any. // If any commands were run then force the next poll to wake up immediately. //參考1.3.4,運行 mCommandQueue 中命令 if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } } // release lock // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); } //InputDispatcher.h EventEntry* mPendingEvent GUARDED_BY(mLock); Queue<EventEntry> mInboundQueue GUARDED_BY(mLock); Queue<EventEntry> mRecentQueue GUARDED_BY(mLock); Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock); //InputDispatcher.cpp bool InputDispatcher::haveCommandsLocked() const { return !mCommandQueue.isEmpty(); }
1.2.2.3講到:輸入事件 由InputReader 獲取處理後,加入到了InputDispatcher中的 mInboundQueue 隊列了。
事件派發 首先從 mInboundQueue隊列中 取出輸入事件,而後進行處理。
//InputDispatcher.cpp void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { ... // Ready to start a new event. // If we don't already have a pending event, go grab one. if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { ... } else { // Inbound queue has at least one entry. //從mInboundQueue中 出隊 一個元素 mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); } // Poke user activity for this event. if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } // Get ready to dispatch the event. //這裏注意下,ANR相關。這裏先mark下,這篇不說明 resetANRTimeoutsLocked(); } // Now we have an event to dispatch. // All events are eventually dequeued and processed this way, even if we intend to drop them. ... switch (mPendingEvent->type) { ... case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); ... //分派事件 done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } ... }
取出事件後,而後分派,這裏一樣以 鍵盤按鍵事件爲例,直接看 dispatchKeyLocked():
直接看 dispatchKeyLocked():
//InputDispatcher.cpp bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { ... // Give the policy a chance to intercept the key. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { //派發給用戶,參考1.3.2.1 if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { //將InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible函數指針做爲參數 //執行postCommandLocked(),執行後 該函數被封裝到CommandEntry 加入到 mCommandQueue隊列 CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); //InputWindowHandle保存了窗口相關信息,由java層而來 //獲取焦點窗口的InputWindowHandle sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { //InputChannel也是一種跨進程 commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken()); } commandEntry->keyEntry = entry; entry->refCount += 1; return false; // wait for the command to run } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } } ... // Identify targets. //參考 1.3.2.3 std::vector<InputTarget> inputTargets; int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); ... // Add monitor channels from event's or focused display. addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry)); // Dispatch the key. //參考1.3.3 dispatchEvenfentLocked(currentTime, entry, inputTargets); return true; } InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry; }
經過postCommandLocked() 將 doInterceptKeyBeforeDispatchingLockedInterruptible 函數做爲參數,封裝到CommandEntry 最後加入到 mCommandQueue隊列。這個函數並無立刻運行。
這個doInterceptKeyBeforeDispatchingLockedInterruptible():
//InputDispatcher.cpp void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; ... sp<IBinder> token = commandEntry->inputChannel != nullptr ? commandEntry->inputChannel->getToken() : nullptr; nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags); ... entry->release(); }
interceptKeyBeforeDispatching() 相似1.2.2.4。最終也是 調用到PhoneWindowManager 中的同名方法。
InputWindowHandle:
InputWindowHandle保存了窗口相關信息,由java層而來。
關於InputWindowHandle 知道這大概是什麼,不影響此篇理解,就沒有徹底跟蹤下去。下面我的查看的路徑開始,內容挺多,也沒跟蹤徹底。先記錄下,後續再看。
//WindowManagerService.java public int addWindow(Session session, IWindow client, int seq, ...) { displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); } //InputMonitor.java /* Updates the cached window information provided to the input dispatcher. */ void updateInputWindowsLw(boolean force) { if (!force && !mUpdateInputWindowsNeeded) { return; } scheduleUpdateInputWindows(); }
InputChannel:
InputChannel也是一種跨進程, 本質也是socket。是一對建立的。
WindowState建立了一對InputChannel。server端註冊到InputDispatcher,創建了Connect。client端返回給應用進程的窗口,ViewRootImpl.setView()時傳入的參數mInputChannel。
InputDispatcher向其InputChannel中寫入事件,窗口就能夠從InputChannel中讀取了。
簡單列出下相關代碼:
//WindowManagerService.java public int addWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState) { final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0); if (openInputChannels) { //outInputChannel來自 ViewRootImpl.setView()時建立的 win.openInputChannel(outInputChannel); } } //WindowState.java void openInputChannel(InputChannel outInputChannel) { if (mInputChannel != null) { throw new IllegalStateException("Window already has an input channel."); } String name = getName(); //建立一對InputChannel,建立過程該篇不說明。 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); mInputChannel = inputChannels[0]; mClientChannel = inputChannels[1]; mInputWindowHandle.token = mClient.asBinder(); if (outInputChannel != null) { //mClientChannel傳遞給 outInputChannel mClientChannel.transferTo(outInputChannel); mClientChannel.dispose(); mClientChannel = null; } else { // If the window died visible, we setup a dummy input channel, so that taps // can still detected by input monitor channel, and we can relaunch the app. // Create dummy event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } //mInputChannel註冊到了InputDispatcher,註冊過程也不說明了。 mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder()); } //InputDispatcher.cpp status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, int32_t displayId) { { // acquire lock sp<Connection> connection = new Connection(inputChannel, false /*monitor*/); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); mInputChannelsByToken[inputChannel->getToken()] = inputChannel; mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); } // release lock }
直接看 findFocusedWindowTargetsLocked() :
//InputDispatcher.cpp int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; std::string reason; int32_t displayId = getTargetDisplayId(entry); sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); sp<InputApplicationHandle> focusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); ... // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(focusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), inputTargets); ... return injectionResult; } void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) { sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken()); if (inputChannel == nullptr) { ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str()); return; } const InputWindowInfo* windowInfo = windowHandle->getInfo(); InputTarget target; target.inputChannel = inputChannel; target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; target.globalScaleFactor = windowInfo->globalScaleFactor; target.windowXScale = windowInfo->windowXScale; target.windowYScale = windowInfo->windowYScale; target.pointerIds = pointerIds; inputTargets.push_back(target); }
找到目標的InputWindowHandle,生成一個InputTarget 而後加入到inputTargets中。
InputTarget包含了窗口的各類信息,如上能夠仔細看下。
直接看 dispatchEventLocked(),。
//InputDispatcher.cpp void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) { ATRACE_CALL(); ... pokeUserActivityLocked(eventEntry); for (const InputTarget& inputTarget : inputTargets) { ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } ... } } void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { ... // Not splitting. Enqueue dispatch entries for the event as is. enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); }
循環取出inputTargets的目標,一個個處理:
//InputDispatcher.cpp void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { ... bool wasEmpty = connection->outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); } } void InputDispatcher::enqueueDispatchEntryLocked( const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { ... DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->globalScaleFactor, inputTarget->windowXScale, inputTarget->windowYScale); ... // Enqueue the dispatch entry. connection->outboundQueue.enqueueAtTail(dispatchEntry); traceOutboundQueueLength(connection); }
Connection我的理解是一個通道。Connection中有一個outboundQueue隊列,上面將符合的事件封裝爲DispatchEntry放到Connection的outboundQueue隊列中了。
而後接着看分派週期 startDispatchCycleLocked():
//InputDispatcher.cpp void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { ... while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { //從connection的outboundQueue隊列取出一個元素 DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); // Publish the key event. //派發按鍵事件 status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, keyEntry->displayId, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, keyEntry->eventTime); break; } ... // Re-enqueue the event on the wait queue. connection->outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLength(connection); connection->waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLength(connection); } } //InputTransport.cpp InputPublisher::InputPublisher(const sp<InputChannel>& channel) : mChannel(channel) { } status_t InputPublisher::publishKeyEvent( ...) { ... InputMessage msg; msg.header.type = InputMessage::TYPE_KEY; msg.body.key.seq = seq; msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.displayId = displayId; msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; msg.body.key.scanCode = scanCode; msg.body.key.metaState = metaState; msg.body.key.repeatCount = repeatCount; msg.body.key.downTime = downTime; msg.body.key.eventTime = eventTime; //經過InputChannel發送消息 return mChannel->sendMessage(&msg); }
循環取出Connection中outboundQueue隊列中的 事件依次處理分派。這裏仍是 以按鍵 爲例,經過 inputPublisher.publishKeyEvent()
分派了事件,即 最終是 將事件等信息 封裝爲InputMessage, 經過InputChannel將 這個消息發送出去。
//InputTransport.cpp status_t InputChannel::sendMessage(const InputMessage* msg) { const size_t msgLength = msg->size(); InputMessage cleanMsg; msg->getSanitizedCopy(&cleanMsg); ssize_t nWrite; do { // nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); ... return OK; }
在InputDispatcher::dispatchOnce()中 ,前面講到的事件分派 都是 dispatchOnceInnerLocked()的執行,這個是 沒有掛起命令狀況下執行的(即mCommandQueue爲空)。
若是mCommandQueue非空,則會執行掛起的命令。如 在1.3.2.1中 攔截命令 被封裝 加入了mCommandQueue 隊列,而後分派就結束了。
若是mCommandQueue非空,會執行其中的命令,即 runCommandsLockedInterruptible() :
//InputDispatcher.cpp bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) { return false; } do { CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); Command command = commandEntry->command; (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' commandEntry->connection.clear(); delete commandEntry; } while (! mCommandQueue.isEmpty()); return true; }
在startOtherServices()中,建立了InputManagerService後,執行了 inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
。這個就是設置的回調(即設置了mWindowManagerCallbacks),與前面提到的 兩個攔截有關,1.2.2.4已經說的比較明白了。這裏主要其中mWindowManagerCallbacks是什麼。
這句話很簡單,直接看下:
//WindowManagerService.java final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this); public InputManagerCallback getInputManagerCallback() { return mInputManagerCallback; } //InputManagerService.java public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { mWindowManagerCallbacks = callbacks; }
這裏的 mWindowManagerCallbacks 就是 wm.getInputManagerCallback(),即 建立的InputManagerCallback對象。
前面 InputReader讀取事件 和 InputDispatcher分派事件,這個過程是在 InputReaderThread和InputDispatcherThread 兩個線程運行起來,執行了 threadLoop() 基礎上講解的。
那麼 這兩個線程是如何 運行起來,執行 threadLoop() 的?下面就來看下。
在 startOtherServices()中,建立IMS後,設置了回調,最後有 inputManager.start();
,這個就是 兩個線程運行起來 並執行了 threadLoop() 的起點。
//InputManagerService.java private static native void nativeStart(long ptr); public void start() { ... nativeStart(mPtr); ... }
這裏主要看下 nativeStart() 這個方法。 在 上面部分1.1 建立 InputManagerService中,你們還記得 mPtr 是:經過nativeInit()進入native建立 NativeInputManager 後的相關返回值(mPtr 是 reinterpret_cast
繼續跟蹤下去。
//com_android_server_input_InputManagerService.cpp static const JNINativeMethod gInputManagerMethods[] = { { "nativeStart", "(J)V", (void*) nativeStart }, } static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) { //mPtr又轉換成了NativeInputManager NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); ... }
mPtr又轉換成了NativeInputManager,而後調用了InputManager的 start()方法。 繼續看:
//InputManager.cpp status_t InputManager::start() { status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); ... result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); ... return OK; }
來看,這裏就是 InputReaderThread 和 InputDispatcherThread 兩個線程 執行了 run() 操做。 具體看下這個run() 作了些啥,須要看其父類Thread。
//system/core/libutils/Threads.cpp Thread::Thread(bool canCallJava) : mCanCallJava(canCallJava), ... { } status_t Thread::run(const char* name, int32_t priority, size_t stack) { Mutex::Autolock _l(mLock); ... bool res; //InputReaderThread 和 InputDispatcherThread 建立時傳入的 爲true。 if (mCanCallJava) { //建立線程。 注意這裏的 _threadLoop res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } else { res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } ... return OK; } //frameworks/native/services/inputflinger/InputReaderBase.cpp InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : Thread(/*canCallJava*/ true), mReader(reader) { } //frameworks/native/services/inputflinger/InputDispatcher.cpp InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { }
這裏,mCanCallJava 是 true(建立 InputReaderThread和InputDispatcherThread時 傳入的,上面代碼也列出),而後經過createThreadEtc() 即建立 線程。 注意其中有個參數 _threadLoop。下面是 _threadLoop。
//system/core/libutils/Threads.cpp int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); ... result = self->threadLoop(); ... return 0; }
這裏 就是 執行 自身的 threadLoop(),即 InputReaderThread 和 InputDispatcherThread 兩線程 執行 threadLoop()。
IMS端講完了,咱們知道最後消息經過InputChannel發送到目標窗口的進程了。接下來看目標窗口是如何接收傳遞的。
首先,來看下ViewRootImpl.setView() :
//ViewRootImpl.java InputQueue.Callback mInputQueueCallback; public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; ... if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { //建立InputChannel對象 mInputChannel mInputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; try { ... //這裏主要關注mInputChannel,它就是前面講到的一個InputChannel,wms建立一對後傳遞回來的 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets); setFrame(mTmpFrame); } ... if (mInputChannel != null) { if (mInputQueueCallback != null) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } //建立WindowInputEventReceiver,這裏的Looper是應用主線程的Looper mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); } ... } } }
前面也提到過,這裏建立的mInputChannel 最終做爲參數傳遞到WMS中,此時它什麼都沒有。在 WMS.addWindow()中 WindowState建立了一對InputChannel,其中一個經過transferTo()傳遞給了 mInputChannel。接下來就看WindowInputEventReceiver的建立。
//ViewRootImpl.java final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); } } //InputEventReceiver.java public InputEventReceiver(InputChannel inputChannel, Looper looper) { ... mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this), inputChannel, mMessageQueue); mCloseGuard.open("dispose"); }
經過nativeInit() 進入 native層:
//android_view_InputEventReceiver.cpp static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { ... //參考2.2,建立NativeInputEventReceiver sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); //參考2.3,執行initialize status_t status = receiver->initialize(); ... receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast<jlong>(receiver.get()); }
//android_view_InputEventReceiver.cpp class NativeInputEventReceiver : public LooperCallback { NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak, const sp<InputChannel>& inputChannel, const sp<MessageQueue>& messageQueue) : mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), mInputConsumer(inputChannel), mMessageQueue(messageQueue), mBatchedInputEventPending(false), mFdEvents(0) { ... } InputConsumer::InputConsumer(const sp<InputChannel>& channel) : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) { }
建立NativeInputEventReceiver,注意兩個地方 後面會講到的:
//android_view_InputEventReceiver.cpp status_t NativeInputEventReceiver::initialize() { setFdEvents(ALOOPER_EVENT_INPUT); return OK; } void NativeInputEventReceiver::setFdEvents(int events) { if (mFdEvents != events) { mFdEvents = events; int fd = mInputConsumer.getChannel()->getFd(); if (events) { //fd添加到Looper中,監聽InputChannel 讀取事件 mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL); } else { mMessageQueue->getLooper()->removeFd(fd); } } } /** * The file descriptor is available for read operations. */ ALOOPER_EVENT_INPUT = 1 << 0,
addFd()參數this是LooperCallback,即NativeInputEventReceiver。
跟蹤下,fd最終添加到Looper的mRequests列表中。
當Looper監聽到有輸入事件時,會回調 NativeInputEventReceiver的handleEvent()方法。 (這裏面的機制也還沒細究)
這個能夠參考下:Looper::pollInner()中 int callbackResult = response.request.callback->handleEvent(fd, events, data);
。
//android_view_InputEventReceiver.cpp int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { ... if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); //獲取事件,而後回調到java層的 InputEventReceiver.dispatchInputEvent status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL); } ... return 1; } //android_view_InputEventReceiver.cpp status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) { ... ScopedLocalRef<jobject> receiverObj(env, NULL); bool skipCallbacks = false; for (;;) { uint32_t seq; InputEvent* inputEvent; //從InputChannel讀取信息,並處理保存事件到inputEvent,參考2.4.1 status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent); ... if (!skipCallbacks) { ... if (inputEventObj) { ... //回調java層的 InputEventReceiver.dispatchInputEvent,參考2.4.2 env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); } } ... } } //jni註冊:android_view_InputEventReceiver.cpp int register_android_view_InputEventReceiver(JNIEnv* env) { int res = RegisterMethodsOrDie(env, "android/view/InputEventReceiver", gMethods, NELEM(gMethods)); jclass clazz = FindClassOrDie(env, "android/view/InputEventReceiver"); gInputEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "dispatchInputEvent", "(ILandroid/view/InputEvent;)V"); gInputEventReceiverClassInfo.dispatchBatchedInputEventPending = GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "dispatchBatchedInputEventPending", "()V"); return res; }
NativeInputEventReceiver::handleEvent() 到 NativeInputEventReceiver::consumeEvents()。這裏關注兩個:
//InputTransport.cpp status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { ... *outSeq = 0; *outEvent = nullptr; // Fetch the next input message. // Loop until an event can be returned or no additional events are received. while (!*outEvent) { //前面列出過InputConsumer建立時 mMsgDeferred爲false if (mMsgDeferred) { ... } else { // Receive a fresh message. //mChannel接收消息,即從socket中讀取 status_t result = mChannel->receiveMessage(&mMsg); ... } ... } switch (mMsg.header.type) { case InputMessage::TYPE_KEY: { ... initializeKeyEvent(keyEvent, &mMsg); *outSeq = mMsg.body.key.seq; *outEvent = keyEvent; break; } case InputMessage::TYPE_MOTION: { ... updateTouchState(mMsg); initializeMotionEvent(motionEvent, &mMsg); *outSeq = mMsg.body.motion.seq; *outEvent = motionEvent; break; } } return OK; }
經過InputChannel接受IMS端發送過來的消息,而且根據事件類型作了一些處理。
//InputEventReceiver.java @UnsupportedAppUsage private void dispatchInputEvent(int seq, InputEvent event) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event); }
前面知道,建立的是InputEventReceiver的子類WindowInputEventReceiver,所以onInputEvent()調用的是子類中方法:
//ViewRootImpl.java final class WindowInputEventReceiver extends InputEventReceiver { @Override public void onInputEvent(InputEvent event) { ... if (processedEvents != null) { ... } else { //輸入事件 加入隊列 enqueueInputEvent(event, this, 0, true); } } }
這裏繼續看 enqueueInputEvent():
//ViewRootImpl.java @UnsupportedAppUsage void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { //獲取QueuedInputEvent,event等封裝進去。 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); //獲取隊尾 QueuedInputEvent last = mPendingInputEventTail; //插入隊尾 if (last == null) { mPendingInputEventHead = q; mPendingInputEventTail = q; } else { last.mNext = q; mPendingInputEventTail = q; } //數目加1 mPendingInputEventCount += 1; Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, mPendingInputEventCount); //是否當即執行 if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } }
enqueueInputEvent() 首先將event等信息封裝到了QueuedInputEvent,而後將其插入輸入事件隊列的隊尾。
繼續看doProcessInputEvents():
//ViewRootImpl.java void doProcessInputEvents() { // Deliver all pending input events in the queue. while (mPendingInputEventHead != null) { QueuedInputEvent q = mPendingInputEventHead; ... deliverInputEvent(q); } }
循環處理隊列中全部事件,每次取隊首元素 傳遞處理。交由deliverInputEvent()方法處理。
繼續看deliverInputEvent():
//ViewRootImpl.java private void deliverInputEvent(QueuedInputEvent q) { ... InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (q.mEvent instanceof KeyEvent) { mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); } if (stage != null) { handleWindowFocusChanged(); //傳遞,參考3.1 stage.deliver(q); } else { finishInputEvent(q); } } public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { // Set up the input pipeline. CharSequence counterSuffix = attrs.getTitle(); mSyntheticInputStage = new SyntheticInputStage(); InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, "aq:native-post-ime:" + counterSuffix); InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); InputStage imeStage = new ImeInputStage(earlyPostImeStage, "aq:ime:" + counterSuffix); InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage); InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, "aq:native-pre-ime:" + counterSuffix); mFirstInputStage = nativePreImeStage; mFirstPostImeInputStage = earlyPostImeStage; mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix; }
在setView() 中,建立了 input pipeline,將事件一層層傳遞下去。 調用stage.deliver(q);
傳遞下去。
前面講到 事件已經傳遞到input pipeline中。這個暫不細究,往下繼續看傳遞到View中的傳遞。
直接看 stage.deliver(q) :
//ViewRootImpl.java abstract class InputStage { public final void deliver(QueuedInputEvent q) { if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { forward(q); } else if (shouldDropInputEvent(q)) { finish(q, false); } else { apply(q, onProcess(q)); } } }
onProcess(q)返回一個處理結果,apply根據這個結果再決定是否傳遞到InputStage的下一層。
這主要關注的 onProcess()。在ViewPostImeInputStage階段,開始向DecorView傳遞。
//ViewRootImpl.java final class ViewPostImeInputStage extends InputStage { @Override protected int onProcess(QueuedInputEvent q) { //處理不一樣類型的事件 if (q.mEvent instanceof KeyEvent) { //按鍵事件處理 return processKeyEvent(q); } else { final int source = q.mEvent.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { return processPointerEvent(q); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { return processTrackballEvent(q); } else { return processGenericMotionEvent(q); } } } private int processKeyEvent(QueuedInputEvent q) { final KeyEvent event = (KeyEvent)q.mEvent; ... // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; } ... return FORWARD; } }
onProcess()中對不一樣類型事件進行不一樣的處理。這裏仍然以按鍵事件爲例,處理方法processKeyEvent()。
這個mView即DecorView,setView()時 傳入的。
爲何是DecorView? 這個過程請參考: Android10_原理機制系列_Activity窗口添加到WMS過程。
//DecorView.java @Override public boolean dispatchKeyEvent(KeyEvent event) { final int keyCode = event.getKeyCode(); final int action = event.getAction(); final boolean isDown = action == KeyEvent.ACTION_DOWN; ... if (!mWindow.isDestroyed()) { final Window.Callback cb = mWindow.getCallback(); final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event); if (handled) { return true; } } return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event) : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event); }
若是是Activity的窗口,cb獲取到的是Activity,mFeatureId是-1。這裏的mWindow是PhoneWindow,即Activity在attach()時 建立的PhoneWindow,在setContentView()過程 經過mDecor.setWindow()傳入到DecorView中的。
這個mWindow.getCallback()獲取的是Activity自己,即Activity在attach()時setCallback() 傳入的this自己。
這個過程請參考( 那篇窗口添加到WMS中 說的很明白,這裏不列出了): Android10_原理機制系列_Activity窗口添加到WMS過程。
因爲按鍵事件 和 觸摸事件是 最多見的,這裏都簡單列舉了下。
接着前面,按鍵事件 能夠直接看cb.dispatchKeyEvent(event):
//Activity.java public boolean dispatchKeyEvent(KeyEvent event) { ... Window win = getWindow(); //交由Window繼續傳遞,返回false,則繼續交由Activity處理。若返回的true,則下層已處理掉了。 if (win.superDispatchKeyEvent(event)) { return true; } View decor = mDecor; if (decor == null) decor = win.getDecorView(); return event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this); } //PhoneWindow.java @Override public boolean superDispatchKeyEvent(KeyEvent event) { //傳遞給DecorView return mDecor.superDispatchKeyEvent(event); } //DecorView.java public boolean superDispatchKeyEvent(KeyEvent event) { ... //傳遞到ViewGroup。返回true,則下層處理了 上層不處理。 if (super.dispatchKeyEvent(event)) { return true; } return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event); } //ViewGroup.java @Override public boolean dispatchKeyEvent(KeyEvent event) { if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) { //傳遞給具體的View if (super.dispatchKeyEvent(event)) { return true; } } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { if (mFocused.dispatchKeyEvent(event)) { return true; } } return false; } //View.java public boolean dispatchKeyEvent(KeyEvent event) { ... // Give any attached key listener a first crack at the event. //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { return true; } if (event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)) { return true; } return false; } //KeyEvent.java public final boolean dispatch(Callback receiver, DispatcherState state, Object target) { switch (mAction) { case ACTION_DOWN: { mFlags &= ~FLAG_START_TRACKING; boolean res = receiver.onKeyDown(mKeyCode, this); ... return res; } case ACTION_UP: ... return receiver.onKeyUp(mKeyCode, this); case ACTION_MULTIPLE: ... return false; } return false; }
由上述代碼過程,keyEvent由外到內傳遞,由Activity到具體的View。
ListenerInfo就是關聯的咱們自定義的監聽,如setOnClickListener(),setOnLongClickListener。
這裏的傳遞是:由Activity到ViewGrop再到View,若是某個環節返回true,即事件被處理掉再也不向下層傳遞。若是最底層View仍未處理 而返回false,則再依次向外傳遞至Activity(向外傳遞中仍未被處理的話)處理。
注意:dispatchKeyEvent()都是有的。 onKeyDown,onKeyUp、onKeyLongPress等是View中有,一樣爲true即處理掉 不在傳遞了。
觸摸事件,相似按鍵事件,這裏直接看 最終傳遞到的Activity的地方。
//Activity.java public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } //傳遞到Window if (getWindow().superDispatchTouchEvent(ev)) { return true; } //若下層不處理,則調用onTouchEvent()處理掉。 return onTouchEvent(ev); } //PhoneWindow.java public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); } //DecorView.java public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); } //ViewGroup.java @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... boolean handled = false; if (onFilterTouchEventForSecurity(ev)) { ... // Check for interception. final boolean intercepted; ... //攔截 intercepted = onInterceptTouchEvent(ev); ... if (intercepted || mFirstTouchTarget != null) { ev.setTargetAccessibilityFocus(false); } //Update list of touch targets for pointer down, if needed. if (!canceled && !intercepted) { ... } // Dispatch to touch targets. if (mFirstTouchTarget == null) { // No touch targets so treat this as an ordinary view. handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { ... if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true; } } } return handled; } private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { ... // Perform any necessary transformations and dispatch. if (child == null) { handled = super.dispatchTouchEvent(transformedEvent); } else { ... handled = child.dispatchTouchEvent(transformedEvent); } return handled; } //View.java public boolean dispatchTouchEvent(MotionEvent event) { ... if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true; } //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } } if (!result && mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } ... return result; }
與按鍵事件相似,由外到內傳遞。也有ListenerInfo關聯View中自定義的監聽。
傳遞過程也基本同樣:由Activity到ViewGrop再到View,若是某個環節返回true,即事件被處理掉再也不向下層傳遞。若是最底層View仍未處理 而返回false,則再依次向外傳遞至Activity(向外傳遞中仍未被處理)處理。
注意:dispatchTouchEvent(),onTouchEvent()都是有的。 ViewGroup中多了個onInterceptTouchEvent(),若爲true, 則是將事件攔截,不在傳遞。
到此結束了,本篇差很少有上萬字了,但也只是個大概。仍需不斷學習。
多謝閱讀,歡迎交流。