• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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