之前提到,InputReader将Key的信息封装成一个NotifyKeyArgs对象,调用InputDispatcher的notifyKey来处理。再进行一些初步的处理后,将个NotifyKeyArgs对象拆包,得到的信息构成一个KeyEvent,并调用interceptKeyBeforeQueueing进行第一次事件拦截,该函数最终会调到java层PhoneWindowManager的interceptKeyBeforeQueueing函数,对一些系统特殊按键进行处理。该函数会返回一个result,如果result带有ACTION_PASS_TO_USER标志位,说明在这次的事件拦截中没有被过滤;如果没有ACTION_PASS_TO_USER标志位,则说明按键在这次事件拦截中被过滤处理掉了。这个ACTION_PASS_TO_USER标志位将被记录在Native层interceptKeyBeforeQueueing函数第二个参数policyFlags中。接下来构造一个KeyEntry,将这个KeyEntry通过enqueueInboundEventLocked加入到mInboundQueue这个Queue< EventEntry>中。每次InputReader推送NotifyKeyArgs对象过来而且mInboundQueue为空时,就会调用wake函数唤醒mLooper,wake函数就是往mWakeEventFd表示的fd写入一个数字进行唤醒。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
args->eventTime, args->deviceId, args->source, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
#endif
if (!validateKeyEvent(args->action)) {
return;
}
uint32_t policyFlags = args->policyFlags;
int32_t flags = args->flags;
int32_t metaState = args->metaState;
if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
policyFlags |= POLICY_FLAG_VIRTUAL;
flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
if (policyFlags & POLICY_FLAG_FUNCTION) {
metaState |= AMETA_FUNCTION_ON;
}
policyFlags |= POLICY_FLAG_TRUSTED;
int32_t keyCode = args->keyCode;
if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {
int32_t newKeyCode = AKEYCODE_UNKNOWN;
if (keyCode == AKEYCODE_DEL) {
newKeyCode = AKEYCODE_BACK;
} else if (keyCode == AKEYCODE_ENTER) {
newKeyCode = AKEYCODE_HOME;
}
if (newKeyCode != AKEYCODE_UNKNOWN) {
AutoMutex _l(mLock);
struct KeyReplacement replacement = {keyCode, args->deviceId};
mReplacedKeys.add(replacement, newKeyCode);
keyCode = newKeyCode;
metaState &= ~AMETA_META_ON;
}
} else if (args->action == AKEY_EVENT_ACTION_UP) {
// In order to maintain a consistent stream of up and down events, check to see if the key
// going up is one we've replaced in a down event and haven't yet replaced in an up event,
// even if the modifier was released between the down and the up events.
AutoMutex _l(mLock);
struct KeyReplacement replacement = {keyCode, args->deviceId};
ssize_t index = mReplacedKeys.indexOfKey(replacement);
if (index >= 0) {
keyCode = mReplacedKeys.valueAt(index);
mReplacedKeys.removeItemsAt(index);
metaState &= ~AMETA_META_ON;
}
}
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);
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
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);
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake();
}
}
InputDispatcher是在一个threadLoop循环中执行dispatchOnce函数的。haveCommandsLocked判断mCommandQueue是否不为空。这里假设是在首次执行dispatchOnce函数时,mCommandQueue理应为空,dispatchOnceInnerLocked函数会被执行。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
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.
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);
}
这里会取出mInboundQueue队列头的KeyEntry作为mPendingEvent继续往后处理。随后通过pokeUserActivityLocked将InputDispatcher::doPokeUserActivityLockedInterruptible函数推入到mCommandQueue里面。
接下来根据情况设置按键丢弃标志。凡是在第一次事件拦截中没有被加上POLICY_FLAG_PASS_TO_USER的Key,其dropReason会被设为DROP_REASON_POLICY。还有一些规则可以细看一下。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// Reset the key repeat timer whenever normal dispatch is suspended while the
// device is in a non-interactive state. This is to ensure that we abort a key
// repeat if the device is just coming out of sleep.
if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
#if DEBUG_FOCUS
ALOGD("Dispatch frozen. Waiting some more.");
#endif
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
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.
resetANRTimeoutsLocked();
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != NULL);
bool done = false;
DropReason dropReason = DROP_REASON_NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DROP_REASON_POLICY;
} else if (!mDispatchEnabled) {
dropReason = DROP_REASON_DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = NULL;
}
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);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
不管是会被丢弃的按键还是保留的按键,都会进入到dispatchKeyLocked函数中。前面是生成重复按键事件,在 mConfig.keyRepeatTimeout时间内同一个按键被按下会被视为重复按键事件,即是长按事件,通过其repeatCount成员是否大于1体现。接着会将doInterceptKeyBeforeDispatchingLockedInterruptible推入到mCommandQueue中,这是第二次执行时间拦截的函数。findFocusedWindowTargetsLocked接受当前焦点窗口句柄mFocusedWindowHandle为参数,构造出一个InputTarget,push到inputTargets中去。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (! entry->dispatchInProgress) {
if (entry->repeatCount == 0
&& entry->action == AKEY_EVENT_ACTION_DOWN
&& (entry->policyFlags & POLICY_FLAG_TRUSTED)
&& (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
if (mKeyRepeatState.lastKeyEntry
&& mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
// We have seen two identical key downs in a row which indicates that the device
// driver is automatically generating key repeats itself. We take note of the
// repeat here, but we disable our own next key repeat timer since it is clear that
// we will not need to synthesize key repeats ourselves.
entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
} else {
// Not a repeat. Save key down state in case we do see a repeat later.
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
entry->refCount += 1;
} else if (! entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
if (entry->repeatCount == 1) {
entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
} else {
entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
}
entry->dispatchInProgress = true;
logOutboundKeyDetailsLocked("dispatchKey - ", entry);
}
// Handle case where the policy asked us to try again later last time.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) {
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
}
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
if (mFocusedWindowHandle != NULL) {
commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
if (*dropReason == DROP_REASON_NOT_DROPPED) {
*dropReason = DROP_REASON_POLICY;
}
}
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
// Identify targets.
Vector<InputTarget> inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
addMonitoringTargetsLocked(inputTargets);
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
dispatchEventLocked会遍历inputTargets中所有InputTarget,每个InputTarget都对应着一个InputChannel,每个InputChannel对应着一个Connection,代表着InputDispatcher和Window的联系纽带。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
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().string());
#endif
}
}
}
直接看enqueueDispatchEntriesLocked。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, scaleFactor=%f, "
"pointerIds=0x%x",
connection->getInputChannelName(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor, 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(), 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());
logOutboundMotionDetailsLocked(" ", 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);
}
enqueueDispatchEntriesLocked将构建一个DispatchEntry,push到Connection的outboundQueue队列中。如果Connection对应的outboundQueue之前为空,现在不为空的话,调用startDispatchCycleLocked进入推送过程。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& 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.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
int32_t inputTargetFlags = inputTarget->flags;
if (!(inputTargetFlags & dispatchMode)) {
return;
}
inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
// Apply target flags and update the connection's input state.
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
dispatchEntry->resolvedAction = keyEntry->action;
dispatchEntry->resolvedFlags = keyEntry->flags;
if (!connection->inputState.trackKey(keyEntry,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
connection->getInputChannelName());
#endif
delete dispatchEntry;
return; // skip the inconsistent event
}
break;
}
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());
#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 (!connection->inputState.trackMotion(motionEntry,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
connection->getInputChannelName());
#endif
delete dispatchEntry;
return; // skip the inconsistent event
}
break;
}
}
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatchesLocked(eventEntry);
}
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
startDispatchCycleLocked会取出outboundQueue中的每一个对应的DispatchEntry,使用Connection的InputPublisher的publishKeyEvent函数将这个DispatchEntry携带的信息组合成一个InputMessage,推送到InputChannel中。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ startDispatchCycle",
connection->getInputChannelName());
#endif
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
// Set the X and Y offset depending on the input source.
float xOffset, yOffset, scaleFactor;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
scaleFactor = dispatchEntry->scaleFactor;
xOffset = dispatchEntry->xOffset * scaleFactor;
yOffset = dispatchEntry->yOffset * scaleFactor;
if (scaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
scaledCoords[i].scale(scaleFactor);
}
usingCoords = scaledCoords;
}
} else {
xOffset = 0.0f;
yOffset = 0.0f;
scaleFactor = 1.0f;
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i].clear();
}
usingCoords = scaledCoords;
}
}
// 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;
}
// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
if (connection->waitQueue.isEmpty()) {
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
"event to it, status=%d", connection->getInputChannelName(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
} else {
// Pipe is full and we are waiting for the app to finish process some events
// before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
"waiting for the application to catch up",
connection->getInputChannelName());
#endif
connection->inputPublisherBlocked = true;
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
"status=%d", connection->getInputChannelName(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
return;
}
// Re-enqueue the event on the wait queue.
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}
}
在窗口的创建过程中,会通过openInputChannelPair创建一对UNIX域套接字。client端即窗口端保存的是inputChannels[0],server端即应用程序端View保存的inputChannels[1]。这些java层的InputChannel在native有着对应的InputChannel。
registerInputChannel的作用是注册InputChanel。在往下调注册InputChannel的时候,会new一个Connection,标示一对连接,并且会将对应的fd和Connection作为键值对保存到mConnectionsByFd中。Connection的构造函数会new一个inputPublisher。所以Connection含有输入窗口句柄InputWindowHandle,连接纽带InputChannel,推送工具InputPublisher,Key保存队列Queue< DispatchEntry>和Key等待队列Queue< DispatchEntry>等成员。
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
...
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
/frameworks/native/services/inputflinger/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
toString(monitor));
#endif
{ // acquire lock
AutoMutex _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
&emsp;现在已经了解了Connection的内部构造。看看Connection内部InputPublisher::publishKeyEvent实现。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
status_t InputPublisher::publishKeyEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%lld, eventTime=%lld",
mChannel->getName().string(), seq,
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
downTime, eventTime);
#endif
if (!seq) {
ALOGE("Attempted to publish a key event with sequence number 0.");
return BAD_VALUE;
}
InputMessage msg;
msg.header.type = InputMessage::TYPE_KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
return mChannel->sendMessage(&msg);
}
InputChannel::sendMessage就是将封装好的InputMessage通过send推送到mFd中去。那么,在server端的InputChannel会接收到这个InputMessage。
/frameworks/native/services/inputflinger/InputDispatcher.cpp
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
int error = errno;
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
msg->header.type, error);
#endif
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
return DEAD_OBJECT;
}
return -error;
}
if (size_t(nWrite) != msgLength) {
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
mName.string(), msg->header.type);
#endif
return DEAD_OBJECT;
}
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
#endif
return OK;
}
至此,派发流程从InputDispatcher的派发中走到了View的逻辑中。