OSDN Git Service

DO NOT MERGE ANYWHERE Bluetooth native dumpsys logging support (2/4)
authorAndre Eisenbach <eisenbach@google.com>
Fri, 5 Dec 2014 17:40:20 +0000 (09:40 -0800)
committerTucker Sylvestro <tuckeris@google.com>
Wed, 4 Mar 2015 22:18:10 +0000 (17:18 -0500)
Includes support for BTSnoop logging in memory.

Bug: 18508263
Change-Id: Iade200283dca3545b7bbd0872c583731eb115d34

19 files changed:
btif/include/btif_debug.h [new file with mode: 0644]
btif/include/btif_debug_btsnoop.h [new file with mode: 0644]
btif/include/btif_debug_conn.h [new file with mode: 0644]
btif/src/bluetooth.c
btif/src/btif_debug.c [new file with mode: 0644]
btif/src/btif_debug_btsnoop.c [new file with mode: 0644]
btif/src/btif_debug_conn.c [new file with mode: 0644]
btif/src/btif_gatt_client.c
btif/src/btif_media_task.c
hci/Android.mk
hci/include/btsnoop_mem.h [new file with mode: 0644]
hci/src/btsnoop.c
hci/src/btsnoop_mem.c [new file with mode: 0644]
include/bt_target.h
main/Android.mk
osi/Android.mk
osi/include/ringbuffer.h [new file with mode: 0644]
osi/src/ringbuffer.c [new file with mode: 0644]
osi/test/ringbuffer_test.cpp [new file with mode: 0644]

diff --git a/btif/include/btif_debug.h b/btif/include/btif_debug.h
new file mode 100644 (file)
index 0000000..fcf9e63
--- /dev/null
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+// Debug API
+
+void btif_debug_init();
+void btif_debug_dump(int fd);
+
+// Debug helpers
+
+// Timestamp in us
+uint64_t btif_debug_ts();
diff --git a/btif/include/btif_debug_btsnoop.h b/btif/include/btif_debug_btsnoop.h
new file mode 100644 (file)
index 0000000..2639f3a
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+#define BTSNOOZ_CURRENT_VERSION 0x01
+
+// The preamble is stored un-encrypted as the first part
+// of the file.
+typedef struct btsnooz_preamble_t {
+  uint8_t version;
+  uint64_t last_ts;
+} __attribute__((__packed__)) btsnooz_preamble_t;
+
+// One header for each HCI packet
+typedef struct btsnooz_hdr_t {
+  uint16_t len;
+  uint32_t delta;
+  uint8_t type;
+} __attribute__((__packed__)) btsnooz_hdr_t;
+
+// Initializes btsnoop memory logging and registers
+void btif_debug_btsnoop_init();
+
+// Writes btsnoop data base64 encoded to fd
+void btif_debug_btsnoop_dump(int fd);
diff --git a/btif/include/btif_debug_conn.h b/btif/include/btif_debug_conn.h
new file mode 100644 (file)
index 0000000..1478f8b
--- /dev/null
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+
+typedef enum {
+  BTIF_DEBUG_CONNECTED = 1,
+  BTIF_DEBUG_DISCONNECTED
+} btif_debug_conn_state_t;
+
+// Report a connection state change
+void btif_debug_conn_state(const bt_bdaddr_t bda, const btif_debug_conn_state_t state,
+    const uint8_t status);
+
+void btif_debug_conn_dump(int fd);
index 5c730f9..9c990ef 100644 (file)
@@ -44,7 +44,9 @@
 #define LOG_TAG "bluedroid"
 
 #include "btif_api.h"
+#include "btif_debug.h"
 #include "bt_utils.h"
+#include "btsnoop_mem.h"
 
 /************************************************************************************
 **  Constants & Macros
@@ -139,6 +141,8 @@ static int init(bt_callbacks_t* callbacks )
     /* init btif */
     btif_init_bluetooth();
 
+    btif_debug_init();
+
     return BT_STATUS_SUCCESS;
 }
 
@@ -329,6 +333,11 @@ static int read_energy_info()
     return BT_STATUS_SUCCESS;
 }
 
+static void dump(int fd)
+{
+    btif_debug_dump(fd);
+}
+
 static const void* get_profile_interface (const char *profile_id)
 {
     ALOGI("get_profile_interface %s", profile_id);
@@ -463,6 +472,7 @@ static const bt_interface_t bluetoothInterface = {
     config_hci_snoop_log,
     set_os_callouts,
     read_energy_info,
+    dump,
 };
 
 const bt_interface_t* bluetooth__get_bluetooth_interface ()
diff --git a/btif/src/btif_debug.c b/btif/src/btif_debug.c
new file mode 100644 (file)
index 0000000..61b40a3
--- /dev/null
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <unistd.h>
+#include "bt_target.h"
+#include "btif_debug.h"
+#include "btif_debug_btsnoop.h"
+#include "btif_debug_conn.h"
+
+void btif_debug_init() {
+#if defined(BTSNOOP_MEM) && (BTSNOOP_MEM == TRUE)
+  btif_debug_btsnoop_init();
+#endif
+}
+
+void btif_debug_dump(int fd) {
+  btif_debug_conn_dump(fd);
+#if defined(BTSNOOP_MEM) && (BTSNOOP_MEM == TRUE)
+  btif_debug_btsnoop_dump(fd);
+#endif
+
+  fsync(fd);
+  close(fd);
+}
+
+uint64_t btif_debug_ts() {
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000000LL) + tv.tv_usec;
+}
diff --git a/btif/src/btif_debug_btsnoop.c b/btif/src/btif_debug_btsnoop.c
new file mode 100644 (file)
index 0000000..3ed7f90
--- /dev/null
@@ -0,0 +1,147 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <resolv.h>
+#include <zlib.h>
+#include "bt_target.h"
+#include "btif_debug.h"
+#include "btif_debug_btsnoop.h"
+#include "btsnoop_mem.h"
+#include "ringbuffer.h"
+
+// Total btsnoop memory log buffer size
+#ifndef BTSNOOP_MEM_BUFFER_SIZE
+#define BTSNOOP_MEM_BUFFER_SIZE 131072
+#endif
+
+// Block size for copying buffers (for compression/encoding etc.)
+#define BLOCK_SIZE 16384
+
+// Maximum line length in bugreport (should be multiple of 4 for base64 output)
+#define MAX_LINE_LENGTH 128
+
+static ringbuffer_t *s_buffer = NULL;
+static uint64_t s_last_ts = 0;
+
+static void btsnoop_cb(const uint8_t type, const uint16_t len, const uint8_t *p_data) {
+  btsnooz_hdr_t hdr;
+
+  // Make room in the ring buffer
+
+  while (ringbuffer_available(s_buffer) < (len + sizeof(btsnooz_hdr_t))) {
+    ringbuffer_pop(s_buffer, (uint8_t*)&hdr, sizeof(btsnooz_hdr_t));
+    ringbuffer_delete(s_buffer, hdr.len-1);
+  }
+
+  // Insert data
+
+  const uint64_t now = btif_debug_ts();
+
+  hdr.type = type;
+  hdr.len = len;
+  hdr.delta = s_last_ts ? now - s_last_ts : 0;
+  s_last_ts = now;
+
+  ringbuffer_insert(s_buffer, (uint8_t*)&hdr, sizeof(btsnooz_hdr_t));
+  ringbuffer_insert(s_buffer, p_data, len-1);
+}
+
+static bool btsnoop_compress(ringbuffer_t *rb_in, ringbuffer_t *rb_out) {
+  if (rb_in == NULL || rb_out == NULL)
+    return false;
+
+  z_stream zs = {0};
+  if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK)
+    return false;
+
+  bool rc = true;
+  uint8_t b_in[BLOCK_SIZE];
+  uint8_t b_out[BLOCK_SIZE];
+
+  while(ringbuffer_size(rb_in) > 0) {
+    zs.avail_in = ringbuffer_pop(rb_in, b_in, BLOCK_SIZE);
+    zs.next_in = b_in;
+
+    do {
+      zs.avail_out = BLOCK_SIZE;
+      zs.next_out = b_out;
+
+      int err = deflate(&zs, ringbuffer_size(rb_in) == 0 ? Z_FINISH : Z_NO_FLUSH);
+      if (err == Z_STREAM_ERROR) {
+        rc = false;
+        break;
+      }
+
+      const size_t len = BLOCK_SIZE - zs.avail_out;
+      ringbuffer_insert(rb_out, b_out, len);
+    } while (zs.avail_out == 0);
+  }
+
+  deflateEnd(&zs);
+  return rc;
+}
+
+void btif_debug_btsnoop_init() {
+  if (s_buffer == NULL)
+    s_buffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
+  btsnoop_mem_set_callback(btsnoop_cb);
+}
+
+void btif_debug_btsnoop_dump(int fd) {
+  dprintf(fd, "\n--- BEGIN:BTSNOOP_LOG_SUMMARY (%zu bytes in) ---\n", ringbuffer_size(s_buffer));
+
+  ringbuffer_t *rb = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
+  if (rb == NULL) {
+    dprintf(fd, "%s() - Unable to allocate memory for compression", __FUNCTION__);
+    return;
+  }
+
+  // Prepend preamble
+
+  btsnooz_preamble_t preamble;
+  preamble.version = BTSNOOZ_CURRENT_VERSION;
+  preamble.last_ts = s_last_ts;
+  ringbuffer_insert(rb, (uint8_t*)&preamble, sizeof(btsnooz_preamble_t));
+
+  // Compress data
+
+  bool rc = btsnoop_compress(s_buffer, rb);
+  if (rc == false) {
+    dprintf(fd, "%s() - Log compression failed", __FUNCTION__);
+    goto err;
+  }
+
+  // Base64 encode & output
+
+  uint8_t b64_in[3] = {0};
+  char b64_out[5] = {0};
+
+  size_t i = sizeof(btsnooz_preamble_t);
+  while (ringbuffer_size(rb) > 0) {
+    size_t read = ringbuffer_pop(rb, b64_in, 3);
+    if (i > 0 && i % MAX_LINE_LENGTH == 0)
+      dprintf(fd, "\n");
+    i += b64_ntop(b64_in, read, b64_out, 5);
+    dprintf(fd, b64_out);
+  }
+
+  dprintf(fd, "\n--- END:BTSNOOP_LOG_SUMMARY (%zu bytes out) ---\n", i);
+
+err:
+  ringbuffer_free(rb);
+}
diff --git a/btif/src/btif_debug_conn.c b/btif/src/btif_debug_conn.c
new file mode 100644 (file)
index 0000000..e0b96c0
--- /dev/null
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "btif_debug.h"
+#include "btif_debug_conn.h"
+
+#define NUM_CONNECTION_EVT  16
+
+typedef struct conn_event_t {
+  uint64_t ts;
+  btif_debug_conn_state_t state;
+  bt_bdaddr_t bda;
+  uint8_t status;
+} conn_event_t;
+
+static conn_event_t connection_events[NUM_CONNECTION_EVT];
+static uint8_t current_event = 0;
+
+static char* format_ts(const uint64_t ts, char* buffer, int len) {
+  const uint64_t ms = ts / 1000;
+  const time_t secs = ms / 1000;
+  struct tm *ptm = localtime(&secs);
+
+  strftime(buffer, len, "%m-%d %H:%M:%S.%%03u", ptm);
+  snprintf(buffer, len, buffer, (uint16_t)(ms % 1000));
+
+  return buffer;
+}
+
+static char* format_state(const btif_debug_conn_state_t state) {
+  switch (state) {
+    case BTIF_DEBUG_CONNECTED:
+      return "CONNECTED   ";
+    case BTIF_DEBUG_DISCONNECTED:
+      return "DISCONNECTED";
+  }
+  return "UNKNOWN";
+}
+
+static void next_event() {
+  ++current_event;
+  if (current_event == NUM_CONNECTION_EVT)
+    current_event = 0;
+}
+
+
+void btif_debug_conn_state(const bt_bdaddr_t bda, const btif_debug_conn_state_t state,
+    const uint8_t status) {
+  next_event();
+
+  conn_event_t *evt = &connection_events[current_event];
+  evt->ts = btif_debug_ts();
+  evt->state = state;
+  evt->status = status;
+  memcpy(&evt->bda, &bda, sizeof(bt_bdaddr_t));
+}
+
+void btif_debug_conn_dump(int fd) {
+  const uint8_t current_event_local = current_event; // Cache to avoid threading issues
+  uint8_t dump_event = current_event_local;
+  char buffer[30] = {0};
+
+  dprintf(fd, "\nConnection Events:\n");
+  if (connection_events[dump_event].ts == 0)
+    dprintf(fd, "  None\n");
+
+  while (connection_events[dump_event].ts) {
+    conn_event_t *evt = &connection_events[dump_event];
+    dprintf(fd, "  %s %s %02x:%02x:%02x:%02x:%02x:%02x status=%d\n",
+      format_ts(evt->ts, buffer, 30),
+      format_state(evt->state),
+      evt->bda.address[0], evt->bda.address[1], evt->bda.address[2],
+      evt->bda.address[3], evt->bda.address[4], evt->bda.address[5],
+      evt->status
+    );
+
+    // Go to previous event; wrap if needed
+    if (dump_event > 0)
+      --dump_event;
+    else
+      dump_event = NUM_CONNECTION_EVT - 1;
+
+    // Check if we dumped all events
+    if (dump_event == current_event_local)
+      break;
+  }
+}
index 5d37fec..39fa777 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "btif_gatt.h"
 #include "btif_gatt_util.h"
+#include "btif_debug_conn.h"
 #include "btif_dm.h"
 #include "btif_storage.h"
 
@@ -538,6 +539,8 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
 
             if (p_data->open.status == BTA_GATT_OK)
                 btif_gatt_check_encrypted_link(p_data->open.remote_bda);
+
+            btif_debug_conn_state(bda, BTIF_DEBUG_CONNECTED, p_data->open.status);
             break;
         }
 
@@ -547,6 +550,8 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
             bdcpy(bda.address, p_data->close.remote_bda);
             HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id
                 , p_data->status, p_data->close.client_if, &bda);
+
+            btif_debug_conn_state(bda, BTIF_DEBUG_DISCONNECTED, p_data->close.status);
             break;
         }
 
index de34818..2cf84f7 100644 (file)
@@ -2842,15 +2842,14 @@ static void btif_media_aa_prep_2_send(UINT8 nb_frame)
 {
     VERBOSE("%s() - frames=%d (queue=%d)", __FUNCTION__, nb_frame, btif_media_cb.TxAaQ.count);
 
-    while (btif_media_cb.TxAaQ.count >= (MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ-nb_frame))
+    if (btif_media_cb.TxAaQ.count >= MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ)
     {
-        APPL_TRACE_WARNING("%s() - TX queue buffer count %d",
-            __FUNCTION__, btif_media_cb.TxAaQ.count);
-        GKI_freebuf(GKI_dequeue(&(btif_media_cb.TxAaQ)));
+        APPL_TRACE_WARNING("%s() - TX queue buffer count %d, truncating to %d",
+            __FUNCTION__, btif_media_cb.TxAaQ.count, nb_frame);
+        while (btif_media_cb.TxAaQ.count > nb_frame)
+            GKI_freebuf(GKI_dequeue(&(btif_media_cb.TxAaQ)));
     }
 
-    if (btif_media_cb.TxAaQ.count) --nb_frame;
-
     switch (btif_media_cb.TxTranscoding)
     {
     case BTIF_MEDIA_TRSCD_PCM_2_SBC:
index f93e658..02ced0f 100644 (file)
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES := \
        src/bt_hci_bdroid.c \
        src/btsnoop.c \
        src/btsnoop_net.c \
+       src/btsnoop_mem.c \
        src/lpm.c \
        src/utils.c \
        src/vendor.c
diff --git a/hci/include/btsnoop_mem.h b/hci/include/btsnoop_mem.h
new file mode 100644 (file)
index 0000000..85c9073
--- /dev/null
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+#include "bt_hci_bdroid.h"
+
+// Callback for each HCI packet.
+// Highlander mode - there can be only one...
+typedef void (*btsnoop_data_cb) (const uint8_t type, const uint16_t len, const uint8_t *p_data);
+
+// --> Sets the HCI packet callback
+void btsnoop_mem_set_callback(btsnoop_data_cb cb);
+
+// <-- Internal callback used to capture packets
+void btsnoop_mem_capture(const HC_BT_HDR *p_buf);
+
index e31af35..11b5722 100644 (file)
@@ -35,6 +35,7 @@
 #include "bt_hci_bdroid.h"
 #include "bt_utils.h"
 #include "utils.h"
+#include "btsnoop_mem.h"
 
 typedef enum {
   kCommandPacket = 1,
@@ -162,6 +163,8 @@ void btsnoop_close(void) {
 void btsnoop_capture(const HC_BT_HDR *p_buf, bool is_rcvd) {
   const uint8_t *p = (const uint8_t *)(p_buf + 1) + p_buf->offset;
 
+  btsnoop_mem_capture(p_buf);
+
   if (hci_btsnoop_fd == -1)
     return;
 
diff --git a/hci/src/btsnoop_mem.c b/hci/src/btsnoop_mem.c
new file mode 100644 (file)
index 0000000..5d4f6db
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "btsnoop_mem.h"
+#include <time.h>
+
+static btsnoop_data_cb s_data_cb = NULL;
+
+void btsnoop_mem_set_callback(btsnoop_data_cb cb) {
+  s_data_cb = cb;
+}
+
+void btsnoop_mem_capture(const HC_BT_HDR *p_buf) {
+  if (s_data_cb == NULL)
+    return;
+
+  const uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+  const uint16_t type = p_buf->event & MSG_EVT_MASK;
+  uint16_t len = 0;
+
+  switch (type) {
+    case MSG_STACK_TO_HC_HCI_CMD:
+      len = p[2] + 4;
+      break;
+
+    case MSG_HC_TO_STACK_HCI_EVT:
+      len = p[1] + 3;
+      break;
+
+    // Ignore data for privacy
+    case MSG_STACK_TO_HC_HCI_ACL:
+    case MSG_STACK_TO_HC_HCI_SCO:
+    case MSG_HC_TO_STACK_HCI_ACL:
+    case MSG_HC_TO_STACK_HCI_SCO:
+      break;
+  }
+
+  if (len)
+    (*s_data_cb)(type >> 8, len, p);
+}
index 66b5f98..296c6ca 100644 (file)
@@ -3804,6 +3804,11 @@ The maximum number of payload octets that the local device can receive in a sing
 **
 ******************************************************************************/
 
+/* Enable/disable BTSnoop memory logging */
+#ifndef BTSNOOP_MEM
+#define BTSNOOP_MEM TRUE
+#endif
+
 #include "bt_trace.h"
 
 #endif /* BT_TARGET_H */
index 21dfa1c..38099eb 100644 (file)
@@ -46,6 +46,9 @@ LOCAL_SRC_FILES += \
        ../btif/src/btif_sock_thread.c \
        ../btif/src/btif_sock_util.c \
        ../btif/src/btif_storage.c \
+       ../btif/src/btif_debug.c \
+       ../btif/src/btif_debug_btsnoop.c \
+       ../btif/src/btif_debug_conn.c \
        ../btif/src/btif_util.c
 
 # callouts
@@ -101,7 +104,8 @@ LOCAL_C_INCLUDES += . \
        $(LOCAL_PATH)/../audio_a2dp_hw \
        $(LOCAL_PATH)/../utils/include \
        $(bdroid_C_INCLUDES) \
-       external/tinyxml2
+       external/tinyxml2 \
+       external/zlib
 
 LOCAL_CFLAGS += -DBUILDCFG $(bdroid_CFLAGS) -Wno-error=maybe-uninitialized -Wno-error=uninitialized -Wno-error=unused-parameter
 LOCAL_CONLYFLAGS := -std=c99
@@ -120,6 +124,7 @@ LOCAL_SHARED_LIBRARIES := \
        libcutils \
        libdl \
        liblog \
+       libz \
        libpower
 
 LOCAL_STATIC_LIBRARIES := \
index 91f76ef..978a3e1 100644 (file)
@@ -12,7 +12,8 @@ LOCAL_SRC_FILES := \
     ./src/list.c \
     ./src/reactor.c \
     ./src/semaphore.c \
-    ./src/thread.c
+    ./src/thread.c \
+    ./src/ringbuffer.c
 
 LOCAL_CFLAGS := -std=c99 -Wall -Werror
 LOCAL_MODULE := libosi
@@ -34,7 +35,8 @@ LOCAL_SRC_FILES := \
     ./test/config_test.cpp \
     ./test/list_test.cpp \
     ./test/reactor_test.cpp \
-    ./test/thread_test.cpp
+    ./test/thread_test.cpp \
+    ./test/ringbuffer_test.cpp
 
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_MODULE := ositests
diff --git a/osi/include/ringbuffer.h b/osi/include/ringbuffer.h
new file mode 100644 (file)
index 0000000..563f798
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+typedef struct ringbuffer_t ringbuffer_t;
+
+// NOTE:
+// None of the functions below are thread safe when it comes to accessing the
+// *rb pointer. It is *NOT* possible to insert and pop/delete at the same time.
+// Callers must protect the *rb pointer separately.
+
+// Create a ringbuffer with the specified size
+// Returns NULL if memory allocation failed. Resulting pointer must be freed
+// using ringbuffer_free().
+ringbuffer_t* ringbuffer_init(const size_t size);
+
+// Frees the ringbuffer structure and buffer
+// Save to call with NULL.
+void ringbuffer_free(ringbuffer_t *rb);
+
+// Returns remaining buffer size
+size_t ringbuffer_available(const ringbuffer_t *rb);
+
+// Returns size of data in buffer
+size_t ringbuffer_size(const ringbuffer_t *rb);
+
+// Attempts to insert up to len bytes of data at *p into the buffer
+// Return actual number of bytes added. Can be less than len if buffer is full.
+size_t ringbuffer_insert(ringbuffer_t *rb, const uint8_t *p, size_t len);
+
+// Peek len number of bytes from the ringbuffer into the buffer *p
+// Return the actual number of bytes peeked. Can be less than len if there is
+// less than 'len' data available.
+size_t ringbuffer_peek(const ringbuffer_t *rb, uint8_t *p, size_t len);
+
+// Does the same as ringbuffer_peek(), but also advances the ring buffer head
+size_t ringbuffer_pop(ringbuffer_t *rb, uint8_t *p, size_t len);
+
+// Deltes len bytes from the ringbuffer starting from the head
+// Return actual number of bytes deleted.
+size_t ringbuffer_delete(ringbuffer_t *rb, size_t len);
diff --git a/osi/src/ringbuffer.c b/osi/src/ringbuffer.c
new file mode 100644 (file)
index 0000000..bbeca66
--- /dev/null
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include "ringbuffer.h"
+
+struct ringbuffer_t {
+  size_t total;
+  size_t available;
+  uint8_t *base;
+  uint8_t *head;
+  uint8_t *tail;
+};
+
+ringbuffer_t* ringbuffer_init(const size_t size) {
+  ringbuffer_t* p = malloc(sizeof(ringbuffer_t));
+  if (p == 0) {
+    return NULL;
+  }
+
+  p->base = malloc(size);
+  if (p->base == 0) {
+    free(p);
+    return NULL;
+  }
+
+  p->head = p->tail = p->base;
+  p->total = p->available = size;
+
+  return p;
+}
+
+void ringbuffer_free(ringbuffer_t *rb) {
+  if (rb != NULL)
+    free(rb->base);
+  free(rb);
+}
+
+size_t ringbuffer_available(const ringbuffer_t *rb) {
+  if (!rb)
+    return 0;
+  return rb->available;
+}
+
+size_t ringbuffer_size(const ringbuffer_t *rb) {
+  if (!rb)
+    return 0;
+  return rb->total - rb->available;
+}
+
+size_t ringbuffer_insert(ringbuffer_t *rb, const uint8_t *p, size_t len) {
+  if (!rb || !p)
+    return 0;
+
+  if (len > ringbuffer_available(rb))
+    len = ringbuffer_available(rb);
+
+  for (size_t i = 0; i != len; ++i) {
+    *rb->tail++ = *p++;
+    if (rb->tail >= (rb->base + rb->total))
+      rb->tail = rb->base;
+  }
+
+  rb->available -= len;
+  return len;
+}
+
+size_t ringbuffer_delete(ringbuffer_t *rb, size_t len) {
+  if (!rb)
+    return 0;
+
+  if (len > ringbuffer_size(rb))
+    len = ringbuffer_size(rb);
+
+  rb->head += len;
+  if (rb->head >= (rb->base + rb->total))
+    rb->head -= rb->total;
+
+  rb->available += len;
+  return len;
+}
+
+size_t ringbuffer_peek(const ringbuffer_t *rb, uint8_t *p, size_t len) {
+  if (!rb || !p)
+    return 0;
+
+  uint8_t *b = rb->head;
+  size_t copied = 0;
+
+  while (copied < len && copied < ringbuffer_size(rb)) {
+    *p++ = *b++;
+    if (b >= (rb->base + rb->total))
+      b = rb->base;
+    ++copied;
+  }
+
+  return copied;
+}
+
+size_t ringbuffer_pop(ringbuffer_t *rb, uint8_t *p, size_t len) {
+  if (!rb || !p)
+    return 0;
+
+  const size_t copied = ringbuffer_peek(rb, p, len);
+  rb->head += copied;
+  if (rb->head >= (rb->base + rb->total))
+    rb->head -= rb->total;
+
+  rb->available += copied;
+  return copied;
+}
diff --git a/osi/test/ringbuffer_test.cpp b/osi/test/ringbuffer_test.cpp
new file mode 100644 (file)
index 0000000..2ebdeca
--- /dev/null
@@ -0,0 +1,139 @@
+#include <gtest/gtest.h>
+
+extern "C" {
+#include "ringbuffer.h"
+#include "osi.h"
+}
+
+TEST(RingbufferTest, test_new_simple) {
+  ringbuffer_t *rb = ringbuffer_init(4096);
+  ASSERT_TRUE(rb != NULL);
+  EXPECT_EQ(4096, ringbuffer_available(rb));
+  EXPECT_EQ(0, ringbuffer_size(rb));
+  ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_insert_basic) {
+  ringbuffer_t *rb = ringbuffer_init(16);
+
+  uint8_t buffer[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
+  ringbuffer_insert(rb, buffer, 10);
+  EXPECT_EQ(10, ringbuffer_size(rb));
+  EXPECT_EQ(6, ringbuffer_available(rb));
+
+  uint8_t peek[10] = {0};
+  size_t peeked = ringbuffer_peek(rb, peek, 10);
+  EXPECT_EQ(10, ringbuffer_size(rb)); // Ensure size doesn't change
+  EXPECT_EQ(6, ringbuffer_available(rb));
+  EXPECT_EQ(10, peeked);
+  ASSERT_TRUE(0 == memcmp(buffer, peek, peeked));
+
+  ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_insert_full) {
+  ringbuffer_t *rb = ringbuffer_init(5);
+
+  uint8_t aa[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+  uint8_t bb[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+  uint8_t peek[5] = {0};
+
+  size_t added = ringbuffer_insert(rb, aa, 7);
+  EXPECT_EQ(5, added);
+  EXPECT_EQ(0, ringbuffer_available(rb));
+  EXPECT_EQ(5, ringbuffer_size(rb));
+
+  added = ringbuffer_insert(rb, bb, 5);
+  EXPECT_EQ(0, added);
+  EXPECT_EQ(0, ringbuffer_available(rb));
+  EXPECT_EQ(5, ringbuffer_size(rb));
+
+  size_t peeked = ringbuffer_peek(rb, peek, 5);
+  EXPECT_EQ(5, peeked);
+  EXPECT_EQ(0, ringbuffer_available(rb));
+  EXPECT_EQ(5, ringbuffer_size(rb));
+
+  ASSERT_TRUE(0 == memcmp(aa, peek, peeked));
+
+  ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_multi_insert_delete) {
+  ringbuffer_t *rb = ringbuffer_init(16);
+  EXPECT_EQ(16, ringbuffer_available(rb));
+  EXPECT_EQ(0, ringbuffer_size(rb));
+
+  // Insert some bytes
+
+  uint8_t aa[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+  size_t added = ringbuffer_insert(rb, aa, sizeof(aa));
+  EXPECT_EQ(8, added);
+  EXPECT_EQ(8, ringbuffer_available(rb));
+  EXPECT_EQ(8, ringbuffer_size(rb));
+
+  uint8_t bb[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+  ringbuffer_insert(rb, bb, sizeof(bb));
+  EXPECT_EQ(3, ringbuffer_available(rb));
+  EXPECT_EQ(13, ringbuffer_size(rb));
+
+  uint8_t content[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+  uint8_t peek[16] = {0};
+  size_t peeked = ringbuffer_peek(rb, peek, 16);
+  EXPECT_EQ(13, peeked);
+  ASSERT_TRUE(0 == memcmp(content, peek, peeked));
+
+  // Delete some bytes
+
+  ringbuffer_delete(rb, sizeof(aa));
+  EXPECT_EQ(11, ringbuffer_available(rb));
+  EXPECT_EQ(5, ringbuffer_size(rb));
+
+  // Add some more to wrap buffer
+
+  uint8_t cc[] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
+  ringbuffer_insert(rb, cc, sizeof(cc));
+  EXPECT_EQ(2, ringbuffer_available(rb));
+  EXPECT_EQ(14, ringbuffer_size(rb));
+
+  uint8_t content2[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xCC, 0xCC};
+  peeked = ringbuffer_peek(rb, peek, 7);
+  EXPECT_EQ(7, peeked);
+  ASSERT_TRUE(0 == memcmp(content2, peek, peeked));
+
+  // Pop buffer
+
+  memset(peek, 0, 16);
+  size_t popped = ringbuffer_pop(rb, peek, 7);
+  EXPECT_EQ(7, popped);
+  EXPECT_EQ(9, ringbuffer_available(rb));
+  ASSERT_TRUE(0 == memcmp(content2, peek, peeked));
+
+  // Add more again to check head motion
+
+  uint8_t dd[] = { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD };
+  added = ringbuffer_insert(rb, dd, sizeof(dd));
+  EXPECT_EQ(8, added);
+  EXPECT_EQ(1, ringbuffer_available(rb));
+
+  // Delete everything
+
+  ringbuffer_delete(rb, 16);
+  EXPECT_EQ(16, ringbuffer_available(rb));
+  EXPECT_EQ(0, ringbuffer_size(rb));
+
+  // Add small token
+
+  uint8_t ae[] = { 0xAE, 0xAE, 0xAE };
+  added = ringbuffer_insert(rb, ae, sizeof(ae));
+  EXPECT_EQ(13, ringbuffer_available(rb));
+
+  // Get everything
+
+  popped = ringbuffer_pop(rb, peek, 16);
+  EXPECT_EQ(added, popped);
+  EXPECT_EQ(16, ringbuffer_available(rb));
+  EXPECT_EQ(0, ringbuffer_size(rb));
+  ASSERT_TRUE(0 == memcmp(ae, peek, popped));
+
+  ringbuffer_free(rb);
+}