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