blob: 88c37f78342064d0c0872bcccf61c9c6856d90fd [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
Zach Johnson9891f322014-09-22 22:11:55 -07003 * Copyright (C) 2014 Google, Inc.
The Android Open Source Project5738f832012-12-12 16:00:35 -08004 *
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
Marie Janssen985d4b62015-07-07 16:47:20 -070019#define LOG_TAG "bt_snoop"
20
Etan Cohen3e59b5b2015-03-31 17:15:53 -070021#include <arpa/inet.h>
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070022#include <assert.h>
Matadeen Mishraaab3e112014-11-14 19:46:19 +053023#include <cutils/properties.h>
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070024#include <errno.h>
25#include <fcntl.h>
Pavlin Radoslavov12265e32016-02-13 08:47:19 -080026#include <inttypes.h>
Scott James Remnant933926c2015-04-02 15:22:14 -070027#include <limits.h>
28#include <netinet/in.h>
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070029#include <stdbool.h>
30#include <stdio.h>
31#include <stdlib.h>
Etan Cohen3e59b5b2015-03-31 17:15:53 -070032#include <string.h>
Matadeen Mishraaab3e112014-11-14 19:46:19 +053033#include <time.h>
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070034#include <sys/stat.h>
35#include <sys/time.h>
Matadeen Mishraaab3e112014-11-14 19:46:19 +053036#include <sys/poll.h>
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070037#include <unistd.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080038
Marie Janssendb554582015-06-26 14:53:46 -070039#include "bt_types.h"
Andre Eisenbach89f5e412014-12-05 09:40:20 -080040#include "hci/include/btsnoop.h"
41#include "hci/include/btsnoop_mem.h"
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070042#include "hci_layer.h"
Sharvil Nanavati44802762014-12-23 23:08:58 -080043#include "osi/include/log.h"
Zach Johnson9891f322014-09-22 22:11:55 -070044#include "stack_config.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080045
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070046typedef enum {
47 kCommandPacket = 1,
48 kAclPacket = 2,
49 kScoPacket = 3,
50 kEventPacket = 4
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070051} packet_type_t;
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070052
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070053// Epoch in microseconds since 01/01/0000.
54static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
55
Zach Johnson9891f322014-09-22 22:11:55 -070056static const stack_config_t *stack_config;
Matadeen Mishraaab3e112014-11-14 19:46:19 +053057extern int client_socket_btsnoop;
58static long int gmt_offset;
59#define USEC_PER_SEC 1000000L
60#define MAX_SNOOP_BUF_SIZE 1200
61
62// External BT snoop
63bool hci_ext_dump_enabled = false;
64
65/* snoop config from the config file, required for userdebug
66 build where snoop is enabled by default.
67 power/perf measurements need the snoop to be disabled.
68*/
69bool btsnoop_conf_from_file = false;
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070070
Zach Johnson9891f322014-09-22 22:11:55 -070071static int logfile_fd = INVALID_FD;
72static bool module_started;
73static bool is_logging;
74static bool logging_enabled_via_api;
75
76// TODO(zachoverflow): merge btsnoop and btsnoop_net together
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070077void btsnoop_net_open();
78void btsnoop_net_close();
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070079void btsnoop_net_write(const void *data, size_t length);
Kim Schulzf1d68e92013-09-23 12:48:47 +020080
Zach Johnson9891f322014-09-22 22:11:55 -070081static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received);
82static void update_logging();
83
84// Module lifecycle functions
85
86static future_t *start_up(void) {
Matadeen Mishraaab3e112014-11-14 19:46:19 +053087 time_t t = time(NULL);
88 struct tm tm_cur;
89
90 localtime_r (&t, &tm_cur);
91 LOG_INFO(LOG_TAG, "%s Time GMT offset %ld\n", __func__, tm_cur.tm_gmtoff);
92 gmt_offset = tm_cur.tm_gmtoff;
93
Zach Johnson9891f322014-09-22 22:11:55 -070094 module_started = true;
Matadeen Mishraaab3e112014-11-14 19:46:19 +053095 stack_config->get_btsnoop_ext_options(&hci_ext_dump_enabled, &btsnoop_conf_from_file);
Gurpreet Ghai842fd8c2017-02-05 20:11:03 +053096#ifdef BLUEDROID_DEBUG
Matadeen Mishraaab3e112014-11-14 19:46:19 +053097 if (btsnoop_conf_from_file == false) {
98 hci_ext_dump_enabled = true;
99 }
Gurpreet Ghai842fd8c2017-02-05 20:11:03 +0530100#endif
Zach Johnson9891f322014-09-22 22:11:55 -0700101 update_logging();
102
103 return NULL;
104}
105
106static future_t *shut_down(void) {
107 module_started = false;
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530108 if (hci_ext_dump_enabled == true) {
Gurpreet Ghaib7998a42016-10-10 11:41:05 +0530109 STOP_SNOOP_LOGGING();
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530110 }
Zach Johnson9891f322014-09-22 22:11:55 -0700111 update_logging();
112
113 return NULL;
114}
115
Ian Coolidge1f81b642015-04-21 16:25:08 -0700116EXPORT_SYMBOL const module_t btsnoop_module = {
Zach Johnson9891f322014-09-22 22:11:55 -0700117 .name = BTSNOOP_MODULE,
118 .init = NULL,
119 .start_up = start_up,
120 .shut_down = shut_down,
121 .clean_up = NULL,
122 .dependencies = {
123 STACK_CONFIG_MODULE,
124 NULL
125 }
126};
127
128// Interface functions
129
130static void set_api_wants_to_log(bool value) {
131 logging_enabled_via_api = value;
132 update_logging();
133}
134
135static void capture(const BT_HDR *buffer, bool is_received) {
136 const uint8_t *p = buffer->data + buffer->offset;
137
Andre Eisenbach89f5e412014-12-05 09:40:20 -0800138 btsnoop_mem_capture(buffer);
139
Zach Johnson9891f322014-09-22 22:11:55 -0700140 if (logfile_fd == INVALID_FD)
141 return;
142
143 switch (buffer->event & MSG_EVT_MASK) {
144 case MSG_HC_TO_STACK_HCI_EVT:
145 btsnoop_write_packet(kEventPacket, p, false);
146 break;
147 case MSG_HC_TO_STACK_HCI_ACL:
148 case MSG_STACK_TO_HC_HCI_ACL:
149 btsnoop_write_packet(kAclPacket, p, is_received);
150 break;
151 case MSG_HC_TO_STACK_HCI_SCO:
152 case MSG_STACK_TO_HC_HCI_SCO:
153 btsnoop_write_packet(kScoPacket, p, is_received);
154 break;
155 case MSG_STACK_TO_HC_HCI_CMD:
156 btsnoop_write_packet(kCommandPacket, p, true);
157 break;
158 }
159}
160
161static const btsnoop_t interface = {
162 set_api_wants_to_log,
163 capture
164};
165
166const btsnoop_t *btsnoop_get_interface() {
167 stack_config = stack_config_get_interface();
168 return &interface;
169}
170
171// Internal functions
172
Tucker Sylvestro1192df92015-07-06 19:29:06 -0400173static uint64_t btsnoop_timestamp(void) {
174 struct timeval tv;
175 gettimeofday(&tv, NULL);
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530176 tv.tv_sec += gmt_offset;
Tucker Sylvestro1192df92015-07-06 19:29:06 -0400177
178 // Timestamp is in microseconds.
zhenchao13e7a892016-12-01 17:43:43 +0800179 uint64_t timestamp = ((uint64_t)tv.tv_sec) * 1000 * 1000LL;
Tucker Sylvestro1192df92015-07-06 19:29:06 -0400180 timestamp += tv.tv_usec;
181 timestamp += BTSNOOP_EPOCH_DELTA;
182 return timestamp;
183}
184
Zach Johnson9891f322014-09-22 22:11:55 -0700185static void update_logging() {
Gurpreet Ghai842fd8c2017-02-05 20:11:03 +0530186 bool btsnoop_log_output = stack_config->get_btsnoop_turned_on();
Zach Johnson9891f322014-09-22 22:11:55 -0700187 bool should_log = module_started &&
Gurpreet Ghai842fd8c2017-02-05 20:11:03 +0530188 (logging_enabled_via_api || btsnoop_log_output || hci_ext_dump_enabled);
Zach Johnson9891f322014-09-22 22:11:55 -0700189
190 if (should_log == is_logging)
191 return;
192
193 is_logging = should_log;
194 if (should_log) {
195 btsnoop_net_open();
Gurpreet Ghai842fd8c2017-02-05 20:11:03 +0530196#ifdef BLUEDROID_DEBUG
197 if(!btsnoop_log_output)
198#endif
199 {
200 if (logging_enabled_via_api || hci_ext_dump_enabled == true) {
201 START_SNOOP_LOGGING();
202 }
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530203 }
Gurpreet Ghai842fd8c2017-02-05 20:11:03 +0530204
Zach Johnson04bb2362015-03-04 14:06:13 -0800205 const char *log_path = stack_config->get_btsnoop_log_path();
Zach Johnson9891f322014-09-22 22:11:55 -0700206
Zach Johnson04bb2362015-03-04 14:06:13 -0800207 // Save the old log if configured to do so
208 if (stack_config->get_btsnoop_should_save_last()) {
209 char last_log_path[PATH_MAX];
Pavlin Radoslavov12265e32016-02-13 08:47:19 -0800210 snprintf(last_log_path, PATH_MAX, "%s.%" PRIu64, log_path,
211 btsnoop_timestamp());
Zach Johnson04bb2362015-03-04 14:06:13 -0800212 if (!rename(log_path, last_log_path) && errno != ENOENT)
Marie Janssendb554582015-06-26 14:53:46 -0700213 LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, log_path, last_log_path, strerror(errno));
Zach Johnson04bb2362015-03-04 14:06:13 -0800214 }
215
Ajay Panickera5124752016-09-14 11:46:23 -0700216 mode_t prevmask = umask(0);
Zach Johnson04bb2362015-03-04 14:06:13 -0800217 logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
Zach Johnson9891f322014-09-22 22:11:55 -0700218 if (logfile_fd == INVALID_FD) {
Marie Janssendb554582015-06-26 14:53:46 -0700219 LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path, strerror(errno));
Zach Johnson04bb2362015-03-04 14:06:13 -0800220 is_logging = false;
Ajay Panickera5124752016-09-14 11:46:23 -0700221 umask(prevmask);
Zach Johnson9891f322014-09-22 22:11:55 -0700222 return;
223 }
Ajay Panickera5124752016-09-14 11:46:23 -0700224 umask(prevmask);
Zach Johnson9891f322014-09-22 22:11:55 -0700225
226 write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
227 } else {
228 if (logfile_fd != INVALID_FD)
229 close(logfile_fd);
230
231 logfile_fd = INVALID_FD;
232 btsnoop_net_close();
233 }
234}
235
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -0700236static void btsnoop_write(const void *data, size_t length) {
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530237 if (client_socket_btsnoop != -1) {
238 btsnoop_net_write(data, length);
239 /* skip writing to file if external client is connected*/
240 return;
241 }
242
Zach Johnson9891f322014-09-22 22:11:55 -0700243 if (logfile_fd != INVALID_FD)
244 write(logfile_fd, data, length);
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -0700245}
Kim Schulzf1d68e92013-09-23 12:48:47 +0200246
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530247#ifdef DEBUG_SNOOP
248static uint64_t time_now_us() {
249 struct timespec ts_now;
250 clock_gettime(CLOCK_BOOTTIME, &ts_now);
251 return ((uint64_t)ts_now.tv_sec * USEC_PER_SEC) + ((uint64_t)ts_now.tv_nsec / 1000);
252}
253#endif
254
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -0700255static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) {
Chris Manton227f6b02014-07-18 13:41:32 -0700256 int length_he = 0;
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -0700257 int length;
258 int flags;
259 int drops = 0;
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530260 struct pollfd pfd;
261#ifdef DEBUG_SNOOP
262 uint64_t ts_begin;
263 uint64_t ts_end, ts_diff;
264#endif
265 uint8_t snoop_buf[MAX_SNOOP_BUF_SIZE] = {0};
266 uint32_t offset = 0;
267
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -0700268 switch (type) {
269 case kCommandPacket:
270 length_he = packet[2] + 4;
271 flags = 2;
272 break;
273 case kAclPacket:
274 length_he = (packet[3] << 8) + packet[2] + 5;
275 flags = is_received;
276 break;
277 case kScoPacket:
278 length_he = packet[2] + 4;
279 flags = is_received;
280 break;
281 case kEventPacket:
282 length_he = packet[1] + 3;
283 flags = 3;
284 break;
285 }
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -0700286
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -0700287 uint64_t timestamp = btsnoop_timestamp();
288 uint32_t time_hi = timestamp >> 32;
289 uint32_t time_lo = timestamp & 0xFFFFFFFF;
Kim Schulzf1d68e92013-09-23 12:48:47 +0200290
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -0700291 length = htonl(length_he);
292 flags = htonl(flags);
293 drops = htonl(drops);
294 time_hi = htonl(time_hi);
295 time_lo = htonl(time_lo);
Kim Schulzf1d68e92013-09-23 12:48:47 +0200296
Matadeen Mishraaab3e112014-11-14 19:46:19 +0530297 /* store the length in both original and included fields */
298 memcpy(snoop_buf + offset, &length, 4);
299 offset += 4;
300 memcpy(snoop_buf + offset, &length, 4);
301 offset += 4;
302
303 /* flags: */
304 memcpy(snoop_buf + offset, &flags, 4);
305 offset += 4;
306
307 /* drops: none */
308 memcpy(snoop_buf + offset, &drops, 4);
309 offset += 4;
310
311 /* time */
312 memcpy(snoop_buf + offset, &time_hi, 4);
313 offset += 4;
314 memcpy(snoop_buf + offset, &time_lo, 4);
315 offset = offset + 4;
316
317 snoop_buf[offset] = type;
318 offset += 1;
319 if (offset + length_he + 1 > MAX_SNOOP_BUF_SIZE) {
320 LOG_ERROR(LOG_TAG, "Bad packet length, downgrading the length to %d from %d",
321 MAX_SNOOP_BUF_SIZE - offset - 1, length_he);
322 length_he = MAX_SNOOP_BUF_SIZE - offset - 1;
323 }
324 memcpy(snoop_buf + offset, packet, length_he - 1);
325
326 if (client_socket_btsnoop != -1) {
327 pfd.fd = client_socket_btsnoop;
328 pfd.events = POLLOUT;
329#ifdef DEBUG_SNOOP
330 ts_begin = time_now_us();
331#endif
332
333 if (poll(&pfd, 1, 10) == 0) {
334 LOG_ERROR(LOG_TAG, "btsnoop poll : Taking more than 10 ms : skip dump");
335#ifdef DEBUG_SNOOP
336 ts_end = time_now_us();
337 ts_diff = ts_end - ts_begin;
338 if (ts_diff > 10000) {
339 LOG_ERROR(LOG_TAG, "btsnoop poll T/O : took more time %08lld us", ts_diff);
340 }
341#endif
342 return;
343 }
344
345#ifdef DEBUG_SNOOP
346 ts_end = time_now_us();
347 ts_diff = ts_end - ts_begin;
348 if (ts_diff > 10000) {
349 LOG_ERROR(LOG_TAG, "btsnoop poll : took more time %08lld us", ts_diff);
350 }
351#endif
352 }
353#ifdef DEBUG_SNOOP
354 ts_begin = time_now_us();
355#endif
356
357 btsnoop_write(snoop_buf, offset + length_he - 1);
358
359#ifdef DEBUG_SNOOP
360 ts_end = time_now_us();
361 ts_diff = ts_end - ts_begin;
362 if (ts_diff > 10000) {
363 LOG_ERROR(LOG_TAG, "btsnoop write : Write took more time %08lld us", ts_diff);
364 }
365#endif
The Android Open Source Project5738f832012-12-12 16:00:35 -0800366}