• 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 // Block size for copying buffers (for compression/encoding etc.)
39 static const size_t BLOCK_SIZE = 16384;
40 
41 // Maximum line length in bugreport (should be multiple of 4 for base64 output)
42 static const uint8_t MAX_LINE_LENGTH = 128;
43 
44 static std::mutex buffer_mutex;
45 static ringbuffer_t* buffer = NULL;
46 static uint64_t last_timestamp_ms = 0;
47 
48 static size_t btsnoop_calculate_packet_length(uint16_t type,
49                                               const uint8_t* data,
50                                               size_t length);
51 
btsnoop_cb(const uint16_t type,const uint8_t * data,const size_t length,const uint64_t timestamp_us)52 static void btsnoop_cb(const uint16_t type, const uint8_t* data,
53                        const size_t length, const uint64_t timestamp_us) {
54   btsnooz_header_t header;
55 
56   size_t included_length = btsnoop_calculate_packet_length(type, data, length);
57   if (included_length == 0) return;
58 
59   std::lock_guard<std::mutex> lock(buffer_mutex);
60 
61   // Make room in the ring buffer
62 
63   while (ringbuffer_available(buffer) <
64          (included_length + sizeof(btsnooz_header_t))) {
65     ringbuffer_pop(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
66     ringbuffer_delete(buffer, header.length - 1);
67   }
68 
69   // Insert data
70   header.type = REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type);
71   header.length = included_length + 1;  // +1 for type byte
72   header.packet_length = length + 1;    // +1 for type byte.
73   header.delta_time_ms =
74       last_timestamp_ms ? timestamp_us - last_timestamp_ms : 0;
75   last_timestamp_ms = timestamp_us;
76 
77   ringbuffer_insert(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
78   ringbuffer_insert(buffer, data, included_length);
79 }
80 
btsnoop_calculate_packet_length(uint16_t type,const uint8_t * data,size_t length)81 static size_t btsnoop_calculate_packet_length(uint16_t type,
82                                               const uint8_t* data,
83                                               size_t length) {
84   static const size_t HCI_ACL_HEADER_SIZE = 4;
85   static const size_t L2CAP_HEADER_SIZE = 4;
86   static const size_t L2CAP_CID_OFFSET = (HCI_ACL_HEADER_SIZE + 2);
87   static const uint16_t L2CAP_SIGNALING_CID = 0x0001;
88 
89   // Maximum amount of ACL data to log.
90   // Enough for an RFCOMM frame up to the frame check;
91   // not enough for a HID report or audio data.
92   static const size_t MAX_HCI_ACL_LEN = 14;
93 
94   // Calculate packet length to be included
95 
96   switch (type) {
97     case BT_EVT_TO_LM_HCI_CMD:
98       return length;
99 
100     case BT_EVT_TO_BTU_HCI_EVT:
101       return length;
102 
103     case BT_EVT_TO_LM_HCI_ACL:
104     case BT_EVT_TO_BTU_HCI_ACL: {
105       size_t len_hci_acl = HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE;
106       // Check if we have enough data for an L2CAP header
107       if (length > len_hci_acl) {
108         uint16_t l2cap_cid =
109             data[L2CAP_CID_OFFSET] | (data[L2CAP_CID_OFFSET + 1] << 8);
110         if (l2cap_cid == L2CAP_SIGNALING_CID) {
111           // For the signaling CID, take the full packet.
112           // That way, the PSM setup is captured, allowing decoding of PSMs down
113           // the road.
114           return length;
115         } else {
116           // Otherwise, return as much as we reasonably can
117           len_hci_acl = MAX_HCI_ACL_LEN;
118         }
119       }
120       return len_hci_acl < length ? len_hci_acl : length;
121     }
122 
123     case BT_EVT_TO_LM_HCI_SCO:
124     case BT_EVT_TO_BTU_HCI_SCO:
125       // We're not logging SCO packets at this time since they are not currently
126       // used.
127       FALLTHROUGH_INTENDED; /* FALLTHROUGH */
128     default:
129       return 0;
130   }
131 }
132 
btsnoop_compress(ringbuffer_t * rb_dst,ringbuffer_t * rb_src)133 static bool btsnoop_compress(ringbuffer_t* rb_dst, ringbuffer_t* rb_src) {
134   CHECK(rb_dst != NULL);
135   CHECK(rb_src != NULL);
136 
137   z_stream zs;
138   zs.zalloc = Z_NULL;
139   zs.zfree = Z_NULL;
140   zs.opaque = Z_NULL;
141 
142   if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return false;
143 
144   bool rc = true;
145   uint8_t block_src[BLOCK_SIZE];
146   uint8_t block_dst[BLOCK_SIZE];
147 
148   const size_t num_blocks =
149       (ringbuffer_size(rb_src) + BLOCK_SIZE - 1) / BLOCK_SIZE;
150   for (size_t i = 0; i < num_blocks; ++i) {
151     zs.avail_in =
152         ringbuffer_peek(rb_src, i * BLOCK_SIZE, block_src, BLOCK_SIZE);
153     zs.next_in = block_src;
154 
155     do {
156       zs.avail_out = BLOCK_SIZE;
157       zs.next_out = block_dst;
158 
159       int err = deflate(&zs, (i == num_blocks - 1) ? Z_FINISH : Z_NO_FLUSH);
160       if (err == Z_STREAM_ERROR) {
161         rc = false;
162         break;
163       }
164 
165       const size_t length = BLOCK_SIZE - zs.avail_out;
166       ringbuffer_insert(rb_dst, block_dst, length);
167     } while (zs.avail_out == 0);
168   }
169 
170   deflateEnd(&zs);
171   return rc;
172 }
173 
btif_debug_btsnoop_init(void)174 void btif_debug_btsnoop_init(void) {
175   if (buffer == NULL) buffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
176   btsnoop_mem_set_callback(btsnoop_cb);
177 }
178 
btif_debug_btsnoop_dump(int fd)179 void btif_debug_btsnoop_dump(int fd) {
180   ringbuffer_t* ringbuffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
181   if (ringbuffer == NULL) {
182     dprintf(fd, "%s Unable to allocate memory for compression", __func__);
183     return;
184   }
185 
186   // Prepend preamble
187 
188   btsnooz_preamble_t preamble;
189   preamble.version = BTSNOOZ_CURRENT_VERSION;
190   preamble.last_timestamp_ms = last_timestamp_ms;
191   ringbuffer_insert(ringbuffer, (uint8_t*)&preamble,
192                     sizeof(btsnooz_preamble_t));
193 
194   // Compress data
195 
196   uint8_t b64_in[3] = {0};
197   char b64_out[5] = {0};
198 
199   size_t line_length = 0;
200 
201   bool rc;
202   {
203     std::lock_guard<std::mutex> lock(buffer_mutex);
204     dprintf(fd, "--- BEGIN:BTSNOOP_LOG_SUMMARY (%zu bytes in) ---\n",
205             ringbuffer_size(buffer));
206     rc = btsnoop_compress(ringbuffer, buffer);
207   }
208 
209   if (!rc) {
210     dprintf(fd, "%s Log compression failed", __func__);
211     goto error;
212   }
213 
214   // Base64 encode & output
215 
216   while (ringbuffer_size(ringbuffer) > 0) {
217     size_t read = ringbuffer_pop(ringbuffer, b64_in, 3);
218     if (line_length >= MAX_LINE_LENGTH) {
219       dprintf(fd, "\n");
220       line_length = 0;
221     }
222     line_length += b64_ntop(b64_in, read, b64_out, 5);
223     dprintf(fd, "%s", b64_out);
224   }
225 
226   dprintf(fd, "\n--- END:BTSNOOP_LOG_SUMMARY ---\n");
227 
228 error:
229   ringbuffer_free(ringbuffer);
230 }
231