summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siarhei Vishniakou <svv@google.com> 2024-10-07 10:58:40 -0700
committer Siarhei Vishniakou <svv@google.com> 2024-10-10 23:41:16 -0700
commitf6abbf4b919b121614384ab2286bcaf16bedd344 (patch)
treee0a96e800c38c6d8a7119a17ba53eb3b259e91da
parent8ea4421c67405c42e670d219e097d290b77a4416 (diff)
Reject inconsistent globally injected events
The dispatcher currently crashes when certain inconsistent input events are injected. This is affecting test stability negatively. In this CL, we reject globally-injected inconsistent events. That may cause some test flakiness, but should eliminate the crashes due to dispatcher reaching bad state later. Unfortunately, we can't currently reject all inconsistent injected events. In the case of targeted injection, it is common for the caller to leave pointers dangling. Since the injection happens into the caller-owned windows only, at the end of those tests the windows get cleaned up, so the dispatcher is still in a good state. The eventual goal is to completely get rid of injection. Meanwhile, however, this should help avoid at least some of the crashes. Bug: 369935405 Flag: EXEMPT bugfix Test: atest inputflinger_tests Change-Id: I0696dbd3e4c5b88aad5aa853759227c0b56d5374
-rw-r--r--include/input/InputEventBuilders.h3
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp63
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h4
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp16
4 files changed, 60 insertions, 26 deletions
diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h
index 1899a66159..1696a62693 100644
--- a/include/input/InputEventBuilders.h
+++ b/include/input/InputEventBuilders.h
@@ -250,6 +250,9 @@ class MotionEventBuilder {
public:
MotionEventBuilder(int32_t action, int32_t source) {
mAction = action;
+ if (mAction == AMOTION_EVENT_ACTION_CANCEL) {
+ mFlags |= AMOTION_EVENT_FLAG_CANCELED;
+ }
mSource = source;
mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
mDownTime = mEventTime;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4b43c277b6..f6182771fc 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4796,6 +4796,39 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan
}
}
+bool InputDispatcher::shouldRejectInjectedMotionLocked(const MotionEvent& motionEvent,
+ DeviceId deviceId,
+ ui::LogicalDisplayId displayId,
+ std::optional<gui::Uid> targetUid,
+ int32_t flags) {
+ // Don't verify targeted injection, since it will only affect the caller's
+ // window, and the windows are typically destroyed at the end of the test.
+ if (targetUid.has_value()) {
+ return false;
+ }
+
+ // Verify all other injected streams, whether the injection is coming from apps or from
+ // input filter. Print an error if the stream becomes inconsistent with this event.
+ // An inconsistent injected event sent could cause a crash in the later stages of
+ // dispatching pipeline.
+ auto [it, _] = mInputFilterVerifiersByDisplay.try_emplace(displayId,
+ std::string("Injection on ") +
+ displayId.toString());
+ InputVerifier& verifier = it->second;
+
+ Result<void> result =
+ verifier.processMovement(deviceId, motionEvent.getSource(), motionEvent.getAction(),
+ motionEvent.getPointerCount(),
+ motionEvent.getPointerProperties(),
+ motionEvent.getSamplePointerCoords(), flags);
+ if (!result.ok()) {
+ logDispatchStateLocked();
+ LOG(ERROR) << "Inconsistent event: " << motionEvent << ", reason: " << result.error();
+ return true;
+ }
+ return false;
+}
+
InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
std::optional<gui::Uid> targetUid,
InputEventInjectionSync syncMode,
@@ -4906,32 +4939,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev
mLock.lock();
- {
- // Verify all injected streams, whether the injection is coming from apps or from
- // input filter. Print an error if the stream becomes inconsistent with this event.
- // An inconsistent injected event sent could cause a crash in the later stages of
- // dispatching pipeline.
- auto [it, _] =
- mInputFilterVerifiersByDisplay.try_emplace(displayId,
- std::string("Injection on ") +
- displayId.toString());
- InputVerifier& verifier = it->second;
-
- Result<void> result =
- verifier.processMovement(resolvedDeviceId, motionEvent.getSource(),
- motionEvent.getAction(),
- motionEvent.getPointerCount(),
- motionEvent.getPointerProperties(),
- motionEvent.getSamplePointerCoords(), flags);
- if (!result.ok()) {
- logDispatchStateLocked();
- LOG(ERROR) << "Inconsistent event: " << motionEvent
- << ", reason: " << result.error();
- if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
- mLock.unlock();
- return InputEventInjectionResult::FAILED;
- }
- }
+ if (shouldRejectInjectedMotionLocked(motionEvent, resolvedDeviceId, displayId,
+ targetUid, flags)) {
+ mLock.unlock();
+ return InputEventInjectionResult::FAILED;
}
const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes();
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 24e36ae710..a6b7cc75c1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -299,6 +299,10 @@ private:
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
+ bool shouldRejectInjectedMotionLocked(const MotionEvent& motion, DeviceId deviceId,
+ ui::LogicalDisplayId displayId,
+ std::optional<gui::Uid> targetUid, int32_t flags)
+ REQUIRES(mLock);
void setInjectionResult(const EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
void transformMotionEntryForInjectionLocked(MotionEntry&,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c5702e92d9..df8bb99520 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -12889,6 +12889,22 @@ TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
// Remove drag window
mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
+ // Complete the first event stream, even though the injection will fail because there aren't any
+ // valid targets to dispatch this event to. This is still needed to make the input stream
+ // consistent
+ ASSERT_EQ(InputEventInjectionResult::FAILED,
+ injectMotionEvent(*mDispatcher,
+ MotionEventBuilder(ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ui::LogicalDisplayId::DEFAULT)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER)
+ .x(150)
+ .y(50))
+ .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
+ .x(50)
+ .y(50))
+ .build(),
+ INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT));
+
// Inject a simple gesture, ensure dispatcher not crashed
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,