Merge "Mask "LE Enhanced Connection Complete" when BLE_PRIVACY_SPT=FALSE"
diff --git a/audio_a2dp_hw/src/audio_a2dp_hw.cc b/audio_a2dp_hw/src/audio_a2dp_hw.cc
index a43a4fb..3622298 100644
--- a/audio_a2dp_hw/src/audio_a2dp_hw.cc
+++ b/audio_a2dp_hw/src/audio_a2dp_hw.cc
@@ -427,10 +427,12 @@
DEBUG("A2DP COMMAND %s", audio_a2dp_hw_dump_ctrl_event(cmd));
if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- INFO("starting up or recovering from previous error");
+ INFO("starting up or recovering from previous error: command=%s",
+ audio_a2dp_hw_dump_ctrl_event(cmd));
a2dp_open_ctrl_path(common);
if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- ERROR("failure to open ctrl path");
+ ERROR("failure to open ctrl path: command=%s",
+ audio_a2dp_hw_dump_ctrl_event(cmd));
return -1;
}
}
@@ -439,7 +441,8 @@
ssize_t sent;
OSI_NO_INTR(sent = send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL));
if (sent == -1) {
- ERROR("cmd failed (%s)", strerror(errno));
+ ERROR("cmd failed (%s): command=%s", strerror(errno),
+ audio_a2dp_hw_dump_ctrl_event(cmd));
skt_disconnect(common->ctrl_fd);
common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
return -1;
@@ -454,7 +457,10 @@
DEBUG("A2DP COMMAND %s DONE STATUS %d", audio_a2dp_hw_dump_ctrl_event(cmd),
ack);
- if (ack == A2DP_CTRL_ACK_INCALL_FAILURE) return ack;
+ if (ack == A2DP_CTRL_ACK_INCALL_FAILURE) {
+ ERROR("A2DP COMMAND %s error %d", audio_a2dp_hw_dump_ctrl_event(cmd), ack);
+ return ack;
+ }
if (ack != A2DP_CTRL_ACK_SUCCESS) {
ERROR("A2DP COMMAND %s error %d", audio_a2dp_hw_dump_ctrl_event(cmd), ack);
return -1;
@@ -742,7 +748,8 @@
static int a2dp_get_presentation_position_cmd(struct a2dp_stream_common* common,
uint64_t* bytes, uint16_t* delay,
struct timespec* timestamp) {
- if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) { // Already disconnected
+ if ((common->ctrl_fd == AUDIO_SKT_DISCONNECTED) ||
+ (common->state != AUDIO_A2DP_STATE_STARTED)) { // Audio is not streaming
return -1;
}
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
index 90c34b0..9676761 100644
--- a/binder/android/bluetooth/IBluetooth.aidl
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -47,6 +47,11 @@
BluetoothClass getBluetoothClass();
boolean setBluetoothClass(in BluetoothClass bluetoothClass);
+ int getIoCapability();
+ boolean setIoCapability(int capability);
+ int getLeIoCapability();
+ boolean setLeIoCapability(int capability);
+
int getScanMode();
boolean setScanMode(int mode, int duration);
diff --git a/binder/android/bluetooth/IBluetoothHeadset.aidl b/binder/android/bluetooth/IBluetoothHeadset.aidl
index 60a92d2..f8dfb65 100644
--- a/binder/android/bluetooth/IBluetoothHeadset.aidl
+++ b/binder/android/bluetooth/IBluetoothHeadset.aidl
@@ -51,8 +51,8 @@
void setAudioRouteAllowed(boolean allowed);
boolean getAudioRouteAllowed();
void setForceScoAudio(boolean forced);
- boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device);
- boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device);
+ boolean startScoUsingVirtualVoiceCall();
+ boolean stopScoUsingVirtualVoiceCall();
oneway void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type);
diff --git a/bta/ag/bta_ag_act.cc b/bta/ag/bta_ag_act.cc
index 75063ac..682140c 100644
--- a/bta/ag/bta_ag_act.cc
+++ b/bta/ag/bta_ag_act.cc
@@ -174,17 +174,13 @@
*
******************************************************************************/
void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
- RawAddress pending_bd_addr = {};
-
- /* store parameters */
- if (!data.IsEmpty()) {
- p_scb->peer_addr = data.api_open.bd_addr;
- p_scb->open_services = data.api_open.services;
- p_scb->cli_sec_mask = data.api_open.sec_mask;
- }
+ p_scb->peer_addr = data.api_open.bd_addr;
+ p_scb->open_services = data.api_open.services;
+ p_scb->cli_sec_mask = data.api_open.sec_mask;
/* Check if RFCOMM has any incoming connection to avoid collision. */
- if (PORT_IsOpening(pending_bd_addr)) {
+ RawAddress pending_bd_addr = RawAddress::kEmpty;
+ if (PORT_IsOpening(&pending_bd_addr)) {
/* Let the incoming connection goes through. */
/* Issue collision for this scb for now. */
/* We will decide what to do when we find incoming connetion later. */
@@ -330,6 +326,7 @@
*
******************************************************************************/
void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) {
+ RawAddress peer_addr = p_scb->peer_addr;
/* reinitialize stuff */
p_scb->conn_handle = 0;
p_scb->conn_service = 0;
@@ -346,7 +343,7 @@
bta_ag_start_servers(p_scb, p_scb->reg_services);
/* call open cback w. failure */
- bta_ag_cback_open(p_scb, RawAddress::kEmpty, BTA_AG_FAIL_RFCOMM);
+ bta_ag_cback_open(p_scb, peer_addr, BTA_AG_FAIL_RFCOMM);
}
/*******************************************************************************
@@ -467,6 +464,20 @@
__func__, p_scb->peer_addr.ToString().c_str());
p_scb->peer_version = HFP_HSP_VERSION_UNKNOWN;
}
+ size_t sdp_features_size = sizeof(p_scb->peer_sdp_features);
+ if (btif_config_get_bin(
+ p_scb->peer_addr.ToString(), HFP_SDP_FEATURES_CONFIG_KEY,
+ (uint8_t*)&p_scb->peer_sdp_features, &sdp_features_size)) {
+ bool sdp_wbs_support = p_scb->peer_sdp_features & BTA_AG_FEAT_WBS_SUPPORT;
+ if (!p_scb->received_at_bac && sdp_wbs_support) {
+ p_scb->codec_updated = true;
+ p_scb->peer_codecs = BTA_AG_CODEC_CVSD & BTA_AG_CODEC_MSBC;
+ p_scb->sco_codec = UUID_CODEC_MSBC;
+ }
+ } else {
+ APPL_TRACE_WARNING("%s: Failed read cached peer HFP SDP features for %s",
+ __func__, p_scb->peer_addr.ToString().c_str());
+ }
}
/* set up AT command interpreter */
@@ -502,56 +513,51 @@
*
******************************************************************************/
void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
- uint16_t lcid;
- int i;
- tBTA_AG_SCB *ag_scb, *other_scb;
- RawAddress dev_addr = {};
- int status;
-
+ APPL_TRACE_DEBUG("%s: serv_handle0 = %d serv_handle1 = %d", __func__,
+ p_scb->serv_handle[0], p_scb->serv_handle[1]);
/* set role */
p_scb->role = BTA_AG_ACP;
- APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
- p_scb->serv_handle[0], p_scb->serv_handle[1]);
-
/* get bd addr of peer */
- if (PORT_SUCCESS !=
- (status = PORT_CheckConnection(data.rfc.port_handle, dev_addr, &lcid))) {
- APPL_TRACE_DEBUG(
- "bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d",
- status);
+ uint16_t lcid = 0;
+ RawAddress dev_addr = RawAddress::kEmpty;
+ int status = PORT_CheckConnection(data.rfc.port_handle, &dev_addr, &lcid);
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ", PORT_CheckConnection returned " << status;
+ return;
}
/* Collision Handling */
- for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_MAX_NUM_CLIENTS;
- i++, ag_scb++) {
- if (ag_scb->in_use && alarm_is_scheduled(ag_scb->collision_timer)) {
- alarm_cancel(ag_scb->collision_timer);
-
- if (dev_addr == ag_scb->peer_addr) {
- /* If incoming and outgoing device are same, nothing more to do. */
- /* Outgoing conn will be aborted because we have successful incoming
- * conn. */
- } else {
- /* Resume outgoing connection. */
- other_scb = bta_ag_get_other_idle_scb(p_scb);
- if (other_scb) {
- other_scb->peer_addr = ag_scb->peer_addr;
- other_scb->open_services = ag_scb->open_services;
- other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
-
- bta_ag_resume_open(other_scb);
+ for (tBTA_AG_SCB& ag_scb : bta_ag_cb.scb) {
+ // Cancel any pending collision timers
+ if (ag_scb.in_use && alarm_is_scheduled(ag_scb.collision_timer)) {
+ alarm_cancel(ag_scb.collision_timer);
+ if (dev_addr != ag_scb.peer_addr && p_scb != &ag_scb) {
+ // Resume outgoing connection if incoming is not on the same device
+ bta_ag_resume_open(&ag_scb);
+ }
+ break;
+ }
+ if (dev_addr == ag_scb.peer_addr && p_scb != &ag_scb) {
+ // Fail the outgoing connection to clean up any upper layer states
+ bta_ag_rfc_fail(&ag_scb, tBTA_AG_DATA::kEmpty);
+ // If client port is opened, close it
+ if (ag_scb.conn_handle > 0) {
+ status = RFCOMM_RemoveConnection(ag_scb.conn_handle);
+ if (status != PORT_SUCCESS) {
+ LOG(WARNING) << __func__ << ": RFCOMM_RemoveConnection failed for "
+ << dev_addr << ", handle "
+ << std::to_string(ag_scb.conn_handle) << ", error "
+ << status;
}
}
-
- break;
}
}
p_scb->peer_addr = dev_addr;
/* determine connected service from port handle */
- for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ for (uint8_t i = 0; i < BTA_AG_NUM_IDX; i++) {
APPL_TRACE_DEBUG(
"bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i,
p_scb->serv_handle[i], data.rfc.port_handle);
@@ -813,3 +819,32 @@
(*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
}
+
+static void bta_ag_collision_timer_cback(void* data) {
+ if (data == nullptr) {
+ LOG(ERROR) << __func__ << ": data should never be null in a timer callback";
+ return;
+ }
+ /* If the peer haven't opened AG connection */
+ /* we will restart opening process. */
+ bta_ag_resume_open(static_cast<tBTA_AG_SCB*>(data));
+}
+
+void bta_ag_handle_collision(tBTA_AG_SCB* p_scb,
+ UNUSED_ATTR const tBTA_AG_DATA& data) {
+ /* Cancel SDP if it had been started. */
+ if (p_scb->p_disc_db) {
+ SDP_CancelServiceSearch(p_scb->p_disc_db);
+ bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
+ }
+
+ /* reopen registered servers */
+ /* Collision may be detected before or after we close servers. */
+ if (bta_ag_is_server_closed(p_scb)) {
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+ }
+
+ /* Start timer to han */
+ alarm_set_on_mloop(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
+ bta_ag_collision_timer_cback, p_scb);
+}
diff --git a/bta/ag/bta_ag_cmd.cc b/bta/ag/bta_ag_cmd.cc
index c162509..d4c67b9 100644
--- a/bta/ag/bta_ag_cmd.cc
+++ b/bta/ag/bta_ag_cmd.cc
@@ -1186,6 +1186,7 @@
case BTA_AG_AT_BAC_EVT:
bta_ag_send_ok(p_scb);
+ p_scb->received_at_bac = true;
/* store available codecs from the peer */
if ((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) &&
@@ -1757,7 +1758,8 @@
******************************************************************************/
void bta_ag_send_ring(tBTA_AG_SCB* p_scb,
UNUSED_ATTR const tBTA_AG_DATA& data) {
- if (p_scb->callsetup_ind != BTA_AG_CALLSETUP_INCOMING) {
+ if ((p_scb->conn_service == BTA_AG_HFP) &&
+ p_scb->callsetup_ind != BTA_AG_CALLSETUP_INCOMING) {
APPL_TRACE_DEBUG("%s: don't send the ring since there is no MT call setup",
__func__);
return;
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index 487664f..cb5f9a9 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -79,6 +79,7 @@
BTA_AG_DISC_FAIL_EVT,
BTA_AG_RING_TIMEOUT_EVT,
BTA_AG_SVC_TIMEOUT_EVT,
+ BTA_AG_COLLISION_EVT,
BTA_AG_MAX_EVT,
};
@@ -203,6 +204,7 @@
tBTA_SEC cli_sec_mask; /* client security mask */
tBTA_AG_FEAT features; /* features registered by application */
tBTA_AG_PEER_FEAT peer_features; /* peer device features */
+ uint16_t peer_sdp_features; /* peer device SDP features */
uint16_t peer_version; /* profile version of peer device */
uint16_t hsp_version; /* HSP profile version before SDP */
uint16_t sco_idx; /* SCO handle */
@@ -231,6 +233,7 @@
alarm_t* collision_timer;
alarm_t* ring_timer;
alarm_t* codec_negotiation_timer;
+ bool received_at_bac; /* indicate AT+BAC is received at least once */
tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */
tBTA_AG_PEER_CODEC sco_codec; /* codec to be used for eSCO connection */
tBTA_AG_PEER_CODEC
@@ -306,7 +309,6 @@
extern uint16_t bta_ag_idx_by_bdaddr(const RawAddress* peer_addr);
extern bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb);
extern bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb);
-extern tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb);
extern void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
const tBTA_AG_DATA& data);
extern void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event,
@@ -378,6 +380,8 @@
extern void bta_ag_result(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
extern void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
extern void bta_ag_send_ring(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_handle_collision(tBTA_AG_SCB* p_scb,
+ const tBTA_AG_DATA& data);
/* Internal utility functions */
extern void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result);
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index b63f459..ec396a3 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -68,6 +68,7 @@
BTA_AG_RESULT,
BTA_AG_SETCODEC,
BTA_AG_SEND_RING,
+ BTA_AG_HANDLE_COLLISION,
BTA_AG_NUM_ACTIONS
};
@@ -133,6 +134,7 @@
CASE_RETURN_STR(BTA_AG_DISC_FAIL_EVT)
CASE_RETURN_STR(BTA_AG_RING_TIMEOUT_EVT)
CASE_RETURN_STR(BTA_AG_SVC_TIMEOUT_EVT)
+ CASE_RETURN_STR(BTA_AG_COLLISION_EVT)
default:
return "Unknown AG Event";
}
@@ -160,7 +162,11 @@
bta_ag_sco_conn_close, bta_ag_sco_listen, bta_ag_sco_open,
bta_ag_sco_close, bta_ag_sco_shutdown, bta_ag_post_sco_open,
bta_ag_post_sco_close, bta_ag_svc_conn_open, bta_ag_result,
- bta_ag_setcodec, bta_ag_send_ring};
+ bta_ag_setcodec, bta_ag_send_ring, bta_ag_handle_collision};
+
+static_assert(sizeof(bta_ag_action) / sizeof(tBTA_AG_ACTION) ==
+ BTA_AG_NUM_ACTIONS,
+ "bta_ag_action must handle all actions");
/* state table information */
#define BTA_AG_ACTIONS 2 /* number of actions */
@@ -189,7 +195,8 @@
/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
- /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
+ /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
/* state table for opening state */
const uint8_t bta_ag_st_opening[][BTA_AG_NUM_COLS] = {
@@ -216,7 +223,9 @@
/* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
/* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
- /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}};
+ /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* COLLISION_EVT */
+ {BTA_AG_HANDLE_COLLISION, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
/* state table for open state */
const uint8_t bta_ag_st_open[][BTA_AG_NUM_COLS] = {
@@ -243,7 +252,8 @@
/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
/* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
- /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+ /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}};
/* state table for closing state */
const uint8_t bta_ag_st_closing[][BTA_AG_NUM_COLS] = {
@@ -269,7 +279,19 @@
/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
- /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+ /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+
+constexpr size_t BTA_AG_NUM_EVENTS =
+ BTA_AG_MAX_EVT - BTA_SYS_EVT_START(BTA_ID_AG);
+static_assert(sizeof(bta_ag_st_init) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+ "bta_ag_st_init must handle all AG events");
+static_assert(sizeof(bta_ag_st_opening) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+ "bta_ag_st_opening must handle all AG events");
+static_assert(sizeof(bta_ag_st_open) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+ "bta_ag_st_open must handle all AG events");
+static_assert(sizeof(bta_ag_st_closing) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+ "bta_ag_st_closing must handle all AG events");
/* type for state table */
typedef const uint8_t (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
@@ -305,12 +327,14 @@
/* initialize variables */
p_scb->in_use = true;
p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_scb->received_at_bac = false;
p_scb->codec_updated = false;
p_scb->codec_fallback = false;
p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
p_scb->sco_codec = BTA_AG_CODEC_CVSD;
p_scb->peer_version = HFP_HSP_VERSION_UNKNOWN;
p_scb->hsp_version = HSP_VERSION_1_2;
+ p_scb->peer_sdp_features = 0;
/* set up timers */
p_scb->ring_timer = alarm_new("bta_ag.scb_ring_timer");
p_scb->collision_timer = alarm_new("bta_ag.scb_collision_timer");
@@ -496,52 +520,6 @@
/*******************************************************************************
*
- * Function bta_ag_get_other_idle_scb
- *
- * Description Return other scb if it is in INIT st.
- *
- *
- * Returns Pointer to other scb if INIT st, NULL otherwise.
- *
- ******************************************************************************/
-tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb) {
- tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
- uint8_t xx;
-
- for (xx = 0; xx < BTA_AG_MAX_NUM_CLIENTS; xx++, p_scb++) {
- if (p_scb->in_use && (p_scb != p_curr_scb) &&
- (p_scb->state == BTA_AG_INIT_ST)) {
- return p_scb;
- }
- }
-
- /* no other scb found */
- APPL_TRACE_DEBUG("bta_ag_get_other_idle_scb: No idle AG scb");
- return nullptr;
-}
-
-/*******************************************************************************
- *
- * Function bta_ag_collision_timer_cback
- *
- * Description AG connection collision timer callback
- *
- *
- * Returns void
- *
- ******************************************************************************/
-static void bta_ag_collision_timer_cback(void* data) {
- tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;
-
- APPL_TRACE_DEBUG("%s", __func__);
-
- /* If the peer haven't opened AG connection */
- /* we will restart opening process. */
- bta_ag_resume_open(p_scb);
-}
-
-/*******************************************************************************
- *
* Function bta_ag_collision_cback
*
* Description Get notified about collision.
@@ -559,33 +537,16 @@
if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
if (id == BTA_ID_SYS) {
- LOG(WARNING) << __func__ << "AG found collision (ACL) for handle "
+ LOG(WARNING) << __func__ << ": AG found collision (ACL) for handle "
<< unsigned(handle) << " device " << peer_addr;
} else if (id == BTA_ID_AG) {
- LOG(WARNING) << __func__ << "AG found collision (RFCOMM) for handle "
+ LOG(WARNING) << __func__ << ": AG found collision (RFCOMM) for handle "
<< unsigned(handle) << " device " << peer_addr;
} else {
- LOG(WARNING) << __func__ << "AG found collision (UNKNOWN) for handle "
+ LOG(WARNING) << __func__ << ": AG found collision (UNKNOWN) for handle "
<< unsigned(handle) << " device " << peer_addr;
}
-
- p_scb->state = BTA_AG_INIT_ST;
-
- /* Cancel SDP if it had been started. */
- if (p_scb->p_disc_db) {
- SDP_CancelServiceSearch(p_scb->p_disc_db);
- bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
- }
-
- /* reopen registered servers */
- /* Collision may be detected before or after we close servers. */
- if (bta_ag_is_server_closed(p_scb)) {
- bta_ag_start_servers(p_scb, p_scb->reg_services);
- }
-
- /* Start timer to han */
- alarm_set_on_mloop(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
- bta_ag_collision_timer_cback, p_scb);
+ bta_ag_sm_execute(p_scb, BTA_AG_COLLISION_EVT, tBTA_AG_DATA::kEmpty);
}
}
@@ -600,20 +561,16 @@
*
******************************************************************************/
void bta_ag_resume_open(tBTA_AG_SCB* p_scb) {
- if (p_scb) {
- APPL_TRACE_DEBUG("%s: handle=%d, bd_addr=%s", __func__,
- bta_ag_scb_to_idx(p_scb),
- p_scb->peer_addr.ToString().c_str());
- /* resume opening process. */
- if (p_scb->state == BTA_AG_INIT_ST) {
- LOG(WARNING) << __func__
- << ": handle=" << unsigned(bta_ag_scb_to_idx(p_scb))
- << ", bd_addr=" << p_scb->peer_addr;
- p_scb->state = BTA_AG_OPENING_ST;
- bta_ag_start_open(p_scb, tBTA_AG_DATA::kEmpty);
- }
+ if (p_scb->state == BTA_AG_INIT_ST) {
+ LOG(INFO) << __func__ << ": Resume connection to " << p_scb->peer_addr
+ << ", handle" << bta_ag_scb_to_idx(p_scb);
+ tBTA_AG_DATA open_data = {.api_open.bd_addr = p_scb->peer_addr,
+ .api_open.services = p_scb->open_services,
+ .api_open.sec_mask = p_scb->cli_sec_mask};
+ bta_ag_sm_execute(p_scb, BTA_AG_API_OPEN_EVT, open_data);
} else {
- LOG(ERROR) << __func__ << ": null p_scb";
+ VLOG(1) << __func__ << ": device " << p_scb->peer_addr
+ << " is already in state " << std::to_string(p_scb->state);
}
}
diff --git a/bta/ag/bta_ag_sdp.cc b/bta/ag/bta_ag_sdp.cc
index 31764b3..c2b8bdc 100644
--- a/bta/ag/bta_ag_sdp.cc
+++ b/bta/ag/bta_ag_sdp.cc
@@ -361,8 +361,32 @@
/* Found attribute. Get value. */
/* There might be race condition between SDP and BRSF. */
/* Do not update if we already received BRSF. */
- if (p_scb->peer_features == 0)
- p_scb->peer_features = p_attr->attr_value.v.u16;
+ uint16_t sdp_features = p_attr->attr_value.v.u16;
+ bool sdp_wbs_support = sdp_features & BTA_AG_FEAT_WBS_SUPPORT;
+ if (!p_scb->received_at_bac && sdp_wbs_support) {
+ // Workaround for misbehaving HFs (e.g. some Hyundai car kit) that:
+ // 1. Indicate WBS support in SDP and codec negotiation in BRSF
+ // 2. But do not send required AT+BAC command
+ // Will assume mSBC is enabled and try codec negotiation by default
+ p_scb->codec_updated = true;
+ p_scb->peer_codecs = BTA_AG_CODEC_CVSD & BTA_AG_CODEC_MSBC;
+ p_scb->sco_codec = UUID_CODEC_MSBC;
+ }
+ if (sdp_features != p_scb->peer_sdp_features) {
+ p_scb->peer_sdp_features = sdp_features;
+ if (btif_config_set_bin(
+ p_scb->peer_addr.ToString(), HFP_SDP_FEATURES_CONFIG_KEY,
+ (const uint8_t*)&sdp_features, sizeof(sdp_features))) {
+ btif_config_save();
+ } else {
+ APPL_TRACE_WARNING(
+ "%s: Failed to store peer HFP SDP Features for %s", __func__,
+ p_scb->peer_addr.ToString().c_str());
+ }
+ }
+ if (p_scb->peer_features == 0) {
+ p_scb->peer_features = sdp_features & HFP_SDP_BRSF_FEATURES_MASK;
+ }
}
} else {
/* No peer version caching for HSP, use discovered one directly */
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 9b07971..89d9523 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -38,6 +38,7 @@
#include "bt_utils.h"
#include "bta_av_int.h"
#include "btif/include/btif_av_co.h"
+#include "btif/include/btif_config.h"
#include "btif/include/btif_storage.h"
#include "btm_int.h"
#include "device/include/controller.h"
@@ -264,11 +265,13 @@
* Returns void
*
******************************************************************************/
-static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& b) {
+static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& bd_addr) {
APPL_TRACE_DEBUG("%s: r:%d, s:%d", __func__, p_scb->recfg_sup,
p_scb->suspend_sup);
- if (p_scb->peer_addr != b) {
- APPL_TRACE_ERROR("%s: reset flags", __func__);
+ if (p_scb->PeerAddress() != bd_addr) {
+ LOG_INFO(LOG_TAG, "%s: reset flags old_addr=%s new_addr=%s", __func__,
+ p_scb->PeerAddress().ToString().c_str(),
+ bd_addr.ToString().c_str());
/* a new addr, reset the supported flags */
p_scb->recfg_sup = true;
p_scb->suspend_sup = true;
@@ -276,7 +279,7 @@
/* do this copy anyway, just in case the first addr matches
* the control block one by accident */
- p_scb->peer_addr = b;
+ p_scb->OnConnected(bd_addr);
}
/*******************************************************************************
@@ -360,9 +363,9 @@
p_scb->sep_info_idx = i;
/* we got a stream; get its capabilities */
- bool get_all_cap = (p_scb->avdt_version >= AVDT_VERSION_1_3) &&
+ bool get_all_cap = (p_scb->AvdtpVersion() >= AVDT_VERSION_1_3) &&
(A2DP_GetAvdtpVersion() >= AVDT_VERSION_1_3);
- AVDT_GetCapReq(p_scb->peer_addr, p_scb->hdi, p_scb->sep_info[i].seid,
+ AVDT_GetCapReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sep_info[i].seid,
&p_scb->peer_cap, &bta_av_proc_stream_evt, get_all_cap);
sent_cmd = true;
break;
@@ -372,7 +375,7 @@
/* if no streams available then stream open fails */
if (!sent_cmd) {
APPL_TRACE_ERROR("%s: BTA_AV_STR_GETCAP_FAIL_EVT: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data);
}
@@ -391,8 +394,9 @@
void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr,
uint8_t event, tAVDT_CTRL* p_data,
uint8_t scb_index) {
- uint16_t sec_len = 0;
+ CHECK_LT(scb_index, BTA_AV_NUM_STRS);
tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[scb_index];
+ uint16_t sec_len = 0;
APPL_TRACE_EVENT(
"%s: peer_address: %s avdt_handle: %d event=0x%x scb_index=%d p_scb=%p",
@@ -531,8 +535,10 @@
* Returns void
*
******************************************************************************/
-static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service) {
- APPL_TRACE_DEBUG("%s: found=%s", __func__, (found) ? "true" : "false");
+static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service,
+ const RawAddress& peer_address) {
+ APPL_TRACE_DEBUG("%s: peer %s : found=%s", __func__,
+ peer_address.ToString().c_str(), (found) ? "true" : "false");
tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
if (p_scb == NULL) {
@@ -543,10 +549,10 @@
if (!found) {
APPL_TRACE_ERROR("%s: peer %s A2DP service discovery failed", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
}
APPL_TRACE_DEBUG("%s: peer %s found=%s", __func__,
- p_scb->peer_addr.ToString().c_str(),
+ p_scb->PeerAddress().ToString().c_str(),
(found) ? "true" : "false");
tBTA_AV_SDP_RES* p_msg =
@@ -556,12 +562,24 @@
} else {
p_msg->hdr.event = BTA_AV_SDP_DISC_FAIL_EVT;
APPL_TRACE_ERROR("%s: BTA_AV_SDP_DISC_FAIL_EVT: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
}
- if (found && (p_service != NULL))
- p_scb->avdt_version = p_service->avdt_version;
- else
- p_scb->avdt_version = 0x00;
+ if (found && (p_service != NULL)) {
+ p_scb->SetAvdtpVersion(p_service->avdt_version);
+ if (p_service->avdt_version != 0) {
+ if (btif_config_set_bin(p_scb->PeerAddress().ToString(),
+ AVDTP_VERSION_CONFIG_KEY,
+ (const uint8_t*)&p_service->avdt_version,
+ sizeof(p_service->avdt_version))) {
+ btif_config_save();
+ } else {
+ APPL_TRACE_WARNING("%s: Failed to store peer AVDTP version for %s",
+ __func__, p_scb->PeerAddress().ToString().c_str());
+ }
+ }
+ } else {
+ p_scb->SetAvdtpVersion(0);
+ }
p_msg->hdr.layer_specific = bta_av_cb.handle;
bta_sys_sendmsg(p_msg);
@@ -608,7 +626,7 @@
tBTA_AV_API_OPEN* p_buf = &p_scb->q_info.open;
APPL_TRACE_DEBUG("%s: peer %s wait:0x%x", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->wait);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->wait);
if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY;
@@ -628,7 +646,7 @@
} else {
/* report failure on OPEN */
APPL_TRACE_ERROR("%s: peer %s role switch failed (wait=0x%x)", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->wait);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->wait);
switch_res = BTA_AV_RS_FAIL;
}
@@ -665,7 +683,7 @@
p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
if (p_data->role_res.hci_status != HCI_SUCCESS) {
p_scb->role &= ~BTA_AV_ROLE_START_INT;
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
/* start failed because of role switch. */
tBTA_AV_START start;
start.chnl = p_scb->chnl;
@@ -688,7 +706,7 @@
if (p_data->role_res.hci_status != HCI_SUCCESS) {
/* Open failed because of role switch. */
tBTA_AV_OPEN av_open;
- av_open.bd_addr = p_scb->peer_addr;
+ av_open.bd_addr = p_scb->PeerAddress();
av_open.chnl = p_scb->chnl;
av_open.hndl = p_scb->hndl;
av_open.status = BTA_AV_FAIL_ROLE;
@@ -728,9 +746,9 @@
******************************************************************************/
void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
APPL_TRACE_DEBUG("%s: peer %s handle:%d delay:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
p_data->str_msg.msg.delay_rpt_cmd.delay);
- p_scb->p_cos->delay(p_scb->hndl, p_scb->peer_addr,
+ p_scb->p_cos->delay(p_scb->hndl, p_scb->PeerAddress(),
p_data->str_msg.msg.delay_rpt_cmd.delay);
}
@@ -775,7 +793,7 @@
/* report a new failure event */
p_scb->open_status = BTA_AV_FAIL_ROLE;
APPL_TRACE_ERROR("%s: BTA_AV_SDP_DISC_FAIL_EVT: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
break;
@@ -820,7 +838,7 @@
p_scb->sec_mask = p_data->api_open.sec_mask;
p_scb->use_rc = p_data->api_open.use_rc;
- bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
/* only one A2DP find service is active at a time */
bta_av_cb.handle = p_scb->hndl;
@@ -839,16 +857,17 @@
APPL_TRACE_DEBUG(
"%s: Initiate SDP discovery for peer %s : uuid_int=0x%x "
"sdp_uuid=0x%x",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->uuid_int, sdp_uuid);
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->uuid_int,
+ sdp_uuid);
tA2DP_STATUS find_service_status = A2DP_FindService(
- sdp_uuid, p_scb->peer_addr, &db_params, bta_av_a2dp_sdp_cback);
+ sdp_uuid, p_scb->PeerAddress(), &db_params, bta_av_a2dp_sdp_cback);
if (find_service_status != A2DP_SUCCESS) {
APPL_TRACE_ERROR(
"%s: A2DP_FindService() failed for peer %s uuid_int=0x%x "
"sdp_uuid=0x%x : status=%d",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->uuid_int,
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->uuid_int,
sdp_uuid, find_service_status);
- bta_av_a2dp_sdp_cback(false, NULL);
+ bta_av_a2dp_sdp_cback(false, nullptr, RawAddress::kEmpty);
}
}
@@ -869,7 +888,7 @@
/* free any buffers */
p_scb->sdp_discovery_started = false;
- p_scb->avdt_version = 0;
+ p_scb->SetAvdtpVersion(0);
/* initialize some control block variables */
p_scb->open_status = BTA_AV_SUCCESS;
@@ -909,7 +928,7 @@
} else {
/* report stream closed to main SM */
msg.is_up = false;
- msg.peer_addr = p_scb->peer_addr;
+ msg.peer_addr = p_scb->PeerAddress();
bta_av_conn_chg((tBTA_AV_DATA*)&msg);
}
}
@@ -949,7 +968,8 @@
p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
APPL_TRACE_DEBUG("%s: peer %s handle:%d local_sep:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl, local_sep);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+ local_sep);
APPL_TRACE_DEBUG("%s: codec: %s", __func__,
A2DP_CodecInfoString(p_evt_cfg->codec_info).c_str());
@@ -995,15 +1015,15 @@
/* in case of A2DP SINK this is the first time peer data is being sent to
* co functions */
if (local_sep == AVDT_TSEP_SNK) {
- p_scb->p_cos->setcfg(p_scb->hndl, p_scb->peer_addr, p_evt_cfg->codec_info,
- p_info->seid, p_evt_cfg->num_protect,
- p_evt_cfg->protect_info, AVDT_TSEP_SNK,
- p_msg->handle);
+ p_scb->p_cos->setcfg(p_scb->hndl, p_scb->PeerAddress(),
+ p_evt_cfg->codec_info, p_info->seid,
+ p_evt_cfg->num_protect, p_evt_cfg->protect_info,
+ AVDT_TSEP_SNK, p_msg->handle);
} else {
- p_scb->p_cos->setcfg(p_scb->hndl, p_scb->peer_addr, p_evt_cfg->codec_info,
- p_info->seid, p_evt_cfg->num_protect,
- p_evt_cfg->protect_info, AVDT_TSEP_SRC,
- p_msg->handle);
+ p_scb->p_cos->setcfg(p_scb->hndl, p_scb->PeerAddress(),
+ p_evt_cfg->codec_info, p_info->seid,
+ p_evt_cfg->num_protect, p_evt_cfg->protect_info,
+ AVDT_TSEP_SRC, p_msg->handle);
}
}
}
@@ -1022,7 +1042,8 @@
tBTA_AV_RCB* p_rcb;
APPL_TRACE_WARNING("%s: conn_lcb: 0x%x peer_addr: %s", __func__,
- bta_av_cb.conn_lcb, p_scb->peer_addr.ToString().c_str());
+ bta_av_cb.conn_lcb,
+ p_scb->PeerAddress().ToString().c_str());
alarm_cancel(bta_av_cb.link_signalling_timer);
alarm_cancel(p_scb->avrc_ct_timer);
@@ -1030,7 +1051,7 @@
if (bta_av_cb.conn_lcb) {
p_rcb = bta_av_get_rcb_by_shdl((uint8_t)(p_scb->hdi + 1));
if (p_rcb) bta_av_del_rc(p_rcb);
- AVDT_DisconnectReq(p_scb->peer_addr, &bta_av_proc_stream_evt);
+ AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt);
} else {
bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
}
@@ -1093,14 +1114,14 @@
local_sep = bta_av_get_scb_sep_type(p_scb, avdt_handle);
bta_av_adjust_seps_idx(p_scb, avdt_handle);
APPL_TRACE_DEBUG("%s: peer %s handle: sep_idx: %d cur_psc_mask:0x%x",
- __func__, p_scb->peer_addr.ToString().c_str(),
+ __func__, p_scb->PeerAddress().ToString().c_str(),
p_scb->sep_idx, p_scb->cur_psc_mask);
if ((AVDT_TSEP_SNK == local_sep) &&
(p_data->ci_setconfig.err_code == AVDT_SUCCESS) &&
(p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) {
tBTA_AV_MEDIA av_sink_codec_info;
- av_sink_codec_info.avk_config.bd_addr = p_scb->peer_addr;
+ av_sink_codec_info.avk_config.bd_addr = p_scb->PeerAddress();
av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(BTA_AV_SINK_MEDIA_CFG_EVT,
&av_sink_codec_info);
@@ -1122,7 +1143,7 @@
p_scb->num_seps = num;
if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
- p_scb->avdt_version = AVDT_VERSION_1_3;
+ p_scb->SetAvdtpVersion(AVDT_VERSION_1_3);
if (A2DP_GetCodecType(p_scb->cfg.codec_info) == A2DP_MEDIA_CT_SBC ||
num > 1) {
@@ -1132,7 +1153,7 @@
/* this is called in A2DP SRC path only, In case of SINK we don't need it
*/
if (local_sep == AVDT_TSEP_SRC)
- p_scb->p_cos->disc_res(p_scb->hndl, p_scb->peer_addr, num, num, 0,
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->PeerAddress(), num, num, 0,
UUID_SERVCLASS_AUDIO_SOURCE);
} else {
/* we do not know the peer device and it is using non-SBC codec
@@ -1175,11 +1196,11 @@
uint16_t mtu;
APPL_TRACE_DEBUG("%s: peer %s handle: %d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl);
msg.hdr.layer_specific = p_scb->hndl;
msg.is_up = true;
- msg.peer_addr = p_scb->peer_addr;
+ msg.peer_addr = p_scb->PeerAddress();
p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
bta_av_conn_chg((tBTA_AV_DATA*)&msg);
/* set the congestion flag, so AV would not send media packets by accident */
@@ -1197,11 +1218,11 @@
L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_HIGH);
L2CA_SetChnlFlushability(p_scb->l2c_cid, true);
- bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
p_scb->l2c_bufs = 0;
- p_scb->p_cos->open(p_scb->hndl, p_scb->peer_addr, mtu);
+ p_scb->p_cos->open(p_scb->hndl, p_scb->PeerAddress(), mtu);
{
/* TODO check if other audio channel is open.
@@ -1215,17 +1236,18 @@
*/
/* check if other audio channel is started. If yes, start */
tBTA_AV_OPEN open;
- open.bd_addr = p_scb->peer_addr;
+ open.bd_addr = p_scb->PeerAddress();
open.chnl = p_scb->chnl;
open.hndl = p_scb->hndl;
open.status = BTA_AV_SUCCESS;
open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
- p = BTM_ReadRemoteFeatures(p_scb->peer_addr);
+ p = BTM_ReadRemoteFeatures(p_scb->PeerAddress());
if (p != NULL) {
if (HCI_EDR_ACL_2MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_2MBPS;
if (HCI_EDR_ACL_3MPS_SUPPORTED(p)) {
- if (!interop_match_addr(INTEROP_2MBPS_LINK_ONLY, &p_scb->peer_addr)) {
+ if (!interop_match_addr(INTEROP_2MBPS_LINK_ONLY,
+ &p_scb->PeerAddress())) {
open.edr |= BTA_AV_EDR_3MBPS;
}
}
@@ -1356,7 +1378,7 @@
******************************************************************************/
void bta_av_connect_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
APPL_TRACE_DEBUG("%s: peer %s coll_mask:0x%x", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->coll_mask);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->coll_mask);
p_scb->sdp_discovery_started = false;
if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
/* SNK initiated L2C connection while SRC was doing SDP. */
@@ -1368,7 +1390,7 @@
return;
}
- AVDT_ConnectReq(p_scb->peer_addr, p_scb->hdi, p_scb->sec_mask,
+ AVDT_ConnectReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sec_mask,
&bta_av_proc_stream_evt);
}
@@ -1383,7 +1405,7 @@
******************************************************************************/
void bta_av_sdp_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
APPL_TRACE_ERROR("%s: peer_addr=%s open_status=%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->open_status);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->open_status);
if (p_scb->open_status == BTA_AV_SUCCESS) {
p_scb->open_status = BTA_AV_FAIL_SDP;
@@ -1410,7 +1432,8 @@
uint16_t uuid_int = p_scb->uuid_int;
APPL_TRACE_DEBUG("%s: peer %s handle: %d initiator UUID 0x%x", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl, uuid_int);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+ uuid_int);
/* store number of stream endpoints returned */
p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
@@ -1429,7 +1452,7 @@
}
}
- p_scb->p_cos->disc_res(p_scb->hndl, p_scb->peer_addr, p_scb->num_seps,
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->PeerAddress(), p_scb->num_seps,
num_snks, num_srcs, uuid_int);
p_scb->num_disc_snks = num_snks;
p_scb->num_disc_srcs = num_srcs;
@@ -1445,7 +1468,7 @@
/* else we got discover response but with no streams; we're done */
else {
APPL_TRACE_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
}
}
@@ -1465,7 +1488,7 @@
uint8_t num_snks = 0, i;
APPL_TRACE_DEBUG("%s: peer %s handle: %d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl);
/* store number of stream endpoints returned */
p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
@@ -1478,7 +1501,7 @@
num_snks++;
}
}
- p_scb->p_cos->disc_res(p_scb->hndl, p_scb->peer_addr, p_scb->num_seps,
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->PeerAddress(), p_scb->num_seps,
num_snks, 0, UUID_SERVCLASS_AUDIO_SOURCE);
p_scb->num_disc_snks = num_snks;
p_scb->num_disc_srcs = 0;
@@ -1494,7 +1517,7 @@
/* else we got discover response but with no streams; we're done */
else {
APPL_TRACE_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
}
}
@@ -1516,14 +1539,14 @@
APPL_TRACE_DEBUG(
"%s: peer %s handle:%d num_seps:%d sep_info_idx:%d wait:0x%x", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl, p_scb->num_seps,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, p_scb->num_seps,
p_scb->sep_info_idx, p_scb->wait);
APPL_TRACE_DEBUG("%s: codec: %s", __func__,
A2DP_CodecInfoString(p_scb->peer_cap.codec_info).c_str());
cfg = p_scb->peer_cap;
/* let application know the capability of the SNK */
- if (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->peer_addr, cfg.codec_info,
+ if (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->PeerAddress(), cfg.codec_info,
&p_scb->sep_info_idx, p_info->seid, &cfg.num_protect,
cfg.protect_info) != A2DP_SUCCESS) {
p_scb->sep_info_idx++;
@@ -1585,11 +1608,11 @@
uint16_t mtu;
APPL_TRACE_DEBUG("%s: peer %s handle:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl);
mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
- p_scb->p_cos->close(p_scb->hndl, p_scb->peer_addr);
+ p_scb->p_cos->close(p_scb->hndl, p_scb->PeerAddress());
}
/*******************************************************************************
@@ -1607,7 +1630,7 @@
uint8_t idx;
APPL_TRACE_ERROR("%s: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
p_scb->open_status = BTA_AV_FAIL_STREAM;
bta_av_cco_close(p_scb, p_data);
@@ -1616,7 +1639,7 @@
for (idx = 0; (idx < BTA_AV_NUM_STRS) && (!is_av_opened); idx++) {
p_opened_scb = bta_av_cb.p_scb[idx];
if (p_opened_scb && (p_opened_scb->state == BTA_AV_OPEN_SST) &&
- (p_opened_scb->peer_addr == p_scb->peer_addr))
+ (p_opened_scb->PeerAddress() == p_scb->PeerAddress()))
is_av_opened = true;
}
@@ -1625,7 +1648,7 @@
BTA_AV_FAIL_GET_CAP status */
if (is_av_opened) {
tBTA_AV_OPEN open;
- open.bd_addr = p_scb->peer_addr;
+ open.bd_addr = p_scb->PeerAddress();
open.chnl = p_scb->chnl;
open.hndl = p_scb->hndl;
open.status = BTA_AV_FAIL_GET_CAP;
@@ -1650,7 +1673,7 @@
bta_av_data.open = open;
(*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, &bta_av_data);
} else {
- AVDT_DisconnectReq(p_scb->peer_addr, &bta_av_proc_stream_evt);
+ AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt);
}
}
@@ -1676,7 +1699,7 @@
memcpy(cfg.protect_info, p_scb->peer_cap.protect_info, AVDT_PROTECT_SIZE);
APPL_TRACE_DEBUG("%s: peer %s handle:%d num_codec:%d psc_mask=0x%x", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
p_scb->peer_cap.num_codec, p_scb->cfg.psc_mask);
APPL_TRACE_DEBUG("%s: media type 0x%x, 0x%x", __func__, media_type,
p_scb->media_type);
@@ -1685,9 +1708,10 @@
/* if codec present and we get a codec configuration */
if ((p_scb->peer_cap.num_codec != 0) && (media_type == p_scb->media_type) &&
- (p_scb->p_cos->getcfg(
- p_scb->hndl, p_scb->peer_addr, cfg.codec_info, &p_scb->sep_info_idx,
- p_info->seid, &cfg.num_protect, cfg.protect_info) == A2DP_SUCCESS)) {
+ (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->PeerAddress(), cfg.codec_info,
+ &p_scb->sep_info_idx, p_info->seid,
+ &cfg.num_protect,
+ cfg.protect_info) == A2DP_SUCCESS)) {
/* UUID for which connection was initiatied */
uint16_t uuid_int = p_scb->uuid_int;
@@ -1713,14 +1737,14 @@
APPL_TRACE_DEBUG(
"%s: peer %s handle:%d sep_idx:%d sep_info_idx:%d "
"cur_psc_mask:0x%x",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
p_scb->sep_idx, p_scb->sep_info_idx, p_scb->cur_psc_mask);
if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) &&
(p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) {
APPL_TRACE_DEBUG("%s: configure decoder for Sink connection", __func__);
tBTA_AV_MEDIA av_sink_codec_info;
- av_sink_codec_info.avk_config.bd_addr = p_scb->peer_addr;
+ av_sink_codec_info.avk_config.bd_addr = p_scb->PeerAddress();
av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(
BTA_AV_SINK_MEDIA_CFG_EVT, &av_sink_codec_info);
@@ -1731,7 +1755,7 @@
}
/* open the stream */
- AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
+ AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->PeerAddress(),
p_scb->hdi, p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
} else {
/* try the next stream, if any */
@@ -1777,7 +1801,7 @@
void bta_av_discover_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
/* send avdtp discover request */
- AVDT_DiscoverReq(p_scb->peer_addr, p_scb->hdi, p_scb->sep_info,
+ AVDT_DiscoverReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sep_info,
BTA_AV_NUM_SEPS, &bta_av_proc_stream_evt);
}
@@ -1792,7 +1816,7 @@
******************************************************************************/
void bta_av_conn_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
APPL_TRACE_ERROR("%s: peer_addr=%s open_status=%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->open_status);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->open_status);
p_scb->open_status = BTA_AV_FAIL_STREAM;
bta_av_str_closed(p_scb, p_data);
@@ -1808,7 +1832,7 @@
*
******************************************************************************/
void bta_av_do_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
- uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t clear_policy = 0;
uint8_t cur_role;
APPL_TRACE_DEBUG("%s: sco_occupied:%d, role:0x%x, started:%d", __func__,
@@ -1821,16 +1845,16 @@
/* disallow role switch during streaming, only if we are the master role
* i.e. allow role switch, if we are slave.
* It would not hurt us, if the peer device wants us to be master */
- if ((BTM_GetRole(p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+ if ((BTM_GetRole(p_scb->PeerAddress(), &cur_role) == BTM_SUCCESS) &&
(cur_role == BTM_ROLE_MASTER)) {
- policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ clear_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
}
- bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ bta_sys_clear_policy(BTA_ID_AV, clear_policy, p_scb->PeerAddress());
if ((!p_scb->started) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) {
p_scb->role |= BTA_AV_ROLE_START_INT;
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
AVDT_StartReq(&p_scb->avdt_handle, 1);
} else if (p_scb->started) {
@@ -1861,18 +1885,19 @@
uint8_t start = p_scb->started;
bool sus_evt = true;
BT_HDR* p_buf;
- uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t set_policy = HCI_ENABLE_SNIFF_MODE;
APPL_TRACE_ERROR(
"%s: peer %s handle:%d audio_open_cnt:%d, p_data %p start:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
bta_av_cb.audio_open_cnt, p_data, start);
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
- bta_av_cb.audio_open_cnt == 1)
- policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
- bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ bta_av_cb.audio_open_cnt == 1) {
+ set_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+ bta_sys_set_policy(BTA_ID_AV, set_policy, p_scb->PeerAddress());
if (p_scb->co_started) {
if (p_scb->offload_started) {
@@ -1883,8 +1908,8 @@
bta_av_stream_chg(p_scb, false);
p_scb->co_started = false;
- p_scb->p_cos->stop(p_scb->hndl, p_scb->peer_addr);
- L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->PeerAddress());
+ L2CA_SetFlushTimeout(p_scb->PeerAddress(), L2CAP_DEFAULT_FLUSH_TO);
}
/* if q_info.a2dp_list is not empty, drop it now */
@@ -2143,7 +2168,7 @@
list_prepend(p_scb->a2dp_list, p_buf);
} else {
/* too many buffers in a2dp_list, drop it. */
- bta_av_co_audio_drop(p_scb->hndl, p_scb->peer_addr);
+ bta_av_co_audio_drop(p_scb->hndl, p_scb->PeerAddress());
osi_free(p_buf);
}
}
@@ -2166,20 +2191,20 @@
uint16_t flush_to;
uint8_t new_role = p_scb->role;
BT_HDR hdr;
- uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t clear_policy = 0;
uint8_t cur_role;
uint8_t local_tsep = p_scb->seps[p_scb->sep_idx].tsep;
APPL_TRACE_DEBUG("%s: peer %s handle:%d wait:0x%x role:0x%x local_tsep:%d",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
- p_scb->wait, p_scb->role, local_tsep);
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ p_scb->hndl, p_scb->wait, p_scb->role, local_tsep);
p_scb->started = true;
if (local_tsep == AVDT_TSEP_SRC) {
// The RTP Header marker bit for the A2DP Source encoder
A2dpCodecConfig* codec_config =
- bta_av_get_a2dp_peer_current_codec(p_scb->peer_addr);
+ bta_av_get_a2dp_peer_current_codec(p_scb->PeerAddress());
CHECK(codec_config != nullptr);
p_scb->use_rtp_header_marker_bit = codec_config->useRtpHeaderMarkerBit();
}
@@ -2201,20 +2226,21 @@
/* role switch has failed */
APPL_TRACE_ERROR(
"%s: peer %s role switch failed: handle:%d wait:0x%x, role:0x%x",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->hndl, p_scb->wait,
- p_scb->role);
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+ p_scb->wait, p_scb->role);
p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED;
p_data = (tBTA_AV_DATA*)&hdr;
hdr.offset = BTA_AV_RS_FAIL;
}
APPL_TRACE_DEBUG("%s: peer %s wait:0x%x use_rtp_header_marker_bit:%s",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->wait,
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ p_scb->wait,
(p_scb->use_rtp_header_marker_bit) ? "true" : "false");
if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE)) {
p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
if (p_data->hdr.offset == BTA_AV_RS_FAIL) {
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
tBTA_AV_START start;
start.chnl = p_scb->chnl;
start.status = BTA_AV_FAIL_ROLE;
@@ -2247,7 +2273,7 @@
if (p_scb->wait) {
APPL_TRACE_ERROR("%s: peer %s wait:0x%x q_tag:%d not started", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->wait,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->wait,
p_scb->q_tag);
/* Clear first bit of p_scb->wait and not to return from this point else
* HAL layer gets blocked. And if there is delay in Get Capability response
@@ -2260,9 +2286,9 @@
}
/* tell role manager to check M/S role */
- bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
if (p_scb->media_type == AVDT_MEDIA_TYPE_AUDIO) {
/* in normal logic, conns should be bta_av_cb.audio_count - 1,
@@ -2276,7 +2302,7 @@
} else {
flush_to = 0;
}
- L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to);
+ L2CA_SetFlushTimeout(p_scb->PeerAddress(), flush_to);
/* clear the congestion flag */
p_scb->cong = false;
@@ -2300,12 +2326,12 @@
* Otherwise allow role switch, if source is slave.
* Because it would not hurt source, if the peer device wants source to be
* master */
- if ((BTM_GetRole(p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+ if ((BTM_GetRole(p_scb->PeerAddress(), &cur_role) == BTM_SUCCESS) &&
(cur_role == BTM_ROLE_MASTER)) {
- policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ clear_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
}
- bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ bta_sys_clear_policy(BTA_ID_AV, clear_policy, p_scb->PeerAddress());
}
p_scb->role = new_role;
@@ -2313,13 +2339,13 @@
p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
p_scb->no_rtp_header = false;
- p_scb->p_cos->start(p_scb->hndl, p_scb->peer_addr, p_scb->cfg.codec_info,
- &p_scb->no_rtp_header);
+ p_scb->p_cos->start(p_scb->hndl, p_scb->PeerAddress(),
+ p_scb->cfg.codec_info, &p_scb->no_rtp_header);
p_scb->co_started = true;
APPL_TRACE_DEBUG("%s: peer %s suspending: %d, role:0x%x, init %d", __func__,
- p_scb->peer_addr.ToString().c_str(), suspend, p_scb->role,
- initiator);
+ p_scb->PeerAddress().ToString().c_str(), suspend,
+ p_scb->role, initiator);
tBTA_AV_START start;
start.suspending = suspend;
@@ -2336,7 +2362,7 @@
p_scb->role |= BTA_AV_ROLE_SUSPEND;
p_scb->cong = true; /* do not allow the media data to go through */
/* do not duplicate the media packets to this channel */
- p_scb->p_cos->stop(p_scb->hndl, p_scb->peer_addr);
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->PeerAddress());
p_scb->co_started = false;
stop.flush = false;
stop.suspend = true;
@@ -2356,14 +2382,20 @@
*
******************************************************************************/
void bta_av_start_failed(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ uint8_t set_policy = (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH);
+
+ APPL_TRACE_ERROR(
+ "%s: peer %s handle:%d audio_open_cnt:%d started:%s co_started:%d",
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+ bta_av_cb.audio_open_cnt, logbool(p_scb->started).c_str(),
+ p_scb->co_started);
+
if (!p_scb->started && !p_scb->co_started) {
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
notify_start_failed(p_scb);
}
- bta_sys_set_policy(BTA_ID_AV,
- (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH),
- p_scb->peer_addr);
+ bta_sys_set_policy(BTA_ID_AV, set_policy, p_scb->PeerAddress());
p_scb->sco_suspend = false;
}
@@ -2379,17 +2411,18 @@
void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
tBTA_AV data;
tBTA_AV_EVT event;
- uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t set_policy = HCI_ENABLE_SNIFF_MODE;
APPL_TRACE_WARNING(
"%s: peer %s handle:%d open_status:%d chnl:%d co_started:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl, p_scb->open_status,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, p_scb->open_status,
p_scb->chnl, p_scb->co_started);
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
- bta_av_cb.audio_open_cnt == 1)
- policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
- bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ bta_av_cb.audio_open_cnt == 1) {
+ set_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+ bta_sys_set_policy(BTA_ID_AV, set_policy, p_scb->PeerAddress());
if (bta_av_cb.audio_open_cnt <= 1) {
/* last connection - restore the allow switch flag */
L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH);
@@ -2397,7 +2430,7 @@
if (p_scb->open_status != BTA_AV_SUCCESS) {
/* must be failure when opening the stream */
- data.open.bd_addr = p_scb->peer_addr;
+ data.open.bd_addr = p_scb->PeerAddress();
data.open.status = p_scb->open_status;
data.open.chnl = p_scb->chnl;
data.open.hndl = p_scb->hndl;
@@ -2410,7 +2443,7 @@
event = BTA_AV_OPEN_EVT;
p_scb->open_status = BTA_AV_SUCCESS;
- bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
bta_av_cleanup(p_scb, p_data);
(*bta_av_cb.p_cback)(event, &data);
} else {
@@ -2420,12 +2453,12 @@
}
{
- p_scb->p_cos->close(p_scb->hndl, p_scb->peer_addr);
+ p_scb->p_cos->close(p_scb->hndl, p_scb->PeerAddress());
data.close.chnl = p_scb->chnl;
data.close.hndl = p_scb->hndl;
event = BTA_AV_CLOSE_EVT;
- bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
bta_av_cleanup(p_scb, p_data);
(*bta_av_cb.p_cback)(event, &data);
}
@@ -2460,11 +2493,11 @@
void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
tBTA_AV_SUSPEND suspend_rsp;
uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
- uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t set_policy = HCI_ENABLE_SNIFF_MODE;
APPL_TRACE_DEBUG("%s: peer %s handle:%d audio_open_cnt:%d err_code:%d",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
- bta_av_cb.audio_open_cnt, err_code);
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ p_scb->hndl, bta_av_cb.audio_open_cnt, err_code);
if (!p_scb->started) {
/* handle the condition where there is a collision of SUSPEND req from
@@ -2498,11 +2531,12 @@
p_scb->cong = false;
}
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
- bta_av_cb.audio_open_cnt == 1)
- policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
- bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ bta_av_cb.audio_open_cnt == 1) {
+ set_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+ bta_sys_set_policy(BTA_ID_AV, set_policy, p_scb->PeerAddress());
/* in case that we received suspend_ind, we may need to call co_stop here */
if (p_scb->co_started) {
@@ -2514,9 +2548,9 @@
{
p_scb->co_started = false;
- p_scb->p_cos->stop(p_scb->hndl, p_scb->peer_addr);
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->PeerAddress());
}
- L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+ L2CA_SetFlushTimeout(p_scb->PeerAddress(), L2CAP_DEFAULT_FLUSH_TO);
}
{
@@ -2541,7 +2575,7 @@
void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
APPL_TRACE_DEBUG("%s: peer %s handle:%d l2c_cid:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
p_scb->l2c_cid);
if (p_data != NULL) {
@@ -2552,7 +2586,7 @@
APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d mtu: %d", __func__,
p_scb->l2c_cid, p_scb->stream_mtu, mtu);
if (mtu == 0 || mtu > p_scb->stream_mtu) mtu = p_scb->stream_mtu;
- p_scb->p_cos->update_mtu(p_scb->hndl, p_scb->peer_addr, mtu);
+ p_scb->p_cos->update_mtu(p_scb->hndl, p_scb->PeerAddress(), mtu);
}
/* rc listen */
@@ -2587,7 +2621,7 @@
void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
APPL_TRACE_ERROR("%s: num_recfg=%d conn_lcb=0x%x peer_addr=%s", __func__,
p_scb->num_recfg, bta_av_cb.conn_lcb,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
bta_av_cco_close(p_scb, p_data);
@@ -2605,7 +2639,7 @@
/* open failed. try again */
p_scb->num_recfg++;
if (bta_av_cb.conn_lcb) {
- AVDT_DisconnectReq(p_scb->peer_addr, &bta_av_proc_stream_evt);
+ AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt);
} else {
bta_av_connect_req(p_scb, NULL);
}
@@ -2631,7 +2665,7 @@
/* let bta_av_rcfg_failed report fail */
bta_av_rcfg_failed(p_scb, NULL);
} else {
- AVDT_ConnectReq(p_scb->peer_addr, p_scb->hdi, p_scb->sec_mask,
+ AVDT_ConnectReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sec_mask,
&bta_av_proc_stream_evt);
}
}
@@ -2648,7 +2682,7 @@
void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
APPL_TRACE_ERROR("%s: num_recfg=%d conn_lcb=0x%x peer_addr=%s", __func__,
p_scb->num_recfg, bta_av_cb.conn_lcb,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
p_scb->num_recfg++;
if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
@@ -2663,7 +2697,7 @@
/* report close event & go to init state */
bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
} else {
- AVDT_ConnectReq(p_scb->peer_addr, p_scb->hdi, p_scb->sec_mask,
+ AVDT_ConnectReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sec_mask,
&bta_av_proc_stream_evt);
}
}
@@ -2694,7 +2728,7 @@
bta_av_data.reconfig = reconfig;
(*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, &bta_av_data);
APPL_TRACE_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
} else {
APPL_TRACE_ERROR("%s: suspend rejected, try close", __func__);
@@ -2738,14 +2772,16 @@
bool disable_avdtp_reconfigure = false;
{
char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
- if (btif_storage_get_stored_remote_name(p_scb->peer_addr, remote_name)) {
+ if (btif_storage_get_stored_remote_name(p_scb->PeerAddress(),
+ remote_name)) {
if (interop_match_name(INTEROP_DISABLE_AVDTP_RECONFIGURE, remote_name) ||
interop_match_addr(INTEROP_DISABLE_AVDTP_RECONFIGURE,
- (const RawAddress*)&p_scb->peer_addr)) {
+ (const RawAddress*)&p_scb->PeerAddress())) {
LOG_INFO(LOG_TAG,
"%s: disable AVDTP RECONFIGURE: interop matched "
"name %s address %s",
- __func__, remote_name, p_scb->peer_addr.ToString().c_str());
+ __func__, remote_name,
+ p_scb->PeerAddress().ToString().c_str());
disable_avdtp_reconfigure = true;
}
}
@@ -2787,15 +2823,15 @@
******************************************************************************/
void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
APPL_TRACE_DEBUG("%s: peer %s handle:%d num_disc_snks:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
p_scb->num_disc_snks);
if (p_scb->num_disc_snks == 0) {
/* Need to update call-out module so that it will be ready for discover */
- p_scb->p_cos->stop(p_scb->hndl, p_scb->peer_addr);
+ p_scb->p_cos->stop(p_scb->hndl, p_scb->PeerAddress());
/* send avdtp discover request */
- AVDT_DiscoverReq(p_scb->peer_addr, p_scb->hdi, p_scb->sep_info,
+ AVDT_DiscoverReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sep_info,
BTA_AV_NUM_SEPS, &bta_av_proc_stream_evt);
} else {
APPL_TRACE_DEBUG("%s: calling AVDT_OpenReq()", __func__);
@@ -2808,7 +2844,7 @@
/* open the stream with the new config */
p_scb->sep_info_idx = p_scb->rcfg_idx;
- AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr, p_scb->hdi,
+ AVDT_OpenReq(p_scb->avdt_handle, p_scb->PeerAddress(), p_scb->hdi,
p_scb->sep_info[p_scb->sep_info_idx].seid, &p_scb->cfg);
}
}
@@ -2860,7 +2896,7 @@
if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
p_scbi->co_started = bta_av_cb.audio_open_cnt;
L2CA_SetFlushTimeout(
- p_scbi->peer_addr,
+ p_scbi->PeerAddress(),
p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
}
}
@@ -2925,7 +2961,8 @@
/* use main SM for AVRC SDP activities */
if (is_new_avrcp_enabled()) {
APPL_TRACE_WARNING("%s: Using the new AVRCP Profile", __func__);
- bluetooth::avrcp::AvrcpService::Get()->ConnectDevice(p_scb->peer_addr);
+ bluetooth::avrcp::AvrcpService::Get()->ConnectDevice(
+ p_scb->PeerAddress());
} else {
bta_av_rc_disc((uint8_t)(p_scb->hdi + 1));
}
@@ -2953,7 +2990,7 @@
memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
APPL_TRACE_DEBUG("%s: peer %s coll_mask:0x%x", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->coll_mask);
+ p_scb->PeerAddress().ToString().c_str(), p_scb->coll_mask);
if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
@@ -3172,8 +3209,9 @@
p_a2dp_offload->max_latency = 0;
p_a2dp_offload->mtu = mtu;
p_a2dp_offload->acl_hdl =
- BTM_GetHCIConnHandle(p_scb->peer_addr, BT_TRANSPORT_BR_EDR);
- p_a2dp_offload->scms_t_enable = p_scb->p_cos->cp_is_active(p_scb->peer_addr);
+ BTM_GetHCIConnHandle(p_scb->PeerAddress(), BT_TRANSPORT_BR_EDR);
+ p_a2dp_offload->scms_t_enable =
+ p_scb->p_cos->cp_is_active(p_scb->PeerAddress());
APPL_TRACE_DEBUG("%s: scms_t_enable =%d", __func__,
p_a2dp_offload->scms_t_enable);
diff --git a/bta/av/bta_av_act.cc b/bta/av/bta_av_act.cc
index 8dc0b3d..df992dc 100644
--- a/bta/av/bta_av_act.cc
+++ b/bta/av/bta_av_act.cc
@@ -319,7 +319,7 @@
tBTA_AV_RCB* p_rcb;
if (role == AVCT_INT) {
- bda = p_scb->peer_addr;
+ bda = p_scb->PeerAddress();
status = BTA_AV_RC_ROLE_INT;
} else {
p_rcb = bta_av_get_rcb_by_shdl(shdl);
@@ -486,7 +486,7 @@
/* find the SCB & stop the timer */
for (i = 0; i < BTA_AV_NUM_STRS; i++) {
p_scb = p_cb->p_scb[i];
- if (p_scb && p_scb->peer_addr == p_data->rc_conn_chg.peer_addr) {
+ if (p_scb && p_scb->PeerAddress() == p_data->rc_conn_chg.peer_addr) {
p_scb->rc_handle = p_data->rc_conn_chg.handle;
APPL_TRACE_DEBUG("%s: shdl:%d, srch %d", __func__, i + 1,
p_scb->rc_handle);
@@ -1081,11 +1081,11 @@
if (started) {
bta_av_cb.audio_streams |= started_msk;
/* Let L2CAP know this channel is processed with high priority */
- L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH);
+ L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_HIGH);
} else {
bta_av_cb.audio_streams &= ~started_msk;
/* Let L2CAP know this channel is processed with low priority */
- L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL);
+ L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_NORMAL);
}
}
@@ -1199,10 +1199,8 @@
/* clear the conned mask for this channel */
p_cb->conn_audio &= ~mask;
if (p_scb) {
- /* the stream is closed.
- * clear the peer address, so it would not mess up the AVRCP for the next
- * round of operation */
- p_scb->peer_addr = RawAddress::kEmpty;
+ // The stream is closed. Clear the state.
+ p_scb->OnDisconnected();
if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
if (p_lcb) {
p_lcb->conn_msk &= ~conn_msk;
@@ -1268,7 +1266,7 @@
if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
p_scbi->co_started = bta_av_cb.audio_open_cnt;
L2CA_SetFlushTimeout(
- p_scbi->peer_addr,
+ p_scbi->PeerAddress(),
p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
}
}
@@ -1366,7 +1364,7 @@
if (p_data->hdr.offset == AVDT_ACP) {
APPL_TRACE_DEBUG(
"%s: Incoming L2CAP acquired, set state as incoming", __func__);
- p_cb->p_scb[xx]->peer_addr = p_data->str_msg.bd_addr;
+ p_cb->p_scb[xx]->OnConnected(p_data->str_msg.bd_addr);
p_cb->p_scb[xx]->use_rc =
true; /* allowing RC for incoming connection */
bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data);
@@ -1382,7 +1380,7 @@
APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__);
bta_sys_conn_open(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
- p_cb->p_scb[xx]->peer_addr);
+ p_cb->p_scb[xx]->PeerAddress());
/* Possible collision : need to avoid outgoing processing while the
* timer is running */
p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
@@ -1422,18 +1420,18 @@
/* clean up ssm */
for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
if (p_cb->p_scb[xx] &&
- p_cb->p_scb[xx]->peer_addr == p_data->str_msg.bd_addr) {
+ p_cb->p_scb[xx]->PeerAddress() == p_data->str_msg.bd_addr) {
APPL_TRACE_DEBUG("%s: Closing timer for AVDTP service", __func__);
bta_sys_conn_close(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
- p_cb->p_scb[xx]->peer_addr);
+ p_cb->p_scb[xx]->PeerAddress());
}
mask = 1 << (xx + 1);
if (((mask & p_lcb->conn_msk) || bta_av_cb.conn_lcb) &&
p_cb->p_scb[xx] &&
- p_cb->p_scb[xx]->peer_addr == p_data->str_msg.bd_addr) {
+ p_cb->p_scb[xx]->PeerAddress() == p_data->str_msg.bd_addr) {
APPL_TRACE_WARNING("%s: Sending AVDT_DISCONNECT_EVT peer_addr=%s",
__func__,
- p_cb->p_scb[xx]->peer_addr.ToString().c_str());
+ p_cb->p_scb[xx]->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL);
}
}
@@ -1775,7 +1773,7 @@
(peer_features & BTA_AV_FEAT_RCTG)) ||
((p_cb->features & BTA_AV_FEAT_RCTG) &&
(peer_features & BTA_AV_FEAT_RCCT)))) {
- p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
+ p_lcb = bta_av_find_lcb(p_scb->PeerAddress(), BTA_AV_LCB_FIND);
if (p_lcb) {
rc_handle = bta_av_rc_create(p_cb, AVCT_INT,
(uint8_t)(p_scb->hdi + 1), p_lcb->lidx);
@@ -1787,7 +1785,7 @@
/* can not find AVRC on peer device. report failure */
p_scb->use_rc = false;
tBTA_AV_RC_OPEN rc_open;
- rc_open.peer_addr = p_scb->peer_addr;
+ rc_open.peer_addr = p_scb->PeerAddress();
rc_open.peer_features = 0;
rc_open.status = BTA_AV_FAIL_SDP;
tBTA_AV bta_av_data;
@@ -1808,7 +1806,7 @@
*/
rc_feat.peer_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr;
} else {
- rc_feat.peer_addr = p_scb->peer_addr;
+ rc_feat.peer_addr = p_scb->PeerAddress();
}
tBTA_AV bta_av_data;
bta_av_data.rc_feat = rc_feat;
@@ -1853,7 +1851,7 @@
p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
}
if (p_scb) {
- rc_close.peer_addr = p_scb->peer_addr;
+ rc_close.peer_addr = p_scb->PeerAddress();
if (p_scb->rc_handle == p_rcb->handle)
p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
APPL_TRACE_DEBUG("%s: shdl:%d, srch:%d", __func__, p_rcb->shdl,
@@ -1971,7 +1969,7 @@
ATTR_ID_SUPPORTED_FEATURES};
uint8_t hdi;
tBTA_AV_SCB* p_scb;
- RawAddress* p_addr = NULL;
+ RawAddress peer_addr = RawAddress::kEmpty;
uint8_t rc_handle;
APPL_TRACE_DEBUG("%s: disc: 0x%x, bta_av_cb.disc: 0x%x", __func__, disc,
@@ -1982,7 +1980,7 @@
/* this is the rc handle/index to tBTA_AV_RCB */
rc_handle = disc & (~BTA_AV_CHNL_MSK);
if (p_cb->rcb[rc_handle].lidx) {
- p_addr = &p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr;
+ peer_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr;
}
} else {
hdi = (disc & BTA_AV_HNDL_MSK) - 1;
@@ -1990,11 +1988,11 @@
if (p_scb) {
APPL_TRACE_DEBUG("%s: rc_handle %d", __func__, p_scb->rc_handle);
- p_addr = &p_scb->peer_addr;
+ peer_addr = p_scb->PeerAddress();
}
}
- if (p_addr) {
+ if (!peer_addr.IsEmpty()) {
/* allocate discovery database */
if (p_cb->p_disc_db == NULL)
p_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AV_DISC_BUF_SIZE);
@@ -2006,7 +2004,8 @@
db_params.p_attrs = attr_list;
/* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */
- if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, *p_addr, &db_params,
+ if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, peer_addr,
+ &db_params,
base::Bind(bta_av_avrc_sdp_cback)) == AVRC_SUCCESS) {
p_cb->disc = disc;
APPL_TRACE_DEBUG("%s: disc 0x%x", __func__, p_cb->disc);
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
index 004552c..e5f0b5a 100644
--- a/bta/av/bta_av_int.h
+++ b/bta/av/bta_av_int.h
@@ -369,7 +369,6 @@
/* data type for BTA_AV_SDP_DISC_OK_EVT */
typedef struct {
BT_HDR hdr;
- uint16_t avdt_version; /* AVDTP protocol version */
} tBTA_AV_SDP_RES;
/* data type for BTA_AV_API_OFFLOAD_RSP_EVT */
@@ -456,7 +455,9 @@
0x02 /* API open was called while incoming timer is running */
/* type for AV stream control block */
-struct tBTA_AV_SCB {
+// TODO: This should be renamed and changed to a proper class
+struct tBTA_AV_SCB final {
+ public:
const tBTA_AV_ACT* p_act_tbl; /* the action table for stream state machine */
const tBTA_AV_CO_FUNCTS* p_cos; /* the associated callout functions */
bool sdp_discovery_started; /* variable to determine whether SDP is started */
@@ -467,10 +468,8 @@
tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */
AvdtpSepConfig cfg; /* local SEP configuration */
alarm_t* avrc_ct_timer; /* delay timer for AVRC CT */
- RawAddress peer_addr; /* peer BD address */
uint16_t l2c_cid; /* L2CAP channel ID */
uint16_t stream_mtu; /* MTU of stream */
- uint16_t avdt_version; /* the avdt version of peer device */
tBTA_SEC sec_mask; /* security mask */
uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
bool cong; /* true if AVDTP congested */
@@ -515,6 +514,40 @@
uint16_t uuid_int; /*intended UUID of Initiator to connect to */
bool offload_start_pending;
bool offload_started;
+
+ /**
+ * Called to setup the state when connected to a peer.
+ *
+ * @param peer_address the peer address
+ */
+ void OnConnected(const RawAddress& peer_address);
+
+ /**
+ * Called to clear the state when disconnected from a peer.
+ *
+ */
+ void OnDisconnected();
+
+ /**
+ * Get the peer address.
+ */
+ const RawAddress& PeerAddress() const { return peer_address_; }
+
+ /**
+ * Get the AVDTP version of the peer device.
+ */
+ uint16_t AvdtpVersion() const { return avdtp_version_; }
+
+ /**
+ * Set the AVDTP version of the peer device.
+ *
+ * @param avdtp_version the AVDTP version to use
+ */
+ void SetAvdtpVersion(uint16_t avdtp_version);
+
+ private:
+ RawAddress peer_address_; // Peer address
+ uint16_t avdtp_version_; // The AVDTP version of the peer device
};
#define BTA_AV_RC_ROLE_MASK 0x10
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index c0d5090..b1cde50 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -35,6 +35,7 @@
#include "bta_av_co.h"
#include "bta_av_int.h"
#include "btif/include/btif_av_co.h"
+#include "btif/include/btif_config.h"
#include "l2c_api.h"
#include "l2cdefs.h"
#include "utl.h"
@@ -267,7 +268,7 @@
for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
if (bta_av_cb.p_scb[xx]) {
- if (bd_addr == bta_av_cb.p_scb[xx]->peer_addr) {
+ if (bd_addr == bta_av_cb.p_scb[xx]->PeerAddress()) {
p_scb = bta_av_cb.p_scb[xx];
break;
}
@@ -316,6 +317,8 @@
for (int xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
if (bta_av_cb.p_scb[xx] != nullptr) continue;
// Found an empty spot
+ // TODO: After tBTA_AV_SCB is changed to a proper class, the entry
+ // here should be allocated by C++ 'new' statement.
tBTA_AV_SCB* p_ret = (tBTA_AV_SCB*)osi_calloc(sizeof(tBTA_AV_SCB));
p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE;
p_ret->chnl = chnl;
@@ -338,9 +341,43 @@
CHECK(p_scb == bta_av_cb.p_scb[scb_index]);
bta_av_cb.p_scb[scb_index] = nullptr;
alarm_free(p_scb->avrc_ct_timer);
+ // TODO: After tBTA_AV_SCB is changed to a proper class, the entry
+ // here should be de-allocated by C++ 'delete' statement.
osi_free(p_scb);
}
+void tBTA_AV_SCB::OnConnected(const RawAddress& peer_address) {
+ peer_address_ = peer_address;
+
+ if (peer_address.IsEmpty()) {
+ LOG_ERROR(LOG_TAG, "%s: Invalid peer address: %s", __func__,
+ peer_address.ToString().c_str());
+ return;
+ }
+
+ // Read and restore the AVDTP version from local storage
+ uint16_t avdtp_version = 0;
+ size_t version_value_size = sizeof(avdtp_version);
+ if (!btif_config_get_bin(peer_address_.ToString(), AVDTP_VERSION_CONFIG_KEY,
+ (uint8_t*)&avdtp_version, &version_value_size)) {
+ LOG_WARN(LOG_TAG, "%s: Failed to read cached peer AVDTP version for %s",
+ __func__, peer_address_.ToString().c_str());
+ } else {
+ SetAvdtpVersion(avdtp_version);
+ }
+}
+
+void tBTA_AV_SCB::OnDisconnected() {
+ peer_address_ = RawAddress::kEmpty;
+ SetAvdtpVersion(0);
+}
+
+void tBTA_AV_SCB::SetAvdtpVersion(uint16_t avdtp_version) {
+ avdtp_version_ = avdtp_version;
+ LOG_DEBUG(LOG_TAG, "%s: AVDTP version for %s set to 0x%x", __func__,
+ peer_address_.ToString().c_str(), avdtp_version_);
+}
+
/*******************************************************************************
******************************************************************************/
void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, const RawAddress& bd_addr,
@@ -775,7 +812,7 @@
if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
p_scbi->co_started = bta_av_cb.audio_open_cnt;
L2CA_SetFlushTimeout(
- p_scbi->peer_addr,
+ p_scbi->PeerAddress(),
p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
}
}
@@ -798,14 +835,15 @@
tBTA_AV_CB* p_cb = &bta_av_cb;
int i;
uint8_t mask;
+ uint8_t set_policy = (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH);
APPL_TRACE_DEBUG("%s: reg_audio: 0x%x", __func__, bta_av_cb.reg_audio);
for (i = 0; i < BTA_AV_NUM_STRS; i++) {
mask = BTA_AV_HNDL_TO_MSK(i);
if (p_cb->conn_audio == mask) {
if (p_cb->p_scb[i]) {
- bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
- p_cb->p_scb[i]->peer_addr);
+ bta_sys_set_policy(BTA_ID_AV, set_policy,
+ p_cb->p_scb[i]->PeerAddress());
}
break;
}
@@ -828,6 +866,7 @@
tBTA_AV_SCB* p_scb = NULL;
uint8_t cur_role;
uint8_t peer_idx = 0;
+ uint8_t set_policy = (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH);
APPL_TRACE_DEBUG(
"%s: peer %s new_role:%d hci_status:0x%x bta_av_cb.rs_idx:%d", __func__,
@@ -838,7 +877,7 @@
* role change event */
/* note that more than one SCB (a2dp & vdp) maybe waiting for this event */
p_scb = bta_av_cb.p_scb[i];
- if (p_scb && p_scb->peer_addr == peer_addr) {
+ if (p_scb && p_scb->PeerAddress() == peer_addr) {
tBTA_AV_ROLE_RES* p_buf =
(tBTA_AV_ROLE_RES*)osi_malloc(sizeof(tBTA_AV_ROLE_RES));
APPL_TRACE_DEBUG(
@@ -847,8 +886,7 @@
/*
if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS))
{
- bta_sys_set_policy(BTA_ID_AV,
- (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr);
+ bta_sys_set_policy(BTA_ID_AV, set_policy, p_scb->PeerAddress());
}
*/
p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT;
@@ -865,7 +903,7 @@
if ((HCI_SUCCESS != app_id) &&
(BTM_GetRole(peer_addr, &cur_role) == BTM_SUCCESS) &&
(cur_role == BTM_ROLE_SLAVE)) {
- bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr);
+ bta_sys_set_policy(BTA_ID_AV, set_policy, peer_addr);
}
/* if BTA_AvOpen() was called for other device, which caused the role switch
@@ -877,8 +915,8 @@
}
if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
APPL_TRACE_DEBUG("%s: peer %s rs_idx:%d, hndl:0x%x q_tag:%d", __func__,
- p_scb->peer_addr.ToString().c_str(), bta_av_cb.rs_idx,
- p_scb->hndl, p_scb->q_tag);
+ p_scb->PeerAddress().ToString().c_str(),
+ bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);
if (HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id) {
p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
@@ -887,7 +925,7 @@
"%s: peer %s (p_scb peer %s) role switch failed: new_role:%d "
"hci_status:0x%x",
__func__, peer_addr.ToString().c_str(),
- p_scb->peer_addr.ToString().c_str(), id, app_id);
+ p_scb->PeerAddress().ToString().c_str(), id, app_id);
p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
}
@@ -978,15 +1016,15 @@
if (p_scbi && (p_scb->hdi != i) && /* not the original channel */
((bta_av_cb.conn_audio & mask))) /* connected audio */
{
- BTM_GetRole(p_scbi->peer_addr, &role);
+ BTM_GetRole(p_scbi->PeerAddress(), &role);
/* this channel is open - clear the role switch link policy for this link
*/
if (BTM_ROLE_MASTER != role) {
if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
- p_scbi->peer_addr);
+ p_scbi->PeerAddress());
if (BTM_CMD_STARTED !=
- BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL)) {
+ BTM_SwitchRole(p_scbi->PeerAddress(), BTM_ROLE_MASTER, NULL)) {
/* can not switch role on SCBI
* start the timer on SCB - because this function is ONLY called when
* SCB gets API_OPEN */
@@ -1018,7 +1056,7 @@
uint8_t role;
bool is_ok = true;
- if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS) {
+ if (BTM_GetRole(p_scb->PeerAddress(), &role) == BTM_SUCCESS) {
LOG_INFO(LOG_TAG,
"%s: hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
__func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits,
@@ -1028,10 +1066,10 @@
(bta_av_cb.features & BTA_AV_FEAT_MASTER))) {
if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
- p_scb->peer_addr);
+ p_scb->PeerAddress());
if (BTM_CMD_STARTED !=
- BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL)) {
+ BTM_SwitchRole(p_scb->PeerAddress(), BTM_ROLE_MASTER, NULL)) {
/* can not switch role on SCB - start the timer on SCB */
}
is_ok = false;
@@ -1113,7 +1151,7 @@
if (list_length(p_scbi->a2dp_list) > p_bta_av_cfg->audio_mqs) {
// Drop the oldest packet
- bta_av_co_audio_drop(p_scbi->hndl, p_scbi->peer_addr);
+ bta_av_co_audio_drop(p_scbi->hndl, p_scbi->PeerAddress());
BT_HDR* p_buf_drop = static_cast<BT_HDR*>(list_front(p_scbi->a2dp_list));
list_remove(p_scbi->a2dp_list, p_buf_drop);
osi_free(p_buf_drop);
@@ -1390,7 +1428,7 @@
continue;
}
dprintf(fd, "\n BTA ID: %zu peer: %s\n", i,
- p_scb->peer_addr.ToString().c_str());
+ p_scb->PeerAddress().ToString().c_str());
dprintf(fd, " SDP discovery started: %s\n",
p_scb->sdp_discovery_started ? "true" : "false");
for (size_t j = 0; j < BTAV_A2DP_CODEC_INDEX_MAX; j++) {
@@ -1418,7 +1456,7 @@
// TODO: Print p_scb->sep_info[], cfg, avrc_ct_timer, current_codec ?
dprintf(fd, " L2CAP Channel ID: %d\n", p_scb->l2c_cid);
dprintf(fd, " Stream MTU: %d\n", p_scb->stream_mtu);
- dprintf(fd, " AVDTP version: 0x%x\n", p_scb->avdt_version);
+ dprintf(fd, " AVDTP version: 0x%x\n", p_scb->AvdtpVersion());
dprintf(fd, " Security mask: 0x%x\n", p_scb->sec_mask);
dprintf(fd, " Media type: %d\n", p_scb->media_type);
dprintf(fd, " Congested: %s\n", p_scb->cong ? "true" : "false");
diff --git a/bta/av/bta_av_ssm.cc b/bta/av/bta_av_ssm.cc
index afa78cc..6c384e0 100644
--- a/bta/av/bta_av_ssm.cc
+++ b/bta/av/bta_av_ssm.cc
@@ -488,7 +488,7 @@
APPL_TRACE_VERBOSE(
"%s: peer %s AV event(0x%x)=0x%x(%s) state=%d(%s) p_scb=%p", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->hndl, event,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, event,
bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state),
p_scb);
@@ -500,7 +500,7 @@
p_scb->state = state_table[event][BTA_AV_SNEXT_STATE];
APPL_TRACE_VERBOSE("%s: peer %s AV next state=%d(%s) p_scb=%p", __func__,
- p_scb->peer_addr.ToString().c_str(), p_scb->state,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->state,
bta_av_sst_code(p_scb->state), p_scb);
/* execute action functions */
@@ -572,9 +572,9 @@
APPL_TRACE_VERBOSE(
"%s: peer %s AV (hndl=0x%x) state=%d(%s) next state=%d(%s) p_scb=%p",
- __func__, p_scb->peer_addr.ToString().c_str(), p_scb->hndl, p_scb->state,
- bta_av_sst_code(p_scb->state), next_state, bta_av_sst_code(next_state),
- p_scb);
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+ p_scb->state, bta_av_sst_code(p_scb->state), next_state,
+ bta_av_sst_code(next_state), p_scb);
p_scb->state = next_state;
}
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index b7a26bd..d497c4f 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -38,6 +38,7 @@
#include "bta_dm_co.h"
#include "bta_dm_int.h"
#include "bta_sys.h"
+#include "btif_storage.h"
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
@@ -245,6 +246,9 @@
extern DEV_CLASS local_device_default_class;
+// Stores the local Input/Output Capabilities of the Bluetooth device.
+static uint8_t btm_local_io_caps;
+
/** Initialises the BT device manager */
void bta_dm_enable(tBTA_DM_SEC_CBACK* p_sec_cback) {
/* if already in use, return an error */
@@ -275,6 +279,8 @@
sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
bta_sys_sendmsg(sys_enable_event);
+
+ btm_local_io_caps = btif_storage_get_local_io_caps();
}
/*******************************************************************************
@@ -2463,20 +2469,20 @@
/* TODO_SP */
switch (event) {
case BTM_SP_IO_REQ_EVT:
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- /* translate auth_req */
- bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
- &p_data->io_req.oob_data, &p_data->io_req.auth_req,
- p_data->io_req.is_orig);
-#endif
+ if (btm_local_io_caps != BTM_IO_CAP_NONE) {
+ /* translate auth_req */
+ bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
+ &p_data->io_req.oob_data, &p_data->io_req.auth_req,
+ p_data->io_req.is_orig);
+ }
APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
p_data->io_req.oob_data);
break;
case BTM_SP_IO_RSP_EVT:
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
- p_data->io_rsp.oob_data, p_data->io_rsp.auth_req);
-#endif
+ if (btm_local_io_caps != BTM_IO_CAP_NONE) {
+ bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
+ p_data->io_rsp.oob_data, p_data->io_rsp.auth_req);
+ }
break;
case BTM_SP_CFM_REQ_EVT:
@@ -2489,12 +2495,16 @@
sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps;
/* continue to next case */
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
/* Passkey entry mode, mobile device with output capability is very
unlikely to receive key request, so skip this event */
/*case BTM_SP_KEY_REQ_EVT: */
case BTM_SP_KEY_NOTIF_EVT:
-#endif
+ if (btm_local_io_caps == BTM_IO_CAP_NONE &&
+ BTM_SP_KEY_NOTIF_EVT == event) {
+ status = BTM_NOT_AUTHORIZED;
+ break;
+ }
+
bta_dm_cb.num_val = sec_event.key_notif.passkey =
p_data->key_notif.passkey;
@@ -3761,13 +3771,12 @@
memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
switch (event) {
case BTM_LE_IO_REQ_EVT:
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
-
- bta_dm_co_ble_io_req(
- bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data,
- &p_data->io_req.auth_req, &p_data->io_req.max_key_size,
- &p_data->io_req.init_keys, &p_data->io_req.resp_keys);
-#endif
+ if (btm_local_io_caps != BTM_IO_CAP_NONE) {
+ bta_dm_co_ble_io_req(
+ bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data,
+ &p_data->io_req.auth_req, &p_data->io_req.max_key_size,
+ &p_data->io_req.init_keys, &p_data->io_req.resp_keys);
+ }
APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
p_data->io_req.oob_data);
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 9b7806c..91053a1 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -236,7 +236,7 @@
/* AV : 4 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
- (BTA_DM_PM_SSR2), /* the SSR entry */
+ (BTA_DM_PM_SSR0), /* the SSR entry */
#endif
{
{{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
index 4dbab39..144dc99 100644
--- a/bta/hearing_aid/hearing_aid.cc
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -70,7 +70,7 @@
Uuid LE_PSM_UUID = Uuid::FromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
// clang-format on
-constexpr uint16_t MIN_CE_LEN_1M = 0x0008;
+constexpr uint16_t MIN_CE_LEN_1M = 0x0006;
void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
void encryption_callback(const RawAddress*, tGATT_TRANSPORT, void*,
@@ -88,6 +88,22 @@
return (uint8_t*)(msg) + BT_HDR_SIZE + L2CAP_MIN_OFFSET;
}
+struct AudioStats {
+ size_t packet_flush_count;
+ size_t packet_send_count;
+ size_t frame_flush_count;
+ size_t frame_send_count;
+
+ AudioStats() { Reset(); }
+
+ void Reset() {
+ packet_flush_count = 0;
+ packet_send_count = 0;
+ frame_flush_count = 0;
+ frame_send_count = 0;
+ }
+};
+
class HearingAidImpl;
HearingAidImpl* instance;
HearingAidAudioReceiver* audioReceiver;
@@ -125,6 +141,8 @@
uint16_t preparation_delay;
uint16_t codecs;
+ AudioStats audio_stats;
+
HearingDevice(const RawAddress& address, uint16_t psm, uint8_t capabilities,
uint16_t codecs, uint16_t audio_control_point_handle,
uint16_t volume_handle, uint64_t hiSyncId,
@@ -259,19 +277,23 @@
uint8_t capabilities, uint16_t codecs,
uint16_t audio_control_point_handle,
uint16_t volume_handle, uint64_t hiSyncId,
- uint16_t render_delay, uint16_t preparation_delay) {
- DVLOG(2) << __func__ << " " << address << ", hiSyncId=" << loghex(hiSyncId);
- hearingDevices.Add(HearingDevice(
- address, psm, capabilities, codecs, audio_control_point_handle,
- volume_handle, hiSyncId, render_delay, preparation_delay));
+ uint16_t render_delay, uint16_t preparation_delay,
+ uint16_t is_white_listed) {
+ DVLOG(2) << __func__ << " " << address << ", hiSyncId=" << loghex(hiSyncId)
+ << ", isWhiteListed=" << is_white_listed;
+ if (is_white_listed) {
+ hearingDevices.Add(HearingDevice(
+ address, psm, capabilities, codecs, audio_control_point_handle,
+ volume_handle, hiSyncId, render_delay, preparation_delay));
- // TODO: we should increase the scanning window for few seconds, to get
- // faster initial connection, same after hearing aid disconnects, i.e.
- // BTM_BleSetConnScanParams(2048, 1024);
+ // TODO: we should increase the scanning window for few seconds, to get
+ // faster initial connection, same after hearing aid disconnects, i.e.
+ // BTM_BleSetConnScanParams(2048, 1024);
- /* add device into BG connection to accept remote initiated connection */
- BTA_GATTC_Open(gatt_if, address, false, GATT_TRANSPORT_LE, false);
- BTA_DmBleStartAutoConn();
+ /* add device into BG connection to accept remote initiated connection */
+ BTA_GATTC_Open(gatt_if, address, false, GATT_TRANSPORT_LE, false);
+ BTA_DmBleStartAutoConn();
+ }
callbacks->OnDeviceAvailable(capabilities, hiSyncId, address);
}
@@ -783,12 +805,12 @@
encoded_data_left.resize(encoded_size);
uint16_t cid = GAP_ConnGetL2CAPCid(left->gap_handle);
- if (DCHECK_IS_ON() && VLOG_IS_ON(2)) {
- uint16_t packets_to_flush =
- L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET);
- if (packets_to_flush)
- VLOG(2) << left->address << " skipping " << packets_to_flush
- << " packets";
+ uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET);
+ if (packets_to_flush) {
+ VLOG(2) << left->address << " skipping " << packets_to_flush
+ << " packets";
+ left->audio_stats.packet_flush_count += packets_to_flush;
+ left->audio_stats.frame_flush_count++;
}
// flush all packets stuck in queue
L2CA_FlushChannel(cid, 0xffff);
@@ -803,12 +825,12 @@
encoded_data_right.resize(encoded_size);
uint16_t cid = GAP_ConnGetL2CAPCid(right->gap_handle);
- if (DCHECK_IS_ON() && VLOG_IS_ON(2)) {
- uint16_t packets_to_flush =
- L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET);
- if (packets_to_flush)
- VLOG(2) << right->address << " skipping " << packets_to_flush
- << " packets";
+ uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET);
+ if (packets_to_flush) {
+ VLOG(2) << right->address << " skipping " << packets_to_flush
+ << " packets";
+ right->audio_stats.packet_flush_count += packets_to_flush;
+ right->audio_stats.frame_flush_count++;
}
// flush all packets stuck in queue
L2CA_FlushChannel(cid, 0xffff);
@@ -828,10 +850,18 @@
}
for (size_t i = 0; i < encoded_data_size; i += packet_size) {
- if (left) SendAudio(encoded_data_left.data() + i, packet_size, left);
- if (right) SendAudio(encoded_data_right.data() + i, packet_size, right);
+ if (left) {
+ left->audio_stats.packet_send_count++;
+ SendAudio(encoded_data_left.data() + i, packet_size, left);
+ }
+ if (right) {
+ right->audio_stats.packet_send_count++;
+ SendAudio(encoded_data_right.data() + i, packet_size, right);
+ }
seq_counter++;
}
+ if (left) left->audio_stats.frame_send_count++;
+ if (right) right->audio_stats.frame_send_count++;
}
void SendAudio(uint8_t* encoded_data, uint16_t packet_size,
@@ -937,6 +967,27 @@
if (instance) instance->GapCallback(gap_handle, event, data);
}
+ void Dump(int fd) {
+ std::stringstream stream;
+ for (const auto& device : hearingDevices.devices) {
+ bool side = device.capabilities & CAPABILITY_SIDE;
+ bool standalone = device.capabilities & CAPABILITY_BINAURAL;
+ stream << " " << device.address.ToString() << " "
+ << (device.accepting_audio ? "" : "not ") << "connected"
+ << "\n " << (standalone ? "binaural" : "monaural") << " "
+ << (side ? "right" : "left") << " " << loghex(device.hi_sync_id)
+ << std::endl;
+ stream
+ << " Packet counts (enqueued/flushed) : "
+ << device.audio_stats.packet_send_count << " / "
+ << device.audio_stats.packet_flush_count
+ << "\n Frame counts (enqueued/flushed) : "
+ << device.audio_stats.frame_send_count << " / "
+ << device.audio_stats.frame_flush_count << std::endl;
+ }
+ dprintf(fd, "%s", stream.str().c_str());
+ }
+
void Disconnect(const RawAddress& address) override {
DVLOG(2) << __func__;
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
@@ -947,6 +998,7 @@
VLOG(2) << __func__ << ": " << address;
+ bool connected = hearingDevice->accepting_audio;
hearingDevice->accepting_audio = false;
if (hearingDevice->connecting_actively) {
@@ -968,7 +1020,8 @@
hearingDevices.Remove(address);
- callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+ if (connected)
+ callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
}
void OnGattDisconnected(tGATT_STATUS status, uint16_t conn_id,
@@ -1125,14 +1178,15 @@
uint16_t audio_control_point_handle,
uint16_t volume_handle, uint64_t hiSyncId,
uint16_t render_delay,
- uint16_t preparation_delay) {
+ uint16_t preparation_delay,
+ uint16_t is_white_listed) {
if (!instance) {
LOG(ERROR) << "Not initialized yet";
}
instance->AddFromStorage(address, psm, capabilities, codecs,
audio_control_point_handle, volume_handle, hiSyncId,
- render_delay, preparation_delay);
+ render_delay, preparation_delay, is_white_listed);
};
void HearingAid::CleanUp() {
@@ -1146,3 +1200,9 @@
instance = nullptr;
delete ptr;
};
+
+void HearingAid::DebugDump(int fd) {
+ dprintf(fd, "\nHearing Aid Manager:\n");
+ if (instance) instance->Dump(fd);
+ HearingAidAudioSource::DebugDump(fd);
+}
\ No newline at end of file
diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc
index cebb4d8..947caaf 100644
--- a/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -22,7 +22,6 @@
#include "uipc.h"
#include <base/files/file_util.h>
-#include <base/strings/string_number_conversions.h>
#include <include/hardware/bt_av.h>
using base::FilePath;
@@ -38,8 +37,24 @@
HearingAidAudioReceiver* localAudioReceiver;
std::unique_ptr<tUIPC_STATE> uipc_hearing_aid;
+struct AudioHalStats {
+ size_t media_read_total_underflow_bytes;
+ size_t media_read_total_underflow_count;
+ uint64_t media_read_last_underflow_us;
+
+ AudioHalStats() { Reset(); }
+
+ void Reset() {
+ media_read_total_underflow_bytes = 0;
+ media_read_total_underflow_count = 0;
+ media_read_last_underflow_us = 0;
+ }
+};
+
+AudioHalStats stats;
+
void send_audio_data(void*) {
- int bytes_per_tick =
+ uint32_t bytes_per_tick =
(num_channels * sample_rate * data_interval_ms * (bit_rate / 8)) / 1000;
uint16_t event;
@@ -49,6 +64,11 @@
&event, p_buf, bytes_per_tick);
VLOG(2) << "bytes_read: " << bytes_read;
+ if (bytes_read < bytes_per_tick) {
+ stats.media_read_total_underflow_bytes += bytes_per_tick - bytes_read;
+ stats.media_read_total_underflow_count++;
+ stats.media_read_last_underflow_us = time_get_os_boottime_us();
+ }
std::vector<uint8_t> data(p_buf, p_buf + bytes_read);
@@ -246,6 +266,7 @@
HearingAidAudioReceiver* audioReceiver) {
localAudioReceiver = audioReceiver;
VLOG(2) << "Hearing Aid UIPC Open";
+ stats.Reset();
}
void HearingAidAudioSource::Stop() {
@@ -263,3 +284,21 @@
void HearingAidAudioSource::CleanUp() {
UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_ALL);
}
+
+void HearingAidAudioSource::DebugDump(int fd) {
+ uint64_t now_us = time_get_os_boottime_us();
+ std::stringstream stream;
+ stream << " Hearing Aid Audio HAL:"
+ << "\n Counts (underflow) : "
+ << stats.media_read_total_underflow_count
+ << "\n Bytes (underflow) : "
+ << stats.media_read_total_underflow_bytes
+ << "\n Last update time ago in ms (underflow) : "
+ << (stats.media_read_last_underflow_us > 0
+ ? (unsigned long long)(now_us -
+ stats.media_read_last_underflow_us) /
+ 1000
+ : 0)
+ << std::endl;
+ dprintf(fd, "%s", stream.str().c_str());
+}
diff --git a/bta/hf_client/bta_hf_client_act.cc b/bta/hf_client/bta_hf_client_act.cc
index 3e6c22d..e3f25f6 100644
--- a/bta/hf_client/bta_hf_client_act.cc
+++ b/bta/hf_client/bta_hf_client_act.cc
@@ -103,8 +103,8 @@
}
/* Check if RFCOMM has any incoming connection to avoid collision. */
- RawAddress pending_bd_addr;
- if (PORT_IsOpening(pending_bd_addr)) {
+ RawAddress pending_bd_addr = RawAddress::kEmpty;
+ if (PORT_IsOpening(&pending_bd_addr)) {
/* Let the incoming connection goes through. */
/* Issue collision for now. */
/* We will decide what to do when we find incoming connection later.*/
@@ -164,21 +164,17 @@
p_data->hdr.layer_specific);
return;
}
-
- uint16_t lcid;
- RawAddress dev_addr;
- int status;
-
/* set role */
client_cb->role = BTA_HF_CLIENT_ACP;
APPL_TRACE_DEBUG("%s: conn_handle %d", __func__, client_cb->conn_handle);
/* get bd addr of peer */
- if (PORT_SUCCESS != (status = PORT_CheckConnection(client_cb->conn_handle,
- dev_addr, &lcid))) {
- APPL_TRACE_DEBUG("%s: error PORT_CheckConnection returned status %d",
- __func__, status);
+ uint16_t lcid = 0;
+ RawAddress dev_addr = RawAddress::kEmpty;
+ int status = PORT_CheckConnection(client_cb->conn_handle, &dev_addr, &lcid);
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status;
}
/* Collision Handling */
diff --git a/bta/hf_client/bta_hf_client_rfc.cc b/bta/hf_client/bta_hf_client_rfc.cc
index e261c16..f3e0947 100644
--- a/bta/hf_client/bta_hf_client_rfc.cc
+++ b/bta/hf_client/bta_hf_client_rfc.cc
@@ -98,9 +98,12 @@
APPL_TRACE_DEBUG("%s: allocating a new CB for incoming connection",
__func__);
// Find the BDADDR of the peer device
- RawAddress peer_addr;
- uint16_t lcid;
- PORT_CheckConnection(port_handle, peer_addr, &lcid);
+ RawAddress peer_addr = RawAddress::kEmpty;
+ uint16_t lcid = 0;
+ int status = PORT_CheckConnection(port_handle, &peer_addr, &lcid);
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status;
+ }
// Since we accepted a remote request we should allocate a handle first.
uint16_t tmp_handle = -1;
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
index 6843dbf..0f6550e 100644
--- a/bta/include/bta_ag_api.h
+++ b/bta/include/bta_ag_api.h
@@ -46,6 +46,7 @@
#define HSP_VERSION_1_2 0x0102
#define HFP_VERSION_CONFIG_KEY "HfpVersion"
+#define HFP_SDP_FEATURES_CONFIG_KEY "HfpSdpFeatures"
/* Note, if you change the default version here, please also change the one in
* bta_hs_api.h, they are meant to be the same.
@@ -66,6 +67,12 @@
#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */
+/* AG SDP feature masks */
+#define BTA_AG_FEAT_WBS_SUPPORT 0x0020 /* Supports WBS */
+
+/* Only SDP feature bits 0 to 4 matches BRSF feature bits */
+#define HFP_SDP_BRSF_FEATURES_MASK 0x001F
+
/* Valid feature bit mask for HFP 1.6 (and below) */
#define HFP_1_6_FEAT_MASK 0x000003FF
diff --git a/bta/include/bta_closure_api.h b/bta/include/bta_closure_api.h
index e0aad47..a4c0188 100644
--- a/bta/include/bta_closure_api.h
+++ b/bta/include/bta_closure_api.h
@@ -23,6 +23,8 @@
#include <base/callback_forward.h>
#include <base/location.h>
+#include <hardware/bluetooth.h>
+
/*
* This method post a closure for execution on bta thread. Please see
* documentation at
@@ -30,7 +32,7 @@
* for how to handle dynamic memory ownership/smart pointers with base::Owned(),
* base::Passed(), base::ConstRef() and others.
*/
-void do_in_bta_thread(const tracked_objects::Location& from_here,
- const base::Closure& task);
+bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task);
#endif /* BTA_CLOSURE_API_H */
diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h
index 59cdf56..6b94722 100644
--- a/bta/include/bta_hearing_aid_api.h
+++ b/bta/include/bta_hearing_aid_api.h
@@ -21,7 +21,6 @@
#include <base/callback_forward.h>
#include <hardware/bt_hearing_aid.h>
-using bluetooth::Uuid;
/** Implementations of HearingAid will also implement this interface */
class HearingAidAudioReceiver {
@@ -41,12 +40,14 @@
static void CleanUp();
static bool IsInitialized();
static HearingAid* Get();
+ static void DebugDump(int fd);
static void AddFromStorage(const RawAddress& address, uint16_t psm,
uint8_t capabilities, uint16_t codec,
uint16_t audioControlPointHandle,
uint16_t volumeHandle, uint64_t hiSyncId,
- uint16_t render_delay, uint16_t preparation_delay);
+ uint16_t render_delay, uint16_t preparation_delay,
+ uint16_t is_white_listed);
virtual void Connect(const RawAddress& address) = 0;
virtual void Disconnect(const RawAddress& address) = 0;
@@ -83,4 +84,5 @@
static void Stop();
static void Initialize();
static void CleanUp();
+ static void DebugDump(int fd);
};
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index 87e5052..d7d1583 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -480,7 +480,7 @@
static tBTA_JV_PM_CB* bta_jv_alloc_set_pm_profile_cb(uint32_t jv_handle,
tBTA_JV_PM_ID app_id) {
bool bRfcHandle = (jv_handle & BTA_JV_RFCOMM_MASK) != 0;
- RawAddress peer_bd_addr;
+ RawAddress peer_bd_addr = RawAddress::kEmpty;
int i, j;
tBTA_JV_PM_CB** pp_cb;
@@ -494,8 +494,9 @@
pp_cb = &bta_jv_cb.port_cb[j].p_pm_cb;
if (PORT_SUCCESS !=
PORT_CheckConnection(bta_jv_cb.port_cb[j].port_handle,
- peer_bd_addr, NULL))
+ &peer_bd_addr, NULL)) {
i = BTA_JV_PM_MAX_NUM;
+ }
break;
}
}
@@ -604,7 +605,7 @@
}
/** Disables the BT device manager free the resources used by java */
-void bta_jv_disable() { LOG(ERROR) << __func__; }
+void bta_jv_disable() { LOG(INFO) << __func__; }
/**
* We keep a list of PSM's that have been freed from JAVA, for reuse.
@@ -941,7 +942,7 @@
if ((type != BTA_JV_CONN_TYPE_L2CAP) ||
(bta_jv_check_psm(remote_psm))) /* allowed */
{
- uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
+ uint16_t max_mps = 0xffff; // Let GAP_ConnOpen set the max_mps.
handle = GAP_ConnOpen("", sec_id, 0, &peer_bd_addr, remote_psm, max_mps,
&cfg, ertm_info.get(), sec_mask, chan_mode_mask,
bta_jv_l2cap_client_cback, type);
@@ -1089,7 +1090,7 @@
*/
uint8_t sec_id = bta_jv_alloc_sec_id();
- uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
+ uint16_t max_mps = 0xffff; // Let GAP_ConnOpen set the max_mps.
/* PSM checking is not required for LE COC */
if (0 == sec_id ||
((type == BTA_JV_CONN_TYPE_L2CAP) && (!bta_jv_check_psm(local_psm))) ||
@@ -1254,7 +1255,7 @@
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
tBTA_JV evt_data;
- RawAddress rem_bda;
+ RawAddress rem_bda = RawAddress::kEmpty;
uint16_t lcid;
tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
@@ -1264,7 +1265,7 @@
VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle
<< ", handle=" << p_cb->handle;
- PORT_CheckConnection(port_handle, rem_bda, &lcid);
+ PORT_CheckConnection(port_handle, &rem_bda, &lcid);
if (code == PORT_SUCCESS) {
evt_data.rfc_open.handle = p_cb->handle;
@@ -1451,7 +1452,7 @@
tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- RawAddress rem_bda;
+ RawAddress rem_bda = RawAddress::kEmpty;
uint16_t lcid;
VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle;
if (NULL == p_cb || NULL == p_cb->p_cback) {
@@ -1465,9 +1466,13 @@
<< ", handle=" << loghex(p_cb->handle) << ", p_pcb" << p_pcb
<< ", user=" << p_pcb->rfcomm_slot_id;
- PORT_CheckConnection(port_handle, rem_bda, &lcid);
+ int status = PORT_CheckConnection(port_handle, &rem_bda, &lcid);
int failed = true;
if (code == PORT_SUCCESS) {
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status
+ << ", although port is supposed to be connected";
+ }
evt_data.rfc_srv_open.handle = p_pcb->handle;
evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
evt_data.rfc_srv_open.rem_bda = rem_bda;
@@ -1521,7 +1526,11 @@
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- if (NULL == p_cb || NULL == p_cb->p_cback) return;
+ if (NULL == p_cb || NULL == p_cb->p_cback) {
+ LOG(ERROR) << __func__ << ": p_cb=" << p_cb
+ << ", p_cb->p_cback=" << (p_cb ? p_cb->p_cback : 0);
+ return;
+ }
VLOG(2) << __func__ << ": code=" << loghex(code)
<< ", port_handle=" << port_handle << ", handle=" << p_cb->handle;
diff --git a/bta/pan/bta_pan_act.cc b/bta/pan/bta_pan_act.cc
index bbcd183..46c8a3d 100644
--- a/bta/pan/bta_pan_act.cc
+++ b/bta/pan/bta_pan_act.cc
@@ -28,7 +28,7 @@
#include <string.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include "bt_common.h"
#include "bta_api.h"
diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h
index 9a3dec0..a72f34b 100644
--- a/bta/sys/bta_sys.h
+++ b/bta/sys/bta_sys.h
@@ -31,6 +31,8 @@
#include <base/logging.h>
#include <base/threading/thread.h>
+#include "bta/include/bta_closure_api.h"
+
/*****************************************************************************
* Constants and data types
****************************************************************************/
@@ -222,8 +224,6 @@
extern bool bta_sys_is_register(uint8_t id);
extern uint16_t bta_sys_get_sys_features(void);
extern void bta_sys_sendmsg(void* p_msg);
-extern void do_in_bta_thread(const tracked_objects::Location& from_here,
- const base::Closure& task);
extern void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval,
uint16_t event, uint16_t layer_specific);
extern void bta_sys_disable(tBTA_SYS_HW_MODULE module);
@@ -266,11 +266,11 @@
#endif
extern void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback);
-extern void bta_sys_notify_role_chg(const RawAddress& p_bda, uint8_t new_role,
- uint8_t hci_status);
+extern void bta_sys_notify_role_chg(const RawAddress& peer_addr,
+ uint8_t new_role, uint8_t hci_status);
extern void bta_sys_collision_register(uint8_t bta_id,
tBTA_SYS_CONN_CBACK* p_cback);
-extern void bta_sys_notify_collision(const RawAddress& p_bda);
+extern void bta_sys_notify_collision(const RawAddress& peer_addr);
#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
extern void bta_sys_eir_register(tBTA_SYS_EIR_CBACK* p_cback);
diff --git a/bta/sys/bta_sys_conn.cc b/bta/sys/bta_sys_conn.cc
index 3c3bc63..ef9649b 100644
--- a/bta/sys/bta_sys_conn.cc
+++ b/bta/sys/bta_sys_conn.cc
@@ -97,12 +97,12 @@
* Returns void
*
******************************************************************************/
-void bta_sys_notify_role_chg(const RawAddress& p_bda, uint8_t new_role,
+void bta_sys_notify_role_chg(const RawAddress& peer_addr, uint8_t new_role,
uint8_t hci_status) {
APPL_TRACE_DEBUG("%s: peer %s new_role:%d hci_status:0x%x", __func__,
- p_bda.ToString().c_str(), new_role, hci_status);
+ peer_addr.ToString().c_str(), new_role, hci_status);
if (bta_sys_cb.p_role_cb) {
- bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda);
+ bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, peer_addr);
}
}
@@ -139,13 +139,13 @@
* Returns void
*
******************************************************************************/
-void bta_sys_notify_collision(const RawAddress& p_bda) {
+void bta_sys_notify_collision(const RawAddress& peer_addr) {
uint8_t index;
for (index = 0; index < MAX_COLLISION_REG; index++) {
if ((bta_sys_cb.colli_reg.id[index] != 0) &&
(bta_sys_cb.colli_reg.p_coll_cback[index] != NULL)) {
- bta_sys_cb.colli_reg.p_coll_cback[index](0, BTA_ID_SYS, 0, p_bda);
+ bta_sys_cb.colli_reg.p_coll_cback[index](0, BTA_ID_SYS, 0, peer_addr);
}
}
}
@@ -368,6 +368,8 @@
******************************************************************************/
void bta_sys_set_policy(uint8_t id, uint8_t policy,
const RawAddress& peer_addr) {
+ APPL_TRACE_DEBUG("%s: peer %s id:%d policy:0x%x", __func__,
+ peer_addr.ToString().c_str(), id, policy);
if (bta_sys_cb.p_policy_cb) {
bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr);
}
@@ -385,6 +387,8 @@
******************************************************************************/
void bta_sys_clear_policy(uint8_t id, uint8_t policy,
const RawAddress& peer_addr) {
+ APPL_TRACE_DEBUG("%s: peer %s id:%d policy:0x%x", __func__,
+ peer_addr.ToString().c_str(), id, policy);
if (bta_sys_cb.p_policy_cb) {
bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr);
}
@@ -401,6 +405,7 @@
*
******************************************************************************/
void bta_sys_set_default_policy(uint8_t id, uint8_t policy) {
+ APPL_TRACE_DEBUG("%s: id:%d policy:0x%x", __func__, id, policy);
if (bta_sys_cb.p_policy_cb) {
bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy,
RawAddress::kEmpty);
@@ -418,6 +423,7 @@
*
******************************************************************************/
void bta_sys_clear_default_policy(uint8_t id, uint8_t policy) {
+ APPL_TRACE_DEBUG("%s: id:%d policy:0x%x", __func__, id, policy);
if (bta_sys_cb.p_policy_cb) {
bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy,
RawAddress::kEmpty);
diff --git a/bta/sys/bta_sys_main.cc b/bta/sys/bta_sys_main.cc
index a196c79..bdedcde 100644
--- a/bta/sys/bta_sys_main.cc
+++ b/bta/sys/bta_sys_main.cc
@@ -547,25 +547,29 @@
*
* Description Post a closure to be ran in the bta thread
*
- * Returns void
+ * Returns BT_STATUS_SUCCESS on success
*
******************************************************************************/
-void do_in_bta_thread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
+bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task) {
base::MessageLoop* bta_message_loop = get_message_loop();
if (!bta_message_loop) {
APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
- return;
+ return BT_STATUS_FAIL;
}
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
bta_message_loop->task_runner();
if (!task_runner.get()) {
APPL_TRACE_ERROR("%s: task runner is dead", __func__);
- return;
+ return BT_STATUS_FAIL;
}
- task_runner->PostTask(from_here, task);
+ if (!task_runner->PostTask(from_here, task)) {
+ APPL_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
}
/*******************************************************************************
diff --git a/btif/avrcp/avrcp_service.cc b/btif/avrcp/avrcp_service.cc
index d6750ce..16b5fab 100644
--- a/btif/avrcp/avrcp_service.cc
+++ b/btif/avrcp/avrcp_service.cc
@@ -115,9 +115,9 @@
public:
MediaInterfaceWrapper(MediaInterface* cb) : wrapped_(cb){};
- void SendKeyEvent(uint8_t key, uint8_t status) override {
+ void SendKeyEvent(uint8_t key, KeyState state) override {
do_in_jni_thread(base::Bind(&MediaInterface::SendKeyEvent,
- base::Unretained(wrapped_), key, status));
+ base::Unretained(wrapped_), key, state));
}
void GetSongInfo(SongInfoCallback info_cb) override {
@@ -273,13 +273,16 @@
instance_->media_interface_ = new MediaInterfaceWrapper(media_interface);
media_interface->RegisterUpdateCallback(instance_);
+ VolumeInterfaceWrapper* wrapped_volume_interface = nullptr;
if (volume_interface != nullptr) {
- instance_->volume_interface_ = new VolumeInterfaceWrapper(volume_interface);
+ wrapped_volume_interface = new VolumeInterfaceWrapper(volume_interface);
}
+ instance_->volume_interface_ = wrapped_volume_interface;
+
ConnectionHandler::Initialize(
base::Bind(&AvrcpService::DeviceCallback, base::Unretained(instance_)),
- &avrcp_interface_, &sdp_interface_, volume_interface);
+ &avrcp_interface_, &sdp_interface_, wrapped_volume_interface);
instance_->connection_handler_ = ConnectionHandler::Get();
}
@@ -402,19 +405,23 @@
void AvrcpService::DebugDump(int fd) {
if (instance_ == nullptr) {
- dprintf(fd, "AVRCP Target Service not started");
+ dprintf(fd, "\nAVRCP Target Service not started\n");
return;
}
- dprintf(fd, "Avrcp Service:\n");
-
auto device_list = instance_->connection_handler_->GetListOfDevices();
- dprintf(fd, "Number of connected deviced: %zu\n", device_list.size());
+ dprintf(fd, "\nAVRCP Target Native Service: %zu devices\n",
+ device_list.size());
+
std::stringstream stream;
- for (auto device : device_list) {
- stream << device;
+ {
+ ScopedIndent indent(stream);
+ for (auto device : device_list) {
+ stream << *device << std::endl;
+ }
}
- dprintf(fd, "%s\n", stream.str().c_str());
+
+ dprintf(fd, "%s", stream.str().c_str());
}
} // namespace avrcp
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 2131f0e..d2f8b19 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -1612,10 +1612,9 @@
APPL_TRACE_DEBUG("%s: peer %s codec_config=%s", __func__,
p_peer->addr.ToString().c_str(),
codec_config.ToString().c_str());
- do_in_jni_thread(
- FROM_HERE,
- base::Bind(&btif_av_report_source_codec_state, p_peer->addr, codec_config,
- codecs_local_capabilities, codecs_selectable_capabilities));
+ btif_av_report_source_codec_state(p_peer->addr, codec_config,
+ codecs_local_capabilities,
+ codecs_selectable_capabilities);
return true;
}
diff --git a/btif/co/bta_dm_co.cc b/btif/co/bta_dm_co.cc
index dfd512b..ab69bfb 100644
--- a/btif/co/bta_dm_co.cc
+++ b/btif/co/bta_dm_co.cc
@@ -25,12 +25,17 @@
#include "bta_sys.h"
#include "bte_appl.h"
#include "btif_dm.h"
+#include "btif_storage.h"
#include "osi/include/osi.h"
+// tBTE_APPL_CFG.ble_io_cap is set to BTM_IO_CAP_UNKNOWN at structure
+// initialization since btif_storage isn't ready yet for data to be fetched.
+// This value is initialized properly during first use by fetching properly
+// from btif_storage.
tBTE_APPL_CFG bte_appl_cfg = {
BTA_LE_AUTH_REQ_SC_MITM_BOND, // Authentication requirements
- BTM_LOCAL_IO_CAPS_BLE, BTM_BLE_INITIATOR_KEY_SIZE,
- BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE};
+ BTM_IO_CAP_UNKNOWN, BTM_BLE_INITIATOR_KEY_SIZE, BTM_BLE_RESPONDER_KEY_SIZE,
+ BTM_BLE_MAX_KEY_SIZE};
/*******************************************************************************
*
@@ -241,6 +246,8 @@
tBTA_LE_AUTH_REQ* p_auth_req, uint8_t* p_max_key_size,
tBTA_LE_KEY_TYPE* p_init_key,
tBTA_LE_KEY_TYPE* p_resp_key) {
+ bte_appl_cfg.ble_io_cap = btif_storage_get_local_io_caps_ble();
+
/* Retrieve the properties from file system if possible */
tBTE_APPL_CFG nv_config;
if (btif_dm_get_smp_config(&nv_config)) bte_appl_cfg = nv_config;
diff --git a/btif/include/btif_a2dp_sink.h b/btif/include/btif_a2dp_sink.h
index 8a3c10c..25e65f4 100644
--- a/btif/include/btif_a2dp_sink.h
+++ b/btif/include/btif_a2dp_sink.h
@@ -54,6 +54,16 @@
// btif_a2dp_sink_startup() to start the streaming session for |peer_address|.
bool btif_a2dp_sink_start_session(const RawAddress& peer_address);
+// Restart the A2DP Sink session.
+// This function should be called by the BTIF state machine after
+// btif_a2dp_sink_startup() to restart the streaming session.
+// |old_peer_address| is the peer address of the old session. This address
+// can be empty.
+// |new_peer_address| is the peer address of the new session. This address
+// cannot be empty.
+bool btif_a2dp_sink_restart_session(const RawAddress& old_peer_address,
+ const RawAddress& new_peer_address);
+
// End the A2DP Sink session.
// This function should be called by the BTIF state machine to end the
// streaming session for |peer_address|.
@@ -109,10 +119,6 @@
// information.
void btif_a2dp_sink_debug_dump(int fd);
-// Update the A2DP Sink related metrics.
-// This function should be called before collecting the metrics.
-void btif_a2dp_sink_update_metrics(void);
-
// Create a request to set the audio focus state for the audio track.
// |state| is the new state value - see |btif_a2dp_sink_focus_state_t|
// for valid values.
diff --git a/btif/include/btif_a2dp_source.h b/btif/include/btif_a2dp_source.h
index 1fc7d9a..bb96e1a 100644
--- a/btif/include/btif_a2dp_source.h
+++ b/btif/include/btif_a2dp_source.h
@@ -39,6 +39,16 @@
// btif_a2dp_source_startup() to start the streaming session for |peer_address|.
bool btif_a2dp_source_start_session(const RawAddress& peer_address);
+// Restart the A2DP Source session.
+// This function should be called by the BTIF state machine after
+// btif_a2dp_source_startup() to restart the streaming session.
+// |old_peer_address| is the peer address of the old session. This address
+// can be empty.
+// |new_peer_address| is the peer address of the new session. This address
+// cannot be empty.
+bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address,
+ const RawAddress& new_peer_address);
+
// End the A2DP Source session.
// This function should be called by the BTIF state machine to end the
// streaming session for |peer_address|.
@@ -64,11 +74,6 @@
// Return true if the A2DP Source module is streaming.
bool btif_a2dp_source_is_streaming(void);
-// Setup the A2DP Source codec, and prepare the encoder.
-// The peer address is |peer_addr|.
-// This function should be called prior to starting A2DP streaming.
-void btif_a2dp_source_setup_codec(const RawAddress& peer_addr);
-
// Process a request to start the A2DP audio encoding task.
void btif_a2dp_source_start_audio_req(void);
@@ -117,8 +122,4 @@
// information.
void btif_a2dp_source_debug_dump(int fd);
-// Update the A2DP Source related metrics.
-// This function should be called before collecting the metrics.
-void btif_a2dp_source_update_metrics(void);
-
#endif /* BTIF_A2DP_SOURCE_H */
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index 4aeafca..2364544 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -88,6 +88,7 @@
btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
btif_hh_device_t* p_curr_dev;
bool service_dereg_active;
+ RawAddress pending_conn_address;
} btif_hh_cb_t;
/*******************************************************************************
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index 7e90162..79a94e3 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -99,6 +99,32 @@
/*******************************************************************************
*
+ * Function btif_storage_get_io_caps
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the device.
+ *
+ * Returns Returns local IO Capability of device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps();
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_io_caps_ble
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the BLE device.
+ *
+ * Returns Returns local IO Capability of BLE device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS_BLE.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps_ble();
+
+/*******************************************************************************
+ *
* Function btif_storage_add_remote_device
*
* Description BTIF storage API - Adds a newly discovered device to
@@ -201,6 +227,9 @@
/** Deletes the bonded hearing aid device info from NVRAM */
void btif_storage_remove_hearing_aid(const RawAddress& address);
+/** Remove the hearing aid device from white list */
+void btif_storage_remove_hearing_aid_white_list(const RawAddress& address);
+
/*******************************************************************************
*
* Function btif_storage_is_retricted_device
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 9d52fdd..92a4092 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -49,6 +49,7 @@
#include "avrcp_service.h"
#include "bt_utils.h"
+#include "bta/include/bta_hearing_aid_api.h"
#include "bta/include/bta_hf_client_api.h"
#include "btif_a2dp.h"
#include "btif_api.h"
@@ -315,11 +316,13 @@
btif_debug_av_dump(fd);
bta_debug_av_dump(fd);
stack_debug_avdtp_api_dump(fd);
+ bluetooth::avrcp::AvrcpService::DebugDump(fd);
btif_debug_config_dump(fd);
BTA_HfClientDumpStatistics(fd);
wakelock_debug_dump(fd);
osi_allocator_debug_dump(fd);
alarm_debug_dump(fd);
+ HearingAid::DebugDump(fd);
#if (BTSNOOP_MEM == TRUE)
btif_debug_btsnoop_dump(fd);
#endif
diff --git a/btif/src/btif_a2dp_audio_interface.cc b/btif/src/btif_a2dp_audio_interface.cc
index 9fa92b2..469776c 100644
--- a/btif/src/btif_a2dp_audio_interface.cc
+++ b/btif/src/btif_a2dp_audio_interface.cc
@@ -268,7 +268,7 @@
}*/
uint8_t btif_a2dp_audio_process_request(uint8_t cmd) {
- APPL_TRACE_DEBUG(LOG_TAG, "%s: cmd: %s", __func__,
+ APPL_TRACE_DEBUG("%s: cmd: %s", __func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
a2dp_cmd_pending = cmd;
uint8_t status;
@@ -280,6 +280,9 @@
* while in a call, and respond with BAD_STATE.
*/
if (!bluetooth::headset::IsCallIdle()) {
+ APPL_TRACE_WARNING("%s: A2DP command %s failed as call state is busy",
+ __func__,
+ audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
status = A2DP_CTRL_ACK_INCALL_FAILURE;
break;
}
@@ -349,7 +352,7 @@
status = A2DP_CTRL_ACK_FAILURE;
break;
}
- APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s DONE",
- audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
+ APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s DONE returning status %d",
+ audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd), status);
return status;
}
diff --git a/btif/src/btif_a2dp_control.cc b/btif/src/btif_a2dp_control.cc
index e64e66c..bae6185 100644
--- a/btif/src/btif_a2dp_control.cc
+++ b/btif/src/btif_a2dp_control.cc
@@ -112,6 +112,8 @@
* while in a call, and respond with BAD_STATE.
*/
if (!bluetooth::headset::IsCallIdle()) {
+ APPL_TRACE_WARNING("%s: A2DP command %s while call state is busy",
+ __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
btif_a2dp_command_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
break;
}
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index b80cdc7..c17b33a 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -197,6 +197,32 @@
// Nothing to do
}
+bool btif_a2dp_sink_restart_session(const RawAddress& old_peer_address,
+ const RawAddress& new_peer_address) {
+ LOG_INFO(LOG_TAG, "%s: old_peer_address=%s new_peer_address=%s", __func__,
+ old_peer_address.ToString().c_str(),
+ new_peer_address.ToString().c_str());
+
+ CHECK(!new_peer_address.IsEmpty());
+
+ if (!old_peer_address.IsEmpty()) {
+ btif_a2dp_sink_end_session(old_peer_address);
+ }
+
+ if (!bta_av_co_set_active_peer(new_peer_address)) {
+ LOG_ERROR(LOG_TAG, "%s: Cannot stream audio: cannot set active peer to %s",
+ __func__, new_peer_address.ToString().c_str());
+ return false;
+ }
+
+ if (old_peer_address.IsEmpty()) {
+ btif_a2dp_sink_startup();
+ }
+ btif_a2dp_sink_start_session(new_peer_address);
+
+ return true;
+}
+
bool btif_a2dp_sink_end_session(const RawAddress& peer_address) {
LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
peer_address.ToString().c_str());
diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc
index f81834c..adaa044 100644
--- a/btif/src/btif_a2dp_source.cc
+++ b/btif/src/btif_a2dp_source.cc
@@ -310,6 +310,10 @@
static void btif_a2dp_source_audio_tx_start_event(void);
static void btif_a2dp_source_audio_tx_stop_event(void);
static void btif_a2dp_source_audio_tx_flush_event(void);
+// Set up the A2DP Source codec, and prepare the encoder.
+// The peer address is |peer_addr|.
+// This function should be called prior to starting A2DP streaming.
+static void btif_a2dp_source_setup_codec(const RawAddress& peer_addr);
static void btif_a2dp_source_setup_codec_delayed(
const RawAddress& peer_address);
static void btif_a2dp_source_encoder_user_config_update_event(
@@ -326,6 +330,9 @@
static void log_tstamps_us(const char* comment, uint64_t timestamp_us);
static void update_scheduling_stats(SchedulingStats* stats, uint64_t now_us,
uint64_t expected_delta);
+// Update the A2DP Source related metrics.
+// This function should be called before collecting the metrics.
+static void btif_a2dp_source_update_metrics(void);
static void btm_read_rssi_cb(void* data);
static void btm_read_failed_contact_counter_cb(void* data);
static void btm_read_automatic_flush_timeout_cb(void* data);
@@ -447,6 +454,38 @@
}
}
+bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address,
+ const RawAddress& new_peer_address) {
+ bool is_streaming = alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
+ LOG_INFO(LOG_TAG,
+ "%s: old_peer_address=%s new_peer_address=%s is_streaming=%s",
+ __func__, old_peer_address.ToString().c_str(),
+ new_peer_address.ToString().c_str(), logbool(is_streaming).c_str());
+
+ CHECK(!new_peer_address.IsEmpty());
+
+ // Must stop first the audio streaming
+ if (is_streaming) {
+ btif_a2dp_source_stop_audio_req();
+ }
+
+ // If the old active peer was valid, end the old session.
+ // Otherwise, time to startup the A2DP Source processing.
+ if (!old_peer_address.IsEmpty()) {
+ btif_a2dp_source_end_session(old_peer_address);
+ } else {
+ btif_a2dp_source_startup();
+ }
+
+ // Start the session.
+ // If audio was streaming before, start audio streaming as well.
+ btif_a2dp_source_start_session(new_peer_address);
+ if (is_streaming) {
+ btif_a2dp_source_start_audio_req();
+ }
+ return true;
+}
+
bool btif_a2dp_source_end_session(const RawAddress& peer_address) {
LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
peer_address.ToString().c_str());
@@ -532,7 +571,7 @@
return alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
}
-void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
+static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
peer_address.ToString().c_str());
@@ -1173,7 +1212,7 @@
(unsigned long long)ave_time_us / 1000);
}
-void btif_a2dp_source_update_metrics(void) {
+static void btif_a2dp_source_update_metrics(void) {
const BtifMediaStats& stats = btif_a2dp_source_cb.stats;
const SchedulingStats& enqueue_stats = stats.tx_queue_enqueue_stats;
A2dpSessionMetrics metrics;
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index a2fa2db..e4e6bac 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -33,7 +33,8 @@
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
#include "bt_common.h"
#include "bt_utils.h"
-#include "bta_api.h"
+#include "bta/include/bta_api.h"
+#include "bta/include/bta_closure_api.h"
#include "btif/include/btif_a2dp_source.h"
#include "btif_a2dp.h"
#include "btif_a2dp_audio_interface.h"
@@ -54,8 +55,6 @@
*****************************************************************************/
static const std::string kBtifAvSourceServiceName = "Advanced Audio Source";
static const std::string kBtifAvSinkServiceName = "Advanced Audio Sink";
-static const std::string kBtifAvA2dpOffloadEnable =
- "persist.bluetooth.a2dp_offload.enable";
static constexpr int kDefaultMaxConnectedAudioDevices = 1;
static constexpr tBTA_AV_HNDL kBtaHandleUnknown = 0;
@@ -66,7 +65,7 @@
typedef struct {
int sample_rate;
int channel_count;
- RawAddress peer_bd;
+ RawAddress peer_address;
} btif_av_sink_config_req_t;
/**
@@ -405,6 +404,7 @@
BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
__func__);
}
+ btif_av_stream_stop();
btif_a2dp_source_end_session(active_peer_);
btif_a2dp_source_shutdown();
active_peer_ = peer_address;
@@ -417,24 +417,11 @@
peer->PeerAddress().ToString().c_str());
return false;
}
- if (!bta_av_co_set_active_peer(peer_address)) {
- BTIF_TRACE_ERROR("%s: unable to set active peer to %s in BtaAvCo",
- __func__, peer_address.ToString().c_str());
+
+ if (!btif_a2dp_source_restart_session(active_peer_, peer_address)) {
return false;
}
-
- // Start/restart the session
- if (!active_peer_.IsEmpty()) {
- btif_a2dp_source_end_session(active_peer_);
- }
- bool should_startup = active_peer_.IsEmpty();
active_peer_ = peer_address;
- if (should_startup) {
- BTIF_TRACE_EVENT("%s: active peer is empty, startup the Audio source",
- __func__);
- btif_a2dp_source_startup();
- }
- btif_a2dp_source_start_session(peer_address);
return true;
}
@@ -567,24 +554,11 @@
peer->PeerAddress().ToString().c_str());
return false;
}
- if (!bta_av_co_set_active_peer(peer_address)) {
- BTIF_TRACE_ERROR("%s: unable to set active peer to %s in BtaAvCo",
- __func__, peer_address.ToString().c_str());
+
+ if (!btif_a2dp_sink_restart_session(active_peer_, peer_address)) {
return false;
}
-
- // Start/restart the session
- if (!active_peer_.IsEmpty()) {
- btif_a2dp_sink_end_session(active_peer_);
- }
- bool should_startup = active_peer_.IsEmpty();
active_peer_ = peer_address;
- if (should_startup) {
- BTIF_TRACE_EVENT("%s: active peer is empty, startup the Audio sink",
- __func__);
- btif_a2dp_sink_startup();
- }
- btif_a2dp_sink_start_session(peer_address);
return true;
}
@@ -639,6 +613,8 @@
btav_connection_state_t state);
static void btif_report_audio_state(const RawAddress& peer_address,
btav_audio_state_t state);
+static void btif_av_report_sink_audio_config_state(
+ const RawAddress& peer_address, int sample_rate, int channel_count);
static void btif_av_source_initiate_av_open_timer_timeout(void* data);
static void btif_av_sink_initiate_av_open_timer_timeout(void* data);
static void bta_av_sink_media_callback(tBTA_AV_EVT event,
@@ -907,9 +883,13 @@
max_connected_peers_ = max_connected_audio_devices;
/* A2DP OFFLOAD */
- char value[PROPERTY_VALUE_MAX] = {'\0'};
- osi_property_get(kBtifAvA2dpOffloadEnable.c_str(), value, "false");
- a2dp_offload_enabled_ = (strcmp(value, "true") == 0);
+ char value_sup[PROPERTY_VALUE_MAX] = {'\0'};
+ char value_dis[PROPERTY_VALUE_MAX] = {'\0'};
+ osi_property_get("ro.bluetooth.a2dp_offload.supported", value_sup, "false");
+ osi_property_get("persist.bluetooth.a2dp_offload.disabled", value_dis,
+ "false");
+ a2dp_offload_enabled_ =
+ (strcmp(value_sup, "true") == 0) && (strcmp(value_dis, "false") == 0);
BTIF_TRACE_DEBUG("a2dp_offload.enable = %d", a2dp_offload_enabled_);
callbacks_ = callbacks;
@@ -929,11 +909,11 @@
btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE);
- do_in_jni_thread(
+ do_in_bta_thread(
FROM_HERE,
base::Bind(base::IgnoreResult(&BtifAvSource::SetActivePeer),
base::Unretained(&btif_av_source), RawAddress::kEmpty));
- do_in_jni_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup));
+ do_in_bta_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup));
btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
CleanupAllPeers();
@@ -1107,11 +1087,11 @@
btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK);
- do_in_jni_thread(
+ do_in_bta_thread(
FROM_HERE,
base::Bind(base::IgnoreResult(&BtifAvSink::SetActivePeer),
base::Unretained(&btif_av_sink), RawAddress::kEmpty));
- do_in_jni_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup));
+ do_in_bta_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup));
btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
CleanupAllPeers();
@@ -1282,10 +1262,10 @@
// Delete peers that are re-entering the Idle state
if (peer_.IsSink()) {
- do_in_jni_thread(FROM_HERE, base::Bind(&BtifAvSource::DeleteIdlePeers,
+ do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSource::DeleteIdlePeers,
base::Unretained(&btif_av_source)));
} else if (peer_.IsSource()) {
- do_in_jni_thread(FROM_HERE, base::Bind(&BtifAvSink::DeleteIdlePeers,
+ do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSink::DeleteIdlePeers,
base::Unretained(&btif_av_sink)));
}
}
@@ -1296,10 +1276,11 @@
}
bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
- BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
- peer_.PeerAddress().ToString().c_str(),
+ BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s active_peer=%s",
+ __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
BtifAvEvent::EventName(event).c_str(),
- peer_.FlagsToString().c_str());
+ peer_.FlagsToString().c_str(),
+ logbool(peer_.IsActivePeer()).c_str());
switch (event) {
case BTA_AV_ENABLE_EVT:
@@ -1403,19 +1384,11 @@
// Procedure, we have to handle Config and Open event in Idle state.
// We hit these scenarios while running PTS test case for AVRCP Controller.
case BTIF_AV_SINK_CONFIG_REQ_EVT: {
- btif_av_sink_config_req_t req;
- // Copy to avoid alignment problems
- memcpy(&req, p_data, sizeof(req));
-
- LOG_INFO(LOG_TAG,
- "%s: Peer %s : event=%s sample_rate=%d channel_count=%d",
- __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
- BtifAvEvent::EventName(event).c_str(), req.sample_rate,
- req.channel_count);
- if (btif_av_sink.Enabled()) {
- HAL_CBACK(btif_av_sink.Callbacks(), audio_config_cb, req.peer_bd,
- req.sample_rate, req.channel_count);
- }
+ const btif_av_sink_config_req_t* p_config_req =
+ static_cast<const btif_av_sink_config_req_t*>(p_data);
+ btif_av_report_sink_audio_config_state(p_config_req->peer_address,
+ p_config_req->sample_rate,
+ p_config_req->channel_count);
} break;
case BTA_AV_OPEN_EVT: {
@@ -1530,10 +1503,11 @@
bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event,
void* p_data) {
- BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
- peer_.PeerAddress().ToString().c_str(),
+ BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s active_peer=%s",
+ __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
BtifAvEvent::EventName(event).c_str(),
- peer_.FlagsToString().c_str());
+ peer_.FlagsToString().c_str(),
+ logbool(peer_.IsActivePeer()).c_str());
switch (event) {
case BTIF_AV_STOP_STREAM_REQ_EVT:
@@ -1623,18 +1597,12 @@
} break;
case BTIF_AV_SINK_CONFIG_REQ_EVT: {
- btif_av_sink_config_req_t req;
- // Copy to avoid alignment problems
- memcpy(&req, p_data, sizeof(req));
-
- LOG_INFO(LOG_TAG,
- "%s: Peer %s : event=%s sample_rate=%d channel_count=%d",
- __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
- BtifAvEvent::EventName(event).c_str(), req.sample_rate,
- req.channel_count);
- if (peer_.IsSource() && btif_av_sink.Enabled()) {
- HAL_CBACK(btif_av_sink.Callbacks(), audio_config_cb,
- peer_.PeerAddress(), req.sample_rate, req.channel_count);
+ const btif_av_sink_config_req_t* p_config_req =
+ static_cast<const btif_av_sink_config_req_t*>(p_data);
+ if (peer_.IsSource()) {
+ btif_av_report_sink_audio_config_state(p_config_req->peer_address,
+ p_config_req->sample_rate,
+ p_config_req->channel_count);
}
} break;
@@ -1678,9 +1646,9 @@
break;
case BTIF_AV_DISCONNECT_REQ_EVT:
+ BTA_AvClose(peer_.BtaHandle());
btif_report_connection_state(peer_.PeerAddress(),
BTAV_CONNECTION_STATE_DISCONNECTED);
- BTA_AvClose(peer_.BtaHandle());
peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
if (peer_.SelfInitiatedConnection()) {
btif_queue_advance();
@@ -1732,10 +1700,11 @@
void* p_data) {
tBTA_AV* p_av = (tBTA_AV*)p_data;
- BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
- peer_.PeerAddress().ToString().c_str(),
+ BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s active_peer=%s",
+ __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
BtifAvEvent::EventName(event).c_str(),
- peer_.FlagsToString().c_str());
+ peer_.FlagsToString().c_str(),
+ logbool(peer_.IsActivePeer()).c_str());
if ((event == BTA_AV_REMOTE_CMD_EVT) &&
peer_.CheckFlags(BtifAvPeer::kFlagRemoteSuspend) &&
@@ -1829,15 +1798,18 @@
btif_a2dp_on_stopped(nullptr);
}
- // Inform the application that we are disconnected
- btif_report_connection_state(peer_.PeerAddress(),
- BTAV_CONNECTION_STATE_DISCONNECTED);
-
// Change state to Idle, send acknowledgement if start is pending
if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
+ BTIF_TRACE_WARNING("%s: Peer %s : failed pending start request",
+ __PRETTY_FUNCTION__,
+ peer_.PeerAddress().ToString().c_str());
btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
// Pending start flag will be cleared when exit current state
}
+
+ // Inform the application that we are disconnected
+ btif_report_connection_state(peer_.PeerAddress(),
+ BTAV_CONNECTION_STATE_DISCONNECTED);
peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
break;
@@ -1849,6 +1821,9 @@
__PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str());
BTA_AvStart(peer_.BtaHandle());
} else if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
+ BTIF_TRACE_WARNING("%s: Peer %s : failed reconfiguration",
+ __PRETTY_FUNCTION__,
+ peer_.PeerAddress().ToString().c_str());
peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
}
@@ -1912,10 +1887,11 @@
void* p_data) {
tBTA_AV* p_av = (tBTA_AV*)p_data;
- BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
- peer_.PeerAddress().ToString().c_str(),
+ BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s active_peer=%s",
+ __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
BtifAvEvent::EventName(event).c_str(),
- peer_.FlagsToString().c_str());
+ peer_.FlagsToString().c_str(),
+ logbool(peer_.IsActivePeer()).c_str());
switch (event) {
case BTIF_AV_ACL_DISCONNECTED:
@@ -1949,7 +1925,12 @@
if (peer_.IsSink()) {
// Immediately stop transmission of frames while suspend is pending
if (peer_.IsActivePeer()) {
- btif_a2dp_source_set_tx_flush(true);
+ if (event == BTIF_AV_STOP_STREAM_REQ_EVT) {
+ btif_a2dp_on_stopped(nullptr);
+ } else {
+ // (event == BTIF_AV_SUSPEND_STREAM_REQ_EVT)
+ btif_a2dp_source_set_tx_flush(true);
+ }
}
} else if (peer_.IsSource()) {
btif_a2dp_on_stopped(nullptr);
@@ -1977,7 +1958,7 @@
peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateClosing);
break;
- case BTA_AV_SUSPEND_EVT:
+ case BTA_AV_SUSPEND_EVT: {
LOG_INFO(LOG_TAG,
"%s: Peer %s : event=%s status=%d initiator=%d flags=%s",
__PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
@@ -1998,6 +1979,7 @@
return false;
}
+ btav_audio_state_t state = BTAV_AUDIO_STATE_REMOTE_SUSPEND;
if (p_av->suspend.initiator != true) {
// Remote suspend, notify HAL and await audioflinger to
// suspend/stop stream.
@@ -2006,18 +1988,16 @@
// stream only if we did not already initiate a local suspend.
if (!peer_.CheckFlags(BtifAvPeer::kFlagLocalSuspendPending))
peer_.SetFlags(BtifAvPeer::kFlagRemoteSuspend);
-
- btif_report_audio_state(peer_.PeerAddress(),
- BTAV_AUDIO_STATE_REMOTE_SUSPEND);
} else {
- btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STOPPED);
+ state = BTAV_AUDIO_STATE_STOPPED;
}
- peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpened);
-
- // Suspend completed and state changed, clear pending status
+ // Suspend completed, clear pending status
peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
- break;
+
+ btif_report_audio_state(peer_.PeerAddress(), state);
+ peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpened);
+ } break;
case BTA_AV_STOP_EVT:
LOG_INFO(LOG_TAG, "%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
@@ -2099,10 +2079,11 @@
bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event,
void* p_data) {
- BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
- peer_.PeerAddress().ToString().c_str(),
+ BTIF_TRACE_DEBUG("%s: Peer %s : event=%s flags=%s active_peer=%s",
+ __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
BtifAvEvent::EventName(event).c_str(),
- peer_.FlagsToString().c_str());
+ peer_.FlagsToString().c_str(),
+ logbool(peer_.IsActivePeer()).c_str());
switch (event) {
case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
@@ -2219,11 +2200,13 @@
peer_address.ToString().c_str(), state);
if (btif_av_source.Enabled()) {
- HAL_CBACK(btif_av_source.Callbacks(), connection_state_cb, peer_address,
- state);
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(btif_av_source.Callbacks()->connection_state_cb,
+ peer_address, state));
} else if (btif_av_sink.Enabled()) {
- HAL_CBACK(btif_av_sink.Callbacks(), connection_state_cb, peer_address,
- state);
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(btif_av_sink.Callbacks()->connection_state_cb,
+ peer_address, state));
}
}
@@ -2242,9 +2225,13 @@
peer_address.ToString().c_str(), state);
if (btif_av_source.Enabled()) {
- HAL_CBACK(btif_av_source.Callbacks(), audio_state_cb, peer_address, state);
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(btif_av_source.Callbacks()->audio_state_cb,
+ peer_address, state));
} else if (btif_av_sink.Enabled()) {
- HAL_CBACK(btif_av_sink.Callbacks(), audio_state_cb, peer_address, state);
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(btif_av_sink.Callbacks()->audio_state_cb,
+ peer_address, state));
}
}
@@ -2257,9 +2244,29 @@
BTIF_TRACE_EVENT("%s: peer_address=%s", __func__,
peer_address.ToString().c_str());
if (btif_av_source.Enabled()) {
- HAL_CBACK(btif_av_source.Callbacks(), audio_config_cb, peer_address,
- codec_config, codecs_local_capabilities,
- codecs_selectable_capabilities);
+ do_in_jni_thread(
+ FROM_HERE,
+ base::Bind(btif_av_source.Callbacks()->audio_config_cb, peer_address,
+ codec_config, codecs_local_capabilities,
+ codecs_selectable_capabilities));
+ }
+}
+
+/**
+ * Report the audio config state of the A2DP Sink connection.
+ *
+ * @param peer_address the peer address
+ * @param sample_rate the sample rate (in samples per second)
+ * @param channel_count the channel count (1 for Mono, 2 for Stereo)
+ */
+static void btif_av_report_sink_audio_config_state(
+ const RawAddress& peer_address, int sample_rate, int channel_count) {
+ LOG_INFO(LOG_TAG, "%s: Peer %s : sample_rate=%d channel_count=%d", __func__,
+ peer_address.ToString().c_str(), sample_rate, channel_count);
+ if (btif_av_sink.Enabled()) {
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(btif_av_sink.Callbacks()->audio_config_cb,
+ peer_address, sample_rate, channel_count));
}
}
@@ -2449,14 +2456,14 @@
BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV));
BTIF_TRACE_EVENT("%s: event=%s", __func__, btif_av_event.ToString().c_str());
- do_in_jni_thread(FROM_HERE,
+ do_in_bta_thread(FROM_HERE,
base::Bind(&btif_av_handle_bta_av_event,
AVDT_TSEP_SNK /* peer_sep */, btif_av_event));
}
static void bta_av_sink_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV));
- do_in_jni_thread(FROM_HERE,
+ do_in_bta_thread(FROM_HERE,
base::Bind(&btif_av_handle_bta_av_event,
AVDT_TSEP_SRC /* peer_sep */, btif_av_event));
}
@@ -2497,12 +2504,12 @@
APPL_TRACE_ERROR("%s: Cannot get the channel count", __func__);
break;
}
- config_req.peer_bd = p_data->avk_config.bd_addr;
+ config_req.peer_address = p_data->avk_config.bd_addr;
BtifAvEvent btif_av_event(BTIF_AV_SINK_CONFIG_REQ_EVT, &config_req,
sizeof(config_req));
- do_in_jni_thread(FROM_HERE, base::Bind(&btif_av_handle_event,
+ do_in_bta_thread(FROM_HERE, base::Bind(&btif_av_handle_event,
AVDT_TSEP_SRC, // peer_sep
- config_req.peer_bd,
+ config_req.peer_address,
kBtaHandleUnknown, btif_av_event));
break;
}
@@ -2623,7 +2630,7 @@
BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address,
sizeof(peer_address));
- return do_in_jni_thread(
+ return do_in_bta_thread(
FROM_HERE, base::Bind(&btif_av_handle_event,
AVDT_TSEP_SNK, // peer_sep
peer_address, kBtaHandleUnknown, btif_av_event));
@@ -2639,7 +2646,7 @@
BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address,
sizeof(peer_address));
- return do_in_jni_thread(
+ return do_in_bta_thread(
FROM_HERE, base::Bind(&btif_av_handle_event,
AVDT_TSEP_SRC, // peer_sep
peer_address, kBtaHandleUnknown, btif_av_event));
@@ -2653,7 +2660,7 @@
return BT_STATUS_NOT_READY;
}
- return do_in_jni_thread(FROM_HERE, base::Bind(&set_active_peer_int,
+ return do_in_bta_thread(FROM_HERE, base::Bind(&set_active_peer_int,
AVDT_TSEP_SNK, // peer_sep
peer_address));
}
@@ -2668,7 +2675,7 @@
return BT_STATUS_NOT_READY;
}
- return do_in_jni_thread(
+ return do_in_bta_thread(
FROM_HERE, base::Bind(&BtifAvSource::UpdateCodecConfig,
base::Unretained(&btif_av_source), peer_address,
codec_preferences));
@@ -2676,13 +2683,13 @@
static void cleanup_src(void) {
BTIF_TRACE_EVENT("%s", __func__);
- do_in_jni_thread(FROM_HERE, base::Bind(&BtifAvSource::Cleanup,
+ do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSource::Cleanup,
base::Unretained(&btif_av_source)));
}
static void cleanup_sink(void) {
BTIF_TRACE_EVENT("%s", __func__);
- do_in_jni_thread(FROM_HERE, base::Bind(&BtifAvSink::Cleanup,
+ do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSink::Cleanup,
base::Unretained(&btif_av_sink)));
}
@@ -2800,7 +2807,7 @@
peer_address.ToString().c_str(),
btif_av_event.ToString().c_str());
- do_in_jni_thread(FROM_HERE,
+ do_in_bta_thread(FROM_HERE,
base::Bind(&btif_av_handle_event,
AVDT_TSEP_SNK, // peer_sep
peer_address, kBtaHandleUnknown, btif_av_event));
@@ -2813,7 +2820,7 @@
peer_address.ToString().c_str(),
btif_av_event.ToString().c_str());
- do_in_jni_thread(FROM_HERE,
+ do_in_bta_thread(FROM_HERE,
base::Bind(&btif_av_handle_event,
AVDT_TSEP_SRC, // peer_sep
peer_address, kBtaHandleUnknown, btif_av_event));
diff --git a/btif/src/btif_core.cc b/btif/src/btif_core.cc
index 975fb26..c2b662a 100644
--- a/btif/src/btif_core.cc
+++ b/btif/src/btif_core.cc
@@ -618,7 +618,8 @@
****************************************************************************/
static bt_status_t btif_in_get_adapter_properties(void) {
- bt_property_t properties[6];
+ const static uint32_t NUM_ADAPTER_PROPERTIES = 8;
+ bt_property_t properties[NUM_ADAPTER_PROPERTIES];
uint32_t num_props = 0;
RawAddress addr;
@@ -628,6 +629,8 @@
RawAddress bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
Uuid local_uuids[BT_MAX_NUM_UUIDS];
bt_status_t status;
+ bt_io_cap_t local_bt_io_cap;
+ bt_io_cap_t local_bt_io_cap_ble;
/* RawAddress */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
@@ -672,6 +675,18 @@
btif_storage_get_adapter_property(&properties[num_props]);
num_props++;
+ /* LOCAL IO Capabilities */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_LOCAL_IO_CAPS,
+ sizeof(bt_io_cap_t), &local_bt_io_cap);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+ BT_PROPERTY_LOCAL_IO_CAPS_BLE, sizeof(bt_io_cap_t),
+ &local_bt_io_cap_ble);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, num_props,
properties);
@@ -1022,6 +1037,13 @@
* BTA events */
status = BT_STATUS_FAIL;
break;
+ case BT_PROPERTY_LOCAL_IO_CAPS:
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE: {
+ // Changing IO Capability of stack at run-time is not currently supported.
+ // This call changes the stored value which will affect the stack next
+ // time it starts up.
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ } break;
default:
BTIF_TRACE_ERROR("btif_get_adapter_property : invalid type %d",
property->type);
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index fc6746a..66268ca 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -43,6 +43,7 @@
#include <bluetooth/uuid.h>
#include <hardware/bluetooth.h>
+#include <hardware/bt_hearing_aid.h>
#include "advertise_data_parser.h"
#include "bt_common.h"
@@ -244,6 +245,8 @@
extern bt_status_t btif_sdp_execute_service(bool b_enable);
extern int btif_hh_connect(const RawAddress* bd_addr);
extern bt_status_t btif_hd_execute_service(bool b_enable);
+extern bluetooth::hearing_aid::HearingAidInterface*
+btif_hearing_aid_get_interface();
/******************************************************************************
* Functions
@@ -1648,6 +1651,7 @@
#if (defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE))
btif_hd_remove_device(bd_addr);
#endif
+ btif_hearing_aid_get_interface()->RemoveDevice(bd_addr);
btif_storage_remove_bonded_device(&bd_addr);
bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_NONE);
break;
@@ -2435,6 +2439,20 @@
prop->len = sizeof(DEV_CLASS);
} break;
+ // While fetching IO_CAP* values for the local device, we maintain backward
+ // compatibility by using the value from #define macros BTM_LOCAL_IO_CAPS,
+ // BTM_LOCAL_IO_CAPS_BLE if the values have never been explicitly set.
+
+ case BT_PROPERTY_LOCAL_IO_CAPS: {
+ *(bt_io_cap_t*)prop->val = (bt_io_cap_t)BTM_LOCAL_IO_CAPS;
+ prop->len = sizeof(bt_io_cap_t);
+ } break;
+
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE: {
+ *(bt_io_cap_t*)prop->val = (bt_io_cap_t)BTM_LOCAL_IO_CAPS_BLE;
+ prop->len = sizeof(bt_io_cap_t);
+ } break;
+
default:
prop->len = 0;
return BT_STATUS_FAIL;
diff --git a/btif/src/btif_hearing_aid.cc b/btif/src/btif_hearing_aid.cc
index 961a542..48aab95 100644
--- a/btif/src/btif_hearing_aid.cc
+++ b/btif/src/btif_hearing_aid.cc
@@ -91,8 +91,8 @@
DVLOG(2) << __func__ << " address: " << address;
do_in_bta_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
Unretained(HearingAid::Get()), address));
- do_in_jni_thread(FROM_HERE,
- Bind(&btif_storage_remove_hearing_aid, address));
+ do_in_jni_thread(
+ FROM_HERE, Bind(&btif_storage_remove_hearing_aid_white_list, address));
}
void SetVolume(int8_t volume) override {
@@ -101,6 +101,19 @@
Unretained(HearingAid::Get()), volume));
}
+ void RemoveDevice(const RawAddress& address) override {
+ DVLOG(2) << __func__ << " address: " << address;
+
+ // RemoveDevice can be called on devices that don't have HA enabled
+ if (HearingAid::IsInitialized()) {
+ do_in_bta_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
+ Unretained(HearingAid::Get()), address));
+ }
+
+ do_in_jni_thread(FROM_HERE,
+ Bind(&btif_storage_remove_hearing_aid, address));
+ }
+
void Cleanup(void) {
DVLOG(2) << __func__;
do_in_bta_thread(FROM_HERE, Bind(&HearingAid::CleanUp));
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index 5573160..a3306ec 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -31,6 +31,7 @@
#include <cstring>
#include <ctime>
+#include <bta/include/bta_ag_api.h>
#include <hardware/bluetooth.h>
#include <hardware/bluetooth_headset_callbacks.h>
#include <hardware/bluetooth_headset_interface.h>
@@ -327,11 +328,11 @@
<< unsigned(p_data->open.status);
btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
} else {
- BTIF_TRACE_WARNING(
- "%s: AG open failed, but another device connected. status=%d "
- "state=%d connected device=%s",
- __func__, p_data->open.status, btif_hf_cb[idx].state,
- btif_hf_cb[idx].connected_bda.ToString().c_str());
+ LOG(WARNING) << __func__ << ": AG open failed for "
+ << p_data->open.bd_addr << ", error "
+ << std::to_string(p_data->open.status)
+ << ", local device is " << btif_hf_cb[idx].connected_bda
+ << ". Ignoring as not expecting to open";
break;
}
bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state,
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index ceb2366..c5a9021 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -544,8 +544,13 @@
BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
return BT_STATUS_SUCCESS;
} else {
- BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__,
- bd_addr->ToString().c_str());
+ BTIF_TRACE_ERROR("%s: Error, device %s not opened, status = %d", __func__,
+ bd_addr->ToString().c_str(), btif_hh_cb.status);
+ if ((btif_hh_cb.pending_conn_address == *bd_addr) &&
+ (btif_hh_cb.status == BTIF_HH_DEV_CONNECTING)) {
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+ btif_hh_cb.pending_conn_address = RawAddress::kEmpty;
+ }
return BT_STATUS_FAIL;
}
}
@@ -600,6 +605,7 @@
pagescan mode, we will do 2 retries to connect before giving up */
tBTA_SEC sec_mask = BTUI_HH_SECURITY;
btif_hh_cb.status = BTIF_HH_DEV_CONNECTING;
+ btif_hh_cb.pending_conn_address = *bd_addr;
BTA_HhOpen(*bd_addr, BTA_HH_PROTO_RPT_MODE, sec_mask);
// TODO(jpawlowski); make cback accept const and remove tmp!
@@ -747,6 +753,7 @@
case BTA_HH_OPEN_EVT:
BTIF_TRACE_WARNING("%s: BTA_HH_OPN_EVT: handle=%d, status =%d", __func__,
p_data->conn.handle, p_data->conn.status);
+ btif_hh_cb.pending_conn_address = RawAddress::kEmpty;
if (p_data->conn.status == BTA_HH_OK) {
p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
if (p_dev == NULL) {
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 861b1c2..d3fb5f0 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -3894,6 +3894,10 @@
switch (avrc_item->item_type) {
case AVRC_ITEM_MEDIA:
BTIF_TRACE_DEBUG("%s setting type to %d", __func__, BTRC_ITEM_MEDIA);
+ /* Allocate Space for Attributes */
+ btrc_item->media.num_attrs = avrc_item->u.media.attr_count;
+ btrc_item->media.p_attrs = (btrc_element_attr_val_t*)osi_malloc(
+ btrc_item->media.num_attrs * sizeof(btrc_element_attr_val_t));
get_folder_item_type_media(avrc_item, btrc_item);
break;
@@ -3919,7 +3923,22 @@
(const btrc_folder_items_t*)btrc_items, item_count);
BTIF_TRACE_DEBUG("%s HAL CBACK get_folder_items_cb finished", __func__);
- /* Release the memory block for items since we OWN the object */
+ /* Release the memory block for items and attributes allocated here */
+ for (uint8_t i = 0; i < item_count; i++) {
+ btrc_folder_items_t* btrc_item = &(btrc_items[i]);
+ switch (btrc_item->item_type) {
+ case BTRC_ITEM_MEDIA:
+ osi_free(btrc_item->media.p_attrs);
+ break;
+ case BTRC_ITEM_PLAYER:
+ case BTRC_ITEM_FOLDER:
+ /*Nothing to free*/
+ break;
+ default:
+ BTIF_TRACE_WARNING("%s free unspecified type", __func__);
+ }
+ }
+
osi_free(btrc_items);
} else {
BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status);
@@ -3967,11 +3986,6 @@
memcpy(btrc_item_media->name, avrc_item_media->name.p_str,
sizeof(uint8_t) * (avrc_item_media->name.str_len));
- /* Copy the parameters */
- btrc_item_media->num_attrs = avrc_item_media->attr_count;
- btrc_item_media->p_attrs = (btrc_element_attr_val_t*)osi_malloc(
- btrc_item_media->num_attrs * sizeof(btrc_element_attr_val_t));
-
/* Extract each attribute */
for (int i = 0; i < avrc_item_media->attr_count; i++) {
btrc_element_attr_val_t* btrc_attr_pair = &(btrc_item_media->p_attrs[i]);
@@ -4092,6 +4106,8 @@
btrc_item_player->major_type = avrc_item_player->major_type;
/* Sub type */
btrc_item_player->sub_type = avrc_item_player->sub_type;
+ /* Play status */
+ btrc_item_player->play_status = avrc_item_player->play_status;
/* Features */
memcpy(btrc_item_player->features, avrc_item_player->features,
BTRC_FEATURE_BIT_MASK_SIZE);
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index e402812..766dc7f 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -82,6 +82,8 @@
#define BTIF_STORAGE_PATH_REMOTE_HIDINFO "HidInfo"
#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name"
#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
+#define BTIF_STORAGE_KEY_LOCAL_IO_CAPS "LocalIOCaps"
+#define BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE "LocalIOCapsBLE"
#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
/* This is a local property to add a device found */
@@ -222,6 +224,14 @@
btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
*(int*)prop->val);
break;
+ case BT_PROPERTY_LOCAL_IO_CAPS:
+ btif_config_set_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS,
+ *(int*)prop->val);
+ break;
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE:
+ btif_config_set_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE,
+ *(int*)prop->val);
+ break;
case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT,
*(int*)prop->val);
@@ -323,6 +333,18 @@
ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
(int*)prop->val);
break;
+
+ case BT_PROPERTY_LOCAL_IO_CAPS:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS,
+ (int*)prop->val);
+ break;
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE,
+ (int*)prop->val);
+ break;
+
case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
if (prop->len >= (int)sizeof(int))
ret = btif_config_get_int(
@@ -542,6 +564,57 @@
return num_uuids;
}
+/**
+ * Helper function for fetching a local Input/Output capability property. If not
+ * set, it returns the default value.
+ */
+static uint8_t btif_storage_get_io_cap_property(bt_property_type_t type,
+ uint8_t default_value) {
+ char buf[sizeof(int)];
+
+ bt_property_t property;
+ property.type = type;
+ property.val = (void*)buf;
+ property.len = sizeof(int);
+
+ bt_status_t ret = btif_storage_get_adapter_property(&property);
+
+ return (ret == BT_STATUS_SUCCESS) ? (uint8_t)(*(int*)property.val)
+ : default_value;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_io_caps
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the device.
+ *
+ * Returns Returns local IO Capability of device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps() {
+ return btif_storage_get_io_cap_property(BT_PROPERTY_LOCAL_IO_CAPS,
+ BTM_LOCAL_IO_CAPS);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_io_caps_ble
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the BLE device.
+ *
+ * Returns Returns local IO Capability of BLE device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS_BLE.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps_ble() {
+ return btif_storage_get_io_cap_property(BT_PROPERTY_LOCAL_IO_CAPS_BLE,
+ BTM_LOCAL_IO_CAPS_BLE);
+}
+
/*******************************************************************************
*
* Function btif_storage_get_adapter_property
@@ -1364,6 +1437,7 @@
constexpr char HEARING_AID_SYNC_ID[] = "HearingAidSyncId";
constexpr char HEARING_AID_RENDER_DELAY[] = "HearingAidRenderDelay";
constexpr char HEARING_AID_PREPARATION_DELAY[] = "HearingAidPreparationDelay";
+constexpr char HEARING_AID_IS_WHITE_LISTED[] = "HearingAidIsWhiteListed";
void btif_storage_add_hearing_aid(const RawAddress& address, uint16_t psm,
uint8_t capabilities, uint16_t codecs,
@@ -1391,6 +1465,7 @@
btif_config_set_int(bdstr, HEARING_AID_RENDER_DELAY, render_delay);
btif_config_set_int(bdstr, HEARING_AID_PREPARATION_DELAY,
preparation_delay);
+ btif_config_set_int(bdstr, HEARING_AID_IS_WHITE_LISTED, true);
btif_config_save();
},
address, psm, capabilities, codecs, audio_control_point_handle,
@@ -1446,13 +1521,18 @@
if (btif_config_get_int(name, HEARING_AID_PREPARATION_DELAY, &value))
preparation_delay = value;
+ uint16_t is_white_listed = 0;
+ if (btif_config_get_int(name, HEARING_AID_IS_WHITE_LISTED, &value))
+ is_white_listed = value;
+
RawAddress bd_addr;
RawAddress::FromString(name, bd_addr);
// add extracted information to BTA Hearing Aid
do_in_bta_thread(
- FROM_HERE, Bind(&HearingAid::AddFromStorage, bd_addr, psm, capabilities,
- codecs, audio_control_point_handle, volume_handle,
- hi_sync_id, render_delay, preparation_delay));
+ FROM_HERE,
+ Bind(&HearingAid::AddFromStorage, bd_addr, psm, capabilities, codecs,
+ audio_control_point_handle, volume_handle, hi_sync_id,
+ render_delay, preparation_delay, is_white_listed));
}
}
@@ -1466,9 +1546,17 @@
btif_config_remove(addrstr, HEARING_AID_AUDIO_CONTROL_POINT);
btif_config_remove(addrstr, HEARING_AID_VOLUME_HANDLE);
btif_config_remove(addrstr, HEARING_AID_SYNC_ID);
+ btif_config_remove(addrstr, HEARING_AID_IS_WHITE_LISTED);
btif_config_save();
}
+/** Remove the hearing aid device from white list */
+void btif_storage_remove_hearing_aid_white_list(const RawAddress& address) {
+ std::string addrstr = address.ToString();
+
+ btif_config_set_int(addrstr, HEARING_AID_IS_WHITE_LISTED, false);
+}
+
/*******************************************************************************
*
* Function btif_storage_is_restricted_device
diff --git a/include/hardware/avrcp/avrcp.h b/include/hardware/avrcp/avrcp.h
index dbd0ad9..8adba47 100644
--- a/include/hardware/avrcp/avrcp.h
+++ b/include/hardware/avrcp/avrcp.h
@@ -101,7 +101,7 @@
// behavior in case the threading model changes on either side.
class MediaInterface {
public:
- virtual void SendKeyEvent(uint8_t key, uint8_t status) = 0;
+ virtual void SendKeyEvent(uint8_t key, KeyState state) = 0;
using SongInfoCallback = base::Callback<void(SongInfo)>;
virtual void GetSongInfo(SongInfoCallback info_cb) = 0;
diff --git a/include/hardware/avrcp/avrcp_common.h b/include/hardware/avrcp/avrcp_common.h
index c805aa5..685eb1a 100644
--- a/include/hardware/avrcp/avrcp_common.h
+++ b/include/hardware/avrcp/avrcp_common.h
@@ -137,6 +137,11 @@
DOWN = 0x01,
};
+enum class KeyState : uint8_t {
+ PUSHED = 0x00,
+ RELEASED = 0x01,
+};
+
class AttributeEntry {
public:
AttributeEntry(const Attribute& attribute, const std::string& value)
diff --git a/include/hardware/avrcp/avrcp_logging_helper.h b/include/hardware/avrcp/avrcp_logging_helper.h
index ce4951b..ce95337 100644
--- a/include/hardware/avrcp/avrcp_logging_helper.h
+++ b/include/hardware/avrcp/avrcp_logging_helper.h
@@ -226,5 +226,18 @@
return os << DirectionText(dir);
}
+inline std::string KeyStateText(const KeyState& state) {
+ switch (state) {
+ CASE_RETURN_TEXT(KeyState::PUSHED);
+ CASE_RETURN_TEXT(KeyState::RELEASED);
+ default:
+ return "Unknown KeyState: " + loghex((uint8_t)state);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const KeyState& dir) {
+ return os << KeyStateText(dir);
+}
+
} // namespace avrcp
} // namespace bluetooth
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index 36680bf..79ad88b 100644
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -66,6 +66,18 @@
/** Bluetooth Adapter State */
typedef enum { BT_STATE_OFF, BT_STATE_ON } bt_state_t;
+/** Bluetooth Adapter Input Output Capabilities which determine Pairing/Security
+ */
+typedef enum {
+ BT_IO_CAP_OUT, /* DisplayOnly */
+ BT_IO_CAP_IO, /* DisplayYesNo */
+ BT_IO_CAP_IN, /* KeyboardOnly */
+ BT_IO_CAP_NONE, /* NoInputNoOutput */
+ BT_IO_CAP_KBDISP, /* Keyboard display */
+ BT_IO_CAP_MAX,
+ BT_IO_CAP_UNKNOWN = 0xFF /* Unknown value */
+} bt_io_cap_t;
+
/** Bluetooth Error Status */
/** We need to build on this */
@@ -240,6 +252,20 @@
*/
BT_PROPERTY_LOCAL_LE_FEATURES,
+ /**
+ * Description - Local Input/Output Capabilities for classic Bluetooth
+ * Access mode - GET and SET
+ * Data Type - bt_io_cap_t.
+ */
+ BT_PROPERTY_LOCAL_IO_CAPS,
+
+ /**
+ * Description - Local Input/Output Capabilities for BLE
+ * Access mode - GET and SET
+ * Data Type - bt_io_cap_t.
+ */
+ BT_PROPERTY_LOCAL_IO_CAPS_BLE,
+
BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
} bt_property_type_t;
diff --git a/include/hardware/bt_hearing_aid.h b/include/hardware/bt_hearing_aid.h
index 3b53d37..a54f82a 100644
--- a/include/hardware/bt_hearing_aid.h
+++ b/include/hardware/bt_hearing_aid.h
@@ -64,6 +64,9 @@
/** Closes the interface. */
virtual void Cleanup(void) = 0;
+
+ /* Called when Hearing Aid is unbonded. */
+ virtual void RemoveDevice(const RawAddress& address) = 0;
};
} // namespace hearing_aid
diff --git a/internal_include/bt_trace.h b/internal_include/bt_trace.h
index 9ab9eb0..a8c4088 100644
--- a/internal_include/bt_trace.h
+++ b/internal_include/bt_trace.h
@@ -741,6 +741,18 @@
}
/**
+ * Obtains the string representation of a boolean value.
+ *
+ * @param value the boolean value to use
+ * @return the string representation of the boolean value: "true" or "false"
+ */
+inline std::string logbool(bool value) {
+ std::stringstream tmp;
+ tmp << std::boolalpha << value;
+ return tmp.str();
+}
+
+/**
* Append a field name to a string.
*
* The field names are added to the string with "|" in between.
@@ -759,4 +771,53 @@
return *p_result;
}
+// This object puts the stream in a state where every time that a new line
+// occurs, the next line is indented a certain number of spaces. The stream is
+// reset to its previous state when the object is destroyed.
+class ScopedIndent {
+ public:
+ ScopedIndent(std::ostream& stream, int indent_size = DEFAULT_TAB)
+ : indented_buf_(stream, indent_size) {
+ old_stream_ = &stream;
+ old_stream_buf_ = stream.rdbuf();
+ stream.rdbuf(&indented_buf_);
+ }
+
+ ~ScopedIndent() { old_stream_->rdbuf(old_stream_buf_); }
+
+ static const size_t DEFAULT_TAB = 2;
+
+ private:
+ class IndentedStreamBuf : public std::streambuf {
+ public:
+ IndentedStreamBuf(std::ostream& stream, int indent_size)
+ : wrapped_buf_(stream.rdbuf()),
+ indent_size_(indent_size),
+ indent_next_line_(true){};
+
+ protected:
+ virtual int overflow(int character) override {
+ if (indent_next_line_ && character != '\n') {
+ for (int i = 0; i < indent_size_; i++) wrapped_buf_->sputc(' ');
+ }
+
+ indent_next_line_ = false;
+ if (character == '\n') {
+ indent_next_line_ = true;
+ }
+
+ return wrapped_buf_->sputc(character);
+ }
+
+ private:
+ std::streambuf* wrapped_buf_;
+ int indent_size_;
+ bool indent_next_line_;
+ };
+
+ std::ostream* old_stream_;
+ std::streambuf* old_stream_buf_;
+ IndentedStreamBuf indented_buf_;
+};
+
#endif
diff --git a/packet/avrcp/pass_through_packet.cc b/packet/avrcp/pass_through_packet.cc
index a384cc0..67b8d16 100644
--- a/packet/avrcp/pass_through_packet.cc
+++ b/packet/avrcp/pass_through_packet.cc
@@ -46,8 +46,9 @@
return true;
}
-bool PassThroughPacket::GetPushed() const {
- return (*(begin() + Packet::kMinSize()) & 0b10000000) == 0;
+KeyState PassThroughPacket::GetKeyState() const {
+ auto it = begin() + Packet::kMinSize();
+ return static_cast<KeyState>(((*it) & 0b10000000) >> 7);
}
uint8_t PassThroughPacket::GetOperationId() const {
@@ -63,7 +64,7 @@
ss << " â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
ss << " â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
ss << " â”” OpCode = " << GetOpcode() << std::endl;
- ss << " â”” Pushed = " << GetPushed() << std::endl;
+ ss << " â”” Pushed = " << GetKeyState() << std::endl;
ss << " â”” Opperation ID = " << loghex(GetOperationId()) << std::endl;
return ss.str();
diff --git a/packet/avrcp/pass_through_packet.h b/packet/avrcp/pass_through_packet.h
index f2cf1d7..903b3d8 100644
--- a/packet/avrcp/pass_through_packet.h
+++ b/packet/avrcp/pass_through_packet.h
@@ -62,7 +62,7 @@
static constexpr size_t kMinSize() { return Packet::kMinSize() + 2; }
// Getter Functions
- bool GetPushed() const;
+ KeyState GetKeyState() const;
uint8_t GetOperationId() const;
// Overloaded Functions
diff --git a/packet/tests/avrcp/avrcp_test_packets.h b/packet/tests/avrcp/avrcp_test_packets.h
index f5c914e..3160ad5 100644
--- a/packet/tests/avrcp/avrcp_test_packets.h
+++ b/packet/tests/avrcp/avrcp_test_packets.h
@@ -291,9 +291,17 @@
0x70, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x6a, 0x00};
+// AVRCP Get Total Number of Items Request with Scope = Media Player List
+std::vector<uint8_t> get_total_number_of_items_request_media_players = {
+ 0x75, 0x00, 0x01, 0x00};
+
+// AVRCP Get Total Number of Items Request with Scope = VFS
+std::vector<uint8_t> get_total_number_of_items_request_vfs = {0x75, 0x00, 0x01,
+ 0x01};
+
// AVRCP Get Total Number of Items Request with Scope = Now Playing List
-std::vector<uint8_t> get_total_number_of_items_request = {0x75, 0x00, 0x01,
- 0x03};
+std::vector<uint8_t> get_total_number_of_items_request_now_playing = {
+ 0x75, 0x00, 0x01, 0x03};
// AVRCP Get Total number of Items Response with 5 items in folder
std::vector<uint8_t> get_total_number_of_items_response = {
diff --git a/packet/tests/avrcp/get_total_number_of_items_packet_test.cc b/packet/tests/avrcp/get_total_number_of_items_packet_test.cc
index cffc2a8..eb7efc2 100644
--- a/packet/tests/avrcp/get_total_number_of_items_packet_test.cc
+++ b/packet/tests/avrcp/get_total_number_of_items_packet_test.cc
@@ -48,19 +48,19 @@
}
TEST(GetTotalNumberOfItemsRequestTest, getterTest) {
- auto test_packet =
- TestGetTotalNumItemsReqPacket::Make(get_total_number_of_items_request);
+ auto test_packet = TestGetTotalNumItemsReqPacket::Make(
+ get_total_number_of_items_request_now_playing);
ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
}
TEST(GetTotalNumberOfItemsRequestTest, validTest) {
- auto test_packet =
- TestGetTotalNumItemsReqPacket::Make(get_total_number_of_items_request);
+ auto test_packet = TestGetTotalNumItemsReqPacket::Make(
+ get_total_number_of_items_request_now_playing);
ASSERT_TRUE(test_packet->IsValid());
}
TEST(GetTotalNumberOfItemsRequestTest, invalidTest) {
- auto packet_copy = get_total_number_of_items_request;
+ auto packet_copy = get_total_number_of_items_request_now_playing;
packet_copy.push_back(0x00);
auto test_packet = TestGetTotalNumItemsReqPacket::Make(packet_copy);
ASSERT_FALSE(test_packet->IsValid());
diff --git a/packet/tests/avrcp/pass_through_packet_test.cc b/packet/tests/avrcp/pass_through_packet_test.cc
index 0ef2879..5ea749f 100644
--- a/packet/tests/avrcp/pass_through_packet_test.cc
+++ b/packet/tests/avrcp/pass_through_packet_test.cc
@@ -42,11 +42,11 @@
TEST(PassThroughPacketTest, getterTest) {
auto test_packet =
TestPassThroughPacket::Make(pass_through_command_play_pushed);
- ASSERT_TRUE(test_packet->GetPushed());
+ ASSERT_EQ(test_packet->GetKeyState(), KeyState::PUSHED);
ASSERT_EQ(test_packet->GetOperationId(), 0x44);
test_packet = TestPassThroughPacket::Make(pass_through_command_play_released);
- ASSERT_FALSE(test_packet->GetPushed());
+ ASSERT_EQ(test_packet->GetKeyState(), KeyState::RELEASED);
ASSERT_EQ(test_packet->GetOperationId(), 0x44);
}
diff --git a/profile/avrcp/connection_handler.cc b/profile/avrcp/connection_handler.cc
index 78a8abf..9ba8384 100644
--- a/profile/avrcp/connection_handler.cc
+++ b/profile/avrcp/connection_handler.cc
@@ -76,6 +76,8 @@
instance_->device_map_.clear();
instance_->feature_map_.clear();
+ instance_->weak_ptr_factory_.InvalidateWeakPtrs();
+
delete instance_;
instance_ = nullptr;
@@ -158,8 +160,9 @@
return avrc_->FindService(
UUID_SERVCLASS_AV_REMOTE_CONTROL, bdaddr, &db_params,
- base::Bind(&ConnectionHandler::SdpCb, base::Unretained(this),
- bdaddr, cb, disc_db)) == AVRC_SUCCESS;
+ base::Bind(&ConnectionHandler::SdpCb,
+ weak_ptr_factory_.GetWeakPtr(), bdaddr, cb, disc_db)) ==
+ AVRC_SUCCESS;
}
bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) {
@@ -168,13 +171,13 @@
tAVRC_CONN_CB open_cb;
if (initiator) {
open_cb.ctrl_cback = base::Bind(&ConnectionHandler::InitiatorControlCb,
- base::Unretained(this));
+ weak_ptr_factory_.GetWeakPtr());
} else {
open_cb.ctrl_cback = base::Bind(&ConnectionHandler::AcceptorControlCb,
- base::Unretained(this));
+ weak_ptr_factory_.GetWeakPtr());
}
open_cb.msg_cback =
- base::Bind(&ConnectionHandler::MessageCb, base::Unretained(this));
+ base::Bind(&ConnectionHandler::MessageCb, weak_ptr_factory_.GetWeakPtr());
open_cb.company_id = AVRC_CO_GOOGLE;
open_cb.conn = initiator ? AVRC_CONN_INT
: AVRC_CONN_ACP; // 0 if initiator, 1 if acceptor
@@ -284,7 +287,7 @@
LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
- base::Unretained(this), handle);
+ weak_ptr_factory_.GetWeakPtr(), handle);
auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN;
auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
std::shared_ptr<Device> newDevice = std::make_shared<Device>(
diff --git a/profile/avrcp/connection_handler.h b/profile/avrcp/connection_handler.h
index 4db38b7..63bc8a0 100644
--- a/profile/avrcp/connection_handler.h
+++ b/profile/avrcp/connection_handler.h
@@ -17,6 +17,7 @@
#pragma once
#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
#include <map>
#include <memory>
@@ -148,14 +149,16 @@
void MessageCb(uint8_t handle, uint8_t label, uint8_t opcode,
tAVRC_MSG* p_msg);
- ConnectionHandler() = default;
+ ConnectionHandler() : weak_ptr_factory_(this){};
virtual ~ConnectionHandler() = default;
// Callback for when sending a response to a device
void SendMessage(uint8_t handle, uint8_t label, bool browse,
std::unique_ptr<::bluetooth::PacketBuilder> message);
+
+ base::WeakPtrFactory<ConnectionHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ConnectionHandler);
};
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index e66caa7..b8afe9d 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -34,7 +34,8 @@
std::unique_ptr<::bluetooth::PacketBuilder> message)>
send_msg_cb,
uint16_t ctrl_mtu, uint16_t browse_mtu)
- : address_(bdaddr),
+ : weak_ptr_factory_(this),
+ address_(bdaddr),
avrcp13_compatibility_(avrcp13_compatibility),
send_message_cb_(send_msg_cb),
ctrl_mtu_(ctrl_mtu),
@@ -123,13 +124,14 @@
case CommandPdu::GET_ELEMENT_ATTRIBUTES: {
media_interface_->GetSongInfo(base::Bind(
- &Device::GetElementAttributesResponse, base::Unretained(this), label,
- Packet::Specialize<GetElementAttributesRequest>(pkt)));
+ &Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(),
+ label, Packet::Specialize<GetElementAttributesRequest>(pkt)));
} break;
case CommandPdu::GET_PLAY_STATUS: {
- media_interface_->GetPlayStatus(base::Bind(
- &Device::GetPlayStatusResponse, base::Unretained(this), label));
+ media_interface_->GetPlayStatus(base::Bind(&Device::GetPlayStatusResponse,
+ weak_ptr_factory_.GetWeakPtr(),
+ label));
} break;
case CommandPdu::PLAY_ITEM: {
@@ -164,14 +166,14 @@
track_changed_ = Notification(true, label);
media_interface_->GetNowPlayingList(
base::Bind(&Device::TrackChangedNotificationResponse,
- base::Unretained(this), label, true));
+ weak_ptr_factory_.GetWeakPtr(), label, true));
} break;
case Event::PLAYBACK_STATUS_CHANGED: {
play_status_changed_ = Notification(true, label);
media_interface_->GetPlayStatus(
base::Bind(&Device::PlaybackStatusNotificationResponse,
- base::Unretained(this), label, true));
+ weak_ptr_factory_.GetWeakPtr(), label, true));
} break;
case Event::PLAYBACK_POS_CHANGED: {
@@ -179,14 +181,14 @@
play_pos_interval_ = pkt->GetInterval();
media_interface_->GetPlayStatus(
base::Bind(&Device::PlaybackPosNotificationResponse,
- base::Unretained(this), label, true));
+ weak_ptr_factory_.GetWeakPtr(), label, true));
} break;
case Event::NOW_PLAYING_CONTENT_CHANGED: {
now_playing_changed_ = Notification(true, label);
media_interface_->GetNowPlayingList(base::Bind(
- &Device::HandleNowPlayingNotificationResponse, base::Unretained(this),
- now_playing_changed_.second, true));
+ &Device::HandleNowPlayingNotificationResponse,
+ weak_ptr_factory_.GetWeakPtr(), now_playing_changed_.second, true));
} break;
case Event::AVAILABLE_PLAYERS_CHANGED: {
@@ -202,7 +204,7 @@
addr_player_changed_ = Notification(true, label);
media_interface_->GetMediaPlayerList(
base::Bind(&Device::AddressedPlayerNotificationResponse,
- base::Unretained(this), label, false));
+ weak_ptr_factory_.GetWeakPtr(), label, false));
} break;
case Event::UIDS_CHANGED: {
@@ -275,13 +277,20 @@
if (volume_ == VOL_NOT_SUPPORTED) {
volume_ = pkt->GetVolume();
volume_interface_->DeviceConnected(
- GetAddress(), base::Bind(&Device::SetVolume, base::Unretained(this)));
+ GetAddress(),
+ base::Bind(&Device::SetVolume, weak_ptr_factory_.GetWeakPtr()));
// Ignore the returned volume in favor of the volume returned
// by the volume interface.
return;
}
+ if (!IsActive()) {
+ DEVICE_VLOG(3) << __func__
+ << ": Ignoring volume changes from non active device";
+ return;
+ }
+
volume_ = pkt->GetVolume();
DEVICE_VLOG(1) << __func__ << ": Volume has changed to " << (uint32_t)volume_;
volume_interface_->SetVolume(volume_);
@@ -401,8 +410,8 @@
// the status bar on the remote device move.
if (status.state == PlayState::PLAYING) {
DEVICE_VLOG(0) << __func__ << ": Queue next play position update";
- play_pos_update_cb_.Reset(
- base::Bind(&Device::HandlePlayPosUpdate, base::Unretained(this)));
+ play_pos_update_cb_.Reset(base::Bind(&Device::HandlePlayPosUpdate,
+ weak_ptr_factory_.GetWeakPtr()));
base::MessageLoop::current()->task_runner()->PostDelayedTask(
FROM_HERE, play_pos_update_cb_.callback(),
base::TimeDelta::FromSeconds(play_pos_interval_));
@@ -485,19 +494,20 @@
case Opcode::PASS_THROUGH: {
auto pass_through_packet = Packet::Specialize<PassThroughPacket>(pkt);
auto response = PassThroughPacketBuilder::MakeBuilder(
- true, pass_through_packet->GetPushed(),
+ true, pass_through_packet->GetKeyState() == KeyState::PUSHED,
pass_through_packet->GetOperationId());
send_message(label, false, std::move(response));
- // TODO (apanicke): Use an enum for media key ID's also handle
- // other keys like forward and back for device switching.
+ // TODO (apanicke): Use an enum for media key ID's
if (pass_through_packet->GetOperationId() == 0x44 &&
- !pass_through_packet->GetPushed()) {
+ pass_through_packet->GetKeyState() == KeyState::PUSHED) {
// We need to get the play status since we need to know
// what the actual playstate is without being modified
// by whether the device is active.
media_interface_->GetPlayStatus(base::Bind(
- [](Device* d, PlayStatus s) {
+ [](base::WeakPtr<Device> d, PlayStatus s) {
+ if (!d) return;
+
if (!d->IsActive()) {
LOG(INFO) << "Setting " << d->address_.ToString()
<< " to be the active device";
@@ -510,14 +520,16 @@
}
}
- d->media_interface_->SendKeyEvent(0x44, 0);
+ d->media_interface_->SendKeyEvent(0x44, KeyState::PUSHED);
},
- base::Unretained(this)));
+ weak_ptr_factory_.GetWeakPtr()));
return;
}
- media_interface_->SendKeyEvent(pass_through_packet->GetOperationId(),
- pass_through_packet->GetPushed() ? 0 : 1);
+ if (IsActive()) {
+ media_interface_->SendKeyEvent(pass_through_packet->GetOperationId(),
+ pass_through_packet->GetKeyState());
+ }
} break;
case Opcode::VENDOR: {
auto vendor_pkt = Packet::Specialize<VendorPacket>(pkt);
@@ -578,8 +590,12 @@
HandleGetItemAttributes(
label, Packet::Specialize<GetItemAttributesRequest>(pkt));
break;
+ case BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS:
+ HandleGetTotalNumberOfItems(
+ label, Packet::Specialize<GetTotalNumberOfItemsRequest>(pkt));
+ break;
default:
- DEVICE_LOG(WARNING) << __func__ << ": " << pkt->GetPdu();
+ DEVICE_LOG(FATAL) << __func__ << ": " << pkt->GetPdu();
break;
}
}
@@ -592,18 +608,18 @@
case Scope::MEDIA_PLAYER_LIST:
media_interface_->GetMediaPlayerList(
base::Bind(&Device::GetMediaPlayerListResponse,
- base::Unretained(this), label, pkt));
+ weak_ptr_factory_.GetWeakPtr(), label, pkt));
break;
case Scope::VFS:
media_interface_->GetFolderItems(
curr_browsed_player_id_, CurrentFolder(),
- base::Bind(&Device::GetVFSListResponse, base::Unretained(this), label,
- pkt));
+ base::Bind(&Device::GetVFSListResponse,
+ weak_ptr_factory_.GetWeakPtr(), label, pkt));
break;
case Scope::NOW_PLAYING:
media_interface_->GetNowPlayingList(
- base::Bind(&Device::GetNowPlayingListResponse, base::Unretained(this),
- label, pkt));
+ base::Bind(&Device::GetNowPlayingListResponse,
+ weak_ptr_factory_.GetWeakPtr(), label, pkt));
break;
default:
DEVICE_LOG(ERROR) << __func__ << ": " << pkt->GetScope();
@@ -611,6 +627,61 @@
}
}
+void Device::HandleGetTotalNumberOfItems(
+ uint8_t label, std::shared_ptr<GetTotalNumberOfItemsRequest> pkt) {
+ DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope();
+
+ switch (pkt->GetScope()) {
+ case Scope::MEDIA_PLAYER_LIST: {
+ media_interface_->GetMediaPlayerList(
+ base::Bind(&Device::GetTotalNumberOfItemsMediaPlayersResponse,
+ weak_ptr_factory_.GetWeakPtr(), label));
+ break;
+ }
+ case Scope::VFS:
+ media_interface_->GetFolderItems(
+ curr_browsed_player_id_, CurrentFolder(),
+ base::Bind(&Device::GetTotalNumberOfItemsVFSResponse,
+ weak_ptr_factory_.GetWeakPtr(), label));
+ break;
+ case Scope::NOW_PLAYING:
+ media_interface_->GetNowPlayingList(
+ base::Bind(&Device::GetTotalNumberOfItemsNowPlayingResponse,
+ weak_ptr_factory_.GetWeakPtr(), label));
+ break;
+ default:
+ DEVICE_LOG(ERROR) << __func__ << ": " << pkt->GetScope();
+ break;
+ }
+}
+
+void Device::GetTotalNumberOfItemsMediaPlayersResponse(
+ uint8_t label, uint16_t curr_player, std::vector<MediaPlayerInfo> list) {
+ DEVICE_VLOG(2) << __func__ << ": num_items=" << list.size();
+
+ auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0x0000, list.size());
+ send_message(label, true, std::move(builder));
+}
+
+void Device::GetTotalNumberOfItemsVFSResponse(uint8_t label,
+ std::vector<ListItem> list) {
+ DEVICE_VLOG(2) << __func__ << ": num_items=" << list.size();
+
+ auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0x0000, list.size());
+ send_message(label, true, std::move(builder));
+}
+
+void Device::GetTotalNumberOfItemsNowPlayingResponse(
+ uint8_t label, std::string curr_song_id, std::vector<SongInfo> list) {
+ DEVICE_VLOG(2) << __func__ << ": num_items=" << list.size();
+
+ auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0x0000, list.size());
+ send_message(label, true, std::move(builder));
+}
+
void Device::HandleChangePath(uint8_t label,
std::shared_ptr<ChangePathRequest> pkt) {
DEVICE_VLOG(2) << __func__ << ": direction=" << pkt->GetDirection()
@@ -647,8 +718,8 @@
media_interface_->GetFolderItems(
curr_browsed_player_id_, CurrentFolder(),
- base::Bind(&Device::ChangePathResponse, base::Unretained(this), label,
- pkt));
+ base::Bind(&Device::ChangePathResponse, weak_ptr_factory_.GetWeakPtr(),
+ label, pkt));
}
void Device::ChangePathResponse(uint8_t label,
@@ -669,7 +740,7 @@
case Scope::NOW_PLAYING: {
media_interface_->GetNowPlayingList(
base::Bind(&Device::GetItemAttributesNowPlayingResponse,
- base::Unretained(this), label, pkt));
+ weak_ptr_factory_.GetWeakPtr(), label, pkt));
} break;
case Scope::VFS:
// TODO (apanicke): Check the vfs_ids_ here. If the item doesn't exist
@@ -679,7 +750,7 @@
media_interface_->GetFolderItems(
curr_browsed_player_id_, CurrentFolder(),
base::Bind(&Device::GetItemAttributesVFSResponse,
- base::Unretained(this), label, pkt));
+ weak_ptr_factory_.GetWeakPtr(), label, pkt));
break;
default:
DEVICE_LOG(ERROR) << "UNKNOWN SCOPE FOR HANDLE GET ITEM ATTRIBUTES";
@@ -927,8 +998,9 @@
uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt) {
DEVICE_VLOG(2) << __func__ << ": player_id=" << pkt->GetPlayerId();
media_interface_->SetBrowsedPlayer(
- pkt->GetPlayerId(), base::Bind(&Device::SetBrowsedPlayerResponse,
- base::Unretained(this), label, pkt));
+ pkt->GetPlayerId(),
+ base::Bind(&Device::SetBrowsedPlayerResponse,
+ weak_ptr_factory_.GetWeakPtr(), label, pkt));
}
void Device::SetBrowsedPlayerResponse(
@@ -994,7 +1066,7 @@
media_interface_->GetNowPlayingList(
base::Bind(&Device::TrackChangedNotificationResponse,
- base::Unretained(this), track_changed_.second, false));
+ weak_ptr_factory_.GetWeakPtr(), track_changed_.second, false));
}
void Device::HandlePlayStatusUpdate() {
@@ -1004,9 +1076,9 @@
return;
}
- media_interface_->GetPlayStatus(
- base::Bind(&Device::PlaybackStatusNotificationResponse,
- base::Unretained(this), play_status_changed_.second, false));
+ media_interface_->GetPlayStatus(base::Bind(
+ &Device::PlaybackStatusNotificationResponse,
+ weak_ptr_factory_.GetWeakPtr(), play_status_changed_.second, false));
}
void Device::HandleNowPlayingUpdate() {
@@ -1017,9 +1089,9 @@
return;
}
- media_interface_->GetNowPlayingList(
- base::Bind(&Device::HandleNowPlayingNotificationResponse,
- base::Unretained(this), now_playing_changed_.second, false));
+ media_interface_->GetNowPlayingList(base::Bind(
+ &Device::HandleNowPlayingNotificationResponse,
+ weak_ptr_factory_.GetWeakPtr(), now_playing_changed_.second, false));
}
void Device::HandleNowPlayingNotificationResponse(
@@ -1052,9 +1124,9 @@
return;
}
- media_interface_->GetPlayStatus(
- base::Bind(&Device::PlaybackPosNotificationResponse,
- base::Unretained(this), play_pos_changed_.second, false));
+ media_interface_->GetPlayStatus(base::Bind(
+ &Device::PlaybackPosNotificationResponse, weak_ptr_factory_.GetWeakPtr(),
+ play_pos_changed_.second, false));
}
void Device::DeviceDisconnected() {
@@ -1075,29 +1147,31 @@
}
std::ostream& operator<<(std::ostream& out, const Device& d) {
- out << "Avrcp Device: Address=" << d.address_.ToString() << std::endl;
- out << " â”” isActive: " << (d.IsActive() ? "YES" : "NO") << std::endl;
- out << " â”” Current Browsed Player: " << d.curr_browsed_player_id_
- << std::endl;
- out << " â”” Registered Notifications: " << std::endl;
- out << " â”” Track: " << d.track_changed_.first << std::endl;
- out << " â”” Play Status: " << d.play_status_changed_.first << std::endl;
- out << " â”” Play Position: " << d.play_pos_changed_.first << std::endl;
- out << " â”” Now Playing: " << d.now_playing_changed_.first << std::endl;
- out << " â”” Addressed Player: " << d.addr_player_changed_.first
- << std::endl;
- out << " â”” Available Players: " << d.avail_players_changed_.first
- << std::endl;
- out << " â”” UIDs Changed: " << d.uids_changed_.first << std::endl;
- out << " â”” Last Song Sent ID: " << d.last_song_info_.media_id << std::endl;
- out << " â”” Last Play State: " << d.last_play_status_.state << std::endl;
- out << " â”” Current Volume: " << volumeToStr(d.volume_) << std::endl;
- out << " â”” Current Folder: " << d.CurrentFolder();
- out << " â”” Control MTU Size: " << d.ctrl_mtu_ << std::endl;
- out << " â”” Browse MTU Size: " << d.browse_mtu_ << std::endl;
- out << " â”” Features Supported: TO BE IMPLEMENTED" << std::endl;
- out << " â”” Last X Media Key Events: TO BE IMPLEMENTED" << std::endl;
+ out << d.address_.ToString();
+ if (d.IsActive()) out << " <Active>";
out << std::endl;
+
+ ScopedIndent indent(out);
+ out << "Current Volume: " << volumeToStr(d.volume_) << std::endl;
+ out << "Current Browsed Player ID: " << d.curr_browsed_player_id_
+ << std::endl;
+ out << "Registered Notifications:\n";
+ {
+ ScopedIndent indent(out);
+ if (d.track_changed_.first) out << "Track Changed\n";
+ if (d.play_status_changed_.first) out << "Play Status\n";
+ if (d.play_pos_changed_.first) out << "Play Position\n";
+ if (d.now_playing_changed_.first) out << "Now Playing\n";
+ if (d.addr_player_changed_.first) out << "Addressed Player\n";
+ if (d.avail_players_changed_.first) out << "Available Players\n";
+ if (d.uids_changed_.first) out << "UIDs Changed\n";
+ }
+ out << "Last Play State: " << d.last_play_status_.state << std::endl;
+ out << "Last Song Sent ID: \"" << d.last_song_info_.media_id << "\"\n";
+ out << "Current Folder: \"" << d.CurrentFolder() << "\"\n";
+ out << "MTU Sizes: CTRL=" << d.ctrl_mtu_ << " BROWSE=" << d.browse_mtu_
+ << std::endl;
+ // TODO (apanicke): Add supported features as well as media keys
return out;
}
diff --git a/profile/avrcp/device.h b/profile/avrcp/device.h
index 33b5662..fefee88 100644
--- a/profile/avrcp/device.h
+++ b/profile/avrcp/device.h
@@ -163,6 +163,16 @@
uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
std::string curr_song_id, std::vector<SongInfo> song_list);
+ // GET TOTAL NUMBER OF ITEMS
+ virtual void HandleGetTotalNumberOfItems(
+ uint8_t label, std::shared_ptr<GetTotalNumberOfItemsRequest> pkt);
+ virtual void GetTotalNumberOfItemsMediaPlayersResponse(
+ uint8_t label, uint16_t curr_player, std::vector<MediaPlayerInfo> list);
+ virtual void GetTotalNumberOfItemsVFSResponse(uint8_t label,
+ std::vector<ListItem> items);
+ virtual void GetTotalNumberOfItemsNowPlayingResponse(
+ uint8_t label, std::string curr_song_id, std::vector<SongInfo> song_list);
+
// GET ITEM ATTRIBUTES
virtual void HandleGetItemAttributes(
uint8_t label, std::shared_ptr<GetItemAttributesRequest> request);
@@ -229,6 +239,7 @@
active_labels_.erase(label);
send_message_cb_.Run(label, browse, std::move(message));
}
+ base::WeakPtrFactory<Device> weak_ptr_factory_;
// TODO (apanicke): Initialize all the variables in the constructor.
RawAddress address_;
diff --git a/profile/avrcp/tests/avrcp_connection_handler_test.cc b/profile/avrcp/tests/avrcp_connection_handler_test.cc
index a46ad02..4008c66 100644
--- a/profile/avrcp/tests/avrcp_connection_handler_test.cc
+++ b/profile/avrcp/tests/avrcp_connection_handler_test.cc
@@ -133,6 +133,30 @@
ConnectionHandler::CleanUp();
};
+// Check that disconnecting without an active connection
+TEST_F(AvrcpConnectionHandlerTest, disconnectAfterCleanupTest) {
+ // Set an Expectation that Open will be called twice as an acceptor and save
+ // the connection callback once it is called.
+ tAVRC_CONN_CB conn_cb;
+ EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
+ .Times(1)
+ .WillOnce(
+ DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));
+
+ // Initialize the interface
+ auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
+ base::Unretained(&device_cb));
+ ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
+ &mock_sdp_, &mock_volume_));
+ connection_handler_ = ConnectionHandler::Get();
+
+ connection_handler_ = nullptr;
+ ConnectionHandler::CleanUp();
+
+ // Call the callback with a message saying the connection has closed
+ conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);
+};
+
// Check that we can handle having a remote device connect to us, start SDP, and
// open another acceptor connection
TEST_F(AvrcpConnectionHandlerTest, remoteDeviceConnectionTest) {
diff --git a/profile/avrcp/tests/avrcp_device_test.cc b/profile/avrcp/tests/avrcp_device_test.cc
index 2207bb0..6e3bb17 100644
--- a/profile/avrcp/tests/avrcp_device_test.cc
+++ b/profile/avrcp/tests/avrcp_device_test.cc
@@ -355,6 +355,79 @@
1, TestAvrcpPacket::Make(get_element_attributes_request_full));
}
+TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsMediaPlayersTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ std::vector<MediaPlayerInfo> player_list = {
+ {0, "player1", true}, {1, "player2", true}, {2, "player3", true},
+ };
+
+ EXPECT_CALL(interface, GetMediaPlayerList(_))
+ .Times(1)
+ .WillOnce(InvokeCb<0>(0, player_list));
+
+ auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0, player_list.size());
+ EXPECT_CALL(response_cb,
+ Call(1, true, matchPacket(std::move(expected_response))))
+ .Times(1);
+
+ SendBrowseMessage(1, TestBrowsePacket::Make(
+ get_total_number_of_items_request_media_players));
+}
+
+TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsVFSTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ std::vector<ListItem> vfs_list = {
+ {ListItem::FOLDER, {"id1", true, "folder1"}, SongInfo()},
+ {ListItem::FOLDER, {"id2", true, "folder2"}, SongInfo()},
+ };
+
+ EXPECT_CALL(interface, GetFolderItems(_, "", _))
+ .Times(1)
+ .WillOnce(InvokeCb<2>(vfs_list));
+
+ auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0, vfs_list.size());
+ EXPECT_CALL(response_cb,
+ Call(1, true, matchPacket(std::move(expected_response))))
+ .Times(1);
+
+ SendBrowseMessage(
+ 1, TestBrowsePacket::Make(get_total_number_of_items_request_vfs));
+}
+
+TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsNowPlayingTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ std::vector<SongInfo> now_playing_list = {
+ {"test_id1", {}}, {"test_id2", {}}, {"test_id3", {}},
+ {"test_id4", {}}, {"test_id5", {}},
+ };
+
+ EXPECT_CALL(interface, GetNowPlayingList(_))
+ .WillRepeatedly(InvokeCb<0>("test_id1", now_playing_list));
+
+ auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+ Status::NO_ERROR, 0, now_playing_list.size());
+ EXPECT_CALL(response_cb,
+ Call(1, true, matchPacket(std::move(expected_response))))
+ .Times(1);
+
+ SendBrowseMessage(
+ 1, TestBrowsePacket::Make(get_total_number_of_items_request_now_playing));
+}
+
TEST_F(AvrcpDeviceTest, getMediaPlayerListTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
@@ -651,6 +724,10 @@
test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+ // Pretend the device is active
+ EXPECT_CALL(a2dp_interface, active_peer())
+ .WillRepeatedly(Return(test_device->GetAddress()));
+
auto reg_notif =
RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif))))
@@ -678,6 +755,46 @@
SendMessage(1, response);
}
+TEST_F(AvrcpDeviceTest, volumeChangedNonActiveTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+ MockVolumeInterface vol_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+
+ // Pretend the device isn't active
+ EXPECT_CALL(a2dp_interface, active_peer())
+ .WillRepeatedly(Return(RawAddress::kEmpty));
+
+ auto reg_notif =
+ RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
+ EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif))))
+ .Times(1);
+ test_device->RegisterVolumeChanged();
+
+ EXPECT_CALL(vol_interface, DeviceConnected(test_device->GetAddress(), _))
+ .Times(1)
+ .WillOnce(InvokeCb<1>(0x30));
+ auto set_vol = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x30);
+ EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(set_vol))))
+ .Times(1);
+
+ auto response = TestAvrcpPacket::Make(interim_volume_changed_notification);
+ SendMessage(1, response);
+
+ // Ensure that SetVolume is never called
+ EXPECT_CALL(vol_interface, SetVolume(0x47)).Times(0);
+
+ auto reg_notif2 =
+ RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
+ EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif2))))
+ .Times(1);
+ response = TestAvrcpPacket::Make(changed_volume_changed_notification);
+ SendMessage(1, response);
+ response = TestAvrcpPacket::Make(interim_volume_changed_notification);
+ SendMessage(1, response);
+}
+
TEST_F(AvrcpDeviceTest, volumeRejectedTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
@@ -697,5 +814,129 @@
EXPECT_CALL(response_cb, Call(_, _, _)).Times(0);
}
+TEST_F(AvrcpDeviceTest, playPushedActiveDeviceTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+ MockVolumeInterface vol_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+
+ // Pretend the device is active
+ EXPECT_CALL(a2dp_interface, active_peer())
+ .WillRepeatedly(Return(test_device->GetAddress()));
+
+ auto play_pushed = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44);
+ auto play_pushed_response =
+ PassThroughPacketBuilder::MakeBuilder(true, true, 0x44);
+ EXPECT_CALL(response_cb,
+ Call(_, false, matchPacket(std::move(play_pushed_response))))
+ .Times(1);
+
+ PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING};
+ EXPECT_CALL(interface, GetPlayStatus(_))
+ .Times(1)
+ .WillOnce(InvokeCb<0>(status));
+
+ EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::PUSHED)).Times(1);
+
+ auto play_pushed_pkt = TestAvrcpPacket::Make();
+ play_pushed->Serialize(play_pushed_pkt);
+
+ SendMessage(1, play_pushed_pkt);
+}
+
+TEST_F(AvrcpDeviceTest, playPushedInactiveDeviceTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+ MockVolumeInterface vol_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+
+ // Pretend the device is not active
+ EXPECT_CALL(a2dp_interface, active_peer())
+ .WillRepeatedly(Return(RawAddress::kEmpty));
+
+ auto play_pushed = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44);
+ auto play_pushed_response =
+ PassThroughPacketBuilder::MakeBuilder(true, true, 0x44);
+ EXPECT_CALL(response_cb,
+ Call(_, false, matchPacket(std::move(play_pushed_response))))
+ .Times(1);
+
+ // Expect that the device will try to set itself as active
+ EXPECT_CALL(interface, SetActiveDevice(test_device->GetAddress())).Times(1);
+
+ // No play command should be sent since the music is already playing
+ PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING};
+ EXPECT_CALL(interface, GetPlayStatus(_))
+ .Times(1)
+ .WillOnce(InvokeCb<0>(status));
+ EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::PUSHED)).Times(0);
+
+ auto play_pushed_pkt = TestAvrcpPacket::Make();
+ play_pushed->Serialize(play_pushed_pkt);
+
+ SendMessage(1, play_pushed_pkt);
+}
+
+TEST_F(AvrcpDeviceTest, mediaKeyActiveDeviceTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+ MockVolumeInterface vol_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+
+ // Pretend the device is active
+ EXPECT_CALL(a2dp_interface, active_peer())
+ .WillRepeatedly(Return(test_device->GetAddress()));
+
+ auto play_released =
+ PassThroughPacketBuilder::MakeBuilder(false, false, 0x44);
+ auto play_released_response =
+ PassThroughPacketBuilder::MakeBuilder(true, false, 0x44);
+ EXPECT_CALL(response_cb,
+ Call(_, false, matchPacket(std::move(play_released_response))))
+ .Times(1);
+
+ EXPECT_CALL(interface, GetPlayStatus(_)).Times(0);
+
+ EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::RELEASED)).Times(1);
+
+ auto play_released_pkt = TestAvrcpPacket::Make();
+ play_released->Serialize(play_released_pkt);
+
+ SendMessage(1, play_released_pkt);
+}
+
+TEST_F(AvrcpDeviceTest, mediaKeyInactiveDeviceTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+ MockVolumeInterface vol_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+
+ // Pretend the device is not active
+ EXPECT_CALL(a2dp_interface, active_peer())
+ .WillRepeatedly(Return(RawAddress::kEmpty));
+
+ auto play_released =
+ PassThroughPacketBuilder::MakeBuilder(false, false, 0x44);
+ auto play_released_response =
+ PassThroughPacketBuilder::MakeBuilder(true, false, 0x44);
+ EXPECT_CALL(response_cb,
+ Call(_, false, matchPacket(std::move(play_released_response))))
+ .Times(1);
+
+ EXPECT_CALL(interface, GetPlayStatus(_)).Times(0);
+
+ // Expect that the key event wont be sent to the media interface
+ EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::RELEASED)).Times(0);
+
+ auto play_released_pkt = TestAvrcpPacket::Make();
+ play_released->Serialize(play_released_pkt);
+
+ SendMessage(1, play_released_pkt);
+}
+
} // namespace avrcp
} // namespace bluetooth
\ No newline at end of file
diff --git a/profile/avrcp/tests/avrcp_test_helper.h b/profile/avrcp/tests/avrcp_test_helper.h
index 594a0ae..16fc31f 100644
--- a/profile/avrcp/tests/avrcp_test_helper.h
+++ b/profile/avrcp/tests/avrcp_test_helper.h
@@ -33,7 +33,7 @@
class MockMediaInterface : public MediaInterface {
public:
- MOCK_METHOD2(SendKeyEvent, void(uint8_t, uint8_t));
+ MOCK_METHOD2(SendKeyEvent, void(uint8_t, KeyState));
MOCK_METHOD1(GetSongInfo, void(MediaInterface::SongInfoCallback));
MOCK_METHOD1(GetPlayStatus, void(MediaInterface::PlayStatusCallback));
MOCK_METHOD1(GetNowPlayingList, void(MediaInterface::NowPlayingCallback));
diff --git a/stack/Android.bp b/stack/Android.bp
index 2b5d430..76cb172 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -197,7 +197,9 @@
"system/bt",
"system/bt/internal_include",
],
- srcs: ["test/stack_a2dp_test.cc"],
+ srcs: [
+ "test/stack_a2dp_test.cc",
+ ],
shared_libs: [
"libhidlbase",
"liblog",
@@ -221,6 +223,56 @@
],
}
+cc_test {
+ name: "net_test_stack_rfcomm",
+ defaults: ["fluoride_defaults"],
+ host_supported: true,
+ local_include_dirs: [
+ "include",
+ "btm",
+ "l2cap",
+ "smp",
+ "rfcomm",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/internal_include",
+ "system/bt/btcore/include",
+ "system/bt/hci/include",
+ "system/bt/utils/include",
+ ],
+ srcs: [
+ "rfcomm/port_api.cc",
+ "rfcomm/port_rfc.cc",
+ "rfcomm/port_utils.cc",
+ "rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_mx_fsm.cc",
+ "rfcomm/rfc_port_fsm.cc",
+ "rfcomm/rfc_port_if.cc",
+ "rfcomm/rfc_ts_frames.cc",
+ "rfcomm/rfc_utils.cc",
+ "test/common/mock_btm_layer.cc",
+ "test/common/mock_btu_layer.cc",
+ "test/common/mock_l2cap_layer.cc",
+ "test/common/stack_test_packet_utils.cc",
+ "test/rfcomm/stack_rfcomm_test.cc",
+ "test/rfcomm/stack_rfcomm_test_main.cc",
+ "test/rfcomm/stack_rfcomm_test_utils.cc",
+ "test/rfcomm/stack_rfcomm_test_utils_test.cc",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "liblog",
+ "libgmock",
+ "libosi",
+ "libbt-protos-lite",
+ ],
+}
+
// Bluetooth stack smp unit tests for target
// ========================================================
cc_test {
diff --git a/stack/a2dp/a2dp_api.cc b/stack/a2dp/a2dp_api.cc
index b4563d7..cc707c4 100644
--- a/stack/a2dp/a2dp_api.cc
+++ b/stack/a2dp/a2dp_api.cc
@@ -68,6 +68,7 @@
bool found = false;
tA2DP_Service a2dp_svc;
tSDP_PROTOCOL_ELEM elem;
+ RawAddress peer_address = RawAddress::kEmpty;
LOG_VERBOSE(LOG_TAG, "%s: status: %d", __func__, status);
@@ -80,6 +81,7 @@
break;
}
memset(&a2dp_svc, 0, sizeof(tA2DP_Service));
+ peer_address = p_rec->remote_bd_addr;
/* get service name */
if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) !=
@@ -118,7 +120,7 @@
osi_free_and_reset((void**)&a2dp_cb.find.p_db);
/* return info from sdp record in app callback function */
if (a2dp_cb.find.p_cback != NULL) {
- (*a2dp_cb.find.p_cback)(found, &a2dp_svc);
+ (*a2dp_cb.find.p_cback)(found, &a2dp_svc, peer_address);
}
return;
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 1279ceb..93d7381 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -549,13 +549,17 @@
char* tok = NULL;
char* tmp_token = NULL;
bool offload_codec_support[BTAV_A2DP_CODEC_INDEX_MAX] = {false};
- char value_cap[PROPERTY_VALUE_MAX], value_enable[PROPERTY_VALUE_MAX];
- osi_property_get("persist.bluetooth.a2dp_offload.cap", value_cap, "false");
- osi_property_get("persist.bluetooth.a2dp_offload.enable", value_enable,
+ char value_sup[PROPERTY_VALUE_MAX], value_dis[PROPERTY_VALUE_MAX];
+
+ osi_property_get("ro.bluetooth.a2dp_offload.supported", value_sup, "false");
+ osi_property_get("persist.bluetooth.a2dp_offload.disabled", value_dis,
"false");
- a2dp_offload_status = (strcmp(value_enable, "true") == 0);
+ a2dp_offload_status =
+ (strcmp(value_sup, "true") == 0) && (strcmp(value_dis, "false") == 0);
if (a2dp_offload_status) {
+ char value_cap[PROPERTY_VALUE_MAX];
+ osi_property_get("persist.bluetooth.a2dp_offload.cap", value_cap, "");
tok = strtok_r((char*)value_cap, "-", &tmp_token);
while (tok != NULL) {
if (strcmp(tok, "sbc") == 0) {
diff --git a/stack/a2dp/a2dp_int.h b/stack/a2dp/a2dp_int.h
index 713faa7..708f908 100644
--- a/stack/a2dp/a2dp_int.h
+++ b/stack/a2dp/a2dp_int.h
@@ -29,7 +29,7 @@
/*****************************************************************************
* Constants
****************************************************************************/
-#define A2DP_VERSION 0x0102
+#define A2DP_VERSION 0x0103
/* Number of attributes in A2DP SDP record. */
#define A2DP_NUM_ATTR 6
diff --git a/stack/btm/btm_ble_adv_filter.cc b/stack/btm/btm_ble_adv_filter.cc
index c8dfff5..1f68fb6 100644
--- a/stack/btm/btm_ble_adv_filter.cc
+++ b/stack/btm/btm_ble_adv_filter.cc
@@ -499,6 +499,19 @@
UINT8_TO_STREAM(p, filt_index);
if (action != BTM_BLE_SCAN_COND_CLEAR) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (addr.type == BLE_ADDR_PUBLIC_ID) {
+ LOG(INFO) << __func__ << " Filter address " << addr.bda
+ << " has type PUBLIC_ID, try to get identity address";
+ /* If no matching identity address is found for the input address,
+ * this call will have no effect. */
+ btm_random_pseudo_to_identity_addr(&addr.bda, &addr.type);
+ }
+#endif
+
+ LOG(INFO) << __func__
+ << " Adding scan filter with peer address: " << addr.bda;
+
BDADDR_TO_STREAM(p, addr.bda);
UINT8_TO_STREAM(p, addr.type);
}
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index e28c157..1f8263f 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -485,37 +485,38 @@
BTM_TRACE_DEBUG("%s", __func__);
/* Check status of command complete event */
- if ((p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF) &&
- (p_vcs_cplt_params->param_len > 0)) {
- p = p_vcs_cplt_params->p_param_buf;
- STREAM_TO_UINT8(status, p);
+ CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF);
+ CHECK(p_vcs_cplt_params->param_len > 0);
+
+ p = p_vcs_cplt_params->p_param_buf;
+ STREAM_TO_UINT8(status, p);
+
+ if (status != HCI_SUCCESS) {
+ BTM_TRACE_DEBUG("%s: Status = 0x%02x (0 is success)", __func__, status);
+ return;
+ }
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.filter_support, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_filter, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.energy_support, p);
+
+ if (p_vcs_cplt_params->param_len >
+ BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE) {
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.version_supported, p);
+ } else {
+ btm_cb.cmn_ble_vsc_cb.version_supported = BTM_VSC_CHIP_CAPABILITY_L_VERSION;
}
- if (status == HCI_SUCCESS) {
- STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p);
- STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p);
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p);
- STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, p);
- STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.filter_support, p);
- STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_filter, p);
- STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.energy_support, p);
-
- if (p_vcs_cplt_params->param_len >
- BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE) {
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.version_supported, p);
- } else {
- btm_cb.cmn_ble_vsc_cb.version_supported =
- BTM_VSC_CHIP_CAPABILITY_L_VERSION;
- }
-
- if (btm_cb.cmn_ble_vsc_cb.version_supported >=
- BTM_VSC_CHIP_CAPABILITY_M_VERSION) {
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
- }
- btm_cb.cmn_ble_vsc_cb.values_read = true;
+ if (btm_cb.cmn_ble_vsc_cb.version_supported >=
+ BTM_VSC_CHIP_CAPABILITY_M_VERSION) {
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
}
+ btm_cb.cmn_ble_vsc_cb.values_read = true;
BTM_TRACE_DEBUG(
"%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d", __func__,
@@ -722,6 +723,7 @@
*
******************************************************************************/
void BTM_BleClearBgConnDev(void) {
+ if (!controller_get_interface()->supports_ble()) return;
btm_ble_start_auto_conn(false);
btm_ble_clear_white_list();
gatt_reset_bgdev_list();
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index b080901..442fb77 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -35,6 +35,7 @@
#include "bt_types.h"
#include "bt_utils.h"
+#include "btif_storage.h"
#include "btm_int.h"
#include "btu.h"
#include "hcimsgs.h"
@@ -1432,7 +1433,6 @@
* BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
*
******************************************************************************/
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr,
uint32_t passkey) {
BTM_TRACE_API("BTM_PasskeyReqReply: State: %s res:%d",
@@ -1479,7 +1479,6 @@
btsnd_hcic_user_passkey_reply(bd_addr, passkey);
}
}
-#endif
/*******************************************************************************
*
@@ -1495,13 +1494,11 @@
* type - notification type
*
******************************************************************************/
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
void BTM_SendKeypressNotif(const RawAddress& bd_addr, tBTM_SP_KEY_TYPE type) {
/* This API only make sense between PASSKEY_REQ and SP complete */
if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY)
btsnd_hcic_send_keypress_notif(bd_addr, type);
}
-#endif
/*******************************************************************************
*
@@ -2719,7 +2716,7 @@
void btm_sec_dev_reset(void) {
if (controller_get_interface()->supports_simple_pairing()) {
/* set the default IO capabilities */
- btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+ btm_cb.devcb.loc_io_caps = btif_storage_get_local_io_caps();
/* add mx service to use no security */
BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,
BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
@@ -3398,26 +3395,27 @@
evt_data.cfm_req.just_works = true;
-/* process user confirm req in association with the auth_req param */
-#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO)
- if (p_dev_rec->rmt_io_caps == BTM_IO_CAP_UNKNOWN) {
- BTM_TRACE_ERROR(
- "%s did not receive IO cap response prior"
- " to BTM_SP_CFM_REQ_EVT, failing pairing request",
- __func__);
- status = BTM_WRONG_MODE;
- BTM_ConfirmReqReply(status, p_bda);
- return;
+ /* process user confirm req in association with the auth_req param */
+ if (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) {
+ if (p_dev_rec->rmt_io_caps == BTM_IO_CAP_UNKNOWN) {
+ BTM_TRACE_ERROR(
+ "%s did not receive IO cap response prior"
+ " to BTM_SP_CFM_REQ_EVT, failing pairing request",
+ __func__);
+ status = BTM_WRONG_MODE;
+ BTM_ConfirmReqReply(status, p_bda);
+ return;
+ }
+ if ((p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO) &&
+ (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) &&
+ ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) ||
+ (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) {
+ /* Both devices are DisplayYesNo and one or both devices want to
+ authenticate -> use authenticated link key */
+ evt_data.cfm_req.just_works = false;
+ }
}
- if ((p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO) &&
- (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) &&
- ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) ||
- (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) {
- /* Both devices are DisplayYesNo and one or both devices want to
- authenticate -> use authenticated link key */
- evt_data.cfm_req.just_works = false;
- }
-#endif
+
BTM_TRACE_DEBUG(
"btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth "
"loc:%d, rmt:%d",
@@ -3440,12 +3438,12 @@
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
break;
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
case BTM_SP_KEY_REQ_EVT:
- /* HCI_USER_PASSKEY_REQUEST_EVT */
- btm_sec_change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY);
+ if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) {
+ /* HCI_USER_PASSKEY_REQUEST_EVT */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY);
+ }
break;
-#endif
}
if (btm_cb.api.p_sp_callback) {
@@ -3463,12 +3461,10 @@
if (event == BTM_SP_CFM_REQ_EVT) {
BTM_TRACE_DEBUG("calling BTM_ConfirmReqReply with status: %d", status);
BTM_ConfirmReqReply(status, p_bda);
- }
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- else if (event == BTM_SP_KEY_REQ_EVT) {
+ } else if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE &&
+ event == BTM_SP_KEY_REQ_EVT) {
BTM_PasskeyReqReply(status, p_bda, 0);
}
-#endif
return;
}
@@ -3489,12 +3485,9 @@
if (p_dev_rec != NULL) {
btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE);
}
- }
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- else {
+ } else if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) {
btsnd_hcic_user_passkey_neg_reply(p_bda);
}
-#endif
}
/*******************************************************************************
@@ -4046,6 +4039,8 @@
__func__, p_dev_rec, p_dev_rec->p_callback);
p_dev_rec->p_callback = NULL;
l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
+ } else if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
}
return;
}
@@ -4700,6 +4695,7 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
VLOG(2) << __func__ << " bda: " << bda;
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
(btm_cb.collision_start_time != 0) &&
@@ -4736,11 +4732,9 @@
static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) {
tBTM_CB* p_cb = &btm_cb;
tBTM_SEC_DEV_REC* p_dev_rec;
-#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE)
- tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
-#else
- tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_YES;
-#endif
+ tBTM_AUTH_REQ auth_req = (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_NONE)
+ ? BTM_AUTH_AP_NO
+ : BTM_AUTH_AP_YES;
uint8_t name[2];
p_dev_rec = btm_find_dev(p_cb->pairing_bda);
@@ -4776,12 +4770,13 @@
/* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
break;
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
case BTM_PAIR_STATE_KEY_ENTRY:
- btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
- /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) {
+ btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
+ } else {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
break;
-#endif /* !BTM_IO_CAP_NONE */
case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index 009c1f1..b6015e5 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -971,8 +971,11 @@
pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
if (pseudo_op_code >= GATT_OP_CODE_MAX) {
- LOG(ERROR) << "ATT - Rcvd L2CAP data, unknown cmd: 0x" << std::hex
- << op_code;
+ /* Note: PTS: GATT/SR/UNS/BI-01-C mandates error on unsupported ATT request.
+ */
+ LOG(ERROR) << __func__
+ << ": ATT - Rcvd L2CAP data, unknown cmd: " << loghex(op_code);
+ gatt_send_error_rsp(tcb, GATT_REQ_NOT_SUPPORTED, op_code, 0, false);
return;
}
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index d71b60d..04eb8c5 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -567,7 +567,7 @@
if (s_hdl > e_hdl || !GATT_HANDLE_IS_VALID(s_hdl) ||
!GATT_HANDLE_IS_VALID(e_hdl)) {
- return GATT_INVALID_PDU;
+ return GATT_INVALID_HANDLE;
}
return GATT_SUCCESS;
diff --git a/stack/include/a2dp_api.h b/stack/include/a2dp_api.h
index 9aba6c7..56e259c 100644
--- a/stack/include/a2dp_api.h
+++ b/stack/include/a2dp_api.h
@@ -82,7 +82,8 @@
} tA2DP_Service;
/* This is the callback to notify the result of the SDP discovery process. */
-typedef void(tA2DP_FIND_CBACK)(bool found, tA2DP_Service* p_service);
+typedef void(tA2DP_FIND_CBACK)(bool found, tA2DP_Service* p_service,
+ const RawAddress& peer_address);
/*****************************************************************************
* external function declarations
diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h
index 5d2135b..fd0721c 100644
--- a/stack/include/avdt_api.h
+++ b/stack/include/avdt_api.h
@@ -31,11 +31,10 @@
/*****************************************************************************
* Constants
****************************************************************************/
-#ifndef AVDT_VERSION
-#define AVDT_VERSION 0x0103
-#endif
#define AVDT_VERSION_1_3 0x0103
+#define AVDTP_VERSION_CONFIG_KEY "AvdtpVersion"
+
/* Maximum size in bytes of the codec capabilities information element. */
#define AVDT_CODEC_SIZE 20
diff --git a/stack/include/port_api.h b/stack/include/port_api.h
index aedbe74..b0a7e63 100644
--- a/stack/include/port_api.h
+++ b/stack/include/port_api.h
@@ -309,7 +309,7 @@
* p_lcid - OUT L2CAP's LCID
*
******************************************************************************/
-extern int PORT_CheckConnection(uint16_t handle, RawAddress& bd_addr,
+extern int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr,
uint16_t* p_lcid);
/*******************************************************************************
@@ -323,7 +323,7 @@
* bd_addr - bd_addr of the peer
*
******************************************************************************/
-extern bool PORT_IsOpening(RawAddress& bd_addr);
+extern bool PORT_IsOpening(RawAddress* bd_addr);
/*******************************************************************************
*
diff --git a/stack/include/smp_api_types.h b/stack/include/smp_api_types.h
index fad8b75..f317993 100644
--- a/stack/include/smp_api_types.h
+++ b/stack/include/smp_api_types.h
@@ -109,10 +109,6 @@
#define SMP_IO_CAP_MAX BTM_IO_CAP_MAX
typedef uint8_t tSMP_IO_CAP;
-#ifndef SMP_DEFAULT_IO_CAPS
-#define SMP_DEFAULT_IO_CAPS SMP_IO_CAP_KBDISP
-#endif
-
/* OOB data present or not */
enum { SMP_OOB_NONE, SMP_OOB_PRESENT, SMP_OOB_UNKNOWN };
typedef uint8_t tSMP_OOB_FLAG;
diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc
index 951a45b..173d0a6 100644
--- a/stack/l2cap/l2c_api.cc
+++ b/stack/l2cap/l2c_api.cc
@@ -275,7 +275,7 @@
*
******************************************************************************/
uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
- return L2CA_ErtmConnectReq(psm, p_bd_addr, NULL);
+ return L2CA_ErtmConnectReq(psm, p_bd_addr, nullptr);
}
/*******************************************************************************
@@ -297,10 +297,6 @@
******************************************************************************/
uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
tL2CAP_ERTM_INFO* p_ertm_info) {
- tL2C_LCB* p_lcb;
- tL2C_CCB* p_ccb;
- tL2C_RCB* p_rcb;
-
VLOG(1) << __func__ << "BDA " << p_bd_addr
<< StringPrintf(" PSM: 0x%04x allowed:0x%x preferred:%d", psm,
(p_ertm_info) ? p_ertm_info->allowed_modes : 0,
@@ -308,36 +304,36 @@
/* Fail if we have not established communications with the controller */
if (!BTM_IsDeviceUp()) {
- L2CAP_TRACE_WARNING("L2CAP connect req - BTU not ready");
- return (0);
+ LOG(WARNING) << __func__ << ": BTU not ready";
+ return 0;
}
/* Fail if the PSM is not registered */
- p_rcb = l2cu_find_rcb_by_psm(psm);
- if (p_rcb == NULL) {
- L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
- return (0);
+ tL2C_RCB* p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == nullptr) {
+ LOG(WARNING) << __func__ << ": no RCB, PSM=" << loghex(psm);
+ return 0;
}
/* First, see if we already have a link to the remote */
/* assume all ERTM l2cap connection is going over BR/EDR for now */
- p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
- if (p_lcb == NULL) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == nullptr) {
/* No link. Get an LCB and start link establishment */
p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
/* currently use BR/EDR for ERTM mode l2cap connection */
- if ((p_lcb == NULL) || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR))) {
- L2CAP_TRACE_WARNING(
- "L2CAP - conn not started for PSM: 0x%04x p_lcb: 0x%08x", psm,
- p_lcb);
- return (0);
+ if ((p_lcb == nullptr) || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR))) {
+ LOG(WARNING) << __func__
+ << ": connection not started for PSM=" << loghex(psm)
+ << ", p_lcb=" << p_lcb;
+ return 0;
}
}
/* Allocate a channel control block */
- p_ccb = l2cu_allocate_ccb(p_lcb, 0);
- if (p_ccb == NULL) {
- L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
- return (0);
+ tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == nullptr) {
+ LOG(WARNING) << __func__ << ": no CCB, PSM=" << loghex(psm);
+ return 0;
}
/* Save registration info */
@@ -366,16 +362,14 @@
/* If link is up, start the L2CAP connection */
if (p_lcb->link_state == LST_CONNECTED) {
- l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
- }
-
- /* If link is disconnecting, save link info to retry after disconnect
- * Possible Race condition when a reconnect occurs
- * on the channel during a disconnect of link. This
- * ccb will be automatically retried after link disconnect
- * arrives
- */
- else if (p_lcb->link_state == LST_DISCONNECTING) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, nullptr);
+ } else if (p_lcb->link_state == LST_DISCONNECTING) {
+ /* If link is disconnecting, save link info to retry after disconnect
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
L2CAP_TRACE_DEBUG("L2CAP API - link disconnecting: RETRY LATER");
/* Save ccb so it can be started after disconnect is finished */
@@ -386,7 +380,7 @@
psm, p_ccb->local_cid);
/* Return the local CID as our handle */
- return (p_ccb->local_cid);
+ return p_ccb->local_cid;
}
/*******************************************************************************
diff --git a/stack/l2cap/l2c_ble.cc b/stack/l2cap/l2c_ble.cc
index 839e5f0..e3bfc52 100644
--- a/stack/l2cap/l2c_ble.cc
+++ b/stack/l2cap/l2c_ble.cc
@@ -31,6 +31,7 @@
#include "btu.h"
#include "device/include/controller.h"
#include "hcimsgs.h"
+#include "l2c_api.h"
#include "l2c_int.h"
#include "l2cdefs.h"
#include "osi/include/osi.h"
@@ -52,11 +53,19 @@
*
******************************************************************************/
bool L2CA_CancelBleConnectReq(const RawAddress& rem_bda) {
- tL2C_LCB* p_lcb;
-
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
/* There can be only one BLE connection request outstanding at a time */
if (btm_ble_get_conn_st() == BLE_CONN_IDLE) {
L2CAP_TRACE_WARNING("%s - no connection pending", __func__);
+ tACL_CONN* p_acl = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE);
+ if (p_acl) {
+ if (p_lcb != NULL &&
+ p_lcb->link_state == LST_CONNECTING && !l2cb.is_ble_connecting) {
+ L2CAP_TRACE_WARNING("%s - disconnecting the LE link", __func__);
+ L2CA_RemoveFixedChnl(L2CAP_ATT_CID, rem_bda);
+ return (true);
+ }
+ }
return (false);
}
@@ -71,7 +80,6 @@
btsnd_hcic_ble_create_conn_cancel();
- p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
/* Do not remove lcb if an LE link is already up as a peripheral */
if (p_lcb != NULL &&
!(p_lcb->link_role == HCI_ROLE_SLAVE &&
diff --git a/stack/l2cap/l2c_utils.cc b/stack/l2cap/l2c_utils.cc
index 337e076..cc16090 100644
--- a/stack/l2cap/l2c_utils.cc
+++ b/stack/l2cap/l2c_utils.cc
@@ -1619,18 +1619,28 @@
p_ccb->in_use = false;
/* If no channels on the connection, start idle timeout */
- if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED)) {
- 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;
+ if ((p_lcb) && p_lcb->in_use) {
+ if (p_lcb->link_state == LST_CONNECTED) {
+ 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 {
- /* Link is still active, adjust channel quotas. */
- l2c_link_adjust_chnl_allocation();
+ l2cu_no_dynamic_ccbs(p_lcb);
+ } else {
+ /* Link is still active, adjust channel quotas. */
+ l2c_link_adjust_chnl_allocation();
+ }
+ } else if (p_lcb->link_state == LST_CONNECTING && !l2cb.is_ble_connecting) {
+ if (!p_lcb->ccb_queue.p_first_ccb) {
+ if (p_lcb->transport == BT_TRANSPORT_LE &&
+ p_ccb->local_cid == L2CAP_ATT_CID) {
+ L2CAP_TRACE_WARNING("%s - disconnecting the LE link", __func__);
+ l2cu_no_dynamic_ccbs(p_lcb);
+ }
+ }
}
}
}
diff --git a/stack/rfcomm/port_api.cc b/stack/rfcomm/port_api.cc
index 1ae8667..0bb817d 100644
--- a/stack/rfcomm/port_api.cc
+++ b/stack/rfcomm/port_api.cc
@@ -118,7 +118,7 @@
*p_handle = 0;
if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
- /* Server Channel Number(SCN) should be in range 1...30 */
+ // Server Channel Number (SCN) should be in range [1, 30]
LOG(ERROR) << __func__ << ": Invalid SCN, bd_addr=" << bd_addr
<< ", scn=" << static_cast<int>(scn)
<< ", is_server=" << is_server
@@ -127,8 +127,8 @@
return (PORT_INVALID_SCN);
}
- /* For client that originate connection on the existing none initiator */
- /* multiplexer channel DLCI should be odd */
+ // For client that originates connection on the existing none initiator
+ // multiplexer channel, DLCI should be odd.
uint8_t dlci;
tRFC_MCB* p_mcb = port_find_mcb(bd_addr);
if (p_mcb && !p_mcb->is_initiator && !is_server) {
@@ -137,13 +137,13 @@
dlci = (scn << 1);
}
- /* For the server side always allocate a new port. On the client side */
- /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+ // On the client side, do not allow the same (dlci, bd_addr) to be opened
+ // twice by application
tPORT* p_port;
if (!is_server) {
p_port = port_find_port(dlci, bd_addr);
if (p_port != nullptr) {
- /* if existing port is also a client port */
+ // if existing port is also a client port, error out
if (!p_port->is_server) {
LOG(ERROR) << __func__ << ": already at opened state "
<< static_cast<int>(p_port->state)
@@ -153,22 +153,26 @@
<< ", bd_addr=" << bd_addr << ", scn=" << std::to_string(scn)
<< ", is_server=" << is_server << ", mtu=" << mtu
<< ", uuid=" << loghex(uuid) << ", dlci=" << +dlci
- << ", p_mcb=" << p_mcb << ", port=" << +p_port->inx;
- *p_handle = p_port->inx;
+ << ", p_mcb=" << p_mcb
+ << ", port=" << std::to_string(p_port->handle);
+ *p_handle = p_port->handle;
return (PORT_ALREADY_OPENED);
}
}
}
+ // On the server side, always allocate a new port.
p_port = port_allocate_port(dlci, bd_addr);
if (p_port == nullptr) {
LOG(ERROR) << __func__ << ": no resources, bd_addr=" << bd_addr
<< ", scn=" << std::to_string(scn) << ", is_server=" << is_server
<< ", mtu=" << mtu << ", uuid=" << loghex(uuid)
<< ", dlci=" << +dlci;
- return (PORT_NO_RESOURCES);
+ return PORT_NO_RESOURCES;
}
+ *p_handle = p_port->handle;
+ // Get default signal state
switch (uuid) {
case UUID_PROTOCOL_OBEX:
p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
@@ -189,42 +193,35 @@
break;
}
- *p_handle = p_port->inx;
-
+ // Assign port specific values
p_port->state = PORT_STATE_OPENING;
p_port->uuid = uuid;
p_port->is_server = is_server;
p_port->scn = scn;
p_port->ev_mask = 0;
- /* If the MTU is not specified (0), keep MTU decision until the
- * PN frame has to be send
- * at that time connection should be established and we
- * will know for sure our prefered MTU
- */
-
+ // Find MTU
+ // If the MTU is not specified (0), keep MTU decision until the PN frame has
+ // to be send at that time connection should be established and we will know
+ // for sure our prefered MTU
uint16_t rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
-
if (mtu) {
p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
} else {
p_port->mtu = rfcomm_mtu;
}
- /* server doesn't need to release port when closing */
+ // Other states
+ // server doesn't need to release port when closing
if (is_server) {
p_port->keep_port_handle = true;
-
- /* keep mtu that user asked, p_port->mtu could be updated during param
- * negotiation */
+ // keep mtu that user asked, p_port->mtu could be updated during param
+ // negotiation
p_port->keep_mtu = p_port->mtu;
}
-
p_port->local_ctrl.modem_signal = p_port->default_signal_state;
p_port->local_ctrl.fc = false;
-
p_port->p_mgmt_callback = p_mgmt_cb;
-
p_port->bd_addr = bd_addr;
LOG(INFO) << __func__ << ": bd_addr=" << bd_addr
@@ -234,12 +231,12 @@
<< ", signal_state=" << loghex(p_port->default_signal_state)
<< ", p_port=" << p_port;
- /* If this is not initiator of the connection need to just wait */
+ // If this is not initiator of the connection need to just wait
if (p_port->is_server) {
return (PORT_SUCCESS);
}
- /* Open will be continued after security checks are passed */
+ // Open will be continued after security checks are passed
return port_open_continue(p_port);
}
@@ -286,24 +283,21 @@
*
******************************************************************************/
int RFCOMM_RemoveServer(uint16_t handle) {
- tPORT* p_port;
-
- RFCOMM_TRACE_API("RFCOMM_RemoveServer() handle:%d", handle);
-
/* Check if handle is valid to avoid crashing */
if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
- RFCOMM_TRACE_ERROR("RFCOMM_RemoveServer() BAD handle:%d", handle);
+ LOG(ERROR) << __func__ << ": bad handle " << handle;
return (PORT_BAD_HANDLE);
}
- p_port = &rfc_cb.port.port[handle - 1];
+ tPORT* p_port = &rfc_cb.port.port[handle - 1];
/* Do not report any events to the client any more. */
- p_port->p_mgmt_callback = NULL;
+ p_port->p_mgmt_callback = nullptr;
if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
- RFCOMM_TRACE_EVENT("RFCOMM_RemoveServer() Not opened:%d", handle);
+ VLOG(1) << __func__ << ": handle " << handle << " not opened";
return (PORT_SUCCESS);
}
+ LOG(INFO) << __func__ << ": handle=" << handle;
/* this port will be deallocated after closing */
p_port->keep_port_handle = false;
@@ -486,18 +480,19 @@
* p_lcid - OUT L2CAP's LCID
*
******************************************************************************/
-int PORT_CheckConnection(uint16_t handle, RawAddress& bd_addr,
+int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr,
uint16_t* p_lcid) {
- tPORT* p_port;
-
- RFCOMM_TRACE_API("PORT_CheckConnection() handle:%d", handle);
-
/* Check if handle is valid to avoid crashing */
if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
return (PORT_BAD_HANDLE);
}
-
- p_port = &rfc_cb.port.port[handle - 1];
+ tPORT* p_port = &rfc_cb.port.port[handle - 1];
+ RFCOMM_TRACE_DEBUG(
+ "%s: handle=%d, in_use=%d, port_state=%d, p_mcb=%p, peer_ready=%d, "
+ "rfc_state=%d",
+ __func__, handle, p_port->in_use, p_port->state, p_port->rfc.p_mcb,
+ (p_port->rfc.p_mcb ? p_port->rfc.p_mcb->peer_ready : -1),
+ p_port->rfc.state);
if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
return (PORT_NOT_OPENED);
@@ -508,7 +503,7 @@
return (PORT_LINE_ERR);
}
- bd_addr = p_port->rfc.p_mcb->bd_addr;
+ *bd_addr = p_port->rfc.p_mcb->bd_addr;
if (p_lcid) *p_lcid = p_port->rfc.p_mcb->lcid;
return (PORT_SUCCESS);
@@ -525,28 +520,23 @@
* bd_addr - bd_addr of the peer
*
******************************************************************************/
-bool PORT_IsOpening(RawAddress& bd_addr) {
- uint8_t xx, yy;
- tRFC_MCB* p_mcb = NULL;
- tPORT* p_port;
- bool found_port;
-
+bool PORT_IsOpening(RawAddress* bd_addr) {
/* Check for any rfc_mcb which is in the middle of opening. */
- for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++) {
- if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
- (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED)) {
- bd_addr = rfc_cb.port.rfc_mcb[xx].bd_addr;
+ for (auto& multiplexer_cb : rfc_cb.port.rfc_mcb) {
+ if ((multiplexer_cb.state > RFC_MX_STATE_IDLE) &&
+ (multiplexer_cb.state < RFC_MX_STATE_CONNECTED)) {
+ *bd_addr = multiplexer_cb.bd_addr;
return true;
}
- if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED) {
- found_port = false;
- p_mcb = &rfc_cb.port.rfc_mcb[xx];
- p_port = &rfc_cb.port.port[0];
+ if (multiplexer_cb.state == RFC_MX_STATE_CONNECTED) {
+ bool found_port = false;
+ tPORT* p_port = nullptr;
- for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++) {
- if (p_port->rfc.p_mcb == p_mcb) {
+ for (tPORT& port : rfc_cb.port.port) {
+ if (port.rfc.p_mcb == &multiplexer_cb) {
found_port = true;
+ p_port = &port;
break;
}
}
@@ -554,7 +544,7 @@
if ((!found_port) ||
(found_port && (p_port->rfc.state < RFC_STATE_OPENED))) {
/* Port is not established yet. */
- bd_addr = rfc_cb.port.rfc_mcb[xx].bd_addr;
+ *bd_addr = multiplexer_cb.bd_addr;
return true;
}
}
@@ -827,7 +817,7 @@
events &= p_port->ev_mask;
if (p_port->p_callback && events) {
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
}
}
return (PORT_SUCCESS);
@@ -894,7 +884,7 @@
events &= p_port->ev_mask;
if (p_port->p_callback && events) {
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
}
}
return (PORT_SUCCESS);
@@ -1118,7 +1108,7 @@
events &= p_port->ev_mask;
if ((p_port->p_callback != NULL) && events)
- (p_port->p_callback)(events, p_port->inx);
+ (p_port->p_callback)(events, p_port->handle);
}
return (PORT_SUCCESS);
@@ -1306,7 +1296,7 @@
osi_free(p_buf);
if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
- p_port->p_callback(PORT_EV_ERR, p_port->inx);
+ p_port->p_callback(PORT_EV_ERR, p_port->handle);
return (PORT_TX_FULL);
}
@@ -1384,7 +1374,7 @@
event &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
return (PORT_SUCCESS);
}
@@ -1539,7 +1529,7 @@
event &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
return (PORT_SUCCESS);
}
@@ -1650,7 +1640,7 @@
event &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
return (PORT_SUCCESS);
}
diff --git a/stack/rfcomm/port_int.h b/stack/rfcomm/port_int.h
index db7d0fd..ecd8fbc 100644
--- a/stack/rfcomm/port_int.h
+++ b/stack/rfcomm/port_int.h
@@ -90,8 +90,8 @@
typedef struct {
alarm_t* mcb_timer; /* MCB timer */
fixed_queue_t* cmd_q; /* Queue for command messages on this mux */
- uint8_t port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
- /* tPORT based on dlci */
+ uint8_t port_handles[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
+ /* port handles based on dlci */
RawAddress bd_addr; /* BD ADDR of the peer if initiator */
uint16_t lcid; /* Local cid used for this channel */
uint16_t peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
@@ -139,7 +139,7 @@
* Define control block containing information about PORT connection
*/
typedef struct {
- uint8_t inx; /* Index of this control block in the port_info array */
+ uint8_t handle; // Starting from 1, unique for this object
bool in_use; /* True when structure is allocated */
#define PORT_STATE_CLOSED 0
diff --git a/stack/rfcomm/port_rfc.cc b/stack/rfcomm/port_rfc.cc
index 5ec5631..3228f64 100644
--- a/stack/rfcomm/port_rfc.cc
+++ b/stack/rfcomm/port_rfc.cc
@@ -56,13 +56,11 @@
*
******************************************************************************/
int port_open_continue(tPORT* p_port) {
- tRFC_MCB* p_mcb;
-
RFCOMM_TRACE_EVENT("port_open_continue, p_port:%p", p_port);
/* Check if multiplexer channel has already been established */
- p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
- if (p_mcb == NULL) {
+ tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
+ if (p_mcb == nullptr) {
RFCOMM_TRACE_WARNING("port_open_continue no mx channel");
port_release_port(p_port);
return (PORT_NO_RESOURCES);
@@ -70,24 +68,22 @@
p_port->rfc.p_mcb = p_mcb;
- p_mcb->port_inx[p_port->dlci] = p_port->inx;
+ p_mcb->port_handles[p_port->dlci] = p_port->handle;
/* Connection is up and we know local and remote features, select MTU */
port_select_mtu(p_port);
if (p_mcb->state == RFC_MX_STATE_CONNECTED) {
- RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
+ RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu);
} else if ((p_mcb->state == RFC_MX_STATE_IDLE) ||
(p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA)) {
- /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */
- /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
- * connection */
- /* after disconnecting is completed */
+ // In RFC_MX_STATE_IDLE state, MX state machine will create connection
+ // In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
+ // connection after disconnecting is completed
RFCOMM_StartReq(p_mcb);
} else {
- /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
- /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
- */
+ // MX state machine ignores RFC_MX_EVENT_START_REQ in these states
+ // When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
RFCOMM_TRACE_DEBUG(
"port_open_continue: mx state(%d) mx channel is openning",
p_mcb->state);
@@ -128,7 +124,8 @@
if (p_mcb == NULL) return;
- RFCOMM_PortNegReq(p_mcb, p_port->dlci, &p_port->user_port_pars);
+ RFCOMM_PortParameterNegotiationRequest(p_mcb, p_port->dlci,
+ &p_port->user_port_pars);
}
/*******************************************************************************
@@ -162,14 +159,14 @@
if (p_port->ev_mask & PORT_EV_ERR) events |= PORT_EV_ERR;
if ((p_port->p_callback != NULL) && events)
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
/* Check if RFCOMM side has been closed while the message was queued */
if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED)) {
/* Call management callback function before calling port_release_port() to
* clear tPort */
if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_CLOSED, p_port->inx);
+ p_port->p_mgmt_callback(PORT_CLOSED, p_port->handle);
port_release_port(p_port);
} else {
@@ -188,37 +185,39 @@
*
******************************************************************************/
void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) {
- tPORT* p_port;
- int i;
bool no_ports_up = true;
- RFCOMM_TRACE_EVENT("PORT_StartCnf result:%d", result);
+ RFCOMM_TRACE_EVENT("%s: result %d", __func__, result);
- p_port = &rfc_cb.port.port[0];
- for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+ tPORT* p_port = &rfc_cb.port.port[0];
+ for (int i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
if (p_port->rfc.p_mcb == p_mcb) {
no_ports_up = false;
- if (result == RFCOMM_SUCCESS)
- RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
- else {
- RFCOMM_TRACE_WARNING("PORT_StartCnf failed result:%d", result);
+ if (result == RFCOMM_SUCCESS) {
+ RFCOMM_TRACE_EVENT("%s: dlci %d", __func__, p_port->dlci);
+ RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu);
+ } else {
+ RFCOMM_TRACE_WARNING("%s: failed result:%d", __func__, result);
/* Warning: result is also set to 4 when l2cap connection
fails due to l2cap connect cnf (no_resources) */
- if (result == HCI_ERR_PAGE_TIMEOUT)
+ if (result == HCI_ERR_PAGE_TIMEOUT) {
p_port->error = PORT_PAGE_TIMEOUT;
- else
+ } else {
p_port->error = PORT_START_FAILED;
+ }
rfc_release_multiplexer_channel(p_mcb);
/* Send event to the application */
- if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
- (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR)) {
+ (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->handle);
+ }
- if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_START_FAILED, p_port->inx);
+ if (p_port->p_mgmt_callback) {
+ p_port->p_mgmt_callback(PORT_START_FAILED, p_port->handle);
+ }
port_release_port(p_port);
}
@@ -272,12 +271,9 @@
******************************************************************************/
void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
uint8_t k) {
+ RFCOMM_TRACE_EVENT("%s: bd_addr=%s, dlci=%d, mtu=%d", __func__,
+ p_mcb->bd_addr.ToString().c_str(), dlci, mtu);
tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
- uint8_t our_cl;
- uint8_t our_k;
-
- RFCOMM_TRACE_EVENT("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
-
if (!p_port) {
/* This can be a first request for this port */
p_port = port_find_dlci_port(dlci);
@@ -292,9 +288,9 @@
rfc_check_mcb_active(p_mcb);
return;
}
- RFCOMM_TRACE_EVENT("%s: port_inx[dlci:%d]:%d->%d", __func__, dlci,
- p_mcb->port_inx[dlci], p_port->inx);
- p_mcb->port_inx[dlci] = p_port->inx;
+ RFCOMM_TRACE_EVENT("%s: port_handles[dlci:%d]:%d->%d", __func__, dlci,
+ p_mcb->port_handles[dlci], p_port->handle);
+ p_mcb->port_handles[dlci] = p_port->handle;
}
p_port->bd_addr = p_mcb->bd_addr;
@@ -329,6 +325,8 @@
/* after the DLCI is already established-- the PN in that case must have cl =
* 0. */
/* See RFCOMM spec 5.5.3 */
+ uint8_t our_cl;
+ uint8_t our_k;
if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1) {
our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
our_k = 0;
@@ -346,7 +344,7 @@
our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
our_k = 0;
}
- RFCOMM_ParNegRsp(p_mcb, dlci, p_port->mtu, our_cl, our_k);
+ RFCOMM_ParameterNegotiationResponse(p_mcb, dlci, p_port->mtu, our_cl, our_k);
}
/*******************************************************************************
@@ -362,12 +360,13 @@
******************************************************************************/
void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
uint8_t k) {
- tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-
RFCOMM_TRACE_EVENT("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu,
cl, k);
-
- if (!p_port) return;
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (!p_port) {
+ LOG(WARNING) << __func__ << ": port is null for " << p_mcb->bd_addr;
+ return;
+ }
/* Flow control mechanism not set yet. Negotiate flow control mechanism. */
if (p_mcb->flow == PORT_FC_UNDEFINED) {
@@ -377,19 +376,17 @@
if ((PORT_FC_DEFAULT == PORT_FC_TS710) &&
(cl == RFCOMM_PN_CONV_LAYER_CBFC_R)) {
RFCOMM_TRACE_WARNING("%s, negotiation fails, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_send_disc(p_mcb, p_port->dlci);
rfc_port_closed(p_port);
return;
- }
- /* Our stack is configured for credit-based and they responded with
- credit-based. */
- else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+ } else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+ // Our stack is configured for credit-based and they responded with
+ // credit-based.
p_mcb->flow = PORT_FC_CREDIT;
- }
- /* They responded with any other value. Treat this as negotiation to
- TS07.10. */
- else {
+ } else {
+ // They responded with any other value. Treat this as negotiation to
+ // TS07.10.
p_mcb->flow = PORT_FC_TS710;
}
}
@@ -436,7 +433,7 @@
RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_ERROR);
return;
}
- p_mcb->port_inx[dlci] = p_port->inx;
+ p_mcb->port_handles[dlci] = p_port->handle;
}
/* If L2CAP's mtu less then RFCOMM's take it */
@@ -450,10 +447,10 @@
/* This is the server side. If application wants to know when connection */
/* is established, thats the place */
if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
- (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle);
if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+ p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle);
p_port->state = PORT_STATE_OPENED;
}
@@ -490,10 +487,10 @@
rfc_timer_stop(p_mcb);
if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
- (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle);
if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+ p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle);
p_port->state = PORT_STATE_OPENED;
@@ -501,7 +498,8 @@
*/
if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING) ||
(p_port->uuid == UUID_SERVCLASS_FAX))
- RFCOMM_PortNegReq(p_port->rfc.p_mcb, p_port->dlci, NULL);
+ RFCOMM_PortParameterNegotiationRequest(p_port->rfc.p_mcb, p_port->dlci,
+ NULL);
else
RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
}
@@ -527,15 +525,15 @@
/* This can be a first request for this port */
p_port = port_find_dlci_port(dlci);
if (!p_port) {
- RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, 0);
+ RFCOMM_PortParameterNegotiationResponse(p_mcb, dlci, p_pars, 0);
return;
}
- p_mcb->port_inx[dlci] = p_port->inx;
+ p_mcb->port_handles[dlci] = p_port->handle;
}
/* Check if the flow control is acceptable on local side */
p_port->peer_port_pars = *p_pars;
- RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, param_mask);
+ RFCOMM_PortParameterNegotiationResponse(p_mcb, dlci, p_pars, param_mask);
}
/*******************************************************************************
@@ -596,9 +594,9 @@
p_port->peer_ctrl = *p_pars;
- if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) {
RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
- else {
+ } else {
/* If this is the first time we received control RFCOMM is connected */
if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)) {
event |= (PORT_EV_CONNECTED & p_port->ev_mask);
@@ -615,7 +613,7 @@
/* execute call back function only if the application is registered for events
*/
- if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle);
RFCOMM_TRACE_EVENT(
"PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
@@ -655,7 +653,7 @@
/* execute call back function only if the application is registered for events
*/
- if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle);
}
/*******************************************************************************
@@ -683,7 +681,7 @@
if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK)) event |= PORT_EV_ERR;
if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
- p_port->p_callback((p_port->ev_mask & event), p_port->inx);
+ p_port->p_callback((p_port->ev_mask & event), p_port->handle);
}
/*******************************************************************************
@@ -695,12 +693,10 @@
*
******************************************************************************/
void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci) {
+ VLOG(1) << __func__ << ": dlci=" << std::to_string(dlci)
+ << ", bd_addr=" << p_mcb->bd_addr;
tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-
- RFCOMM_TRACE_EVENT("PORT_DlcReleaseInd");
-
if (!p_port) return;
-
port_rfc_closed(p_port, PORT_CLOSED);
}
@@ -775,7 +771,7 @@
* receive data */
if (p_port->p_data_co_callback) {
/* Another packet is delivered to user. Send credits to peer if required */
- if (p_port->p_data_co_callback(p_port->inx, (uint8_t*)p_buf, -1,
+ if (p_port->p_data_co_callback(p_port->handle, (uint8_t*)p_buf, -1,
DATA_CO_CALLBACK_TYPE_INCOMING)) {
port_flow_control_peer(p_port, true, 1);
} else {
@@ -788,8 +784,8 @@
if (p_port->p_data_callback) {
/* Another packet is delivered to user. Send credits to peer if required */
port_flow_control_peer(p_port, true, 1);
- p_port->p_data_callback(p_port->inx, (uint8_t*)(p_buf + 1) + p_buf->offset,
- p_buf->len);
+ p_port->p_data_callback(p_port->handle,
+ (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
osi_free(p_buf);
return;
}
@@ -837,7 +833,7 @@
/* Mask out all events that are not of interest to user */
events &= p_port->ev_mask;
- if (p_port->p_callback && events) p_port->p_callback(events, p_port->inx);
+ if (p_port->p_callback && events) p_port->p_callback(events, p_port->handle);
}
/*******************************************************************************
@@ -884,7 +880,8 @@
events &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && events) (p_port->p_callback)(events, p_port->inx);
+ if (p_port->p_callback && events)
+ (p_port->p_callback)(events, p_port->handle);
/* If DLCI is not 0 event applies to one port only */
if (dlci != 0) break;
@@ -962,7 +959,7 @@
p_port->rfc.state = RFC_STATE_CLOSED;
if (p_mcb) {
- p_mcb->port_inx[p_port->dlci] = 0;
+ p_mcb->port_handles[p_port->dlci] = 0;
/* If there are no more ports opened on this MCB release it */
rfc_check_mcb_active(p_mcb);
@@ -993,17 +990,19 @@
}
if ((p_port->p_callback != NULL) && events)
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
- if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->inx);
+ if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->handle);
p_port->rfc.state = RFC_STATE_CLOSED;
- RFCOMM_TRACE_WARNING(
- "%s: RFCOMM connection closed, index=%d, state=%d reason=%s[%d], "
- "UUID=%04X, bd_addr=%s, is_server=%d",
- __func__, p_port->inx, p_port->state, PORT_GetResultString(res), res,
- p_port->uuid, p_port->bd_addr.ToString().c_str(), p_port->is_server);
+ LOG(INFO) << __func__ << ": RFCOMM connection closed, index="
+ << std::to_string(p_port->handle)
+ << ", state=" << std::to_string(p_port->state)
+ << ", reason=" << PORT_GetResultString(res) << "["
+ << std::to_string(res) << "], UUID=" << loghex(p_port->uuid)
+ << ", bd_addr=" << p_port->bd_addr
+ << ", is_server=" << p_port->is_server;
port_release_port(p_port);
}
diff --git a/stack/rfcomm/port_utils.cc b/stack/rfcomm/port_utils.cc
index 9dc05c8..7798375 100644
--- a/stack/rfcomm/port_utils.cc
+++ b/stack/rfcomm/port_utils.cc
@@ -61,36 +61,36 @@
*
******************************************************************************/
tPORT* port_allocate_port(uint8_t dlci, const RawAddress& bd_addr) {
- tPORT* p_port = &rfc_cb.port.port[0];
- uint8_t xx, yy;
-
- for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
- if (yy >= MAX_RFC_PORTS) yy = 0;
-
- p_port = &rfc_cb.port.port[yy];
+ uint8_t port_index = rfc_cb.rfc.last_port_index + static_cast<uint8_t>(1);
+ // Loop at most MAX_RFC_PORTS items
+ for (int loop_counter = 0; loop_counter < MAX_RFC_PORTS;
+ loop_counter++, port_index++) {
+ if (port_index >= MAX_RFC_PORTS) {
+ port_index = 0;
+ }
+ tPORT* p_port = &rfc_cb.port.port[port_index];
if (!p_port->in_use) {
+ // Assume that we already called port_release_port on this
memset(p_port, 0, sizeof(tPORT));
-
p_port->in_use = true;
- p_port->inx = yy + 1;
-
- /* During the open set default state for the port connection */
+ // handle is a port handle starting from 1
+ p_port->handle = port_index + static_cast<uint8_t>(1);
+ // During the open set default state for the port connection
port_set_defaults(p_port);
-
p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
- rfc_cb.rfc.last_port = yy;
-
p_port->dlci = dlci;
p_port->bd_addr = bd_addr;
-
- RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy,
- p_port, rfc_cb.rfc.last_port);
- VLOG(1) << __func__ << ": bd_addr:" << bd_addr;
- return (p_port);
+ rfc_cb.rfc.last_port_index = port_index;
+ RFCOMM_TRACE_DEBUG(
+ "%s: rfc_cb.port.port[%d]:%p chosen, "
+ "last_port_index:%d, bd_addr=%s",
+ __func__, port_index, p_port, rfc_cb.rfc.last_port_index,
+ bd_addr.ToString().c_str());
+ return p_port;
}
}
-
- /* If here, no free PORT found */
+ LOG(WARNING) << __func__ << ": running out of free ports for dlci "
+ << std::to_string(dlci) << ", bd_addr " << bd_addr;
return nullptr;
}
@@ -146,7 +146,7 @@
packet_size = btm_get_max_packet_size(p_port->bd_addr);
if (packet_size == 0) {
/* something is very wrong */
- RFCOMM_TRACE_WARNING("port_select_mtu bad packet size");
+ LOG(WARNING) << __func__ << ": bad packet size 0 for" << p_port->bd_addr;
p_port->mtu = RFCOMM_DEFAULT_MTU;
} else {
/* We try to negotiate MTU that each packet can be split into whole
@@ -166,17 +166,16 @@
p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size *
packet_size) -
RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
- RFCOMM_TRACE_DEBUG(
- "port_select_mtu selected %d based on connection speed",
- p_port->mtu);
+ RFCOMM_TRACE_DEBUG("%s: selected %d based on connection speed",
+ __func__, p_port->mtu);
} else {
p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
- RFCOMM_TRACE_DEBUG(
- "port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+ RFCOMM_TRACE_DEBUG("%s: selected %d based on l2cap PDU size", __func__,
+ p_port->mtu);
}
}
} else {
- RFCOMM_TRACE_DEBUG("port_select_mtu application selected %d", p_port->mtu);
+ RFCOMM_TRACE_DEBUG("%s: application selected %d", __func__, p_port->mtu);
}
p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM)
@@ -188,7 +187,7 @@
if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM)
p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
RFCOMM_TRACE_DEBUG(
- "port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
+ "%s: credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d", __func__,
p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
}
@@ -226,7 +225,7 @@
if (p_port->rfc.state == RFC_STATE_CLOSED) {
if (p_port->rfc.p_mcb) {
- p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
+ p_port->rfc.p_mcb->port_handles[p_port->dlci] = 0;
/* If there are no more ports opened on this MCB release it */
rfc_check_mcb_active(p_port->rfc.p_mcb);
@@ -242,7 +241,8 @@
mutex_global_unlock();
if (p_port->keep_port_handle) {
- RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
+ RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__,
+ p_port->handle);
/* save event mask and callback */
uint32_t mask = p_port->ev_mask;
@@ -264,7 +264,7 @@
p_port->local_ctrl.modem_signal = p_port->default_signal_state;
p_port->bd_addr = RawAddress::kAny;
} else {
- RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
+ RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->handle);
alarm_free(p_port->rfc.port_timer);
memset(p_port, 0, sizeof(tPORT));
}
@@ -317,15 +317,14 @@
return nullptr;
}
- uint8_t inx = p_mcb->port_inx[dlci];
- if (inx == 0) {
- LOG(WARNING) << __func__
- << ": Cannot find allocated RFCOMM app port for DLCI "
- << std::to_string(dlci) << " on " << p_mcb->bd_addr
- << ", p_mcb=" << p_mcb;
+ uint8_t handle = p_mcb->port_handles[dlci];
+ if (handle == 0) {
+ LOG(INFO) << __func__ << ": Cannot find allocated RFCOMM app port for DLCI "
+ << std::to_string(dlci) << " on " << p_mcb->bd_addr
+ << ", p_mcb=" << p_mcb;
return nullptr;
}
- return &rfc_cb.port.port[inx - 1];
+ return &rfc_cb.port.port[handle - 1];
}
/*******************************************************************************
diff --git a/stack/rfcomm/rfc_int.h b/stack/rfcomm/rfc_int.h
index 05afa9d..22aab66 100644
--- a/stack/rfcomm/rfc_int.h
+++ b/stack/rfcomm/rfc_int.h
@@ -56,18 +56,23 @@
extern void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci);
-extern void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu);
-extern void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
- uint8_t cl, uint8_t k);
+extern void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu);
+extern void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu, uint8_t cl,
+ uint8_t k);
extern void RFCOMM_TestReq(uint8_t* p_data, uint16_t len);
extern void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool state);
-extern void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci,
- tPORT_STATE* p_pars);
-extern void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci,
- tPORT_STATE* p_pars, uint16_t param_mask);
+extern void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb,
+ uint8_t dlci,
+ tPORT_STATE* p_pars);
+extern void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb,
+ uint8_t dlci,
+ tPORT_STATE* p_pars,
+ uint16_t param_mask);
extern void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci,
tPORT_CTRL* p_pars);
@@ -221,7 +226,7 @@
tRFC_MCB* p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS];
bool peer_rx_disabled; /* If true peer sent FCOFF */
uint8_t last_mux; /* Last mux allocated */
- uint8_t last_port; /* Last port allocated */
+ uint8_t last_port_index; // Index of last port allocated in rfc_cb.port
} tRFCOMM_CB;
/* Main Control Block for the RFCOMM Layer (PORT and RFC) */
diff --git a/stack/rfcomm/rfc_l2cap_if.cc b/stack/rfcomm/rfc_l2cap_if.cc
index a20f399..380f5bf 100644
--- a/stack/rfcomm/rfc_l2cap_if.cc
+++ b/stack/rfcomm/rfc_l2cap_if.cc
@@ -110,14 +110,14 @@
} else {
/* we cannot accept connection request from peer at this state */
/* don't update lcid */
- p_mcb = NULL;
+ p_mcb = nullptr;
}
} else {
/* store mcb even if null */
rfc_save_lcid_mcb(p_mcb, lcid);
}
- if (p_mcb == NULL) {
+ if (p_mcb == nullptr) {
L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
return;
}
@@ -163,13 +163,13 @@
/* update direction bit */
for (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
- uint8_t idx = p_mcb->port_inx[i];
- if (idx != 0) {
- p_mcb->port_inx[i] = 0;
- p_mcb->port_inx[i + 1] = idx;
- rfc_cb.port.port[idx - 1].dlci += 1;
- RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", idx, i,
- rfc_cb.port.port[idx - 1].dlci);
+ uint8_t handle = p_mcb->port_handles[i];
+ if (handle != 0) {
+ p_mcb->port_handles[i] = 0;
+ p_mcb->port_handles[i + 1] = handle;
+ rfc_cb.port.port[handle - 1].dlci += 1;
+ RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", handle,
+ i, rfc_cb.port.port[handle - 1].dlci);
}
}
@@ -254,17 +254,16 @@
*
******************************************************************************/
void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) {
+ VLOG(1) << __func__ << ": lcid=" << loghex(lcid)
+ << ", is_conf_needed=" << is_conf_needed;
tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
-
if (is_conf_needed) {
L2CA_DisconnectRsp(lcid);
}
-
if (!p_mcb) {
- RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid);
+ LOG(WARNING) << __func__ << ": no mcb for lcid " << loghex(lcid);
return;
}
-
rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr);
}
@@ -299,7 +298,7 @@
}
if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
- RFCOMM_TRACE_DEBUG("%s: Handle multiplexer event %d, p_mcb=%p", __func__,
+ RFCOMM_TRACE_DEBUG("%s: handle multiplexer event %d, p_mcb=%p", __func__,
event, p_mcb);
/* Take special care of the Multiplexer Control Messages */
if (event == RFC_EVENT_UIH) {
@@ -341,10 +340,11 @@
osi_free(p_buf);
return;
}
- RFCOMM_TRACE_DEBUG("%s: port_inx[dlci=%d]:%d->%d, p_mcb=%p", __func__,
+ RFCOMM_TRACE_DEBUG("%s: port_handles[dlci=%d]:%d->%d, p_mcb=%p", __func__,
rfc_cb.rfc.rx_frame.dlci,
- p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci], p_port->inx);
- p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+ p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci],
+ p_port->handle);
+ p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci] = p_port->handle;
p_port->rfc.p_mcb = p_mcb;
}
@@ -419,6 +419,14 @@
*
******************************************************************************/
void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) {
- if (lcid < L2CAP_BASE_APPL_CID) return;
- rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
+ if (lcid < L2CAP_BASE_APPL_CID) {
+ LOG(ERROR) << __func__ << ": LCID " << lcid << " is too small";
+ return;
+ }
+ auto mcb_index = static_cast<size_t>(lcid - L2CAP_BASE_APPL_CID);
+ if (mcb_index >= MAX_L2CAP_CHANNELS) {
+ LOG(ERROR) << __func__ << ": LCID " << lcid << " is too large";
+ return;
+ }
+ rfc_cb.rfc.p_rfc_lcid_mcb[mcb_index] = p_mcb;
}
diff --git a/stack/rfcomm/rfc_mx_fsm.cc b/stack/rfcomm/rfc_mx_fsm.cc
index dfab62f..4fbf870 100644
--- a/stack/rfcomm/rfc_mx_fsm.cc
+++ b/stack/rfcomm/rfc_mx_fsm.cc
@@ -69,6 +69,9 @@
*
******************************************************************************/
void rfc_mx_sm_execute(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+ CHECK(p_mcb != nullptr) << __func__ << ": NULL mcb for event " << event;
+ VLOG(1) << __func__ << ": bd_addr=" << p_mcb->bd_addr
+ << ", state=" << std::to_string(p_mcb->state) << ", event=" << event;
switch (p_mcb->state) {
case RFC_MX_STATE_IDLE:
rfc_mx_sm_state_idle(p_mcb, event, p_data);
@@ -112,7 +115,7 @@
*
******************************************************************************/
void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_idle - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ: {
/* Initialize L2CAP MTU */
@@ -120,7 +123,9 @@
uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
if (lcid == 0) {
- rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+ LOG(ERROR) << __func__ << ": failed to open L2CAP channel for "
+ << p_mcb->bd_addr;
+ rfc_save_lcid_mcb(nullptr, p_mcb->lcid);
p_mcb->lcid = 0;
PORT_StartCnf(p_mcb, RFCOMM_ERROR);
return;
@@ -182,7 +187,7 @@
******************************************************************************/
void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, uint16_t event,
void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
@@ -218,7 +223,7 @@
/* we gave up outgoing connection request then try peer's request */
if (p_mcb->pending_lcid) {
uint16_t i;
- uint8_t idx;
+ uint8_t handle;
RFCOMM_TRACE_DEBUG(
"RFCOMM MX retry as acceptor in collision case - evt:%d in "
@@ -233,13 +238,13 @@
/* update direction bit */
for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
- idx = p_mcb->port_inx[i];
- if (idx != 0) {
- p_mcb->port_inx[i] = 0;
- p_mcb->port_inx[i + 1] = idx;
- rfc_cb.port.port[idx - 1].dlci += 1;
+ handle = p_mcb->port_handles[i];
+ if (handle != 0) {
+ p_mcb->port_handles[i] = 0;
+ p_mcb->port_handles[i + 1] = handle;
+ rfc_cb.port.port[handle - 1].dlci += 1;
RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i,
- rfc_cb.port.port[idx - 1].dlci);
+ rfc_cb.port.port[handle - 1].dlci);
}
}
@@ -264,7 +269,7 @@
*
******************************************************************************/
void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_configure - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
case RFC_MX_EVENT_CONN_CNF:
@@ -286,6 +291,8 @@
return;
case RFC_EVENT_TIMEOUT:
+ LOG(ERROR) << __func__ << ": L2CAP configuration timeout for "
+ << p_mcb->bd_addr;
p_mcb->state = RFC_MX_STATE_IDLE;
L2CA_DisconnectReq(p_mcb->lcid);
@@ -308,7 +315,7 @@
******************************************************************************/
void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
UNUSED_ATTR void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
case RFC_MX_EVENT_CONN_CNF:
@@ -368,7 +375,7 @@
*
******************************************************************************/
void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_DISC_IND:
p_mcb->state = RFC_MX_STATE_IDLE;
@@ -431,7 +438,7 @@
******************************************************************************/
void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, uint16_t event,
UNUSED_ATTR void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_connected - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_EVENT_TIMEOUT:
@@ -475,7 +482,7 @@
void* p_data) {
BT_HDR* p_buf;
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_EVENT_UA:
case RFC_EVENT_DM:
@@ -549,12 +556,8 @@
*
******************************************************************************/
static void rfc_mx_send_config_req(tRFC_MCB* p_mcb) {
- tL2CAP_CFG_INFO cfg;
-
RFCOMM_TRACE_EVENT("rfc_mx_send_config_req");
-
- memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
+ tL2CAP_CFG_INFO cfg = {};
cfg.mtu_present = true;
cfg.mtu = L2CAP_MTU_SIZE;
@@ -580,11 +583,15 @@
*
******************************************************************************/
static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
- RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg,
+ RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x result:%d ", p_cfg,
(p_cfg) ? p_cfg->result : 0);
if (p_cfg->result != L2CAP_CFG_OK) {
+ LOG(ERROR) << __func__ << ": failed to configure L2CAP for "
+ << p_mcb->bd_addr;
if (p_mcb->is_initiator) {
+ LOG(ERROR) << __func__ << ": disconnect L2CAP due to config failure for "
+ << p_mcb->bd_addr;
PORT_StartCnf(p_mcb, p_cfg->result);
L2CA_DisconnectReq(p_mcb->lcid);
}
@@ -619,10 +626,11 @@
static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
/* Save peer L2CAP MTU if present */
/* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
- if (p_cfg->mtu_present)
+ if (p_cfg->mtu_present) {
p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
- else
+ } else {
p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+ }
p_cfg->mtu_present = false;
p_cfg->flush_to_present = false;
diff --git a/stack/rfcomm/rfc_port_fsm.cc b/stack/rfcomm/rfc_port_fsm.cc
index 4ff4628..9c62989 100644
--- a/stack/rfcomm/rfc_port_fsm.cc
+++ b/stack/rfcomm/rfc_port_fsm.cc
@@ -64,11 +64,11 @@
*
******************************************************************************/
void rfc_port_sm_execute(tPORT* p_port, uint16_t event, void* p_data) {
- if (!p_port) {
- RFCOMM_TRACE_WARNING("NULL port event %d", event);
- return;
- }
-
+ CHECK(p_port != nullptr) << __func__ << ": NULL port event " << event;
+ VLOG(1) << __func__ << ": BD_ADDR=" << p_port->bd_addr
+ << ", PORT=" << std::to_string(p_port->handle)
+ << ", STATE=" << std::to_string(p_port->rfc.state)
+ << ", EVENT=" << event;
switch (p_port->rfc.state) {
case RFC_STATE_CLOSED:
rfc_port_sm_state_closed(p_port, event, p_data);
@@ -143,7 +143,8 @@
return;
case RFC_EVENT_DM:
- RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+ RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -194,7 +195,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -210,7 +211,8 @@
return;
case RFC_EVENT_DM:
- RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+ RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+ p_port->handle);
p_port->rfc.p_mcb->is_disc_initiator = true;
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
@@ -219,7 +221,7 @@
case RFC_EVENT_DISC:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DISC, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
@@ -282,7 +284,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
rfc_port_closed(p_port);
return;
@@ -339,7 +341,8 @@
case RFC_EVENT_SEC_COMPLETE:
if (*((uint8_t*)p_data) != BTM_SUCCESS) {
RFCOMM_TRACE_ERROR("%s, RFC_EVENT_SEC_COMPLETE, index=%d, result=%d",
- __func__, event, p_port->inx, *((uint8_t*)p_data));
+ __func__, event, p_port->handle,
+ *((uint8_t*)p_data));
p_port->rfc.p_mcb->is_disc_initiator = true;
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, 0,
RFCOMM_SECURITY_ERR);
@@ -359,7 +362,7 @@
case RFC_EVENT_CLOSE:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLOSE, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
rfc_port_closed(p_port);
return;
@@ -403,7 +406,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -435,7 +438,8 @@
return;
case RFC_EVENT_DM:
- RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+ RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+ p_port->handle);
PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
rfc_port_closed(p_port);
return;
@@ -484,7 +488,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__, event,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -498,7 +502,7 @@
case RFC_EVENT_DM:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM|RFC_EVENT_UA[%d], index=%d",
- __func__, event, p_port->inx);
+ __func__, event, p_port->handle);
rfc_port_closed(p_port);
return;
@@ -517,7 +521,7 @@
case RFC_EVENT_TIMEOUT:
RFCOMM_TRACE_ERROR("%s, RFC_EVENT_TIMEOUT, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
}
@@ -545,7 +549,9 @@
*
******************************************************************************/
void rfc_process_pn(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) {
- tPORT* p_port;
+ RFCOMM_TRACE_DEBUG("%s: is_initiator=%d, is_cmd=%d, state=%d, bd_addr=%s",
+ __func__, p_mcb->is_initiator, is_command, p_mcb->state,
+ p_mcb->bd_addr.ToString().c_str());
uint8_t dlci = p_frame->dlci;
if (is_command) {
@@ -563,7 +569,7 @@
return;
}
/* If we are not awaiting response just ignore it */
- p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if ((p_port == nullptr) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) {
LOG(WARNING) << ": Ignore unwanted response, p_mcb=" << p_mcb
<< ", bd_addr=" << p_mcb->bd_addr
diff --git a/stack/rfcomm/rfc_port_if.cc b/stack/rfcomm/rfc_port_if.cc
index 2ce5f9e..097d774 100644
--- a/stack/rfcomm/rfc_port_if.cc
+++ b/stack/rfcomm/rfc_port_if.cc
@@ -115,7 +115,7 @@
/*******************************************************************************
*
- * Function RFCOMM_ParNegReq
+ * Function RFCOMM_ParameterNegotiationRequest
*
* Description This function is called by the user app to start
* DLC parameter negotiation. Port emulation can send this
@@ -124,7 +124,8 @@
* block.
*
******************************************************************************/
-void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
+void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu) {
uint8_t flow;
uint8_t cl;
uint8_t k;
@@ -166,14 +167,14 @@
/*******************************************************************************
*
- * Function RFCOMM_ParNegRsp
+ * Function RFCOMM_ParameterNegotiationResponse
*
* Description This function is called by the user app to acknowledge
* DLC parameter negotiation.
*
******************************************************************************/
-void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
- uint8_t k) {
+void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu, uint8_t cl, uint8_t k) {
if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
/* Send Parameter Negotiation Response UIH frame */
@@ -182,7 +183,7 @@
/*******************************************************************************
*
- * Function RFCOMM_PortNegReq
+ * Function RFCOMM_PortParameterNegotiationRequest
*
* Description This function is called by the user app to start
* Remote Port parameter negotiation. Port emulation can
@@ -191,7 +192,8 @@
* control block.
*
******************************************************************************/
-void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
+void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_STATE* p_pars) {
if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
return;
@@ -215,14 +217,15 @@
/*******************************************************************************
*
- * Function RFCOMM_PortNegRsp
+ * Function RFCOMM_PortParameterNegotiationResponse
*
* Description This function is called by the user app to acknowledge
* Port parameters negotiation.
*
******************************************************************************/
-void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
- uint16_t param_mask) {
+void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_STATE* p_pars,
+ uint16_t param_mask) {
if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
diff --git a/stack/rfcomm/rfc_ts_frames.cc b/stack/rfcomm/rfc_ts_frames.cc
index 0c8ce09..51fbcac 100644
--- a/stack/rfcomm/rfc_ts_frames.cc
+++ b/stack/rfcomm/rfc_ts_frames.cc
@@ -153,14 +153,19 @@
uint8_t credits;
p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
- if (p_buf->len > 127) p_buf->offset--;
+ if (p_buf->len > 127) {
+ p_buf->offset--;
+ }
- if (dlci)
+ if (dlci) {
credits = (uint8_t)p_buf->layer_specific;
- else
+ } else {
credits = 0;
+ }
- if (credits) p_buf->offset--;
+ if (credits) {
+ p_buf->offset--;
+ }
p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
@@ -218,11 +223,11 @@
** We will use the fact that we reply in the same context so rx_frame can
*still be used.
*/
- if (is_command)
+ if (is_command) {
*p_data++ = RFCOMM_PN_PRIORITY_0;
- else
+ } else {
*p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
-
+ }
*p_data++ = RFCOMM_T1_DSEC;
*p_data++ = mtu & 0xFF;
*p_data++ = mtu >> 8;
@@ -527,8 +532,9 @@
p_frame->credit = *p_data++;
p_buf->len--;
p_buf->offset++;
- } else
+ } else {
p_frame->credit = 0;
+ }
if (p_buf->len != len) {
RFCOMM_TRACE_ERROR("Bad Length2 %d %d", p_buf->len, len);
@@ -589,8 +595,9 @@
/* we assume that this is ok to allow bad implementations to work */
RFCOMM_TRACE_ERROR("Bad UIH - response");
return (RFC_EVENT_UIH);
- } else
+ } else {
return (RFC_EVENT_UIH);
+ }
}
return (RFC_EVENT_BAD_FRAME);
@@ -609,7 +616,6 @@
MX_FRAME* p_rx_frame = &rfc_cb.rfc.rx_frame;
uint16_t length = p_buf->len;
uint8_t ea, cr, mx_len;
- bool is_command;
p_rx_frame->ea = *p_data & RFCOMM_EA;
p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
@@ -625,7 +631,7 @@
length--;
- is_command = p_rx_frame->cr;
+ bool is_command = p_rx_frame->cr;
ea = *p_data & RFCOMM_EA;
@@ -644,8 +650,8 @@
return;
}
- RFCOMM_TRACE_DEBUG("%s: type=%d, p_mcb=%p", __func__, p_rx_frame->type,
- p_mcb);
+ RFCOMM_TRACE_DEBUG("%s: type=0x%02x, bd_addr=%s", __func__, p_rx_frame->type,
+ p_mcb->bd_addr.ToString().c_str());
switch (p_rx_frame->type) {
case RFCOMM_MX_PN:
if (length != RFCOMM_MX_PN_LEN) {
diff --git a/stack/rfcomm/rfc_utils.cc b/stack/rfcomm/rfc_utils.cc
index 74e336a..616e24e 100644
--- a/stack/rfcomm/rfc_utils.cc
+++ b/stack/rfcomm/rfc_utils.cc
@@ -285,7 +285,7 @@
uint16_t i;
for (i = 0; i < RFCOMM_MAX_DLCI; i++) {
- if (p_mcb->port_inx[i] != 0) {
+ if (p_mcb->port_handles[i] != 0) {
p_mcb->is_disc_initiator = false;
return;
}
@@ -353,7 +353,7 @@
/* If multiplexer channel was up mark it as down */
if (p_mcb) {
- p_mcb->port_inx[p_port->dlci] = 0;
+ p_mcb->port_handles[p_port->dlci] = 0;
/* If there are no more ports opened on this MCB release it */
rfc_check_mcb_active(p_mcb);
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index dc45690..0cc1a59 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -18,6 +18,7 @@
#include <string.h>
#include "btif_common.h"
+#include "btif_storage.h"
#include "device/include/interop.h"
#include "internal_include/bt_target.h"
#include "stack/btm/btm_int.h"
@@ -104,7 +105,7 @@
case SMP_IO_CAP_REQ_EVT:
cb_data.io_req.auth_req = p_cb->peer_auth_req;
cb_data.io_req.oob_data = SMP_OOB_NONE;
- cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS;
+ cb_data.io_req.io_cap = btif_storage_get_local_io_caps_ble();
cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
cb_data.io_req.init_keys = p_cb->local_i_key;
cb_data.io_req.resp_keys = p_cb->local_r_key;
diff --git a/stack/test/common/mock_btm_layer.cc b/stack/test/common/mock_btm_layer.cc
new file mode 100644
index 0000000..1405c55
--- /dev/null
+++ b/stack/test/common/mock_btm_layer.cc
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "mock_btm_layer.h"
+
+static bluetooth::manager::MockBtmSecurityInternalInterface*
+ btm_security_internal_interface = nullptr;
+
+void bluetooth::manager::SetMockSecurityInternalInterface(
+ MockBtmSecurityInternalInterface* mock_btm_security_internal_interface) {
+ btm_security_internal_interface = mock_btm_security_internal_interface;
+}
+
+void btm_sec_abort_access_req(const RawAddress& bd_addr) {
+ btm_security_internal_interface->AbortAccessRequest(bd_addr);
+}
+
+tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, uint16_t psm,
+ bool is_originator, uint32_t mx_proto_id,
+ uint32_t mx_chan_id,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data) {
+ return btm_security_internal_interface->MultiplexingProtocolAccessRequest(
+ bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback,
+ p_ref_data);
+}
+
+uint16_t btm_get_max_packet_size(const RawAddress& addr) {
+ return RFCOMM_DEFAULT_MTU;
+}
\ No newline at end of file
diff --git a/stack/test/common/mock_btm_layer.h b/stack/test/common/mock_btm_layer.h
new file mode 100644
index 0000000..45f32d1
--- /dev/null
+++ b/stack/test/common/mock_btm_layer.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "btm_int.h"
+
+namespace bluetooth {
+namespace manager {
+
+class BtmSecurityInternalInterface {
+ public:
+ virtual void AbortAccessRequest(const RawAddress& bd_addr) = 0;
+ virtual tBTM_STATUS MultiplexingProtocolAccessRequest(
+ const RawAddress& bd_addr, uint16_t psm, bool is_originator,
+ uint32_t mx_proto_id, uint32_t mx_chan_id, tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data) = 0;
+ virtual ~BtmSecurityInternalInterface() = default;
+};
+
+class MockBtmSecurityInternalInterface : public BtmSecurityInternalInterface {
+ public:
+ MOCK_METHOD1(AbortAccessRequest, void(const RawAddress& bd_addr));
+ MOCK_METHOD7(MultiplexingProtocolAccessRequest,
+ tBTM_STATUS(const RawAddress& bd_addr, uint16_t psm,
+ bool is_originator, uint32_t mx_proto_id,
+ uint32_t mx_chan_id, tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data));
+};
+
+/**
+ * Set the {@link MockBtmSecurityInternalInterface} for testing
+ *
+ * @param mock_btm_security_internal_interface pointer to mock btm security
+ * internal interface, could be null
+ */
+void SetMockSecurityInternalInterface(
+ MockBtmSecurityInternalInterface* mock_btm_security_internal_interface);
+
+} // namespace manager
+} // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/common/mock_btu_layer.cc b/stack/test/common/mock_btu_layer.cc
new file mode 100644
index 0000000..f5bbf7a
--- /dev/null
+++ b/stack/test/common/mock_btu_layer.cc
@@ -0,0 +1,21 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/message_loop/message_loop.h>
+
+base::MessageLoop* get_message_loop() { return nullptr; }
\ No newline at end of file
diff --git a/stack/test/common/mock_l2cap_layer.cc b/stack/test/common/mock_l2cap_layer.cc
new file mode 100644
index 0000000..9f08d56
--- /dev/null
+++ b/stack/test/common/mock_l2cap_layer.cc
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include "mock_l2cap_layer.h"
+
+static bluetooth::l2cap::MockL2capInterface* l2cap_interface = nullptr;
+
+void bluetooth::l2cap::SetMockInterface(
+ MockL2capInterface* mock_l2cap_interface) {
+ l2cap_interface = mock_l2cap_interface;
+}
+
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+ VLOG(1) << __func__ << ": psm=" << psm << ", p_cb_info=" << p_cb_info;
+ return l2cap_interface->Register(psm, p_cb_info);
+}
+
+uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& bd_addr) {
+ return l2cap_interface->ConnectRequest(psm, bd_addr);
+}
+
+bool L2CA_ConnectRsp(const RawAddress& bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status) {
+ return l2cap_interface->ConnectResponse(bd_addr, id, lcid, result, status);
+}
+
+bool L2CA_DisconnectReq(uint16_t cid) {
+ return l2cap_interface->DisconnectRequest(cid);
+}
+
+bool L2CA_DisconnectRsp(uint16_t cid) {
+ return l2cap_interface->DisconnectResponse(cid);
+}
+
+bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ return l2cap_interface->ConfigRequest(cid, p_cfg);
+}
+
+bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ return l2cap_interface->ConfigResponse(cid, p_cfg);
+}
+
+uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+ return l2cap_interface->DataWrite(cid, p_data);
+}
diff --git a/stack/test/common/mock_l2cap_layer.h b/stack/test/common/mock_l2cap_layer.h
new file mode 100644
index 0000000..78c8a9c
--- /dev/null
+++ b/stack/test/common/mock_l2cap_layer.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "l2c_api.h"
+
+namespace bluetooth {
+namespace l2cap {
+
+class L2capInterface {
+ public:
+ virtual uint16_t Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) = 0;
+ virtual uint16_t ConnectRequest(uint16_t psm, const RawAddress& bd_addr) = 0;
+ virtual bool ConnectResponse(const RawAddress& bd_addr, uint8_t id,
+ uint16_t lcid, uint16_t result,
+ uint16_t status) = 0;
+ virtual bool DisconnectRequest(uint16_t cid) = 0;
+ virtual bool DisconnectResponse(uint16_t cid) = 0;
+ virtual bool ConfigRequest(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) = 0;
+ virtual bool ConfigResponse(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) = 0;
+ virtual uint8_t DataWrite(uint16_t cid, BT_HDR* p_data) = 0;
+ virtual ~L2capInterface() = default;
+};
+
+class MockL2capInterface : public L2capInterface {
+ public:
+ MOCK_METHOD2(Register, uint16_t(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info));
+ MOCK_METHOD2(ConnectRequest,
+ uint16_t(uint16_t psm, const RawAddress& bd_addr));
+ MOCK_METHOD5(ConnectResponse,
+ bool(const RawAddress& bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status));
+ MOCK_METHOD1(DisconnectRequest, bool(uint16_t cid));
+ MOCK_METHOD1(DisconnectResponse, bool(uint16_t cid));
+ MOCK_METHOD2(ConfigRequest, bool(uint16_t cid, tL2CAP_CFG_INFO* p_cfg));
+ MOCK_METHOD2(ConfigResponse, bool(uint16_t cid, tL2CAP_CFG_INFO* p_cfg));
+ MOCK_METHOD2(DataWrite, uint8_t(uint16_t cid, BT_HDR* p_data));
+};
+
+/**
+ * Set the {@link MockL2capInterface} for testing
+ *
+ * @param mock_l2cap_interface pointer to mock l2cap interface, could be null
+ */
+void SetMockInterface(MockL2capInterface* mock_l2cap_interface);
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/stack/test/common/stack_test_packet_utils.cc b/stack/test/common/stack_test_packet_utils.cc
new file mode 100644
index 0000000..74fc57d
--- /dev/null
+++ b/stack/test/common/stack_test_packet_utils.cc
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "hci_layer.h"
+#include "l2c_api.h"
+#include "osi/include/allocator.h"
+
+#include "stack_test_packet_utils.h"
+
+namespace bluetooth {
+
+std::vector<uint8_t> CreateL2capDataPacket(uint16_t lcid,
+ const std::vector<uint8_t>& data) {
+ // Data in little endian order
+ std::vector<uint8_t> result;
+ auto data_size = static_cast<uint16_t>(data.size());
+ result.push_back(static_cast<uint8_t>(data_size));
+ result.push_back(static_cast<uint8_t>(data_size >> 8));
+ result.push_back(static_cast<uint8_t>(lcid));
+ result.push_back(static_cast<uint8_t>(lcid >> 8));
+ result.insert(result.end(), data.begin(), data.end());
+ return result;
+}
+
+std::vector<uint8_t> CreateAclPacket(uint16_t handle, uint8_t pb, uint8_t bc,
+ const std::vector<uint8_t>& data) {
+ // Data in little endian order
+ std::vector<uint8_t> result;
+ result.push_back(static_cast<uint8_t>(handle & 0x0F));
+ uint8_t second_byte = 0;
+ second_byte |= (bc << 6) & 0b11000000;
+ second_byte |= (pb << 4) & 0b00110000;
+ second_byte |= (handle >> 8) & 0b00001111;
+ result.push_back(second_byte);
+ auto data_size = static_cast<uint16_t>(data.size());
+ result.push_back(static_cast<uint8_t>(data_size));
+ result.push_back(static_cast<uint8_t>(data_size >> 8));
+ result.insert(result.end(), data.begin(), data.end());
+ return result;
+}
+
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(const uint8_t* acl_packet_bytes,
+ size_t buffer_length) {
+ size_t packet_size = buffer_length + BT_HDR_SIZE;
+ auto packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size));
+ // Add ACL packet overhead + L2CAP packet overhead
+ packet->offset = 4 + L2CAP_PKT_OVERHEAD;
+ packet->len = static_cast<uint16_t>(buffer_length - 4 - L2CAP_PKT_OVERHEAD);
+ packet->layer_specific = 0;
+ packet->event = MSG_HC_TO_STACK_HCI_ACL;
+ memcpy(packet->data, acl_packet_bytes, buffer_length);
+ return packet;
+}
+
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(
+ const std::vector<uint8_t>& buffer) {
+ return AllocateWrappedIncomingL2capAclPacket(buffer.data(), buffer.size());
+}
+
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(const uint8_t* acl_packet_bytes,
+ size_t buffer_length) {
+ size_t acl_l2cap_header_size = 4 + L2CAP_PKT_OVERHEAD;
+ CHECK_GE(L2CAP_MIN_OFFSET, static_cast<int>(acl_l2cap_header_size));
+ size_t packet_size =
+ BT_HDR_SIZE + L2CAP_MIN_OFFSET + buffer_length - acl_l2cap_header_size;
+ auto packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size));
+ packet->offset = L2CAP_MIN_OFFSET;
+ packet->len = static_cast<uint16_t>(buffer_length - acl_l2cap_header_size);
+ packet->layer_specific = 0;
+ packet->event = 0;
+ memcpy(packet->data + packet->offset - acl_l2cap_header_size,
+ acl_packet_bytes, buffer_length);
+ return packet;
+}
+
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(
+ const std::vector<uint8_t>& buffer) {
+ return AllocateWrappedOutgoingL2capAclPacket(buffer.data(), buffer.size());
+}
+
+} // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/common/stack_test_packet_utils.h b/stack/test/common/stack_test_packet_utils.h
new file mode 100644
index 0000000..fcbc5a9
--- /dev/null
+++ b/stack/test/common/stack_test_packet_utils.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "bt_types.h"
+
+namespace bluetooth {
+
+/**
+ * Create L2CAP data packet
+ *
+ * @param lcid
+ * @param data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateL2capDataPacket(uint16_t lcid,
+ const std::vector<uint8_t>& data);
+
+/**
+ * Create ACL data packet
+ *
+ * @param handle ACL connection hanle
+ * @param pb pb byte
+ * @param bc bc byte
+ * @param data frame data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateAclPacket(uint16_t handle, uint8_t pb, uint8_t bc,
+ const std::vector<uint8_t>& data);
+
+/**
+ * Given an array of ACL packet bytes from BTSNOOP log, allocate an OSI
+ * allocated BT_HDR pointer to a packet that can be processed by L2CAP
+ * application layer
+ *
+ * Note: BT_HDR offset is configured for incoming packets
+ *
+ * @param acl_packet_bytes pointer to array of ACL packet bytes
+ * @param buffer_length length of the packet buffer
+ * @return BT_HDR pointer to an OSI heap allocated packet
+ */
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(const uint8_t* acl_packet_bytes,
+ size_t buffer_length);
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(
+ const std::vector<uint8_t>& buffer);
+
+/**
+ * Given an array of ACL packet bytes from BTSNOOP log, allocate an OSI
+ * allocated BT_HDR pointer to a packet that can be processed by L2CAP
+ * application layer
+ *
+ * Note: BT_HDR offset is configured for outgoing packets
+ *
+ * @param acl_packet_bytes pointer to array of ACL packet bytes
+ * @param buffer_length length of the packet buffer
+ * @return BT_HDR pointer to an OSI heap allocated packet
+ */
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(const uint8_t* acl_packet_bytes,
+ size_t buffer_length);
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(
+ const std::vector<uint8_t>& buffer);
+
+} // namespace bluetooth
diff --git a/stack/test/rfcomm/stack_rfcomm_test.cc b/stack/test/rfcomm/stack_rfcomm_test.cc
new file mode 100644
index 0000000..3d9da3f
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test.cc
@@ -0,0 +1,892 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "bt_types.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+
+#include "btm_int.h"
+#include "rfc_int.h"
+
+#include "mock_btm_layer.h"
+#include "mock_l2cap_layer.h"
+#include "stack_rfcomm_test_utils.h"
+#include "stack_test_packet_utils.h"
+
+std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
+ std::stringstream str;
+ str.setf(std::ios_base::hex, std::ios::basefield);
+ str.setf(std::ios_base::uppercase);
+ str.fill('0');
+ for (size_t i = 0; i < len; ++i) {
+ str << std::setw(2) << static_cast<uint16_t>(p_data[i]);
+ str << " ";
+ }
+ return str.str();
+}
+
+std::string DumpBtHdrToString(BT_HDR* p_hdr) {
+ uint8_t* p_hdr_data = p_hdr->data + p_hdr->offset;
+ return DumpByteBufferToString(p_hdr_data, p_hdr->len);
+}
+
+void PrintTo(BT_HDR* value, ::std::ostream* os) {
+ *os << DumpBtHdrToString(value);
+}
+
+void PrintTo(tL2CAP_CFG_INFO* value, ::std::ostream* os) {
+ *os << DumpByteBufferToString((uint8_t*)value, sizeof(tL2CAP_CFG_INFO));
+}
+
+namespace {
+
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::Test;
+using testing::StrictMock;
+using testing::SaveArg;
+using testing::SaveArgPointee;
+using testing::Pointee;
+using testing::StrEq;
+using testing::NotNull;
+
+using bluetooth::CreateL2capDataPacket;
+using bluetooth::CreateAclPacket;
+using bluetooth::AllocateWrappedIncomingL2capAclPacket;
+using bluetooth::AllocateWrappedOutgoingL2capAclPacket;
+
+using bluetooth::rfcomm::GetDlci;
+using bluetooth::rfcomm::GetAddressField;
+using bluetooth::rfcomm::GetControlField;
+using bluetooth::rfcomm::CreateMccPnFrame;
+using bluetooth::rfcomm::CreateMccMscFrame;
+using bluetooth::rfcomm::CreateMultiplexerControlFrame;
+using bluetooth::rfcomm::CreateRfcommPacket;
+using bluetooth::rfcomm::CreateQuickDataPacket;
+using bluetooth::rfcomm::CreateQuickPnPacket;
+using bluetooth::rfcomm::CreateQuickSabmPacket;
+using bluetooth::rfcomm::CreateQuickUaPacket;
+using bluetooth::rfcomm::CreateQuickMscPacket;
+
+MATCHER_P(PointerMemoryEqual, ptr,
+ DumpByteBufferToString((uint8_t*)ptr, sizeof(*ptr))) {
+ return memcmp(arg, ptr, sizeof(*ptr)) == 0;
+}
+
+MATCHER_P(BtHdrEqual, expected, DumpBtHdrToString(expected)) {
+ auto arg_hdr = static_cast<BT_HDR*>(arg);
+ uint8_t* arg_data = arg_hdr->data + arg_hdr->offset;
+ auto expected_hdr = static_cast<BT_HDR*>(expected);
+ uint8_t* expected_data = expected_hdr->data + expected_hdr->offset;
+ return memcmp(arg_data, expected_data, expected_hdr->len) == 0;
+}
+
+bluetooth::rfcomm::MockRfcommCallback* rfcomm_callback = nullptr;
+
+void port_mgmt_cback_0(uint32_t code, uint16_t port_handle) {
+ rfcomm_callback->PortManagementCallback(code, port_handle, 0);
+}
+
+void port_mgmt_cback_1(uint32_t code, uint16_t port_handle) {
+ rfcomm_callback->PortManagementCallback(code, port_handle, 1);
+}
+
+void port_event_cback_0(uint32_t code, uint16_t port_handle) {
+ rfcomm_callback->PortEventCallback(code, port_handle, 0);
+}
+
+void port_event_cback_1(uint32_t code, uint16_t port_handle) {
+ rfcomm_callback->PortEventCallback(code, port_handle, 1);
+}
+
+RawAddress GetTestAddress(int index) {
+ CHECK_LT(index, UINT8_MAX);
+ RawAddress result = {
+ {0xAA, 0x00, 0x11, 0x22, 0x33, static_cast<uint8_t>(index)}};
+ return result;
+}
+
+class StackRfcommTest : public Test {
+ public:
+ void StartServerPort(uint16_t uuid, uint8_t scn, uint16_t mtu,
+ tPORT_CALLBACK* management_callback,
+ tPORT_CALLBACK* event_callback,
+ uint16_t* server_handle) {
+ VLOG(1) << "Step 1";
+ ASSERT_EQ(RFCOMM_CreateConnection(uuid, scn, true, mtu, RawAddress::kAny,
+ server_handle, management_callback),
+ PORT_SUCCESS);
+ ASSERT_EQ(PORT_SetEventMask(*server_handle, PORT_EV_RXCHAR), PORT_SUCCESS);
+ ASSERT_EQ(PORT_SetEventCallback(*server_handle, event_callback),
+ PORT_SUCCESS);
+ }
+
+ void ConnectServerL2cap(const RawAddress& peer_addr, uint16_t acl_handle,
+ uint16_t lcid) {
+ VLOG(1) << "Step 1";
+ // Remote device connect to this channel, we shall accept
+ static const uint8_t cmd_id = 0x07;
+ EXPECT_CALL(l2cap_interface_,
+ ConnectResponse(peer_addr, cmd_id, lcid, L2CAP_CONN_OK, 0));
+ tL2CAP_CFG_INFO cfg_req = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+ EXPECT_CALL(l2cap_interface_,
+ ConfigRequest(lcid, PointerMemoryEqual(&cfg_req)))
+ .WillOnce(Return(true));
+ l2cap_appl_info_.pL2CA_ConnectInd_Cb(peer_addr, lcid, BT_PSM_RFCOMM,
+ cmd_id);
+
+ VLOG(1) << "Step 2";
+ // MTU configuration is done
+ cfg_req.mtu_present = false;
+ l2cap_appl_info_.pL2CA_ConfigCfm_Cb(lcid, &cfg_req);
+
+ VLOG(1) << "Step 3";
+ // Remote device also ask to configure MTU size
+ EXPECT_CALL(l2cap_interface_,
+ ConfigResponse(lcid, PointerMemoryEqual(&cfg_req)))
+ .WillOnce(Return(true));
+ l2cap_appl_info_.pL2CA_ConfigInd_Cb(lcid, &cfg_req);
+
+ VLOG(1) << "Step 4";
+ // Remote device connect to server channel 0
+ BT_HDR* sabm_channel_0 = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickSabmPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+ BT_HDR* ua_channel_0 = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickUaPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(ua_channel_0)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ // Packet should be freed by RFCOMM
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, sabm_channel_0);
+ osi_free(ua_channel_0);
+ }
+
+ void ConnectServerPort(const RawAddress& peer_addr, uint16_t port_handle,
+ uint8_t scn, uint16_t mtu, uint16_t acl_handle,
+ uint16_t lcid, int port_callback_index) {
+ VLOG(1) << "Step 1";
+ // Negotiate parameters on scn
+ BT_HDR* uih_pn_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickPnPacket(true, GetDlci(false, scn), true, mtu,
+ RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, 0, RFCOMM_K_MAX,
+ lcid, acl_handle));
+ BT_HDR* uih_pn_rsp_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickPnPacket(false, GetDlci(false, scn), false, mtu,
+ RFCOMM_PN_CONV_LAYER_CBFC_R >> 4, 0, RFCOMM_K_MAX,
+ lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(lcid, BtHdrEqual(uih_pn_rsp_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ // uih_pn_cmd_from_peer should be freed by this method
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_pn_cmd_from_peer);
+ osi_free(uih_pn_rsp_to_peer);
+
+ VLOG(1) << "Step 2";
+ // Remote device connect to scn
+ tBTM_SEC_CALLBACK* security_callback = nullptr;
+ void* p_port = nullptr;
+ BT_HDR* sabm_channel_dlci = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickSabmPacket(GetDlci(false, scn), lcid, acl_handle));
+ EXPECT_CALL(btm_security_internal_interface_,
+ MultiplexingProtocolAccessRequest(peer_addr, BT_PSM_RFCOMM,
+ false, BTM_SEC_PROTO_RFCOMM,
+ scn, NotNull(), NotNull()))
+ .WillOnce(DoAll(SaveArg<5>(&security_callback), SaveArg<6>(&p_port),
+ Return(BTM_SUCCESS)));
+ // sabm_channel_dlci should be freed by this method
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, sabm_channel_dlci);
+
+ VLOG(1) << "Step 3";
+ // Confirm security check should trigger port as connected
+ EXPECT_CALL(
+ rfcomm_callback_,
+ PortManagementCallback(PORT_SUCCESS, port_handle, port_callback_index));
+ BT_HDR* ua_channel_dlci = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickUaPacket(GetDlci(false, scn), lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(ua_channel_dlci)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ ASSERT_TRUE(security_callback);
+ security_callback(&peer_addr, BT_TRANSPORT_BR_EDR, p_port, BTM_SUCCESS);
+ osi_free(ua_channel_dlci);
+
+ VLOG(1) << "Step 4";
+ // Remote also need to configure its modem signal before we can send data
+ BT_HDR* uih_msc_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, true,
+ false, true, true, false, true));
+ BT_HDR* uih_msc_response_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle,
+ false, false, true, true, false, true));
+ // We also have to do modem configuration ourself
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(lcid, BtHdrEqual(uih_msc_response_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ BT_HDR* uih_msc_cmd_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle, true,
+ false, true, true, false, true));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(lcid, BtHdrEqual(uih_msc_cmd_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ // uih_msc_cmd_from_peer should be freed by this method
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_cmd_from_peer);
+ osi_free(uih_msc_response_to_peer);
+
+ VLOG(1) << "Step 5";
+ // modem configuration is done
+ BT_HDR* uih_msc_response_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, false,
+ false, true, true, false, true));
+ // uih_msc_response_from_peer should be freed by this method
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_response_from_peer);
+ }
+
+ void StartClientPort(const RawAddress& peer_bd_addr, uint16_t uuid,
+ uint8_t scn, uint16_t mtu,
+ tPORT_CALLBACK* management_callback,
+ tPORT_CALLBACK* event_callback, uint16_t lcid,
+ uint16_t acl_handle, uint16_t* client_handle,
+ bool is_first_connection) {
+ VLOG(1) << "Step 1";
+ BT_HDR* uih_pn_channel_3 =
+ AllocateWrappedOutgoingL2capAclPacket(CreateQuickPnPacket(
+ true, GetDlci(false, scn), true, mtu, RFCOMM_PN_CONV_LAYER_TYPE_1,
+ RFCOMM_PN_PRIORITY_0, RFCOMM_K, lcid, acl_handle));
+ if (is_first_connection) {
+ EXPECT_CALL(l2cap_interface_, ConnectRequest(BT_PSM_RFCOMM, peer_bd_addr))
+ .WillOnce(Return(lcid));
+ } else {
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(lcid, BtHdrEqual(uih_pn_channel_3)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ }
+ ASSERT_EQ(RFCOMM_CreateConnection(uuid, scn, false, mtu, peer_bd_addr,
+ client_handle, management_callback),
+ PORT_SUCCESS);
+ ASSERT_EQ(PORT_SetEventMask(*client_handle, PORT_EV_RXCHAR), PORT_SUCCESS);
+ ASSERT_EQ(PORT_SetEventCallback(*client_handle, event_callback),
+ PORT_SUCCESS);
+ osi_free(uih_pn_channel_3);
+ }
+
+ void TestConnectClientPortL2cap(uint16_t acl_handle, uint16_t lcid) {
+ VLOG(1) << "Step 1";
+ // Send configuration request when L2CAP connect is succsseful
+ tL2CAP_CFG_INFO cfg_req = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+ EXPECT_CALL(l2cap_interface_,
+ ConfigRequest(lcid, PointerMemoryEqual(&cfg_req)))
+ .WillOnce(Return(true));
+ l2cap_appl_info_.pL2CA_ConnectCfm_Cb(lcid, L2CAP_CONN_OK);
+
+ VLOG(1) << "Step 2";
+ // Remote device confirms our configuration request
+ cfg_req.mtu_present = false;
+ l2cap_appl_info_.pL2CA_ConfigCfm_Cb(lcid, &cfg_req);
+
+ VLOG(1) << "Step 3";
+ // Remote device also asks to configure MTU
+ // Once configuration is done, we connect to multiplexer control channel 0
+ EXPECT_CALL(l2cap_interface_,
+ ConfigResponse(lcid, PointerMemoryEqual(&cfg_req)))
+ .WillOnce(Return(true));
+ // multiplexer control channel's DLCI is always 0
+ BT_HDR* sabm_channel_0 = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickSabmPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(sabm_channel_0)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ l2cap_appl_info_.pL2CA_ConfigInd_Cb(lcid, &cfg_req);
+ osi_free(sabm_channel_0);
+ }
+
+ void ConnectClientPort(const RawAddress& peer_addr, uint16_t port_handle,
+ uint8_t scn, uint16_t mtu, uint16_t acl_handle,
+ uint16_t lcid, int port_callback_index,
+ bool is_first_connection) {
+ VLOG(1) << "Step 1";
+ if (is_first_connection) {
+ VLOG(1) << "Step 1.5";
+ // Once remote accept multiplexer control channel 0
+ // We change to desired channel on non-initiating device (remote device)
+ BT_HDR* ua_channel_0 = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickUaPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+ BT_HDR* uih_pn_channel_3 =
+ AllocateWrappedOutgoingL2capAclPacket(CreateQuickPnPacket(
+ true, GetDlci(false, scn), true, mtu,
+ RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, RFCOMM_PN_PRIORITY_0,
+ RFCOMM_K_MAX, lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(lcid, BtHdrEqual(uih_pn_channel_3)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, ua_channel_0);
+ osi_free(uih_pn_channel_3);
+ }
+
+ VLOG(1) << "Step 2";
+ // Once remote accept service channel change, we start security procedure
+ BT_HDR* uih_pn_channel_3_accept =
+ AllocateWrappedIncomingL2capAclPacket(CreateQuickPnPacket(
+ false, GetDlci(false, scn), false, mtu,
+ RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, RFCOMM_PN_PRIORITY_0,
+ RFCOMM_K_MAX, lcid, acl_handle));
+ tBTM_SEC_CALLBACK* security_callback = nullptr;
+ void* p_port = nullptr;
+ EXPECT_CALL(btm_security_internal_interface_,
+ MultiplexingProtocolAccessRequest(peer_addr, BT_PSM_RFCOMM,
+ true, BTM_SEC_PROTO_RFCOMM,
+ scn, NotNull(), NotNull()))
+ .WillOnce(DoAll(SaveArg<5>(&security_callback), SaveArg<6>(&p_port),
+ Return(BTM_SUCCESS)));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_pn_channel_3_accept);
+
+ VLOG(1) << "Step 3";
+ // Once security procedure is done, we officially connect to target scn
+ BT_HDR* sabm_channel_3 = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickSabmPacket(GetDlci(false, scn), lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(sabm_channel_3)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ ASSERT_TRUE(security_callback);
+ security_callback(&peer_addr, BT_TRANSPORT_BR_EDR, p_port, BTM_SUCCESS);
+ osi_free(sabm_channel_3);
+
+ VLOG(1) << "Step 4";
+ // When target scn is accepted by remote, we need to configure modem signal
+ // state beofre using the port
+ EXPECT_CALL(
+ rfcomm_callback_,
+ PortManagementCallback(PORT_SUCCESS, port_handle, port_callback_index));
+ BT_HDR* uih_msc_cmd = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, true,
+ false, true, true, false, true));
+ EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(uih_msc_cmd)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ BT_HDR* ua_channel_3 = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickUaPacket(GetDlci(false, scn), lcid, acl_handle));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, ua_channel_3);
+ osi_free(uih_msc_cmd);
+
+ VLOG(1) << "Step 5";
+ // modem configuration is done
+ BT_HDR* uih_msc_response = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle,
+ false, false, true, true, false, true));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_response);
+
+ VLOG(1) << "Step 6";
+ // Remote also need to configure its modem signal before we can send data
+ BT_HDR* uih_msc_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle, true,
+ false, true, true, false, true));
+ BT_HDR* uih_msc_response_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, false,
+ false, true, true, false, true));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(lcid, BtHdrEqual(uih_msc_response_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_cmd_from_peer);
+ osi_free(uih_msc_response_to_peer);
+ }
+
+ void SendAndVerifyOutgoingTransmission(uint16_t port_handle,
+ bool is_initiator, uint8_t scn,
+ bool cr, const std::string& message,
+ int credits, uint16_t acl_handle,
+ uint16_t lcid) {
+ VLOG(1) << "Step 1";
+ BT_HDR* data_packet = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickDataPacket(GetDlci(is_initiator, scn), cr, lcid, acl_handle,
+ credits, message));
+ uint16_t transmitted_length = 0;
+ EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(data_packet)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ ASSERT_EQ(PORT_WriteData(port_handle, message.data(), message.size(),
+ &transmitted_length),
+ PORT_SUCCESS);
+ ASSERT_EQ(transmitted_length, message.size());
+ }
+
+ void ReceiveAndVerifyIncomingTransmission(uint16_t port_handle,
+ bool is_initiator, uint8_t scn,
+ bool cr, const std::string& message,
+ int credits, uint16_t acl_handle,
+ uint16_t lcid,
+ int port_callback_index) {
+ VLOG(1) << "Step 1";
+ BT_HDR* data_packet = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickDataPacket(GetDlci(is_initiator, scn), cr, lcid, acl_handle,
+ credits, message));
+ EXPECT_CALL(rfcomm_callback_,
+ PortEventCallback(_, port_handle, port_callback_index));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, data_packet);
+
+ VLOG(1) << "Step 2";
+ char buffer[L2CAP_MTU_SIZE] = {};
+ uint16_t length = 0;
+ int status = PORT_ReadData(port_handle, buffer, L2CAP_MTU_SIZE, &length);
+ ASSERT_EQ(status, PORT_SUCCESS);
+ ASSERT_THAT(buffer, StrEq(message));
+ }
+
+ protected:
+ void SetUp() override {
+ Test::SetUp();
+ bluetooth::manager::SetMockSecurityInternalInterface(
+ &btm_security_internal_interface_);
+ bluetooth::l2cap::SetMockInterface(&l2cap_interface_);
+ rfcomm_callback = &rfcomm_callback_;
+ EXPECT_CALL(l2cap_interface_, Register(BT_PSM_RFCOMM, _))
+ .WillOnce(
+ DoAll(SaveArgPointee<1>(&l2cap_appl_info_), Return(BT_PSM_RFCOMM)));
+ RFCOMM_Init();
+ rfc_cb.trace_level = BT_TRACE_LEVEL_DEBUG;
+ }
+
+ void TearDown() override {
+ rfcomm_callback = nullptr;
+ bluetooth::l2cap::SetMockInterface(nullptr);
+ bluetooth::manager::SetMockSecurityInternalInterface(nullptr);
+ testing::Test::TearDown();
+ }
+ StrictMock<bluetooth::manager::MockBtmSecurityInternalInterface>
+ btm_security_internal_interface_;
+ StrictMock<bluetooth::l2cap::MockL2capInterface> l2cap_interface_;
+ StrictMock<bluetooth::rfcomm::MockRfcommCallback> rfcomm_callback_;
+ tL2CAP_APPL_INFO l2cap_appl_info_;
+};
+
+TEST_F(StackRfcommTest, SingleServerConnectionHelloWorld) {
+ // Prepare a server channel at kTestChannelNumber0
+ static const uint16_t acl_handle = 0x0009;
+ static const uint16_t lcid = 0x0054;
+ static const uint16_t test_uuid = 0x1112;
+ static const uint8_t test_scn = 8;
+ static const uint16_t test_mtu = 1600;
+ static const RawAddress test_address = GetTestAddress(0);
+ uint16_t server_handle = 0;
+ ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid, test_scn, test_mtu,
+ port_mgmt_cback_0, port_event_cback_0,
+ &server_handle));
+ ASSERT_NO_FATAL_FAILURE(ConnectServerL2cap(test_address, acl_handle, lcid));
+ ASSERT_NO_FATAL_FAILURE(ConnectServerPort(
+ test_address, server_handle, test_scn, test_mtu, acl_handle, lcid, 0));
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ server_handle, false, test_scn, true, "Hello World!\r", 50, acl_handle,
+ lcid, 0));
+ ASSERT_NO_FATAL_FAILURE(
+ SendAndVerifyOutgoingTransmission(server_handle, false, test_scn, false,
+ "\r!dlroW olleH", 4, acl_handle, lcid));
+}
+
+TEST_F(StackRfcommTest, MultiServerPortSameDeviceHelloWorld) {
+ // Prepare a server channel at kTestChannelNumber0
+ static const uint16_t acl_handle = 0x0009;
+ static const uint16_t lcid = 0x0054;
+ static const uint16_t test_mtu = 1600;
+ static const RawAddress test_address = GetTestAddress(0);
+
+ // Service 0
+ uint16_t server_handle_0 = 0;
+ static const uint8_t test_scn_0 = 8;
+ static const uint16_t test_uuid_0 = 0x1112;
+ ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid_0, test_scn_0, test_mtu,
+ port_mgmt_cback_0, port_event_cback_0,
+ &server_handle_0));
+ ASSERT_NO_FATAL_FAILURE(ConnectServerL2cap(test_address, acl_handle, lcid));
+ ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address, server_handle_0,
+ test_scn_0, test_mtu, acl_handle,
+ lcid, 0));
+
+ // Service 1
+ uint16_t server_handle_1 = 0;
+ static const uint8_t test_scn_1 = 10;
+ static const uint16_t test_uuid_1 = 0x111F;
+ ASSERT_NE(test_scn_1, test_scn_0);
+ ASSERT_NE(test_uuid_1, test_uuid_0);
+ ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid_1, test_scn_1, test_mtu,
+ port_mgmt_cback_1, port_event_cback_1,
+ &server_handle_1));
+ // No L2CAP setup for 2nd device
+ ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address, server_handle_1,
+ test_scn_1, test_mtu, acl_handle,
+ lcid, 1));
+
+ // Use service 0
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ server_handle_0, false, test_scn_0, true, "Hello World0!\r", 50,
+ acl_handle, lcid, 0));
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ server_handle_0, false, test_scn_0, false, "\r!0dlroW olleH", 4,
+ acl_handle, lcid));
+ // Use service 1
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ server_handle_1, false, test_scn_1, true, "Hello World1!\r", 50,
+ acl_handle, lcid, 1));
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ server_handle_1, false, test_scn_1, false, "\r!1dlroW olleH", 4,
+ acl_handle, lcid));
+}
+
+TEST_F(StackRfcommTest, SameServerPortMultiDeviceHelloWorld) {
+ // Prepare a server channel at kTestChannelNumber0
+ static const uint16_t test_mtu = 1600;
+ static const uint8_t test_scn = 3;
+ static const uint16_t test_uuid = 0x1112;
+
+ // Service 0
+ static const RawAddress test_address_0 = GetTestAddress(0);
+ static const uint16_t acl_handle_0 = 0x0009;
+ static const uint16_t lcid_0 = 0x0054;
+ uint16_t server_handle_0 = 0;
+ ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid, test_scn, test_mtu,
+ port_mgmt_cback_0, port_event_cback_0,
+ &server_handle_0));
+ ASSERT_NO_FATAL_FAILURE(
+ ConnectServerL2cap(test_address_0, acl_handle_0, lcid_0));
+ ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address_0, server_handle_0,
+ test_scn, test_mtu, acl_handle_0,
+ lcid_0, 0));
+
+ // Service 1
+ static const RawAddress test_address_1 = GetTestAddress(1);
+ static const uint16_t acl_handle_1 = 0x0012;
+ static const uint16_t lcid_1 = 0x0045;
+ uint16_t server_handle_1 = 0;
+ ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid, test_scn, test_mtu,
+ port_mgmt_cback_1, port_event_cback_1,
+ &server_handle_1));
+ ASSERT_NO_FATAL_FAILURE(
+ ConnectServerL2cap(test_address_1, acl_handle_1, lcid_1));
+ ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address_1, server_handle_1,
+ test_scn, test_mtu, acl_handle_1,
+ lcid_1, 1));
+
+ // Use service 0
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ server_handle_0, false, test_scn, true, "Hello World0!\r", 50,
+ acl_handle_0, lcid_0, 0));
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ server_handle_0, false, test_scn, false, "\r!0dlroW olleH", 4,
+ acl_handle_0, lcid_0));
+ // Use service 1
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ server_handle_1, false, test_scn, true, "Hello World1!\r", 50,
+ acl_handle_1, lcid_1, 1));
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ server_handle_1, false, test_scn, false, "\r!1dlroW olleH", 4,
+ acl_handle_1, lcid_1));
+}
+
+TEST_F(StackRfcommTest, SingleClientConnectionHelloWorld) {
+ static const uint16_t acl_handle = 0x0009;
+ static const uint16_t lcid = 0x0054;
+ static const uint16_t test_uuid = 0x1112;
+ static const uint8_t test_scn = 8;
+ static const uint16_t test_mtu = 1600;
+ static const RawAddress test_address = GetTestAddress(0);
+ uint16_t client_handle = 0;
+ ASSERT_NO_FATAL_FAILURE(StartClientPort(
+ test_address, test_uuid, test_scn, test_mtu, port_mgmt_cback_0,
+ port_event_cback_0, lcid, acl_handle, &client_handle, true));
+ ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle, lcid));
+ ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address, client_handle,
+ test_scn, test_mtu, acl_handle,
+ lcid, 0, true));
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ client_handle, false, test_scn, true, "\r!dlroW olleH", -1, acl_handle,
+ lcid));
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ client_handle, false, test_scn, false, "Hello World!\r", -1, acl_handle,
+ lcid, 0));
+}
+
+TEST_F(StackRfcommTest, MultiClientPortSameDeviceHelloWorld) {
+ static const uint16_t acl_handle = 0x0009;
+ static const uint16_t lcid = 0x0054;
+ static const uint16_t test_mtu = 1600;
+ static const RawAddress test_address = GetTestAddress(0);
+
+ // Connection 0
+ static const uint16_t test_uuid_0 = 0x1112;
+ static const uint8_t test_scn_0 = 8;
+ uint16_t client_handle_0 = 0;
+ ASSERT_NO_FATAL_FAILURE(StartClientPort(
+ test_address, test_uuid_0, test_scn_0, test_mtu, port_mgmt_cback_0,
+ port_event_cback_0, lcid, acl_handle, &client_handle_0, true));
+ ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle, lcid));
+ ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address, client_handle_0,
+ test_scn_0, test_mtu, acl_handle,
+ lcid, 0, true));
+
+ // Connection 1
+ static const uint16_t test_uuid_1 = 0x111F;
+ static const uint8_t test_scn_1 = 10;
+ uint16_t client_handle_1 = 0;
+ ASSERT_NO_FATAL_FAILURE(StartClientPort(
+ test_address, test_uuid_1, test_scn_1, test_mtu, port_mgmt_cback_1,
+ port_event_cback_1, lcid, acl_handle, &client_handle_1, false));
+ ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address, client_handle_1,
+ test_scn_1, test_mtu, acl_handle,
+ lcid, 1, false));
+
+ // Use connection 0
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ client_handle_0, false, test_scn_0, true, "\r!dlroW olleH", -1,
+ acl_handle, lcid));
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ client_handle_0, false, test_scn_0, false, "Hello World!\r", -1,
+ acl_handle, lcid, 0));
+
+ // Use connection 1
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ client_handle_1, false, test_scn_1, true, "\r!dlroW olleH", -1,
+ acl_handle, lcid));
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ client_handle_1, false, test_scn_1, false, "Hello World!\r", -1,
+ acl_handle, lcid, 1));
+}
+
+TEST_F(StackRfcommTest, SameClientPortMultiDeviceHelloWorld) {
+ static const uint16_t test_uuid = 0x1112;
+ static const uint8_t test_scn = 8;
+ static const uint16_t test_mtu = 1600;
+
+ // Connection 0
+ static const RawAddress test_address_0 = GetTestAddress(0);
+ static const uint16_t acl_handle_0 = 0x0009;
+ static const uint16_t lcid_0 = 0x0054;
+ uint16_t client_handle_0 = 0;
+ ASSERT_NO_FATAL_FAILURE(StartClientPort(
+ test_address_0, test_uuid, test_scn, test_mtu, port_mgmt_cback_0,
+ port_event_cback_0, lcid_0, acl_handle_0, &client_handle_0, true));
+ ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle_0, lcid_0));
+ ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address_0, client_handle_0,
+ test_scn, test_mtu, acl_handle_0,
+ lcid_0, 0, true));
+
+ // Connection 1
+ static const RawAddress test_address_1 = GetTestAddress(1);
+ static const uint16_t acl_handle_1 = 0x0012;
+ static const uint16_t lcid_1 = 0x0045;
+ uint16_t client_handle_1 = 0;
+ ASSERT_NO_FATAL_FAILURE(StartClientPort(
+ test_address_1, test_uuid, test_scn, test_mtu, port_mgmt_cback_1,
+ port_event_cback_1, lcid_1, acl_handle_1, &client_handle_1, true));
+ ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle_1, lcid_1));
+ ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address_1, client_handle_1,
+ test_scn, test_mtu, acl_handle_1,
+ lcid_1, 1, true));
+
+ // Use connection 0
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ client_handle_0, false, test_scn, true, "\r!dlroW olleH", -1,
+ acl_handle_0, lcid_0));
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ client_handle_0, false, test_scn, false, "Hello World!\r", -1,
+ acl_handle_0, lcid_0, 0));
+
+ // Use connection 1
+ ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+ client_handle_1, false, test_scn, true, "\r!dlroW olleH", -1,
+ acl_handle_1, lcid_1));
+ ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+ client_handle_1, false, test_scn, false, "Hello World!\r", -1,
+ acl_handle_1, lcid_1, 1));
+}
+
+TEST_F(StackRfcommTest, TestConnectionCollision) {
+ static const uint16_t acl_handle = 0x0008;
+ static const uint16_t old_lcid = 0x004a;
+ static const uint16_t new_lcid = 0x005c;
+ static const uint16_t test_uuid = 0x1112;
+ static const uint8_t test_server_scn = 3;
+ static const uint8_t test_peer_scn = 10;
+ // Must be smaller than L2CAP_MTU_SIZE by at least 4 bytes
+ static const uint16_t test_mtu = 1000;
+ static const RawAddress test_address = GetTestAddress(0);
+ uint16_t server_handle = 0;
+ VLOG(1) << "Step 1";
+ // Prepare a server port
+ int status = RFCOMM_CreateConnection(test_uuid, test_server_scn, true,
+ test_mtu, RawAddress::kAny,
+ &server_handle, port_mgmt_cback_0);
+ ASSERT_EQ(status, PORT_SUCCESS);
+ status = PORT_SetEventMask(server_handle, PORT_EV_RXCHAR);
+ ASSERT_EQ(status, PORT_SUCCESS);
+ status = PORT_SetEventCallback(server_handle, port_event_cback_0);
+ ASSERT_EQ(status, PORT_SUCCESS);
+
+ VLOG(1) << "Step 2";
+ // Try to connect to a client port
+ uint16_t client_handle_1 = 0;
+ EXPECT_CALL(l2cap_interface_, ConnectRequest(BT_PSM_RFCOMM, test_address))
+ .Times(1)
+ .WillOnce(Return(old_lcid));
+ status = RFCOMM_CreateConnection(test_uuid, test_peer_scn, false, test_mtu,
+ test_address, &client_handle_1,
+ port_mgmt_cback_1);
+ ASSERT_EQ(status, PORT_SUCCESS);
+ status = PORT_SetEventMask(client_handle_1, PORT_EV_RXCHAR);
+ ASSERT_EQ(status, PORT_SUCCESS);
+ status = PORT_SetEventCallback(client_handle_1, port_event_cback_1);
+ ASSERT_EQ(status, PORT_SUCCESS);
+
+ VLOG(1) << "Step 3";
+ // While our connection is pending, remote device tries to connect to
+ // new_lcid, with L2CAP command id: pending_cmd_id
+ static const uint8_t pending_cmd_id = 0x05;
+ // RFCOMM starts timer for collision:
+ l2cap_appl_info_.pL2CA_ConnectInd_Cb(test_address, new_lcid, BT_PSM_RFCOMM,
+ pending_cmd_id);
+
+ VLOG(1) << "Step 4";
+ // Remote reject our connection request saying PSM not allowed
+ // This should trigger RFCOMM to accept remote L2CAP connection at new_lcid
+ EXPECT_CALL(l2cap_interface_, ConnectResponse(test_address, pending_cmd_id,
+ new_lcid, L2CAP_CONN_OK, 0))
+ .WillOnce(Return(true));
+ // Followed by configure request for MTU size
+ tL2CAP_CFG_INFO our_cfg_req = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+ EXPECT_CALL(l2cap_interface_,
+ ConfigRequest(new_lcid, PointerMemoryEqual(&our_cfg_req)))
+ .WillOnce(Return(true));
+ l2cap_appl_info_.pL2CA_ConnectCfm_Cb(old_lcid, L2CAP_CONN_NO_PSM);
+
+ VLOG(1) << "Step 5";
+ // Remote device also ask to configure MTU size as well
+ tL2CAP_CFG_INFO peer_cfg_req = {.mtu_present = true, .mtu = test_mtu};
+ // We responded by saying OK
+ tL2CAP_CFG_INFO our_cfg_rsp = {.result = L2CAP_CFG_OK,
+ .mtu = peer_cfg_req.mtu};
+ EXPECT_CALL(l2cap_interface_,
+ ConfigResponse(new_lcid, PointerMemoryEqual(&our_cfg_rsp)))
+ .WillOnce(Return(true));
+ l2cap_appl_info_.pL2CA_ConfigInd_Cb(new_lcid, &peer_cfg_req);
+
+ VLOG(1) << "Step 6";
+ // Remote device accepted our MTU size
+ tL2CAP_CFG_INFO peer_cfg_rsp = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+ l2cap_appl_info_.pL2CA_ConfigCfm_Cb(new_lcid, &peer_cfg_rsp);
+
+ // L2CAP collision and connection setup done
+
+ VLOG(1) << "Step 7";
+ // Remote device connect multiplexer channel
+ BT_HDR* sabm_channel_0 = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickSabmPacket(RFCOMM_MX_DLCI, new_lcid, acl_handle));
+ // We accept
+ BT_HDR* ua_channel_0 = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickUaPacket(RFCOMM_MX_DLCI, new_lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_, DataWrite(new_lcid, BtHdrEqual(ua_channel_0)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ // And immediately try to configure test_peer_scn
+ BT_HDR* uih_pn_cmd_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickPnPacket(false, GetDlci(true, test_peer_scn), true, test_mtu,
+ RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, 0, RFCOMM_K_MAX,
+ new_lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(new_lcid, BtHdrEqual(uih_pn_cmd_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ // Packet should be freed by this method
+ l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, sabm_channel_0);
+ osi_free(ua_channel_0);
+ osi_free(uih_pn_cmd_to_peer);
+
+ VLOG(1) << "Step 8";
+ // Peer tries to configure test_server_scn
+ BT_HDR* uih_pn_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickPnPacket(true, GetDlci(false, test_server_scn), true, test_mtu,
+ RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, 0, RFCOMM_K_MAX,
+ new_lcid, acl_handle));
+ // We, as acceptor, must accept
+ BT_HDR* uih_pn_rsp_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickPnPacket(false, GetDlci(false, test_server_scn), false,
+ test_mtu, RFCOMM_PN_CONV_LAYER_CBFC_R >> 4, 0,
+ RFCOMM_K_MAX, new_lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(new_lcid, BtHdrEqual(uih_pn_rsp_to_peer)))
+ .Times(1)
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, uih_pn_cmd_from_peer);
+ osi_free(uih_pn_rsp_to_peer);
+
+ VLOG(1) << "Step 9";
+ // Remote never replies our configuration request for test_peer_scn
+ // But instead connect to test_server_scn directly
+ BT_HDR* sabm_server_scn =
+ AllocateWrappedIncomingL2capAclPacket(CreateQuickSabmPacket(
+ GetDlci(false, test_server_scn), new_lcid, acl_handle));
+ // We must do security check first
+ tBTM_SEC_CALLBACK* security_callback = nullptr;
+ void* p_port = nullptr;
+ EXPECT_CALL(btm_security_internal_interface_,
+ MultiplexingProtocolAccessRequest(
+ test_address, BT_PSM_RFCOMM, false, BTM_SEC_PROTO_RFCOMM,
+ test_server_scn, NotNull(), NotNull()))
+ .WillOnce(DoAll(SaveArg<5>(&security_callback), SaveArg<6>(&p_port),
+ Return(BTM_SUCCESS)));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, sabm_server_scn);
+
+ VLOG(1) << "Step 10";
+ // After security check, we accept the connection
+ ASSERT_TRUE(security_callback);
+ BT_HDR* ua_server_scn =
+ AllocateWrappedOutgoingL2capAclPacket(CreateQuickUaPacket(
+ GetDlci(false, test_server_scn), new_lcid, acl_handle));
+ EXPECT_CALL(l2cap_interface_, DataWrite(new_lcid, BtHdrEqual(ua_server_scn)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ // Callback should come from server port instead, client port will timeout
+ // in 20 seconds
+ EXPECT_CALL(rfcomm_callback_,
+ PortManagementCallback(PORT_SUCCESS, server_handle, 0));
+ security_callback(&test_address, BT_TRANSPORT_BR_EDR, p_port, BTM_SUCCESS);
+ osi_free(ua_server_scn);
+
+ VLOG(1) << "Step 11";
+ // MPX_CTRL Modem Status Command (MSC)
+ BT_HDR* uih_msc_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickMscPacket(true, GetDlci(false, test_server_scn), new_lcid,
+ acl_handle, true, false, true, true, false, true));
+ BT_HDR* uih_msc_rsp_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickMscPacket(false, GetDlci(false, test_server_scn), new_lcid,
+ acl_handle, false, false, true, true, false, true));
+ // MPX_CTRL Modem Status Response (MSC)
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(new_lcid, BtHdrEqual(uih_msc_rsp_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ BT_HDR* uih_msc_cmd_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+ CreateQuickMscPacket(false, GetDlci(false, test_server_scn), new_lcid,
+ acl_handle, true, false, true, true, false, true));
+ EXPECT_CALL(l2cap_interface_,
+ DataWrite(new_lcid, BtHdrEqual(uih_msc_cmd_to_peer)))
+ .WillOnce(Return(L2CAP_DW_SUCCESS));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, uih_msc_cmd_from_peer);
+ osi_free(uih_msc_rsp_to_peer);
+ osi_free(uih_msc_cmd_to_peer);
+
+ VLOG(1) << "Step 12";
+ BT_HDR* uih_msc_rsp_from_peer = AllocateWrappedIncomingL2capAclPacket(
+ CreateQuickMscPacket(true, GetDlci(false, test_server_scn), new_lcid,
+ acl_handle, false, false, true, true, false, true));
+ l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, uih_msc_rsp_from_peer);
+}
+
+} // namespace
diff --git a/stack/test/rfcomm/stack_rfcomm_test_main.cc b/stack/test/rfcomm/stack_rfcomm_test_main.cc
new file mode 100644
index 0000000..b6a7b25
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_main.cc
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/strings/string_piece.h>
+#include <base/strings/string_util.h>
+#include <gtest/gtest.h>
+
+#include <string>
+
+#include "bt_trace.h"
+
+// Override LogMsg method so that we can output log via VLOG(1)
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {
+ char buffer[256];
+ va_list args;
+ va_start(args, fmt_str);
+ vsnprintf(buffer, 256, fmt_str, args);
+ VLOG(1) << buffer;
+ va_end(args);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (base::CommandLine::InitializedForCurrentProcess()) {
+ LOG(FATAL) << "base::CommandLine::Init should not be called twice";
+ return 1;
+ }
+
+ const char* log_level_arg = nullptr;
+ for (int i = 0; i < argc; ++i) {
+ if (base::StartsWith(base::StringPiece(argv[i]), base::StringPiece("--v="),
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ log_level_arg = argv[i];
+ }
+ }
+ if (log_level_arg == nullptr) {
+ log_level_arg = "--v=0";
+ }
+ const char* logging_argv[] = {"bt_stack", log_level_arg};
+ // Init command line object with logging switches
+ if (!base::CommandLine::Init(2, logging_argv)) {
+ LOG(FATAL) << "base::CommandLine::Init failed, arg0=" << logging_argv[0]
+ << ", arg1=" << logging_argv[1];
+ return 1;
+ }
+
+ logging::LoggingSettings log_settings;
+ if (!logging::InitLogging(log_settings)) {
+ LOG(ERROR) << "Failed to set up logging";
+ }
+
+ // Android already logs thread_id, proc_id, timestamp, so disable those.
+ logging::SetLogItems(false, false, false, false);
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/stack/test/rfcomm/stack_rfcomm_test_utils.cc b/stack/test/rfcomm/stack_rfcomm_test_utils.cc
new file mode 100644
index 0000000..f7745c9
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_utils.cc
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <bitset>
+#include <string>
+#include <vector>
+
+#include "rfc_int.h"
+#include "stack_test_packet_utils.h"
+
+#include "stack_rfcomm_test_utils.h"
+
+namespace bluetooth {
+namespace rfcomm {
+
+uint8_t GetDlci(bool on_originator_side, uint8_t scn) {
+ return static_cast<uint8_t>((scn << 1) + (on_originator_side ? 1 : 0));
+}
+
+uint8_t GetAddressField(bool ea, bool cr, uint8_t dlci) {
+ std::bitset<8> address;
+ address.set(0, ea);
+ // For UIH frame, cr for initiating device is 1, otherwise 0
+ // Otherwise:
+ // Command: Initiator -> Responder: 1
+ // Command: Responder -> Initiator 0
+ // Response: Initiator -> Responder 0
+ // Response: Responder -> Initiator 1
+ // Initiator is defined by the one who send SABM=1 command
+ address.set(1, cr);
+ address |= dlci << 2;
+ return static_cast<uint8_t>(address.to_ulong());
+}
+
+uint8_t GetControlField(bool pf, uint8_t frame_type) {
+ std::bitset<8> control;
+ control |= frame_type;
+ control.set(4, pf);
+ return static_cast<uint8_t>(control.to_ulong());
+}
+
+uint8_t GetFrameTypeFromControlField(uint8_t control_field) {
+ return static_cast<uint8_t>(control_field & ~(0b10000));
+}
+
+std::vector<uint8_t> CreateMccPnFrame(uint8_t dlci, uint8_t i_bits,
+ uint8_t cl_bits, uint8_t priority,
+ uint8_t timer_value, uint16_t rfcomm_mtu,
+ uint8_t max_num_retransmission,
+ uint8_t err_recovery_window_k) {
+ // Data in little endian order
+ std::vector<uint8_t> result;
+ result.push_back(static_cast<uint8_t>(dlci & 0b00111111));
+ result.push_back(static_cast<uint8_t>((cl_bits << 4) | (i_bits & 0x0F)));
+ result.push_back(static_cast<uint8_t>(priority & 0b00111111));
+ result.push_back(timer_value);
+ result.push_back(static_cast<uint8_t>(rfcomm_mtu));
+ result.push_back(static_cast<uint8_t>(rfcomm_mtu >> 8));
+ result.push_back(max_num_retransmission);
+ result.push_back(static_cast<uint8_t>(err_recovery_window_k & 0b111));
+ return result;
+}
+
+std::vector<uint8_t> CreateMccMscFrame(uint8_t dlci, bool fc, bool rtc,
+ bool rtr, bool ic, bool dv) {
+ // Data in little endian order
+ std::vector<uint8_t> result;
+ result.push_back(static_cast<uint8_t>((dlci << 2) | 0b11));
+ std::bitset<8> v24_signals;
+ // EA = 1, single byte
+ v24_signals.set(0, true);
+ v24_signals.set(1, fc);
+ v24_signals.set(2, rtc);
+ v24_signals.set(3, rtr);
+ v24_signals.set(6, ic);
+ v24_signals.set(7, dv);
+ result.push_back(static_cast<uint8_t>(v24_signals.to_ulong()));
+ return result;
+}
+
+std::vector<uint8_t> CreateMultiplexerControlFrame(
+ uint8_t command_type, bool cr, const std::vector<uint8_t>& data) {
+ // Data in little endian order
+ std::vector<uint8_t> result;
+ std::bitset<8> header;
+ header.set(0, true); // EA is always 1
+ header.set(1, cr);
+ header |= command_type << 2;
+ result.push_back(static_cast<uint8_t>(header.to_ulong()));
+ // 7 bit length + EA(1)
+ result.push_back(static_cast<uint8_t>((data.size() << 1) + 1));
+ result.insert(result.end(), data.begin(), data.end());
+ return result;
+}
+
+std::vector<uint8_t> CreateRfcommPacket(uint8_t address, uint8_t control,
+ int credits,
+ const std::vector<uint8_t>& data) {
+ // Data in little endian order
+ std::vector<uint8_t> result;
+ result.push_back(address);
+ result.push_back(control);
+ size_t length = data.size();
+ if ((length & 0b1000000) != 0) {
+ // 15 bits of length in little endian order + EA(0)
+ // Lower 7 bits + EA(0)
+ result.push_back(static_cast<uint8_t>(length) << 1);
+ // Upper 8 bits
+ result.push_back(static_cast<uint8_t>(length >> 8));
+ } else {
+ // 7 bits of length + EA(1)
+ result.push_back(static_cast<uint8_t>((length << 1) + 1));
+ }
+ if (credits > 0) {
+ result.push_back(static_cast<uint8_t>(credits));
+ }
+ result.insert(result.end(), data.begin(), data.end());
+ if (GetFrameTypeFromControlField(control) == RFCOMM_UIH) {
+ result.push_back(rfc_calc_fcs(2, result.data()));
+ } else {
+ result.push_back(
+ rfc_calc_fcs(static_cast<uint16_t>(result.size()), result.data()));
+ }
+ return result;
+}
+
+std::vector<uint8_t> CreateQuickUaPacket(uint8_t dlci, uint16_t l2cap_lcid,
+ uint16_t acl_handle) {
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ uint8_t control_field = GetControlField(true, RFCOMM_UA);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, {});
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+ return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickSabmPacket(uint8_t dlci, uint16_t l2cap_lcid,
+ uint16_t acl_handle) {
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ uint8_t control_field = GetControlField(true, RFCOMM_SABME);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, {});
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+ return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickPnPacket(bool rfc_cr, uint8_t target_dlci,
+ bool mx_cr, uint16_t rfc_mtu,
+ uint8_t cl, uint8_t priority,
+ uint8_t k, uint16_t l2cap_lcid,
+ uint16_t acl_handle) {
+ uint8_t address_field = GetAddressField(true, rfc_cr, RFCOMM_MX_DLCI);
+ uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+ std::vector<uint8_t> mcc_pn_data = CreateMccPnFrame(
+ target_dlci, 0x0, cl, priority, RFCOMM_T1_DSEC, rfc_mtu, RFCOMM_N2, k);
+ std::vector<uint8_t> mcc_payload =
+ CreateMultiplexerControlFrame(0x20, mx_cr, mcc_pn_data);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+ return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickMscPacket(bool rfc_cr, uint8_t dlci,
+ uint16_t l2cap_lcid,
+ uint16_t acl_handle, bool mx_cr,
+ bool fc, bool rtc, bool rtr, bool ic,
+ bool dv) {
+ uint8_t address_field = GetAddressField(true, rfc_cr, RFCOMM_MX_DLCI);
+ uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+ std::vector<uint8_t> mcc_msc_data =
+ CreateMccMscFrame(dlci, fc, rtc, rtr, ic, dv);
+ std::vector<uint8_t> mcc_payload =
+ CreateMultiplexerControlFrame(0x38, mx_cr, mcc_msc_data);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+ return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+ uint16_t l2cap_lcid,
+ uint16_t acl_handle, int credits,
+ const std::vector<uint8_t>& data) {
+ uint8_t address_field = GetAddressField(true, cr, dlci);
+ uint8_t control_field =
+ GetControlField(credits > 0 ? true : false, RFCOMM_UIH);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, credits, data);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+ return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+ uint16_t l2cap_lcid,
+ uint16_t acl_handle, int credits,
+ const std::string& str) {
+ std::vector<uint8_t> data(str.begin(), str.end());
+ return CreateQuickDataPacket(dlci, cr, l2cap_lcid, acl_handle, credits, data);
+}
+
+} // namespace rfcomm
+} // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/rfcomm/stack_rfcomm_test_utils.h b/stack/test/rfcomm/stack_rfcomm_test_utils.h
new file mode 100644
index 0000000..c7fee43
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_utils.h
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <vector>
+
+#include <gmock/gmock.h>
+
+#include "bt_types.h"
+
+namespace bluetooth {
+namespace rfcomm {
+
+class RfcommCallback {
+ public:
+ virtual void PortManagementCallback(uint32_t code, uint16_t port_handle,
+ uint16_t callback_index) = 0;
+ virtual void PortEventCallback(uint32_t code, uint16_t port_handle,
+ uint16_t callback_index) = 0;
+ virtual ~RfcommCallback() = default;
+};
+
+class MockRfcommCallback : public RfcommCallback {
+ public:
+ MOCK_METHOD3(PortManagementCallback, void(uint32_t code, uint16_t port_handle,
+ uint16_t callback_index));
+ MOCK_METHOD3(PortEventCallback, void(uint32_t code, uint16_t port_handle,
+ uint16_t callback_index));
+};
+
+/**
+ * Create DLCI using direction of service channel number
+ *
+ * @param on_originator_side is this a channel on initiator side
+ * @param scn service channel number
+ * @return DLCI
+ */
+uint8_t GetDlci(bool on_originator_side, uint8_t scn);
+
+/**
+ * Create address field in RFCOMM packet
+ *
+ * @param ea end of field byte, true if field only has 1 byte, false otherwise
+ * @param cr command and response bit, true if packet is from initiator,
+ * false otherwise, not actual "command" and "response"
+ * @param dlci DLCI of this pcaket, RFCOMM_MX_DLCI for multiplexer control
+ * @return address field
+ */
+uint8_t GetAddressField(bool ea, bool cr, uint8_t dlci);
+
+/**
+ * Create control field in RFCOMM packet
+ *
+ * @param pf Poll/Finish bit, normally 1 for multiplexer control channel
+ * @param frame_type frame type
+ * @return control field
+ */
+uint8_t GetControlField(bool pf, uint8_t frame_type);
+
+/**
+ * Create Multiplexer control channel parameter negotiation frame
+ *
+ * @param dlci DLCI to be configured
+ * @param i_bits i bits
+ * @param cl_bits cl bits
+ * @param priority priority
+ * @param timer_value timer value
+ * @param rfcomm_mtu rfcomm mtu
+ * @param max_num_retransmission maximum number of retransmission
+ * @param err_recovery_window_k error recovery window k
+ * @return vector of bytes of this frame
+ */
+std::vector<uint8_t> CreateMccPnFrame(uint8_t dlci, uint8_t i_bits,
+ uint8_t cl_bits, uint8_t priority,
+ uint8_t timer_value, uint16_t rfcomm_mtu,
+ uint8_t max_num_retransmission,
+ uint8_t err_recovery_window_k);
+/**
+ * Create Multiplexer Control Modem Status Configuration Frame
+ *
+ * @param dlci DLCI to be configured
+ * @param fc flow control
+ * @param rtc ready to communicate
+ * @param rtr ready to receive
+ * @param ic incoming call indicator
+ * @param dv is data valid
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateMccMscFrame(uint8_t dlci, bool fc, bool rtc,
+ bool rtr, bool ic, bool dv);
+
+/**
+ * Create Multiplexer Control Frame
+ *
+ * @param command_type type of command
+ * @param cr command or response flag, true when this is a command, false when
+ * this is a response, regardless of connection direction
+ * @param data frame data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateMultiplexerControlFrame(
+ uint8_t command_type, bool cr, const std::vector<uint8_t>& data);
+
+/**
+ * Create a general RFCOMM packet
+ *
+ * @param address address byte
+ * @param control control byte
+ * @param credits number of credits, <= 0 will cause this to be ignored
+ * @param data frame data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateRfcommPacket(uint8_t address, uint8_t control,
+ int credits,
+ const std::vector<uint8_t>& data);
+/*
+ * Various shortcut for getting frequently used packets
+ */
+
+/**
+ * Create SABM packet that is used to connect to a service channel number in a
+ * multiplexer
+ *
+ * @param dlci DLCI to be connected
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickSabmPacket(uint8_t dlci, uint16_t l2cap_lcid,
+ uint16_t acl_handle);
+
+/**
+ * Create UA packet that is used to acknowledge service channel connection
+ *
+ * @param dlci DLCI to be connected
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickUaPacket(uint8_t dlci, uint16_t l2cap_lcid,
+ uint16_t acl_handle);
+
+/**
+ * Create parameter negotiation packet used to setup parameters for a DLCI
+ *
+ * @param rfc_cr RFCOMM command/response bit, true of initiator
+ * @param target_dlci DLCI to be configured
+ * @param mx_cr multiplexer command or reponse, regardless of initiator
+ * @param rfc_mtu RFCOMM mtu to be used for DLCI
+ * @param cl CL bit
+ * @param priority prirority
+ * @param k error recovery window k
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickPnPacket(bool rfc_cr, uint8_t target_dlci,
+ bool mx_cr, uint16_t rfc_mtu,
+ uint8_t cl, uint8_t priority,
+ uint8_t k, uint16_t l2cap_lcid,
+ uint16_t acl_handle);
+
+/**
+ * Create modem signal control packet
+ *
+ * @param rfc_cr RFCOMM command/response bit, true of initiator
+ * @param dlci DLCI to be configured
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @param mx_cr multiplexer command or reponse, regardless of initiator
+ * @param fc flow control
+ * @param rtc ready to communicate
+ * @param rtr ready to receive
+ * @param ic incoming call indicator
+ * @param dv data valid
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickMscPacket(bool rfc_cr, uint8_t dlci,
+ uint16_t l2cap_lcid,
+ uint16_t acl_handle, bool mx_cr,
+ bool fc, bool rtc, bool rtr, bool ic,
+ bool dv);
+
+/**
+ * Create a quick RFCOMM data packet
+ *
+ * @param dlci DLCI of this packet
+ * @param cr command or control, true for initiator
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @param credits number of credits
+ * @param data data bytes
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+ uint16_t l2cap_lcid,
+ uint16_t acl_handle, int credits,
+ const std::vector<uint8_t>& data);
+
+/**
+ * Create a quick RFCOMM data packet
+ *
+ * @param dlci DLCI of this packet
+ * @param cr command or control, true for initiator
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @param credits number of credits
+ * @param str message in string format
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+ uint16_t l2cap_lcid,
+ uint16_t acl_handle, int credits,
+ const std::string& str);
+
+} // namespace rfcomm
+} // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc b/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc
new file mode 100644
index 0000000..3d9a2d5
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc
@@ -0,0 +1,246 @@
+/******************************************************************************
+ *
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "rfcdefs.h"
+#include "stack_rfcomm_test_utils.h"
+#include "stack_test_packet_utils.h"
+
+namespace {
+
+using testing::ElementsAreArray;
+
+using bluetooth::CreateL2capDataPacket;
+using bluetooth::CreateAclPacket;
+using bluetooth::AllocateWrappedIncomingL2capAclPacket;
+
+using bluetooth::rfcomm::GetDlci;
+using bluetooth::rfcomm::GetAddressField;
+using bluetooth::rfcomm::GetControlField;
+using bluetooth::rfcomm::CreateMccPnFrame;
+using bluetooth::rfcomm::CreateMccMscFrame;
+using bluetooth::rfcomm::CreateMultiplexerControlFrame;
+using bluetooth::rfcomm::CreateRfcommPacket;
+using bluetooth::rfcomm::CreateQuickDataPacket;
+using bluetooth::rfcomm::CreateQuickPnPacket;
+using bluetooth::rfcomm::CreateQuickSabmPacket;
+using bluetooth::rfcomm::CreateQuickUaPacket;
+using bluetooth::rfcomm::CreateQuickMscPacket;
+
+const uint8_t kIncomingSabmChannel0[] = {0x08, 0x20, 0x08, 0x00, 0x04, 0x00,
+ 0x5c, 0x00, 0x03, 0x3f, 0x01, 0x1c};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateSabmChannel0Packet) {
+ uint8_t dlci = GetDlci(false, 0);
+ EXPECT_EQ(dlci, 0);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x03);
+ uint8_t control_field = GetControlField(true, RFCOMM_SABME);
+ EXPECT_EQ(control_field, 0x3F);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, {});
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x005c, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingSabmChannel0));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateSabmChannel0Packet) {
+ EXPECT_THAT(CreateQuickSabmPacket(RFCOMM_MX_DLCI, 0x005c, 0x0008),
+ ElementsAreArray(kIncomingSabmChannel0));
+}
+
+const uint8_t kOutgoingUaChannel0[] = {0x08, 0x20, 0x08, 0x00, 0x04, 0x00,
+ 0x00, 0x17, 0x03, 0x73, 0x01, 0xd7};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUaPacket) {
+ uint8_t dlci = GetDlci(false, 0);
+ EXPECT_EQ(dlci, 0);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x03);
+ uint8_t control_field = GetControlField(true, RFCOMM_UA);
+ EXPECT_EQ(control_field, 0x73);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, {});
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x1700, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kOutgoingUaChannel0));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUaPacket) {
+ EXPECT_THAT(CreateQuickUaPacket(RFCOMM_MX_DLCI, 0x1700, 0x0008),
+ ElementsAreArray(kOutgoingUaChannel0));
+}
+
+const uint8_t kIncomingUihPnSetChannelTo3[] = {
+ 0x08, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x5c, 0x00, 0x03, 0xef, 0x15,
+ 0x83, 0x11, 0x06, 0xf0, 0x00, 0x00, 0x74, 0x03, 0x00, 0x01, 0x70};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUihPnSetChannel3Packet) {
+ uint8_t dlci = GetDlci(false, 0);
+ EXPECT_EQ(dlci, 0);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x03);
+ uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+ EXPECT_EQ(control_field, 0xEF);
+ uint8_t new_dlci = GetDlci(false, 3);
+ EXPECT_EQ(new_dlci, 6);
+ std::vector<uint8_t> mcc_pn_data =
+ CreateMccPnFrame(new_dlci, 0x0, 0xF, 0, 0, 884, 0, 1);
+ std::vector<uint8_t> mcc_payload =
+ CreateMultiplexerControlFrame(0x20, true, mcc_pn_data);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x005c, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingUihPnSetChannelTo3));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUihPnSetChannel3Packet) {
+ EXPECT_THAT(CreateQuickPnPacket(true, GetDlci(false, 3), true, 884, 0xF, 0, 1,
+ 0x005c, 0x0008),
+ ElementsAreArray(kIncomingUihPnSetChannelTo3));
+}
+
+const uint8_t kIncomingSabmChannel3[] = {0x08, 0x20, 0x08, 0x00, 0x04, 0x00,
+ 0x5c, 0x00, 0x1b, 0x3f, 0x01, 0xd3};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateSabmChannel3Packet) {
+ uint8_t dlci = GetDlci(false, 3);
+ EXPECT_EQ(dlci, 6);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x1b);
+ uint8_t control_field = GetControlField(true, RFCOMM_SABME);
+ EXPECT_EQ(control_field, 0x3F);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, {});
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x005c, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingSabmChannel3));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateQuickSabmChannel3Packet) {
+ EXPECT_THAT(CreateQuickSabmPacket(GetDlci(false, 3), 0x005c, 0x0008),
+ ElementsAreArray(kIncomingSabmChannel3));
+}
+
+const uint8_t kIncomingUihMscCmdFrame[] = {0x08, 0x20, 0x0c, 0x00, 0x08, 0x00,
+ 0x5c, 0x00, 0x03, 0xef, 0x09, 0xe3,
+ 0x05, 0x1b, 0x8d, 0x70};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUihMscCmdPacket) {
+ uint8_t dlci = GetDlci(false, 0);
+ EXPECT_EQ(dlci, 0);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x03);
+ uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+ EXPECT_EQ(control_field, 0xEF);
+ uint8_t new_dlci = GetDlci(false, 3);
+ EXPECT_EQ(new_dlci, 6);
+ std::vector<uint8_t> mcc_msc_data =
+ CreateMccMscFrame(new_dlci, false, true, true, false, true);
+ std::vector<uint8_t> mcc_payload =
+ CreateMultiplexerControlFrame(0x38, true, mcc_msc_data);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x005c, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingUihMscCmdFrame));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUihMscCmdPacket) {
+ EXPECT_THAT(CreateQuickMscPacket(true, GetDlci(false, 3), 0x005c, 0x0008,
+ true, false, true, true, false, true),
+ ElementsAreArray(kIncomingUihMscCmdFrame));
+}
+
+const uint8_t kIncomingUihMscResponseFrame[] = {
+ 0x08, 0x20, 0x0c, 0x00, 0x08, 0x00, 0x5c, 0x00,
+ 0x03, 0xef, 0x09, 0xe1, 0x05, 0x1b, 0x8d, 0x70};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUihMscResponsePacket) {
+ uint8_t dlci = GetDlci(false, 0);
+ EXPECT_EQ(dlci, 0);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x03);
+ uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+ EXPECT_EQ(control_field, 0xEF);
+ uint8_t new_dlci = GetDlci(false, 3);
+ EXPECT_EQ(new_dlci, 6);
+ std::vector<uint8_t> mcc_msc_data =
+ CreateMccMscFrame(new_dlci, false, true, true, false, true);
+ std::vector<uint8_t> mcc_payload =
+ CreateMultiplexerControlFrame(0x38, false, mcc_msc_data);
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x005c, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingUihMscResponseFrame));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUihMscResponsePacket) {
+ EXPECT_THAT(CreateQuickMscPacket(true, GetDlci(false, 3), 0x005c, 0x0008,
+ false, false, true, true, false, true),
+ ElementsAreArray(kIncomingUihMscResponseFrame));
+}
+
+const uint8_t kIncomingBrsfFrame[] = {0x08, 0x20, 0x15, 0x00, 0x11, 0x00, 0x5c,
+ 0x00, 0x1b, 0xff, 0x19, 0x06, 0x41, 0x54,
+ 0x2b, 0x42, 0x52, 0x53, 0x46, 0x3d, 0x39,
+ 0x35, 0x39, 0x0d, 0x93};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateDataPacket) {
+ uint8_t dlci = GetDlci(false, 3);
+ EXPECT_EQ(dlci, 6);
+ uint8_t address_field = GetAddressField(true, true, dlci);
+ EXPECT_EQ(address_field, 0x1B);
+ uint8_t control_field = GetControlField(true, RFCOMM_UIH);
+ EXPECT_EQ(control_field, 0xFF);
+ const std::string data_str = "AT+BRSF=959\r";
+ const std::vector<uint8_t> data(data_str.begin(), data_str.end());
+ std::vector<uint8_t> rfcomm_packet =
+ CreateRfcommPacket(address_field, control_field, 6, data);
+ std::vector<uint8_t> l2cap_packet =
+ CreateL2capDataPacket(0x005c, rfcomm_packet);
+ std::vector<uint8_t> acl_packet =
+ CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+ EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingBrsfFrame));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateDataPacket) {
+ EXPECT_THAT(CreateQuickDataPacket(GetDlci(false, 3), true, 0x005c, 0x0008, 6,
+ "AT+BRSF=959\r"),
+ ElementsAreArray(kIncomingBrsfFrame));
+}
+
+} // namespace
\ No newline at end of file
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index 9fc0676..066e8e1 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -20,10 +20,11 @@
net_test_btu_message_loop
net_test_osi
net_test_performance
+ net_test_stack_rfcomm
)
known_remote_tests=(
- net_test_rfcomm
+ net_test_rfcomm_suite
)
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index fb501c7..ed5b531 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -28,7 +28,7 @@
// Bluetooth test suite for target
// ========================================================
cc_test {
- name: "net_test_rfcomm",
+ name: "net_test_rfcomm_suite",
defaults: ["fluoride_defaults"],
include_dirs: ["system/bt"],
srcs: [
diff --git a/tools/mcap_tool/Android.bp b/tools/mcap_tool/Android.bp
index eec750c..137578d 100644
--- a/tools/mcap_tool/Android.bp
+++ b/tools/mcap_tool/Android.bp
@@ -29,7 +29,6 @@
"system/bt/stack/include",
"system/bt/btcore/include",
],
- tags: ["debug", "optional"],
shared_libs: [
"libcutils",
"libutils",