Merge the 2021-02-05 SPL branch from AOSP-Partner

* security-aosp-pi-release:
  ACL: Drop broadcasts
  Fix potential OOB write in libbluetooth
  Fix a security issue in sdp_server.cc
  Check Classic key before cross-key derivation
  Send a response to an smp security request depending on the callback event
  Return after removing sample LTK device
  Check whether local device is an ATV device to determine whether to show the consent dialog for BLE pairing in JUSTWORKS and ENCRYPTION_ONLY mode
  Shows a consent dialog on the local device when pairing a bluetooth low energy device if the local device has a display.

Change-Id: Iabdf85de3f3a41f828f5cd9d443a3c9b5359b29d
diff --git a/audio_a2dp_hw/src/audio_a2dp_hw.cc b/audio_a2dp_hw/src/audio_a2dp_hw.cc
index 3622298..7b82dd9 100644
--- a/audio_a2dp_hw/src/audio_a2dp_hw.cc
+++ b/audio_a2dp_hw/src/audio_a2dp_hw.cc
@@ -611,6 +611,7 @@
       stream_config.is_stereo_to_mono = true;
       break;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
       stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
       stream_config.is_stereo_to_mono = false;
       break;
@@ -1075,6 +1076,7 @@
       number_of_channels = 1;
       break;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
       number_of_channels = 2;
       break;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
@@ -1285,7 +1287,9 @@
       if (!param.empty()) param += "|";
       param += "AUDIO_CHANNEL_OUT_MONO";
     }
-    if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO) {
+    if (codec_capability.channel_mode &
+        (BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO |
+         BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL)) {
       if (!param.empty()) param += "|";
       param += "AUDIO_CHANNEL_OUT_STEREO";
     }
diff --git a/audio_a2dp_hw/test/audio_a2dp_hw_test.cc b/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
index 8fcbae5..ce64e6e 100644
--- a/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
+++ b/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
@@ -67,6 +67,7 @@
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
       return 1;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
       return 2;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       break;
diff --git a/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc b/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc
index c5d0e2b..55b0515 100644
--- a/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc
+++ b/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc
@@ -67,6 +67,7 @@
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
       return 1;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
       return 2;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       break;
diff --git a/device/include/controller.h b/device/include/controller.h
index c1fe337..f1c85aa 100644
--- a/device/include/controller.h
+++ b/device/include/controller.h
@@ -85,6 +85,7 @@
   uint8_t (*get_ble_resolving_list_max_size)(void);
   void (*set_ble_resolving_list_max_size)(int resolving_list_max_size);
   uint8_t* (*get_local_supported_codecs)(uint8_t* number_of_codecs);
+  bool (*supports_ble_offload_features)(void);
   uint8_t (*get_le_all_initiating_phys)(void);
 
 } controller_t;
diff --git a/device/src/controller.cc b/device/src/controller.cc
index 02a3998..2cf024f 100644
--- a/device/src/controller.cc
+++ b/device/src/controller.cc
@@ -22,6 +22,7 @@
 
 #include <base/logging.h>
 
+#include "bt_target.h"
 #include "bt_types.h"
 #include "btcore/include/event_mask.h"
 #include "btcore/include/module.h"
@@ -77,6 +78,7 @@
 
 static bool readable;
 static bool ble_supported;
+static bool ble_offload_features_supported;
 static bool simple_pairing_supported;
 static bool secure_connections_supported;
 
@@ -119,6 +121,9 @@
       AWAIT_COMMAND(packet_factory->make_read_local_supported_commands());
   packet_parser->parse_read_local_supported_commands_response(
       response, supported_commands, HCI_SUPPORTED_COMMANDS_ARRAY_SIZE);
+#if (BTM_SCO_ENHANCED_SYNC_ENABLED == FALSE)
+  supported_commands[29] &= ~0x08;
+#endif
 
   // Read page 0 of the controller features next
   uint8_t page_number = 0;
@@ -171,14 +176,19 @@
     page_number++;
   }
 
+  // read BLE offload features support from controller
+  response = AWAIT_COMMAND(packet_factory->make_ble_read_offload_features_support());
+  packet_parser->parse_ble_read_offload_features_response(response, &ble_offload_features_supported);
 #if (SC_MODE_INCLUDED == TRUE)
-  secure_connections_supported =
-      HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array);
-  if (secure_connections_supported) {
-    response = AWAIT_COMMAND(
-        packet_factory->make_write_secure_connections_host_support(
-            HCI_SC_MODE_ENABLED));
-    packet_parser->parse_generic_command_complete(response);
+  if(ble_offload_features_supported) {
+    secure_connections_supported =
+        HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array);
+    if (secure_connections_supported) {
+      response = AWAIT_COMMAND(
+          packet_factory->make_write_secure_connections_host_support(
+              HCI_SC_MODE_ENABLED));
+      packet_parser->parse_generic_command_complete(response);
+    }
   }
 #endif
 
@@ -436,6 +446,12 @@
   return HCI_LE_PERIODIC_ADVERTISING_SUPPORTED(features_ble.as_array);
 }
 
+static bool supports_ble_offload_features(void) {
+  assert(readable);
+  assert(ble_supported);
+  return ble_offload_features_supported;
+}
+
 static uint16_t get_acl_data_size_classic(void) {
   CHECK(readable);
   return acl_data_size_classic;
@@ -573,6 +589,7 @@
     get_ble_resolving_list_max_size,
     set_ble_resolving_list_max_size,
     get_local_supported_codecs,
+    supports_ble_offload_features,
     get_le_all_initiating_phys};
 
 const controller_t* controller_get_interface() {
diff --git a/hci/include/hci_packet_factory.h b/hci/include/hci_packet_factory.h
index e7cb47b..91caa7a 100644
--- a/hci/include/hci_packet_factory.h
+++ b/hci/include/hci_packet_factory.h
@@ -46,6 +46,7 @@
   BT_HDR* (*make_ble_read_number_of_supported_advertising_sets)(void);
   BT_HDR* (*make_ble_set_event_mask)(const bt_event_mask_t* event_mask);
   BT_HDR* (*make_read_local_supported_codecs)(void);
+  BT_HDR *(*make_ble_read_offload_features_support)(void);
 } hci_packet_factory_t;
 
 const hci_packet_factory_t* hci_packet_factory_get_interface();
diff --git a/hci/include/hci_packet_parser.h b/hci/include/hci_packet_parser.h
index 8878cb9..06af557 100644
--- a/hci/include/hci_packet_parser.h
+++ b/hci/include/hci_packet_parser.h
@@ -83,6 +83,9 @@
       BT_HDR* response, uint8_t* number_of_local_supported_codecs,
       uint8_t* local_supported_codecs);
 
+  void (*parse_ble_read_offload_features_response)(
+    BT_HDR *response,
+    bool *ble_offload_features_supported);
 } hci_packet_parser_t;
 
 const hci_packet_parser_t* hci_packet_parser_get_interface();
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index 5111fc5..6d7993d 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -472,7 +472,7 @@
 
   // We shouldn't try to recover the stack from this command timeout.
   // If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
-  abort();
+  exit(0);
 }
 
 // Print debugging information and quit. Don't dereference original_wait_entry.
@@ -688,7 +688,26 @@
 
     return wait_entry;
   }
+  // look for any command complete with improper VS Opcode
+  for (const list_node_t *node = list_begin(commands_pending_response);
+      node != list_end(commands_pending_response);
+      node = list_next(node)) {
+    waiting_command_t *wait_entry =
+        reinterpret_cast<waiting_command_t*> (list_node(node));
 
+    if (wait_entry && (wait_entry->opcode != opcode) &&
+        (((wait_entry->opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) &&
+        ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC))) {
+        LOG_DEBUG(LOG_TAG,"%s VS event found treat it as valid 0x%x", __func__, opcode);
+    }
+    else {
+        continue;
+    }
+
+    list_remove(commands_pending_response, wait_entry);
+
+    return wait_entry;
+  }
   return NULL;
 }
 
diff --git a/hci/src/hci_packet_factory.cc b/hci/src/hci_packet_factory.cc
index ca0fb5f..1cff9f6 100644
--- a/hci/src/hci_packet_factory.cc
+++ b/hci/src/hci_packet_factory.cc
@@ -159,6 +159,10 @@
   return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CODECS);
 }
 
+static BT_HDR* make_ble_read_offload_features_support(void) {
+    return make_command_no_params(HCI_BLE_VENDOR_CAP_OCF);
+}
+
 static BT_HDR* make_ble_set_event_mask(const bt_event_mask_t* event_mask) {
   uint8_t* stream;
   uint8_t parameter_size = sizeof(bt_event_mask_t);
@@ -220,7 +224,8 @@
     make_ble_read_maximum_advertising_data_length,
     make_ble_read_number_of_supported_advertising_sets,
     make_ble_set_event_mask,
-    make_read_local_supported_codecs};
+    make_read_local_supported_codecs,
+    make_ble_read_offload_features_support};
 
 const hci_packet_factory_t* hci_packet_factory_get_interface() {
   buffer_allocator = buffer_allocator_get_interface();
diff --git a/hci/src/hci_packet_parser.cc b/hci/src/hci_packet_parser.cc
index b1efd44..3f4e46c 100644
--- a/hci/src/hci_packet_parser.cc
+++ b/hci/src/hci_packet_parser.cc
@@ -85,6 +85,20 @@
   buffer_allocator->free(response);
 }
 
+static void parse_ble_read_offload_features_response(
+    BT_HDR *response,
+    bool *ble_offload_features_supported) {
+
+  uint8_t *stream = read_command_complete_header(response, NO_OPCODE_CHECKING, 0 /* bytes after */);
+  if(stream) {
+    *ble_offload_features_supported  = true;
+  } else {
+    *ble_offload_features_supported  = false;
+  }
+
+  buffer_allocator->free(response);
+}
+
 static void parse_read_bd_addr_response(BT_HDR* response,
                                         RawAddress* address_ptr) {
   uint8_t* stream = read_command_complete_header(
@@ -281,7 +295,8 @@
     parse_ble_read_maximum_data_length_response,
     parse_ble_read_maximum_advertising_data_length,
     parse_ble_read_number_of_supported_advertising_sets,
-    parse_read_local_supported_codecs_response};
+    parse_read_local_supported_codecs_response,
+    parse_ble_read_offload_features_response};
 
 const hci_packet_parser_t* hci_packet_parser_get_interface() {
   buffer_allocator = buffer_allocator_get_interface();
diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h
index bdb1285..0fa4982 100644
--- a/include/hardware/bt_av.h
+++ b/include/hardware/bt_av.h
@@ -104,7 +104,8 @@
 typedef enum {
   BTAV_A2DP_CODEC_CHANNEL_MODE_NONE = 0x0,
   BTAV_A2DP_CODEC_CHANNEL_MODE_MONO = 0x1 << 0,
-  BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO = 0x1 << 1
+  BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO = 0x1 << 1,
+  BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL = 0x1 << 2
 } btav_a2dp_codec_channel_mode_t;
 
 /*
@@ -211,6 +212,9 @@
     AppendCapability(channel_mode_str,
                      (channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO),
                      "STEREO");
+    AppendCapability(channel_mode_str,
+                     (channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL),
+                     "DUAL_CHANNEL");
 
     return "codec: " + codec_name_str +
            " priority: " + std::to_string(codec_priority) +
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index cf09b15..3de5510 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -287,6 +287,12 @@
 #define BTM_DISC_DURING_RS TRUE
 #endif
 
+/*  This is used to work around a controller bug that report supporting
+ *  enhanced synchronous commands */
+#ifndef BTM_SCO_ENHANCED_SYNC_ENABLED
+#define BTM_SCO_ENHANCED_SYNC_ENABLED TRUE
+#endif
+
 /**************************
  * Initial SCO TX credit
  ************************/
diff --git a/osi/src/alarm.cc b/osi/src/alarm.cc
index 07d8704..bdf977f 100644
--- a/osi/src/alarm.cc
+++ b/osi/src/alarm.cc
@@ -115,12 +115,6 @@
 int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
 static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
 
-#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
-static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
-#else
-static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
-#endif
-
 // This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
 // functions execute serially and not concurrently. As a result, this mutex
 // also protects the |alarms| list.
@@ -330,7 +324,11 @@
   if (!timer_create_internal(CLOCK_ID, &timer)) goto error;
   timer_initialized = true;
 
-  if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) goto error;
+  if (!timer_create_internal(CLOCK_BOOTTIME_ALARM, &wakeup_timer)) {
+    if (!timer_create_internal(CLOCK_BOOTTIME, &wakeup_timer)) {
+      goto error;
+    }
+  }
   wakeup_timer_initialized = true;
 
   alarm_expired = semaphore_new(0);
diff --git a/osi/src/wakelock.cc b/osi/src/wakelock.cc
index 46c462c..389c681 100644
--- a/osi/src/wakelock.cc
+++ b/osi/src/wakelock.cc
@@ -213,6 +213,10 @@
 }
 
 void wakelock_cleanup(void) {
+  if (wakelock_stats.is_acquired) {
+    LOG_ERROR(LOG_TAG, "%s releasing wake lock as part of cleanup", __func__);
+    wakelock_release();
+  }
   wake_lock_path.clear();
   wake_unlock_path.clear();
   initialized = PTHREAD_ONCE_INIT;
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
index 7792631..e55b199 100644
--- a/stack/a2dp/a2dp_aac.cc
+++ b/stack/a2dp/a2dp_aac.cc
@@ -952,6 +952,7 @@
         return true;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       break;
   }
@@ -1223,6 +1224,7 @@
         codec_config_.channel_mode = codec_user_config_.channel_mode;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
       codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 196b5f8..699faec 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -326,6 +326,9 @@
     uint8_t* p_result_codec_config, bool* p_restart_input,
     bool* p_restart_output, bool* p_config_updated) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  auto stereo_dualchannel_inv_mask =
+      ~(BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL |
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO);
   *p_restart_input = false;
   *p_restart_output = false;
   *p_config_updated = false;
@@ -356,7 +359,9 @@
   if ((saved_codec_config.sample_rate != new_codec_config.sample_rate) ||
       (saved_codec_config.bits_per_sample !=
        new_codec_config.bits_per_sample) ||
-      (saved_codec_config.channel_mode != new_codec_config.channel_mode)) {
+      ((saved_codec_config.channel_mode != new_codec_config.channel_mode) &&
+       (saved_codec_config.channel_mode & stereo_dualchannel_inv_mask) !=
+           (new_codec_config.channel_mode & stereo_dualchannel_inv_mask))) {
     *p_restart_input = true;
   }
 
@@ -485,6 +490,10 @@
     if (!result.empty()) result += "|";
     result += "STEREO";
   }
+  if (codec_channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL) {
+    if (!result.empty()) result += "|";
+    result += "DUAL_CHANNEL";
+  }
   if (result.empty()) {
     std::stringstream ss;
     ss << "UnknownChannelMode(0x" << std::hex << codec_channel_mode << ")";
diff --git a/stack/a2dp/a2dp_sbc.cc b/stack/a2dp/a2dp_sbc.cc
index bef5bf9..d6c38d0 100644
--- a/stack/a2dp/a2dp_sbc.cc
+++ b/stack/a2dp/a2dp_sbc.cc
@@ -55,8 +55,9 @@
 
 /* SBC Source codec capabilities */
 static const tA2DP_SBC_CIE a2dp_sbc_source_caps = {
-    (A2DP_SBC_IE_SAMP_FREQ_44),                         /* samp_freq */
-    (A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_JOINT), /* ch_mode */
+    (A2DP_SBC_IE_SAMP_FREQ_44),        /* samp_freq */
+    (A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_JOINT |
+     A2DP_SBC_IE_CH_MD_DUAL),          /* ch_mode */
     (A2DP_SBC_IE_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
      A2DP_SBC_IE_BLOCKS_4),            /* block_len */
     A2DP_SBC_IE_SUBBAND_8,             /* num_subbands */
@@ -832,10 +833,11 @@
   if (config_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO)
     result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
 
-  if (config_cie.ch_mode & (A2DP_SBC_IE_CH_MD_STEREO | A2DP_SBC_IE_CH_MD_JOINT |
-                            A2DP_SBC_IE_CH_MD_DUAL)) {
+  if (config_cie.ch_mode & (A2DP_SBC_IE_CH_MD_STEREO | A2DP_SBC_IE_CH_MD_JOINT))
     result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
-  }
+
+  if (config_cie.ch_mode & A2DP_SBC_IE_CH_MD_DUAL)
+    result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
 }
 
 A2dpCodecConfigSbcSource::A2dpCodecConfigSbcSource(
@@ -861,7 +863,8 @@
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
   if (a2dp_sbc_source_caps.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
-    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+    codec_local_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
   }
 }
 
@@ -988,7 +991,7 @@
   }
   if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
     p_result->ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
-    p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+    p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
     return true;
   }
   if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
@@ -1027,9 +1030,12 @@
         p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
         return true;
       }
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
       if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
         p_result->ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
-        p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+        p_codec_config->channel_mode =
+            BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
         return true;
       }
       break;
@@ -1079,17 +1085,9 @@
   }
   // Try using the prefered peer codec config (if valid), instead of the peer
   // capability.
-  if (is_capability) {
-    if (is_source_) {
-      if (A2DP_IsPeerSinkCodecValidSbc(ota_codec_peer_config_)) {
-        status =
-            A2DP_ParseInfoSbc(&peer_info_cie, ota_codec_peer_config_, false);
-      }
-    } else {
-      if (A2DP_IsPeerSourceCodecValidSbc(ota_codec_peer_config_)) {
-        status =
-            A2DP_ParseInfoSbc(&peer_info_cie, ota_codec_peer_config_, false);
-      }
+  if (is_capability && !is_source_) {
+    if (A2DP_IsPeerSourceCodecValidSbc(ota_codec_peer_config_)) {
+      status = A2DP_ParseInfoSbc(&peer_info_cie, ota_codec_peer_config_, false);
     }
     if (status != A2DP_SUCCESS) {
       // Use the peer codec capability
@@ -1263,11 +1261,12 @@
         codec_config_.channel_mode = codec_user_config_.channel_mode;
         break;
       }
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
       if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
         result_config_cie.ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
         codec_capability_.channel_mode = codec_user_config_.channel_mode;
         codec_config_.channel_mode = codec_user_config_.channel_mode;
-        break;
       }
       break;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
@@ -1293,7 +1292,7 @@
     }
     if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
       codec_selectable_capability_.channel_mode |=
-          BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+          BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
     }
 
     if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
@@ -1301,10 +1300,11 @@
     // Compute the common capability
     if (ch_mode & A2DP_SBC_IE_CH_MD_MONO)
       codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
-    if (ch_mode & (A2DP_SBC_IE_CH_MD_JOINT | A2DP_SBC_IE_CH_MD_STEREO |
-                   A2DP_SBC_IE_CH_MD_DUAL)) {
+    if (ch_mode & (A2DP_SBC_IE_CH_MD_JOINT | A2DP_SBC_IE_CH_MD_STEREO)) {
       codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
     }
+    if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL)
+      codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
 
     // No user preference - use the codec audio config
     if (select_audio_channel_mode(&codec_audio_config_, ch_mode,
@@ -1507,7 +1507,7 @@
   }
   if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
     codec_selectable_capability_.channel_mode |=
-        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+        BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL;
   }
 
   status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
diff --git a/stack/a2dp/a2dp_sbc_encoder.cc b/stack/a2dp/a2dp_sbc_encoder.cc
index bd09989..fa3342b 100644
--- a/stack/a2dp/a2dp_sbc_encoder.cc
+++ b/stack/a2dp/a2dp_sbc_encoder.cc
@@ -38,8 +38,20 @@
 // A2DP SBC encoder interval in milliseconds.
 #define A2DP_SBC_ENCODER_INTERVAL_MS 20
 
-/* High quality quality setting @ 44.1 khz */
-#define A2DP_SBC_DEFAULT_BITRATE 328
+/*
+ * Higher quality setting. 492 kbps @ 48 khz, 452 kbps @ 44.1 khz.
+ * Up to 4 frames for 2DH5, 6 frames for 3DH5.
+ */
+#define A2DP_SBC_DEFAULT_BITRATE 454
+#define A2DP_SBC_48KHZ_BITRATE 494
+
+/*
+ * SBC Dual Channel (SBC HD) 3DH5 bitrates.
+ * 600 kbps @ 48 khz, 551.3 kbps @ 44.1 khz.
+ * Up to 5 frames for 3DH5.
+ */
+#define A2DP_SBC_3DH5_DEFAULT_BITRATE 552
+#define A2DP_SBC_3DH5_48KHZ_BITRATE 601
 
 #define A2DP_SBC_NON_EDR_MAX_RATE 229
 
@@ -48,10 +60,17 @@
  * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
  */
 #define MAX_2MBPS_AVDTP_MTU 663
+
+/*
+ * 3DH5 minimum safe payload size for 4 audio frames of:
+ * 817 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
+ */
+#define MIN_3MBPS_AVDTP_SAFE_MTU 801
+
 #define A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK 3
 
-#define A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1 119
-#define A2DP_SBC_MAX_HQ_FRAME_SIZE_48 115
+#define A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1 165
+#define A2DP_SBC_MAX_HQ_FRAME_SIZE_48 165
 
 /* Define the bitrate step when trying to match bitpool value */
 #define A2DP_SBC_BITRATE_STEP 5
@@ -835,6 +854,16 @@
 static uint16_t a2dp_sbc_source_rate() {
   uint16_t rate = A2DP_SBC_DEFAULT_BITRATE;
 
+  if (a2dp_sbc_encoder_cb.sbc_encoder_params.s16SamplingFreq == SBC_sf48000)
+    rate = A2DP_SBC_48KHZ_BITRATE;
+
+  if (a2dp_sbc_encoder_cb.peer_supports_3mbps &&
+      a2dp_sbc_encoder_cb.TxAaMtuSize >= MIN_3MBPS_AVDTP_SAFE_MTU) {
+    rate = A2DP_SBC_3DH5_DEFAULT_BITRATE;
+    if (a2dp_sbc_encoder_cb.sbc_encoder_params.s16SamplingFreq == SBC_sf48000)
+      rate = A2DP_SBC_3DH5_48KHZ_BITRATE;
+  }
+
   /* restrict bitrate if a2dp link is non-edr */
   if (!a2dp_sbc_encoder_cb.is_peer_edr) {
     rate = A2DP_SBC_NON_EDR_MAX_RATE;
diff --git a/stack/a2dp/a2dp_vendor_aptx.cc b/stack/a2dp/a2dp_vendor_aptx.cc
index 7017f06..8d903e2 100644
--- a/stack/a2dp/a2dp_vendor_aptx.cc
+++ b/stack/a2dp/a2dp_vendor_aptx.cc
@@ -587,6 +587,7 @@
         return true;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       break;
   }
@@ -788,6 +789,7 @@
         codec_config_.channel_mode = codec_user_config_.channel_mode;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
       codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd.cc b/stack/a2dp/a2dp_vendor_aptx_hd.cc
index 798e4fd..23fe197 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd.cc
@@ -604,6 +604,7 @@
         return true;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       break;
   }
@@ -806,6 +807,7 @@
         codec_config_.channel_mode = codec_user_config_.channel_mode;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
       codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
diff --git a/stack/a2dp/a2dp_vendor_ldac.cc b/stack/a2dp/a2dp_vendor_ldac.cc
index 266db81..9e1299a 100644
--- a/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/stack/a2dp/a2dp_vendor_ldac.cc
@@ -815,6 +815,7 @@
         return true;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       break;
   }
@@ -1093,6 +1094,7 @@
         break;
       }
       break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_DUAL_CHANNEL:
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
       codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
       codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index 1f8263f..4e84712 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -513,8 +513,8 @@
   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);
+    STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
+    STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
   }
   btm_cb.cmn_ble_vsc_cb.values_read = true;
 
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index b0281a0..d0866f5 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -19,6 +19,7 @@
 #include "bluetooth_hci.h"
 
 #include <base/logging.h>
+#include <cutils/properties.h>
 #include <string.h>
 #include <utils/Log.h>
 
@@ -44,6 +45,15 @@
 using test_vendor_lib::TaskCallback;
 using test_vendor_lib::TestChannelTransport;
 
+namespace {
+
+bool BtTestConsoleEnabled() {
+  // Assume enabled by default.
+  return property_get_bool("bt.rootcanal_test_console", true);
+}
+
+}  // namespace
+
 class BluetoothDeathRecipient : public hidl_death_recipient {
  public:
   BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
@@ -130,7 +140,9 @@
   controller_.RegisterTaskCancel(
       [this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });
 
-  SetUpTestChannel(6111);
+  if (BtTestConsoleEnabled()) {
+    SetUpTestChannel(6111);
+  }
 
   unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
     if (death_recipient->getHasDied())