1 /*
2  * Copyright (C) 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 "src/trace_processor/importers/proto/winscope/android_input_event_parser.h"
18 
19 #include "perfetto/ext/base/base64.h"
20 #include "protos/perfetto/trace/android/android_input_event.pbzero.h"
21 #include "src/trace_processor/importers/common/args_tracker.h"
22 #include "src/trace_processor/importers/proto/args_parser.h"
23 #include "src/trace_processor/storage/trace_storage.h"
24 #include "src/trace_processor/tables/android_tables_py.h"
25 #include "src/trace_processor/types/trace_processor_context.h"
26 #include "src/trace_processor/util/winscope_proto_mapping.h"
27 
28 namespace perfetto::trace_processor {
29 
30 using perfetto::protos::pbzero::AndroidInputEvent;
31 using perfetto::protos::pbzero::AndroidKeyEvent;
32 using perfetto::protos::pbzero::AndroidMotionEvent;
33 using perfetto::protos::pbzero::AndroidWindowInputDispatchEvent;
34 using perfetto::protos::pbzero::TracePacket;
35 
AndroidInputEventParser(TraceProcessorContext * context)36 AndroidInputEventParser::AndroidInputEventParser(TraceProcessorContext* context)
37     : context_(*context), args_parser_{*context->descriptor_pool_} {}
38 
ParseAndroidInputEvent(int64_t packet_ts,const protozero::ConstBytes & bytes)39 void AndroidInputEventParser::ParseAndroidInputEvent(
40     int64_t packet_ts,
41     const protozero::ConstBytes& bytes) {
42   auto input_event = AndroidInputEvent::Decoder(bytes);
43 
44   constexpr static auto supported_fields = std::array{
45       AndroidInputEvent::kDispatcherMotionEventFieldNumber,
46       AndroidInputEvent::kDispatcherMotionEventRedactedFieldNumber,
47       AndroidInputEvent::kDispatcherKeyEventFieldNumber,
48       AndroidInputEvent::kDispatcherKeyEventRedactedFieldNumber,
49       AndroidInputEvent::kDispatcherWindowDispatchEventFieldNumber,
50       AndroidInputEvent::kDispatcherWindowDispatchEventRedactedFieldNumber};
51 
52   for (auto sub_field_id : supported_fields) {
53     auto sub_field = input_event.Get(static_cast<uint32_t>(sub_field_id));
54     if (!sub_field.valid())
55       continue;
56 
57     switch (sub_field_id) {
58       case AndroidInputEvent::kDispatcherMotionEventFieldNumber:
59       case AndroidInputEvent::kDispatcherMotionEventRedactedFieldNumber:
60         ParseMotionEvent(packet_ts, sub_field.as_bytes());
61         return;
62       case AndroidInputEvent::kDispatcherKeyEventFieldNumber:
63       case AndroidInputEvent::kDispatcherKeyEventRedactedFieldNumber:
64         ParseKeyEvent(packet_ts, sub_field.as_bytes());
65         return;
66       case AndroidInputEvent::kDispatcherWindowDispatchEventFieldNumber:
67       case AndroidInputEvent::kDispatcherWindowDispatchEventRedactedFieldNumber:
68         ParseWindowDispatchEvent(packet_ts, sub_field.as_bytes());
69         return;
70     }
71   }
72 }
73 
ParseMotionEvent(int64_t packet_ts,const protozero::ConstBytes & bytes)74 void AndroidInputEventParser::ParseMotionEvent(
75     int64_t packet_ts,
76     const protozero::ConstBytes& bytes) {
77   AndroidMotionEvent::Decoder event_proto(bytes);
78   tables::AndroidMotionEventsTable::Row event_row;
79   event_row.event_id = event_proto.event_id();
80   event_row.ts = packet_ts;
81   event_row.base64_proto =
82       context_.storage->mutable_string_pool()->InternString(
83           base::StringView(base::Base64Encode(bytes.data, bytes.size)));
84   event_row.base64_proto_id = event_row.base64_proto.raw_id();
85 
86   auto event_row_id = context_.storage->mutable_android_motion_events_table()
87                           ->Insert(event_row)
88                           .id;
89   auto inserter = context_.args_tracker->AddArgsTo(event_row_id);
90   ArgsParser writer{packet_ts, inserter, *context_.storage};
91 
92   base::Status status =
93       args_parser_.ParseMessage(bytes,
94                                 *util::winscope_proto_mapping::GetProtoName(
95                                     tables::AndroidMotionEventsTable::Name()),
96                                 nullptr /*parse all fields*/, writer);
97   if (!status.ok())
98     context_.storage->IncrementStats(stats::android_input_event_parse_errors);
99 }
100 
ParseKeyEvent(int64_t packet_ts,const protozero::ConstBytes & bytes)101 void AndroidInputEventParser::ParseKeyEvent(
102     int64_t packet_ts,
103     const protozero::ConstBytes& bytes) {
104   AndroidKeyEvent::Decoder event_proto(bytes);
105   tables::AndroidKeyEventsTable::Row event_row;
106   event_row.event_id = event_proto.event_id();
107   event_row.ts = packet_ts;
108   event_row.base64_proto =
109       context_.storage->mutable_string_pool()->InternString(
110           base::StringView(base::Base64Encode(bytes.data, bytes.size)));
111   event_row.base64_proto_id = event_row.base64_proto.raw_id();
112 
113   auto event_row_id = context_.storage->mutable_android_key_events_table()
114                           ->Insert(event_row)
115                           .id;
116   auto inserter = context_.args_tracker->AddArgsTo(event_row_id);
117   ArgsParser writer{packet_ts, inserter, *context_.storage};
118 
119   base::Status status =
120       args_parser_.ParseMessage(bytes,
121                                 *util::winscope_proto_mapping::GetProtoName(
122                                     tables::AndroidKeyEventsTable::Name()),
123                                 nullptr /*parse all fields*/, writer);
124   if (!status.ok())
125     context_.storage->IncrementStats(stats::android_input_event_parse_errors);
126 }
127 
ParseWindowDispatchEvent(int64_t packet_ts,const protozero::ConstBytes & bytes)128 void AndroidInputEventParser::ParseWindowDispatchEvent(
129     int64_t packet_ts,
130     const protozero::ConstBytes& bytes) {
131   AndroidWindowInputDispatchEvent::Decoder event_proto(bytes);
132   tables::AndroidInputEventDispatchTable::Row event_row;
133   event_row.event_id = event_proto.event_id();
134   event_row.vsync_id = event_proto.vsync_id();
135   event_row.window_id = event_proto.window_id();
136   event_row.base64_proto =
137       context_.storage->mutable_string_pool()->InternString(
138           base::StringView(base::Base64Encode(bytes.data, bytes.size)));
139   event_row.base64_proto_id = event_row.base64_proto.raw_id();
140 
141   auto event_row_id =
142       context_.storage->mutable_android_input_event_dispatch_table()
143           ->Insert(event_row)
144           .id;
145 
146   auto inserter = context_.args_tracker->AddArgsTo(event_row_id);
147   ArgsParser writer{packet_ts, inserter, *context_.storage};
148 
149   base::Status status = args_parser_.ParseMessage(
150       bytes,
151       *util::winscope_proto_mapping::GetProtoName(
152           tables::AndroidInputEventDispatchTable::Name()),
153       nullptr /*parse all fields*/, writer);
154   if (!status.ok())
155     context_.storage->IncrementStats(stats::android_input_event_parse_errors);
156 }
157 
158 }  // namespace perfetto::trace_processor
159