1 /*
2 * Copyright (C) 2023 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/network_trace_module.h"
18
19 #include "perfetto/ext/base/string_writer.h"
20 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
21 #include "protos/perfetto/trace/trace_packet.pbzero.h"
22 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
23 #include "src/trace_processor/importers/common/slice_tracker.h"
24 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
25 #include "src/trace_processor/sorter/trace_sorter.h"
26 #include "src/trace_processor/storage/trace_storage.h"
27 #include "src/trace_processor/types/tcp_state.h"
28
29 namespace perfetto {
30 namespace trace_processor {
31 namespace {
32 // From android.os.UserHandle.PER_USER_RANGE
33 constexpr int kPerUserRange = 100000;
34
35 // Convert the bitmask into a string where '.' indicates an unset bit
36 // and each bit gets a unique letter if set. The letters correspond to
37 // the bitfields in tcphdr (fin, syn, rst, etc).
GetTcpFlagMask(uint32_t tcp_flags)38 base::StackString<12> GetTcpFlagMask(uint32_t tcp_flags) {
39 static constexpr char kBitNames[] = "fsrpauec";
40 static constexpr int kBitCount = 8;
41
42 char flags[kBitCount + 1] = {'\0'};
43 for (int f = 0; f < kBitCount; f++) {
44 flags[f] = (tcp_flags & (1 << f)) ? kBitNames[f] : '.';
45 }
46
47 return base::StackString<12>("%s", flags);
48 }
49 } // namespace
50
51 using ::perfetto::protos::pbzero::NetworkPacketBundle;
52 using ::perfetto::protos::pbzero::NetworkPacketEvent;
53 using ::perfetto::protos::pbzero::TracePacket;
54 using ::perfetto::protos::pbzero::TrafficDirection;
55 using ::protozero::ConstBytes;
56
NetworkTraceModule(TraceProcessorContext * context)57 NetworkTraceModule::NetworkTraceModule(TraceProcessorContext* context)
58 : context_(context),
59 net_arg_length_(context->storage->InternString("packet_length")),
60 net_arg_ip_proto_(context->storage->InternString("packet_transport")),
61 net_arg_tcp_flags_(context->storage->InternString("packet_tcp_flags")),
62 net_arg_tag_(context->storage->InternString("socket_tag")),
63 net_arg_uid_(context->storage->InternString("socket_uid")),
64 net_arg_local_port_(context->storage->InternString("local_port")),
65 net_arg_remote_port_(context->storage->InternString("remote_port")),
66 net_arg_icmp_type_(context->storage->InternString("packet_icmp_type")),
67 net_arg_icmp_code_(context->storage->InternString("packet_icmp_code")),
68 net_ipproto_tcp_(context->storage->InternString("IPPROTO_TCP")),
69 net_ipproto_udp_(context->storage->InternString("IPPROTO_UDP")),
70 net_ipproto_icmp_(context->storage->InternString("IPPROTO_ICMP")),
71 net_ipproto_icmpv6_(context->storage->InternString("IPPROTO_ICMPV6")),
72 packet_count_(context->storage->InternString("packet_count")) {
73 RegisterForField(TracePacket::kNetworkPacketFieldNumber, context);
74 RegisterForField(TracePacket::kNetworkPacketBundleFieldNumber, context);
75 }
76
TokenizePacket(const protos::pbzero::TracePacket::Decoder & decoder,TraceBlobView *,int64_t ts,RefPtr<PacketSequenceStateGeneration> state,uint32_t field_id)77 ModuleResult NetworkTraceModule::TokenizePacket(
78 const protos::pbzero::TracePacket::Decoder& decoder,
79 TraceBlobView*,
80 int64_t ts,
81 RefPtr<PacketSequenceStateGeneration> state,
82 uint32_t field_id) {
83 if (field_id != TracePacket::kNetworkPacketBundleFieldNumber) {
84 return ModuleResult::Ignored();
85 }
86
87 NetworkPacketBundle::Decoder evt(decoder.network_packet_bundle());
88
89 ConstBytes context = evt.ctx();
90 if (evt.has_iid()) {
91 auto* interned = state->LookupInternedMessage<
92 protos::pbzero::InternedData::kPacketContextFieldNumber,
93 protos::pbzero::NetworkPacketContext>(evt.iid());
94 if (!interned) {
95 context_->storage->IncrementStats(stats::network_trace_intern_errors);
96 } else {
97 context = interned->ctx();
98 }
99 }
100
101 if (evt.has_total_length()) {
102 // Forward the bundle with (possibly de-interned) context.
103 packet_buffer_->set_timestamp(static_cast<uint64_t>(ts));
104 auto* event = packet_buffer_->set_network_packet_bundle();
105 event->set_ctx()->AppendRawProtoBytes(context.data, context.size);
106 event->set_total_length(evt.total_length());
107 event->set_total_packets(evt.total_packets());
108 event->set_total_duration(evt.total_duration());
109 PushPacketBufferForSort(ts, state);
110 } else {
111 // Push a NetworkPacketEvent for each packet in the packed arrays.
112 bool parse_error = false;
113 auto length_iter = evt.packet_lengths(&parse_error);
114 auto timestamp_iter = evt.packet_timestamps(&parse_error);
115 if (parse_error) {
116 context_->storage->IncrementStats(stats::network_trace_parse_errors);
117 return ModuleResult::Handled();
118 }
119
120 for (; timestamp_iter && length_iter; ++timestamp_iter, ++length_iter) {
121 int64_t real_ts = ts + static_cast<int64_t>(*timestamp_iter);
122 packet_buffer_->set_timestamp(static_cast<uint64_t>(real_ts));
123 auto* event = packet_buffer_->set_network_packet();
124 event->AppendRawProtoBytes(context.data, context.size);
125 event->set_length(*length_iter);
126 PushPacketBufferForSort(real_ts, state);
127 }
128 }
129
130 return ModuleResult::Handled();
131 }
132
ParseTracePacketData(const TracePacket::Decoder & decoder,int64_t ts,const TracePacketData &,uint32_t field_id)133 void NetworkTraceModule::ParseTracePacketData(
134 const TracePacket::Decoder& decoder,
135 int64_t ts,
136 const TracePacketData&,
137 uint32_t field_id) {
138 switch (field_id) {
139 case TracePacket::kNetworkPacketFieldNumber:
140 ParseNetworkPacketEvent(ts, decoder.network_packet());
141 return;
142 case TracePacket::kNetworkPacketBundleFieldNumber:
143 ParseNetworkPacketBundle(ts, decoder.network_packet_bundle());
144 return;
145 }
146 }
147
ParseGenericEvent(int64_t ts,int64_t dur,int64_t length,int64_t count,protos::pbzero::NetworkPacketEvent::Decoder & evt)148 void NetworkTraceModule::ParseGenericEvent(
149 int64_t ts,
150 int64_t dur,
151 int64_t length,
152 int64_t count,
153 protos::pbzero::NetworkPacketEvent::Decoder& evt) {
154 // Tracks are per interface and per direction.
155 const char* track_suffix =
156 evt.direction() == TrafficDirection::DIR_INGRESS ? "Received"
157 : evt.direction() == TrafficDirection::DIR_EGRESS ? "Transmitted"
158 : "DIR_UNKNOWN";
159
160 base::StackString<64> name("%.*s %s", static_cast<int>(evt.interface().size),
161 evt.interface().data, track_suffix);
162 StringId track_name = context_->storage->InternString(name.string_view());
163 StringId direction = context_->storage->InternString(track_suffix);
164 StringId iface = context_->storage->InternString(evt.interface());
165
166 if (!loaded_package_names_) {
167 loaded_package_names_ = true;
168 const auto& package_list = context_->storage->package_list_table();
169 for (auto row = package_list.IterateRows(); row; ++row) {
170 package_names_.Insert(row.uid(), row.package_name());
171 }
172 }
173
174 // Android stores the app id in the lower part of the uid. The actual uid will
175 // be `user_id * kPerUserRange + app_id`. For package lookup, we want app id.
176 uint32_t app_id = evt.uid() % kPerUserRange;
177
178 // Event titles are the package name, if available.
179 StringId slice_name = kNullStringId;
180 if (evt.uid() > 0) {
181 StringId* iter = package_names_.Find(app_id);
182 if (iter != nullptr) {
183 slice_name = *iter;
184 }
185 }
186
187 // If the above fails, fall back to the uid.
188 if (slice_name == kNullStringId) {
189 base::StackString<32> title_str("uid=%" PRIu32, evt.uid());
190 slice_name = context_->storage->InternString(title_str.string_view());
191 }
192
193 TrackId track_id = context_->async_track_set_tracker->Scoped(
194 context_->async_track_set_tracker->InternGlobalTrackSet(track_name), ts,
195 dur);
196
197 tables::AndroidNetworkPacketsTable::Row actual_row;
198 actual_row.ts = ts;
199 actual_row.dur = dur;
200 actual_row.name = slice_name;
201 actual_row.track_id = track_id;
202 actual_row.category = track_name;
203 actual_row.iface = iface;
204 actual_row.direction = direction;
205 actual_row.packet_transport = GetIpProto(evt);
206 actual_row.packet_length = length;
207 actual_row.packet_count = count;
208 actual_row.socket_tag = evt.tag();
209 actual_row.socket_uid = evt.uid();
210 actual_row.socket_tag_str = context_->storage->InternString(
211 base::StackString<16>("0x%x", evt.tag()).string_view());
212
213 if (evt.has_local_port()) {
214 actual_row.local_port = evt.local_port();
215 }
216 if (evt.has_remote_port()) {
217 actual_row.remote_port = evt.remote_port();
218 }
219 if (evt.has_icmp_type()) {
220 actual_row.packet_icmp_type = evt.icmp_type();
221 }
222 if (evt.has_icmp_code()) {
223 actual_row.packet_icmp_code = evt.icmp_code();
224 }
225 if (evt.has_tcp_flags()) {
226 actual_row.packet_tcp_flags = evt.tcp_flags();
227 actual_row.packet_tcp_flags_str = context_->storage->InternString(
228 GetTcpFlagMask(evt.tcp_flags()).string_view());
229 }
230
231 context_->slice_tracker->ScopedTyped(
232 context_->storage->mutable_android_network_packets_table(), actual_row,
233 [&](ArgsTracker::BoundInserter* i) {
234 i->AddArg(net_arg_ip_proto_,
235 Variadic::String(actual_row.packet_transport));
236
237 i->AddArg(net_arg_uid_, Variadic::Integer(evt.uid()));
238 i->AddArg(net_arg_tag_, Variadic::String(actual_row.socket_tag_str));
239
240 if (actual_row.packet_tcp_flags_str.has_value()) {
241 i->AddArg(net_arg_tcp_flags_,
242 Variadic::String(*actual_row.packet_tcp_flags_str));
243 }
244
245 if (evt.has_local_port()) {
246 i->AddArg(net_arg_local_port_, Variadic::Integer(evt.local_port()));
247 }
248 if (evt.has_remote_port()) {
249 i->AddArg(net_arg_remote_port_, Variadic::Integer(evt.remote_port()));
250 }
251 if (evt.has_icmp_type()) {
252 i->AddArg(net_arg_icmp_type_, Variadic::Integer(evt.icmp_type()));
253 }
254 if (evt.has_icmp_code()) {
255 i->AddArg(net_arg_icmp_code_, Variadic::Integer(evt.icmp_code()));
256 }
257 i->AddArg(net_arg_length_, Variadic::Integer(length));
258 i->AddArg(packet_count_, Variadic::Integer(count));
259 });
260 }
261
GetIpProto(NetworkPacketEvent::Decoder & evt)262 StringId NetworkTraceModule::GetIpProto(NetworkPacketEvent::Decoder& evt) {
263 switch (evt.ip_proto()) {
264 case kIpprotoTcp:
265 return net_ipproto_tcp_;
266 case kIpprotoUdp:
267 return net_ipproto_udp_;
268 case kIpprotoIcmp:
269 return net_ipproto_icmp_;
270 case kIpprotoIcmpv6:
271 return net_ipproto_icmpv6_;
272 default:
273 return context_->storage->InternString(
274 base::StackString<32>("IPPROTO (%d)", evt.ip_proto()).string_view());
275 }
276 }
277
ParseNetworkPacketEvent(int64_t ts,ConstBytes blob)278 void NetworkTraceModule::ParseNetworkPacketEvent(int64_t ts, ConstBytes blob) {
279 NetworkPacketEvent::Decoder event(blob);
280 ParseGenericEvent(ts, /*dur=*/0, event.length(), /*count=*/1, event);
281 }
282
ParseNetworkPacketBundle(int64_t ts,ConstBytes blob)283 void NetworkTraceModule::ParseNetworkPacketBundle(int64_t ts, ConstBytes blob) {
284 NetworkPacketBundle::Decoder event(blob);
285 NetworkPacketEvent::Decoder ctx(event.ctx());
286 int64_t dur = static_cast<int64_t>(event.total_duration());
287 int64_t length = static_cast<int64_t>(event.total_length());
288
289 // Any bundle that makes it through tokenization must be aggregated bundles
290 // with total packets/total length.
291 ParseGenericEvent(ts, dur, length, event.total_packets(), ctx);
292 }
293
PushPacketBufferForSort(int64_t timestamp,RefPtr<PacketSequenceStateGeneration> state)294 void NetworkTraceModule::PushPacketBufferForSort(
295 int64_t timestamp,
296 RefPtr<PacketSequenceStateGeneration> state) {
297 std::vector<uint8_t> v = packet_buffer_.SerializeAsArray();
298 context_->sorter->PushTracePacket(
299 timestamp, std::move(state),
300 TraceBlobView(TraceBlob::CopyFrom(v.data(), v.size())));
301 packet_buffer_.Reset();
302 }
303
304 } // namespace trace_processor
305 } // namespace perfetto
306