1010000 bt_hci_timeout (opcode|1)
1010001 bt_config_source (opcode|1)
1010002 bt_hci_unknown_type (hci_type|1)
-1010003 bt_conn_param_update_status (status|1)
bta_sys_sendmsg(p_buf);
}
-
-void BTA_AgSetScoAllowed(bool value)
-{
- tBTA_AG_API_SET_SCO_ALLOWED *p_buf =
- (tBTA_AG_API_SET_SCO_ALLOWED *)osi_malloc(sizeof(tBTA_AG_API_SET_SCO_ALLOWED));
-
- p_buf->hdr.event = BTA_AG_API_SET_SCO_ALLOWED_EVT;
- p_buf->value = value;
-
- bta_sys_sendmsg(p_buf);
-}
p_scb->peer_features, features);
/* send BRSF, send OK */
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t)features);
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t) features);
bta_ag_send_ok(p_scb);
break;
}
/* these events are handled outside of the state machine */
BTA_AG_API_ENABLE_EVT,
- BTA_AG_API_DISABLE_EVT,
- BTA_AG_API_SET_SCO_ALLOWED_EVT
+ BTA_AG_API_DISABLE_EVT
};
/* Actions to perform after a SCO event */
tBTA_AG_PEER_CODEC codec;
} tBTA_AG_API_SETCODEC;
-/* data type for BTA_AG_API_SET_SCO_ALLOWED_EVT */
-typedef struct
-{
- BT_HDR hdr;
- bool value;
-} tBTA_AG_API_SET_SCO_ALLOWED;
-
/* data type for BTA_AG_DISC_RESULT_EVT */
typedef struct
{
extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param);
extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
-extern void bta_ag_set_sco_allowed(tBTA_AG_DATA *p_data);
#endif /* BTA_AG_INT_H */
bta_ag_api_result((tBTA_AG_DATA *) p_msg);
break;
- case BTA_AG_API_SET_SCO_ALLOWED_EVT:
- bta_ag_set_sco_allowed((tBTA_AG_DATA *) p_msg);
- break;
-
/* all others reference scb by handle */
default:
if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL)
static char *bta_ag_sco_state_str(UINT8 state);
#endif
-static bool sco_allowed = true;
-
#define BTA_AG_NO_EDR_ESCO (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
UINT8 event;
UNUSED(p_data);
- if (!sco_allowed)
- {
- APPL_TRACE_DEBUG("%s not opening sco, by policy", __func__);
- return;
- }
-
/* if another scb using sco, this is a transfer */
if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb)
{
}
}
-void bta_ag_set_sco_allowed(tBTA_AG_DATA *p_data)
-{
- sco_allowed = ((tBTA_AG_API_SET_SCO_ALLOWED *) p_data)->value;
- APPL_TRACE_DEBUG(sco_allowed ? "sco now allowed" : "sco now not allowed");
-}
-
/*******************************************************************************
** Debugging functions
*******************************************************************************/
/*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,
}
}
- 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
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;
void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data)
{
if (!L2CA_UpdateBleConnParams(p_data->ble_update_conn_params.bd_addr,
- p_data->ble_update_conn_params.min_int,
- p_data->ble_update_conn_params.max_int,
- p_data->ble_update_conn_params.latency,
- p_data->ble_update_conn_params.timeout,
- p_data->ble_update_conn_params.p_conn_param_update_cback))
+ p_data->ble_update_conn_params.min_int,
+ p_data->ble_update_conn_params.max_int,
+ p_data->ble_update_conn_params.latency,
+ p_data->ble_update_conn_params.timeout))
{
APPL_TRACE_ERROR("Update connection parameters failed!");
}
UNUSED(p_cback);
#endif
}
+/*******************************************************************************
+**
+** Function BTA_DmBleUpdateConnectionParam
+**
+** Description Update connection parameters, can only be used when connection is up.
+**
+** Parameters: bd_addr - BD address of the peer
+** min_int - minimum connection interval, [0x0004~ 0x4000]
+** max_int - maximum connection interval, [0x0004~ 0x4000]
+** latency - slave latency [0 ~ 500]
+** timeout - supervision timeout [0x000a ~ 0xc80]
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, UINT16 min_int,
+ UINT16 max_int, UINT16 latency,
+ UINT16 timeout)
+{
+#if BLE_INCLUDED == TRUE
+ tBTA_DM_API_UPDATE_CONN_PARAM *p_msg =
+ (tBTA_DM_API_UPDATE_CONN_PARAM *)osi_calloc(sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
+
+ p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->min_int = min_int;
+ p_msg->max_int = max_int;
+ p_msg->latency = latency;
+ p_msg->timeout = timeout;
+
+ bta_sys_sendmsg(p_msg);
+#endif
+}
/*******************************************************************************
**
**
** Description Update connection parameters, can only be used when connection is up.
**
-** Parameters: bd_addr - BD address of the peer
+** Parameters: bd_addr - BD address of the peer
** min_int - minimum connection interval, [0x0004~ 0x4000]
** max_int - maximum connection interval, [0x0004~ 0x4000]
** latency - slave latency [0 ~ 500]
** timeout - supervision timeout [0x000a ~ 0xc80]
- p_cback - callback on connection parameters updated
**
** Returns void
**
*******************************************************************************/
-void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int,
- UINT16 max_int, UINT16 latency, UINT16 timeout,
- tBTA_DM_BLE_CONN_PARAM_CBACK *p_cback)
+void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int, UINT16 max_int,
+ UINT16 latency, UINT16 timeout)
{
tBTA_DM_API_UPDATE_CONN_PARAM *p_msg =
(tBTA_DM_API_UPDATE_CONN_PARAM *)osi_calloc(sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
p_msg->max_int = max_int;
p_msg->latency = latency;
p_msg->timeout = timeout;
- p_msg->p_conn_param_update_cback = p_cback;
bta_sys_sendmsg(p_msg);
}
UINT16 conn_int_max;
UINT16 supervision_tout;
UINT16 slave_latency;
+
}tBTA_DM_API_BLE_CONN_PARAMS;
typedef struct
tBTA_DM_LINK_TYPE link_type;
} tBTA_DM_API_REMOVE_ALL_ACL;
-
-/* data type for BTA_DM_API_UPDATE_CONN_PARAM_EVT */
typedef struct
{
BT_HDR hdr;
UINT16 max_int;
UINT16 latency;
UINT16 timeout;
- tBTA_DM_BLE_CONN_PARAM_CBACK *p_conn_param_update_cback;
-} tBTA_DM_API_UPDATE_CONN_PARAM;
+}tBTA_DM_API_UPDATE_CONN_PARAM;
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
typedef struct
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);
*******************************************************************************/
bool bta_gattc_cache_load(tBTA_GATTC_CLCB *p_clcb)
{
-
-#if (defined WEAR_DISABLE_GATT_CACHE && WEAR_DISABLE_GATT_CACHE == TRUE)
- LOG_WARN(LOG_TAG, "%s GATT cache not used.", __func__);
- return false;
-#endif
-
char fname[255] = {0};
bta_gattc_generate_cache_file_name(fname, p_clcb->p_srcb->server_bda);
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);
/* no match found; disconnect sco, init sco variables */
else
{
- /* should not force the sco state to shutdown state here */
+ bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
BTM_RemoveSco(sco_idx);
}
}
if (tout < BTM_BLE_CONN_TIMEOUT_MIN_DEF)
tout = BTM_BLE_CONN_TIMEOUT_MIN_DEF;
- BTM_BleSetPrefConnParams(p_dev_cb->addr, min, max, latency, tout);
- L2CA_UpdateBleConnParams(p_dev_cb->addr, min, max, latency, tout, NULL);
+ BTM_BleSetPrefConnParams (p_dev_cb->addr, min, max, latency, tout);
+ L2CA_UpdateBleConnParams(p_dev_cb->addr, min, max, latency, tout);
}
else
{
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;
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;
}
*******************************************************************************/
void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec);
-void BTA_AgSetScoAllowed(bool value);
-
#ifdef __cplusplus
}
#endif
#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
typedef void (tBTA_DM_BLE_PF_STATUS_CBACK) (UINT8 action, tBTA_STATUS status,
tBTA_DM_BLE_REF_VALUE ref_value);
-/* Connection update callback */
-typedef void (tBTA_DM_BLE_CONN_PARAM_CBACK) (BD_ADDR bd_addr, UINT16 interval, UINT16 latency,
- UINT16 timeout, tBTA_STATUS status);
#define BTA_DM_BLE_PF_BRDCAST_ADDR_FILT 1
#define BTA_DM_BLE_PF_SERV_DATA_CHG_FILT 2
**
** Description Update connection parameters, can only be used when connection is up.
**
-** Parameters: bd_addr - BD address of the peer
+** Parameters: bd_addr - BD address of the peer
** min_int - minimum connection interval, [0x0004~ 0x4000]
** max_int - maximum connection interval, [0x0004~ 0x4000]
** latency - slave latency [0 ~ 500]
** Returns void
**
*******************************************************************************/
-extern void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int, UINT16 max_int,
- UINT16 latency, UINT16 timeout,
- tBTA_DM_BLE_CONN_PARAM_CBACK p_cback);
+extern void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int,
+ UINT16 max_int, UINT16 latency, UINT16 timeout);
/*******************************************************************************
**
#define BTA_GATTC_SCAN_FLT_PARAM_EVT 32 /* Param filter event */
#define BTA_GATTC_SCAN_FLT_STATUS_EVT 33 /* Filter status event */
#define BTA_GATTC_ADV_VSC_EVT 34 /* ADV VSC event */
-#define BTA_GATTC_CONN_PARAM_UPD_EVT 35 /* Connection parameter update event */
typedef UINT8 tBTA_GATTC_EVT;
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;
}
}
uint32_t disc_timeout;
bt_bdaddr_t bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
- bt_status_t status;
num_props = 0;
/* BD_ADDR */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
sizeof(addr), &addr);
- status = btif_storage_get_adapter_property(&properties[num_props]);
- // Add BT_PROPERTY_BDADDR property into list only when successful.
- // Otherwise, skip this property entry.
- if (status == BT_STATUS_SUCCESS) {
- num_props++;
- }
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
/* BD_NAME */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDNAME,
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);
#endif
static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
}
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) &&
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)
{
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;
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);
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);
}
btif_storage_remove_bonded_device(&bdaddr);
state = BT_BOND_STATE_NONE;
} else {
- /*
- * Note: This is a Wear-specific feature for iOS pairing.
- * Store the address of the first bonded device that is also of type LE to
- * enable auto connection parameter update.
- */
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
- if (btif_storage_get_num_bonded_devices() == 0) {
- bdstr_t bdstr;
- bdaddr_to_string(&bdaddr, bdstr, sizeof(bdstr));
- btif_config_set_str("Adapter", "AutoConnParamUpdateAddr", bdstr);
- }
-#endif
btif_dm_save_ble_bonding_keys();
BTA_GATTC_Refresh(bd_addr.address);
btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
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;
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)
{
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);
}
#include "btif_gatt_multi_adv_util.h"
#include "btif_gatt_util.h"
#include "btif_storage.h"
+#include "btif_storage.h"
#include "osi/include/log.h"
-#include "osi/include/alarm.h"
-#include "stack/include/gatt_api.h"
#include "vendor_api.h"
/*******************************************************************************
#define BLE_RESOLVE_ADDR_MSB 0x40 /* bit7, bit6 is 01 to be resolvable random */
#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */
#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
-#define BT_CONN_PARAM_UPDATE_STATUS 1010003
typedef enum {
BTIF_GATTC_REGISTER_APP = 1000,
typedef struct
{
- uint8_t client_if;
bt_bdaddr_t bd_addr;
- uint16_t requested_min_interval;
- uint16_t requested_max_interval;
- uint16_t configured_interval;
+ uint16_t min_interval;
+ uint16_t max_interval;
uint16_t timeout;
uint16_t latency;
- uint8_t status;
-}__attribute__((packed)) btif_conn_param_cb_t;
+} btif_conn_param_cb_t;
typedef struct
{
static uint8_t rssi_request_client_if;
/*******************************************************************************
-** Auto Connection Parameter Update
-**
-** Feature is enabled when WEAR_AUTO_CONN_PARAM_UPDATE build config is set to
-** TRUE. It looks for a whitelisted address in the configuration file and
-** automatically applies a connection interval parameter update
-** (WEAR_AUTO_CONN_IDLE_INTERVAL_1_25_MS) when the connection is idle for a
-** specific period of time (WEAR_AUTO_CONN_IDLE_TIMEOUT_MS).
-********************************************************************************/
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
-typedef struct
-{
- bt_bdaddr_t device_address;
- uint16_t min_interval;
- uint16_t max_interval;
- uint16_t timeout;
- uint16_t latency;
- bool is_auto_update_address_known;
- bool is_auto_update_enabled;
- bool is_updating;
- alarm_t *check_idle_alarm;
-} btgatt_auto_connection_param_update_cb_t;
-
-static btgatt_auto_connection_param_update_cb_t auto_conn_param_update_cb;
-
-static bt_status_t btif_gattc_conn_parameter_update_internal(const bt_bdaddr_t *bd_addr, int min_interval,
- int max_interval, int latency, int timeout);
-
-static void auto_connection_param_update_idle_cb(UNUSED_ATTR void *data)
-{
- btgatt_auto_connection_param_update_cb_t *auto_update_cb =
- (btgatt_auto_connection_param_update_cb_t *)data;
-
- if (auto_conn_param_update_cb.is_updating)
- {
- LOG_WARN(LOG_TAG, "%s another connection update in progress", __FUNCTION__);
- return;
- }
-
- btif_gattc_conn_parameter_update_internal(&auto_update_cb->device_address,
- WEAR_AUTO_CONN_IDLE_INTERVAL_1_25_MS, WEAR_AUTO_CONN_IDLE_INTERVAL_1_25_MS, 0, 2000);
- LOG_INFO(LOG_TAG, "%s auto adjust connection interval to %dms", __FUNCTION__,
- (int)(WEAR_AUTO_CONN_IDLE_INTERVAL_1_25_MS * 1.25f));
-}
-
-static void maybe_set_connection_param_update_in_progress(const bt_bdaddr_t *bd_addr, bool in_progress)
-{
- if (auto_conn_param_update_cb.is_auto_update_enabled &&
- bdcmp(auto_conn_param_update_cb.device_address.address, bd_addr->address) == 0)
- {
- auto_conn_param_update_cb.is_updating = in_progress;
- }
-}
-
-static void maybe_enable_auto_connection_param_update(const bt_bdaddr_t *bd_addr, int min_interval,
- int max_interval, int latency, int timeout)
-{
- /* First check if there is a whitelisted address to enable auto connection param update */
- if (!auto_conn_param_update_cb.is_auto_update_address_known)
- {
- bdstr_t bdstr;
- int bdstr_size = sizeof(bdstr);
- /*
- * If AutoConnParamUpdateAddr is not set from bonding, infer the first LE address performing
- * connection parameter update as the companion.
- */
- if (!btif_config_get_str("Adapter", "AutoConnParamUpdateAddr", bdstr, &bdstr_size)) {
- bdaddr_to_string(bd_addr, bdstr, bdstr_size);
- btif_config_set_str("Adapter", "AutoConnParamUpdateAddr", bdstr);
- LOG_INFO(LOG_TAG, "%s force set AutoConnParamUpdateAddr: %s", __FUNCTION__, bdstr);
- }
-
- bdcpy(auto_conn_param_update_cb.device_address.address, bd_addr->address);
- auto_conn_param_update_cb.is_auto_update_address_known = true;
- LOG_INFO(LOG_TAG, "%s auto connection param update for address: %s", __FUNCTION__, bdstr);
- }
-
- /* If the address matches the auto update address, store the connection parameter value */
- if (bdcmp(auto_conn_param_update_cb.device_address.address, bd_addr->address) == 0)
- {
- auto_conn_param_update_cb.min_interval = min_interval;
- auto_conn_param_update_cb.max_interval = max_interval;
- auto_conn_param_update_cb.timeout = timeout;
- auto_conn_param_update_cb.latency = latency;
- auto_conn_param_update_cb.is_auto_update_enabled = true;
- }
-}
-
-static void maybe_restore_connection_parameters(BD_ADDR address) {
- /*
- * Will not perform auto connection parameter update if:
- *
- * - feature not enabled (yet)
- * - address doesn't match auto update address
- * - connection parameter update is in progress
- */
- if (!auto_conn_param_update_cb.is_auto_update_enabled ||
- (bdcmp(auto_conn_param_update_cb.device_address.address, address) != 0) ||
- auto_conn_param_update_cb.is_updating)
- {
- return;
- }
-
- if (alarm_is_scheduled(auto_conn_param_update_cb.check_idle_alarm))
- {
- /* Idle alarm is scheduled, reschedule it */
- alarm_cancel(auto_conn_param_update_cb.check_idle_alarm);
- }
- else
- {
- /* No idle alarm and no update in progress, restore specified connection parameters */
- btif_gattc_conn_parameter_update_internal(&auto_conn_param_update_cb.device_address,
- auto_conn_param_update_cb.min_interval,
- auto_conn_param_update_cb.max_interval,
- auto_conn_param_update_cb.latency,
- auto_conn_param_update_cb.timeout);
- LOG_VERBOSE(LOG_TAG, "%s restore connection parameters", __FUNCTION__);
- }
-
- /* Schedule idle alarm */
- if (!auto_conn_param_update_cb.check_idle_alarm)
- {
- auto_conn_param_update_cb.check_idle_alarm =
- alarm_new("gatt_client.auto_conn_param_update_idle_alarm");
- }
- alarm_set(auto_conn_param_update_cb.check_idle_alarm, WEAR_AUTO_CONN_IDLE_TIMEOUT_MS,
- auto_connection_param_update_idle_cb, &auto_conn_param_update_cb);
-
- return;
-}
-#endif
-
-/*******************************************************************************
** Static functions
********************************************************************************/
if (p_data->notify.is_notify == FALSE)
BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, p_data->notify.handle);
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
- maybe_restore_connection_parameters(data.bda.address);
-#endif
-
break;
}
break;
}
- case BTA_GATTC_CONN_PARAM_UPD_EVT:
- {
- btif_conn_param_cb_t *p_btif_cb = (btif_conn_param_cb_t *)p_param;
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
- maybe_set_connection_param_update_in_progress(&p_btif_cb->bd_addr, false);
-#endif
- /* Log update failures */
- if (p_btif_cb->status != 0)
- {
- LOG_EVENT_INT(BT_CONN_PARAM_UPDATE_STATUS, p_btif_cb->status);
- }
- break;
- }
-
case BTIF_GATTC_SCAN_PARAM_EVT:
{
btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t *)p_param;
(char*) &btif_cb, sizeof(btgatt_adv_filter_cb_t), NULL);
}
-static void bta_gattc_conn_param_update_cback(BD_ADDR bd_addr, UINT16 interval,
- UINT16 latency, UINT16 timeout, tBTA_STATUS status)
-{
- btif_conn_param_cb_t btif_cb;
-
- bdcpy(btif_cb.bd_addr.address, bd_addr);
- btif_cb.configured_interval = interval;
- btif_cb.latency = latency;
- btif_cb.timeout = timeout;
- btif_cb.status = status;
- btif_transfer_context(btif_gattc_upstreams_evt, BTA_GATTC_CONN_PARAM_UPD_EVT,
- (char*) &btif_cb, sizeof(btif_conn_param_cb_t), NULL);
-}
-
static void btgattc_free_event_data(UINT16 event, char *event_data)
{
switch (event)
break;
case BTIF_GATTC_WRITE_CHAR:
- {
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
- /* TODO(jackyc): find a cleaner way to get address from connection id */
- tGATT_IF gatt_if;
- BD_ADDR bd_addr;
- tBT_TRANSPORT transport;
- if (GATT_GetConnectionInfor(p_cb->conn_id, &gatt_if, bd_addr, &transport) == TRUE)
- {
- maybe_restore_connection_parameters(bd_addr);
- }
-#endif
BTA_GATTC_WriteCharValue(p_cb->conn_id, p_cb->handle, p_cb->write_type,
p_cb->len, p_cb->value, p_cb->auth_req);
break;
- }
case BTIF_GATTC_WRITE_CHAR_DESCR:
descr_val.len = p_cb->len;
if (BTA_DmGetConnectionState(p_conn_param_cb->bd_addr.address))
{
BTA_DmBleUpdateConnectionParams(p_conn_param_cb->bd_addr.address,
- p_conn_param_cb->requested_min_interval,
- p_conn_param_cb->requested_max_interval,
- p_conn_param_cb->latency, p_conn_param_cb->timeout,
- bta_gattc_conn_param_update_cback);
+ p_conn_param_cb->min_interval, p_conn_param_cb->max_interval,
+ p_conn_param_cb->latency, p_conn_param_cb->timeout);
} else {
BTA_DmSetBlePrefConnParams(p_conn_param_cb->bd_addr.address,
- p_conn_param_cb->requested_min_interval,
- p_conn_param_cb->requested_max_interval,
+ p_conn_param_cb->min_interval, p_conn_param_cb->max_interval,
p_conn_param_cb->latency, p_conn_param_cb->timeout);
}
break;
(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}
-static bt_status_t btif_gattc_conn_parameter_update_internal(const bt_bdaddr_t *bd_addr, int min_interval,
- int max_interval, int latency, int timeout)
+static bt_status_t btif_gattc_conn_parameter_update(const bt_bdaddr_t *bd_addr, int min_interval,
+ int max_interval, int latency, int timeout)
{
CHECK_BTGATT_INIT();
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
- maybe_set_connection_param_update_in_progress(bd_addr, true);
-#endif
btif_conn_param_cb_t btif_cb;
- btif_cb.requested_min_interval = min_interval;
- btif_cb.requested_max_interval = max_interval;
+ btif_cb.min_interval = min_interval;
+ btif_cb.max_interval = max_interval;
btif_cb.latency = latency;
btif_cb.timeout = timeout;
bdcpy(btif_cb.bd_addr.address, bd_addr->address);
(char*) &btif_cb, sizeof(btif_conn_param_cb_t), NULL);
}
-static bt_status_t btif_gattc_conn_parameter_update(const bt_bdaddr_t *bd_addr, int min_interval,
- int max_interval, int latency, int timeout)
-{
-#if (defined(WEAR_AUTO_CONN_PARAM_UPDATE) && (WEAR_AUTO_CONN_PARAM_UPDATE == TRUE))
- maybe_enable_auto_connection_param_update(bd_addr, min_interval, max_interval, latency, timeout);
-#endif
-
- return btif_gattc_conn_parameter_update_internal(bd_addr, min_interval, max_interval, latency, timeout);
-}
-
static bt_status_t btif_gattc_scan_filter_param_setup(btgatt_filt_param_setup_t
filt_param)
{
return BT_STATUS_SUCCESS;
}
-static bt_status_t set_sco_allowed(bool value)
-{
- CHECK_BTHF_INIT();
-
- BTA_AgSetScoAllowed(value);
- return BT_STATUS_SUCCESS;
-}
-
/*******************************************************************************
**
** Function formatted_at_response
cleanup,
configure_wbs,
bind_response,
- set_sco_allowed,
};
/*******************************************************************************
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;
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;
alarm_t *media_alarm;
alarm_t *decode_alarm;
btif_media_stats_t stats;
+ btif_media_stats_t accumulated_stats;
#endif
} tBTIF_MEDIA_CB;
/*****************************************************************************
** 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)
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
{
assert(CHAR_BIT == 8);
memset(&btif_media_cb, 0, sizeof(btif_media_cb));
- btif_media_cb.stats.session_start_us = time_now_us();
UIPC_Init(NULL);
raise_priority_a2dp(TASK_HIGH_MEDIA);
media_task_running = MEDIA_TASK_STATE_ON;
+ metrics_log_bluetooth_session_start(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
}
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);
}
/*******************************************************************************
p_buf->event = BTIF_MEDIA_START_AA_TX;
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;
}
* 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;
}
}
/* 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;
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));
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;
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);
}
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "device/include/controller.h"
-
/************************************************************************************
** Constants & Macros
************************************************************************************/
/* This is a local property to add a device found */
#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
-// TODO: This macro should be converted to a function
-#define BTIF_STORAGE_GET_ADAPTER_PROP(s, t,v,l,p) \
- {p.type=t;p.val=v;p.len=l; s = btif_storage_get_adapter_property(&p);}
+#define BTIF_STORAGE_GET_ADAPTER_PROP(t,v,l,p) \
+ {p.type=t;p.val=v;p.len=l; btif_storage_get_adapter_property(&p);}
-// TODO: This macro should be converted to a function
#define BTIF_STORAGE_GET_REMOTE_PROP(b,t,v,l,p) \
{p.type=t;p.val=v;p.len=l;btif_storage_get_remote_device_property(b,&p);}
if (property->type == BT_PROPERTY_BDADDR)
{
bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)property->val;
- /* Fetch the local BD ADDR */
- const controller_t* controller = controller_get_interface();
- if (controller->get_is_ready() == false) {
- BTIF_TRACE_DEBUG("%s: Controller not ready! Unable to return Bluetooth Address",
- __FUNCTION__);
- memset(bd_addr, 0, sizeof(bt_bdaddr_t));
- return BT_STATUS_FAIL;
- } else {
- BTIF_TRACE_DEBUG("%s: Controller ready!", __FUNCTION__);
- memcpy(bd_addr, controller->get_address(), sizeof(bt_bdaddr_t));
- }
+ /* This has been cached in btif. Just fetch it from there */
+ memcpy(bd_addr, &btif_local_bd_addr, sizeof(bt_bdaddr_t));
property->len = sizeof(bt_bdaddr_t);
return BT_STATUS_SUCCESS;
}
uint32_t disc_timeout;
bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
- bt_status_t status;
btif_in_fetch_bonded_devices(&bonded_devices, 1);
memset(adapter_props, 0, sizeof(adapter_props));
/* BD_ADDR */
- BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_BDADDR, &addr, sizeof(addr),
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDADDR, &addr, sizeof(addr),
adapter_props[num_props]);
- // Add BT_PROPERTY_BDADDR property into list only when successful.
- // Otherwise, skip this property entry.
- if (status == BT_STATUS_SUCCESS) {
- num_props++;
- }
+ num_props++;
/* BD_NAME */
- BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_BDNAME, &name, sizeof(name),
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDNAME, &name, sizeof(name),
adapter_props[num_props]);
num_props++;
num_props++;
/* DISC_TIMEOUT */
- BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
&disc_timeout, sizeof(disc_timeout),
adapter_props[num_props]);
num_props++;
num_props++;
/* LOCAL UUIDs */
- BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_UUIDS,
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_UUIDS,
local_uuids, sizeof(local_uuids),
adapter_props[num_props]);
num_props++;
BtSnoopLogOutput=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
// Keyboards should use a variable pin at all times. However, some keyboards
// require a fixed pin of all 0000. This workaround enables auto pairing for
// those keyboards.
- INTEROP_KEYBOARD_REQUIRES_FIXED_PIN
+ INTEROP_KEYBOARD_REQUIRES_FIXED_PIN,
+
+ // Some headsets have audio jitter issues because of increased re-transmissions as the
+ // 3 Mbps packets have a lower link margin, and are more prone to interference. We can
+ // disable 3DH packets (use only 2DH packets) for the ACL link to improve sensitivity
+ // when streaming A2DP audio to the headset. Air sniffer logs show reduced
+ // re-transmissions after switching to 2DH packets.
+ //
+ // Disable 3Mbps packets and use only 2Mbps packets for ACL links when streaming audio.
+ INTEROP_2MBPS_LINK_ONLY
} interop_feature_t;
// Check if a given |addr| matches a known interoperability workaround as identified
{{{0x44, 0x5e, 0xf3, 0,0,0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
{{{0xd4, 0x9c, 0x28, 0,0,0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+ // JayBird Family
+ {{{0x00, 0x18, 0x91, 0,0,0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+
// LG Tone HBS-730 - unacceptably loud volume
{{{0x00, 0x18, 0x6b, 0,0,0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
{{{0xb8, 0xad, 0x3e, 0,0,0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
+ CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
}
return "UNKNOWN";
gettimeofday(&tv, NULL);
// Timestamp is in microseconds.
- uint64_t timestamp = tv.tv_sec;
- timestamp *= (uint64_t)1000000ULL;
+ uint64_t timestamp = tv.tv_sec * 1000 * 1000LL;
timestamp += tv.tv_usec;
timestamp += BTSNOOP_EPOCH_DELTA;
return timestamp;
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 {
/* 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
-
-/*
- * Enable/disable LE auto connection parameter update.
- * When enabled, the first bonded device that is also of type LE will be whitelisted
- * to use auto connection parameter update.
- */
-#ifndef WEAR_AUTO_CONN_PARAM_UPDATE
-#define WEAR_AUTO_CONN_PARAM_UPDATE FALSE
-#endif
-
-/*
- * Idle timeout period in milliseconds for auto connection parameter update.
- * Only used when WEAR_AUTO_CONN_PARAM_UPDATE is enabled.
- */
-#ifndef WEAR_AUTO_CONN_IDLE_TIMEOUT_MS
-#define WEAR_AUTO_CONN_IDLE_TIMEOUT_MS 10000
-#endif
-
-/*
- * Connection interval parameter applied when the connection is detected to be idle for
- * WEAR_AUTO_CONN_IDLE_TIMEOUT_MS of time.
- * Only used when WEAR_AUTO_CONN_PARAM_UPDATE is enabled.
- */
-#ifndef WEAR_AUTO_CONN_IDLE_INTERVAL_1_25_MS
-#define WEAR_AUTO_CONN_IDLE_INTERVAL_1_25_MS 72
-#endif
-
-/*
- * Disable the use of local GATT cache. This forces service discovery on connection
- * establishment.
- */
-#ifndef WEAR_DISABLE_GATT_CACHE
-#define WEAR_DISABLE_GATT_CACHE TRUE
+#define WEAR_LE_IO_CAP_OVERRIDE FALSE
#endif
#endif /* BT_TARGET_H */
// 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) {
./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 \
btosiCommonIncludes := \
$(LOCAL_PATH)/.. \
+ $(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../utils/include \
$(LOCAL_PATH)/../stack/include \
$(bluetooth_C_INCLUDES)
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)
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)
"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",
deps = [
"//osi",
"//third_party/googletest:gtest_main",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
]
libs = [
--- /dev/null
+/******************************************************************************
+ *
+ * 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
#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,
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,
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
--- /dev/null
+/******************************************************************************
+ *
+ * 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
* 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;
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) {
}
}
-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);
}
* 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
}
// 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.
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;
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;
// 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 {
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.
// Buffer underruns count.
optional int32 buffer_underruns_count = 7;
+
+ // Total audio time in this A2DP session
+ optional int64 audio_duration_millis = 8;
}
message PairEvent {
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);
}
//
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) {
--- /dev/null
+/******************************************************************************
+ *
+ * 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;
+}
+}
--- /dev/null
+/******************************************************************************
+ *
+ * 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_));
+}
+}
#include "l2cdefs.h"
#include "btm_api.h"
#include "btm_int.h"
-
+#include "device/include/interop.h"
/* callback function declarations */
void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
p_tbl->state = AVDT_AD_ST_SEC_ACP;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
- // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
- tACL_CONN *p_acl_cb = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
- btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
- HCI_PKT_TYPES_MASK_NO_3_DH1 |
- HCI_PKT_TYPES_MASK_NO_3_DH3 |
- HCI_PKT_TYPES_MASK_NO_3_DH5));
+ if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *)&bd_addr)) {
+ // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
+ tACL_CONN *p_acl_cb = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+ btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
+ HCI_PKT_TYPES_MASK_NO_3_DH1 |
+ HCI_PKT_TYPES_MASK_NO_3_DH3 |
+ HCI_PKT_TYPES_MASK_NO_3_DH5));
+ }
/* Check the security */
rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
p_tbl->lcid = lcid;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
- // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
- tACL_CONN *p_acl_cb = btm_bda_to_acl(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
- btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
- HCI_PKT_TYPES_MASK_NO_3_DH1 |
- HCI_PKT_TYPES_MASK_NO_3_DH3 |
- HCI_PKT_TYPES_MASK_NO_3_DH5));
+ if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *) &p_ccb->peer_addr)) {
+ // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
+ tACL_CONN *p_acl_cb = btm_bda_to_acl(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
+ btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
+ HCI_PKT_TYPES_MASK_NO_3_DH1 |
+ HCI_PKT_TYPES_MASK_NO_3_DH3 |
+ HCI_PKT_TYPES_MASK_NO_3_DH5));
+ }
/* Check the security */
btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
** 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;
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
}
#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))
break;
}
** 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");
** 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);
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;
}
#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
** 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);
** 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]);
** 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;
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);
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);
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);
if (ret)
{
if (!opportunistic)
- gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE);
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
else
GATT_TRACE_DEBUG("%s: connection is opportunistic, not updating app usage",
__func__);
** 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);
/*******************************************************************************
** 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);
/*******************************************************************************
**
** 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);
/*******************************************************************************
*******************************************************************************/
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);
+
/*******************************************************************************
**
#include "bt_target.h"
#include "l2cdefs.h"
#include "hcidefs.h"
-#include "bta_api.h"
/*****************************************************************************
** Constants
** Return value: TRUE if update started
**
*******************************************************************************/
-extern BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bdRa, UINT16 min_int, UINT16 max_int,
- UINT16 latency, UINT16 timeout,
- tBTA_DM_BLE_CONN_PARAM_CBACK *p_cback);
+extern BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bdRa, UINT16 min_int,
+ UINT16 max_int, UINT16 latency, UINT16 timeout);
/*******************************************************************************
**
** Return value: TRUE if update started
**
*******************************************************************************/
-BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int,
- UINT16 max_int, UINT16 latency, UINT16 timeout,
- tBTA_DM_BLE_CONN_PARAM_CBACK *p_callback)
+BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_int,
+ UINT16 latency, UINT16 timeout)
{
tL2C_LCB *p_lcb;
tACL_CONN *p_acl_cb = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE);
p_lcb->latency = latency;
p_lcb->timeout = timeout;
p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
- p_lcb->p_conn_param_update_cb = p_callback;
l2cble_start_conn_update(p_lcb);
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
l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, NULL);
}
}
-
- l2cble_use_preferred_conn_params(bda);
}
/*******************************************************************************
*******************************************************************************/
static void l2cble_start_conn_update (tL2C_LCB *p_lcb)
{
+ UINT16 min_conn_int, max_conn_int, slave_latency, supervision_tout;
tACL_CONN *p_acl_cb = btm_bda_to_acl(p_lcb->remote_bd_addr, BT_TRANSPORT_LE);
// TODO(armansito): The return value of this call wasn't being used but the
if (p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE)
{
- UINT16 min_conn_int, max_conn_int, slave_latency, supervision_tout;
/* application requests to disable parameters update.
If parameters are already updated, lets set them
up to what has been requested during connection establishement */
btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, p_lcb->min_interval,
p_lcb->max_interval, p_lcb->latency, p_lcb->timeout, 0, 0);
p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
-
- /* Record the BLE connection update request if the role is master device */
- bt_bdaddr_t bd_addr;
- bdcpy(bd_addr.address, p_lcb->remote_bd_addr);
- btif_debug_ble_connection_update_request(bd_addr, p_lcb->min_interval, p_lcb->max_interval,
- p_lcb->latency, p_lcb->timeout);
}
else
{
}
p_lcb->conn_update_mask &= ~L2C_BLE_NEW_CONN_PARAM;
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);
+ }
}
/*******************************************************************************
l2cble_start_conn_update(p_lcb);
- /* Callback to upper layer */
- if (p_lcb->p_conn_param_update_cb) {
- p_lcb->p_conn_param_update_cb(p_lcb->remote_bd_addr, interval, latency,
- timeout, status);
- }
-
/* Record the BLE connection update response. */
bt_bdaddr_t bd_addr;
bdcpy(bd_addr.address, p_lcb->remote_bd_addr);
UINT16 latency;
UINT16 timeout;
- tBTA_DM_BLE_CONN_PARAM_CBACK *p_conn_param_update_cb;
#endif
#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
extern BOOLEAN l2cu_create_conn (tL2C_LCB *p_lcb, tBT_TRANSPORT transport);
extern BOOLEAN l2cu_create_conn_after_switch (tL2C_LCB *p_lcb);
-extern BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb, UINT16 *fixed_cid);
+extern BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb);
extern void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda);
extern void l2cu_initialize_amp_ccb (tL2C_LCB *p_lcb);
extern void l2cu_adjust_out_mps (tL2C_CCB *p_ccb);
extern fixed_queue_t *btu_general_alarm_queue;
-static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf, UINT16 fixed_cid);
+static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf);
/*******************************************************************************
**
{
int xx;
BOOLEAN single_write = FALSE;
- UINT16 fixed_cid;
/* Save the channel ID for faster counting */
if (p_buf)
/* Loop through, starting at the next */
for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
{
- /* Check for wraparound */
- if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
- p_lcb = &l2cb.lcb_pool[0];
-
/* If controller window is full, nothing to do */
- if (p_lcb->transport == BT_TRANSPORT_BR_EDR &&
- (l2cb.controller_xmit_window == 0 ||
- l2cb.round_robin_unacked >= l2cb.round_robin_quota))
- {
+ if (((l2cb.controller_xmit_window == 0 ||
+ (l2cb.round_robin_unacked >= l2cb.round_robin_quota))
#if (BLE_INCLUDED == TRUE)
- continue;
+ && (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+ )
+ || (p_lcb->transport == BT_TRANSPORT_LE &&
+ (l2cb.ble_round_robin_unacked >= l2cb.ble_round_robin_quota ||
+ l2cb.controller_le_xmit_window == 0 )))
#else
- /* No more quota and only BR/EDR supported, so nothing more to do*/
- break;
+ ))
#endif
- }
+ break;
-#if (BLE_INCLUDED == TRUE)
- if (p_lcb->transport == BT_TRANSPORT_LE &&
- (l2cb.controller_le_xmit_window == 0 ||
- l2cb.ble_round_robin_unacked >= l2cb.ble_round_robin_quota))
- {
- continue;
- }
-#endif
+
+ /* Check for wraparound */
+ if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
+ p_lcb = &l2cb.lcb_pool[0];
if ( (!p_lcb->in_use)
|| (p_lcb->partial_segment_being_sent)
if (!list_is_empty(p_lcb->link_xmit_data_q)) {
p_buf = (BT_HDR *)list_front(p_lcb->link_xmit_data_q);
list_remove(p_lcb->link_xmit_data_q, p_buf);
- l2c_link_send_to_lower (p_lcb, p_buf, 0);
+ l2c_link_send_to_lower (p_lcb, p_buf);
}
else if (single_write)
{
break;
}
/* If nothing on the link queue, check the channel queue */
- else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb, &fixed_cid)) != NULL)
+ else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
{
- l2c_link_send_to_lower (p_lcb, p_buf, fixed_cid);
+ l2c_link_send_to_lower (p_lcb, p_buf);
}
}
p_buf = (BT_HDR *)list_front(p_lcb->link_xmit_data_q);
list_remove(p_lcb->link_xmit_data_q, p_buf);
- if (!l2c_link_send_to_lower (p_lcb, p_buf, 0))
+ if (!l2c_link_send_to_lower (p_lcb, p_buf))
break;
}
while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
#endif
{
- if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb, &fixed_cid)) == NULL)
+ if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)
break;
- if (!l2c_link_send_to_lower (p_lcb, p_buf, fixed_cid))
+ if (!l2c_link_send_to_lower (p_lcb, p_buf))
break;
}
}
** Returns TRUE for success, FALSE for fail
**
*******************************************************************************/
-static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf, UINT16 fixed_cid)
+static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
{
UINT16 num_segs;
UINT16 xmit_window, acl_data_size;
}
#endif
- if (fixed_cid != 0)
- {
- L2CAP_TRACE_DEBUG("%s: fixed_cid = %d, send tx complete", __func__, fixed_cid);
- /* send tx complete */
- if (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedTxComplete_Cb)
- {
- (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedTxComplete_Cb)(fixed_cid, 1);
- }
- }
return TRUE;
}
{
if (!p_lcb->ccb_queue.p_first_ccb)
{
- // Closing a security channel on LE device should not start connection
- // timeout
- if (p_lcb->transport == BT_TRANSPORT_LE &&
- p_ccb->local_cid == L2CAP_SMP_CID)
- return;
-
l2cu_no_dynamic_ccbs (p_lcb);
}
else
** Returns pointer to buffer or NULL
**
*******************************************************************************/
-BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb, UINT16 *fixed_cid)
+BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb)
{
tL2C_CCB *p_ccb;
BT_HDR *p_buf;
#if (L2CAP_NUM_FIXED_CHNLS > 0)
int xx;
- *fixed_cid = 0;
for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
{
if ((p_ccb = p_lcb->p_fixed_ccbs[xx]) == NULL)
L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send: No data to be sent");
return (NULL);
}
- if (fixed_cid != NULL)
- {
- *fixed_cid = p_ccb->local_cid;
- L2CAP_TRACE_DEBUG("l2cu_get_buffer_to_send: fixed_cid = %d", *fixed_cid);
- }
+ /* send tx complete */
+ if (l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)
+ (*l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)(p_ccb->local_cid, 1);
l2cu_check_channel_congestion (p_ccb);
l2cu_set_acl_hci_header (p_buf, p_ccb);
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;
}