Merge branch 'security-aosp-pi-release' into int/p/fp2

* security-aosp-pi-release:
  osi: Prevent memory allocations with MSB set

Change-Id: Ie537d367e584db36044af3233b74e7d392ed0b4a
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())