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