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