最近工作中遇到InputManagerService相关的问题,所以将InputReader和InputDispatcher看了一遍,水平有限,有的也没有理解。
这是input的中重要的两个类,这两个类由对应的两个线程来管理InputReaderThread和InputDispatcherThread,他们都是使用C++实现的。 首先简单介绍下InputManagerService的实现。
InputReaderThread InputDispatcherThread Binder(InputManagerService)… Proxy…
负责从/dev/input/下读取输入事件,之后将input_event进入队列,
通知inputDispatcherThread 处理 得到输入事件后,根据当前inputChannel情况,进行发送 负责对InputReader和InputDispatcher的管理, 提供接口供其他进程访问,如插入一个输入事件,注册一个inputChannel灯 外部调用,如果input作为一个模块的话,这个接口是真正对外开放的
1 俩线程的启动
JAVA: InputManagerService.nativeInt () ->C++:NativeInputManager()->C++:InputManager()->C++:InputManager->initialize():如下代码所示:
48:void InputManager::initialize() {
49: mReaderThread = new InputReaderThread(mReader);
50: mDispatcherThread = new InputDispatcherThread(mDispatcher);
51:}
注意在本文之后inputReaderThread简称R线程,inputDispatcherThread简称D线程。
2 InputReader的执行
重要的函数:InputReader->loopOnce();,R线程是不断地在这个函数里循环。下面就看这个函数做了什么,首先介绍几个不重要的成员变量:
mGeneration:这个变量是标识输入设备的变化的,也就是说当设备新建,添加,删除时就会执行loopOnce()中的这段代码:
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);
}
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
当调用这个函数时,如果有事件发生,count>0, 事件存储在mEventBuffer中。
mEventBuffer:这是存储时间的缓冲。
下面就是重要级的函数,对事件的处理processEventsLocked(mEventBuffer, count);
processEventsLocked->processEventsForDeviceLocked->device->process(rawEvents, count)->mapper->process(rawEvent);
mDevices: 每个输入设备的对象,每个输入设备对应一个process去处理它自己的事件。
mMappers:每个输入设备可能对应不同输入类型,这就需要要mMappers去处理,在mMapers->process中通过notify机制去通知D线程处理输入。
3 InputDispatcher:
InputDispatcher->dispatchOnce()->dispatchOnceInnerLocked:
mPendingEvent:当前需要处理的的事件,如果没有就从mInboundQueue中取。
mInboundQueue:InputDispatcher的事件队列,R线程负责进队列,D进程出队列处理事件。
mTouchState: 表示当前时间处理的状态。
当mPendingEvent的事件需要派发时,如下代码所示:
switch (mPendingEvent->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::TYPE_DEVICE_RESET: {
DeviceResetEntry* typedEntry =
static_cast<DeviceResetEntry*>(mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
break;
}
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEventLocked(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DROP_REASON_NOT_DROPPED) {
dropReason = DROP_REASON_APP_SWITCH;
}
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
default:
ALOG_ASSERT(false);
break;
}
if (done) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::TYPE_KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
if (isAppSwitchKeyEventLocked(keyEntry)) {
if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
ALOGD(“App switch is pending!”);
#endif
mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}
case EventEntry::TYPE_MOTION: {
// Optimize case where the current application is unresponsive and the user
// decides to touch a window in a different application.
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
&& mInputTargetWaitApplicationHandle != NULL) {
int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
if (touchedWindowHandle != NULL
&& touchedWindowHandle->inputApplicationHandle
!= mInputTargetWaitApplicationHandle) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
needWake = true;
}
}
break;
}
这些是处理事件的核心,我们就拿TYPE_MOTION举例,
dispatchMotionLocked->
findTouchedWindowTargetsLocked //填充inputTargets,是否有touchedWindowTarget需要事件
addMonitoringTargetsLocked //加入monitoringTarget
dispatchEventLocked -> //对inputTarget中的每个window进行派发事件
prepareDispatchCycleLocked->
enqueueDispatchEntriesLocked->
connection->outboundQueue.enqueueAtTail(dispatchEntry);
dispatchMotionLocked还是蛮复杂的,很多地方我也没弄明白。看代码话说windowmanagerService通过setInputWindows去填充InputDispacther的mWindowHandles,这是和所有window交流的根源,之后InputDispatcher填充inputTarget, 创建mConntionFd, 与需要input的window进行连接。