原创内容,转载请注明出处,多谢配合。
上篇简单交代了下输入子系统,那么这篇主要分析下InputReader获取事件过程。
一、InputReader初始化
从前面初始化的介绍中,我们知道InputReader是在InputManager构造方法中被初始化的。
frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
值得留意的是,InputDispatcher作为参数传入了InputReader的构造方法。
再看InputReader的构造方法:
InputReader::InputReader(const sp& eventHub,
const sp& policy,
const sp& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);//这个listener对应的就是InputDispatcher
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
InputReader的构造函数中初始化了一个QueuedInputListener, 它接收InputListenerInterface作为它的参数,从InputReader调用可知,这个InputListenerInterface其实就是InputDispatcher, QueueInputListener只是作为InputDispatcher的Wrapper.这里先埋个伏笔。
二、InputReader运行
在InputManager执行start的时候InputReaderThread->run()
frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
接着执行 mReader->loopOnce();
void InputReader::loopOnce() {
…
//获取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//处理事件
processEventsLocked(mEventBuffer, count);
}
...
//传递事件
mQueuedListener->flush();
}
这里主要做了三件事:获取事件、处理事件、传递事件,下面分别来看看:
2.1 获取事件
EventHub->getEvents上一篇已经分析了,主要就是获取kernel的event, 这里事件不仅包括input,还包括输入设备的add/remove等相关事件。加入的输入设备在没有事件的时候,会block在EventHub中的epoll处,当有事件产生后,epoll_wait就会返回,然后针对变化的事件进行处理。
2.2 处理事件
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;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
//1、处理输入事件
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED://2、添加输入设备
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED://3、删除输入设备
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN://4、完成设备扫描
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
这里主要处理以上这4类事件,这里重点只关注下input event的收集流程:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
...
InputDevice* device = mDevices.valueAt(deviceIndex);//获取到对应的device
...
device->process(rawEvents, count);//device执行process操作
}
这里看到input的处理流程是由device执行process发起的。
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
...
if (mDropUntilNextSync) {
...
} 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 {//对应的EV_KEY type走如下流程
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);//对应的InputMapper执行process操作
}
}
}
}
这里执行的是mapper对应的process,而mapper实际上就是对应device中能匹配处理当前event的具体执行类。
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;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
这里以案件事件EV_KEY为例,这里会执行processKey方法
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
…
//调用eventhub的mapKey
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
&keyCode, &keyMetaState, &policyFlags)) {
...
}
...
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);//参数打包成args发送给Listener
}
最终将event组合成了一个notifykeyArgs数据结构,同时调用了listener的notifykey方法。
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
这里将NotifyKeyArgs放入了一个ArgsQueue中。
这部分简单来梳理一下:
InputReader收集不同设备输入信息,而不同设备对事件的处理又有分类,因为具体device的具体event交由对应的mapper来处理,而不匹配的则忽略。而mapper的处理主要是将event按NotifyArgs数据结构进行封装,并加入到一个ArgsQueue中。而NotifyArgs本身也是按事件类型来封装的。
2.3 传递事件
frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
从ArgsQueue把事件取出来,分别调用它们自己的notify方法
以NotifyKeyArgs为例:
void NotifyKeyArgs::notify(const sp& listener) const {
listener->notifyKey(this);
}
这个listener对应的是mInnerListener,那么要想知道Args传递到哪去了,就确定下mInnerListener是什么就好了。而在之前的初始化介绍部分已经埋过伏笔的,QueuedInputListener(listener);中传入的这个listener对应的就是InputDispatcher。
frameworks/native/services/inputflinger/InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp& innerListener) :
mInnerListener(innerListener) {
}
所以最终跟代码发现innerListener实际上就是InputDispatcher,notifyKey()就是InputDispacher的成员函数
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
...
int32_t keyCode = args->keyCode;
...
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action, flags, keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime);
…
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
...
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
if (needWake) {
mLooper->wake();//如果需要被唤醒,则唤醒dispatcher对应的Looper
}
}
这里重点看两个方法:interceptKeyBeforeQueueing 与 enqueueInboundEventLocked
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
...
if (keyEventObj) { //通过jni方式回调java层
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
} else {
ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
...
}
}
这部分其实就是PhoneWindowManager先做一次事件拦截处理操作,也就解释了为什么有些点击事件是不会传给应用的,而是在PhoneWindowManager那里就已经被拦截了。具体逻辑不铺开分析。
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast(entry);
...
break;
}
...
}
return needWake;
}
这里将keyArgs转换成KeyEntery这种数据封装,并添加到InputDispatcher的mInboundQueue里,最后唤醒InputDispacher线程。
最后简单总结一下整个InputReader获取事件流程:
在InputManager执行start的时候InputReaderThread->run(),接着会执行 mReader->loopOnce();
内部逻辑主要分三块:
获取事件:
getEvents时,打开"/dev/input/"目录下的input设备,并将其注册到epoll的监控队列中。这样一旦对应设备上有可读的input事件,则epool_wait()就会返回,并带回deviceid,找到具体的device。整个事件的获取中,除了input事件,设备的打开关闭等信息,也要包装成event,上报给InputReader。
处理事件:
processEventsForDeviceLocked 调用对应的InputDevice处理Input事件,而InputDevice又会去匹配上对应的InputMapper来处理对应事件。(在InputDevice中,存储着许多InputMapper,每种InputMapper对应一类Device,例如:Touch、Keyboard、Vibrator等等……)而调用InputDevice的process函数,就是将Input事件传递给每一个InputMapper,匹配的InputMapper就会对Input事件进行处理,不匹配的则会忽略。而对应的InputMapper最终会按对应的NotifyArgs数据结构对事件进行封装,并加入到ArgsQueue中。
传递事件:
flush会将ArgsQueue中的每一个Arg取出来交由innerListener对应的InputDispacher执行对应类型的notify方法,将keyArgs转换成KeyEntery这种数据封装,并添加到InputDispatcher的mInboundQueue里,最后唤醒InputDispacher线程。
最后放上整体流程图以及时序图
到这里,整个的input事件的获取就已经完成了。
下一篇文章:
Android Input(四) -InputDispatcher分发事件
参考:
https://www.jianshu.com/p/2bff4ecd86c9 借用两张图