xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/network_trace_module.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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