diff options
author | Arne Coucheron <arco68@gmail.com> | 2017-04-05 01:59:46 +0200 |
---|---|---|
committer | Dan Pasanen <dan.pasanen@gmail.com> | 2017-04-05 11:13:15 -0500 |
commit | c0e5c0bc6667b80a95805c30d65601a309c2f2f6 (patch) | |
tree | 4b53ab727c41d07f8d4868e8ed900905a745cf6f | |
parent | 838550cd605956e5dc4e29fdf826a58ba3ff8161 (diff) | |
parent | 5a9925784a4a34811ae29608b67dee4a580c226b (diff) | |
download | android_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
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; } |