1 /******************************************************************************
2 *
3 * Copyright 2015 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <mutex>
20
21 #include <base/logging.h>
22 #include <resolv.h>
23 #include <zlib.h>
24
25 #include "btif/include/btif_debug.h"
26 #include "btif/include/btif_debug_btsnoop.h"
27 #include "hci/include/btsnoop_mem.h"
28 #include "internal_include/bt_target.h"
29 #include "osi/include/ringbuffer.h"
30
31 #define REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type) ((type) >> 8)
32
33 // Total btsnoop memory log buffer size
34 #ifndef BTSNOOP_MEM_BUFFER_SIZE
35 static const size_t BTSNOOP_MEM_BUFFER_SIZE = (256 * 1024);
36 #endif
37
38 static std::mutex buffer_mutex;
39 static ringbuffer_t* buffer = NULL;
40 static uint64_t last_timestamp_ms = 0;
41
42 static size_t btsnoop_calculate_packet_length(uint16_t type,
43 const uint8_t* data,
44 size_t length);
45
btsnoop_cb(const uint16_t type,const uint8_t * data,const size_t length,const uint64_t timestamp_us)46 static void btsnoop_cb(const uint16_t type, const uint8_t* data,
47 const size_t length, const uint64_t timestamp_us) {
48 btsnooz_header_t header;
49
50 size_t included_length = btsnoop_calculate_packet_length(type, data, length);
51 if (included_length == 0) return;
52
53 std::lock_guard<std::mutex> lock(buffer_mutex);
54
55 // Make room in the ring buffer
56
57 while (ringbuffer_available(buffer) <
58 (included_length + sizeof(btsnooz_header_t))) {
59 ringbuffer_pop(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
60 ringbuffer_delete(buffer, header.length - 1);
61 }
62
63 // Insert data
64 header.type = REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type);
65 header.length = included_length + 1; // +1 for type byte
66 header.packet_length = length + 1; // +1 for type byte.
67 header.delta_time_ms =
68 last_timestamp_ms ? timestamp_us - last_timestamp_ms : 0;
69 last_timestamp_ms = timestamp_us;
70
71 ringbuffer_insert(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
72 ringbuffer_insert(buffer, data, included_length);
73 }
74
btsnoop_calculate_packet_length(uint16_t type,const uint8_t * data,size_t length)75 static size_t btsnoop_calculate_packet_length(uint16_t type,
76 const uint8_t* data,
77 size_t length) {
78 static const size_t HCI_ACL_HEADER_SIZE = 4;
79 static const size_t L2CAP_HEADER_SIZE = 4;
80 static const size_t L2CAP_CID_OFFSET = (HCI_ACL_HEADER_SIZE + 2);
81 static const uint16_t L2CAP_SIGNALING_CID = 0x0001;
82
83 // Maximum amount of ACL data to log.
84 // Enough for an RFCOMM frame up to the frame check;
85 // not enough for a HID report or audio data.
86 static const size_t MAX_HCI_ACL_LEN = 14;
87
88 // Calculate packet length to be included
89
90 switch (type) {
91 case BT_EVT_TO_LM_HCI_CMD:
92 return length;
93
94 case BT_EVT_TO_BTU_HCI_EVT:
95 return length;
96
97 case BT_EVT_TO_LM_HCI_ACL:
98 case BT_EVT_TO_BTU_HCI_ACL: {
99 size_t len_hci_acl = HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE;
100 // Check if we have enough data for an L2CAP header
101 if (length > len_hci_acl) {
102 uint16_t l2cap_cid =
103 data[L2CAP_CID_OFFSET] | (data[L2CAP_CID_OFFSET + 1] << 8);
104 if (l2cap_cid == L2CAP_SIGNALING_CID) {
105 // For the signaling CID, take the full packet.
106 // That way, the PSM setup is captured, allowing decoding of PSMs down
107 // the road.
108 return length;
109 } else {
110 // Otherwise, return as much as we reasonably can
111 len_hci_acl = MAX_HCI_ACL_LEN;
112 }
113 }
114 return len_hci_acl < length ? len_hci_acl : length;
115 }
116
117 case BT_EVT_TO_LM_HCI_ISO:
118 case BT_EVT_TO_BTU_HCI_ISO:
119 return length;
120
121 case BT_EVT_TO_LM_HCI_SCO:
122 case BT_EVT_TO_BTU_HCI_SCO:
123 // We're not logging SCO packets at this time since they are not currently
124 // used.
125 FALLTHROUGH_INTENDED; /* FALLTHROUGH */
126 default:
127 return 0;
128 }
129 }
130
btif_debug_btsnoop_init(void)131 void btif_debug_btsnoop_init(void) {
132 if (buffer == NULL) buffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
133 btsnoop_mem_set_callback(btsnoop_cb);
134 }
135
136 #ifndef OS_ANDROID
btif_debug_btsnoop_dump(int fd)137 void btif_debug_btsnoop_dump(int fd) {}
138 #else
139
140 // Block size for copying buffers (for compression/encoding etc.)
141 static constexpr size_t BLOCK_SIZE = 16384;
142
btsnoop_compress(ringbuffer_t * rb_dst,ringbuffer_t * rb_src)143 static bool btsnoop_compress(ringbuffer_t* rb_dst, ringbuffer_t* rb_src) {
144 CHECK(rb_dst != NULL);
145 CHECK(rb_src != NULL);
146
147 z_stream zs;
148 zs.zalloc = Z_NULL;
149 zs.zfree = Z_NULL;
150 zs.opaque = Z_NULL;
151
152 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return false;
153
154 bool rc = true;
155 uint8_t block_src[BLOCK_SIZE];
156 uint8_t block_dst[BLOCK_SIZE];
157
158 const size_t num_blocks =
159 (ringbuffer_size(rb_src) + BLOCK_SIZE - 1) / BLOCK_SIZE;
160 for (size_t i = 0; i < num_blocks; ++i) {
161 zs.avail_in =
162 ringbuffer_peek(rb_src, i * BLOCK_SIZE, block_src, BLOCK_SIZE);
163 zs.next_in = block_src;
164
165 do {
166 zs.avail_out = BLOCK_SIZE;
167 zs.next_out = block_dst;
168
169 int err = deflate(&zs, (i == num_blocks - 1) ? Z_FINISH : Z_NO_FLUSH);
170 if (err == Z_STREAM_ERROR) {
171 rc = false;
172 break;
173 }
174
175 const size_t length = BLOCK_SIZE - zs.avail_out;
176 ringbuffer_insert(rb_dst, block_dst, length);
177 } while (zs.avail_out == 0);
178 }
179
180 deflateEnd(&zs);
181 return rc;
182 }
183
btif_debug_btsnoop_dump(int fd)184 void btif_debug_btsnoop_dump(int fd) {
185 ringbuffer_t* ringbuffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
186 if (ringbuffer == NULL) {
187 dprintf(fd, "%s Unable to allocate memory for compression", __func__);
188 return;
189 }
190
191 // Prepend preamble
192
193 btsnooz_preamble_t preamble;
194 preamble.version = BTSNOOZ_CURRENT_VERSION;
195 preamble.last_timestamp_ms = last_timestamp_ms;
196 ringbuffer_insert(ringbuffer, (uint8_t*)&preamble,
197 sizeof(btsnooz_preamble_t));
198
199 // Compress data
200
201 uint8_t b64_in[3] = {0};
202 char b64_out[5] = {0};
203
204 size_t line_length = 0;
205
206 bool rc;
207 {
208 std::lock_guard<std::mutex> lock(buffer_mutex);
209 dprintf(fd, "--- BEGIN:BTSNOOP_LOG_SUMMARY (%zu bytes in) ---\n",
210 ringbuffer_size(buffer));
211 rc = btsnoop_compress(ringbuffer, buffer);
212 }
213
214 if (!rc) {
215 dprintf(fd, "%s Log compression failed", __func__);
216 goto error;
217 }
218
219 // Base64 encode & output
220
221 while (ringbuffer_size(ringbuffer) > 0) {
222 size_t read = ringbuffer_pop(ringbuffer, b64_in, 3);
223 // Maximum line length in bugreport (should be multiple of 4 for base64
224 // output)
225 constexpr uint8_t MAX_LINE_LENGTH = 128;
226 if (line_length >= MAX_LINE_LENGTH) {
227 dprintf(fd, "\n");
228 line_length = 0;
229 }
230 line_length += b64_ntop(b64_in, read, b64_out, 5);
231 dprintf(fd, "%s", b64_out);
232 }
233
234 dprintf(fd, "\n--- END:BTSNOOP_LOG_SUMMARY ---\n");
235
236 error:
237 ringbuffer_free(ringbuffer);
238 }
239 #endif
240