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",