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 "InputTraceSession.h"
18
19 #include <NotifyArgsBuilders.h>
20 #include <android-base/logging.h>
21 #include <gtest/gtest.h>
22 #include <input/PrintTools.h>
23 #include <perfetto/trace/android/android_input_event.pbzero.h>
24 #include <perfetto/trace/android/winscope_extensions.pbzero.h>
25 #include <perfetto/trace/android/winscope_extensions_impl.pbzero.h>
26
27 #include <utility>
28
29 namespace android {
30
31 using perfetto::protos::pbzero::AndroidInputEvent;
32 using perfetto::protos::pbzero::AndroidInputEventConfig;
33 using perfetto::protos::pbzero::AndroidKeyEvent;
34 using perfetto::protos::pbzero::AndroidMotionEvent;
35 using perfetto::protos::pbzero::AndroidWindowInputDispatchEvent;
36 using perfetto::protos::pbzero::WinscopeExtensions;
37 using perfetto::protos::pbzero::WinscopeExtensionsImpl;
38
39 // These operator<< definitions must be in the global namespace for them to be accessible to the
40 // GTEST library. They cannot be in the anonymous namespace.
operator <<(std::ostream & out,const std::variant<KeyEvent,MotionEvent> & event)41 static std::ostream& operator<<(std::ostream& out,
42 const std::variant<KeyEvent, MotionEvent>& event) {
43 std::visit([&](const auto& e) { out << e; }, event);
44 return out;
45 }
46
operator <<(std::ostream & out,const InputTraceSession::WindowDispatchEvent & event)47 static std::ostream& operator<<(std::ostream& out,
48 const InputTraceSession::WindowDispatchEvent& event) {
49 out << "Window dispatch to windowId: " << event.window->getId() << ", event: " << event.event;
50 return out;
51 }
52
53 namespace {
54
getId(const std::variant<KeyEvent,MotionEvent> & event)55 inline uint32_t getId(const std::variant<KeyEvent, MotionEvent>& event) {
56 return std::visit([&](const auto& e) { return e.getId(); }, event);
57 }
58
startTrace(const std::function<void (protozero::HeapBuffered<AndroidInputEventConfig> &)> & configure)59 std::unique_ptr<perfetto::TracingSession> startTrace(
60 const std::function<void(protozero::HeapBuffered<AndroidInputEventConfig>&)>& configure) {
61 protozero::HeapBuffered<AndroidInputEventConfig> inputEventConfig{};
62 configure(inputEventConfig);
63
64 perfetto::TraceConfig config;
65 config.add_buffers()->set_size_kb(1024); // Record up to 1 MiB.
66 auto* dataSourceConfig = config.add_data_sources()->mutable_config();
67 dataSourceConfig->set_name("android.input.inputevent");
68 dataSourceConfig->set_android_input_event_config_raw(inputEventConfig.SerializeAsString());
69
70 std::unique_ptr<perfetto::TracingSession> tracingSession(perfetto::Tracing::NewTrace());
71 tracingSession->Setup(config);
72 tracingSession->StartBlocking();
73 return tracingSession;
74 }
75
stopTrace(std::unique_ptr<perfetto::TracingSession> tracingSession)76 std::string stopTrace(std::unique_ptr<perfetto::TracingSession> tracingSession) {
77 tracingSession->StopBlocking();
78 std::vector<char> traceChars(tracingSession->ReadTraceBlocking());
79 return {traceChars.data(), traceChars.size()};
80 }
81
82 // Decodes the trace, and returns all of the traced input events, and whether they were each
83 // traced as a redacted event.
decodeTrace(const std::string & rawTrace)84 auto decodeTrace(const std::string& rawTrace) {
85 using namespace perfetto::protos::pbzero;
86
87 ArrayMap<AndroidMotionEvent::Decoder, bool /*redacted*/> tracedMotions;
88 ArrayMap<AndroidKeyEvent::Decoder, bool /*redacted*/> tracedKeys;
89 ArrayMap<AndroidWindowInputDispatchEvent::Decoder, bool /*redacted*/> tracedWindowDispatches;
90
91 Trace::Decoder trace{rawTrace};
92 if (trace.has_packet()) {
93 for (auto it = trace.packet(); it; it++) {
94 TracePacket::Decoder packet{it->as_bytes()};
95 if (!packet.has_winscope_extensions()) {
96 continue;
97 }
98
99 WinscopeExtensions::Decoder extensions{packet.winscope_extensions()};
100 const auto& field =
101 extensions.Get(WinscopeExtensionsImpl::kAndroidInputEventFieldNumber);
102 if (!field.valid()) {
103 continue;
104 }
105
106 EXPECT_TRUE(packet.has_timestamp());
107 EXPECT_TRUE(packet.has_timestamp_clock_id());
108 EXPECT_EQ(packet.timestamp_clock_id(),
109 static_cast<uint32_t>(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC));
110
111 AndroidInputEvent::Decoder event{field.as_bytes()};
112 if (event.has_dispatcher_motion_event()) {
113 tracedMotions.emplace_back(event.dispatcher_motion_event(),
114 /*redacted=*/false);
115 }
116 if (event.has_dispatcher_motion_event_redacted()) {
117 tracedMotions.emplace_back(event.dispatcher_motion_event_redacted(),
118 /*redacted=*/true);
119 }
120 if (event.has_dispatcher_key_event()) {
121 tracedKeys.emplace_back(event.dispatcher_key_event(),
122 /*redacted=*/false);
123 }
124 if (event.has_dispatcher_key_event_redacted()) {
125 tracedKeys.emplace_back(event.dispatcher_key_event_redacted(),
126 /*redacted=*/true);
127 }
128 if (event.has_dispatcher_window_dispatch_event()) {
129 tracedWindowDispatches.emplace_back(event.dispatcher_window_dispatch_event(),
130 /*redacted=*/false);
131 }
132 if (event.has_dispatcher_window_dispatch_event_redacted()) {
133 tracedWindowDispatches
134 .emplace_back(event.dispatcher_window_dispatch_event_redacted(),
135 /*redacted=*/true);
136 }
137 }
138 }
139 return std::tuple{std::move(tracedMotions), std::move(tracedKeys),
140 std::move(tracedWindowDispatches)};
141 }
142
eventMatches(const MotionEvent & expected,const AndroidMotionEvent::Decoder & traced)143 bool eventMatches(const MotionEvent& expected, const AndroidMotionEvent::Decoder& traced) {
144 return static_cast<uint32_t>(expected.getId()) == traced.event_id();
145 }
146
eventMatches(const KeyEvent & expected,const AndroidKeyEvent::Decoder & traced)147 bool eventMatches(const KeyEvent& expected, const AndroidKeyEvent::Decoder& traced) {
148 return static_cast<uint32_t>(expected.getId()) == traced.event_id();
149 }
150
eventMatches(const InputTraceSession::WindowDispatchEvent & expected,const AndroidWindowInputDispatchEvent::Decoder & traced)151 bool eventMatches(const InputTraceSession::WindowDispatchEvent& expected,
152 const AndroidWindowInputDispatchEvent::Decoder& traced) {
153 return static_cast<uint32_t>(getId(expected.event)) == traced.event_id() &&
154 expected.window->getId() == traced.window_id();
155 }
156
157 template <typename ExpectedEvents, typename TracedEvents>
verifyExpectedEventsTraced(const ExpectedEvents & expectedEvents,const TracedEvents & tracedEvents,std::string_view name)158 void verifyExpectedEventsTraced(const ExpectedEvents& expectedEvents,
159 const TracedEvents& tracedEvents, std::string_view name) {
160 uint32_t totalExpectedCount = 0;
161
162 for (const auto& [expectedEvent, expectedLevel] : expectedEvents) {
163 int32_t totalMatchCount = 0;
164 int32_t redactedMatchCount = 0;
165 for (const auto& [tracedEvent, isRedacted] : tracedEvents) {
166 if (eventMatches(expectedEvent, tracedEvent)) {
167 totalMatchCount++;
168 if (isRedacted) {
169 redactedMatchCount++;
170 }
171 }
172 }
173 switch (expectedLevel) {
174 case Level::NONE:
175 ASSERT_EQ(totalMatchCount, 0) << "Event should not be traced, but it was traced"
176 << "\n\tExpected event: " << expectedEvent;
177 break;
178 case Level::REDACTED:
179 case Level::COMPLETE:
180 ASSERT_EQ(totalMatchCount, 1)
181 << "Event should match exactly one traced event, but it matched: "
182 << totalMatchCount << "\n\tExpected event: " << expectedEvent;
183 ASSERT_EQ(redactedMatchCount, expectedLevel == Level::REDACTED ? 1 : 0);
184 totalExpectedCount++;
185 break;
186 }
187 }
188
189 ASSERT_EQ(tracedEvents.size(), totalExpectedCount)
190 << "The number of traced " << name
191 << " events does not exactly match the number of expected events";
192 }
193
194 } // namespace
195
InputTraceSession(std::function<void (protozero::HeapBuffered<AndroidInputEventConfig> &)> configure)196 InputTraceSession::InputTraceSession(
197 std::function<void(protozero::HeapBuffered<AndroidInputEventConfig>&)> configure)
198 : mPerfettoSession(startTrace(std::move(configure))) {}
199
~InputTraceSession()200 InputTraceSession::~InputTraceSession() {
201 const auto rawTrace = stopTrace(std::move(mPerfettoSession));
202 verifyExpectations(rawTrace);
203 }
204
expectMotionTraced(Level level,const MotionEvent & event)205 void InputTraceSession::expectMotionTraced(Level level, const MotionEvent& event) {
206 mExpectedMotions.emplace_back(event, level);
207 }
208
expectKeyTraced(Level level,const KeyEvent & event)209 void InputTraceSession::expectKeyTraced(Level level, const KeyEvent& event) {
210 mExpectedKeys.emplace_back(event, level);
211 }
212
expectDispatchTraced(Level level,const WindowDispatchEvent & event)213 void InputTraceSession::expectDispatchTraced(Level level, const WindowDispatchEvent& event) {
214 mExpectedWindowDispatches.emplace_back(event, level);
215 }
216
verifyExpectations(const std::string & rawTrace)217 void InputTraceSession::verifyExpectations(const std::string& rawTrace) {
218 auto [tracedMotions, tracedKeys, tracedWindowDispatches] = decodeTrace(rawTrace);
219
220 verifyExpectedEventsTraced(mExpectedMotions, tracedMotions, "motion");
221 verifyExpectedEventsTraced(mExpectedKeys, tracedKeys, "key");
222 verifyExpectedEventsTraced(mExpectedWindowDispatches, tracedWindowDispatches,
223 "window dispatch");
224 }
225
226 } // namespace android
227