diff options
-rw-r--r-- | libs/gui/WindowInfo.cpp | 9 | ||||
-rw-r--r-- | libs/gui/include/gui/WindowInfo.h | 2 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 24 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 18 |
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, |