InputDispatcher: Fix crash with out-of-order pointer capture requests
One of the conditions being tested in a LOG_ALWAYS_FATAL call was
incorrect, causing a crash when Pointer Capture requests happened in a
certain order.
This CL adds a test that exposes the sequence of events that caused the
crash, and changes the condition in the LOG_ALWAYS_FATAL check to the
correct condition, thereby fixing the crash.
Bug: 179303721
Test: atest inputflinger_tests
Change-Id: I145c71609572b6c6714b8932889cd48523c91511
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 0495d68..90848a9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1247,9 +1247,10 @@
nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry,
DropReason& dropReason) {
const bool haveWindowWithPointerCapture = mWindowTokenWithPointerCapture != nullptr;
- if (entry->pointerCaptureEnabled == haveWindowWithPointerCapture) {
- LOG_ALWAYS_FATAL_IF(mFocusedWindowRequestedPointerCapture,
- "The Pointer Capture state has already been dispatched to the window.");
+ if (entry->pointerCaptureEnabled && haveWindowWithPointerCapture) {
+ LOG_ALWAYS_FATAL("Pointer Capture has already been enabled for the window.");
+ }
+ if (!entry->pointerCaptureEnabled && !haveWindowWithPointerCapture) {
// Pointer capture was already forcefully disabled because of focus change.
dropReason = DropReason::NOT_DROPPED;
return;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c7e05eb..1106099 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -4215,4 +4215,27 @@
mWindow->assertNoEvents();
}
+TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
+ requestAndVerifyPointerCapture(mWindow, true);
+
+ // The first window loses focus.
+ setFocusedWindow(mSecondWindow);
+ mFakePolicy->waitForSetPointerCapture(false);
+ mWindow->consumeCaptureEvent(false);
+
+ // Request Pointer Capture from the second window before the notification from InputReader
+ // arrives.
+ mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
+ mFakePolicy->waitForSetPointerCapture(true);
+
+ // InputReader notifies Pointer Capture was disabled (because of the focus change).
+ notifyPointerCaptureChanged(false);
+
+ // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
+ notifyPointerCaptureChanged(true);
+
+ mSecondWindow->consumeFocusEvent(true);
+ mSecondWindow->consumeCaptureEvent(true);
+}
+
} // namespace android::inputdispatcher