Android 常见的View Touch事件的分发,相信大家都已经耳熟能详了。但是这是触摸事件的消费处理过程,有没有想过touch事件是由谁产生,又是如何传递给View的。本文从源码角度浅析一下Touch事件的分发过程。
1. InputDispatcher 接收到事件
在上篇Android Touch事件InputManagerService源码解析(一) 讲到InputReader读取到Touch事件后,通过接口回调notifyMotion将事件抛给了InputDispatcher [-> InputDispatcher.cpp]
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
、、、
if (!validateMotionEvent(args->action, args->actionButton,
args->pointerCount, args->pointerProperties)) {
return;
}
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
android::base::Timer t;
mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendMotionToInputFilterLocked(args)) {
mLock.unlock();
MotionEvent event;
event.initialize(args->deviceId, args->source, args->displayId,
args->action, args->actionButton,
args->flags, args->edgeFlags, args->metaState, args->buttonState,
args->classification, 0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState, args->classification,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
//将newEntry放到队列
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
//会触发dispatchOnce()
mLooper->wake();
}
}
2. 将事件放到mInboundQueue队列
enqueueInboundEventLocked 其实就是将产生的事件放到了一个队列的尾部
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
//mInboundQueue的类型为Queue<EventEntry>,此处将entry添加到队列的尾部
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 (isAppSwitchKeyEvent(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
&& mInputTargetWaitApplicationToken != nullptr) {
int32_t displayId = motionEntry->displayId;
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(displayId, x, y);
if (touchedWindowHandle != nullptr
&& touchedWindowHandle->getApplicationToken()
!= mInputTargetWaitApplicationToken) {
// 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;
}
}
return needWake;
}
3. 开始分发
3.1 dispatchOnce
InputDispatcher内部有个线程,在有事件到来时会被唤醒触发dispatchOnce
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
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.
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();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
3.2 dispatchOnceInnerLocked
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
// 记录当前时间
nsecs_t currentTime = now();
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
// mPendingEvent初始化为空
if (!mPendingEvent) {
if (mInboundQueue.empty()) {
......
// 如果mInboundQueue队列为空,而且没有待处理的输入事件则直接返回
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// 否则直接从mInboundQueue队列头取出一个EventEntry来处理
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.front();
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(*mPendingEvent);
}
}
......
switch (mPendingEvent->type) {
......
case EventEntry::Type::MOTION: {
// 将mPendingEvent强转为MotionEntry
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
// 如果是Motion Event则会走dispatchMotionLocked
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
if (done) {
if (dropReason != DropReason::NOT_DROPPED) {
dropInboundEventLocked(*mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
// 处理完成之后释放mPendingEvent
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
dispatchOnceInnerLocked会从mInboundQueue队头取出EntryEvent赋值给mPendingEvent,并根据输入事件的类型作不同的处理,处理完成之后再释放mPendingEvent,这里我们以MotionEvent为例来分析输入事件的处理流程; dispatchMotionLocked
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// 判断是否是Touch事件
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
std::vector<InputTarget> inputTargets;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
// 寻找Touch事件的焦点窗口
injectionResult =
findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
&conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
// 寻找非Touch事件的焦点窗口
injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
}
// 对于MotionEvent有3种情况会返回INPUT_EVENT_INJECTION_PENDING状态
// 焦点窗口为空而焦点应用不为空时分两种情况:
// 1.未设置焦点窗口缺失的超时时间;
// 2.焦点窗口缺少的超时时间还未到;
// 焦点窗口和焦点应用都不为空时:
// 3.焦点窗口处于暂停状态;
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResult(entry, injectionResult);
if (injectionResult == INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
return true;
}
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
CancelationOptions::Mode mode(isPointerEvent
? CancelationOptions::CANCEL_POINTER_EVENTS
: CancelationOptions::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
return true;
}
// 找到目标窗口之后开始分发事件
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
3.3 找到要分发的目标窗口
我们的设备在显示的时候其实是有多个窗口叠在一起的,最常见的就是Activity,每一个Activity都有一个window,状态栏、下拉栏、一个透明的Activity悬浮在另一个页面上、通过WindowManger添加View等。因此我们要先找到要处理事件的窗口。
寻找目标窗口有两种方式,findTouchedWindowTargetsLocked与findFocusedWindowTargetsLocked,这里我们分析比较简单的findFocusedWindowTargetsLocked。
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry& entry,
std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime) {
std::string reason;
// 寻找输入事件的display id,由于Android支持多屏设备,所以可能会有多个display id,默认为0
int32_t displayId = getTargetDisplayId(entry);
// 根据display id查找InputWindowHandle
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
// 根据display id查找InputApplicationHandle
sp<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
// If there is no currently focused window and no focused application
// then drop the event.
// 如果focusedWindowHandle和focusedApplicationHandle同时为空,代表当前即无焦点应用也无焦点窗口,所以直接将此事件丢弃
if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) {
ALOGI("Dropping %s event because there is no focused window or focused application in "
"display %" PRId32 ".",
EventEntry::typeToString(entry.type), displayId);
return INPUT_EVENT_INJECTION_FAILED;
}
// Compatibility behavior: raise ANR if there is a focused application, but no focused window.
// Only start counting when we have a focused event to dispatch. The ANR is canceled if we
// start interacting with another application via touch (app switch). This code can be removed
// if the "no focused window ANR" is moved to the policy. Input doesn't know whether
// an app is expected to have a focused window.
// 焦点应用不为空而焦点窗口为空
if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
// 未设置焦点窗口缺失的超时时间
if (!mNoFocusedWindowTimeoutTime.has_value()) {
// We just discovered that there's no focused window. Start the ANR timer
// 获取超时时间,默认为5s
const nsecs_t timeout = focusedApplicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT.count());
// 记录超时时间
mNoFocusedWindowTimeoutTime = currentTime + timeout;
// 记录等待焦点窗口的焦点应用
mAwaitedFocusedApplication = focusedApplicationHandle;
ALOGW("Waiting because no window has focus but %s may eventually add a "
"window when it finishes starting up. Will wait for %" PRId64 "ms",
mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout));
*nextWakeupTime = *mNoFocusedWindowTimeoutTime;
return INPUT_EVENT_INJECTION_PENDING;
} else if (currentTime > *mNoFocusedWindowTimeoutTime) {
// Already raised ANR. Drop the event
// 如果已经超时,则直接丢弃该事件
ALOGE("Dropping %s event because there is no focused window",
EventEntry::typeToString(entry.type));
return INPUT_EVENT_INJECTION_FAILED;
} else {
// Still waiting for the focused window
// 还未到超时时间则继续等待
return INPUT_EVENT_INJECTION_PENDING;
}
}
// we have a valid, non-null focused window
// 重置超时时间和等待的焦点应用
resetNoFocusedWindowTimeoutLocked();
// Check permissions.
if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
return INPUT_EVENT_INJECTION_PERMISSION_DENIED;
}
// 焦点窗口已经paused
if (focusedWindowHandle->getInfo()->paused) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
return INPUT_EVENT_INJECTION_PENDING;
}
// Success! Output targets.
// 成功找到焦点窗口后,将其添加到inputTargets尾部,inputTargets是一个vector
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0), inputTargets);
// Done.
return INPUT_EVENT_INJECTION_SUCCEEDED;
}
getValueByKey 其实就是从一个map里面取出 数据
template<typename T, typename U>
static T getValueByKey(std::unordered_map<U, T>& map, U key) {
typename std::unordered_map<U, T>::const_iterator it = map.find(key);
return it != map.end() ? it->second : T{};
}
3.4 focusedWindowHandle与focusedApplicationHandle
在3.3中要找到目标窗口我们发现其实是从map里找到focusedWindowHandle 与focusedApplicationHandle这两个句柄,句柄内存储了目标窗口的相关信息,然后将句柄存储起来。那么这里我们自然要关心这两个句柄是什么时候存到map里面的。
void InputDispatcher::setFocusedApplication(
int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
{ // acquire lock
std::scoped_lock _l(mLock);
// 根据displayId获取历史焦点应用
sp<InputApplicationHandle> oldFocusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
// 如果已经切换到新的应用,而且历史应用之前在等待焦点窗口,那么继续等待已经没有意义,所以重置等待的焦点应用和等待时间
if (oldFocusedApplicationHandle == mAwaitedFocusedApplication &&
inputApplicationHandle != oldFocusedApplicationHandle) {
resetNoFocusedWindowTimeoutLocked();
}
if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
if (oldFocusedApplicationHandle != inputApplicationHandle) {
// 更新焦点应用
mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
}
} else if (oldFocusedApplicationHandle != nullptr) {
oldFocusedApplicationHandle.clear();
// 清除历史焦点应用
mFocusedApplicationHandlesByDisplay.erase(displayId);
}
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
// 唤醒InputDispatcher线程
mLooper->wake();
}
在Acitivity.onResume时会调用 -->frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.setResumedActivityUncheckLocked -->frameworks/base/services/core/java/com/android/server/wm/DisplayContent.setFocusedApp -->frameworks/base/services/core/java/com/android/server/wm/InputMonitor.setFocusedAppLw -->frameworks/base/services/core/java/com/android/server/input/InputManagerService.setFocusedApplication -->frameworks/base/services/core/jni/com_android_server_input_InputManagerService.nativeSetFocusedApplication -->frameworks/base/services/core/jni/com_android_server_input_InputManagerService.NativeInputManager.setFocusedApplication -->frameworks/native/services/inputflinger/InputDispatcher.setFocusedApplication
3.5 dispatchEventLocked
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (const InputTarget& inputTarget : inputTargets) {
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
//connection 可用于跨进程通信
sp<Connection> 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().c_str());
#endif
}
}
}
prepareDispatchCycleLocked
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf(
"prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",
connection->getInputChannelName().c_str(), eventEntry->sequenceNum);
ATRACE_NAME(message.c_str());
}
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
"windowScaleFactor=(%f, %f), pointerIds=0x%x",
connection->getInputChannelName().c_str(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
inputTarget->globalScaleFactor,
inputTarget->windowXScale, inputTarget->windowYScale,
inputTarget->pointerIds.value);
#endif
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
return;
}
// Split a motion event if needed.
if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
MotionEntry* splitMotionEntry = splitMotionEvent(
originalMotionEntry, inputTarget->pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
}
#if DEBUG_FOCUS
ALOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName().c_str());
logOutboundMotionDetails(" ", splitMotionEntry);
#endif
enqueueDispatchEntriesLocked(currentTime, connection,
splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf(
"enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",
connection->getInputChannelName().c_str(), eventEntry->sequenceNum);
ATRACE_NAME(message.c_str());
}
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.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
enqueueDispatchEntryLocked
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
、、、
switch (eventEntry->type) {
、、、
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
} else {
dispatchEntry->resolvedAction = motionEntry->action;
}
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
&& !connection->inputState.isHovering(
motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
connection->getInputChannelName().c_str());
#endif
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
dispatchEntry->resolvedFlags = motionEntry->flags;
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
}
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
if (!connection->inputState.trackMotion(motionEntry,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
connection->getInputChannelName().c_str());
#endif
delete dispatchEntry;
return; // skip the inconsistent event
}
dispatchPointerDownOutsideFocus(motionEntry->source,
dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());
break;
}
}
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatches(eventEntry);
}
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
traceOutboundQueueLength(connection);
}
enqueueDispatchEntriesLocked 在最后调用了startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
// 经过enqueueDispatchEntryLocked之后,connection->outboundQueue不为空
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
// 记录事件分发的时间
dispatchEntry->deliveryTime = currentTime;
// 默认超时时间为5s
const nsecs_t timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
// 分发超时时间为当前时间加上默认超时时间
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::Type::MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
// 获取事件签名
std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
// Publish the motion event.
// 通过Connection的InputPublisher.publishMotionEvent将输入事件发布出去
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId,
motionEntry->deviceId, motionEntry->source,
motionEntry->displayId, std::move(hmac),
dispatchEntry->resolvedAction,
motionEntry->actionButton,
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
motionEntry->buttonState,
motionEntry->classification, xScale, yScale,
xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount,
motionEntry->pointerProperties, usingCoords);
reportTouchEventForStatistics(*motionEntry);
break;
}
}
// Re-enqueue the event on the wait queue.
// 发布完之后将DispatchEntry从Connection的outboundQueue中移除
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
// 然后将DispatchEntry加入Connection的waitQueue
connection->waitQueue.push_back(dispatchEntry);
if (connection->responsive) {
// 往AnrTracker中插入一条记录
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
traceWaitQueueLength(connection);
}
}
4.将事件发送给对应的进程publishMotionEvent
status_t InputPublisher::publishMotionEvent(
uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, float xScale, float yScale, float xOffset,
float yOffset, float xPrecision, float yPrecision, float xCursorPosition,
float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
InputMessage msg;
msg.header.type = InputMessage::Type::MOTION;
msg.body.motion.seq = seq;
msg.body.motion.eventId = eventId;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.displayId = displayId;
msg.body.motion.hmac = std::move(hmac);
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.classification = classification;
msg.body.motion.xScale = xScale;
msg.body.motion.yScale = yScale;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.xCursorPosition = xCursorPosition;
msg.body.motion.yCursorPosition = yCursorPosition;
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]);
}
// 将输入事件封装成InputMessage,并继续通过InputChannel.sendMessage发送消息
return mChannel->sendMessage(&msg);
}
status_t InputChannel::sendMessage(const InputMessage* msg) {
const size_t msgLength = msg->size();
InputMessage cleanMsg;
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
// 通过socket将InputMessage发送给应用进程
nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
......
return OK;
}
5.总结
InputReader不停的从底层读取事件发送给InputDispatcher,InputDispatcher内有一个线程,当有新的事件的时候会从休眠中唤醒调用dispatchOnce。找到要处理事件对应的窗口,通过connection把事件发送到对应的进程。
本文由 mdnice 多平台发布