summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArne Coucheron <arco68@gmail.com>2017-04-05 01:59:46 +0200
committerDan Pasanen <dan.pasanen@gmail.com>2017-04-05 11:13:15 -0500
commitc0e5c0bc6667b80a95805c30d65601a309c2f2f6 (patch)
tree4b53ab727c41d07f8d4868e8ed900905a745cf6f
parent838550cd605956e5dc4e29fdf826a58ba3ff8161 (diff)
parent5a9925784a4a34811ae29608b67dee4a580c226b (diff)
downloadandroid_system_bt-staging/cm-14.1_android-7.1.2_r2.tar.gz
android_system_bt-staging/cm-14.1_android-7.1.2_r2.tar.bz2
android_system_bt-staging/cm-14.1_android-7.1.2_r2.zip
Merge tag 'android-7.1.2_r2' into cm-14.1staging/cm-14.1_android-7.1.2_r2
Change-Id: I6d14049f050ea0b25c74f82af86c23b57910f567
-rw-r--r--bta/dm/bta_dm_act.c8
-rw-r--r--bta/gatt/bta_gattc_cache.c3
-rw-r--r--bta/gatt/bta_gattc_utils.c6
-rw-r--r--bta/hh/bta_hh_le.c12
-rw-r--r--bta/include/bta_api.h3
-rw-r--r--btif/Android.mk1
-rw-r--r--btif/co/bta_dm_co.c22
-rw-r--r--btif/include/btif_debug_l2c.h54
-rw-r--r--btif/include/btif_storage.h11
-rw-r--r--btif/src/bluetooth.c10
-rw-r--r--btif/src/btif_debug_l2c.c159
-rw-r--r--btif/src/btif_dm.c112
-rw-r--r--btif/src/btif_media_task.c194
-rw-r--r--btif/src/btif_storage.c15
-rw-r--r--conf/bt_stack.conf2
-rw-r--r--hci/src/btsnoop.c3
-rw-r--r--include/bt_target.h11
-rw-r--r--main/stack_config.c3
-rw-r--r--osi/Android.mk7
-rw-r--r--osi/BUILD.gn4
-rw-r--r--osi/include/leaky_bonded_queue.h158
-rw-r--r--osi/include/metrics.h109
-rw-r--r--osi/include/metrics_cpp.h230
-rw-r--r--osi/src/metrics.cpp617
-rw-r--r--osi/src/metrics_linux.cpp236
-rw-r--r--osi/src/protos/bluetooth.proto38
-rw-r--r--osi/src/wakelock.c4
-rw-r--r--osi/test/leaky_bonded_queue_test.cpp242
-rw-r--r--osi/test/metrics_test.cpp805
-rw-r--r--stack/btm/btm_acl.c44
-rw-r--r--stack/btm/btm_ble.c50
-rw-r--r--stack/btm/btm_dev.c4
-rw-r--r--stack/btm/btm_inq.c4
-rw-r--r--stack/btm/btm_int.h6
-rw-r--r--stack/include/btm_api.h4
-rw-r--r--stack/include/btm_ble_api.h18
-rw-r--r--stack/l2cap/l2c_ble.c53
-rw-r--r--stack/sdp/sdp_discovery.c9
38 files changed, 2899 insertions, 372 deletions
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
index a426d0917..1923f467e 100644
--- a/bta/dm/bta_dm_act.c
+++ b/bta/dm/bta_dm_act.c
@@ -2960,6 +2960,8 @@ static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data)
/*case BTM_SP_KEY_REQ_EVT: */
case BTM_SP_KEY_NOTIF_EVT:
#endif
+ bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey;
+
if(BTM_SP_CFM_REQ_EVT == event)
{
/* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT,
@@ -2990,7 +2992,6 @@ static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data)
}
}
- bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey;
if (BTM_SP_KEY_NOTIF_EVT == event)
{
/* If the device name is not known, save bdaddr and devclass
@@ -4489,6 +4490,11 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D
bta_dm_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event);
break;
+ case BTM_LE_SC_OOB_REQ_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_SC_OOB_REQ_EVT, &sec_event);
+ break;
+
case BTM_LE_KEY_EVT:
bdcpy(sec_event.ble_key.bd_addr, bda);
sec_event.ble_key.key_type = p_data->key.key_type;
diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
index 832b0abb7..1a42e7df6 100644
--- a/bta/gatt/bta_gattc_cache.c
+++ b/bta/gatt/bta_gattc_cache.c
@@ -326,7 +326,8 @@ static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb,
descriptor->handle = handle;
memcpy(&descriptor->uuid, p_uuid, sizeof(tBT_UUID));
- if (service->characteristics == NULL) {
+ if (service->characteristics == NULL ||
+ list_is_empty(service->characteristics)) {
APPL_TRACE_ERROR("%s: Illegal action to add descriptor before adding a characteristic!",
__func__);
osi_free(descriptor);
diff --git a/bta/gatt/bta_gattc_utils.c b/bta/gatt/bta_gattc_utils.c
index bd0d466f5..8910bd367 100644
--- a/bta/gatt/bta_gattc_utils.c
+++ b/bta/gatt/bta_gattc_utils.c
@@ -302,6 +302,12 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb)
p_srcb->connected = FALSE;
p_srcb->state = BTA_GATTC_SERV_IDLE;
p_srcb->mtu = 0;
+
+ /* clean up cache */
+ if (p_srcb->p_srvc_cache) {
+ list_free(p_srcb->p_srvc_cache);
+ p_srcb->p_srvc_cache = NULL;
+ }
}
osi_free_and_reset((void **)&p_clcb->p_q_cmd);
diff --git a/bta/hh/bta_hh_le.c b/bta/hh/bta_hh_le.c
index 28d3897c0..9bc5de3dc 100644
--- a/bta/hh/bta_hh_le.c
+++ b/bta/hh/bta_hh_le.c
@@ -2225,12 +2225,19 @@ void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY *p_data)
if (p_dev_cb == NULL)
{
- APPL_TRACE_ERROR("notification received from Unknown device");
+ APPL_TRACE_ERROR("%s: notification received from Unknown device, conn_id: 0x%04x",
+ __func__, p_data->conn_id);
return;
}
const tBTA_GATTC_CHARACTERISTIC *p_char = BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id,
p_data->handle);
+ if (p_char == NULL)
+ {
+ APPL_TRACE_ERROR("%s: notification received for Unknown Characteristic, conn_id: 0x%04x, handle: 0x%04x",
+ __func__, p_dev_cb->conn_id, p_data->handle);
+ return;
+ }
app_id= p_dev_cb->app_id;
@@ -2246,7 +2253,8 @@ void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY *p_data)
p_char->handle);
if (p_rpt == NULL)
{
- APPL_TRACE_ERROR("notification received for Unknown Report");
+ APPL_TRACE_ERROR("%s: notification received for Unknown Report, uuid: 0x%04x, handle: 0x%04x",
+ __func__, p_char->uuid.uu.uuid16, p_char->handle);
return;
}
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 913b65772..5cfd121d5 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -593,7 +593,8 @@ typedef UINT8 tBTA_SIG_STRENGTH_MASK;
#define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */
#define BTA_DM_LE_FEATURES_READ 27 /* Cotroller specific LE features are read */
#define BTA_DM_ENER_INFO_READ 28 /* Energy info read */
-typedef UINT8 tBTA_DM_SEC_EVT;
+#define BTA_DM_BLE_SC_OOB_REQ_EVT 29 /* SMP SC OOB request event */
+typedef uint8_t tBTA_DM_SEC_EVT;
/* Structure associated with BTA_DM_ENABLE_EVT */
typedef struct
diff --git a/btif/Android.mk b/btif/Android.mk
index ce4efc2fd..d3e33742f 100644
--- a/btif/Android.mk
+++ b/btif/Android.mk
@@ -36,6 +36,7 @@ btifCommonSrc += \
src/btif_debug.c \
src/btif_debug_btsnoop.c \
src/btif_debug_conn.c \
+ src/btif_debug_l2c.c \
src/btif_dm.c \
src/btif_gatt.c \
src/btif_gatt_client.c \
diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c
index 9d6fc80f3..5c3b0a3c1 100644
--- a/btif/co/bta_dm_co.c
+++ b/btif/co/bta_dm_co.c
@@ -24,6 +24,9 @@
#include "bta_dm_ci.h"
#include "bt_utils.h"
#include "btif_dm.h"
+#if (defined WEAR_LE_IO_CAP_OVERRIDE && WEAR_LE_IO_CAP_OVERRIDE == TRUE)
+#include "btif_storage.h"
+#endif
#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
#include "bte_appl.h"
@@ -408,7 +411,24 @@ void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
tBTA_LE_KEY_TYPE *p_resp_key )
{
UNUSED(bd_addr);
- /* Retrieve the properties from file system if possible */
+
+
+#if (defined WEAR_LE_IO_CAP_OVERRIDE && WEAR_LE_IO_CAP_OVERRIDE == TRUE)
+ /*
+ * Note: This is a Wear-specific feature for iOS pairing.
+ *
+ * Set WearLeIoCap config to force local IO capability to be BTM_IO_CAP_NONE
+ * (No input, no output) for the first bond creation, that indirectly
+ * triggers Just Works pairing.
+ */
+ if (btif_storage_get_num_bonded_devices() == 0)
+ bte_appl_cfg.ble_io_cap = BTM_IO_CAP_NONE;
+#endif
+
+ /* For certification testing purpose, LE IO capability can also be specified with
+ * "PTS_SmpOptions" in the BT stack configuration file (i.e. bt_stack.conf).
+ * Note that if "PTS_SmpOptions" is set, it could override IO capability set above.
+ */
tBTE_APPL_CFG nv_config;
if(btif_dm_get_smp_config(&nv_config))
bte_appl_cfg = nv_config;
diff --git a/btif/include/btif_debug_l2c.h b/btif/include/btif_debug_l2c.h
new file mode 100644
index 000000000..b77c49bc3
--- /dev/null
+++ b/btif/include/btif_debug_l2c.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 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>
+
+#include <hardware/bluetooth.h>
+
+// Captures a BLE connection parameter update request (Section 4.20 of
+// Bluetooth Core V4.2 specification):
+//
+// |min_interval| and |max_interval| define the minimum and maximum values for
+// the connection event interval (in units of 1.25ms and should be in the
+// [6, 3200] range).
+// |slave_latency_param| is the slave latency parameter for the connection in
+// number of connection events (unitless and should be less than 500).
+// |timeout_multiplier| is the connection timeout parameter (in units of 10ms
+// and should be in the [10, 3200] range).
+void btif_debug_ble_connection_update_request(bt_bdaddr_t bda,
+ uint16_t min_interval, uint16_t max_interval, uint16_t slave_latency_param,
+ uint16_t timeout_multiplier);
+
+// Captures a BLE connection parameter update response ((Section 4.21 of
+// Bluetooth Core V4.2 specification):
+//
+// |interval| defines the minimum and maximum values for the
+// connection event interval (in units of 1.25ms and should be in the
+// [6, 3200] range).
+// |slave_latency_param| is the slave latency parameter for the connection in
+// number of connection events (unitless and should be less than 500).
+// |timeout_multiplier| is the connection timeout parameter (in units of 10ms
+// and should be in the [10, 3200] range).
+void btif_debug_ble_connection_update_response(bt_bdaddr_t bda, uint8_t status,
+ uint16_t interval, uint16_t slave_latency_param,
+ uint16_t timeout_multiplier);
+
+// Dumps captured L2C information.
+void btif_debug_l2c_dump(int fd);
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index 2559c94df..98f15d666 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -288,6 +288,17 @@ BOOLEAN btif_storage_is_restricted_device(const bt_bdaddr_t *remote_bd_addr);
/*******************************************************************************
**
+** Function btif_storage_get_num_bonded_devices
+**
+** Description BTIF storage API - Gets the number of bonded devices
+**
+** Returns the number of bonded devices
+**
+*******************************************************************************/
+int btif_storage_get_num_bonded_devices(void);
+
+/*******************************************************************************
+**
** Function btif_storage_is_wiimote
**
** Description BTIF storage API - checks if this device is a wiimote
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
index ae9850d1b..eaa8cd829 100644
--- a/btif/src/bluetooth.c
+++ b/btif/src/bluetooth.c
@@ -64,6 +64,7 @@
#include "btif_storage.h"
#include "btif/include/btif_debug_btsnoop.h"
#include "btif/include/btif_debug_conn.h"
+#include "btif/include/btif_debug_l2c.h"
#include "btif/include/btif_media.h"
#include "l2cdefs.h"
#include "l2c_api.h"
@@ -363,20 +364,15 @@ static int read_energy_info()
static void dump(int fd, const char **arguments)
{
if (arguments != NULL && arguments[0] != NULL) {
- if (strncmp(arguments[0], "--proto-text", 12) == 0) {
- btif_update_a2dp_metrics();
- metrics_print(fd, true);
- return;
- }
if (strncmp(arguments[0], "--proto-bin", 11) == 0) {
- btif_update_a2dp_metrics();
- metrics_write(fd, true);
+ metrics_write_base64(fd, true);
return;
}
}
btif_debug_conn_dump(fd);
btif_debug_bond_event_dump(fd);
btif_debug_a2dp_dump(fd);
+ btif_debug_l2c_dump(fd);
btif_debug_config_dump(fd);
wakelock_debug_dump(fd);
alarm_debug_dump(fd);
diff --git a/btif/src/btif_debug_l2c.c b/btif/src/btif_debug_l2c.c
new file mode 100644
index 000000000..5a0413578
--- /dev/null
+++ b/btif/src/btif_debug_l2c.c
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#include "btcore/include/bdaddr.h"
+#include "btif/include/btif_debug.h"
+#include "btif/include/btif_debug_l2c.h"
+
+#define NUM_UPDATE_REQUESTS 5
+#define NUM_UPDATE_RESPONSES 5
+
+#define INTERVAL_1_25_MS_MULTIPLIER 1.25f
+#define TIMEOUT_10_MS_MULTIPLIER 10
+
+typedef enum {
+ BTIF_DEBUG_CONNECTION_UPDATE_REQUEST,
+ BTIF_DEBUG_CONNECTION_UPDATE_RESPONSE,
+} btif_debug_ble_conn_update_t;
+
+/* Shared Connection update record for both request and response. */
+typedef struct ble_conn_update_t {
+ uint64_t timestamp_ms;
+ bt_bdaddr_t bda;
+ btif_debug_ble_conn_update_t type;
+ uint8_t status; /* Not populated for request. */
+ uint16_t min_interval; /* Not populated for response. */
+ uint16_t max_interval;
+ uint16_t latency;
+ uint16_t timeout;
+} ble_conn_update_t;
+
+static int update_request_index;
+static int update_response_index;
+static ble_conn_update_t last_ble_conn_update_requests[NUM_UPDATE_REQUESTS];
+static ble_conn_update_t last_ble_conn_update_responses[NUM_UPDATE_RESPONSES];
+
+static int dump_connection_update(int fd, const ble_conn_update_t *update) {
+ if (!update || update->timestamp_ms == 0) {
+ return -1;
+ }
+
+ /* Format timestamp */
+ const uint64_t msecs = update->timestamp_ms / 1000;
+ const time_t secs = msecs / 1000;
+ struct tm *ptm = localtime(&secs);
+ char time_buf[20] = {0};
+ strftime(time_buf, sizeof(time_buf), "%m-%d %H:%M:%S", ptm);
+ snprintf(time_buf, sizeof(time_buf), "%s.%03u", time_buf,
+ (uint16_t)(msecs % 1000));
+
+ /* Format address */
+ char addr_buf[18] = {0};
+ bdaddr_to_string(&update->bda, addr_buf, sizeof(addr_buf));
+
+ if (update->type == BTIF_DEBUG_CONNECTION_UPDATE_REQUEST) {
+ dprintf(fd,
+ " %s %s min interval=%d (%.2fms) max interval=%d (%.2fms) "
+ "latency parameter=%d timeout multiplier=%d (%dms)\n",
+ time_buf, addr_buf, update->min_interval,
+ (float)update->min_interval * INTERVAL_1_25_MS_MULTIPLIER,
+ update->max_interval,
+ (float)update->max_interval * INTERVAL_1_25_MS_MULTIPLIER,
+ update->latency, update->timeout,
+ update->timeout * TIMEOUT_10_MS_MULTIPLIER);
+ } else {
+ dprintf(fd,
+ " %s %s status=%d interval=%d (%.2fms) latency parameter=%d "
+ "timeout multiplier=%d (%dms)\n", time_buf,
+ addr_buf, update->status, update->max_interval,
+ (float)update->max_interval * INTERVAL_1_25_MS_MULTIPLIER,
+ update->latency, update->timeout,
+ update->timeout * TIMEOUT_10_MS_MULTIPLIER);
+ }
+
+ return 0;
+}
+
+static void record_connection_update(bt_bdaddr_t bda, uint8_t status,
+ uint16_t min_interval, uint16_t max_interval, uint16_t latency,
+ uint16_t timeout, btif_debug_ble_conn_update_t type,
+ ble_conn_update_t* update) {
+
+ memcpy(&update->bda, &bda, sizeof(bt_bdaddr_t));
+ update->type = type;
+ update->timestamp_ms = btif_debug_ts();
+ update->min_interval = min_interval;
+ update->max_interval = max_interval;
+ update->latency = latency;
+ update->timeout = timeout;
+ update->status = 0;
+}
+
+void btif_debug_ble_connection_update_request(bt_bdaddr_t bda,
+ uint16_t min_interval, uint16_t max_interval, uint16_t slave_latency_param,
+ uint16_t timeout_multiplier) {
+ ble_conn_update_t *request =
+ &last_ble_conn_update_requests[update_request_index];
+
+ record_connection_update(bda, 0, min_interval, max_interval, slave_latency_param,
+ timeout_multiplier, BTIF_DEBUG_CONNECTION_UPDATE_REQUEST, request);
+
+ update_request_index = (update_request_index == NUM_UPDATE_REQUESTS - 1) ?
+ 0 : update_request_index + 1;
+}
+
+void btif_debug_ble_connection_update_response(bt_bdaddr_t bda, uint8_t status,
+ uint16_t interval, uint16_t slave_latency_param,
+ uint16_t timeout_multiplier) {
+ ble_conn_update_t *response =
+ &last_ble_conn_update_responses[update_response_index];
+
+ record_connection_update(bda, status, 0, interval, slave_latency_param,
+ timeout_multiplier, BTIF_DEBUG_CONNECTION_UPDATE_RESPONSE, response);
+
+ update_response_index = (update_response_index == NUM_UPDATE_RESPONSES - 1) ?
+ 0 : update_response_index + 1;
+}
+
+void btif_debug_l2c_dump(int fd) {
+ dprintf(fd, "\nLE Connection Parameter Updates:\n");
+
+ int i;
+ dprintf(fd, " Last %d Request(s):\n", NUM_UPDATE_REQUESTS);
+ for (i = 0; i < NUM_UPDATE_REQUESTS; ++i) {
+ if (dump_connection_update(fd, &last_ble_conn_update_requests[i]) < 0 &&
+ i == 0) {
+ dprintf(fd, " None\n");
+ break;
+ }
+ }
+
+ dprintf(fd, "\n Last %d Response(s):\n", NUM_UPDATE_RESPONSES);
+ for (i = 0; i < NUM_UPDATE_RESPONSES; ++i) {
+ if (dump_connection_update(fd, &last_ble_conn_update_responses[i]) < 0 &&
+ i == 0) {
+ dprintf(fd, " None\n");
+ break;
+ }
+ }
+}
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
index b3a6e7bd0..f6880dd58 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -231,6 +231,7 @@ static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl);
static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ *p_pin_req);
static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF *p_notif_req) ;
static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
+static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
@@ -815,7 +816,15 @@ static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr, tBTA_TRANSPORT transpor
}
if (btif_storage_get_remote_addr_type(bd_addr, &addr_type) != BT_STATUS_SUCCESS)
{
- btif_storage_set_remote_addr_type(bd_addr, BLE_ADDR_PUBLIC);
+
+ // Try to read address type. OOB pairing might have set it earlier, but
+ // didn't store it, it defaults to BLE_ADDR_PUBLIC
+ uint8_t tmp_dev_type;
+ uint8_t tmp_addr_type;
+ BTM_ReadDevInfo(bd_addr->address, &tmp_dev_type, &tmp_addr_type);
+ addr_type = tmp_addr_type;
+
+ btif_storage_set_remote_addr_type(bd_addr, addr_type);
}
}
if((btif_config_get_int((char const *)&bdstr,"DevType", &device_type) &&
@@ -1886,7 +1895,7 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
uint32_t i;
bt_bdaddr_t bd_addr;
- BTIF_TRACE_EVENT("btif_dm_upstreams_cback ev: %s", dump_dm_event(event));
+ BTIF_TRACE_EVENT("%s: ev: %s", __func__, dump_dm_event(event));
switch (event)
{
@@ -2175,6 +2184,10 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
BTIF_TRACE_DEBUG("BTA_DM_BLE_OOB_REQ_EVT. ");
btif_dm_ble_oob_req_evt(&p_data->rmt_oob);
break;
+ case BTA_DM_BLE_SC_OOB_REQ_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_SC_OOB_REQ_EVT. ");
+ btif_dm_ble_sc_oob_req_evt(&p_data->rmt_oob);
+ break;
case BTA_DM_BLE_LOCAL_IR_EVT:
BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. ");
ble_local_key_cb.is_id_keys_rcvd = TRUE;
@@ -2644,6 +2657,19 @@ bt_status_t btif_dm_create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int tran
bdcpy(oob_cb.bdaddr, bd_addr->address);
memcpy(&oob_cb.oob_data, oob_data, sizeof(bt_out_of_band_data_t));
+ uint8_t empty[] = {0, 0, 0, 0, 0, 0, 0};
+ // If LE Bluetooth Device Address is provided, use provided address type
+ // value.
+ if (memcmp(oob_data->le_bt_dev_addr, empty, 7) != 0) {
+ /* byte no 7 is address type in LE Bluetooth Address OOB data */
+ uint8_t address_type = oob_data->le_bt_dev_addr[6];
+ if (address_type == BLE_ADDR_PUBLIC || address_type == BLE_ADDR_RANDOM) {
+ // bd_addr->address is already reversed, so use it instead of
+ // oob_data->le_bt_dev_addr
+ BTM_SecAddBleDevice(bd_addr->address, NULL, BT_DEVICE_TYPE_BLE, address_type);
+ }
+ }
+
bdstr_t bdstr;
BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
return btif_dm_create_bond(bd_addr, transport);
@@ -3116,29 +3142,36 @@ void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr, tBTA_OOB_DATA *p_has_oob_da
tBTA_LE_AUTH_REQ *p_auth_req)
{
- /* We currently support only Security Manager TK as OOB data for LE transport.
- If it's not present mark no OOB data.
- */
- if (!is_empty_128bit(oob_cb.oob_data.sm_tk))
- {
+ if (!is_empty_128bit(oob_cb.oob_data.le_sc_c) &&
+ !is_empty_128bit(oob_cb.oob_data.le_sc_r)) {
+ /* We have LE SC OOB data */
+
+ /* make sure OOB data is for this particular device */
+ if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
+ *p_auth_req = ((*p_auth_req) | BTM_LE_AUTH_REQ_SC_ONLY);
+ *p_has_oob_data = true;
+ } else {
+ *p_has_oob_data = false;
+ BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+ __func__);
+ }
+ } else if (!is_empty_128bit(oob_cb.oob_data.sm_tk)) {
+ /* We have security manager TK */
+
/* make sure OOB data is for this particular device */
if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
// When using OOB with TK, SC Secure Connections bit must be disabled.
tBTA_LE_AUTH_REQ mask = ~BTM_LE_AUTH_REQ_SC_ONLY;
*p_auth_req = ((*p_auth_req) & mask);
- *p_has_oob_data = TRUE;
- }
- else
- {
- *p_has_oob_data = FALSE;
+ *p_has_oob_data = true;
+ } else {
+ *p_has_oob_data = false;
BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
__func__);
}
- }
- else
- {
- *p_has_oob_data = FALSE;
+ } else {
+ *p_has_oob_data = false;
}
BTIF_TRACE_DEBUG("%s *p_has_oob_data=%d", __func__, *p_has_oob_data);
}
@@ -3643,10 +3676,9 @@ static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type)
bt_bdaddr_t bd_addr;
bdcpy(bd_addr.address, req_oob_type->bd_addr);
-
- /* We currently support only Security Manager TK as OOB data. We already
- * checked if it's present in btif_dm_set_oob_for_le_io_req, but check here
- * again. If it's not present do nothing, pairing will timeout.
+ /* We already checked if OOB data is present in
+ * btif_dm_set_oob_for_le_io_req, but check here again. If it's not present
+ * do nothing, pairing will timeout.
*/
if (is_empty_128bit(oob_cb.oob_data.sm_tk)) {
return;
@@ -3670,6 +3702,44 @@ static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type)
BTM_BleOobDataReply(req_oob_type->bd_addr, 0, 16, oob_cb.oob_data.sm_tk);
}
+
+static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type)
+{
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, req_oob_type->bd_addr);
+
+ /* We already checked if OOB data is present in
+ * btif_dm_set_oob_for_le_io_req, but check here again. If it's not present
+ * do nothing, pairing will timeout.
+ */
+ if (is_empty_128bit(oob_cb.oob_data.le_sc_c) &&
+ is_empty_128bit(oob_cb.oob_data.le_sc_r)) {
+ BTIF_TRACE_WARNING("%s: LE SC OOB data is empty", __func__);
+ return;
+ }
+
+ /* make sure OOB data is for this particular device */
+ if (memcmp(req_oob_type->bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) != 0) {
+ BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address", __func__);
+ return;
+ }
+
+ /* Remote name update */
+ btif_update_remote_properties(req_oob_type->bd_addr , req_oob_type->bd_name,
+ NULL, BT_DEVICE_TYPE_BLE);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = false;
+ pairing_cb.is_le_only = true; //TODO: we can derive classic pairing from this one
+ pairing_cb.is_le_nc = false;
+
+ BTM_BleSecureConnectionOobDataReply(req_oob_type->bd_addr,
+ oob_cb.oob_data.le_sc_c,
+ oob_cb.oob_data.le_sc_r);
+}
+
void btif_dm_update_ble_remote_properties( BD_ADDR bd_addr, BD_NAME bd_name,
tBT_DEVICE_TYPE dev_type)
{
@@ -3815,7 +3885,7 @@ static void btif_stats_add_bond_event(const bt_bdaddr_t *bd_addr,
uint32_t cod = get_cod(bd_addr);
uint64_t ts = event->timestamp.tv_sec * 1000 +
event->timestamp.tv_nsec / 1000000;
- metrics_pair_event(0, ts, cod, device_type);
+ metrics_log_pair_event(0, ts, cod, device_type);
pthread_mutex_unlock(&bond_event_lock);
}
diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c
index 11a0495f2..977d2668d 100644
--- a/btif/src/btif_media_task.c
+++ b/btif/src/btif_media_task.c
@@ -305,6 +305,7 @@ typedef struct {
typedef struct {
uint64_t session_start_us;
+ uint64_t session_end_us;
scheduling_stats_t tx_queue_enqueue_stats;
scheduling_stats_t tx_queue_dequeue_stats;
@@ -322,6 +323,7 @@ typedef struct {
uint64_t tx_queue_last_flushed_us;
size_t tx_queue_total_dropped_messages;
+ size_t tx_queue_max_dropped_messages;
size_t tx_queue_dropouts;
uint64_t tx_queue_last_dropouts_us;
@@ -400,6 +402,7 @@ typedef struct
alarm_t *media_alarm;
alarm_t *decode_alarm;
btif_media_stats_t stats;
+ btif_media_stats_t accumulated_stats;
//#ifdef BTA_AV_SPLIT_A2DP_ENABLED
UINT8 max_bitpool;
UINT8 min_bitpool;
@@ -532,6 +535,68 @@ static uint8_t multicast_query = FALSE;
/*****************************************************************************
** Misc helper functions
*****************************************************************************/
+void btif_a2dp_source_accumulate_scheduling_stats(scheduling_stats_t* src,
+ scheduling_stats_t* dst) {
+ dst->total_updates += src->total_updates;
+ dst->last_update_us = src->last_update_us;
+ dst->overdue_scheduling_count += src->overdue_scheduling_count;
+ dst->total_overdue_scheduling_delta_us += src->total_overdue_scheduling_delta_us;
+ if (src->max_overdue_scheduling_delta_us > dst->max_overdue_scheduling_delta_us) {
+ dst->max_overdue_scheduling_delta_us = src->max_overdue_scheduling_delta_us;
+ }
+ dst->premature_scheduling_count += src->premature_scheduling_count;
+ dst->total_premature_scheduling_delta_us += src->total_premature_scheduling_delta_us;
+ if (src->max_premature_scheduling_delta_us > dst->max_premature_scheduling_delta_us) {
+ dst->max_premature_scheduling_delta_us = src->max_premature_scheduling_delta_us;
+ }
+ dst->exact_scheduling_count += src->exact_scheduling_count;
+ dst->total_scheduling_time_us += src->total_scheduling_time_us;
+}
+
+void btif_a2dp_source_accumulate_stats(btif_media_stats_t* src,
+ btif_media_stats_t* dst) {
+ dst->tx_queue_total_frames += src->tx_queue_total_frames;
+ if (src->tx_queue_max_frames_per_packet > dst->tx_queue_max_frames_per_packet) {
+ dst->tx_queue_max_frames_per_packet = src->tx_queue_max_frames_per_packet;
+ }
+ dst->tx_queue_total_queueing_time_us += src->tx_queue_total_queueing_time_us;
+ if (src->tx_queue_max_queueing_time_us > dst->tx_queue_max_queueing_time_us) {
+ dst->tx_queue_max_queueing_time_us = src->tx_queue_max_queueing_time_us;
+ }
+ dst->tx_queue_total_readbuf_calls += src->tx_queue_total_readbuf_calls;
+ dst->tx_queue_last_readbuf_us = src->tx_queue_last_readbuf_us;
+ dst->tx_queue_total_flushed_messages += src->tx_queue_total_flushed_messages;
+ dst->tx_queue_last_flushed_us = src->tx_queue_last_flushed_us;
+ dst->tx_queue_total_dropped_messages += src->tx_queue_total_dropped_messages;
+ if (src->tx_queue_max_dropped_messages > dst->tx_queue_max_dropped_messages) {
+ dst->tx_queue_max_dropped_messages = src->tx_queue_max_dropped_messages;
+ }
+ dst->tx_queue_dropouts += src->tx_queue_dropouts;
+ dst->tx_queue_last_dropouts_us = src->tx_queue_last_dropouts_us;
+ dst->media_read_total_underflow_bytes +=
+ src->media_read_total_underflow_bytes;
+ dst->media_read_total_underflow_count +=
+ src->media_read_total_underflow_count;
+ dst->media_read_last_underflow_us = src->media_read_last_underflow_us;
+ dst->media_read_total_underrun_bytes += src->media_read_total_underrun_bytes;
+ dst->media_read_total_underflow_count += src->media_read_total_underrun_count;
+ dst->media_read_last_underrun_us = src->media_read_last_underrun_us;
+ dst->media_read_total_expected_frames += src->media_read_total_expected_frames;
+ if (src->media_read_max_expected_frames > dst->media_read_max_expected_frames) {
+ dst->media_read_max_expected_frames = src->media_read_max_expected_frames;
+ }
+ dst->media_read_expected_count += src->media_read_expected_count;
+ dst->media_read_total_limited_frames += src->media_read_total_limited_frames;
+ if (src->media_read_max_limited_frames > dst->media_read_max_limited_frames) {
+ dst->media_read_max_limited_frames = src->media_read_max_limited_frames;
+ }
+ dst->media_read_limited_count += src->media_read_limited_count;
+ btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_enqueue_stats,
+ &dst->tx_queue_enqueue_stats);
+ btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_dequeue_stats,
+ &dst->tx_queue_dequeue_stats);
+ memset(src, 0, sizeof(btif_media_stats_t));
+}
static void update_scheduling_stats(scheduling_stats_t *stats,
uint64_t now_us, uint64_t expected_delta)
@@ -629,7 +694,11 @@ UNUSED_ATTR static const char *dump_media_event(UINT16 event)
static void btm_read_rssi_cb(void *data)
{
- assert(data);
+ if (data == NULL)
+ {
+ LOG_ERROR(LOG_TAG, "%s RSSI request timed out", __func__);
+ return;
+ }
tBTM_RSSI_RESULTS *result = (tBTM_RSSI_RESULTS*)data;
if (result->status != BTM_SUCCESS)
@@ -2032,6 +2101,9 @@ static void btif_media_task_aa_handle_timer(UNUSED_ATTR void *context)
if (alarm_is_scheduled(btif_media_cb.media_alarm))
{
btif_media_send_aa_frame(timestamp_us);
+ update_scheduling_stats(&btif_media_cb.stats.tx_queue_enqueue_stats,
+ timestamp_us,
+ BTIF_SINK_MEDIA_TIME_TICK_MS * 1000);
}
else
{
@@ -2059,7 +2131,6 @@ static void btif_media_thread_init(UNUSED_ATTR void *context) {
APPL_TRACE_IMP(" btif_media_thread_init");
memset(&btif_media_cb, 0, sizeof(btif_media_cb));
- btif_media_cb.stats.session_start_us = time_now_us();
UIPC_Init(NULL);
@@ -2071,6 +2142,7 @@ static void btif_media_thread_init(UNUSED_ATTR void *context) {
raise_priority_a2dp(TASK_HIGH_MEDIA);
media_task_running = MEDIA_TASK_STATE_ON;
+ metrics_log_bluetooth_session_start(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
APPL_TRACE_DEBUG(" btif_media_thread_init complete");
}
@@ -2089,6 +2161,7 @@ static void btif_media_thread_cleanup(UNUSED_ATTR void *context) {
/* Clear media task flag */
media_task_running = MEDIA_TASK_STATE_OFF;
+ metrics_log_bluetooth_session_end(DISCONNECT_REASON_UNKNOWN, 0);
APPL_TRACE_DEBUG(" btif_media_thread_cleanup complete");
}
@@ -2445,6 +2518,15 @@ BOOLEAN btif_media_task_start_aa_req(void)
if (btif_media_cmd_msg_queue != NULL)
fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+
+ memset(&btif_media_cb.stats, 0, sizeof(btif_media_stats_t));
+ // Assign session_start_us to 1 when time_now_us() is 0 to indicate
+ // btif_media_task_start_aa_req() has been called
+ btif_media_cb.stats.session_start_us = time_now_us();
+ if (btif_media_cb.stats.session_start_us == 0) {
+ btif_media_cb.stats.session_start_us = 1;
+ }
+ btif_media_cb.stats.session_end_us = 0;
return TRUE;
}
@@ -2473,8 +2555,14 @@ BOOLEAN btif_media_task_stop_aa_req(void)
* the "cleanup() -> btif_a2dp_stop_media_task()" processing during
* the shutdown of the Bluetooth stack.
*/
- if (btif_media_cmd_msg_queue != NULL)
+ if (btif_media_cmd_msg_queue != NULL) {
fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ }
+
+ btif_media_cb.stats.session_end_us = time_now_us();
+ btif_update_a2dp_metrics();
+ btif_a2dp_source_accumulate_stats(&btif_media_cb.stats,
+ &btif_media_cb.accumulated_stats);
return TRUE;
}
@@ -4232,9 +4320,6 @@ static void btif_media_aa_prep_sbc_2_send(UINT8 nb_frame,
}
/* Enqueue the encoded SBC frame in AA Tx Queue */
- update_scheduling_stats(&btif_media_cb.stats.tx_queue_enqueue_stats,
- timestamp_us,
- BTIF_SINK_MEDIA_TIME_TICK_MS * 1000);
uint8_t done_nb_frame = remain_nb_frame - nb_frame;
remain_nb_frame = nb_frame;
btif_media_cb.stats.tx_queue_total_frames += done_nb_frame;
@@ -4277,6 +4362,10 @@ static void btif_media_aa_prep_2_send(UINT8 nb_frame, uint64_t timestamp_us)
btif_media_cb.stats.tx_queue_last_dropouts_us = timestamp_us;
// Flush all queued buffers...
+ size_t drop_n = fixed_queue_length(btif_media_cb.TxAaQ);
+ if (drop_n > btif_media_cb.stats.tx_queue_max_dropped_messages) {
+ btif_media_cb.stats.tx_queue_max_dropped_messages = drop_n;
+ }
while (fixed_queue_length(btif_media_cb.TxAaQ)) {
btif_media_cb.stats.tx_queue_total_dropped_messages++;
osi_free(fixed_queue_try_dequeue(btif_media_cb.TxAaQ));
@@ -4954,8 +5043,10 @@ void dump_codec_info(unsigned char *p_codec)
void btif_debug_a2dp_dump(int fd)
{
+ btif_a2dp_source_accumulate_stats(&btif_media_cb.stats,
+ &btif_media_cb.accumulated_stats);
uint64_t now_us = time_now_us();
- btif_media_stats_t *stats = &btif_media_cb.stats;
+ btif_media_stats_t *stats = &btif_media_cb.accumulated_stats;
scheduling_stats_t *enqueue_stats = &stats->tx_queue_enqueue_stats;
scheduling_stats_t *dequeue_stats = &stats->tx_queue_dequeue_stats;
size_t ave_size;
@@ -5089,52 +5180,51 @@ void btif_debug_a2dp_dump(int fd)
void btif_update_a2dp_metrics(void)
{
- uint64_t now_us = time_now_us();
- btif_media_stats_t *stats = &btif_media_cb.stats;
- scheduling_stats_t *dequeue_stats = &stats->tx_queue_dequeue_stats;
- int32_t media_timer_min_ms = 0;
- int32_t media_timer_max_ms = 0;
- int32_t media_timer_avg_ms = 0;
- int32_t buffer_overruns_max_count = 0;
- int32_t buffer_overruns_total = 0;
- float buffer_underruns_average = 0.0;
- int32_t buffer_underruns_count = 0;
-
- int64_t session_duration_sec =
- (now_us - stats->session_start_us) / (1000 * 1000);
-
- /* NOTE: Disconnect reason is unused */
- const char *disconnect_reason = NULL;
- uint32_t device_class = BTM_COD_MAJOR_AUDIO;
-
- if (dequeue_stats->total_updates > 1) {
- media_timer_min_ms = BTIF_SINK_MEDIA_TIME_TICK_MS -
- (dequeue_stats->max_premature_scheduling_delta_us / 1000);
- media_timer_max_ms = BTIF_SINK_MEDIA_TIME_TICK_MS +
- (dequeue_stats->max_overdue_scheduling_delta_us / 1000);
-
- uint64_t total_scheduling_count =
- dequeue_stats->overdue_scheduling_count +
- dequeue_stats->premature_scheduling_count +
- dequeue_stats->exact_scheduling_count;
- if (total_scheduling_count > 0) {
- media_timer_avg_ms = dequeue_stats->total_scheduling_time_us /
- (1000 * total_scheduling_count);
+ btif_media_stats_t* stats = &btif_media_cb.stats;
+ scheduling_stats_t* enqueue_stats = &stats->tx_queue_enqueue_stats;
+ A2dpSessionMetrics_t metrics;
+ metrics.media_timer_min_ms = -1;
+ metrics.media_timer_max_ms = -1;
+ metrics.media_timer_avg_ms = -1;
+ metrics.total_scheduling_count = -1;
+ metrics.buffer_overruns_max_count = -1;
+ metrics.buffer_overruns_total = -1;
+ metrics.buffer_underruns_average = -1.0;
+ metrics.buffer_underruns_count = -1;
+ metrics.audio_duration_ms = -1;
+ // session_start_us is 0 when btif_media_task_start_aa_req() is not called
+ // mark the metric duration as invalid (-1) in this case
+ if (stats->session_start_us != 0) {
+ int64_t session_end_us = stats->session_end_us == 0
+ ? time_now_us()
+ : stats->session_end_us;
+ metrics.audio_duration_ms = (session_end_us - stats->session_start_us) / 1000;
+ }
+ if (enqueue_stats->total_updates > 1) {
+ metrics.media_timer_min_ms = BTIF_SINK_MEDIA_TIME_TICK_MS -
+ (enqueue_stats->max_premature_scheduling_delta_us / 1000);
+ metrics.media_timer_max_ms = BTIF_SINK_MEDIA_TIME_TICK_MS +
+ (enqueue_stats->max_overdue_scheduling_delta_us / 1000);
+ metrics.total_scheduling_count
+ = enqueue_stats->overdue_scheduling_count +
+ enqueue_stats->premature_scheduling_count +
+ enqueue_stats->exact_scheduling_count;
+ if (metrics.total_scheduling_count > 0) {
+ metrics.media_timer_avg_ms = enqueue_stats->total_scheduling_time_us /
+ (1000 * metrics.total_scheduling_count);
}
-
- buffer_overruns_max_count = stats->media_read_max_expected_frames;
- buffer_overruns_total = stats->tx_queue_total_dropped_messages;
- buffer_underruns_count = stats->media_read_total_underflow_count +
- stats->media_read_total_underrun_count;
- if (buffer_underruns_count > 0) {
- buffer_underruns_average =
- (stats->media_read_total_underflow_bytes + stats->media_read_total_underrun_bytes) / buffer_underruns_count;
+ metrics.buffer_overruns_max_count = stats->tx_queue_max_dropped_messages;
+ metrics.buffer_overruns_total = stats->tx_queue_total_dropped_messages;
+ metrics.buffer_underruns_count =
+ stats->media_read_total_underflow_count +
+ stats->media_read_total_underrun_count;
+ metrics.buffer_underruns_average = 0;
+ if (metrics.buffer_underruns_count > 0) {
+ metrics.buffer_underruns_average =
+ (stats->media_read_total_underflow_bytes +
+ stats->media_read_total_underrun_bytes) /
+ metrics.buffer_underruns_count;
}
}
-
- metrics_a2dp_session(session_duration_sec, disconnect_reason, device_class,
- media_timer_min_ms, media_timer_max_ms,
- media_timer_avg_ms, buffer_overruns_max_count,
- buffer_overruns_total, buffer_underruns_average,
- buffer_underruns_count);
+ metrics_log_a2dp_session(&metrics);
}
diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
index 36bafa981..20c519c05 100644
--- a/btif/src/btif_storage.c
+++ b/btif/src/btif_storage.c
@@ -1450,6 +1450,21 @@ bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr)
/*******************************************************************************
**
+** Function btif_storage_get_num_bonded_devices
+**
+** Description BTIF storage API - Gets the number of bonded devices
+**
+** Returns the number of bonded devices
+**
+*******************************************************************************/
+int btif_storage_get_num_bonded_devices(void) {
+ btif_bonded_devices_t bonded_devices;
+ btif_in_fetch_bonded_devices(&bonded_devices, 0);
+ return bonded_devices.num_devices;
+}
+
+/*******************************************************************************
+**
** Function btif_storage_read_hl_apps_cb
**
** Description BTIF storage API - Read HL application control block from NVRAM
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index 4a99ef98b..03628235d 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -9,7 +9,7 @@ BtSnoopLogOutput=false
BtSnoopExtDump=false
# BtSnoop log output file
-BtSnoopFileName=/sdcard/btsnoop_hci.log
+BtSnoopFileName=/data/misc/bluetooth/logs/btsnoop_hci.log
# Preserve existing BtSnoop log before overwriting
BtSnoopSaveLog=false
diff --git a/hci/src/btsnoop.c b/hci/src/btsnoop.c
index edffa2022..0ef6fe006 100644
--- a/hci/src/btsnoop.c
+++ b/hci/src/btsnoop.c
@@ -207,12 +207,15 @@ static void update_logging() {
LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, log_path, last_log_path, strerror(errno));
}
+ mode_t prevmask = umask(0);
logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
if (logfile_fd == INVALID_FD) {
LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path, strerror(errno));
is_logging = false;
+ umask(prevmask);
return;
}
+ umask(prevmask);
write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
} else {
diff --git a/include/bt_target.h b/include/bt_target.h
index 0b4880ade..19d2cceee 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -1687,4 +1687,15 @@ The maximum number of payload octets that the local device can receive in a sing
#include "bt_trace.h"
+/******************************************************************************
+**
+** Wear
+**
+******************************************************************************/
+
+/* Enable/disable LE IO capability overriding to no-input-no-output on first bond */
+#ifndef WEAR_LE_IO_CAP_OVERRIDE
+#define WEAR_LE_IO_CAP_OVERRIDE FALSE
+#endif
+
#endif /* BT_TARGET_H */
diff --git a/main/stack_config.c b/main/stack_config.c
index 7a894c960..f12a78900 100644
--- a/main/stack_config.c
+++ b/main/stack_config.c
@@ -82,7 +82,8 @@ EXPORT_SYMBOL const module_t stack_config_module = {
// Interface functions
static const char *get_btsnoop_log_path(void) {
- return config_get_string(config, CONFIG_DEFAULT_SECTION, BTSNOOP_LOG_PATH_KEY, "/data/misc/bluedroid/btsnoop_hci.log");
+ return config_get_string(config, CONFIG_DEFAULT_SECTION, BTSNOOP_LOG_PATH_KEY,
+ "/data/misc/bluetooth/logs/btsnoop_hci.log");
}
static bool get_btsnoop_turned_on(void) {
diff --git a/osi/Android.mk b/osi/Android.mk
index 4d372ec60..d1937d1c2 100644
--- a/osi/Android.mk
+++ b/osi/Android.mk
@@ -67,7 +67,9 @@ btosiCommonTestSrc := \
./test/future_test.cpp \
./test/hash_map_test.cpp \
./test/hash_map_utils_test.cpp \
+ ./test/leaky_bonded_queue_test.cpp \
./test/list_test.cpp \
+ ./test/metrics_test.cpp \
./test/properties_test.cpp \
./test/rand_test.cpp \
./test/reactor_test.cpp \
@@ -78,6 +80,7 @@ btosiCommonTestSrc := \
btosiCommonIncludes := \
$(LOCAL_PATH)/.. \
+ $(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../utils/include \
$(LOCAL_PATH)/../stack/include \
$(bluetooth_C_INCLUDES)
@@ -166,7 +169,7 @@ LOCAL_SRC_FILES := $(btosiCommonTestSrc)
LOCAL_MODULE := net_test_osi
LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := libc liblog libprotobuf-cpp-full libchrome libcutils
-LOCAL_STATIC_LIBRARIES := libosi libbt-protos
+LOCAL_STATIC_LIBRARIES := libosi libbt-protos libgmock
LOCAL_CFLAGS += $(bluetooth_CFLAGS)
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
@@ -184,7 +187,7 @@ LOCAL_LDLIBS := -lrt -lpthread
LOCAL_MODULE := net_test_osi
LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := liblog libprotobuf-cpp-full libchrome
-LOCAL_STATIC_LIBRARIES := libosi-host libbt-protos
+LOCAL_STATIC_LIBRARIES := libosi-host libbt-protos libgmock_host
LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DOS_GENERIC
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
diff --git a/osi/BUILD.gn b/osi/BUILD.gn
index ed91fb1cd..80d7d3bf6 100644
--- a/osi/BUILD.gn
+++ b/osi/BUILD.gn
@@ -71,7 +71,9 @@ executable("net_test_osi") {
"test/future_test.cpp",
"test/hash_map_test.cpp",
"test/hash_map_utils_test.cpp",
+ "test/leaky_bonded_queue_test.cpp",
"test/list_test.cpp",
+ "test/metrics_test.cpp",
"test/properties_test.cpp",
"test/rand_test.cpp",
"test/reactor_test.cpp",
@@ -88,6 +90,8 @@ executable("net_test_osi") {
deps = [
"//osi",
"//third_party/googletest:gtest_main",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
]
libs = [
diff --git a/osi/include/leaky_bonded_queue.h b/osi/include/leaky_bonded_queue.h
new file mode 100644
index 000000000..8259cdcac
--- /dev/null
+++ b/osi/include/leaky_bonded_queue.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 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 <memory>
+#include <mutex>
+#include <queue>
+
+namespace system_bt_osi {
+
+/*
+ * LeakyBondedQueue<T>
+ *
+ * - LeakyLondedQueue<T> is a fixed size queue that leaks oldest item when
+ * reaching its capacity. This is useful in creating memory bonded data
+ * structure where freshness is more important than full coverage.
+ * - The queue is protected by a simple mutex and is thread-safe, although
+ * improvements could be made to lock enqueue and dequeue separately, it
+ * is not implemented at this moment due to lack of demand
+ * - The queue uses unique_ptr to automatically free its content when it is
+ * destructed. It is the user's responsibility to implement T's destructor
+ * correctly.
+ *
+ */
+template <class T>
+class LeakyBondedQueue {
+ public:
+ LeakyBondedQueue(size_t capacity);
+ /* Default destructor
+ *
+ * Call Clear() and free the queue structure itself
+ */
+ ~LeakyBondedQueue();
+ /*
+ * Add item NEW_ITEM to the underlining queue. If the queue is full, pop
+ * the oldest item
+ */
+ void Enqueue(T* new_item);
+ /*
+ * Add item NEW_ITEM to the underlining queue. If the queue is full, dequeue
+ * the oldest item and returns it to the caller. Return nullptr otherwise.
+ */
+ T* EnqueueWithPop(T* new_item);
+ /*
+ * Dequeues the oldest item from the queue. Return nullptr if queue is empty
+ */
+ T* Dequeue();
+ /*
+ * Returns the length of queue
+ */
+ size_t Length();
+ /*
+ * Returns the defined capacity of the queue
+ */
+ size_t Capacity();
+ /*
+ * Returns whether the queue is empty
+ */
+ bool Empty();
+ /*
+ * Pops all items from the queue
+ */
+ void Clear();
+
+ private:
+ // Put item in unique_ptr so that they get freed automatically when poped or
+ // when queue_ is freed
+ std::queue<std::unique_ptr<T>> queue_;
+ std::mutex lock_;
+ size_t capacity_;
+};
+
+/*
+* Definitions must be in the header for template classes
+*/
+
+template <class T>
+LeakyBondedQueue<T>::LeakyBondedQueue(size_t capacity) {
+ capacity_ = capacity;
+}
+
+template <class T>
+LeakyBondedQueue<T>::~LeakyBondedQueue() {}
+
+template <class T>
+void LeakyBondedQueue<T>::Enqueue(T* new_item) {
+ std::lock_guard<std::mutex> lock(lock_);
+ if ((queue_.size() + 1) > capacity_) {
+ queue_.pop();
+ }
+ std::unique_ptr<T> item_ptr(new_item);
+ queue_.push(std::move(item_ptr));
+}
+
+template <class T>
+T* LeakyBondedQueue<T>::EnqueueWithPop(T* new_item) {
+ std::lock_guard<std::mutex> lock(lock_);
+ T* old_item = nullptr;
+ if ((queue_.size() + 1) > capacity_) {
+ std::unique_ptr<T> item = std::move(queue_.front());
+ queue_.pop();
+ old_item = item.release();
+ }
+ std::unique_ptr<T> item_ptr(new_item);
+ queue_.push(std::move(item_ptr));
+ return old_item;
+}
+
+template <class T>
+T* LeakyBondedQueue<T>::Dequeue() {
+ std::lock_guard<std::mutex> lock(lock_);
+ std::unique_ptr<T> item = std::move(queue_.front());
+ queue_.pop();
+ return item.release();
+}
+
+template <class T>
+void LeakyBondedQueue<T>::Clear() {
+ std::lock_guard<std::mutex> lock(lock_);
+ while (!queue_.empty()) {
+ // unique_ptr does not need to be freed
+ queue_.pop();
+ }
+}
+
+template <class T>
+size_t LeakyBondedQueue<T>::Length() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return queue_.size();
+}
+
+template <class T>
+size_t LeakyBondedQueue<T>::Capacity() {
+ return capacity_;
+}
+
+template <class T>
+bool LeakyBondedQueue<T>::Empty() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return queue_.empty();
+}
+
+} // namespace system_bt_osi
diff --git a/osi/include/metrics.h b/osi/include/metrics.h
index 4855301af..4ef12b20d 100644
--- a/osi/include/metrics.h
+++ b/osi/include/metrics.h
@@ -20,6 +20,11 @@
#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Typedefs to hide protobuf definition to the rest of stack
+
typedef enum {
DEVICE_TYPE_UNKNOWN,
DEVICE_TYPE_BREDR,
@@ -27,26 +32,12 @@ typedef enum {
DEVICE_TYPE_DUMO,
} device_type_t;
-// Record a pairing event at Unix epoch time |timestamp_ms|
-// |device_class| and |device_type| denote the type of device paired.
-// |disconnect_reason| is the HCI reason for pairing disconnection,
-// see stack/include/hcidefs.h
-void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
- uint32_t device_class, device_type_t device_type);
-
typedef enum {
WAKE_EVENT_UNKNOWN,
WAKE_EVENT_ACQUIRED,
WAKE_EVENT_RELEASED,
} wake_event_type_t;
-// Record a wake event at Unix epoch time |timestamp_ms|.
-// |type| specifies whether it was acquired or relased,
-// |requestor| if provided is the service requesting the wake lock.
-// |name| is the name of the wake lock held.
-void metrics_wake_event(wake_event_type_t type, const char *requestor,
- const char *name, uint64_t timestamp_ms);
-
typedef enum {
SCAN_TYPE_UNKNOWN,
SCAN_TECH_TYPE_LE,
@@ -54,44 +45,52 @@ typedef enum {
SCAN_TECH_TYPE_BOTH,
} scan_tech_t;
-// Record a scan event at Unix epoch time |timestamp_ms|.
-// |start| is true if this is the beginning of the scan.
-// |initiator| is a unique ID identifying the app starting the scan.
-// |type| is whether the scan reports BR/EDR, LE, or both.
-// |results| is the number of results to be reported.
-void metrics_scan_event(bool start, const char *initator, scan_tech_t type,
- uint32_t results, uint64_t timestamp_ms);
-
-// Record A2DP session information.
-// |session_duration_sec| is the session duration (in seconds).
-// |device_class| is the device class of the paired device.
-// |media_timer_min_ms| is the minimum scheduled time (in milliseconds)
-// of the media timer.
-// |media_timer_max_ms| is the maximum scheduled time (in milliseconds)
-// of the media timer.
-// |media_timer_avg_ms| is the average scheduled time (in milliseconds)
-// of the media timer.
-// |buffer_overruns_max_count| - TODO - not clear what this is.
-// |buffer_overruns_total| is the number of times the media buffer with
-// audio data has overrun.
-// |buffer_underruns_average| - TODO - not clear what this is.
-// |buffer_underruns_count| is the number of times there was no enough
-// audio data to add to the media buffer.
-void metrics_a2dp_session(int64_t session_duration_sec,
- const char *disconnect_reason,
- uint32_t device_class,
- int32_t media_timer_min_ms,
- int32_t media_timer_max_ms,
- int32_t media_timer_avg_ms,
- int32_t buffer_overruns_max_count,
- int32_t buffer_overruns_total,
- float buffer_underruns_average,
- int32_t buffer_underruns_count);
-
-// Writes the metrics, in packed protobuf format, into the descriptor |fd|.
-// If |clear| is true, metrics events are cleared afterwards.
-void metrics_write(int fd, bool clear);
-
-// Writes the metrics, in human-readable protobuf format, into the descriptor
-// |fd|. If |clear| is true, metrics events are cleared afterwards.
-void metrics_print(int fd, bool clear);
+typedef enum {
+ CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
+ CONNECTION_TECHNOLOGY_TYPE_LE,
+ CONNECTION_TECHNOLOGY_TYPE_BREDR,
+} connection_tech_t;
+
+typedef enum {
+ DISCONNECT_REASON_UNKNOWN,
+ DISCONNECT_REASON_METRICS_DUMP,
+ DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
+} disconnect_reason_t;
+
+typedef struct {
+ int64_t audio_duration_ms;
+ int32_t media_timer_min_ms;
+ int32_t media_timer_max_ms;
+ int32_t media_timer_avg_ms;
+ int64_t total_scheduling_count;
+ int32_t buffer_overruns_max_count;
+ int32_t buffer_overruns_total;
+ float buffer_underruns_average;
+ int32_t buffer_underruns_count;
+} A2dpSessionMetrics_t;
+
+void metrics_log_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type);
+
+void metrics_log_wake_event(wake_event_type_t type, const char* requestor,
+ const char* name, uint64_t timestamp_ms);
+
+void metrics_log_scan_event(bool start, const char* initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms);
+
+void metrics_log_bluetooth_session_start(connection_tech_t connection_tech_type,
+ uint64_t timestamp_ms);
+
+void metrics_log_bluetooth_session_end(disconnect_reason_t disconnect_reason,
+ uint64_t timestamp_ms);
+
+void metrics_log_bluetooth_session_device_info(uint32_t device_class,
+ device_type_t device_type);
+
+void metrics_log_a2dp_session(A2dpSessionMetrics_t* metrics);
+
+void metrics_write_base64(int fd, bool clear);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/osi/include/metrics_cpp.h b/osi/include/metrics_cpp.h
new file mode 100644
index 000000000..dcba21c9b
--- /dev/null
+++ b/osi/include/metrics_cpp.h
@@ -0,0 +1,230 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 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 <stdint.h>
+#include <memory>
+#include <string>
+
+namespace system_bt_osi {
+
+/* Values of A2DP metrics that we care about
+ *
+ * audio_duration_ms : sum of audio duration (in milliseconds).
+ * device_class: device class of the paired device.
+ * media_timer_min_ms : minimum scheduled time (in milliseconds)
+ * of the media timer.
+ * media_timer_max_ms: maximum scheduled time (in milliseconds)
+ * of the media timer.
+ * media_timer_avg_ms: average scheduled time (in milliseconds)
+ * of the media timer.
+ * buffer_overruns_max_count: TODO - not clear what this is.
+ * buffer_overruns_total : number of times the media buffer with
+ * audio data has overrun
+ * buffer_underruns_average: TODO - not clear what this is.
+ * buffer_underruns_count: number of times there was no enough
+ * audio data to add to the media buffer.
+ * NOTE: Negative values are invalid
+*/
+class A2dpSessionMetrics {
+ public:
+ A2dpSessionMetrics() {}
+
+ /*
+ * Update the metrics value in the current metrics object using the metrics
+ * objects supplied
+ */
+ void Update(const A2dpSessionMetrics& metrics);
+
+ /*
+ * Compare whether two metrics objects are equal
+ */
+ bool operator==(const A2dpSessionMetrics& rhs) const;
+
+ /*
+ * Initialize all values to -1 which is invalid in order to make a distinction
+ * between 0 and invalid values
+ */
+ int64_t audio_duration_ms = -1;
+ int32_t media_timer_min_ms = -1;
+ int32_t media_timer_max_ms = -1;
+ int32_t media_timer_avg_ms = -1;
+ int64_t total_scheduling_count = -1;
+ int32_t buffer_overruns_max_count = -1;
+ int32_t buffer_overruns_total = -1;
+ float buffer_underruns_average = -1;
+ int32_t buffer_underruns_count = -1;
+};
+
+class BluetoothMetricsLogger {
+ public:
+ static BluetoothMetricsLogger* GetInstance() {
+ static BluetoothMetricsLogger* instance = new BluetoothMetricsLogger();
+ return instance;
+ }
+
+ /*
+ * Record a pairing event
+ *
+ * Parameters:
+ * timestamp_ms: Unix epoch time in milliseconds
+ * device_class: class of remote device
+ * device_type: type of remote device
+ * disconnect_reason: HCI reason for pairing disconnection.
+ * See: stack/include/hcidefs.h
+ */
+ void LogPairEvent(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type);
+
+ /*
+ * Record a wake event
+ *
+ * Parameters:
+ * timestamp_ms: Unix epoch time in milliseconds
+ * type: whether it was acquired or released
+ * requestor: if provided is the service requesting the wake lock
+ * name: the name of the wake lock held
+ */
+ void LogWakeEvent(wake_event_type_t type, const std::string& requestor,
+ const std::string& name, uint64_t timestamp_ms);
+
+ /*
+ * Record a scan event
+ *
+ * Parameters
+ * timestamp_ms : Unix epoch time in milliseconds
+ * start : true if this is the beginning of the scan
+ * initiator: a unique ID identifying the app starting the scan
+ * type: whether the scan reports BR/EDR, LE, or both.
+ * results: number of results to be reported.
+ */
+ void LogScanEvent(bool start, const std::string& initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms);
+
+ /*
+ * Start logging a Bluetooth session
+ *
+ * A Bluetooth session is defined a a connection between this device and
+ * another remote device which may include multiple profiles and protocols
+ *
+ * Only one Bluetooth session can exist at one time. Calling this method twice
+ * without LogBluetoothSessionEnd will result in logging a premature end of
+ * current Bluetooth session
+ *
+ * Parameters:
+ * connection_tech_type : type of connection technology
+ * timestamp_ms : the timestamp for session start, 0 means now
+ *
+ */
+ void LogBluetoothSessionStart(connection_tech_t connection_tech_type,
+ uint64_t timestamp_ms);
+
+ /*
+ * Stop logging a Bluetooth session and pushes it to the log queue
+ *
+ * If no Bluetooth session exist, this method exits immediately
+ *
+ * Parameters:
+ * disconnect_reason : A string representation of disconnect reason
+ * timestamp_ms : the timestamp of session end, 0 means now
+ *
+ */
+ void LogBluetoothSessionEnd(disconnect_reason_t disconnect_reason,
+ uint64_t timestamp_ms);
+
+ /*
+ * Log information about remote device in a current Bluetooth session
+ *
+ * If a Bluetooth session does not exist, create one with default parameter
+ * and timestamp now
+ *
+ * Parameters:
+ * device_class : device_class defined in btm_api_types.h
+ * device_type : type of remote device
+ */
+ void LogBluetoothSessionDeviceInfo(uint32_t device_class,
+ device_type_t device_type);
+
+ /*
+ * Log A2DP Audio Session Information
+ *
+ * - Repeated calls to this method will override previous metrics if in the
+ * same Bluetooth connection
+ * - If a Bluetooth session does not exist, create one with default parameter
+ * and timestamp now
+ *
+ * Parameters:
+ * a2dp_session_metrics - pointer to struct holding a2dp stats
+ *
+ */
+ void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
+
+ /*
+ * Writes the metrics, in base64 protobuf format, into the descriptor FD
+ * If CLEAR is true, metrics events are cleared afterwards.
+ */
+ void WriteBase64(int fd, bool clear);
+ void WriteBase64String(std::string* serialized, bool clear);
+ void WriteString(std::string* serialized, bool clear);
+
+ /*
+ * Reset the metrics logger by cleaning up its staging queues and existing
+ * protobuf objects.
+ */
+ void Reset();
+
+ /*
+ * Maximum number of log entries for each session or event
+ */
+ static const size_t kMaxNumBluetoothSession = 50;
+ static const size_t kMaxNumPairEvent = 50;
+ static const size_t kMaxNumWakeEvent = 1000;
+ static const size_t kMaxNumScanEvent = 50;
+
+ private:
+ BluetoothMetricsLogger();
+
+ /*
+ * When a Bluetooth session is on and the user initiates a metrics dump, we
+ * need to be able to upload whatever we have first. This method breaks the
+ * ongoing Bluetooth session into two sessions with the previous one labeled
+ * as "METRICS_DUMP" for the disconnect reason.
+ */
+ void CutoffSession();
+
+ /*
+ * Build the internal metrics object using information gathered
+ */
+ void Build();
+
+ /*
+ * Reset objects related to current Bluetooth session
+ */
+ void ResetSession();
+
+ /*
+ * Reset the underlining BluetoothLog object
+ */
+ void ResetLog();
+
+ /*
+ * PIMPL style implementation to hide internal dependencies
+ */
+ struct impl;
+ std::unique_ptr<impl> const pimpl_;
+};
+
+} // namespace system_bt_osi
diff --git a/osi/src/metrics.cpp b/osi/src/metrics.cpp
index 064f99e78..9a919836f 100644
--- a/osi/src/metrics.cpp
+++ b/osi/src/metrics.cpp
@@ -15,28 +15,37 @@
* limitations under the License.
*
******************************************************************************/
-
-
#define LOG_TAG "bt_osi_metrics"
-extern "C" {
-#include "osi/include/metrics.h"
+#include <unistd.h>
+#include <algorithm>
+#include <cerrno>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <mutex>
-#include <errno.h>
+#include <base/base64.h>
+#include <base/logging.h>
+#include "osi/include/leaky_bonded_queue.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-}
+#include "stack/include/btm_api.h"
#include "osi/src/protos/bluetooth.pb.h"
-#include <base/base64.h>
-#include <google/protobuf/text_format.h>
-#include <mutex>
+#include "osi/include/metrics.h"
+#include "osi/include/metrics_cpp.h"
+
+namespace system_bt_osi {
using clearcut::connectivity::A2DPSession;
using clearcut::connectivity::BluetoothLog;
using clearcut::connectivity::BluetoothSession;
+using clearcut::connectivity::BluetoothSession_ConnectionTechnologyType;
+using clearcut::connectivity::BluetoothSession_DisconnectReasonType;
using clearcut::connectivity::DeviceInfo;
using clearcut::connectivity::DeviceInfo_DeviceType;
using clearcut::connectivity::PairEvent;
@@ -46,156 +55,378 @@ using clearcut::connectivity::ScanEvent_ScanEventType;
using clearcut::connectivity::WakeEvent;
using clearcut::connectivity::WakeEvent_WakeEventType;
-BluetoothLog *pending;
-std::mutex log_lock;
+uint64_t metrics_time_get_os_boottime_us(void) {
+ struct timespec ts_now;
+ clock_gettime(CLOCK_BOOTTIME, &ts_now);
-static void lazy_initialize(void) {
- if (pending == nullptr) {
- pending = BluetoothLog::default_instance().New();
- }
+ return ((uint64_t)ts_now.tv_sec * 1000000L) +
+ ((uint64_t)ts_now.tv_nsec / 1000);
}
-void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
- uint32_t device_class, device_type_t device_type) {
- std::lock_guard<std::mutex> lock(log_lock);
- lazy_initialize();
-
- PairEvent *event = pending->add_pair_event();
-
- DeviceInfo *info = event->mutable_device_paired_with();
-
- info->set_device_class(device_class);
-
- DeviceInfo_DeviceType type = DeviceInfo::DEVICE_TYPE_UNKNOWN;
-
- if (device_type == DEVICE_TYPE_BREDR)
- type = DeviceInfo::DEVICE_TYPE_BREDR;
- if (device_type == DEVICE_TYPE_LE)
- type = DeviceInfo::DEVICE_TYPE_LE;
- if (device_type == DEVICE_TYPE_DUMO)
- type = DeviceInfo::DEVICE_TYPE_DUMO;
+/*
+ * Get current OS boot time in millisecond
+ */
+static int64_t time_get_os_boottime_ms(void) {
+ return metrics_time_get_os_boottime_us() / 1000;
+}
- info->set_device_type(type);
+static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
- event->set_disconnect_reason(disconnect_reason);
+static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
- event->set_event_time_millis(timestamp_ms);
+void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
+ if (metrics.audio_duration_ms >= 0) {
+ audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
+ audio_duration_ms += metrics.audio_duration_ms;
+ }
+ if (metrics.media_timer_min_ms >= 0) {
+ if (media_timer_min_ms < 0) {
+ media_timer_min_ms = metrics.media_timer_min_ms;
+ } else {
+ media_timer_min_ms =
+ std::min(media_timer_min_ms, metrics.media_timer_min_ms);
+ }
+ }
+ if (metrics.media_timer_max_ms >= 0) {
+ media_timer_max_ms =
+ std::max(media_timer_max_ms, metrics.media_timer_max_ms);
+ }
+ if (metrics.media_timer_avg_ms >= 0 && metrics.total_scheduling_count >= 0) {
+ if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
+ media_timer_avg_ms = metrics.media_timer_avg_ms;
+ total_scheduling_count = metrics.total_scheduling_count;
+ } else {
+ media_timer_avg_ms = combine_averages(
+ media_timer_avg_ms, total_scheduling_count,
+ metrics.media_timer_avg_ms, metrics.total_scheduling_count);
+ total_scheduling_count += metrics.total_scheduling_count;
+ }
+ }
+ if (metrics.buffer_overruns_max_count >= 0) {
+ buffer_overruns_max_count =
+ std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
+ }
+ if (metrics.buffer_overruns_total >= 0) {
+ buffer_overruns_total =
+ std::max(static_cast<int32_t>(0), buffer_overruns_total);
+ buffer_overruns_total += metrics.buffer_overruns_total;
+ }
+ if (metrics.buffer_underruns_average >= 0 &&
+ metrics.buffer_underruns_count >= 0) {
+ if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
+ buffer_underruns_average = metrics.buffer_underruns_average;
+ buffer_underruns_count = metrics.buffer_underruns_count;
+ } else {
+ buffer_underruns_average = combine_averages(
+ buffer_underruns_average, buffer_underruns_count,
+ metrics.buffer_underruns_average, metrics.buffer_underruns_count);
+ buffer_underruns_count += metrics.buffer_underruns_count;
+ }
+ }
}
-void metrics_wake_event(wake_event_type_t type, const char *requestor,
- const char *name, uint64_t timestamp_ms) {
- std::lock_guard<std::mutex> lock(log_lock);
- lazy_initialize();
+bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
+ return audio_duration_ms == rhs.audio_duration_ms &&
+ media_timer_min_ms == rhs.media_timer_min_ms &&
+ media_timer_max_ms == rhs.media_timer_max_ms &&
+ media_timer_avg_ms == rhs.media_timer_avg_ms &&
+ total_scheduling_count == rhs.total_scheduling_count &&
+ buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
+ buffer_overruns_total == rhs.buffer_overruns_total &&
+ buffer_underruns_average == rhs.buffer_underruns_average &&
+ buffer_underruns_count == rhs.buffer_underruns_count;
+}
- WakeEvent *event = pending->add_wake_event();
+static DeviceInfo_DeviceType get_device_type(device_type_t type) {
+ switch (type) {
+ case DEVICE_TYPE_BREDR:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR;
+ case DEVICE_TYPE_LE:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_LE;
+ case DEVICE_TYPE_DUMO:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_DUMO;
+ case DEVICE_TYPE_UNKNOWN:
+ default:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_UNKNOWN;
+ }
+}
- WakeEvent_WakeEventType waketype = WakeEvent::UNKNOWN;
+static BluetoothSession_ConnectionTechnologyType get_connection_tech_type(
+ connection_tech_t type) {
+ switch (type) {
+ case CONNECTION_TECHNOLOGY_TYPE_LE:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE;
+ case CONNECTION_TECHNOLOGY_TYPE_BREDR:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR;
+ case CONNECTION_TECHNOLOGY_TYPE_UNKNOWN:
+ default:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN;
+ }
+}
- if (type == WAKE_EVENT_ACQUIRED)
- waketype = WakeEvent::ACQUIRED;
- if (type == WAKE_EVENT_RELEASED)
- waketype = WakeEvent::RELEASED;
+static ScanEvent_ScanTechnologyType get_scan_tech_type(scan_tech_t type) {
+ switch (type) {
+ case SCAN_TECH_TYPE_LE:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_LE;
+ case SCAN_TECH_TYPE_BREDR:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR;
+ case SCAN_TECH_TYPE_BOTH:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BOTH;
+ case SCAN_TYPE_UNKNOWN:
+ default:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TYPE_UNKNOWN;
+ }
+}
- event->set_wake_event_type(waketype);
+static WakeEvent_WakeEventType get_wake_event_type(wake_event_type_t type) {
+ switch (type) {
+ case WAKE_EVENT_ACQUIRED:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED;
+ case WAKE_EVENT_RELEASED:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED;
+ case WAKE_EVENT_UNKNOWN:
+ default:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_UNKNOWN;
+ }
+}
- if (requestor)
- event->set_requestor(requestor);
+static BluetoothSession_DisconnectReasonType get_disconnect_reason_type(
+ disconnect_reason_t type) {
+ switch (type) {
+ case DISCONNECT_REASON_METRICS_DUMP:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP;
+ case DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS;
+ case DISCONNECT_REASON_UNKNOWN:
+ default:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN;
+ }
+}
- if (name)
- event->set_name(name);
+struct BluetoothMetricsLogger::impl {
+ impl(size_t max_bluetooth_session, size_t max_pair_event,
+ size_t max_wake_event, size_t max_scan_event)
+ : bt_session_queue_(
+ new LeakyBondedQueue<BluetoothSession>(max_bluetooth_session)),
+ pair_event_queue_(new LeakyBondedQueue<PairEvent>(max_pair_event)),
+ wake_event_queue_(new LeakyBondedQueue<WakeEvent>(max_wake_event)),
+ scan_event_queue_(new LeakyBondedQueue<ScanEvent>(max_scan_event)) {
+ bluetooth_log_ = BluetoothLog::default_instance().New();
+ bluetooth_session_ = nullptr;
+ bluetooth_session_start_time_ms_ = 0;
+ a2dp_session_metrics_ = A2dpSessionMetrics();
+ }
+ /* Bluetooth log lock protected */
+ BluetoothLog* bluetooth_log_;
+ std::recursive_mutex bluetooth_log_lock_;
+ /* End Bluetooth log lock protected */
+ /* Bluetooth session lock protected */
+ BluetoothSession* bluetooth_session_;
+ uint64_t bluetooth_session_start_time_ms_;
+ A2dpSessionMetrics a2dp_session_metrics_;
+ std::recursive_mutex bluetooth_session_lock_;
+ /* End bluetooth session lock protected */
+ std::unique_ptr<LeakyBondedQueue<BluetoothSession>> bt_session_queue_;
+ std::unique_ptr<LeakyBondedQueue<PairEvent>> pair_event_queue_;
+ std::unique_ptr<LeakyBondedQueue<WakeEvent>> wake_event_queue_;
+ std::unique_ptr<LeakyBondedQueue<ScanEvent>> scan_event_queue_;
+};
+
+BluetoothMetricsLogger::BluetoothMetricsLogger()
+ : pimpl_(new impl(kMaxNumBluetoothSession, kMaxNumPairEvent,
+ kMaxNumWakeEvent, kMaxNumScanEvent)) {}
+
+void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
+ uint64_t timestamp_ms,
+ uint32_t device_class,
+ device_type_t device_type) {
+ PairEvent* event = new PairEvent();
+ DeviceInfo* info = event->mutable_device_paired_with();
+ info->set_device_class(device_class);
+ info->set_device_type(get_device_type(device_type));
+ event->set_disconnect_reason(disconnect_reason);
event->set_event_time_millis(timestamp_ms);
+ pimpl_->pair_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_pair_event(
+ pimpl_->bluetooth_log_->num_pair_event() + 1);
+ }
}
-void metrics_scan_event(bool start, const char *initator, scan_tech_t type,
- uint32_t results, uint64_t timestamp_ms) {
- std::lock_guard<std::mutex> lock(log_lock);
- lazy_initialize();
-
- ScanEvent *event = pending->add_scan_event();
+void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
+ const std::string& requestor,
+ const std::string& name,
+ uint64_t timestamp_ms) {
+ WakeEvent* event = new WakeEvent();
+ event->set_wake_event_type(get_wake_event_type(type));
+ event->set_requestor(requestor);
+ event->set_name(name);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->wake_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_wake_event(
+ pimpl_->bluetooth_log_->num_wake_event() + 1);
+ }
+}
- if (start)
+void BluetoothMetricsLogger::LogScanEvent(bool start,
+ const std::string& initator,
+ scan_tech_t type, uint32_t results,
+ uint64_t timestamp_ms) {
+ ScanEvent* event = new ScanEvent();
+ if (start) {
event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
- else
+ } else {
event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
-
- if (initator)
- event->set_initiator(initator);
-
- ScanEvent::ScanTechnologyType scantype = ScanEvent::SCAN_TYPE_UNKNOWN;
-
- if (type == SCAN_TECH_TYPE_LE)
- scantype = ScanEvent::SCAN_TECH_TYPE_LE;
- if (type == SCAN_TECH_TYPE_BREDR)
- scantype = ScanEvent::SCAN_TECH_TYPE_BREDR;
- if (type == SCAN_TECH_TYPE_BOTH)
- scantype = ScanEvent::SCAN_TECH_TYPE_BOTH;
-
- event->set_scan_technology_type(scantype);
-
+ }
+ event->set_initiator(initator);
+ event->set_scan_technology_type(get_scan_tech_type(type));
event->set_number_results(results);
-
event->set_event_time_millis(timestamp_ms);
+ pimpl_->scan_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_scan_event(
+ pimpl_->bluetooth_log_->num_scan_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionStart(
+ connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ LogBluetoothSessionEnd(DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
+ 0);
+ }
+ if (timestamp_ms == 0) {
+ timestamp_ms = time_get_os_boottime_ms();
+ }
+ pimpl_->bluetooth_session_start_time_ms_ = timestamp_ms;
+ pimpl_->bluetooth_session_ = new BluetoothSession();
+ pimpl_->bluetooth_session_->set_connection_technology_type(
+ get_connection_tech_type(connection_tech_type));
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionEnd(
+ disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ return;
+ }
+ if (timestamp_ms == 0) {
+ timestamp_ms = time_get_os_boottime_ms();
+ }
+ int64_t session_duration_sec =
+ (timestamp_ms - pimpl_->bluetooth_session_start_time_ms_) / 1000;
+ pimpl_->bluetooth_session_->set_session_duration_sec(session_duration_sec);
+ pimpl_->bluetooth_session_->set_disconnect_reason_type(
+ get_disconnect_reason_type(disconnect_reason));
+ pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
+ pimpl_->bluetooth_session_ = nullptr;
+ {
+ std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_bluetooth_session(
+ pimpl_->bluetooth_log_->num_bluetooth_session() + 1);
+ }
}
-void metrics_a2dp_session(int64_t session_duration_sec,
- const char *disconnect_reason,
- uint32_t device_class,
- int32_t media_timer_min_ms,
- int32_t media_timer_max_ms,
- int32_t media_timer_avg_ms,
- int32_t buffer_overruns_max_count,
- int32_t buffer_overruns_total,
- float buffer_underruns_average,
- int32_t buffer_underruns_count) {
- std::lock_guard<std::mutex> lock(log_lock);
- lazy_initialize();
-
- BluetoothSession *bt_session = pending->add_session();
-
- // Set connection type: for A2DP it is always BR/EDR
- BluetoothSession::ConnectionTechnologyType conn_type =
- BluetoothSession::CONNECTION_TECHNOLOGY_TYPE_BREDR;
- bt_session->set_connection_technology_type(conn_type);
-
- bt_session->set_session_duration_sec(session_duration_sec);
- if (disconnect_reason != NULL)
- bt_session->set_disconnect_reason(disconnect_reason);
-
- // Set device: class and type are pre-defined
- DeviceInfo *info = bt_session->mutable_device_connected_to();
+void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
+ uint32_t device_class, device_type_t device_type) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
+ }
+ DeviceInfo* info = pimpl_->bluetooth_session_->mutable_device_connected_to();
info->set_device_class(device_class);
info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
+}
- A2DPSession *a2dp_session = bt_session->mutable_a2dp_session();
- a2dp_session->set_media_timer_min_millis(media_timer_min_ms);
- a2dp_session->set_media_timer_max_millis(media_timer_max_ms);
- a2dp_session->set_media_timer_avg_millis(media_timer_avg_ms);
- a2dp_session->set_buffer_overruns_max_count(buffer_overruns_max_count);
- a2dp_session->set_buffer_overruns_total(buffer_overruns_total);
- a2dp_session->set_buffer_underruns_average(buffer_underruns_average);
- a2dp_session->set_buffer_underruns_count(buffer_underruns_count);
+void BluetoothMetricsLogger::LogA2dpSession(
+ const A2dpSessionMetrics& a2dp_session_metrics) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ // When no bluetooth session exist, create one on system's behalf
+ // Set connection type: for A2DP it is always BR/EDR
+ LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ LogBluetoothSessionDeviceInfo(BTM_COD_MAJOR_AUDIO, DEVICE_TYPE_BREDR);
+ }
+ // Accumulate metrics
+ pimpl_->a2dp_session_metrics_.Update(a2dp_session_metrics);
+ // Get or allocate new A2DP session object
+ A2DPSession* a2dp_session =
+ pimpl_->bluetooth_session_->mutable_a2dp_session();
+ a2dp_session->set_audio_duration_millis(
+ pimpl_->a2dp_session_metrics_.audio_duration_ms);
+ a2dp_session->set_media_timer_min_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_min_ms);
+ a2dp_session->set_media_timer_max_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_max_ms);
+ a2dp_session->set_media_timer_avg_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_avg_ms);
+ a2dp_session->set_buffer_overruns_max_count(
+ pimpl_->a2dp_session_metrics_.buffer_overruns_max_count);
+ a2dp_session->set_buffer_overruns_total(
+ pimpl_->a2dp_session_metrics_.buffer_overruns_total);
+ a2dp_session->set_buffer_underruns_average(
+ pimpl_->a2dp_session_metrics_.buffer_underruns_average);
+ a2dp_session->set_buffer_underruns_count(
+ pimpl_->a2dp_session_metrics_.buffer_underruns_count);
}
-void metrics_write(int fd, bool clear) {
- log_lock.lock();
+void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ LOG_DEBUG(LOG_TAG, "%s building metrics", __func__);
+ Build();
LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
- lazy_initialize();
-
- std::string serialized;
- if (!pending->SerializeToString(&serialized)) {
+ if (!pimpl_->bluetooth_log_->SerializeToString(serialized)) {
LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
return;
}
-
if (clear) {
- pending->Clear();
+ pimpl_->bluetooth_log_->Clear();
}
- log_lock.unlock();
+}
- std::string protoBase64;
- base::Base64Encode(serialized, &protoBase64);
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
+ bool clear) {
+ this->WriteString(serialized, clear);
+ base::Base64Encode(*serialized, serialized);
+}
+void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
+ std::string protoBase64;
+ this->WriteBase64String(&protoBase64, clear);
ssize_t ret;
OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
if (ret == -1) {
@@ -204,23 +435,137 @@ void metrics_write(int fd, bool clear) {
}
}
-void metrics_print(int fd, bool clear) {
- log_lock.lock();
- LOG_DEBUG(LOG_TAG, "%s printing metrics", __func__);
- lazy_initialize();
-
- std::string pretty_output;
- google::protobuf::TextFormat::PrintToString(*pending, &pretty_output);
+void BluetoothMetricsLogger::CutoffSession() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ BluetoothSession* new_bt_session =
+ new BluetoothSession(*pimpl_->bluetooth_session_);
+ new_bt_session->clear_a2dp_session();
+ new_bt_session->clear_rfcomm_session();
+ LogBluetoothSessionEnd(DISCONNECT_REASON_METRICS_DUMP, 0);
+ pimpl_->bluetooth_session_ = new_bt_session;
+ pimpl_->bluetooth_session_start_time_ms_ = time_get_os_boottime_ms();
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+ }
+}
- if (clear) {
- pending->Clear();
+void BluetoothMetricsLogger::Build() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ CutoffSession();
+ BluetoothLog* bluetooth_log = pimpl_->bluetooth_log_;
+ while (!pimpl_->bt_session_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->session_size()) <=
+ pimpl_->bt_session_queue_->Capacity()) {
+ bluetooth_log->mutable_session()->AddAllocated(
+ pimpl_->bt_session_queue_->Dequeue());
+ }
+ while (!pimpl_->pair_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->pair_event_size()) <=
+ pimpl_->pair_event_queue_->Capacity()) {
+ bluetooth_log->mutable_pair_event()->AddAllocated(
+ pimpl_->pair_event_queue_->Dequeue());
+ }
+ while (!pimpl_->scan_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->scan_event_size()) <=
+ pimpl_->scan_event_queue_->Capacity()) {
+ bluetooth_log->mutable_scan_event()->AddAllocated(
+ pimpl_->scan_event_queue_->Dequeue());
+ }
+ while (!pimpl_->wake_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->wake_event_size()) <=
+ pimpl_->wake_event_queue_->Capacity()) {
+ bluetooth_log->mutable_wake_event()->AddAllocated(
+ pimpl_->wake_event_queue_->Dequeue());
}
- log_lock.unlock();
+ while (!pimpl_->bt_session_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->wake_event_size()) <=
+ pimpl_->wake_event_queue_->Capacity()) {
+ bluetooth_log->mutable_wake_event()->AddAllocated(
+ pimpl_->wake_event_queue_->Dequeue());
+ }
+}
- ssize_t ret;
- OSI_NO_INTR(ret = write(fd, pretty_output.c_str(), pretty_output.size()));
- if (ret == -1) {
- LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
- strerror(errno), errno);
+void BluetoothMetricsLogger::ResetSession() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ delete pimpl_->bluetooth_session_;
+ pimpl_->bluetooth_session_ = nullptr;
}
+ pimpl_->bluetooth_session_start_time_ms_ = 0;
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+}
+
+void BluetoothMetricsLogger::ResetLog() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->Clear();
+}
+
+void BluetoothMetricsLogger::Reset() {
+ ResetSession();
+ ResetLog();
+ pimpl_->bt_session_queue_->Clear();
+ pimpl_->pair_event_queue_->Clear();
+ pimpl_->wake_event_queue_->Clear();
+ pimpl_->scan_event_queue_->Clear();
+}
+
+} // namespace system_bt_osi
+
+using system_bt_osi::BluetoothMetricsLogger;
+
+void metrics_log_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type) {
+ BluetoothMetricsLogger::GetInstance()->LogPairEvent(disconnect_reason,
+ timestamp_ms, device_class, device_type);
+}
+
+void metrics_log_wake_event(wake_event_type_t type, const char* requestor,
+ const char* name, uint64_t timestamp_ms) {
+ std::string requestor_str(requestor);
+ std::string name_str(name);
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(type, requestor_str,
+ name_str, timestamp_ms);
+}
+
+void metrics_log_scan_event(bool start, const char* initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms) {
+ std::string initator_str(initator);
+ BluetoothMetricsLogger::GetInstance()->LogScanEvent(start, initator_str, type,
+ results, timestamp_ms);
+}
+
+void metrics_log_bluetooth_session_start(connection_tech_t connection_tech_type,
+ uint64_t timestamp_ms) {
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ connection_tech_type, 0);
+}
+
+void metrics_log_bluetooth_session_end(disconnect_reason_t disconnect_reason,
+ uint64_t timestamp_ms) {
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ disconnect_reason, timestamp_ms);
+}
+
+void metrics_log_bluetooth_session_device_info(uint32_t device_class,
+ device_type_t device_type) {
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ device_class, device_type);
+}
+
+void metrics_log_a2dp_session(A2dpSessionMetrics_t* metrics) {
+ system_bt_osi::A2dpSessionMetrics metrics_obj;
+ metrics_obj.audio_duration_ms = metrics->audio_duration_ms;
+ metrics_obj.media_timer_min_ms = metrics->media_timer_min_ms;
+ metrics_obj.media_timer_max_ms = metrics->media_timer_max_ms;
+ metrics_obj.media_timer_avg_ms = metrics->media_timer_avg_ms;
+ metrics_obj.total_scheduling_count = metrics->total_scheduling_count;
+ metrics_obj.buffer_overruns_max_count = metrics->buffer_overruns_max_count;
+ metrics_obj.buffer_overruns_total = metrics->buffer_overruns_total;
+ metrics_obj.buffer_underruns_average = metrics->buffer_underruns_average;
+ metrics_obj.buffer_underruns_count = metrics->buffer_underruns_count;
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics_obj);
+}
+
+void metrics_write_base64(int fd, bool clear) {
+ BluetoothMetricsLogger::GetInstance()->WriteBase64(fd, clear);
}
diff --git a/osi/src/metrics_linux.cpp b/osi/src/metrics_linux.cpp
index f01323617..f63451618 100644
--- a/osi/src/metrics_linux.cpp
+++ b/osi/src/metrics_linux.cpp
@@ -15,46 +15,230 @@
* limitations under the License.
*
******************************************************************************/
+#define LOG_TAG "bt_osi_metrics"
+#include <unistd.h>
+#include <algorithm>
+#include <cerrno>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <mutex>
-#define LOG_TAG "bt_osi_metrics"
+#include <base/base64.h>
+#include <base/logging.h>
+
+#include "osi/include/leaky_bonded_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
-extern "C" {
#include "osi/include/metrics.h"
+#include "osi/include/metrics_cpp.h"
+
+
+namespace system_bt_osi {
+
+// Maximum number of log entries for each repeated field
+#define MAX_NUM_BLUETOOTH_SESSION 50
+#define MAX_NUM_PAIR_EVENT 50
+#define MAX_NUM_WAKE_EVENT 50
+#define MAX_NUM_SCAN_EVENT 50
+
+static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
+ if (metrics.audio_duration_ms > 0) {
+ audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
+ audio_duration_ms += metrics.audio_duration_ms;
+ }
+ if (metrics.media_timer_min_ms > 0) {
+ if (media_timer_min_ms < 0) {
+ media_timer_min_ms = metrics.media_timer_min_ms;
+ } else {
+ media_timer_min_ms =
+ std::min(media_timer_min_ms, metrics.media_timer_min_ms);
+ }
+ }
+ if (metrics.media_timer_max_ms > 0) {
+ media_timer_max_ms =
+ std::max(media_timer_max_ms, metrics.media_timer_max_ms);
+ }
+ if (metrics.media_timer_avg_ms > 0 && metrics.total_scheduling_count > 0) {
+ if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
+ media_timer_avg_ms = metrics.media_timer_avg_ms;
+ total_scheduling_count = metrics.total_scheduling_count;
+ } else {
+ media_timer_avg_ms = combine_averages(
+ media_timer_avg_ms, total_scheduling_count,
+ metrics.media_timer_avg_ms, metrics.total_scheduling_count);
+ total_scheduling_count += metrics.total_scheduling_count;
+ }
+ }
+ if (metrics.buffer_overruns_max_count > 0) {
+ buffer_overruns_max_count =
+ std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
+ }
+ if (metrics.buffer_overruns_total > 0) {
+ buffer_overruns_total =
+ std::max(static_cast<int32_t>(0), buffer_overruns_total);
+ buffer_overruns_total += metrics.buffer_overruns_total;
+ }
+ if (metrics.buffer_underruns_average > 0 &&
+ metrics.buffer_underruns_count > 0) {
+ if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
+ buffer_underruns_average = metrics.buffer_underruns_average;
+ buffer_underruns_count = metrics.buffer_underruns_count;
+ } else {
+ buffer_underruns_average = combine_averages(
+ metrics.buffer_underruns_average, metrics.buffer_underruns_count,
+ buffer_underruns_average, buffer_underruns_count);
+ buffer_underruns_count += metrics.buffer_underruns_count;
+ }
+ }
+}
+
+bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
+ return audio_duration_ms == rhs.audio_duration_ms &&
+ media_timer_min_ms == rhs.media_timer_min_ms &&
+ media_timer_max_ms == rhs.media_timer_max_ms &&
+ media_timer_avg_ms == rhs.media_timer_avg_ms &&
+ total_scheduling_count == rhs.total_scheduling_count &&
+ buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
+ buffer_overruns_total == rhs.buffer_overruns_total &&
+ buffer_underruns_average == rhs.buffer_underruns_average &&
+ buffer_underruns_count == rhs.buffer_underruns_count;
+}
+
+struct BluetoothMetricsLogger::impl {
+ // TODO(siyuanh): Implement for linux
+};
+
+BluetoothMetricsLogger::BluetoothMetricsLogger() : pimpl_(new impl) {}
+
+void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
+ uint64_t timestamp_ms,
+ uint32_t device_class,
+ device_type_t device_type) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
+ const std::string& requestor,
+ const std::string& name,
+ uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogScanEvent(bool start,
+ const std::string& initator,
+ scan_tech_t type, uint32_t results,
+ uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionStart(
+ connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionEnd(
+ const std::string& disconnect_reason, uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
+ uint32_t device_class, device_type_t device_type) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogA2dpSession(
+ const A2dpSessionMetrics& a2dp_session_metrics) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
+ bool clear) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::CutoffSession() {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::Build() {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::Reset() {
+ // TODO(siyuanh): Implement for linux
+}
+
+} // namespace system_bt_osi
+
+void metrics_log_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void metrics_log_wake_event(wake_event_type_t type, const char* requestor,
+ const char* name, uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
}
-void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
- uint32_t device_class, device_type_t device_type) {
- //TODO(jpawlowski): implement
+void metrics_log_scan_event(bool start, const char* initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
}
-void metrics_wake_event(wake_event_type_t type, const char *requestor,
- const char *name, uint64_t timestamp_ms) {
- //TODO(jpawlowski): implement
+void metrics_log_bluetooth_session_start(connection_tech_t connection_tech_type,
+ uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
}
-void metrics_scan_event(bool start, const char *initator, scan_tech_t type,
- uint32_t results, uint64_t timestamp_ms) {
- //TODO(jpawlowski): implement
+void metrics_log_bluetooth_session_end(const char* disconnect_reason,
+ uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
}
-void metrics_a2dp_session(int64_t session_duration_sec,
- const char *disconnect_reason,
- uint32_t device_class,
- int32_t media_timer_min_ms,
- int32_t media_timer_max_ms,
- int32_t media_timer_avg_ms,
- int32_t buffer_overruns_max_count,
- int32_t buffer_overruns_total,
- float buffer_underruns_average,
- int32_t buffer_underruns_count) {
- //TODO(jpawlowski): implement
+void metrics_log_bluetooth_session_device_info(uint32_t device_class,
+ device_type_t device_type) {
+ // TODO(siyuanh): Implement for linux
}
-void metrics_write(int fd, bool clear) {
- //TODO(jpawlowski): implement
+void metrics_log_a2dp_session(A2dpSessionMetrics_t* metrics) {
+ // TODO(siyuanh): Implement for linux
}
-void metrics_print(int fd, bool clear) {
- //TODO(jpawlowski): implement
+void metrics_write_base64(int fd, bool clear) {
+ // TODO(siyuanh): Implement for linux
}
diff --git a/osi/src/protos/bluetooth.proto b/osi/src/protos/bluetooth.proto
index 9a233ad26..14c1ef2ca 100644
--- a/osi/src/protos/bluetooth.proto
+++ b/osi/src/protos/bluetooth.proto
@@ -24,6 +24,21 @@ message BluetoothLog {
// Scan event information.
repeated ScanEvent scan_event = 4;
+
+ // Number of bonded devices.
+ optional int32 num_bonded_devices = 5;
+
+ // Number of BluetoothSession including discarded ones beyond capacity
+ optional int64 num_bluetooth_session = 6;
+
+ // Number of PairEvent including discarded ones beyond capacity
+ optional int64 num_pair_event = 7;
+
+ // Number of WakeEvent including discarded ones beyond capacity
+ optional int64 num_wake_event = 8;
+
+ // Number of ScanEvent including discarded ones beyond capacity
+ optional int64 num_scan_event = 9;
}
// The information about the device.
@@ -63,6 +78,17 @@ message BluetoothSession {
CONNECTION_TECHNOLOGY_TYPE_BREDR = 2;
}
+ enum DisconnectReasonType {
+ UNKNOWN = 0;
+
+ // A metrics dump takes a snapshot of current Bluetooth session and thus
+ // is not a real disconnect, but a discontinuation in metrics logging.
+ // This enum indicates this situation.
+ METRICS_DUMP = 1;
+
+ NEXT_START_WITHOUT_END_PREVIOUS = 2;
+ }
+
// Duration of the session.
optional int64 session_duration_sec = 2;
@@ -70,7 +96,7 @@ message BluetoothSession {
optional ConnectionTechnologyType connection_technology_type = 3;
// Reason for disconnecting.
- optional string disconnect_reason = 4;
+ optional string disconnect_reason = 4 [deprecated=true];
// The information about the device which it is connected to.
optional DeviceInfo device_connected_to = 5;
@@ -78,8 +104,11 @@ message BluetoothSession {
// The information about the RFComm session.
optional RFCommSession rfcomm_session = 6;
- // The information about the A2DP session.
+ // The information about the A2DP audio session.
optional A2DPSession a2dp_session = 7;
+
+ // Numeric reason for disconnecting as defined in metrics.h
+ optional DisconnectReasonType disconnect_reason_type = 8;
}
message RFCommSession {
@@ -91,7 +120,7 @@ message RFCommSession {
optional int32 tx_bytes = 2;
}
-// Session information that gets logged for every A2DP session.
+// Session information that gets logged for A2DP session.
message A2DPSession {
// Media timer in milliseconds.
@@ -114,6 +143,9 @@ message A2DPSession {
// Buffer underruns count.
optional int32 buffer_underruns_count = 7;
+
+ // Total audio time in this A2DP session
+ optional int64 audio_duration_millis = 8;
}
message PairEvent {
diff --git a/osi/src/wakelock.c b/osi/src/wakelock.c
index fc19cc44b..9681bd058 100644
--- a/osi/src/wakelock.c
+++ b/osi/src/wakelock.c
@@ -294,7 +294,7 @@ static void update_wakelock_acquired_stats(bt_status_t acquired_status) {
pthread_mutex_unlock(&monitor);
- metrics_wake_event(WAKE_EVENT_ACQUIRED, NULL, WAKE_LOCK_ID, now_ms);
+ metrics_log_wake_event(WAKE_EVENT_ACQUIRED, "", "", now_ms);
}
//
@@ -338,7 +338,7 @@ static void update_wakelock_released_stats(bt_status_t released_status) {
pthread_mutex_unlock(&monitor);
- metrics_wake_event(WAKE_EVENT_RELEASED, NULL, WAKE_LOCK_ID, now_ms);
+ metrics_log_wake_event(WAKE_EVENT_RELEASED, "", "", now_ms);
}
void wakelock_debug_dump(int fd) {
diff --git a/osi/test/leaky_bonded_queue_test.cpp b/osi/test/leaky_bonded_queue_test.cpp
new file mode 100644
index 000000000..c538101ed
--- /dev/null
+++ b/osi/test/leaky_bonded_queue_test.cpp
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+
+#include "osi/include/leaky_bonded_queue.h"
+
+namespace testing {
+
+using system_bt_osi::LeakyBondedQueue;
+
+#define ITEM_EQ(a, b) \
+ do { \
+ EXPECT_EQ(a, b); \
+ EXPECT_EQ(a->index, b->index); \
+ } while (0)
+
+class Item {
+ public:
+ Item(int i) { index = i; }
+ virtual ~Item() {}
+ int index;
+};
+
+class MockItem : public Item {
+ public:
+ MockItem(int i) : Item(i) {}
+ ~MockItem() { Destruct(); }
+ MOCK_METHOD0(Destruct, void());
+};
+
+TEST(LeakyBondedQueueTest, TestEnqueueDequeue) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(3);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(3));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
+ MockItem* item2_2 = queue->Dequeue();
+ MockItem* item3_3 = queue->Dequeue();
+ MockItem* item4_4 = queue->Dequeue();
+ EXPECT_THAT(item2_2, NotNull());
+ ITEM_EQ(item2_2, item2);
+ EXPECT_THAT(item3_3, NotNull());
+ ITEM_EQ(item3_3, item3);
+ EXPECT_THAT(item4_4, NotNull());
+ ITEM_EQ(item4_4, item4);
+ LOG(INFO) << "All done release items";
+ EXPECT_CALL(*item2_2, Destruct()).Times(1);
+ delete item2_2;
+ EXPECT_CALL(*item3_3, Destruct()).Times(1);
+ delete item3_3;
+ EXPECT_CALL(*item4_4, Destruct()).Times(1);
+ delete item4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestEnqueueDequeue2) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item4_4_4 = queue->Dequeue();
+ MockItem* item1_1_1 = queue->Dequeue();
+ ITEM_EQ(item4_4_4, item4);
+ ITEM_EQ(item1_1_1, item1);
+ EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
+ delete item1_1_1;
+ EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
+ delete item4_4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestEnqueuePop) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item2_2 = queue->EnqueueWithPop(item4);
+ EXPECT_THAT(item2_2, NotNull());
+ ITEM_EQ(item2_2, item2);
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ delete item2_2;
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item3_3 = queue->EnqueueWithPop(item1);
+ EXPECT_THAT(item3_3, NotNull());
+ ITEM_EQ(item3_3, item3);
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ delete item3_3;
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item4_4_4 = queue->Dequeue();
+ MockItem* item1_1_1 = queue->Dequeue();
+ ITEM_EQ(item4_4_4, item4);
+ ITEM_EQ(item1_1_1, item1);
+ EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
+ delete item1_1_1;
+ EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
+ delete item4_4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestQueueClear) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ EXPECT_CALL(*item4, Destruct()).Times(1);
+ queue->Clear();
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestQueueFree) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ EXPECT_CALL(*item4, Destruct()).Times(1);
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestPushNull) {
+ MockItem* item1 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ queue->Enqueue(item1);
+ MockItem* item1_1 = queue->Dequeue();
+ EXPECT_THAT(item1_1, IsNull());
+}
+
+TEST(LeakyBondedQueueTest, TestPushNullOverflowQueue) {
+ MockItem* item1 = nullptr;
+ MockItem* item2 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(1);
+ queue->Enqueue(item1);
+ queue->Enqueue(item2);
+ MockItem* item2_2 = queue->Dequeue();
+ EXPECT_THAT(item2_2, IsNull());
+}
+
+TEST(LeakyBondedQueueTest, TestPushNullDeleteQueue) {
+ MockItem* item1 = nullptr;
+ MockItem* item2 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ queue->Enqueue(item1);
+ queue->Enqueue(item2);
+ delete queue;
+}
+}
diff --git a/osi/test/metrics_test.cpp b/osi/test/metrics_test.cpp
new file mode 100644
index 000000000..597e4b3b8
--- /dev/null
+++ b/osi/test/metrics_test.cpp
@@ -0,0 +1,805 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 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 <chrono>
+#include <cstdint>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+
+#include "osi/include/metrics.h"
+#include "osi/include/metrics_cpp.h"
+#include "osi/include/time.h"
+#include "osi/src/protos/bluetooth.pb.h"
+
+#define BTM_COD_MAJOR_AUDIO_TEST 0x04
+
+namespace testing {
+
+using clearcut::connectivity::A2DPSession;
+using clearcut::connectivity::BluetoothLog;
+using clearcut::connectivity::BluetoothSession;
+using clearcut::connectivity::BluetoothSession_ConnectionTechnologyType;
+using clearcut::connectivity::BluetoothSession_DisconnectReasonType;
+using clearcut::connectivity::DeviceInfo;
+using clearcut::connectivity::DeviceInfo_DeviceType;
+using clearcut::connectivity::PairEvent;
+using clearcut::connectivity::RFCommSession;
+using clearcut::connectivity::ScanEvent;
+using clearcut::connectivity::ScanEvent_ScanTechnologyType;
+using clearcut::connectivity::ScanEvent_ScanEventType;
+using clearcut::connectivity::WakeEvent;
+using clearcut::connectivity::WakeEvent_WakeEventType;
+using system_bt_osi::BluetoothMetricsLogger;
+using system_bt_osi::A2dpSessionMetrics;
+
+namespace {
+const size_t kMaxEventGenerationLimit = 5000;
+}
+
+uint64_t metrics_time_get_os_boottime_us(void) {
+ struct timespec ts_now;
+ clock_gettime(CLOCK_BOOTTIME, &ts_now);
+
+ return ((uint64_t)ts_now.tv_sec * 1000000L) +
+ ((uint64_t)ts_now.tv_nsec / 1000);
+}
+
+/*
+ * Get current OS boot time in millisecond
+ */
+static int64_t time_get_os_boottime_ms(void) {
+ return metrics_time_get_os_boottime_us() / 1000;
+}
+
+static void sleep_ms(int64_t t) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(t));
+}
+
+DeviceInfo* MakeDeviceInfo(int32_t device_class,
+ DeviceInfo_DeviceType device_type) {
+ DeviceInfo* info = new DeviceInfo();
+ info->set_device_class(device_class);
+ info->set_device_type(device_type);
+ return info;
+}
+
+PairEvent* MakePairEvent(int32_t disconnect_reason, int64_t timestamp_ms,
+ DeviceInfo* device_info) {
+ PairEvent* event = new PairEvent();
+ event->set_disconnect_reason(disconnect_reason);
+ event->set_event_time_millis(timestamp_ms);
+ if (device_info) event->set_allocated_device_paired_with(device_info);
+ return event;
+}
+
+WakeEvent* MakeWakeEvent(WakeEvent_WakeEventType event_type,
+ const std::string& requestor, const std::string& name,
+ int64_t timestamp_ms) {
+ WakeEvent* event = new WakeEvent();
+ event->set_wake_event_type(event_type);
+ event->set_requestor(requestor);
+ event->set_name(name);
+ event->set_event_time_millis(timestamp_ms);
+ return event;
+}
+
+ScanEvent* MakeScanEvent(ScanEvent_ScanEventType event_type,
+ const std::string& initiator,
+ ScanEvent_ScanTechnologyType tech_type,
+ int32_t num_results, int64_t timestamp_ms) {
+ ScanEvent* event = new ScanEvent();
+ event->set_scan_event_type(event_type);
+ event->set_initiator(initiator);
+ event->set_scan_technology_type(tech_type);
+ event->set_number_results(num_results);
+ event->set_event_time_millis(timestamp_ms);
+ return event;
+}
+
+A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics) {
+ A2DPSession* session = new A2DPSession();
+ session->set_media_timer_min_millis(metrics.media_timer_min_ms);
+ session->set_media_timer_max_millis(metrics.media_timer_max_ms);
+ session->set_media_timer_avg_millis(metrics.media_timer_avg_ms);
+ session->set_buffer_overruns_max_count(metrics.buffer_overruns_max_count);
+ session->set_buffer_overruns_total(metrics.buffer_overruns_total);
+ session->set_buffer_underruns_average(metrics.buffer_underruns_average);
+ session->set_buffer_underruns_count(metrics.buffer_underruns_count);
+ session->set_audio_duration_millis(metrics.audio_duration_ms);
+ return session;
+}
+
+BluetoothSession* MakeBluetoothSession(
+ int64_t session_duration_sec,
+ BluetoothSession_ConnectionTechnologyType conn_type,
+ BluetoothSession_DisconnectReasonType disconnect_reason,
+ DeviceInfo* device_info, RFCommSession* rfcomm_session,
+ A2DPSession* a2dp_session) {
+ BluetoothSession* session = new BluetoothSession();
+ if (a2dp_session) session->set_allocated_a2dp_session(a2dp_session);
+ if (rfcomm_session) session->set_allocated_rfcomm_session(rfcomm_session);
+ if (device_info) session->set_allocated_device_connected_to(device_info);
+ session->set_session_duration_sec(session_duration_sec);
+ session->set_connection_technology_type(conn_type);
+ session->set_disconnect_reason_type(disconnect_reason);
+ return session;
+}
+
+BluetoothLog* MakeBluetoothLog(std::vector<BluetoothSession*> bt_sessions,
+ std::vector<PairEvent*> pair_events,
+ std::vector<WakeEvent*> wake_events,
+ std::vector<ScanEvent*> scan_events) {
+ BluetoothLog* bt_log = new BluetoothLog();
+ for (BluetoothSession* session : bt_sessions) {
+ bt_log->mutable_session()->AddAllocated(session);
+ }
+ bt_sessions.clear();
+ for (PairEvent* event : pair_events) {
+ bt_log->mutable_pair_event()->AddAllocated(event);
+ }
+ pair_events.clear();
+ for (WakeEvent* event : wake_events) {
+ bt_log->mutable_wake_event()->AddAllocated(event);
+ }
+ wake_events.clear();
+ for (ScanEvent* event : scan_events) {
+ bt_log->mutable_scan_event()->AddAllocated(event);
+ }
+ scan_events.clear();
+ return bt_log;
+}
+
+void GenerateWakeEvents(size_t start, size_t end,
+ std::vector<WakeEvent*>* wake_events) {
+ for (size_t i = start; i < end; ++i) {
+ wake_events->push_back(MakeWakeEvent(
+ i % 2 == 0 ? WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED
+ : WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED,
+ "TEST_REQ", "TEST_NAME", i));
+ }
+}
+
+#define COMPARE_A2DP_METRICS(a, b) \
+ do { \
+ EXPECT_EQ(a.audio_duration_ms, b.audio_duration_ms); \
+ EXPECT_EQ(a.media_timer_min_ms, b.media_timer_min_ms); \
+ EXPECT_EQ(a.media_timer_max_ms, b.media_timer_max_ms); \
+ EXPECT_EQ(a.media_timer_avg_ms, b.media_timer_avg_ms); \
+ EXPECT_EQ(a.total_scheduling_count, b.total_scheduling_count); \
+ EXPECT_EQ(a.buffer_overruns_max_count, b.buffer_overruns_max_count); \
+ EXPECT_EQ(a.buffer_overruns_total, b.buffer_overruns_total); \
+ EXPECT_THAT(a.buffer_underruns_average, \
+ FloatNear(b.buffer_underruns_average, 0.01)); \
+ a.buffer_underruns_average = b.buffer_underruns_average; \
+ EXPECT_EQ(a.buffer_underruns_count, b.buffer_underruns_count); \
+ } while (0)
+
+/*
+ * metrics_sum = metrics1 + metrics2
+ */
+TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNormal) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNew) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 100;
+ metrics_sum.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 130;
+ metrics_sum.buffer_underruns_count = 2400;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestNullUpdate) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 100;
+ metrics_sum.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 130;
+ metrics_sum.buffer_underruns_count = 2400;
+ metrics2.Update(metrics1);
+ COMPARE_A2DP_METRICS(metrics2, metrics_sum);
+ EXPECT_TRUE(metrics2 == metrics_sum);
+ EXPECT_EQ(metrics2, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestPartialUpdate) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics_sum.media_timer_max_ms = 100;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics_sum.media_timer_avg_ms = 50;
+ metrics_sum.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics_sum.buffer_overruns_max_count = 70;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 80;
+ metrics_sum.buffer_underruns_count = 1200;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+class BluetoothMetricsLoggerTest : public Test {
+ protected:
+ // Use to hold test protos
+ std::vector<PairEvent*> pair_events_;
+ std::vector<WakeEvent*> wake_events_;
+ std::vector<ScanEvent*> scan_events_;
+ std::vector<BluetoothSession*> bt_sessions_;
+ int64_t num_pair_event_ = 0;
+ int64_t num_wake_event_ = 0;
+ int64_t num_scan_event_ = 0;
+ int64_t num_bt_session_ = 0;
+ BluetoothLog* bt_log_;
+ std::string bt_log_str_;
+ std::string bt_log_ascii_str_;
+
+ void UpdateLog() {
+ for (BluetoothSession* session : bt_sessions_) {
+ bt_log_->mutable_session()->AddAllocated(session);
+ }
+ if (num_bt_session_ > 0) {
+ bt_log_->set_num_bluetooth_session(num_bt_session_);
+ } else if (bt_sessions_.size() > 0) {
+ bt_log_->set_num_bluetooth_session(bt_sessions_.size());
+ }
+ bt_sessions_.clear();
+ for (PairEvent* event : pair_events_) {
+ bt_log_->mutable_pair_event()->AddAllocated(event);
+ }
+ if (num_pair_event_ > 0) {
+ bt_log_->set_num_pair_event(num_pair_event_);
+ } else if (pair_events_.size() > 0) {
+ bt_log_->set_num_pair_event(pair_events_.size());
+ }
+ pair_events_.clear();
+ for (WakeEvent* event : wake_events_) {
+ bt_log_->mutable_wake_event()->AddAllocated(event);
+ }
+ if (num_wake_event_ > 0) {
+ bt_log_->set_num_wake_event(num_wake_event_);
+ } else if (wake_events_.size() > 0) {
+ bt_log_->set_num_wake_event(wake_events_.size());
+ }
+ wake_events_.clear();
+ for (ScanEvent* event : scan_events_) {
+ bt_log_->mutable_scan_event()->AddAllocated(event);
+ }
+ if (num_scan_event_ > 0) {
+ bt_log_->set_num_scan_event(num_scan_event_);
+ } else if (scan_events_.size() > 0) {
+ bt_log_->set_num_scan_event(scan_events_.size());
+ }
+ scan_events_.clear();
+ bt_log_->SerializeToString(&bt_log_str_);
+ }
+
+ void ClearLog() {
+ for (BluetoothSession* session : bt_sessions_) {
+ session->Clear();
+ delete session;
+ }
+ bt_sessions_.clear();
+ for (PairEvent* event : pair_events_) {
+ event->Clear();
+ delete event;
+ }
+ pair_events_.clear();
+ for (WakeEvent* event : wake_events_) {
+ event->Clear();
+ delete event;
+ }
+ wake_events_.clear();
+ for (ScanEvent* event : scan_events_) {
+ event->Clear();
+ delete event;
+ }
+ scan_events_.clear();
+ bt_log_->Clear();
+ }
+
+ void SetUp() {
+ bt_log_ = new BluetoothLog();
+ // Clear existing metrics entries, if any
+ BluetoothMetricsLogger::GetInstance()->Reset();
+ }
+ void TearDown() {
+ // Clear remaining metrics entries, if any
+ BluetoothMetricsLogger::GetInstance()->Reset();
+ ClearLog();
+ delete bt_log_;
+ }
+
+ public:
+};
+
+TEST_F(BluetoothMetricsLoggerTest, PairEventTest) {
+ pair_events_.push_back(MakePairEvent(
+ 35, 12345,
+ MakeDeviceInfo(
+ 42, DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR)));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogPairEvent(
+ 35, 12345, 42, DEVICE_TYPE_BREDR);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, WakeEventTest) {
+ wake_events_.push_back(
+ MakeWakeEvent(WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED,
+ "TEST_REQ", "TEST_NAME", 12345));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ WAKE_EVENT_ACQUIRED, "TEST_REQ", "TEST_NAME", 12345);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, WakeEventOverrunTest) {
+ GenerateWakeEvents(kMaxEventGenerationLimit -
+ BluetoothMetricsLogger::kMaxNumWakeEvent,
+ kMaxEventGenerationLimit, &wake_events_);
+ num_wake_event_ = kMaxEventGenerationLimit;
+ UpdateLog();
+ for (size_t i = 0; i < kMaxEventGenerationLimit; ++i) {
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ i % 2 == 0 ? WAKE_EVENT_ACQUIRED : WAKE_EVENT_RELEASED,
+ "TEST_REQ", "TEST_NAME", i);
+ }
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, ScanEventTest) {
+ scan_events_.push_back(MakeScanEvent(
+ ScanEvent_ScanEventType::ScanEvent_ScanEventType_SCAN_EVENT_STOP,
+ "TEST_INITIATOR", ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR,
+ 42, 123456));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogScanEvent(
+ false, "TEST_INITIATOR", SCAN_TECH_TYPE_BREDR, 42, 123456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 10,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_LE, 123456);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ DISCONNECT_REASON_UNKNOWN, 133456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionDumpBeforeEndTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_LE, time_get_os_boottime_ms());
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionStartBeforeEndTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS,
+ nullptr, nullptr, nullptr));
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 2,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_LE, 0);
+ sleep_ms(2000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 4. LogA2dpSession
+ * 5. LogA2dpSession
+ * 6. LogBluetoothSessionEnd
+ * 7. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics_sum);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 10,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_BREDR, 123456);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ DISCONNECT_REASON_UNKNOWN, 133456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesSeparatedbyDumpTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 4. LogA2dpSession
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 7. LogBluetoothSessionEnd
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyDumpTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics1);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ session = MakeA2DPSession(metrics2);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case 1: A2DPSessionOnlyTest
+ *
+ * 1. Create Instance
+ * 4. LogA2dpSession
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionOnlyTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics_sum);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionDumpBeforeTwoUpdatesTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 7. LogA2dpSession
+ * 8. LogBluetoothSessionEnd
+ * 9. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionDumpBeforeTwoUpdatesTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, DEVICE_TYPE_BREDR);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics_sum);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+}
diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
index e24e65420..f863b210b 100644
--- a/stack/btm/btm_acl.c
+++ b/stack/btm/btm_acl.c
@@ -167,7 +167,7 @@ void btm_acl_init (void)
** NULL if not found.
**
*******************************************************************************/
-tACL_CONN *btm_bda_to_acl (BD_ADDR bda, tBT_TRANSPORT transport)
+tACL_CONN *btm_bda_to_acl (const BD_ADDR bda, tBT_TRANSPORT transport)
{
tACL_CONN *p = &btm_cb.acl_db[0];
UINT16 xx;
@@ -1005,6 +1005,43 @@ void BTM_SetDefaultLinkPolicy (UINT16 settings)
btsnd_hcic_write_def_policy_set(settings);
}
+
+void btm_use_preferred_conn_params(BD_ADDR bda) {
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda);
+
+ /* If there are any preferred connection parameters, set them now */
+ if ( (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN ) &&
+ (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX ) &&
+ (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN ) &&
+ (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX ) &&
+ (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX ) &&
+ (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
+ (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ ((p_lcb->min_interval < p_dev_rec->conn_params.min_conn_int &&
+ p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
+ (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) ||
+ (p_lcb->latency > p_dev_rec->conn_params.slave_latency) ||
+ (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout)))
+ {
+ BTM_TRACE_DEBUG ("%s: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", __func__,
+ p_lcb->handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int,
+ p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout);
+
+ p_lcb->min_interval = p_dev_rec->conn_params.min_conn_int;
+ p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int;
+ p_lcb->timeout = p_dev_rec->conn_params.supervision_tout;
+ p_lcb->latency = p_dev_rec->conn_params.slave_latency;
+
+ btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle,
+ p_dev_rec->conn_params.min_conn_int,
+ p_dev_rec->conn_params.max_conn_int,
+ p_dev_rec->conn_params.slave_latency,
+ p_dev_rec->conn_params.supervision_tout,
+ 0, 0);
+ }
+}
+
/*******************************************************************************
**
** Function btm_read_remote_version_complete
@@ -1046,8 +1083,9 @@ void btm_read_remote_version_complete (UINT8 *p)
}
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
- if (p_acl_cb->transport == BT_TRANSPORT_LE){
+ if (p_acl_cb->transport == BT_TRANSPORT_LE) {
l2cble_notify_le_connection (p_acl_cb->remote_addr);
+ btm_use_preferred_conn_params(p_acl_cb->remote_addr);
}
#endif // (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
BTM_TRACE_WARNING ("btm_read_remote_version_complete: BDA: %02x-%02x-%02x-%02x-%02x-%02x",
@@ -1532,7 +1570,7 @@ UINT16 btm_get_acl_disc_reason_code (void)
** Returns the handle of the connection, or 0xFFFF if none.
**
*******************************************************************************/
-UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda, tBT_TRANSPORT transport)
+UINT16 BTM_GetHCIConnHandle (const BD_ADDR remote_bda, tBT_TRANSPORT transport)
{
tACL_CONN *p;
BTM_TRACE_DEBUG ("BTM_GetHCIConnHandle");
diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
index d6d8d6045..542c87a9b 100644
--- a/stack/btm/btm_ble.c
+++ b/stack/btm/btm_ble.c
@@ -70,7 +70,7 @@ extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);
** Returns TRUE if added OK, else FALSE
**
*******************************************************************************/
-BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
+BOOLEAN BTM_SecAddBleDevice (const BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
tBLE_ADDR_TYPE addr_type)
{
BTM_TRACE_DEBUG ("%s: dev_type=0x%x", __func__, dev_type);
@@ -453,11 +453,10 @@ void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data)
tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
- BTM_TRACE_DEBUG ("BTM_BleOobDataReply");
+ BTM_TRACE_DEBUG ("%s:", __func__);
- if (p_dev_rec == NULL)
- {
- BTM_TRACE_ERROR("BTM_BleOobDataReply() to Unknown device");
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s: Unknown device", __func__);
return;
}
@@ -466,6 +465,47 @@ void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data)
#endif
}
+/*******************************************************************************
+**
+** Function BTM_BleSecureConnectionOobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+** data is available
+**
+** Parameters: bd_addr - Address of the peer device
+** p_c - pointer to Confirmation.
+** p_r - pointer to Randomizer
+**
+*******************************************************************************/
+void BTM_BleSecureConnectionOobDataReply(BD_ADDR bd_addr,
+ uint8_t *p_c, uint8_t *p_r)
+{
+#if SMP_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG ("%s:", __func__);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s: Unknown device", __func__);
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+ tSMP_SC_OOB_DATA oob;
+ memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA));
+
+ oob.peer_oob_data.present = true;
+ memcpy(&oob.peer_oob_data.randomizer, p_r, BT_OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.commitment, p_c, BT_OCTET16_LEN);
+ oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type;
+ memcpy(&oob.peer_oob_data.addr_rcvd_from.bda, bd_addr, sizeof(BD_ADDR));
+
+ SMP_SecureConnectionOobDataReply((uint8_t*)&oob);
+#endif
+}
+
/******************************************************************************
**
** Function BTM_BleSetConnScanParams
diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
index 3b5b6c09b..bffb1173a 100644
--- a/stack/btm/btm_dev.c
+++ b/stack/btm/btm_dev.c
@@ -422,12 +422,12 @@ bool is_address_equal(void *data, void *context)
** Returns Pointer to the record or NULL
**
*******************************************************************************/
-tBTM_SEC_DEV_REC *btm_find_dev(BD_ADDR bd_addr)
+tBTM_SEC_DEV_REC *btm_find_dev(const BD_ADDR bd_addr)
{
if (!bd_addr)
return NULL;
- list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_address_equal, bd_addr);
+ list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_address_equal, (void*)bd_addr);
if (n)
return list_node(n);
diff --git a/stack/btm/btm_inq.c b/stack/btm/btm_inq.c
index 93954d8d3..e0d40bd0f 100644
--- a/stack/btm/btm_inq.c
+++ b/stack/btm/btm_inq.c
@@ -1131,7 +1131,7 @@ tBTM_STATUS BTM_CancelRemoteDeviceName (void)
** Returns pointer to entry, or NULL if not found
**
*******************************************************************************/
-tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda)
+tBTM_INQ_INFO *BTM_InqDbRead (const BD_ADDR p_bda)
{
BTM_TRACE_API ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]",
p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
@@ -1538,7 +1538,7 @@ BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda)
** Returns pointer to entry, or NULL if not found
**
*******************************************************************************/
-tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda)
+tINQ_DB_ENT *btm_inq_db_find (const BD_ADDR p_bda)
{
UINT16 xx;
tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index 08a20fc21..cab6ce43f 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -952,7 +952,7 @@ extern void btm_process_cancel_complete(UINT8 status, UINT8 mode);
extern void btm_event_filter_complete (UINT8 *p);
extern void btm_inq_stop_on_ssp(void);
extern void btm_inq_clear_ssp(void);
-extern tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda);
+extern tINQ_DB_ENT *btm_inq_db_find (const BD_ADDR p_bda);
extern BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda);
extern BOOLEAN btm_lookup_eir(BD_ADDR_PTR p_rem_addr);
@@ -999,7 +999,7 @@ extern void btm_establish_continue (tACL_CONN *p_acl_cb);
extern void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type);
/* Read maximum data packet that can be sent over current connection */
extern UINT16 btm_get_max_packet_size (BD_ADDR addr);
-extern tACL_CONN *btm_bda_to_acl (BD_ADDR bda, tBT_TRANSPORT transport);
+extern tACL_CONN *btm_bda_to_acl (const BD_ADDR bda, tBT_TRANSPORT transport);
extern BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda);
extern void btm_pm_reset(void);
@@ -1080,7 +1080,7 @@ extern BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
extern tBTM_SEC_DEV_REC *btm_sec_allocate_dev_rec(void);
extern tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr);
extern void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec);
-extern tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC *btm_find_dev (const BD_ADDR bd_addr);
extern tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr);
extern tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle);
extern tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr);
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 9fff83d9a..4e3be8cb6 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -2555,7 +2555,7 @@ extern UINT8 *BTM_ReadAllRemoteFeatures (BD_ADDR addr);
** Returns pointer to entry, or NULL if not found
**
*******************************************************************************/
-extern tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda);
+extern tBTM_INQ_INFO *BTM_InqDbRead (const BD_ADDR p_bda);
/*******************************************************************************
@@ -3761,7 +3761,7 @@ extern tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
** Returns the handle of the connection, or 0xFFFF if none.
**
*******************************************************************************/
-extern UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda, tBT_TRANSPORT transport);
+extern UINT16 BTM_GetHCIConnHandle (const BD_ADDR remote_bda, tBT_TRANSPORT transport);
/*******************************************************************************
**
diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
index ab5ea38b1..412fa8ea3 100644
--- a/stack/include/btm_ble_api.h
+++ b/stack/include/btm_ble_api.h
@@ -912,7 +912,7 @@ extern "C" {
** Returns TRUE if added OK, else FALSE
**
*******************************************************************************/
-extern BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name,
+extern BOOLEAN BTM_SecAddBleDevice (const BD_ADDR bd_addr, BD_NAME bd_name,
tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type);
/*******************************************************************************
@@ -1236,6 +1236,22 @@ extern void BTM_BleConfirmReply (BD_ADDR bd_addr, UINT8 res);
*******************************************************************************/
extern void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data);
+/*******************************************************************************
+**
+** Function BTM_BleSecureConnectionOobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+** data is available
+**
+** Parameters: bd_addr - Address of the peer device
+** p_c - pointer to Confirmation
+** p_r - pointer to Randomizer.
+**
+*******************************************************************************/
+extern void BTM_BleSecureConnectionOobDataReply(BD_ADDR bd_addr,
+ uint8_t *p_c, uint8_t *p_r);
+
/*******************************************************************************
**
diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
index 4b8d56a58..be933f73d 100644
--- a/stack/l2cap/l2c_ble.c
+++ b/stack/l2cap/l2c_ble.c
@@ -32,6 +32,7 @@
#include "hcimsgs.h"
#include "device/include/controller.h"
#include "stack_config.h"
+#include "btif_debug_l2c.h"
#if (BLE_INCLUDED == TRUE)
@@ -233,42 +234,6 @@ UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport)
return reason;
}
-void l2cble_use_preferred_conn_params(BD_ADDR bda) {
- tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
- tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda);
-
- /* If there are any preferred connection parameters, set them now */
- if ( (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN ) &&
- (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX ) &&
- (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN ) &&
- (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX ) &&
- (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX ) &&
- (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
- (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
- ((p_lcb->min_interval < p_dev_rec->conn_params.min_conn_int &&
- p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
- (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) ||
- (p_lcb->latency > p_dev_rec->conn_params.slave_latency) ||
- (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout)))
- {
- L2CAP_TRACE_DEBUG ("%s: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", __func__,
- p_lcb->handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int,
- p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout);
-
- p_lcb->min_interval = p_dev_rec->conn_params.min_conn_int;
- p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int;
- p_lcb->timeout = p_dev_rec->conn_params.supervision_tout;
- p_lcb->latency = p_dev_rec->conn_params.slave_latency;
-
- btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle,
- p_dev_rec->conn_params.min_conn_int,
- p_dev_rec->conn_params.max_conn_int,
- p_dev_rec->conn_params.slave_latency,
- p_dev_rec->conn_params.supervision_tout,
- 0, 0);
- }
-}
-
/*******************************************************************************
**
** Function l2cble_notify_le_connection
@@ -301,8 +266,6 @@ void l2cble_notify_le_connection (BD_ADDR bda)
l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, NULL);
}
}
-
- l2cble_use_preferred_conn_params(bda);
}
/*******************************************************************************
@@ -571,6 +534,14 @@ static void l2cble_start_conn_update (tL2C_LCB *p_lcb)
p_lcb->conn_update_mask |= L2C_BLE_NOT_DEFAULT_PARAM;
}
}
+
+ /* Record the BLE connection update request. */
+ if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) {
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, p_lcb->remote_bd_addr);
+ btif_debug_ble_connection_update_request(bd_addr, min_conn_int, max_conn_int, slave_latency,
+ supervision_tout);
+ }
}
/*******************************************************************************
@@ -605,6 +576,12 @@ void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status,
l2cble_start_conn_update(p_lcb);
+ /* Record the BLE connection update response. */
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, p_lcb->remote_bd_addr);
+ btif_debug_ble_connection_update_response(bd_addr, status, interval,
+ latency, timeout);
+
L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d", __func__, p_lcb->conn_update_mask);
}
diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
index 1377af597..5acaba6c7 100644
--- a/stack/sdp/sdp_discovery.c
+++ b/stack/sdp/sdp_discovery.c
@@ -384,10 +384,11 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
cpy_len = rem_len;
}
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d",
- list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
-#endif
+ SDP_TRACE_WARNING(
+ "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
+ "raw_used:%d raw_data:%p",
+ __func__, list_len, cpy_len, p, p_ccb, p_ccb->p_db,
+ p_ccb->p_db->raw_size, p_ccb->p_db->raw_used, p_ccb->p_db->raw_data);
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
p_ccb->p_db->raw_used += cpy_len;
}