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