1 /*
2 * Copyright (C) 2025 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 #ifdef __ANDROID__
18 #include "hal/snoop_logger_tracing.h"
19
20 #include <bluetooth/log.h>
21 #include <perfetto/trace/android/bluetooth_trace.pbzero.h>
22 #include <perfetto/tracing.h>
23
24 #include "hal/snoop_logger.h"
25 #include "hci/hci_packets.h"
26
27 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(bluetooth::hal::SnoopLoggerTracing);
28
29 using perfetto::protos::pbzero::BluetoothTracePacketType;
30
31 namespace bluetooth {
32 namespace hal {
33 namespace {
34
35 // The Perfetto trace flush interval in nanoseconds.
36 constexpr uint64_t TRACE_FLUSH_INTERVAL_NANOS = 100 * 1000 * 1000;
37
SkipTracePoint(const HciPacket & packet,SnoopLogger::PacketType type)38 static bool SkipTracePoint(const HciPacket& packet, SnoopLogger::PacketType type) {
39 if (type == SnoopLogger::PacketType::EVT) {
40 uint8_t evt_code = packet[0];
41
42 // Below set of commands does not provide further insight into bluetooth
43 // behavior. Skip these to save bluetooth tracing from becoming too large.
44 return evt_code == static_cast<uint8_t>(hci::EventCode::NUMBER_OF_COMPLETED_PACKETS) ||
45 evt_code == static_cast<uint8_t>(hci::EventCode::COMMAND_COMPLETE) ||
46 evt_code == static_cast<uint8_t>(hci::EventCode::COMMAND_STATUS);
47 }
48
49 return false;
50 }
51 } // namespace
52
BundleKey(const HciPacket & packet,SnoopLogger::Direction direction,SnoopLogger::PacketType type)53 BundleKey::BundleKey(const HciPacket& packet, SnoopLogger::Direction direction,
54 SnoopLogger::PacketType type)
55 : packet_type(type), direction(direction) {
56 switch (type) {
57 case SnoopLogger::PacketType::EVT: {
58 event_code = packet[0];
59
60 if (event_code == static_cast<uint8_t>(hci::EventCode::LE_META_EVENT) ||
61 event_code == static_cast<uint8_t>(hci::EventCode::VENDOR_SPECIFIC)) {
62 subevent_code = packet[2];
63 }
64 } break;
65 case SnoopLogger::PacketType::CMD: {
66 op_code = packet[0] | (packet[1] << 8);
67 } break;
68 case SnoopLogger::PacketType::ACL:
69 case SnoopLogger::PacketType::ISO:
70 case SnoopLogger::PacketType::SCO: {
71 handle = (packet[0] | (packet[1] << 8)) & 0x0fff;
72 } break;
73 }
74 }
75
76 #define AGG_FIELDS(x) \
77 (x).packet_type, (x).direction, (x).event_code, (x).subevent_code, (x).op_code, (x).handle
78
operator ==(const BundleKey & b) const79 bool BundleKey::operator==(const BundleKey& b) const {
80 return std::tie(AGG_FIELDS(*this)) == std::tie(AGG_FIELDS(b));
81 }
82
83 template <typename T, typename... Rest>
HashCombine(std::size_t & seed,const T & val,const Rest &...rest)84 void HashCombine(std::size_t& seed, const T& val, const Rest&... rest) {
85 seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
86 (HashCombine(seed, rest), ...);
87 }
88
operator ()(const BundleKey & a) const89 std::size_t BundleHash::operator()(const BundleKey& a) const {
90 std::size_t seed = 0;
91 HashCombine(seed, AGG_FIELDS(a));
92 return seed;
93 }
94
95 #undef AGG_FIELDS
96
InitializePerfetto()97 void SnoopLoggerTracing::InitializePerfetto() {
98 perfetto::TracingInitArgs args;
99 args.backends |= perfetto::kSystemBackend;
100
101 perfetto::Tracing::Initialize(args);
102 perfetto::DataSourceDescriptor dsd;
103 dsd.set_name("android.bluetooth_tracing");
104 SnoopLoggerTracing::Register(dsd);
105 }
106
HciToTracePacketType(SnoopLogger::PacketType hci_packet_type,SnoopLogger::Direction direction)107 BluetoothTracePacketType SnoopLoggerTracing::HciToTracePacketType(
108 SnoopLogger::PacketType hci_packet_type, SnoopLogger::Direction direction) {
109 BluetoothTracePacketType trace_packet_type;
110 switch (hci_packet_type) {
111 case SnoopLogger::PacketType::CMD: {
112 trace_packet_type = BluetoothTracePacketType::HCI_CMD;
113 } break;
114 case SnoopLogger::PacketType::EVT: {
115 trace_packet_type = BluetoothTracePacketType::HCI_EVT;
116 } break;
117 case SnoopLogger::PacketType::ACL: {
118 if (direction == SnoopLogger::INCOMING) {
119 trace_packet_type = BluetoothTracePacketType::HCI_ACL_RX;
120 } else {
121 trace_packet_type = BluetoothTracePacketType::HCI_ACL_TX;
122 }
123 } break;
124 case SnoopLogger::PacketType::ISO: {
125 if (direction == SnoopLogger::INCOMING) {
126 trace_packet_type = BluetoothTracePacketType::HCI_ISO_RX;
127 } else {
128 trace_packet_type = BluetoothTracePacketType::HCI_ISO_TX;
129 }
130 } break;
131 case SnoopLogger::PacketType::SCO: {
132 if (direction == SnoopLogger::INCOMING) {
133 trace_packet_type = BluetoothTracePacketType::HCI_SCO_RX;
134 } else {
135 trace_packet_type = BluetoothTracePacketType::HCI_SCO_TX;
136 }
137 } break;
138 }
139 return trace_packet_type;
140 }
141
TracePacket(const HciPacket & packet,SnoopLogger::Direction direction,SnoopLogger::PacketType type)142 void SnoopLoggerTracing::TracePacket(const HciPacket& packet, SnoopLogger::Direction direction,
143 SnoopLogger::PacketType type) {
144 if (SkipTracePoint(packet, type)) {
145 return;
146 }
147
148 SnoopLoggerTracing::Trace([&](SnoopLoggerTracing::TraceContext ctx) {
149 perfetto::LockedHandle<SnoopLoggerTracing> handle = ctx.GetDataSourceLocked();
150 if (handle.valid()) {
151 handle->Record(ctx, packet, direction, type);
152 }
153 });
154 }
155
Record(TraceContext & ctx,const HciPacket & packet,SnoopLogger::Direction direction,SnoopLogger::PacketType type)156 void SnoopLoggerTracing::Record(TraceContext& ctx, const HciPacket& packet,
157 SnoopLogger::Direction direction, SnoopLogger::PacketType type) {
158 // Write pending events before saving the new one to the bundle. Not doing this
159 // includes the new event after a potentially long gap, leading to a bundle with
160 // a very long duration.
161 uint64_t timestamp_ns = perfetto::base::GetBootTimeNs().count();
162 if (last_flush_ns_ + TRACE_FLUSH_INTERVAL_NANOS < timestamp_ns) {
163 for (const auto& [key, details] : bttrace_bundles_) {
164 Write(ctx, key, details);
165 }
166
167 bttrace_bundles_.clear();
168 last_flush_ns_ = timestamp_ns;
169 }
170
171 BundleKey key(packet, direction, type);
172
173 BundleDetails& bundle = bttrace_bundles_[key];
174 bundle.count++;
175 bundle.total_length += packet.size();
176 bundle.start_ts = std::min(bundle.start_ts, timestamp_ns);
177 bundle.end_ts = std::max(bundle.end_ts, timestamp_ns);
178 }
179
Write(TraceContext & ctx,const BundleKey & key,const BundleDetails & details)180 void SnoopLoggerTracing::Write(TraceContext& ctx, const BundleKey& key,
181 const BundleDetails& details) {
182 auto trace_pkt = ctx.NewTracePacket();
183 trace_pkt->set_timestamp(details.start_ts);
184 auto* bt_event = trace_pkt->set_bluetooth_trace_event();
185 bt_event->set_packet_type(HciToTracePacketType(key.packet_type, key.direction));
186 bt_event->set_count(details.count);
187 bt_event->set_length(details.total_length);
188 bt_event->set_duration(details.end_ts - details.start_ts);
189 if (key.op_code.has_value()) {
190 bt_event->set_op_code(*key.op_code);
191 }
192 if (key.event_code.has_value()) {
193 bt_event->set_event_code(*key.event_code);
194 }
195 if (key.subevent_code.has_value()) {
196 bt_event->set_subevent_code(*key.subevent_code);
197 }
198 if (key.handle.has_value()) {
199 bt_event->set_connection_handle(*key.handle);
200 }
201 }
202
OnSetup(const SetupArgs &)203 void SnoopLoggerTracing::OnSetup(const SetupArgs&) {}
OnStart(const StartArgs &)204 void SnoopLoggerTracing::OnStart(const StartArgs&) {}
OnStop(const StopArgs &)205 void SnoopLoggerTracing::OnStop(const StopArgs&) {}
OnFlush(const FlushArgs &)206 void SnoopLoggerTracing::OnFlush(const FlushArgs&) {}
207
208 } // namespace hal
209 } // namespace bluetooth
210 #endif // __ANDROID__
211