summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siarhei Vishniakou <svv@google.com> 2024-01-09 08:57:13 -0800
committer Siarhei Vishniakou <svv@google.com> 2024-01-09 18:34:01 -0800
commitaeed0da5878b59b42a9e9e40e48f36809bb315cb (patch)
treed6588c20b8ccb1528a7a6781c30d4ca613426801
parent5704dbd9a4ecd55af96eaf840852fdcb728cca4d (diff)
Check for redundant windows inside WindowInfos
Recently, our team has seen traces where dispatcher is taking a long time to run - sometimes, more than 22 milliseconds. That's way longer than the expected ~ 0.3 milliseconds for the entire inputflinger. After examining the traces, I noticed that there's a lot of time spent in both findTouchedWindowTargets and dispatchInputEvent. It appears that we are trying to dispatch one input event multiple times to the same channel, dreamOverlay. One way this could be possible if we receive multiple, redundant windows. In this CL, we add a crash to identify and get out of this bad state. Bug: 311142655 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I2170928d1bb1e591b9c93b42dd86827e86a0c7fb
-rw-r--r--libs/gui/WindowInfo.cpp9
-rw-r--r--libs/gui/include/gui/WindowInfo.h2
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp24
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp18
4 files changed, 51 insertions, 2 deletions
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index ba1d196e9c..95b2641f04 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -258,8 +258,7 @@ void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) {
mInfo = handle->mInfo;
}
-std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
- const WindowInfo& info = *window.getInfo();
+std::ostream& operator<<(std::ostream& out, const WindowInfo& info) {
std::string transform;
info.transform.dump(transform, "transform", " ");
out << "name=" << info.name << ", id=" << info.id << ", displayId=" << info.displayId
@@ -277,4 +276,10 @@ std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
return out;
}
+std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
+ const WindowInfo& info = *window.getInfo();
+ out << info;
+ return out;
+}
+
} // namespace android::gui
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index b72b71a3ce..e72fd59147 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -269,6 +269,8 @@ struct WindowInfo : public Parcelable {
status_t readFromParcel(const android::Parcel* parcel) override;
};
+std::ostream& operator<<(std::ostream& out, const WindowInfo& window);
+
/*
* Handle for a window that can receive input.
*
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 162a7bd6c5..39657f2ced 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -763,6 +763,21 @@ bool isStylusActiveInDisplay(
return state.hasActiveStylus();
}
+Result<void> validateWindowInfosUpdate(const gui::WindowInfosUpdate& update) {
+ struct HashFunction {
+ size_t operator()(const WindowInfo& info) const { return info.id; }
+ };
+
+ std::unordered_set<WindowInfo, HashFunction> windowSet;
+ for (const WindowInfo& info : update.windowInfos) {
+ const auto [_, inserted] = windowSet.insert(info);
+ if (!inserted) {
+ return Error() << "Duplicate entry for " << info;
+ }
+ }
+ return {};
+}
+
} // namespace
// --- InputDispatcher ---
@@ -6762,6 +6777,15 @@ void InputDispatcher::displayRemoved(int32_t displayId) {
}
void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update) {
+ if (auto result = validateWindowInfosUpdate(update); !result.ok()) {
+ {
+ // acquire lock
+ std::scoped_lock _l(mLock);
+ logDispatchStateLocked();
+ }
+ LOG_ALWAYS_FATAL("Incorrect WindowInfosUpdate provided: %s",
+ result.error().message().c_str());
+ };
// The listener sends the windows as a flattened array. Separate the windows by display for
// more convenient parsing.
std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8be1b3ba00..5c5dfe1bf1 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1680,6 +1680,24 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
+using InputDispatcherDeathTest = InputDispatcherTest;
+
+/**
+ * When 'onWindowInfosChanged' arguments contain a duplicate entry for the same window, dispatcher
+ * should crash.
+ */
+TEST_F(InputDispatcherDeathTest, DuplicateWindowInfosAbortDispatcher) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ ScopedSilentDeath _silentDeath;
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
+ ASSERT_DEATH(mDispatcher->onWindowInfosChanged(
+ {{*window->getInfo(), *window->getInfo()}, {}, 0, 0}),
+ "Incorrect WindowInfosUpdate provided");
+}
+
TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,