
前言
- 事件分發(fā)機制是Android中的基礎(chǔ)而重要的知識,一般認(rèn)為
Activity#dispatchKeyEvent()或者Activity#dispatchTouchEvent()是分發(fā)的起點。那么問題來了,是誰調(diào)用了Activity的方法呢?輸入事件是如何產(chǎn)生的? - Android系統(tǒng)有一整套從
Linux內(nèi)核到應(yīng)用框架層到應(yīng)用層的事件處理機制 - 本文將以
InputManagerService為線索,分析輸入事件的產(chǎn)生-采集-分發(fā)流程,希望能幫上忙


1. 啟動服務(wù)
Android系統(tǒng)啟動后,系統(tǒng)進(jìn)程SystemServer.java將依次啟動各個系統(tǒng)服務(wù),我們搜索下InputManagerService,不會匹配到太多東西,梳理一下有關(guān)的代碼:
關(guān)于系統(tǒng)服務(wù)的更多介紹參考:[Android | 系統(tǒng)啟動過程]
// /frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
InputManagerService inputManager = null;
WindowManagerService wm = null;
// ...
// 實例化InputManagerService
inputManager = new InputManagerService(context);
// 實例化WindowManagerService
wm = WindowManagerService.main(context,inputManager,...);
// 添加到ServiceManager統(tǒng)一管理
ServiceManager.addService(Context.WINDOW_SERVICE, wm, ...);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,...);
// ...
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
// 啟動InputManager服務(wù)
inputManager.start();
}

可以看出,系統(tǒng)進(jìn)程分別實例化了InputManagerService 和 WindowManagerService,前者的實例直接傳入后者,而后者又傳遞了一個InputMonitor對象給前者,這是為什么呢?暫時跳過,繼續(xù)往下看InputManagerService.java:
// /frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
private static native long nativeInit(InputManagerService service,Context context, MessageQueue messageQueue);
private static native void nativeStart(long ptr);
public InputManagerService(Context context) {
// ...
// 調(diào)用了native層
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
// ...
}
public void start() {
// 調(diào)用了native層
nativeStart(mPtr);
// ...
}
這里只是調(diào)用到native層的兩個靜態(tài)方法,繼續(xù)往下看com_android_server_input_InputManagerService.cpp:
// /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// ...
// 實例化NativeInputManager對象
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 調(diào)用到InputManager#start()
status_t result = im->getInputManager()->start();
}
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
// ...
// 實例化EventHub對象
sp<EventHub> eventHub = new EventHub();
// 實例化InputManager對象
mInputManager = new InputManager(eventHub, this, this);
}
public:
inline sp<InputManager> getInputManager() const { return mInputManager; }
可以看出,在native層實例化了NativeInputManager,其構(gòu)造方法里還實例化了InputManager與EventHub對象,后者是干什么的呢?暫時跳過,繼續(xù)往下看InputManager.cpp:
// /frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
// 實例化InputDispatcher與InputReader
mDispatcher = new InputDispatcher(dispatcherPolicy);
// InputDispatcher實例與EventHub實例傳遞給InputReader
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
// 實例化兩個線程
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
// 運行兩個線程
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
// ...
}
可以看出,InputManager的構(gòu)造方法中實例化了InputDispatcher與InputReader,隨后start()中啟動了InputDispatcherThread線程與InputReaderThread線程(繼承于Thread.cpp)。

這兩個線程分別做什么事呢?繼續(xù)往下看InputReder.cpp與InputDispatcher.cpp:
// /frameworks/native/services/inputflinger/InputReader.cpp
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
// 繼承于Thread
Thread(/*canCallJava*/ true), mReader(reader) {
}
/**
* true:循環(huán)執(zhí)行threadLoop()直到調(diào)用requireExit()退出循環(huán)
**/
bool InputReaderThread::threadLoop() {
// 讀取/采集一次事件
mReader->loopOnce();
return true;
}
// /frameworks/native/services/inputflinger/InputDispatcher.cpp
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
bool InputDispatcherThread::threadLoop() {
// 分發(fā)一次事件
mDispatcher->dispatchOnce();
return true;
}
可以看到,到這里InputManagerService的啟動就完成了,提煉出關(guān)鍵點:
-
InputManagerService和WindowManagerService運行在系統(tǒng)進(jìn)程SystemServer -
InputManagerService啟動了InputReaderThread線程與InputDispatcherThread線程,分別死循環(huán)調(diào)用InputReader#loopOnce()與InputDispatcher#dispatchOnce()。

2. 采集事件
上一節(jié)講到,InputReaderThread線程死循環(huán)執(zhí)行InputReader#loopOnce(),用于采集事件,簡化代碼如下:
// /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
// ...
// 從EventHub中讀取事件,存儲在指針mEventBuffer中
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
if (count) {
// 處理讀取到的事件
processEventsLocked(mEventBuffer, count);
}
// ...
// 這一行是干什么的?稍后介紹
mQueuedListener->flush();
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
// 遍歷每個事件
for (const RawEvent* rawEvent = rawEvents; count;) {
// ...
int32_t type = rawEvent->type;
if(type < EventHubInterface::FIRST_SYNTHETIC_EVENT){
// 分支1:輸入事件
// ...
// 處理每一個輸入事件
int32_t deviceId = rawEvent->deviceId;
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}else{
// 分支2:設(shè)備事件
switch(rawEvent->type){
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
// ...
}
}
}
// ...
}
可以看到,loopOnce()從EventHub實例中獲取到原始事件,并依次處理每個事件,分為兩種:
- 輸入事件(分支1)
- 設(shè)備事件(分支2)
我們先看分支1的processEventsForDeviceLocked(),簡化代碼如下:
// /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
// ...
InputDevice* device = mDevices.valueAt(deviceIndex);
// ...
device->process(rawEvents, count);
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
size_t numMappers = mMappers.size();
// 遍歷每個事件
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
// 依次交給每個InputMapper處理
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}
}
可以看到,輸入事件交給了InputDevice處理,在內(nèi)部實際上是執(zhí)行了多次InputMapper#process(),這里的InputDevice和InputMapper是什么呢,還記得分支2的addDeviceLocked()嗎?簡化代碼如下:
// /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
// ...
// 創(chuàng)建InputDevice實例
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
// ...
// 添加到mDevices列表
// InputReader.h:KeyedVector<int32_t, InputDevice*> mDevices;
mDevices.add(deviceId, device);
// ...
}
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) {
// 創(chuàng)建InputDevice實例
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes);
// ...
// Scroll wheel-like devices. - 滾輪式
if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
device->addMapper(new RotaryEncoderInputMapper(device));
}
// ...
// Touchscreens and touchpad devices. - 觸屏式
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
// 多點觸控設(shè)備
device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
// 單點觸控設(shè)備
device->addMapper(new SingleTouchInputMapper(device));
}
// Joystick-like devices. - 操縱桿式
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
device->addMapper(new JoystickInputMapper(device));
}
// ...
}
可以看到分支2里,先創(chuàng)建了InputDevice實例,隨后根據(jù)不同的設(shè)備事件的類型,又添加了不同InputMapper,比如滾輪式,觸屏式,操縱桿式,這也就說明了,一個Android設(shè)備上是支持同時接入多個輸入設(shè)備的,當(dāng)然觸屏設(shè)備才是本文分析的重點。
讓我們回到分支1的InputMapper#process(),因為我們的重點是觸屏設(shè)備,所以我們只關(guān)心MultiTouchInputMapper和SingleTouchInputMapper,代碼如下:
// /frameworks/native/services/inputflinger/InputReader.cpp
// 多點觸控設(shè)備
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
// ...
}
// 單點觸控設(shè)備
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
// ...
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
// ...
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}
void TouchInputMapper::sync(nsecs_t when) {
// ...
processRawTouches(false /*timeout*/);
}
void TouchInputMapper::processRawTouches(bool timeout) {
// ...
cookAndDispatch(mCurrentRawState.when);
}
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
// ...
// 按鍵事件
if (consumeRawTouches(when, policyFlags)) {
mCurrentRawState.rawPointerData.clear();
}
// ...
// 觸點事件
dispatchPointerUsage(when, policyFlags, pointerUsage);
// ...
}
從簡化的代碼可以看出,不論是MultiTouchInputMapper還是SingleTouchInputMapper,最終都會走到cookAndDispatch()這個方法,分別處理了兩類事件:
- 按鍵事件
- 觸點事件
// /frameworks/native/services/inputflinger/InputReader.cpp
bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
// ...
// 處理虛擬按鍵事件
dispatchVirtualKey(...)
// ...
}
void TouchInputMapper::dispatchVirtualKey(...) {
// ...
// 實例化一個NotifyKeyArgs
NotifyKeyArgs args(...);
// 回調(diào)
getListener()->notifyKey(&args);
}
// /frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage) {
// ...
// 處理觸點事件
dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
// ...
}
void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) {
// ...
// 處理觸點事件
dispatchMotion(...)
// ...
}
void TouchInputMapper::dispatchMotion(...){
// ...
// 實例化一個NotifyMotionArgs
NotifyMotionArgs args(...);
// 回調(diào)
getListener()->notifyMotion(&args);
}
從簡化代碼可以看出,對于按鍵事件和觸點事件,分別實例化了NotifyKeyArgs和NotifyMotionArgs,隨后分別調(diào)用了getListener()->notifyKey()和getListener()->notifyMotion()。

getListener()->notifyKey()看起來很像是告知監(jiān)聽器已經(jīng)采集到事件了,是不是這樣呢?找一下getListener()相關(guān)代碼:
// /frameworks/native/services/inputflinger/InputReader.cpp
InputListenerInterface* InputReader::ContextImpl::getListener() {
// 弱指針的用法,簡單理解為返回了mQueuedListener就好
return mReader->mQueuedListener.get();
}
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) {
// 實例化QueuedInputListener
mQueuedListener = new QueuedInputListener(listener);
}
可以看出,getListener()的返回值是mQueuedListener,返回值類型是InputListenerInterface,它在InputReader的構(gòu)造方法中創(chuàng)建,并包裝了InputReader構(gòu)造方法的第三個參數(shù)listener,這個listener又是什么呢?讓我們回去找到實例化InputReader的地方:
// /frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(...) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
// InputDispatcher實例與EventHub實例傳遞給InputReader
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
原來如此,InputDispatcher實例就是這第三個參數(shù)listener,我們查看InputDispatcher和InputListenerInterface的定義:InputDispatcher.h與InputListener.h
// /frameworks/native/services/inputflinger/InputDispatcher.h
class InputDispatcher : public InputDispatcherInterface {
// ...
}
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
//...
}
// /frameworks/native/services/inputflinger/InputListener.h
/**
* 基類
**/
struct NotifyArgs {
virtual ~NotifyArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
};
/**
* 觸點事件
**/
struct NotifyMotionArgs : public NotifyArgs {
// ...
}
/**
* 按鍵事件
**/
struct NotifyKeyArgs : public NotifyArgs {
// ...
}
class InputListenerInterface : public virtual RefBase {/**弱指針**/
// ...
public:
virtual void notifyKey(const NotifyKeyArgs* args) = 0;
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
// ...
};
class QueuedInputListener : public InputListenerInterface {
// ...
public:
explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
virtual void notifyKey(const NotifyKeyArgs* args);
virtual void notifyMotion(const NotifyMotionArgs* args);
void flush();
// ...
private:
sp<InputListenerInterface> mInnerListener;
Vector<NotifyArgs*> mArgsQueue;
};
可以看到,QueuedInputListener和InputDispatcher都是實現(xiàn)了InputListenerInterface,前者其實就是后者的包裝類。

我們看看包裝類QueuedInputListener都做了什么,簡化代碼如下InputListener.cpp:
// /frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
// push到隊列中
mArgsQueue.push(new NotifyKeyArgs(*args));
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
// push到隊列中
mArgsQueue.push(new NotifyMotionArgs(*args));
}
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
// 遍歷每個NotifyArgs
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
// mInnerListener就是InputDispatcher
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
可以看到,之前的getListener()->notifyMotion()或者getListener()->notifyKey()都是把事件push到mArgsQueue隊列中。那么隊列中的這些事件到底什么時候才被處理呢?還記得InputReader#loopOnce()的最后一步嗎?
// /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
// ...
// 從EventHub中讀取事件,存儲在指針mEventBuffer中
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
if (count) {
// 處理讀取到的事件
processEventsLocked(mEventBuffer, count);
}
// ...
mQueuedListener->flush();
}
原來如此,所有事件被push到mArgsQueue隊列之后,會調(diào)用mQueuedListener->flush(),最終會調(diào)用到InputDispatcher#notifyKey()和InputDispatcher#notifyMotion(),歸納時序圖如下:

繼續(xù)查看InputDispatcher#notifyKey()和InputDispatcher#notifyMotion()的簡化代碼:
// /frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
// ...
// 實例化KeyEntry
KeyEntry* newEntry = new KeyEntry(...);
// 加入事件隊列
enqueueInboundEventLocked(newEntry);
// 喚醒在mLooper上等待的線程
mLooper->wake();
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
// ...
// 實例化MotionEntry
MotionEntry* newEntry = new MotionEntry(...);
// 加入事件隊列
enqueueInboundEventLocked(newEntry);
// 喚醒在mLooper上等待的線程
mLooper->wake();
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
// 加入隊列尾部
mInboundQueue.enqueueAtTail(entry);
// ...
}
可以看到,InputDispatcher#notifyKey()和InputDispatcher#notifyMotion()基本類似,都是將事件KeyEntry或MotionEntry加入隊列mInboundQueue尾部,隨后喚醒在mLooper(Looper.h)上等待的線程。

記得我們熟知的生產(chǎn)者-消費者模型嗎?
到這里,我們就完整地在InputReaderThread線程中執(zhí)行了一次loopOnce(),總結(jié)一下關(guān)鍵點:
-
InputReader從EventHub中讀取事件,其中一部分是輸入事件,我們關(guān)心的是按鍵事件和觸點事件 - 事件最終被加入
mInboundQueue隊列,隨即喚醒在mLooper上等待的線程
那么,喚醒的是哪個線程呢?會不會就是InputDispatcherThread線程呢?相關(guān)代碼如下:
// /frameworks/native/services/inputflinger/InputDispatcher.cpp
// --- InputDispatcherThread ---
InputDispatcherThread::InputDispatcherThread(...) {
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
}
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(...){
mLooper = new Looper(false);
}
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
// ...
// 分發(fā)一次事件
dispatchOnceInnerLocked(&nextWakeupTime);
// ...
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 在mLooper上等待一段時間
mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
// ...
// 獲取mInboundQueue隊列頭部的事件
mPendingEvent = mInboundQueue.dequeueAtHead();
//...
switch (mPendingEvent->type) {
// ...
case EventEntry::TYPE_KEY: {
// ...
// 分發(fā)按鍵事件
done = dispatchKeyLocked(...);
break;
}
case EventEntry::TYPE_MOTION: {
// ...
// 分發(fā)觸點事件
done = dispatchMotionLocked(...);
break;
}
}
// ...
}
可以看出,InputDispatcherThread線程中死循環(huán)運行dispatchOnce(),每一次都從mInboundQueue隊列中獲取頭部的事件,并執(zhí)行一次事件分發(fā)。每分發(fā)一次事件后都會調(diào)用mLooper->pollOnce()等待一段時間。等待的過程中,可能被InputReaderThread線程中執(zhí)行的mLooper.wake()提前喚醒,從而觸發(fā)下一次事件分發(fā)。
到這里,我們就完整分析了InputManagerService的事件采集流程,下一篇文章我們將討論事件分發(fā)過程,歡迎關(guān)注彭旭銳的簡書!
延伸閱讀
- [Android | 系統(tǒng)啟動過程]
- [Android | InputManagerService與輸入事件分發(fā)]
推薦閱讀
- 計算機組成原理 | 為什么浮點數(shù)運算不精確?(阿里筆試)
- Android | 自定義屬性
- Android | 文件存儲
- Android | 再按一次返回鍵退出
- 設(shè)計模式 | 靜態(tài)代理與動態(tài)代理
- 筆記 | 使用Markdown高效率編寫文檔
- 筆記 | Android Studio極速編譯
- 筆記 | 使用Keytool管理密鑰和證書
感謝喜歡!你的點贊是對我最大的鼓勵!歡迎關(guān)注彭旭銳的簡書!
