• 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 "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.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_ipproto_tcp_(context->storage->InternString("IPPROTO_TCP")),
67       net_ipproto_udp_(context->storage->InternString("IPPROTO_UDP")),
68       packet_count_(context->storage->InternString("packet_count")) {
69   RegisterForField(TracePacket::kNetworkPacketFieldNumber, context);
70   RegisterForField(TracePacket::kNetworkPacketBundleFieldNumber, context);
71 }
72 
TokenizePacket(const protos::pbzero::TracePacket::Decoder & decoder,TraceBlobView *,int64_t ts,PacketSequenceState * state,uint32_t field_id)73 ModuleResult NetworkTraceModule::TokenizePacket(
74     const protos::pbzero::TracePacket::Decoder& decoder,
75     TraceBlobView*,
76     int64_t ts,
77     PacketSequenceState* state,
78     uint32_t field_id) {
79   if (field_id != TracePacket::kNetworkPacketBundleFieldNumber) {
80     return ModuleResult::Ignored();
81   }
82 
83   auto seq_state = state->current_generation();
84   NetworkPacketBundle::Decoder evt(decoder.network_packet_bundle());
85 
86   ConstBytes context = evt.ctx();
87   if (evt.has_iid()) {
88     auto* interned = seq_state->LookupInternedMessage<
89         protos::pbzero::InternedData::kPacketContextFieldNumber,
90         protos::pbzero::NetworkPacketContext>(evt.iid());
91     if (!interned) {
92       context_->storage->IncrementStats(stats::network_trace_intern_errors);
93     } else {
94       context = interned->ctx();
95     }
96   }
97 
98   if (evt.has_total_length()) {
99     // Forward the bundle with (possibly de-interned) context.
100     packet_buffer_->set_timestamp(static_cast<uint64_t>(ts));
101     auto* event = packet_buffer_->set_network_packet_bundle();
102     event->set_ctx()->AppendRawProtoBytes(context.data, context.size);
103     event->set_total_length(evt.total_length());
104     event->set_total_packets(evt.total_packets());
105     event->set_total_duration(evt.total_duration());
106     PushPacketBufferForSort(ts, state);
107   } else {
108     // Push a NetworkPacketEvent for each packet in the packed arrays.
109     bool parse_error = false;
110     auto length_iter = evt.packet_lengths(&parse_error);
111     auto timestamp_iter = evt.packet_timestamps(&parse_error);
112     if (parse_error) {
113       context_->storage->IncrementStats(stats::network_trace_parse_errors);
114       return ModuleResult::Handled();
115     }
116 
117     for (; timestamp_iter && length_iter; ++timestamp_iter, ++length_iter) {
118       int64_t real_ts = ts + static_cast<int64_t>(*timestamp_iter);
119       packet_buffer_->set_timestamp(static_cast<uint64_t>(real_ts));
120       auto* event = packet_buffer_->set_network_packet();
121       event->AppendRawProtoBytes(context.data, context.size);
122       event->set_length(*length_iter);
123       PushPacketBufferForSort(real_ts, state);
124     }
125   }
126 
127   return ModuleResult::Handled();
128 }
129 
ParseTracePacketData(const TracePacket::Decoder & decoder,int64_t ts,const TracePacketData &,uint32_t field_id)130 void NetworkTraceModule::ParseTracePacketData(
131     const TracePacket::Decoder& decoder,
132     int64_t ts,
133     const TracePacketData&,
134     uint32_t field_id) {
135   switch (field_id) {
136     case TracePacket::kNetworkPacketFieldNumber:
137       ParseNetworkPacketEvent(ts, decoder.network_packet());
138       return;
139     case TracePacket::kNetworkPacketBundleFieldNumber:
140       ParseNetworkPacketBundle(ts, decoder.network_packet_bundle());
141       return;
142   }
143 }
144 
ParseGenericEvent(int64_t ts,int64_t dur,protos::pbzero::NetworkPacketEvent::Decoder & evt,std::function<void (ArgsTracker::BoundInserter *)> extra_args)145 void NetworkTraceModule::ParseGenericEvent(
146     int64_t ts,
147     int64_t dur,
148     protos::pbzero::NetworkPacketEvent::Decoder& evt,
149     std::function<void(ArgsTracker::BoundInserter*)> extra_args) {
150   // Tracks are per interface and per direction.
151   const char* track_suffix =
152       evt.direction() == TrafficDirection::DIR_INGRESS  ? " Received"
153       : evt.direction() == TrafficDirection::DIR_EGRESS ? " Transmitted"
154                                                         : " DIR_UNKNOWN";
155 
156   base::StackString<64> name("%.*s%s", static_cast<int>(evt.interface().size),
157                              evt.interface().data, track_suffix);
158   StringId name_id = context_->storage->InternString(name.string_view());
159 
160   // Android stores the app id in the lower part of the uid. The actual uid will
161   // be `user_id * kPerUserRange + app_id`. For package lookup, we want app id.
162   int app_id = evt.uid() % kPerUserRange;
163 
164   // Event titles are the package name, if available.
165   StringId title_id = kNullStringId;
166   if (evt.uid() > 0) {
167     const auto& package_list = context_->storage->package_list_table();
168     std::optional<uint32_t> pkg_row = package_list.uid().IndexOf(app_id);
169     if (pkg_row) {
170       title_id = package_list.package_name()[*pkg_row];
171     }
172   }
173 
174   // If the above fails, fall back to the uid.
175   if (title_id == kNullStringId) {
176     base::StackString<32> title_str("uid=%" PRIu32, evt.uid());
177     title_id = context_->storage->InternString(title_str.string_view());
178   }
179 
180   TrackId track_id = context_->async_track_set_tracker->Scoped(
181       context_->async_track_set_tracker->InternGlobalTrackSet(name_id), ts,
182       dur);
183 
184   context_->slice_tracker->Scoped(
185       ts, track_id, name_id, title_id, dur, [&](ArgsTracker::BoundInserter* i) {
186         StringId ip_proto;
187         if (evt.ip_proto() == kIpprotoTcp) {
188           ip_proto = net_ipproto_tcp_;
189         } else if (evt.ip_proto() == kIpprotoUdp) {
190           ip_proto = net_ipproto_udp_;
191         } else {
192           base::StackString<32> proto("IPPROTO (%d)", evt.ip_proto());
193           ip_proto = context_->storage->InternString(proto.string_view());
194         }
195 
196         i->AddArg(net_arg_ip_proto_, Variadic::String(ip_proto));
197 
198         i->AddArg(net_arg_uid_, Variadic::Integer(evt.uid()));
199         base::StackString<16> tag("0x%x", evt.tag());
200         i->AddArg(net_arg_tag_,
201                   Variadic::String(
202                       context_->storage->InternString(tag.string_view())));
203 
204         base::StackString<12> flags = GetTcpFlagMask(evt.tcp_flags());
205         i->AddArg(net_arg_tcp_flags_,
206                   Variadic::String(
207                       context_->storage->InternString(flags.string_view())));
208 
209         i->AddArg(net_arg_local_port_, Variadic::Integer(evt.local_port()));
210         i->AddArg(net_arg_remote_port_, Variadic::Integer(evt.remote_port()));
211         extra_args(i);
212       });
213 }
214 
ParseNetworkPacketEvent(int64_t ts,ConstBytes blob)215 void NetworkTraceModule::ParseNetworkPacketEvent(int64_t ts, ConstBytes blob) {
216   NetworkPacketEvent::Decoder event(blob);
217   ParseGenericEvent(ts, /*dur=*/0, event, [&](ArgsTracker::BoundInserter* i) {
218     i->AddArg(net_arg_length_, Variadic::Integer(event.length()));
219   });
220 }
221 
ParseNetworkPacketBundle(int64_t ts,ConstBytes blob)222 void NetworkTraceModule::ParseNetworkPacketBundle(int64_t ts, ConstBytes blob) {
223   NetworkPacketBundle::Decoder event(blob);
224   NetworkPacketEvent::Decoder ctx(event.ctx());
225   int64_t dur = static_cast<int64_t>(event.total_duration());
226 
227   // Any bundle that makes it through tokenization must be aggregated bundles
228   // with total packets/total length.
229   ParseGenericEvent(ts, dur, ctx, [&](ArgsTracker::BoundInserter* i) {
230     i->AddArg(net_arg_length_, Variadic::UnsignedInteger(event.total_length()));
231     i->AddArg(packet_count_, Variadic::UnsignedInteger(event.total_packets()));
232   });
233 }
234 
PushPacketBufferForSort(int64_t timestamp,PacketSequenceState * state)235 void NetworkTraceModule::PushPacketBufferForSort(int64_t timestamp,
236                                                  PacketSequenceState* state) {
237   std::vector<uint8_t> v = packet_buffer_.SerializeAsArray();
238   context_->sorter->PushTracePacket(
239       timestamp, state->current_generation(),
240       TraceBlobView(TraceBlob::CopyFrom(v.data(), v.size())));
241   packet_buffer_.Reset();
242 }
243 
244 }  // namespace trace_processor
245 }  // namespace perfetto
246