Skip to content

Commit c5fc7d4

Browse files
prabirmspAndroid (Google) Code Review
authored andcommitted
Merge changes from topic "reland-input-tracing-tests" into main
* changes: Reland "Increase the test timeout used when waiting for events to be traced" InputDispatcher_test: Fix flakiness when verifying traced events Reland "InputDispatcher_test: Verify all consumed events are traced"
2 parents 9edb922 + a2d3cf1 commit c5fc7d4

4 files changed

Lines changed: 245 additions & 6 deletions

File tree

services/inputflinger/tests/Android.bp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ cc_test {
4545
"EventHub_test.cpp",
4646
"FakeEventHub.cpp",
4747
"FakeInputReaderPolicy.cpp",
48+
"FakeInputTracingBackend.cpp",
4849
"FakePointerController.cpp",
4950
"FocusResolver_test.cpp",
5051
"GestureConverter_test.cpp",
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "FakeInputTracingBackend.h"
18+
19+
#include <android-base/logging.h>
20+
#include <utils/Errors.h>
21+
22+
namespace android::inputdispatcher {
23+
24+
namespace {
25+
26+
// Use a larger timeout while waiting for events to be traced, compared to the timeout used while
27+
// waiting to receive events through the input channel. Events are traced from a separate thread,
28+
// which does not have the same high thread priority as the InputDispatcher's thread, so the tracer
29+
// is expected to lag behind the Dispatcher at times.
30+
constexpr auto TRACE_TIMEOUT = std::chrono::seconds(5);
31+
32+
base::ResultError<> error(const std::ostringstream& ss) {
33+
return base::ResultError(ss.str(), BAD_VALUE);
34+
}
35+
36+
} // namespace
37+
38+
// --- VerifyingTrace ---
39+
40+
void VerifyingTrace::expectKeyDispatchTraced(const KeyEvent& event) {
41+
std::scoped_lock lock(mLock);
42+
mExpectedEvents.emplace_back(event);
43+
}
44+
45+
void VerifyingTrace::expectMotionDispatchTraced(const MotionEvent& event) {
46+
std::scoped_lock lock(mLock);
47+
mExpectedEvents.emplace_back(event);
48+
}
49+
50+
void VerifyingTrace::verifyExpectedEventsTraced() {
51+
std::unique_lock lock(mLock);
52+
base::ScopedLockAssertion assumeLocked(mLock);
53+
54+
base::Result<void> result;
55+
mEventTracedCondition.wait_for(lock, TRACE_TIMEOUT, [&]() REQUIRES(mLock) {
56+
for (const auto& expectedEvent : mExpectedEvents) {
57+
std::visit([&](const auto& event)
58+
REQUIRES(mLock) { result = verifyEventTraced(event); },
59+
expectedEvent);
60+
if (!result.ok()) {
61+
return false;
62+
}
63+
}
64+
return true;
65+
});
66+
67+
EXPECT_TRUE(result.ok())
68+
<< "Timed out waiting for all expected events to be traced successfully: "
69+
<< result.error().message();
70+
}
71+
72+
void VerifyingTrace::reset() {
73+
std::scoped_lock lock(mLock);
74+
mTracedEvents.clear();
75+
mExpectedEvents.clear();
76+
}
77+
78+
template <typename Event>
79+
base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent) const {
80+
std::ostringstream msg;
81+
82+
auto tracedEventsIt = mTracedEvents.find(expectedEvent.getId());
83+
if (tracedEventsIt == mTracedEvents.end()) {
84+
msg << "Expected event with ID 0x" << std::hex << expectedEvent.getId()
85+
<< " to be traced, but it was not.\n"
86+
<< "Expected event: " << expectedEvent;
87+
return error(msg);
88+
}
89+
90+
return {};
91+
}
92+
93+
// --- FakeInputTracingBackend ---
94+
95+
void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const {
96+
{
97+
std::scoped_lock lock(mTrace->mLock);
98+
mTrace->mTracedEvents.emplace(event.id);
99+
}
100+
mTrace->mEventTracedCondition.notify_all();
101+
}
102+
103+
void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const {
104+
{
105+
std::scoped_lock lock(mTrace->mLock);
106+
mTrace->mTracedEvents.emplace(event.id);
107+
}
108+
mTrace->mEventTracedCondition.notify_all();
109+
}
110+
111+
} // namespace android::inputdispatcher
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include "../dispatcher/trace/InputTracingBackendInterface.h"
20+
21+
#include <android-base/result.h>
22+
#include <android-base/thread_annotations.h>
23+
#include <gtest/gtest.h>
24+
#include <input/Input.h>
25+
#include <condition_variable>
26+
#include <memory>
27+
#include <mutex>
28+
#include <unordered_set>
29+
#include <vector>
30+
31+
namespace android::inputdispatcher {
32+
33+
/**
34+
* A class representing an input trace, used to make assertions on what was traced by
35+
* InputDispatcher in tests. This class is thread-safe.
36+
*/
37+
class VerifyingTrace {
38+
public:
39+
VerifyingTrace() = default;
40+
41+
/** Add an expectation for a key event to be traced. */
42+
void expectKeyDispatchTraced(const KeyEvent& event);
43+
44+
/** Add an expectation for a motion event to be traced. */
45+
void expectMotionDispatchTraced(const MotionEvent& event);
46+
47+
/**
48+
* Wait and verify that all expected events are traced.
49+
* This is a lenient verifier that does not expect the events to be traced in the order
50+
* that the events were expected, and does not fail if there are events that are traced that
51+
* were not expected. Verifying does not clear the expectations.
52+
*/
53+
void verifyExpectedEventsTraced();
54+
55+
/** Reset the trace and clear all expectations. */
56+
void reset();
57+
58+
private:
59+
std::mutex mLock;
60+
std::condition_variable mEventTracedCondition;
61+
std::unordered_set<uint32_t /*eventId*/> mTracedEvents GUARDED_BY(mLock);
62+
std::vector<std::variant<KeyEvent, MotionEvent>> mExpectedEvents GUARDED_BY(mLock);
63+
64+
friend class FakeInputTracingBackend;
65+
66+
// Helper to verify that the given event appears as expected in the trace. If the verification
67+
// fails, the error message describes why.
68+
template <typename Event>
69+
base::Result<void> verifyEventTraced(const Event&) const REQUIRES(mLock);
70+
};
71+
72+
/**
73+
* A backend implementation for input tracing that records events to the provided
74+
* VerifyingTrace used for testing.
75+
*/
76+
class FakeInputTracingBackend : public trace::InputTracingBackendInterface {
77+
public:
78+
FakeInputTracingBackend(std::shared_ptr<VerifyingTrace> trace) : mTrace(trace) {}
79+
80+
private:
81+
std::shared_ptr<VerifyingTrace> mTrace;
82+
83+
void traceKeyEvent(const trace::TracedKeyEvent& entry) const override;
84+
void traceMotionEvent(const trace::TracedMotionEvent& entry) const override;
85+
void traceWindowDispatch(const WindowDispatchArgs& entry) const override {}
86+
};
87+
88+
} // namespace android::inputdispatcher

services/inputflinger/tests/InputDispatcher_test.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "../dispatcher/InputDispatcher.h"
1818
#include "../BlockingQueue.h"
1919
#include "FakeApplicationHandle.h"
20+
#include "FakeInputTracingBackend.h"
2021
#include "TestEventMatchers.h"
2122

2223
#include <NotifyArgsBuilders.h>
@@ -660,21 +661,30 @@ class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
660661

661662
// --- InputDispatcherTest ---
662663

664+
// The trace is a global variable for now, to avoid having to pass it into all of the
665+
// FakeWindowHandles created throughout the tests.
666+
// TODO(b/210460522): Update the tests to avoid the need to have the trace be a global variable.
667+
static std::shared_ptr<VerifyingTrace> gVerifyingTrace = std::make_shared<VerifyingTrace>();
668+
663669
class InputDispatcherTest : public testing::Test {
664670
protected:
665671
std::unique_ptr<FakeInputDispatcherPolicy> mFakePolicy;
666672
std::unique_ptr<InputDispatcher> mDispatcher;
667673

668674
void SetUp() override {
675+
gVerifyingTrace->reset();
669676
mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
670-
mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, nullptr);
677+
mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy,
678+
std::make_unique<FakeInputTracingBackend>(
679+
gVerifyingTrace));
671680

672681
mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
673682
// Start InputDispatcher thread
674683
ASSERT_EQ(OK, mDispatcher->start());
675684
}
676685

677686
void TearDown() override {
687+
ASSERT_NO_FATAL_FAILURE(gVerifyingTrace->verifyExpectedEventsTraced());
678688
ASSERT_EQ(OK, mDispatcher->stop());
679689
mFakePolicy.reset();
680690
mDispatcher.reset();
@@ -1397,11 +1407,7 @@ class FakeWindowHandle : public WindowInfoHandle {
13971407
}
13981408

13991409
std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent() {
1400-
if (mInputReceiver == nullptr) {
1401-
ADD_FAILURE() << "Invalid receive event on window with no receiver";
1402-
return std::make_pair(std::nullopt, nullptr);
1403-
}
1404-
return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
1410+
return receive();
14051411
}
14061412

14071413
void finishEvent(uint32_t sequenceNum) {
@@ -1439,6 +1445,7 @@ class FakeWindowHandle : public WindowInfoHandle {
14391445

14401446
int getChannelFd() { return mInputReceiver->getChannelFd(); }
14411447

1448+
// FakeWindowHandle uses this consume method to ensure received events are added to the trace.
14421449
std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) {
14431450
if (mInputReceiver == nullptr) {
14441451
LOG(FATAL) << "Cannot consume event from a window with no input event receiver";
@@ -1447,6 +1454,7 @@ class FakeWindowHandle : public WindowInfoHandle {
14471454
if (event == nullptr) {
14481455
ADD_FAILURE() << "Consume failed: no event";
14491456
}
1457+
expectReceivedEventTraced(event);
14501458
return event;
14511459
}
14521460

@@ -1456,6 +1464,37 @@ class FakeWindowHandle : public WindowInfoHandle {
14561464
std::shared_ptr<FakeInputReceiver> mInputReceiver;
14571465
static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
14581466
friend class sp<FakeWindowHandle>;
1467+
1468+
// FakeWindowHandle uses this receive method to ensure received events are added to the trace.
1469+
std::pair<std::optional<uint32_t /*seq*/>, std::unique_ptr<InputEvent>> receive() {
1470+
if (mInputReceiver == nullptr) {
1471+
ADD_FAILURE() << "Invalid receive event on window with no receiver";
1472+
return std::make_pair(std::nullopt, nullptr);
1473+
}
1474+
auto out = mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
1475+
const auto& [_, event] = out;
1476+
expectReceivedEventTraced(event);
1477+
return std::move(out);
1478+
}
1479+
1480+
void expectReceivedEventTraced(const std::unique_ptr<InputEvent>& event) {
1481+
if (!event) {
1482+
return;
1483+
}
1484+
1485+
switch (event->getType()) {
1486+
case InputEventType::KEY: {
1487+
gVerifyingTrace->expectKeyDispatchTraced(static_cast<KeyEvent&>(*event));
1488+
break;
1489+
}
1490+
case InputEventType::MOTION: {
1491+
gVerifyingTrace->expectMotionDispatchTraced(static_cast<MotionEvent&>(*event));
1492+
break;
1493+
}
1494+
default:
1495+
break;
1496+
}
1497+
}
14591498
};
14601499

14611500
std::atomic<int32_t> FakeWindowHandle::sId{1};

0 commit comments

Comments
 (0)