本文主要描述了Android Input框架中的InputDispatcher的功能和数据处理流程。InputDispatcher的功能总结成一句话就是处理InputReader传递过来的事件并将事件进行再次封装为一个InputDispatcher事件然后传递给App进行处理,当App处理完成后,通知InputDispatcher模块清理InputDispatcher上报的事件,即完成整个输入事件的处理流程。
frameworks/native/services/inputflinger/InputDispatcher.cpp
frameworks/native/services/inputflinger/InputReader.cpp
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
InputDispatcher的初始化由InputManager完成,如下所示:
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
/* 创建事件分发对象 */
mDispatcher = new InputDispatcher(dispatcherPolicy);
/* 创建事件获取对象 */
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputDispatcher初始化中传递了一个dispatcherPolicy参数,该参数是NativeInputManager对象,如下所示:
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
......
mInputManager = new InputManager(eventHub, this, this);
}
然后,我们进入InputDispatcher类的构造函数,如下所示:
InputDispatcher::InputDispatcher(const sp& policy) :
mPolicy(policy),
mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
// 创建Looper
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
}
初始化过程比较简单,最关键就是创建了一个自己的Looper对象处理自己的消息,感兴趣的同学可以研究一下Looper的实现,这里我们不再详细描述其作用。
InputDispatcher的运行在InputDispatcherThread线程中,如下所示:
void InputManager::initialize() {
......
/* 创建事件分发线程 */
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
/* 开启事件分发线程 */
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
......
return OK;
}
调用线程运行回调接口,如下所示:
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
// 如果Command队列为空的情况下,才处理mInboundQueue队列中的事件
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
// 处理command队列
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
// 计算epoll阻塞等待的超时时间
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 阻塞等待timeoutMillis
mLooper->pollOnce(timeoutMillis);
}
InputDispatcher的线程回调逻辑比较简单,主要逻辑如下:
1、优先处理Command队列中的事件,InputDispatcher将所有处理的事务,封装为一个Command事项加入Command队列等待处理。实现了事件的异步处理,并不需要同步等待处理结果。
2、当Command队列为空时,从InputDispatcher的事件管理队列mInboundQueue中获取事件(本质上是InputReader上报的事件)进行处理,处理的过程后面的章节有详细描述;
3、如果mInboundQueue队列也为空,则InputDispacher进入阻塞等待事件的到来;
当InputDispatcher开始运行时,Command队列为空,mInboundQueue队列也为空,InputDispatcher进入阻塞等待事件的到来。我们在前一个章节讲述过,InputReader最终将事件传递给InputDispatcher的notify*接口,比如触摸屏幕调用noifyMotion接口,如下所示:
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
....
needWake = enqueueInboundEventLocked(newEntry);
....
if (needWake) {
mLooper->wake();
}
}
这个函数的接口很简单,将触摸事件加入到mInboundQueue队列调用mLooper-wake()唤醒InputDispatcher线程继续执行,最终进入dispatchOnceInnerLocked接口,如下所示:
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
....
if (!mPendingEvent) {
// 如果分发事件队列为空
if (mInboundQueue.isEmpty()) {
....
} else {
// Inbound queue has at least one entry.
// 从mInboundQueue队列中取出一个待分发事件
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
// Get ready to dispatch the event.
// 复位anr时间
resetANRTimeoutsLocked();
}
......
switch (mPendingEvent->type) {
......
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast(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);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
dispatchOnceInnerLocked接口的逻辑如下:
1、从mInboundQueue队列中取出一个待处理的事件mPendingEvent;
2、重置ANR时间;
3、根据事件的类型,调用相应的接口进行处理,对于触摸屏设备来说,调用dispatchMotionLocked()进行处理;
4、事件处理完成后, 释放entry;
我们主要讲述触摸屏事件的处理,因此进入dispatchMotionLocked()接口,进一步进行分析
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
......
bool conflictingPointerActions = false;
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
// 发现目标窗口
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
......
// 开始向App分发
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
dispatchMotionLocked接口的逻辑主要如下:
1、找到事件分发的目标窗口,也就是响应事件的焦点窗口,关于目标窗口的寻找这里不再展开描述。
2、找到目标窗口后,执行dispatchEventLocked()开始向App进程发送事件,实现如下:
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector& inputTargets) {
......
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
// 根据inputTarget.inputChannel找到连接目标
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
// 找到链接通道
sp connection = mConnectionsByFd.valueAt(connectionIndex);
// 开始向连接通道分发事件
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
#if DEBUG_FOCUS
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().string());
#endif
}
}
}
dispatchEventLocked的逻辑如下:
1、找到与App连接的InputChannel通道(本质上是Unix 域socket套接字);
2、调用prepareDispatchCycleLocked接口,开始分发;
prepareDispatchCycleLocked的接口, 我们直接进入核心实现如下:
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
......
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
enqueueDispatchEntriesLocked的实现:
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
// connection连接输出通道队列不为空,开始向App分发事件
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
这个接口,多次调用enqueueDispatchEntryLocked(),为了便于阅读,我们只保留了核心代码,该接口的实现如下所示:
void InputDispatcher::enqueueDispatchEntryLocked(
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
......
// 重新构造一个DispatchEntry分发实体
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
......
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatchesLocked(eventEntry);
}
// Enqueue the dispatch entry.
// 将dispatchEntry加入到连接通道的输出队列的队尾
connection->outboundQueue.enqueueAtTail(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
}
enqueueDispatchEntryLocked接口的主要核心逻辑就是将eventEntry事件封装为一个dispatchEntry实体,然后加入到连接通道的输出队列;
当dispatchEntry事件被加入到connect的输出队列后,我返回到enqueueDispatchEntriesLocked接口的尾部,调用startDispatchCycleLocked()正式向App进程发送输入事件:
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp& connection) {
.......
// 连接通道正常,并且输出队列不为空
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
// 分发Entry
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
// 设置开始分发的时间
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast(eventEntry);
......
// Publish the motion event.
// 分发触摸事件
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
default:
ALOG_ASSERT(false);
return;
}
......
}
// Re-enqueue the event on the wait queue.
// 将dispatchEntry移动到等待队列
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}
}
startDispatchCycleLocked()接口的实现:
1、 主要处理加入到connect输出队列中的dispachEntry,然后根据事件的类型,调用各自的处理接口,对于触摸屏幕来说,就是调用publishMotionEvent,如下所示:
status_t InputPublisher::publishMotionEvent(
......
InputMessage msg;
msg.header.type = InputMessage::TYPE_MOTION;
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
// 向unix socket写入msg, 这样App进程就能夸进程可以读到数据
return mChannel->sendMessage(&msg);
}
重新再次创建一个App可识别的消息msg,然后调用mChannel->sendMessage进行发送,关于InputChannel,我们下一篇文章进行讲述其实现原理(本质上是向unix socket发送数据);
2、发送完事件后,将dispatchEntry事件从输出队列移动到waitQueue队列;
至此,我们讲述完了InputDispatcher向App目标窗口分发事件的整个数据处理的流程。
当App处理完InputDispatcher上报的事件后,App通过输入通道InputChannel,告诉InputDispatcher处理结果,最终回调handleReceiveCallback()进行事件的后期处理,handleReceiveCallback在进行输入通道注册时,加入到InputDispatcher的looper监控中,实现如下:
// 注册输入通道
status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
......
// 将输入通道的文件描述符加入到mLooper监控
// 当向输入通道写入数据时,回调handleReceiveCallback()接口
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
我们下一篇会讲解InputDispatcher与App进行交互的桥梁InputChannel的实现,这里不展开描述,我们只关注App处理完事件后,会向输入通道InputChannel写入信息,将事件的后期处理交给InputDispatcher进行处理,最后会回调handleReceiveCallback接口,如下所示:
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
InputDispatcher* d = static_cast(data);
{ // acquire lock
AutoMutex _l(d->mLock);
......
sp connection = d->mConnectionsByFd.valueAt(connectionIndex);
......
for (;;) {
uint32_t seq;
bool handled;
status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
if (status) {
break;
}
d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
gotOne = true;
}
if (gotOne) {
d->runCommandsLockedInterruptible();
if (status == WOULD_BLOCK) {
return 1;
}
}
notify = status != DEAD_OBJECT || !connection->monitor;
if (notify) {
ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
}
} else {
// Monitor channels are never explicitly unregistered.
// We do it automatically when the remote endpoint is closed so don't warn
// about them.
notify = !connection->monitor;
if (notify) {
ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
}
}
// Unregister the channel.
d->unregisterInputChannelLocked(connection->inputChannel, notify);
return 0; // remove the callback
} // release lock
}
1、调用receiveFinishedSignal从App哪里获取数据,核心实现如下所示:
status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
......
InputMessage msg;
// 从输入通道获取msg
status_t result = mChannel->receiveMessage(&msg);
if (result) {
*outSeq = 0;
*outHandled = false;
return result;
}
......
*outSeq = msg.body.finished.seq;
*outHandled = msg.body.finished.handled;
return OK;
}
2、调用finishDispatchCycleLocked,改接口最终调用onDispatchCycleFinishedLocked()进行事件的清理,核心实现如下所示:
void InputDispatcher::onDispatchCycleFinishedLocked(
nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) {
// 构造一个结束分发的command
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
}
构造一个Command. 并加入到InputDispatcher的mCommandQueue队列中,
3、当接受完所有的App发送的数据后,跳出死循环,进入runCommandsLockedInterruptible进行处理,实现如下:
bool InputDispatcher::runCommandsLockedInterruptible() {
if (mCommandQueue.isEmpty()) {
return false;
}
do {
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
Command command = commandEntry->command;
(this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
delete commandEntry;
} while (! mCommandQueue.isEmpty());
return true;
}
该函数的实现非常简单,处理mCommandQueue队列中的command,然后调用command注册的回调。对于App下发的信息处理回调接口是doDispatchCycleFinishedLockedInterruptible,实现如下:
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
if (dispatchEntry) {
bool restartEvent;
if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
KeyEntry* keyEntry = static_cast(dispatchEntry->eventEntry);
restartEvent = afterKeyEventLockedInterruptible(connection,
dispatchEntry, keyEntry, handled);
} else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
MotionEntry* motionEntry = static_cast(dispatchEntry->eventEntry);
restartEvent = afterMotionEventLockedInterruptible(connection,
dispatchEntry, motionEntry, handled);
} else {
restartEvent = false;
}
// Dequeue the event and start the next cycle.
// Note that because the lock might have been released, it is possible that the
// contents of the wait queue to have been drained, so we need to double-check
// a few things.
if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
// 从waitQueue队列中删除
connection->waitQueue.dequeue(dispatchEntry);
// 是否需要事件重发
if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
connection->outboundQueue.enqueueAtHead(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
} else {
// 释放dispatchEntry
releaseDispatchEntryLocked(dispatchEntry);
}
}
// Start the next dispatch cycle for this connection.
// 继续分发
startDispatchCycleLocked(now(), connection);
}
}
doDispatchCycleFinishedLockedInterruptible()接口的主要逻辑就是:
1、从waitQueue队列中找到App处理完成的InputDispatcher,然后释放InputDispatcher占用的资源,标记该事件处理完毕;
2、检查是否需要重发事件,重发逻辑不展开描述;
3、继续事件分发;
至此,我们讲述完了App通知InputDispatcher进行事件的清理工作。
本文主要讲述了InputDispatcher事件向App分发和App处理完事件后告知InputDispatcher的处理流程。下一篇讲述InputDispatcher和App进行交互的桥梁InputChannel的实现;