在InputManagerService服务初始化时,会在Native层创建两个线程:InputDispatcherThread和InputReaderThread。InputReader线程负责读取输入事件,并把输入事件传递给InputDispatcher线程,然后由InputDispatcher将输入事件分发给处于激活的窗口。
接下来将从源码的角度来分析输入事件的一个分发过程。
在InputReaderThread线程中,将会循环执行其threadLoop()方法。
2.1 InputReaderThread.threadLoop()
bool InputReaderThread::threadLoop() {
mReader->loopOnce();//调用InputReader的loopOnce()方法,见2.2
return true;
}
当threadLoop()方法返回true时,代表将循环调用loopOnce()方法。当threadLoop()方法返回false时,代表退出循环。
2.2 InputReader.loopOnce()
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
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);// 1.从EventHub中获取输入事件,见2.3
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count);//2.如果获取到了输入事件,则处理该输入事件,见2.4
}
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
if (inputDevicesChanged) {// 输入设备发生了变化
mPolicy->notifyInputDevicesChanged(inputDevices);
}
mQueuedListener->flush();// 3.发送输入事件到InputDispatcher,见2.12
}
在loopOnce()方法中,主要做了三件事情:
接下来将分别围绕这三个过程来讲解。
2.3 EventHub.getEvents()
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer;//原始事件
size_t capacity = bufferSize;//容量大小为256
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// 当前时间
// 是否需要重新打开设备
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
closeAllDevicesLocked();
mNeedToScanDevices = true;
break;
}
// 记录最近被删除的设备
while (mClosingDevices) {
Device* device = mClosingDevices;
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
event->type = DEVICE_REMOVED;//事件类型为设备删除
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
// 需要扫描设备
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();//扫描设备,扫描的路径为/dev/input
mNeedToSendFinishedDeviceScan = true;
}
// 记录打开的设备
while (mOpeningDevices != NULL) {
Device* device = mOpeningDevices;
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;//事件类型为打开设备
event += 1;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
//结束设备扫描
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;//事件类型为设备扫描结束
event += 1;
if (--capacity == 0) {
break;
}
}
// 获取下一个输入事件
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];//获取待处理的epoll事件
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {//epoll数据类型为EPOLL_ID_INOTIFY
if (eventItem.events & EPOLLIN) {//epoll事件类型为可读
mPendingINotify = true;//发送通知
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
}
// epoll数据类型为EPOLL_ID_WAKE
if (eventItem.data.u32 == EPOLL_ID_WAKE) {
if (eventItem.events & EPOLLIN) {//epoll事件类型为可读
ALOGV("awoken after wake()");
awoken = true;//唤醒
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));//从mWakeReadPipeFd中读取数据
} 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);// 获取设备索引
Device* device = mDevices.valueAt(deviceIndex);// 根据设备索引获取设备
if (eventItem.events & EPOLLIN) {//如果epoll事件类型为可读
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);//从设备文件描述符中读取数据到readBuffer
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
.......
} else if ((readSize % sizeof(struct input_event)) != 0) {
......
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;//设备ID
size_t count = size_t(readSize) / sizeof(struct input_event);//获取读到的输入事件数量
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];//输入事件
.......
//将input_event事件,封装成RawEvent事件
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
if (capacity == 0) {
mPendingEventIndex -= 1;
break;
}
}
.....
// 如果获取到了输入事件或者需要唤醒,则立即返回
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
mLock.unlock();//释放锁
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();//获取锁
if (pollResult == 0) {//发生了超时
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// 发生了错误
mPendingEventCount = 0;
......
} else {
// 发生了一些输入事件
mPendingEventCount = size_t(pollResult);
}
}
}
return event - buffer;//然后读取的输入事件
}
在EventHub的getEvent方法中,如果是第一次调用的话,则需要先扫描/dev/input目录下的输入设备。接着用mPendingEventItems保存待处理的输入事件,如果以及有输入事件需要处理,则立即返回;否则通过epoll_wait等待输入事件到来。
从EventHub中获取到输入事件之后,接着调用processEventsLocked()方法进行事件处理。
2.4 InputReader.processEventsLocked()
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;//设备ID
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);// 处理设备事件,见2.7
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);//添加设备,见2.5
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;
}
}
count -= batchSize;//更新待处理的输入事件数量
rawEvent += batchSize;
}
}
事件处理总共有以下几种类型:
下面看下设备添加事件处理过程。
2.5 InputReader.addDeviceLocked()
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//设备索引
if (deviceIndex >= 0) {
//设备已经添加了,则直接返回
return;
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);//创建设备,见2.6
device->configure(when, &mConfig, 0);
device->reset(when);
mDevices.add(deviceId, device);//添加设备到mDevices中
......
}
2.6 InputReader.createDeviceLocked()
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);//创建InputDevice对象
// 外部设备
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device->setExternal(true);
}
// 鼠标
if (classes & INPUT_DEVICE_CLASS_MIC) {
device->setMic(true);
}
......
// 键盘类型
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;
}
// 添加键盘类设备KeyboardInputMapper
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
// 添加鼠标类设备CursorInputMapper
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(device));
}
// 添加触屏类设备MultiTouchInputMapper或者SingleTouchInputMapper
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;
}
该方法的主要功能是创建一个InputDevice对象,将InputReader的mContext对象赋值给InputDevice对象所对应的变量;根据设备的类型来创建并添加对应的InputMapper。
输入设备的类型有很多种,其中常见的包含以下几种:
介绍完了设备的添加过程,接下来回到2.4处,继续分析设备输入事件的处理过程,该过程主要是调用processEventsForDeviceLocked()方法。
2.7 InputReader.processEventsForDeviceLocked()
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//设备索引
if (deviceIndex < 0) {
//如果设备不存在,则直接返回
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);//获取设备
if (device->isIgnored()) {
//如果设备需要忽略,则直接返回
return;
}
device->process(rawEvents, count);//调用InputDevice的process方法来处理,见2.8
}
2.8 InputDevice.process()
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
size_t numMappers = mMappers.size();//mapper的数量
// 处理所有的输入事件
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
}
} else if(rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED){
mDropUntilNextSync = true;
reset(rawEvent->when);
}else {
// 调用每个mapper依次处理该事件
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];//获取InputMapper
mapper->process(rawEvent);// 调用InputMapper的处理方法,见2.9
}
}
}
}
针对每个mapper,顺序处理所有的输入事件。在前面的2.6过程中,创建了许多类型的InputMapper,这里我们将以KeyboardInputMapper(按键事件)为例来说明事件的传递过程。
2.9 KeyboardInputMapper.process()
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);//处理方法,见2.10
}
break;
}
......
}
}
在KeyboardInputMapper方法中,首先会判断扫描码是否为键盘码,如果是的话,则调用processKey()方法处理。
2.10 KeyboardInputMapper.processKey()
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
&keyCode, &keyMetaState, &policyFlags)) {// 根据扫描码获取对应的keyCode
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
if (down) {//处理按下的键
// 根据方向需要旋转keyCode
if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
keyCode = rotateKeyCode(keyCode, mOrientation);
}
// 添加key down事件
ssize_t keyDownIndex = findKeyDown(scanCode);// key down索引
if (keyDownIndex >= 0) {
// key事件重复了,必须确保和之前的keyCode一致
keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
} else {
if ((policyFlags & POLICY_FLAG_VIRTUAL)
&& mContext->shouldDropVirtualKey(when,
getDevice(), keyCode, scanCode)) {
return;
}
if (policyFlags & POLICY_FLAG_GESTURE) {
mDevice->cancelTouch(when);
}
// mKeyDowns记录着所有按下的键
mKeyDowns.push();//压入栈顶
KeyDown& keyDown = mKeyDowns.editTop();
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
}
mDownTime = when;//记录按下时间
}else{//处理抬起操作
移除key down事件
ssize_t keyDownIndex = findKeyDown(scanCode);// 查找key down事件
if (keyDownIndex >= 0) {
// key up操作,必须确保和之前的keyCode保持一致
keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
mKeyDowns.removeAt(size_t(keyDownIndex));
} else {
return;
}
}
......
nsecs_t downTime = mDownTime;
......
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);//创建NotifyKeyArgs对象,when记录eventTime,downTime记录按下时间。
getListener()->notifyKey(&args);//通知key事件,见2.11
}
在processKey方法中,首先根据扫描码获取到对应的keyCode方法,构建NotifyKeyArgs对象,然后调用notifyKey()方法通知key事件。
NotifykeyArgs对象记录了key按下的时间,keyCode以及scanCode,定义如下:
NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
metaState(metaState), downTime(downTime) {
}
getListener()方法获取的是mQueuedListener,而mQueuedListener的类型是QueuedInputListener。
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
sp mQueuedListener;
2.11 QueuedInputListener.notifyKey()
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
mArgsQueue的数据类型为Vector
InputReader的核心工作就是从EventHub获取数据后生成EventEntry事件,然后加入到InputDispatcher的mInboundQueue队列,最后唤醒InputDispatcherThread线程进行处理。InputReader整个工作流程包含以下三个部分:
InputReader的调用过程如下:
InputReaderThread.threadLoop()
InputReader.loopOnce()
EventHub.getEvents()
InputReader.processEventsLocked()
InputReader.addDeviceLocked()
InputReader.createDeviceLocked()
InputReader.processEventsForDeviceLocked()
InputDevice.process()
KeyboardInputMapper.process()
KeyboardInputMapper.processKey()
QueuedInputListener.notifyKey()
QueuedInputListener.flush()
NotifyKeyArgs.notify()
InputDispatcher.notifyKey()
NativeInputManager.interceptKeyBeforeQueueing()
InputManagerService.interceptKeyBeforeQueueing()
InputMonitor.interceptKeyBeforeQueueing()
PhoneWindowManager.interceptKeyBeforeQueueing()
NativeInputManager.filterInputEvent()
InputDispatcher.enqueueInboundEventLocked()
Looper.wake()
InputManagerService分发输入事件消息给应用程序(下)将从InputDispatcherThread线程开始分析,InputDispatcher如何将输入事件分发到应用程序激活的Activity窗口。