InputDispatcher: Only dispatch fallback keys when there's a window
InputDispatcher has an invariant where an input channel must have a
window for dispatcher to be able to target an event to the channel
(i.e. enqueue the event onto the channel's outbound queue - excluding
global monitors).
Fallback key handling logic seems to be the only place where this
invariant does not explicitly hold.
In this CL, we add checks to the fallback logic to uphold this invariant
and ensure the channel has at least one window before generating events
for it.
Bug: 210460522
Test: atest inputflinger_tests
Change-Id: I76ef8b559150a44dc98ea42e52fa92a6b90cde3a
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 77c2222..9d744f6 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -6207,8 +6207,18 @@
}
traceWaitQueueLength(*connection);
if (fallbackKeyEntry && connection->status == Connection::Status::NORMAL) {
- const InputTarget target{.connection = connection, .flags = dispatchEntry->targetFlags};
- enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry), target);
+ const auto windowHandle = getWindowHandleLocked(connection->getToken());
+ // Only dispatch fallbacks if there is a window for the connection.
+ if (windowHandle != nullptr) {
+ const auto inputTarget =
+ createInputTargetLocked(windowHandle, InputTarget::DispatchMode::AS_IS,
+ dispatchEntry->targetFlags,
+ fallbackKeyEntry->downTime);
+ if (inputTarget.has_value()) {
+ enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry),
+ *inputTarget);
+ }
+ }
}
releaseDispatchEntry(std::move(dispatchEntry));
}
@@ -6440,14 +6450,18 @@
mLock.lock();
- // Cancel the fallback key.
+ // Cancel the fallback key, but only if we still have a window for the channel.
+ // It could have been removed during the policy call.
if (*fallbackKeyCode != AKEYCODE_UNKNOWN) {
- CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
- "application handled the original non-fallback key "
- "or is no longer a foreground target, "
- "canceling previously dispatched fallback key");
- options.keyCode = *fallbackKeyCode;
- synthesizeCancelationEventsForConnectionLocked(connection, options);
+ const auto windowHandle = getWindowHandleLocked(connection->getToken());
+ if (windowHandle != nullptr) {
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
+ "application handled the original non-fallback key "
+ "or is no longer a foreground target, "
+ "canceling previously dispatched fallback key");
+ options.keyCode = *fallbackKeyCode;
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
+ }
}
connection->inputState.removeFallbackKey(originalKeyCode);
}
@@ -6523,10 +6537,13 @@
}
}
- CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
- "canceling fallback, policy no longer desires it");
- options.keyCode = *fallbackKeyCode;
- synthesizeCancelationEventsForConnectionLocked(connection, options);
+ const auto windowHandle = getWindowHandleLocked(connection->getToken());
+ if (windowHandle != nullptr) {
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
+ "canceling fallback, policy no longer desires it");
+ options.keyCode = *fallbackKeyCode;
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
+ }
fallback = false;
*fallbackKeyCode = AKEYCODE_UNKNOWN;