Loading services/inputflinger/tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ cc_test { "EventHub_test.cpp", "FakeEventHub.cpp", "FakeInputReaderPolicy.cpp", "FakeInputTracingBackend.cpp", "FakePointerController.cpp", "FocusResolver_test.cpp", "GestureConverter_test.cpp", Loading services/inputflinger/tests/FakeInputTracingBackend.cpp 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "FakeInputTracingBackend.h" #include <android-base/logging.h> #include <utils/Errors.h> namespace android::inputdispatcher { namespace { constexpr auto TRACE_TIMEOUT = std::chrono::milliseconds(100); base::ResultError<> error(const std::ostringstream& ss) { return base::ResultError(ss.str(), BAD_VALUE); } } // namespace // --- VerifyingTrace --- void VerifyingTrace::expectKeyDispatchTraced(const KeyEvent& event) { std::scoped_lock lock(mLock); mExpectedEvents.emplace_back(event); } void VerifyingTrace::expectMotionDispatchTraced(const MotionEvent& event) { std::scoped_lock lock(mLock); mExpectedEvents.emplace_back(event); } void VerifyingTrace::verifyExpectedEventsTraced() { std::unique_lock lock(mLock); base::ScopedLockAssertion assumeLocked(mLock); base::Result<void> result; mEventTracedCondition.wait_for(lock, TRACE_TIMEOUT, [&]() REQUIRES(mLock) { for (const auto& expectedEvent : mExpectedEvents) { std::visit([&](const auto& event) REQUIRES(mLock) { result = verifyEventTraced(event); }, expectedEvent); if (!result.ok()) { return false; } } return true; }); EXPECT_TRUE(result.ok()) << "Timed out waiting for all expected events to be traced successfully: " << result.error().message(); } void VerifyingTrace::reset() { std::scoped_lock lock(mLock); mTracedEvents.clear(); mExpectedEvents.clear(); } template <typename Event> base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent) const { std::ostringstream msg; auto tracedEventsIt = mTracedEvents.find(expectedEvent.getId()); if (tracedEventsIt == mTracedEvents.end()) { msg << "Expected event with ID 0x" << std::hex << expectedEvent.getId() << " to be traced, but it was not.\n" << "Expected event: " << expectedEvent; return error(msg); } return {}; } // --- FakeInputTracingBackend --- void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); } mTrace->mEventTracedCondition.notify_all(); } void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); } mTrace->mEventTracedCondition.notify_all(); } } // namespace android::inputdispatcher services/inputflinger/tests/FakeInputTracingBackend.h 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "../dispatcher/trace/InputTracingBackendInterface.h" #include <android-base/result.h> #include <android-base/thread_annotations.h> #include <gtest/gtest.h> #include <input/Input.h> #include <condition_variable> #include <memory> #include <mutex> #include <unordered_set> #include <vector> namespace android::inputdispatcher { /** * A class representing an input trace, used to make assertions on what was traced by * InputDispatcher in tests. This class is thread-safe. */ class VerifyingTrace { public: VerifyingTrace() = default; /** Add an expectation for a key event to be traced. */ void expectKeyDispatchTraced(const KeyEvent& event); /** Add an expectation for a motion event to be traced. */ void expectMotionDispatchTraced(const MotionEvent& event); /** * Wait and verify that all expected events are traced. * This is a lenient verifier that does not expect the events to be traced in the order * that the events were expected, and does not fail if there are events that are traced that * were not expected. Verifying does not clear the expectations. */ void verifyExpectedEventsTraced(); /** Reset the trace and clear all expectations. */ void reset(); private: std::mutex mLock; std::condition_variable mEventTracedCondition; std::unordered_set<uint32_t /*eventId*/> mTracedEvents GUARDED_BY(mLock); std::vector<std::variant<KeyEvent, MotionEvent>> mExpectedEvents GUARDED_BY(mLock); friend class FakeInputTracingBackend; // Helper to verify that the given event appears as expected in the trace. If the verification // fails, the error message describes why. template <typename Event> base::Result<void> verifyEventTraced(const Event&) const REQUIRES(mLock); }; /** * A backend implementation for input tracing that records events to the provided * VerifyingTrace used for testing. */ class FakeInputTracingBackend : public trace::InputTracingBackendInterface { public: FakeInputTracingBackend(std::shared_ptr<VerifyingTrace> trace) : mTrace(trace) {} private: std::shared_ptr<VerifyingTrace> mTrace; void traceKeyEvent(const trace::TracedKeyEvent& entry) const override; void traceMotionEvent(const trace::TracedMotionEvent& entry) const override; void traceWindowDispatch(const WindowDispatchArgs& entry) const override {} }; } // namespace android::inputdispatcher services/inputflinger/tests/InputDispatcher_test.cpp +45 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "../dispatcher/InputDispatcher.h" #include "../BlockingQueue.h" #include "FakeApplicationHandle.h" #include "FakeInputTracingBackend.h" #include "TestEventMatchers.h" #include <NotifyArgsBuilders.h> Loading Loading @@ -658,14 +659,22 @@ private: // --- InputDispatcherTest --- // The trace is a global variable for now, to avoid having to pass it into all of the // FakeWindowHandles created throughout the tests. // TODO(b/210460522): Update the tests to avoid the need to have the trace be a global variable. static std::shared_ptr<VerifyingTrace> gVerifyingTrace = std::make_shared<VerifyingTrace>(); class InputDispatcherTest : public testing::Test { protected: std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy; std::unique_ptr<InputDispatcher> mDispatcher; void SetUp() override { gVerifyingTrace->reset(); mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>(); mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, nullptr); mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, std::make_unique<FakeInputTracingBackend>( gVerifyingTrace)); mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false); // Start InputDispatcher thread Loading @@ -676,6 +685,7 @@ protected: ASSERT_EQ(OK, mDispatcher->stop()); mFakePolicy.reset(); mDispatcher.reset(); ASSERT_NO_FATAL_FAILURE(gVerifyingTrace->verifyExpectedEventsTraced()); } /** Loading Loading @@ -1395,11 +1405,7 @@ public: } std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent() { if (mInputReceiver == nullptr) { ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::make_pair(std::nullopt, nullptr); } return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); return receive(); } void finishEvent(uint32_t sequenceNum) { Loading Loading @@ -1444,6 +1450,7 @@ private: static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; // FakeWindowHandle uses this consume method to ensure received events are added to the trace. std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) { if (mInputReceiver == nullptr) { LOG(FATAL) << "Cannot consume event from a window with no input event receiver"; Loading @@ -1452,8 +1459,40 @@ private: if (event == nullptr) { ADD_FAILURE() << "Consume failed: no event"; } expectReceivedEventTraced(event); return event; } // FakeWindowHandle uses this receive method to ensure received events are added to the trace. std::pair<std::optional<uint32_t /*seq*/>, std::unique_ptr<InputEvent>> receive() { if (mInputReceiver == nullptr) { ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::make_pair(std::nullopt, nullptr); } auto out = mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); const auto& [_, event] = out; expectReceivedEventTraced(event); return std::move(out); } void expectReceivedEventTraced(const std::unique_ptr<InputEvent>& event) { if (!event) { return; } switch (event->getType()) { case InputEventType::KEY: { gVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event)); break; } case InputEventType::MOTION: { gVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event)); break; } default: break; } } }; std::atomic<int32_t> FakeWindowHandle::sId{1}; Loading Loading
services/inputflinger/tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ cc_test { "EventHub_test.cpp", "FakeEventHub.cpp", "FakeInputReaderPolicy.cpp", "FakeInputTracingBackend.cpp", "FakePointerController.cpp", "FocusResolver_test.cpp", "GestureConverter_test.cpp", Loading
services/inputflinger/tests/FakeInputTracingBackend.cpp 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "FakeInputTracingBackend.h" #include <android-base/logging.h> #include <utils/Errors.h> namespace android::inputdispatcher { namespace { constexpr auto TRACE_TIMEOUT = std::chrono::milliseconds(100); base::ResultError<> error(const std::ostringstream& ss) { return base::ResultError(ss.str(), BAD_VALUE); } } // namespace // --- VerifyingTrace --- void VerifyingTrace::expectKeyDispatchTraced(const KeyEvent& event) { std::scoped_lock lock(mLock); mExpectedEvents.emplace_back(event); } void VerifyingTrace::expectMotionDispatchTraced(const MotionEvent& event) { std::scoped_lock lock(mLock); mExpectedEvents.emplace_back(event); } void VerifyingTrace::verifyExpectedEventsTraced() { std::unique_lock lock(mLock); base::ScopedLockAssertion assumeLocked(mLock); base::Result<void> result; mEventTracedCondition.wait_for(lock, TRACE_TIMEOUT, [&]() REQUIRES(mLock) { for (const auto& expectedEvent : mExpectedEvents) { std::visit([&](const auto& event) REQUIRES(mLock) { result = verifyEventTraced(event); }, expectedEvent); if (!result.ok()) { return false; } } return true; }); EXPECT_TRUE(result.ok()) << "Timed out waiting for all expected events to be traced successfully: " << result.error().message(); } void VerifyingTrace::reset() { std::scoped_lock lock(mLock); mTracedEvents.clear(); mExpectedEvents.clear(); } template <typename Event> base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent) const { std::ostringstream msg; auto tracedEventsIt = mTracedEvents.find(expectedEvent.getId()); if (tracedEventsIt == mTracedEvents.end()) { msg << "Expected event with ID 0x" << std::hex << expectedEvent.getId() << " to be traced, but it was not.\n" << "Expected event: " << expectedEvent; return error(msg); } return {}; } // --- FakeInputTracingBackend --- void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); } mTrace->mEventTracedCondition.notify_all(); } void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); } mTrace->mEventTracedCondition.notify_all(); } } // namespace android::inputdispatcher
services/inputflinger/tests/FakeInputTracingBackend.h 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "../dispatcher/trace/InputTracingBackendInterface.h" #include <android-base/result.h> #include <android-base/thread_annotations.h> #include <gtest/gtest.h> #include <input/Input.h> #include <condition_variable> #include <memory> #include <mutex> #include <unordered_set> #include <vector> namespace android::inputdispatcher { /** * A class representing an input trace, used to make assertions on what was traced by * InputDispatcher in tests. This class is thread-safe. */ class VerifyingTrace { public: VerifyingTrace() = default; /** Add an expectation for a key event to be traced. */ void expectKeyDispatchTraced(const KeyEvent& event); /** Add an expectation for a motion event to be traced. */ void expectMotionDispatchTraced(const MotionEvent& event); /** * Wait and verify that all expected events are traced. * This is a lenient verifier that does not expect the events to be traced in the order * that the events were expected, and does not fail if there are events that are traced that * were not expected. Verifying does not clear the expectations. */ void verifyExpectedEventsTraced(); /** Reset the trace and clear all expectations. */ void reset(); private: std::mutex mLock; std::condition_variable mEventTracedCondition; std::unordered_set<uint32_t /*eventId*/> mTracedEvents GUARDED_BY(mLock); std::vector<std::variant<KeyEvent, MotionEvent>> mExpectedEvents GUARDED_BY(mLock); friend class FakeInputTracingBackend; // Helper to verify that the given event appears as expected in the trace. If the verification // fails, the error message describes why. template <typename Event> base::Result<void> verifyEventTraced(const Event&) const REQUIRES(mLock); }; /** * A backend implementation for input tracing that records events to the provided * VerifyingTrace used for testing. */ class FakeInputTracingBackend : public trace::InputTracingBackendInterface { public: FakeInputTracingBackend(std::shared_ptr<VerifyingTrace> trace) : mTrace(trace) {} private: std::shared_ptr<VerifyingTrace> mTrace; void traceKeyEvent(const trace::TracedKeyEvent& entry) const override; void traceMotionEvent(const trace::TracedMotionEvent& entry) const override; void traceWindowDispatch(const WindowDispatchArgs& entry) const override {} }; } // namespace android::inputdispatcher
services/inputflinger/tests/InputDispatcher_test.cpp +45 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "../dispatcher/InputDispatcher.h" #include "../BlockingQueue.h" #include "FakeApplicationHandle.h" #include "FakeInputTracingBackend.h" #include "TestEventMatchers.h" #include <NotifyArgsBuilders.h> Loading Loading @@ -658,14 +659,22 @@ private: // --- InputDispatcherTest --- // The trace is a global variable for now, to avoid having to pass it into all of the // FakeWindowHandles created throughout the tests. // TODO(b/210460522): Update the tests to avoid the need to have the trace be a global variable. static std::shared_ptr<VerifyingTrace> gVerifyingTrace = std::make_shared<VerifyingTrace>(); class InputDispatcherTest : public testing::Test { protected: std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy; std::unique_ptr<InputDispatcher> mDispatcher; void SetUp() override { gVerifyingTrace->reset(); mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>(); mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, nullptr); mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, std::make_unique<FakeInputTracingBackend>( gVerifyingTrace)); mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false); // Start InputDispatcher thread Loading @@ -676,6 +685,7 @@ protected: ASSERT_EQ(OK, mDispatcher->stop()); mFakePolicy.reset(); mDispatcher.reset(); ASSERT_NO_FATAL_FAILURE(gVerifyingTrace->verifyExpectedEventsTraced()); } /** Loading Loading @@ -1395,11 +1405,7 @@ public: } std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent() { if (mInputReceiver == nullptr) { ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::make_pair(std::nullopt, nullptr); } return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); return receive(); } void finishEvent(uint32_t sequenceNum) { Loading Loading @@ -1444,6 +1450,7 @@ private: static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; // FakeWindowHandle uses this consume method to ensure received events are added to the trace. std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) { if (mInputReceiver == nullptr) { LOG(FATAL) << "Cannot consume event from a window with no input event receiver"; Loading @@ -1452,8 +1459,40 @@ private: if (event == nullptr) { ADD_FAILURE() << "Consume failed: no event"; } expectReceivedEventTraced(event); return event; } // FakeWindowHandle uses this receive method to ensure received events are added to the trace. std::pair<std::optional<uint32_t /*seq*/>, std::unique_ptr<InputEvent>> receive() { if (mInputReceiver == nullptr) { ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::make_pair(std::nullopt, nullptr); } auto out = mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); const auto& [_, event] = out; expectReceivedEventTraced(event); return std::move(out); } void expectReceivedEventTraced(const std::unique_ptr<InputEvent>& event) { if (!event) { return; } switch (event->getType()) { case InputEventType::KEY: { gVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event)); break; } case InputEventType::MOTION: { gVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event)); break; } default: break; } } }; std::atomic<int32_t> FakeWindowHandle::sId{1}; Loading