在上一节 input输入事件番外3 中讲到 IMS 在 native 层的启动,其中关于事件读取线程循环读取事件时调用了如下代码:
// 循环执行任务
bool InputReaderThread::threadLoop() {
mReader->loopOnce(); // 循环执行 mReader 的 loopOnce() 方法;
return true;
}
事件的读取关键就是 InputReader 的 loopOnce() 方法,接下来就从这个方法入手分析 InputReader 这个类以及它所要完成的任务;
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
// 1. 读取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 2. 事件的简单处理;
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// 3. 把事件传给 InputDispatcher 处理(也可以理解为交给分发线程处理)
mQueuedListener->flush(); // 这个 mQueuedListener 其实就是 InputDispatcher
}
从上面的代码中可以总结为三点:
(1)读取事件;
(2)事件的简单处理;
(3)把事件传给 InputDispatcher 处理(也可以理解为交给分发线程处理);
1. 读取事件
读取事件是通过 mEventHub->getEvents() 方法获取的,其基本原理在 Linux知识 中已经介绍过,接下来简单分析一下 EventHub。
1.1 EventHub 的构造函数:
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);
//(epoll 的用法第 1 步):epoll_create()
mEpollFd = epoll_create(EPOLL_SIZE_HINT); // EPOLL_SIZE_HINT 指定最大监听个数为 8
// inotify 用法第 1 步:inotify_init(),初始化 fd
mINotifyFd = inotify_init();
// inotify 用法第 2 步:inotify_add_watch(),监测;其中 DEVICE_PATH = "/dev/input";
// inotify 用法第 3 步:read(),读取;在 getEvents() 中调用
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; // 这里并没有使用fd字段,而使用了自定义的值EPOLL_ID_INOTIFY
//(epoll 的用法第 2 步):epoll_ctl()
//(epoll 的用法第 3 步):epoll_wait();在 getEvents() 中调用
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); // 将对mINotifyFd的监听注册到epoll对象中
// ... 省略部分代码 见注释 1
}
在构造函数中,使用了 inotify 机制监测 "/dev/input" 目录的变化;使用 epoll 监测有无数据;大致流程如下:
(1)创建 inotify 的文件句柄 mINotifyFd = inotify_init() 并通过 inotify_add_watch() 监测 "/dev/input" 目录;
(2)在 openDeviceLocked() 中调用 fd = open(devicePath, O_RDWR | O_CLOEXEC) 打开各种设备节点,例如 /dev/input/event0;
(3)使用 epoll_wait() 监测这些文件句柄 mINotifyFd、fd;
(4)读取文件句柄,构造相应的 RawEvent (下面有介绍),例如新增了设备节点就可以通过 mINotifyFd 监测到;
注释1:在构造函数省略的代码中,EventHub 创建了一个名为 wakeFds 的匿名管道,并将管道读取端的描述符的可读事件注册到 epoll 对象中。因为 InputReader 在执行 getEvents() 时会因无事件而导致其线程阻塞在 epoll_wait() 的调用里,然而有时希望能够立刻唤醒 InputReader 线程使其处理一些请求。此时只需向 wakeFds 管道的写入端写入任意数据,此时读取端有数据可读,使得epoll_wait() 得以返回,从而达到唤醒 InputReader 线程的目的;
1.2 获取事件:getEvents()
通过 mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE) 方法来获取事件,其中 mEventBuffer 是一个大小为 256 的 RawEvent 数组,用于存放获取到的事件;
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
struct RawEvent {
nsecs_t when;
int32_t deviceId;
int32_t type; // 事件的类型
int32_t code;
int32_t value;
};
// RawEvent 的 type 类型:
enum {
// Sent when a device is added.
DEVICE_ADDED = 0x10000000,
// Sent when a device is removed.
DEVICE_REMOVED = 0x20000000,
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
// 另外在扫描 "dev/input" 目录下设备节点的过程中,中可以发现还有一下的一些事件类型:
// openDeviceLocked() 中;
// EV_KEY 0x01 按键事件
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
// EV_ABS 0x03 绝对坐标,如触摸屏上报的坐标
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
// EV_REL 0x02 相对坐标, 如鼠标上报的坐标
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
// 用来描述具备两种状态的输入开关
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
// EV_LED 0x11 LED
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
// EV_FF 0x15 力反馈
ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
// 另外,还有 EV_SYN(0x00 同步事件);SYN_REPORT(一次事件的结尾) 等等;
// 收到一个点之后并不会立即处理,而是一个事件完成之后才会处理,SYN_REPORT就是这个事件的标志。
接下来是 getEvents() 的分析:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
// event指针指向了在 buffer 下一个可用于存储事件的 RawEvent 结构体。每存储一个事件,event 指针都回向后偏移一个元素
RawEvent* event = buffer;
// capacity 记录了 buffer 中剩余的元素数量。当capacity为0时,表示 buffer 已满,此时需要停继续处理新
// 事件,并将已处理的事件返回给调用者
size_t capacity = bufferSize;
bool awoken = false;
// getEvents()的关键部分:在这个循环中,会先将可用事件放入到buffer中并返回。如果没有可用事件,
// 则进入 epoll_wait() 等待事件的到来,epoll_wait() 返回后会重新循环将可用将新事件放入 buffer
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// ... 省略部分代码
//(1)第一步:****************************** 见下方解释 *****************************
if (mNeedToScanDevices) { // 稍稍注意下在 EventHub 构造函数中 mNeedToScanDevices(true)
mNeedToScanDevices = false;
// 第一次进入时扫描 "dev/input" 目录下所有的设备节点时,会建立设备列表存储在mDevice成员变量
// 中 (EventHub中有设备列表 KeyedVector mDevices);并通过 open() 函
// 数打开节点,最终调用 epoll_ctl() 添加到 epoll 中;
scanDevicesLocked(); // 这个方法有兴趣可以跟进去看看
mNeedToSendFinishedDeviceScan = true;
}
// ...
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
// Grab the next input event.
//(2)第二步:****************************** 见下方解释 *****************************
bool deviceChanged = false;
// mPendingEventItems:处理未被 InputReader 取走的输入事件与设备事件
while (mPendingEventIndex < mPendingEventCount) {
/* 在这里分析每一个 epoll_event,如果是表示设备节点可读,则读取原始事件并放置到 buffer
中。如果是表示 mINotifyFd 可读,则设置 mPendingINotify 为 true,当 InputReader
将现有的输入事件都取出后读取 mINotifyFd 中的事件,并进行相应的设备加载与卸载操作。
另外,如果此 epoll_event 表示 wakeFds 的读取端有数据可读,则设置 awake 标志为 true,
无论此次 getEvents() 调用有无取到事件,都不会再次进行 epoll_wait() 进行事件等待 */
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (deviceIndex < 0) {
ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
eventItem.events, eventItem.data.u32);
continue;
}
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
// input_event 是 linux kernel 获取到的输入事件
struct input_event& iev = readBuffer[i];
if (iev.type == EV_MSC) {
if (iev.code == MSC_ANDROID_TIME_SEC) {
device->timestampOverrideSec = iev.value;
continue;
} else if (iev.code == MSC_ANDROID_TIME_USEC) {
device->timestampOverrideUsec = iev.value;
continue;
}
}
if (device->timestampOverrideSec || device->timestampOverrideUsec) {
iev.time.tv_sec = device->timestampOverrideSec;
iev.time.tv_usec = device->timestampOverrideUsec;
if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
device->timestampOverrideSec = 0;
device->timestampOverrideUsec = 0;
}
ALOGV("applied override time %d.%06d",
int(iev.time.tv_sec), int(iev.time.tv_usec));
}
#else
event->when = now;
#endif
// 将 input_event 封装成 RawEvent
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.string());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.string());
}
}
//(3)第三步:****************************** 见下方解释 *****************************
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
/* 读取 mINotifyFd 中的事件,同时对输入设备进行相应的加载与卸载操作。这个操作必须当
InputReader 将现有输入事件读取并处理完毕后才能进行,因为现有的输入事件可能来自需要
被卸载的输入设备,InputReader 处理这些事件依赖于对应的设备信息 */
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
// 设备节点增删操作发生时,则重新执行循环体,以便将设备变化的事件放入buffer中
if (deviceChanged) {
continue;
}
// Return now if we have collected any events or if we were explicitly awoken.
// 如果此次getEvents()调用成功获取了一些事件,或者要求唤醒InputReader,则退出循环并
// 结束getEvents()的调用,使InputReader可以立刻对事件进行处理
if (event != buffer || awoken) {
break;
}
//(4)第四步:****************************** 见下方解释 *****************************
// 此次getEvents()调用没能获取事件
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
// Sleep after errors to avoid locking up the system.
// Hopefully the error is transient.
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
// 从 epoll_wait() 中得到新的事件后,重新循环,对新事件进行处理
mPendingEventCount = size_t(pollResult);
}
}
// All done, return the number of events we read.
// 返回本次getEvents()调用所读取的事件数量
return event - buffer;
}
(1)第一步:首先进行与设备相关的工作。如 EventHub 创建后第一次执行 getEvents() 函数时,需要扫描 "/de/input" 目录下所有设备节点并打开这些设备节点。另外,当设备节点的发生增加时,会将设备事件存入到 buffer 中;
(2)第二步:处理未被 InputReader 取走的输入事件与设备事件。epoll_wait() 所取出的 epoll_event 存储在mPendingEventItems中,mPendingEventCount 指定了 mPendingEventItems 数组所存储的事件个数。而mPendingEventIndex 指定尚未处理的 epoll_event 的索引;
(3)第三步:如果 mINotifyFd 有数据可读,说明设备节点发生了增删操作;
(4)第四步:如果此次 getEvents() 调用没能获取事件,说明 mPendingEventItems 中没有事件可用,于是执行 epoll_wait() 函数等待新的事件到来,将结果存储到 mPendingEventItems 里,并重置 mPendingEventIndex 为 0;
2. 事件的简单处理
在 InputReader 中 loopOnce() 方法中调用 processEventsLocked(mEventBuffer, count) 会对获取到的事件进行简单的处理,其复杂的处理及分发是在 InputDispatcher 中完成的;
// 根据获取到的 RawEvent 的 type 类型进行处理:
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
// 如果是常规的 event 事件,FIRST_SYNTHETIC_EVENT = DEVICE_ADDED (0x10000000)
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;
}
// processEventsForDeviceLocked() 处理一般的事件: 见 2.2
// 把这次获取到的 event 数组中属于同一批次的,进一步处理,判定条件就是:常规 event 以及是属于同一设备
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}
// 处理 3 种特殊的事件:例如添加设备, 见 2.1
else { // 这里就是3种特殊的 event 类型,例如有时候打开设备的时候会有这个 ADD 事件
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
// 如果在上面没有处理完 event 数组中的成员,那么依次继续
count -= batchSize;
rawEvent += batchSize;
}
}
2.1 添加设备:
既然是添加设备,那么必定有一个容器来保存这些设备,这个容器就是 KeyedVector
// EventHub 中的 Device:
struct Device {
Device* next;
// 文件句柄;
int fd; // may be -1 if device is virtual
// classes 信息,在 InputReader 中会用到;
uint32_t classes;
// 设备信息;
const InputDeviceIdentifier identifier;
// 配置信息(例如 Linux 内核获取到的按键值1,在 Android 中经过配置文件转换并不是1,而是其他值);
String8 configurationFile;
PropertyMap* configuration;
// ... 省略
}
// InputReader 中的 InputDevice:
class InputDevice {
private:
InputReaderContext* mContext;
int32_t mId;
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
// 关注点:这里有一个 InputMapper 的成员变量,它的作用是将各种封装了各种不同的事件类型,例如
// 键盘事件的设备对应的是 KeyboardInputMapper;
Vector mMappers;
// ... 省略
}
这里就会有一个问题,为什么对于一个设备要进行添加两次,这么做是不是多余的呢?在我看来,这么设计的目的应该是一个分层设计(或者说单一职责)的思想;在 EventHub 中处理的是比较原始的数据,主要是一些事件的获取、设备的配置等工作,而在 InputReader 中是对 EventHub 中获取的一些事件进行初步处理和传递事件发给 InputDispatcher 处理,所以才这么封装的;
那么,接下来就分析一下添加设备的源代码 addDeviceLocked():
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; 详见下面 createDeviceLocked() 的分析
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
if (device->isIgnored()) {
ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
identifier.name.string());
} else {
ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
identifier.name.string(), device->getSources());
}
mDevices.add(deviceId, device); // 将创建出的 device 加入到 mDevices 中;
bumpGenerationLocked();
}
创建 InputDevice:createDeviceLocked()
// 根据 rawEvent 中的 deviceId 创建相应的 InputDevice 并添加相应的 Mapper
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device->setExternal(true);
}
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
}
// Vibrator-like devices.
if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
device->addMapper(new VibratorInputMapper(device));
}
// Keyboard-like devices.
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
// Cursor-like devices.
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(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));
}
return device;
}
2.2 事件初步处理:
// InputReader.cpp 中 processEventsForDeviceLocked() 方法:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
// 这里根据 deviceId 取出上面添加进去的 InputDevice
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
// InputReader.cpp 中 process() 方法:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// 这里有个 mapper 数组,在 create 时 会根据 classes 类型去匹配处理 mapper,一般都是匹配一个
size_t numMappers = mMappers.size();
// 遍历事件数组,依次去处理
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
ALOGD("Recovered from input event buffer overrun.");
} else {
ALOGD("Dropped input event while waiting for next input sync.");
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().string());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (size_t i = 0; i < numMappers; i++) {
// 调用 mapper 的 process 函数,交给 InputDispatcher 并开始分发流程;
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent); // 最终是调用了 设备相应的 mapper->process(rawEvent) 方法;
}
}
}
}
3. 事件传递给 InputDispatcher 处理:
事件经过获取,初步处理,最终执行了 mapper->process(rawEvent) 方法,对于 mapper->process() 这个方法需要查看 InputReader::createDeviceLocked() 中创建的具体的InputMapper的process函数。下面就以 SingleTouchInputMapper 的 process() 为例:
SingleTouchInputMapper 的 process() 方法:
// (1)
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent); // 调用父类的process
mSingleTouchMotionAccumulator.process(rawEvent);
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
// 一组同步事件,并且已经完结(有事件结束标值 SYN_REPORT);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when); // 关键方法,后续有分析;
}
}
/**
以下语句均是将输入事件信息转存至类成员变量中:
mCursorButtonAccumulator.process(rawEvent); // 注释 1
mCursorScrollAccumulator.process(rawEvent); // 注释 2
mTouchButtonAccumulator.process(rawEvent); // 注释 3
mSingleTouchMotionAccumulator.process(rawEvent); // 注释 4
**/
注释1:mCursorButtonAccumulator.process(rawEvent)
记录鼠标或触摸板的按键状态:记录 rawEvent->type 为 EV_KEY,且rawEvent->code为BTN_LEFT、BTN_RIGHT、BTN_MIDDLE、BTN_BACK、BTN_SIDE、BTN_FORWARD、BTN_EXTRA、BTN_TASK 事件。
注释2:mCursorScrollAccumulator.process(rawEvent)
记录光标滚动:记录rawEvent->type为EV_REL,且rawEvent->code为REL_WHEEL、REL_HWHEEL 事件。
注释3:mTouchButtonAccumulator.process(rawEvent)
记录触摸 手写笔 工具按钮状态:记录rawEvent->type为EV_KEY,且rawEvent->code为BTN_TOUCH、BTN_STYLUS、BTN_STYLUS2、BTN_TOOL_FINGER、BTN_TOOL_PEN、BTN_TOOL_RUBBER、BTN_TOOL_BRUSH、BTN_TOOL_PENCIL、BTN_TOOL_AIRBRUSH、BTN_TOOL_MOUSE、BTN_TOOL_LENS、BTN_TOOL_DOUBLETAP、BTN_TOOL_TRIPLETAP、BTN_TOOL_QUADTAP 事件。
BTN_TOUCH 的数据在这里被处理了,且其 value 被保存在 mBtnTouch 成员变量中;
注释4:mSingleTouchMotionAccumulator.process
记录ABS相关的值,记录rawEvent->type为EV_ABS,且rawEvent->scanCode为ABS_X、ABS_Y、ABS_PRESSURE、ABS_TOOL_WIDTH、ABS_DISTANCE、ABS_TILT_X、ABS_TILT_Y的事件。
ABS_X和ABS_Y 的数据在这里被处理了。
TouchInputMapper 中的 sync(nsecs_t when)方法:
// 输入事件分发的关键在 sync(nsecs_t when) 中:这个同步函数比较长,下面是简化后的代码,重点事件的分发
void TouchInputMapper::sync(nsecs_t when) {
// Sync button state.
mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
// Sync scroll state.
mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch state.
bool havePointerIds = true;
mCurrentRawPointerData.clear();
/*调用子类的 syncTouch,这里是 SingleTouchMotionAccumulator的syncTouch(),
更新 ABS 坐标值,这里是把数据存入到 mCurrentRawPointerData 中供下面 cook */
syncTouch(when, &havePointerIds); //这里是一个虚函数
/***** 虚函数是一个类中希望重载的成员函数 ,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数 *****/
// Reset state that we will compute below.
mCurrentFingerIdBits.clear();
mCurrentStylusIdBits.clear();
mCurrentMouseIdBits.clear();
mCurrentCookedPointerData.clear(); // 先清除一下
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled.
mCurrentRawPointerData.clear();
mCurrentButtonState = 0;
} else {
// ...
// 这个函数很庞大,cook 数据,主要是生成 mCurrentCookedPointerData.pointerCoords,
// mCurrentCookedPointerData.pointerProperties 和 mCurrentCookedPointerData.idToIndex
cookPointerData();
if (mDeviceMode == DEVICE_MODE_POINTER) {
PointerUsage pointerUsage = mPointerUsage;
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != NULL) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentButtonState);
mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
mCurrentCookedPointerData.touchingIdBits);
}
// 分发事件,这里的三个方法最终都回调用 dispatchMotion()
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
}
// 之后的代码是一些数据保存之类的操作
// ...
}
// ...
mCurrentRawVScroll = 0;
mCurrentRawHScroll = 0;
}
事件传递给 InputDispatcher 处理 dispatchMotion():
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
// ...
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
// 这里的 getListener() 其实就是 InputReader 的构造函数中传入的 mDispatcher 作为回调,只是做了进一步封装;
getListener()->notifyMotion(&args);
}
通过调用 dispatchMotion() 方法,事件最终交由 InputDispatcher 处理,到这里本小节的内容就结束了,下一节将继续 InputDispatcher 的学习。