前言
- 事件分发机制是Android中的基础而重要的知识,一般认为
Activity#dispatchKeyEvent()
或者Activity#dispatchTouchEvent()
是分发的起点。那么问题来了,是谁调用了Activity
的方法呢?输入事件是如何产生的? - Android系统有一整套从
Linux内核
到应用框架层
到应用层
的事件处理机制 - 本文将以
InputManagerService
为线索,分析输入事件的产生-采集-分发
流程,希望能帮上忙
1. 启动服务
Android系统启动后,系统进程SystemServer.java将依次启动各个系统服务,我们搜索下InputManagerService
,不会匹配到太多东西,梳理一下有关的代码:
关于系统服务的更多介绍参考:[Android | 系统启动过程]
// /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统一管理
ServiceManager.addService(Context.WINDOW_SERVICE, wm, ...);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,...);
// ...
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
// 启动InputManager服务
inputManager.start();
}
可以看出,系统进程分别实例化了InputManagerService
和 WindowManagerService
,前者的实例直接传入后者,而后者又传递了一个InputMonitor
对象给前者,这是为什么呢?暂时跳过,继续往下看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) {
// ...
// 调用了native层
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
// ...
}
public void start() {
// 调用了native层
nativeStart(mPtr);
// ...
}
这里只是调用到native层的两个静态方法,继续往下看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);
// 调用到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
,其构造方法里还实例化了InputManager
与EventHub
对象,后者是干什么的呢?暂时跳过,继续往下看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
的构造方法中实例化了InputDispatcher
与InputReader
,随后start()
中启动了InputDispatcherThread
线程与InputReaderThread
线程(继承于Thread.cpp)。
这两个线程分别做什么事呢?继续往下看InputReder.cpp与InputDispatcher.cpp:
// /frameworks/native/services/inputflinger/InputReader.cpp
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
// 继承于Thread
Thread(/*canCallJava*/ true), mReader(reader) {
}
/**
* true:循环执行threadLoop()直到调用requireExit()退出循环
**/
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() {
// 分发一次事件
mDispatcher->dispatchOnce();
return true;
}
可以看到,到这里InputManagerService
的启动就完成了,提炼出关键点:
-
InputManagerService
和WindowManagerService
运行在系统进程SystemServer -
InputManagerService
启动了InputReaderThread
线程与InputDispatcherThread
线程,分别死循环调用InputReader#loopOnce()
与InputDispatcher#dispatchOnce()
。
2. 采集事件
上一节讲到,InputReaderThread
线程死循环执行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:设备事件
switch(rawEvent->type){
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
// ...
}
}
}
// ...
}
可以看到,loopOnce()
从EventHub
实例中获取到原始事件,并依次处理每个事件,分为两种:
- 输入事件(分支1)
- 设备事件(分支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
处理,在内部实际上是执行了多次InputMapper#process()
,这里的InputDevice
和InputMapper
是什么呢,还记得分支2的addDeviceLocked()
吗?简化代码如下:
// /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
// ...
// 创建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) {
// 创建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) {
// 多点触控设备
device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
// 单点触控设备
device->addMapper(new SingleTouchInputMapper(device));
}
// Joystick-like devices. - 操纵杆式
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
device->addMapper(new JoystickInputMapper(device));
}
// ...
}
可以看到分支2里,先创建了InputDevice
实例,随后根据不同的设备事件的类型,又添加了不同InputMapper
,比如滚轮式,触屏式,操纵杆式,这也就说明了,一个Android设备上是支持同时接入多个输入设备的,当然触屏设备才是本文分析的重点。
让我们回到分支1的InputMapper#process()
,因为我们的重点是触屏设备,所以我们只关心MultiTouchInputMapper
和SingleTouchInputMapper
,代码如下:
// /frameworks/native/services/inputflinger/InputReader.cpp
// 多点触控设备
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
// ...
}
// 单点触控设备
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(...);
// 回调
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(...);
// 回调
getListener()->notifyMotion(&args);
}
从简化代码可以看出,对于按键事件和触点事件,分别实例化了NotifyKeyArgs
和NotifyMotionArgs
,随后分别调用了getListener()->notifyKey()
和getListener()->notifyMotion()
。
getListener()->notifyKey()
看起来很像是告知监听器已经采集到事件了,是不是这样呢?找一下getListener()
相关代码:
// /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
的构造方法中创建,并包装了InputReader
构造方法的第三个参数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
实例就是这第三个参数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
都是实现了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
队列之后,会调用mQueuedListener->flush()
,最终会调用到InputDispatcher#notifyKey()
和InputDispatcher#notifyMotion()
,归纳时序图如下:
继续查看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)上等待的线程。
记得我们熟知的生产者-消费者模型吗?
到这里,我们就完整地在InputReaderThread
线程中执行了一次loopOnce()
,总结一下关键点:
-
InputReader
从EventHub
中读取事件,其中一部分是输入事件,我们关心的是按键事件
和触点事件
- 事件最终被加入
mInboundQueue
队列,随即唤醒在mLooper
上等待的线程
那么,唤醒的是哪个线程呢?会不会就是InputDispatcherThread
线程呢?相关代码如下:
// /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;
// ...
// 分发一次事件
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: {
// ...
// 分发按键事件
done = dispatchKeyLocked(...);
break;
}
case EventEntry::TYPE_MOTION: {
// ...
// 分发触点事件
done = dispatchMotionLocked(...);
break;
}
}
// ...
}
可以看出,InputDispatcherThread
线程中死循环运行dispatchOnce()
,每一次都从mInboundQueue
队列中获取头部的事件,并执行一次事件分发。每分发一次事件后都会调用mLooper->pollOnce()
等待一段时间。等待的过程中,可能被InputReaderThread
线程中执行的mLooper.wake()
提前唤醒,从而触发下一次事件分发。
到这里,我们就完整分析了InputManagerService
的事件采集流程,下一篇文章我们将讨论事件分发过程,欢迎关注彭旭锐的简书!
延伸阅读
- [Android | 系统启动过程]
- [Android | InputManagerService与输入事件分发]
推荐阅读
- 计算机组成原理 | 为什么浮点数运算不精确?(阿里笔试)
- Android | 自定义属性
- Android | 文件存储
- Android | 再按一次返回键退出
- 设计模式 | 静态代理与动态代理
- 笔记 | 使用Markdown高效率编写文档
- 笔记 | Android Studio极速编译
- 笔记 | 使用Keytool管理密钥和证书