Merge changes from topic "am-2c2c464f-fb3a-4c93-8661-57c986c3e069-nyc-dev" into oc-dev am: 0d4898a05d am: a9fc38bcbf
am: a7d532c77c

Change-Id: Ic3bbfdf73d39b1455f6d27bf9294fb56011d0829
diff --git a/.clang-format b/.clang-format
index fa9d143..0b4b45a 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2016 The Android Open Source Project
+# Copyright 2016 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.
diff --git a/.gn b/.gn
index 947ebac..1c2396d 100644
--- a/.gn
+++ b/.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/Android.bp b/Android.bp
index 462b8be..fb0fdd9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,10 @@
 subdirs = [
+    "binder",
     "build",
     "btif",
     "btcore",
     "audio_a2dp_hw",
+    "audio_hearing_aid_hw",
     "hci",
     "utils",
     "device",
@@ -10,6 +12,7 @@
     "osi",
     "embdrv",
     "service",
+    "include",
     "main",
     "bta",
     "vendor_libs",
@@ -17,4 +20,5 @@
     "types",
     "udrv",
     "tools",
+    "proto",
 ]
diff --git a/BUILD.gn b/BUILD.gn
index 618de1c..04c32a1 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 # This pulls in main/BUILD.gn and all of its dependencies.
 group("bluetooth") {
   deps = [
-    "//main:bluetooth.default",
+    "//main:bluetooth",
     "//service:bluetoothtbd",
   ]
 }
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 518119b..8be8c0a 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 The Android Open Source Project
+# Copyright 2007 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.
diff --git a/OWNERS b/OWNERS
index a795df4..2ddc791 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,7 +3,6 @@
 # Project owners
 eisenbach@google.com
 apanicke@google.com
-jamuraa@google.com
 jpawlowski@google.com
 mylesgw@google.com
 pavlin@google.com
diff --git a/README.md b/README.md
index e937e81..869bc1f 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,6 @@
 git clone https://android.googlesource.com/platform/external/libldac
 git clone https://android.googlesource.com/platform/external/modp_b64
 git clone https://android.googlesource.com/platform/external/tinyxml2
-git clone https://android.googlesource.com/platform/hardware/libhardware
 ```
 
 And third party dependencies of third party dependencies:
@@ -60,7 +59,6 @@
 ln -s ../../../external/libldac libldac
 ln -s ../../../external/modp_b64 modp_b64
 ln -s ../../../external/tinyxml2 tinyxml2
-ln -s ../../../hardware/libhardware libhardware
 ln -s ../../../external/googletest googletest
 ```
 
diff --git a/audio_a2dp_hw/Android.bp b/audio_a2dp_hw/Android.bp
index ae93e06..7a23e27 100644
--- a/audio_a2dp_hw/Android.bp
+++ b/audio_a2dp_hw/Android.bp
@@ -3,6 +3,7 @@
     defaults: ["fluoride_defaults"],
     include_dirs: [
         "system/bt",
+        "system/bt/include",
         "system/bt/audio_a2dp_hw/include",
     ]
 }
@@ -19,6 +20,7 @@
     ],
     shared_libs: [
         "liblog",
+        "libcutils",
     ],
     static_libs: ["libosi"],
 }
diff --git a/audio_a2dp_hw/include/audio_a2dp_hw.h b/audio_a2dp_hw/include/audio_a2dp_hw.h
index d6c69e1..4d32432 100644
--- a/audio_a2dp_hw/include/audio_a2dp_hw.h
+++ b/audio_a2dp_hw/include/audio_a2dp_hw.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -85,13 +85,16 @@
   A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG,
   A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG,
   A2DP_CTRL_CMD_OFFLOAD_START,
+  A2DP_CTRL_GET_PRESENTATION_POSITION,
 } tA2DP_CTRL_CMD;
 
 typedef enum {
   A2DP_CTRL_ACK_SUCCESS,
   A2DP_CTRL_ACK_FAILURE,
   A2DP_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
-  A2DP_CTRL_ACK_UNSUPPORTED
+  A2DP_CTRL_ACK_UNSUPPORTED,
+  A2DP_CTRL_ACK_PENDING,
+  A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS,
 } tA2DP_CTRL_ACK;
 
 typedef uint32_t tA2DP_SAMPLE_RATE;
@@ -140,12 +143,15 @@
 //
 // Returns the computed buffer size. If any of the input parameters is
 // invalid, the return value is the default |AUDIO_STREAM_OUTPUT_BUFFER_SZ|.
-extern size_t audio_a2dp_hw_stream_compute_buffer_size(
+size_t audio_a2dp_hw_stream_compute_buffer_size(
     btav_a2dp_codec_sample_rate_t codec_sample_rate,
     btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
     btav_a2dp_codec_channel_mode_t codec_channel_mode);
 
+// Returns whether the delay reporting property is set.
+bool delay_reporting_enabled();
+
 // Returns a string representation of |event|.
-extern const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);
+const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);
 
 #endif /* A2DP_AUDIO_HW_H */
diff --git a/audio_a2dp_hw/src/audio_a2dp_hw.cc b/audio_a2dp_hw/src/audio_a2dp_hw.cc
index 1fcc408..3622298 100644
--- a/audio_a2dp_hw/src/audio_a2dp_hw.cc
+++ b/audio_a2dp_hw/src/audio_a2dp_hw.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -58,6 +58,13 @@
 #define USEC_PER_SEC 1000000L
 #define SOCK_SEND_TIMEOUT_MS 2000 /* Timeout for sending */
 #define SOCK_RECV_TIMEOUT_MS 5000 /* Timeout for receiving */
+#define SEC_TO_MS 1000
+#define SEC_TO_NS 1000000000
+#define MS_TO_NS 1000000
+#define DELAY_TO_NS 100000
+
+#define MIN_DELAY_MS 100
+#define MAX_DELAY_MS 1000
 
 // set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking
 // sockets
@@ -105,6 +112,7 @@
 struct a2dp_config {
   uint32_t rate;
   uint32_t channel_mask;
+  bool is_stereo_to_mono;  // True if fetching Stereo and mixing into Mono
   int format;
 };
 
@@ -144,11 +152,14 @@
  *  Static variables
  *****************************************************************************/
 
+static bool enable_delay_reporting = false;
+
 /*****************************************************************************
  *  Static functions
  *****************************************************************************/
 
 static size_t out_get_buffer_size(const struct audio_stream* stream);
+static uint32_t out_get_latency(const struct audio_stream_out* stream);
 
 /*****************************************************************************
  *  Externs
@@ -416,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;
     }
   }
@@ -428,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;
@@ -443,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;
@@ -591,27 +608,43 @@
   switch (codec_config->channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
       stream_config.channel_mask = AUDIO_CHANNEL_OUT_MONO;
+      stream_config.is_stereo_to_mono = true;
       break;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
       stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+      stream_config.is_stereo_to_mono = false;
       break;
     case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
     default:
       ERROR("Invalid channel mode: 0x%x", codec_config->channel_mode);
       return -1;
   }
+  if (stream_config.is_stereo_to_mono) {
+    stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+  }
 
   // Update the output stream configuration
   if (update_stream_config) {
     common->cfg.rate = stream_config.rate;
     common->cfg.channel_mask = stream_config.channel_mask;
+    common->cfg.is_stereo_to_mono = stream_config.is_stereo_to_mono;
     common->cfg.format = stream_config.format;
     common->buffer_sz = audio_a2dp_hw_stream_compute_buffer_size(
         codec_config->sample_rate, codec_config->bits_per_sample,
         codec_config->channel_mode);
+    if (common->cfg.is_stereo_to_mono) {
+      // We need to fetch twice as much data from the Audio framework
+      common->buffer_sz *= 2;
+    }
   }
 
   INFO(
+      "got output codec config (update_stream_config=%s): "
+      "sample_rate=0x%x bits_per_sample=0x%x channel_mode=0x%x",
+      update_stream_config ? "true" : "false", codec_config->sample_rate,
+      codec_config->bits_per_sample, codec_config->channel_mode);
+
+  INFO(
       "got output codec capability: sample_rate=0x%x bits_per_sample=0x%x "
       "channel_mode=0x%x",
       codec_capability->sample_rate, codec_capability->bits_per_sample,
@@ -679,7 +712,11 @@
       codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
       break;
     case AUDIO_CHANNEL_OUT_STEREO:
-      codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+      if (common->cfg.is_stereo_to_mono) {
+        codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+      } else {
+        codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+      }
       break;
     default:
       ERROR("Invalid channel mask: 0x%x", common->cfg.channel_mask);
@@ -708,6 +745,41 @@
   return 0;
 }
 
+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) ||
+      (common->state != AUDIO_A2DP_STATE_STARTED)) {  // Audio is not streaming
+    return -1;
+  }
+
+  if (a2dp_command(common, A2DP_CTRL_GET_PRESENTATION_POSITION) < 0) {
+    return -1;
+  }
+
+  if (a2dp_ctrl_receive(common, bytes, sizeof(*bytes)) < 0) {
+    return -1;
+  }
+
+  if (a2dp_ctrl_receive(common, delay, sizeof(*delay)) < 0) {
+    return -1;
+  }
+
+  uint32_t seconds;
+  if (a2dp_ctrl_receive(common, &seconds, sizeof(seconds)) < 0) {
+    return -1;
+  }
+
+  uint32_t nsec;
+  if (a2dp_ctrl_receive(common, &nsec, sizeof(nsec)) < 0) {
+    return -1;
+  }
+
+  timestamp->tv_sec = seconds;
+  timestamp->tv_nsec = nsec;
+  return 0;
+}
+
 static void a2dp_open_ctrl_path(struct a2dp_stream_common* common) {
   int i;
 
@@ -782,6 +854,10 @@
     }
   }
   common->state = (a2dp_state_t)AUDIO_A2DP_STATE_STARTED;
+
+  /* check to see if delay reporting is enabled */
+  enable_delay_reporting = delay_reporting_enabled();
+
   return 0;
 
 error:
@@ -844,6 +920,7 @@
                          size_t bytes) {
   struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
   int sent = -1;
+  size_t write_bytes = bytes;
 
   DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd);
 
@@ -865,8 +942,21 @@
     goto finish;
   }
 
+  // Mix the stereo into mono if necessary
+  if (out->common.cfg.is_stereo_to_mono) {
+    const size_t frames = bytes / audio_stream_out_frame_size(stream);
+    int16_t* src = (int16_t*)buffer;
+    int16_t* dst = (int16_t*)buffer;
+    for (size_t i = 0; i < frames; i++, dst++, src += 2) {
+      *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
+    }
+    write_bytes /= 2;
+    DEBUG("stereo-to-mono mixing: write %zu bytes (fd %d)", write_bytes,
+          out->common.audio_fd);
+  }
+
   lock.unlock();
-  sent = skt_write(out->common.audio_fd, buffer, bytes);
+  sent = skt_write(out->common.audio_fd, buffer, write_bytes);
   lock.lock();
 
   if (sent == -1) {
@@ -1251,17 +1341,44 @@
   FNLOG();
   if (stream == NULL || frames == NULL || timestamp == NULL) return -EINVAL;
 
-  int ret = -EWOULDBLOCK;
   std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+
+  // bytes is the total number of bytes sent by the Bluetooth stack to a
+  // remote headset
+  uint64_t bytes = 0;
+
+  // delay_report is the audio delay from the remote headset receiving data to
+  // the headset playing sound in units of 1/10ms
+  uint16_t delay_report = 0;
+
+  // If for some reason getting a delay fails or delay reports are disabled,
+  // default to old delay
+  if (enable_delay_reporting &&
+      a2dp_get_presentation_position_cmd(&out->common, &bytes, &delay_report,
+                                         timestamp) == 0) {
+    uint64_t delay_ns = delay_report * DELAY_TO_NS;
+    if (delay_ns > MIN_DELAY_MS * MS_TO_NS &&
+        delay_ns < MAX_DELAY_MS * MS_TO_NS) {
+      *frames = bytes / audio_stream_out_frame_size(stream);
+
+      timestamp->tv_nsec += delay_ns;
+      if (timestamp->tv_nsec > 1 * SEC_TO_NS) {
+        timestamp->tv_sec++;
+        timestamp->tv_nsec -= SEC_TO_NS;
+      }
+      return 0;
+    }
+  }
+
   uint64_t latency_frames =
       (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
   if (out->frames_presented >= latency_frames) {
+    clock_gettime(CLOCK_MONOTONIC, timestamp);
     *frames = out->frames_presented - latency_frames;
-    clock_gettime(CLOCK_MONOTONIC,
-                  timestamp);  // could also be associated with out_write().
-    ret = 0;
+    return 0;
   }
-  return ret;
+
+  return -EWOULDBLOCK;
 }
 
 static int out_get_render_position(const struct audio_stream_out* stream,
diff --git a/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc b/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
index 199b0f9..984e46b 100644
--- a/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
+++ b/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
  ******************************************************************************/
 
 #include "audio_a2dp_hw.h"
+#include "osi/include/properties.h"
 
 #define CASE_RETURN_STR(const) \
   case const:                  \
@@ -33,9 +34,12 @@
     CASE_RETURN_STR(A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG)
     CASE_RETURN_STR(A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG)
     CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_START)
-    default:
-      break;
+    CASE_RETURN_STR(A2DP_CTRL_GET_PRESENTATION_POSITION)
   }
 
   return "UNKNOWN A2DP_CTRL_CMD";
 }
+
+bool delay_reporting_enabled() {
+  return !osi_property_get_bool("persist.bluetooth.disabledelayreports", false);
+}
diff --git a/audio_a2dp_hw/test/audio_a2dp_hw_test.cc b/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
index f2cefa8..8fcbae5 100644
--- a/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
+++ b/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -36,6 +36,10 @@
       return 176400;
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
       return 192000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+      return 16000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+      return 24000;
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       break;
   }
diff --git a/audio_hearing_aid_hw/Android.bp b/audio_hearing_aid_hw/Android.bp
new file mode 100644
index 0000000..229fc25
--- /dev/null
+++ b/audio_hearing_aid_hw/Android.bp
@@ -0,0 +1,51 @@
+cc_defaults {
+    name: "audio_hearing_aid_hw_defaults",
+    defaults: ["fluoride_defaults"],
+    include_dirs: [
+        "system/bt",
+        "system/bt/include",
+        "system/bt/audio_hearing_aid_hw/include",
+    ]
+}
+
+// Audio A2DP shared library for target
+// ========================================================
+cc_library {
+    name: "audio.hearing_aid.default",
+    defaults: ["audio_hearing_aid_hw_defaults"],
+    relative_install_path: "hw",
+    srcs: [
+        "src/audio_hearing_aid_hw.cc",
+        "src/audio_hearing_aid_hw_utils.cc",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    static_libs: ["libosi"],
+}
+
+cc_library_static {
+    name: "libaudio-hearing-aid-hw-utils",
+    defaults: ["audio_hearing_aid_hw_defaults"],
+    srcs: [
+        "src/audio_hearing_aid_hw_utils.cc",
+    ],
+}
+
+// Audio A2DP library unit tests for target and host
+// ========================================================
+cc_test {
+    name: "net_test_audio_hearing_aid_hw",
+    test_suites: ["device-tests"],
+    defaults: ["audio_hearing_aid_hw_defaults"],
+    srcs: [
+        "test/audio_hearing_aid_hw_test.cc",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    static_libs: [
+        "audio.hearing_aid.default",
+        "libosi",
+    ],
+}
diff --git a/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h b/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h
new file mode 100644
index 0000000..56d8576
--- /dev/null
+++ b/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ *  Copyright 2016 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      audio_hearing_aid_hw.h
+ *
+ *  Description:
+ *
+ *****************************************************************************/
+
+#ifndef AUDIO_HEARING_AID_HW_H
+#define AUDIO_HEARING_AID_HW_H
+
+#include <stdint.h>
+
+#include <hardware/bt_av.h>
+
+/*****************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+
+#define HEARING_AID_AUDIO_HARDWARE_INTERFACE "audio.hearing_aid"
+#define HEARING_AID_CTRL_PATH "/data/misc/bluedroid/.hearing_aid_ctrl"
+#define HEARING_AID_DATA_PATH "/data/misc/bluedroid/.hearing_aid_data"
+
+// AUDIO_STREAM_OUTPUT_BUFFER_SZ controls the size of the audio socket buffer.
+// If one assumes the write buffer is always full during normal BT playback,
+// then increasing this value increases our playback latency.
+//
+// FIXME: The BT HAL should consume data at a constant rate.
+// AudioFlinger assumes that the HAL draws data at a constant rate, which is
+// true for most audio devices; however, the BT engine reads data at a variable
+// rate (over the short term), which confuses both AudioFlinger as well as
+// applications which deliver data at a (generally) fixed rate.
+//
+// 20 * 512 is not sufficient to smooth the variability for some BT devices,
+// resulting in mixer sleep and throttling. We increase this to 28 * 512 to help
+// reduce the effect of variable data consumption.
+#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512)
+#define AUDIO_STREAM_CONTROL_OUTPUT_BUFFER_SZ 256
+
+// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is divided
+// for AudioFlinger data delivery. The AudioFlinger mixer delivers data in
+// chunks of AUDIO_STREAM_OUTPUT_BUFFER_SZ / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS.
+// If the number of periods is 2, the socket buffer represents "double
+// buffering" of the AudioFlinger mixer buffer.
+//
+// In general, AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 * 4 should be a divisor
+// of AUDIO_STREAM_OUTPUT_BUFFER_SZ.
+//
+// These values should be chosen such that
+//
+// AUDIO_STREAM_BUFFER_SIZE * 1000 / (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS
+//         * AUDIO_STREAM_DEFAULT_RATE * 4) > 20 (ms)
+//
+// to avoid introducing the FastMixer in AudioFlinger. Using the FastMixer
+// results in unnecessary latency and CPU overhead for Bluetooth.
+#define AUDIO_STREAM_OUTPUT_BUFFER_PERIODS 2
+
+#define AUDIO_SKT_DISCONNECTED (-1)
+
+typedef enum {
+  HEARING_AID_CTRL_CMD_NONE,
+  HEARING_AID_CTRL_CMD_CHECK_READY,
+  HEARING_AID_CTRL_CMD_START,
+  HEARING_AID_CTRL_CMD_STOP,
+  HEARING_AID_CTRL_CMD_SUSPEND,
+  HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG,
+  HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG,
+  HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG,
+  HEARING_AID_CTRL_CMD_OFFLOAD_START,
+} tHEARING_AID_CTRL_CMD;
+
+typedef enum {
+  HEARING_AID_CTRL_ACK_SUCCESS,
+  HEARING_AID_CTRL_ACK_FAILURE,
+  HEARING_AID_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
+  HEARING_AID_CTRL_ACK_UNSUPPORTED
+} tHEARING_AID_CTRL_ACK;
+
+typedef uint32_t tHA_SAMPLE_RATE;
+typedef uint8_t tHA_CHANNEL_COUNT;
+
+/*****************************************************************************
+ *  Type definitions for callback functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  Type definitions and return values
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  Extern variables and functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  Functions
+ *****************************************************************************/
+
+// Computes the Audio Hearing Aid HAL output buffer size.
+// |codec_sample_rate| is the sample rate of the output stream.
+// |codec_bits_per_sample| is the number of bits per sample of the output
+// stream.
+// |codec_channel_mode| is the channel mode of the output stream.
+//
+// The buffer size is computed by using the following formula:
+//
+// AUDIO_STREAM_OUTPUT_BUFFER_SIZE =
+//    (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
+//     SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000
+//
+// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is
+// divided for AudioFlinger data delivery. The AudioFlinger mixer delivers
+// data in chunks of
+// (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) .
+// If the number of periods is 2, the socket buffer represents "double
+// buffering" of the AudioFlinger mixer buffer.
+//
+// Furthermore, the AudioFlinger expects the buffer size to be a multiple
+// of 16 frames.
+//
+// NOTE: Currently, the computation uses the conservative 20ms time period.
+//
+// Returns the computed buffer size. If any of the input parameters is
+// invalid, the return value is the default |AUDIO_STREAM_OUTPUT_BUFFER_SZ|.
+extern size_t audio_ha_hw_stream_compute_buffer_size(
+    btav_a2dp_codec_sample_rate_t codec_sample_rate,
+    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
+    btav_a2dp_codec_channel_mode_t codec_channel_mode);
+
+// Returns a string representation of |event|.
+extern const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event);
+
+#endif /* AUDIO_HEARING_AID_HW_H */
diff --git a/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc b/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc
new file mode 100644
index 0000000..f3f535e
--- /dev/null
+++ b/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc
@@ -0,0 +1,1889 @@
+/******************************************************************************
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/* Implements hal for bluedroid ha audio device */
+
+#define LOG_TAG "bt_hearing_aid_hw"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+
+#include "osi/include/hash_map_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#include "audio_hearing_aid_hw.h"
+
+/*****************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+
+#define CTRL_CHAN_RETRY_COUNT 3
+#define USEC_PER_SEC 1000000L
+#define SOCK_SEND_TIMEOUT_MS 2000 /* Timeout for sending */
+#define SOCK_RECV_TIMEOUT_MS 5000 /* Timeout for receiving */
+
+// set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking
+// sockets
+#define WRITE_POLL_MS 20
+
+#define FNLOG() LOG_VERBOSE(LOG_TAG, "%s", __func__);
+#define DEBUG(fmt, ...) \
+  LOG_VERBOSE(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define INFO(fmt, ...) LOG_INFO(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define WARN(fmt, ...) LOG_WARN(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define ERROR(fmt, ...) LOG_ERROR(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define ASSERTC(cond, msg, val)                                           \
+  if (!(cond)) {                                                          \
+    ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, \
+          val);                                                           \
+  }
+
+/*****************************************************************************
+ *  Local type definitions
+ *****************************************************************************/
+
+typedef enum {
+  AUDIO_HA_STATE_STARTING,
+  AUDIO_HA_STATE_STARTED,
+  AUDIO_HA_STATE_STOPPING,
+  AUDIO_HA_STATE_STOPPED,
+  /* need explicit set param call to resume (suspend=false) */
+  AUDIO_HA_STATE_SUSPENDED,
+  AUDIO_HA_STATE_STANDBY /* allows write to autoresume */
+} ha_state_t;
+
+struct ha_stream_in;
+struct ha_stream_out;
+
+struct ha_audio_device {
+  // Important: device must be first as an audio_hw_device* may be cast to
+  // ha_audio_device* when the type is implicitly known.
+  struct audio_hw_device device;
+  std::recursive_mutex* mutex;  // See note below on mutex acquisition order.
+  struct ha_stream_in* input;
+  struct ha_stream_out* output;
+};
+
+struct ha_config {
+  uint32_t rate;
+  uint32_t channel_mask;
+  bool is_stereo_to_mono;  // True if fetching Stereo and mixing into Mono
+  int format;
+};
+
+/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
+
+struct ha_stream_common {
+  std::recursive_mutex* mutex;  // See note below on mutex acquisition order.
+  int ctrl_fd;
+  int audio_fd;
+  size_t buffer_sz;
+  struct ha_config cfg;
+  ha_state_t state;
+};
+
+struct ha_stream_out {
+  struct audio_stream_out stream;
+  struct ha_stream_common common;
+  uint64_t frames_presented;  // frames written, never reset
+  uint64_t frames_rendered;   // frames written, reset on standby
+};
+
+struct ha_stream_in {
+  struct audio_stream_in stream;
+  struct ha_stream_common common;
+};
+
+/*
+ * Mutex acquisition order:
+ *
+ * The ha_audio_device (adev) mutex must be acquired before
+ * the ha_stream_common (out or in) mutex.
+ *
+ * This may differ from other audio HALs.
+ */
+
+/*****************************************************************************
+ *  Static variables
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  Static functions
+ *****************************************************************************/
+
+static size_t out_get_buffer_size(const struct audio_stream* stream);
+
+/*****************************************************************************
+ *  Externs
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  Functions
+ *****************************************************************************/
+static void ha_open_ctrl_path(struct ha_stream_common* common);
+
+/*****************************************************************************
+ *   Miscellaneous helper functions
+ *****************************************************************************/
+
+/* logs timestamp with microsec precision
+   pprev is optional in case a dedicated diff is required */
+static void ts_log(UNUSED_ATTR const char* tag, UNUSED_ATTR int val,
+                   struct timespec* pprev_opt) {
+  struct timespec now;
+  static struct timespec prev = {0, 0};
+  unsigned long long now_us;
+  unsigned long long diff_us;
+
+  clock_gettime(CLOCK_MONOTONIC, &now);
+
+  now_us = now.tv_sec * USEC_PER_SEC + now.tv_nsec / 1000;
+
+  if (pprev_opt) {
+    diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC +
+              (now.tv_nsec - prev.tv_nsec) / 1000;
+    *pprev_opt = now;
+    DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
+  } else {
+    diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC +
+              (now.tv_nsec - prev.tv_nsec) / 1000;
+    prev = now;
+    DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
+  }
+}
+
+static int calc_audiotime_usec(struct ha_config cfg, int bytes) {
+  int chan_count = audio_channel_count_from_out_mask(cfg.channel_mask);
+  int bytes_per_sample;
+
+  switch (cfg.format) {
+    case AUDIO_FORMAT_PCM_8_BIT:
+      bytes_per_sample = 1;
+      break;
+    case AUDIO_FORMAT_PCM_16_BIT:
+      bytes_per_sample = 2;
+      break;
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+      bytes_per_sample = 3;
+      break;
+    case AUDIO_FORMAT_PCM_8_24_BIT:
+      bytes_per_sample = 4;
+      break;
+    case AUDIO_FORMAT_PCM_32_BIT:
+      bytes_per_sample = 4;
+      break;
+    default:
+      ASSERTC(false, "unsupported sample format", cfg.format);
+      bytes_per_sample = 2;
+      break;
+  }
+
+  return (
+      int)(((int64_t)bytes * (USEC_PER_SEC / (chan_count * bytes_per_sample))) /
+           cfg.rate);
+}
+
+/*****************************************************************************
+ *
+ *   bluedroid stack adaptation
+ *
+ ****************************************************************************/
+
+static int skt_connect(const char* path, size_t buffer_sz) {
+  int ret;
+  int skt_fd;
+  int len;
+
+  INFO("connect to %s (sz %zu)", path, buffer_sz);
+
+  skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+  if (osi_socket_local_client_connect(
+          skt_fd, path, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0) {
+    ERROR("failed to connect (%s)", strerror(errno));
+    close(skt_fd);
+    return -1;
+  }
+
+  len = buffer_sz;
+  ret =
+      setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
+  if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+  ret =
+      setsockopt(skt_fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, (int)sizeof(len));
+  if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+  /* Socket send/receive timeout value */
+  struct timeval tv;
+  tv.tv_sec = SOCK_SEND_TIMEOUT_MS / 1000;
+  tv.tv_usec = (SOCK_SEND_TIMEOUT_MS % 1000) * 1000;
+
+  ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+  if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+  tv.tv_sec = SOCK_RECV_TIMEOUT_MS / 1000;
+  tv.tv_usec = (SOCK_RECV_TIMEOUT_MS % 1000) * 1000;
+
+  ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+  if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+  INFO("connected to stack fd = %d", skt_fd);
+
+  return skt_fd;
+}
+
+static int skt_read(int fd, void* p, size_t len) {
+  ssize_t read;
+
+  FNLOG();
+
+  ts_log("skt_read recv", len, NULL);
+
+  OSI_NO_INTR(read = recv(fd, p, len, MSG_NOSIGNAL));
+  if (read == -1) ERROR("read failed with errno=%d\n", errno);
+
+  return (int)read;
+}
+
+static int skt_write(int fd, const void* p, size_t len) {
+  ssize_t sent;
+  FNLOG();
+
+  ts_log("skt_write", len, NULL);
+
+  if (WRITE_POLL_MS == 0) {
+    // do not poll, use blocking send
+    OSI_NO_INTR(sent = send(fd, p, len, MSG_NOSIGNAL));
+    if (sent == -1) ERROR("write failed with error(%s)", strerror(errno));
+
+    return (int)sent;
+  }
+
+  // use non-blocking send, poll
+  int ms_timeout = SOCK_SEND_TIMEOUT_MS;
+  size_t count = 0;
+  while (count < len) {
+    OSI_NO_INTR(sent = send(fd, p, len - count, MSG_NOSIGNAL | MSG_DONTWAIT));
+    if (sent == -1) {
+      if (errno != EAGAIN && errno != EWOULDBLOCK) {
+        ERROR("write failed with error(%s)", strerror(errno));
+        return -1;
+      }
+      if (ms_timeout >= WRITE_POLL_MS) {
+        usleep(WRITE_POLL_MS * 1000);
+        ms_timeout -= WRITE_POLL_MS;
+        continue;
+      }
+      WARN("write timeout exceeded, sent %zu bytes", count);
+      return -1;
+    }
+    count += sent;
+    p = (const uint8_t*)p + sent;
+  }
+  return (int)count;
+}
+
+static int skt_disconnect(int fd) {
+  INFO("fd %d", fd);
+
+  if (fd != AUDIO_SKT_DISCONNECTED) {
+    shutdown(fd, SHUT_RDWR);
+    close(fd);
+  }
+  return 0;
+}
+
+/*****************************************************************************
+ *
+ *  AUDIO CONTROL PATH
+ *
+ ****************************************************************************/
+
+static int ha_ctrl_receive(struct ha_stream_common* common, void* buffer,
+                           size_t length) {
+  ssize_t ret;
+  int i;
+
+  for (i = 0;; i++) {
+    OSI_NO_INTR(ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL));
+    if (ret > 0) {
+      break;
+    }
+    if (ret == 0) {
+      ERROR("receive control data failed: peer closed");
+      break;
+    }
+    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+      ERROR("receive control data failed: error(%s)", strerror(errno));
+      break;
+    }
+    if (i == (CTRL_CHAN_RETRY_COUNT - 1)) {
+      ERROR("receive control data failed: max retry count");
+      break;
+    }
+    INFO("receive control data failed (%s), retrying", strerror(errno));
+  }
+  if (ret <= 0) {
+    skt_disconnect(common->ctrl_fd);
+    common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+  }
+  return ret;
+}
+
+// Sends control info for stream |common|. The data to send is stored in
+// |buffer| and has size |length|.
+// On success, returns the number of octets sent, otherwise -1.
+static int ha_ctrl_send(struct ha_stream_common* common, const void* buffer,
+                        size_t length) {
+  ssize_t sent;
+  size_t remaining = length;
+  int i;
+
+  if (length == 0) return 0;  // Nothing to do
+
+  for (i = 0;; i++) {
+    OSI_NO_INTR(sent = send(common->ctrl_fd, buffer, remaining, MSG_NOSIGNAL));
+    if (sent == static_cast<ssize_t>(remaining)) {
+      remaining = 0;
+      break;
+    }
+    if (sent > 0) {
+      buffer = (static_cast<const char*>(buffer) + sent);
+      remaining -= sent;
+      continue;
+    }
+    if (sent < 0) {
+      if (errno != EWOULDBLOCK && errno != EAGAIN) {
+        ERROR("send control data failed: error(%s)", strerror(errno));
+        break;
+      }
+      INFO("send control data failed (%s), retrying", strerror(errno));
+    }
+    if (i >= (CTRL_CHAN_RETRY_COUNT - 1)) {
+      ERROR("send control data failed: max retry count");
+      break;
+    }
+  }
+  if (remaining > 0) {
+    skt_disconnect(common->ctrl_fd);
+    common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    return -1;
+  }
+  return length;
+}
+
+static int ha_command(struct ha_stream_common* common,
+                      tHEARING_AID_CTRL_CMD cmd) {
+  char ack;
+
+  DEBUG("HEARING_AID COMMAND %s", audio_ha_hw_dump_ctrl_event(cmd));
+
+  if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+    INFO("starting up or recovering from previous error");
+    ha_open_ctrl_path(common);
+    if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+      ERROR("failure to open ctrl path");
+      return -1;
+    }
+  }
+
+  /* send command */
+  ssize_t sent;
+  OSI_NO_INTR(sent = send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL));
+  if (sent == -1) {
+    ERROR("cmd failed (%s)", strerror(errno));
+    skt_disconnect(common->ctrl_fd);
+    common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    return -1;
+  }
+
+  /* wait for ack byte */
+  if (ha_ctrl_receive(common, &ack, 1) < 0) {
+    ERROR("HEARING_AID COMMAND %s: no ACK", audio_ha_hw_dump_ctrl_event(cmd));
+    return -1;
+  }
+
+  DEBUG("HEARING_AID COMMAND %s DONE STATUS %d",
+        audio_ha_hw_dump_ctrl_event(cmd), ack);
+
+  if (ack == HEARING_AID_CTRL_ACK_INCALL_FAILURE) return ack;
+  if (ack != HEARING_AID_CTRL_ACK_SUCCESS) {
+    ERROR("HEARING_AID COMMAND %s error %d", audio_ha_hw_dump_ctrl_event(cmd),
+          ack);
+    return -1;
+  }
+
+  return 0;
+}
+
+static int check_ha_ready(struct ha_stream_common* common) {
+  if (ha_command(common, HEARING_AID_CTRL_CMD_CHECK_READY) < 0) {
+    ERROR("check ha ready failed");
+    return -1;
+  }
+  return 0;
+}
+
+static int ha_read_input_audio_config(struct ha_stream_common* common) {
+  tHA_SAMPLE_RATE sample_rate;
+  tHA_CHANNEL_COUNT channel_count;
+
+  if (ha_command(common, HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG) < 0) {
+    ERROR("get ha input audio config failed");
+    return -1;
+  }
+
+  if (ha_ctrl_receive(common, &sample_rate, sizeof(tHA_SAMPLE_RATE)) < 0)
+    return -1;
+  if (ha_ctrl_receive(common, &channel_count, sizeof(tHA_CHANNEL_COUNT)) < 0) {
+    return -1;
+  }
+
+  switch (sample_rate) {
+    case 16000:
+    case 24000:
+    case 44100:
+    case 48000:
+      common->cfg.rate = sample_rate;
+      break;
+    default:
+      ERROR("Invalid sample rate: %" PRIu32, sample_rate);
+      return -1;
+  }
+
+  switch (channel_count) {
+    case 1:
+      common->cfg.channel_mask = AUDIO_CHANNEL_IN_MONO;
+      break;
+    case 2:
+      common->cfg.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+      break;
+    default:
+      ERROR("Invalid channel count: %" PRIu32, channel_count);
+      return -1;
+  }
+
+  // TODO: For now input audio format is always hard-coded as PCM 16-bit
+  common->cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+
+  INFO("got input audio config %d %d", common->cfg.format, common->cfg.rate);
+
+  return 0;
+}
+
+static int ha_read_output_audio_config(
+    struct ha_stream_common* common, btav_a2dp_codec_config_t* codec_config,
+    btav_a2dp_codec_config_t* codec_capability, bool update_stream_config) {
+  struct ha_config stream_config;
+
+  if (ha_command(common, HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG) < 0) {
+    ERROR("get ha output audio config failed");
+    return -1;
+  }
+
+  // Receive the current codec config
+  if (ha_ctrl_receive(common, &codec_config->sample_rate,
+                      sizeof(btav_a2dp_codec_sample_rate_t)) < 0) {
+    return -1;
+  }
+  if (ha_ctrl_receive(common, &codec_config->bits_per_sample,
+                      sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) {
+    return -1;
+  }
+  if (ha_ctrl_receive(common, &codec_config->channel_mode,
+                      sizeof(btav_a2dp_codec_channel_mode_t)) < 0) {
+    return -1;
+  }
+
+  // Receive the current codec capability
+  if (ha_ctrl_receive(common, &codec_capability->sample_rate,
+                      sizeof(btav_a2dp_codec_sample_rate_t)) < 0) {
+    return -1;
+  }
+  if (ha_ctrl_receive(common, &codec_capability->bits_per_sample,
+                      sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) {
+    return -1;
+  }
+  if (ha_ctrl_receive(common, &codec_capability->channel_mode,
+                      sizeof(btav_a2dp_codec_channel_mode_t)) < 0) {
+    return -1;
+  }
+
+  // Check the codec config sample rate
+  switch (codec_config->sample_rate) {
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+      stream_config.rate = 44100;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+      stream_config.rate = 48000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+      stream_config.rate = 88200;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+      stream_config.rate = 96000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+      stream_config.rate = 176400;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+      stream_config.rate = 192000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+      stream_config.rate = 16000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+      stream_config.rate = 24000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+    default:
+      ERROR("Invalid sample rate: 0x%x", codec_config->sample_rate);
+      return -1;
+  }
+
+  // Check the codec config bits per sample
+  switch (codec_config->bits_per_sample) {
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+      stream_config.format = AUDIO_FORMAT_PCM_16_BIT;
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      stream_config.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      stream_config.format = AUDIO_FORMAT_PCM_32_BIT;
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+    default:
+      ERROR("Invalid bits per sample: 0x%x", codec_config->bits_per_sample);
+      return -1;
+  }
+
+  // Check the codec config channel mode
+  switch (codec_config->channel_mode) {
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+      stream_config.channel_mask = AUDIO_CHANNEL_OUT_MONO;
+      stream_config.is_stereo_to_mono = true;
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+      stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+      stream_config.is_stereo_to_mono = false;
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+    default:
+      ERROR("Invalid channel mode: 0x%x", codec_config->channel_mode);
+      return -1;
+  }
+  if (stream_config.is_stereo_to_mono) {
+    stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+  }
+
+  // Update the output stream configuration
+  if (update_stream_config) {
+    common->cfg.rate = stream_config.rate;
+    common->cfg.channel_mask = stream_config.channel_mask;
+    common->cfg.is_stereo_to_mono = stream_config.is_stereo_to_mono;
+    common->cfg.format = stream_config.format;
+    common->buffer_sz = audio_ha_hw_stream_compute_buffer_size(
+        codec_config->sample_rate, codec_config->bits_per_sample,
+        codec_config->channel_mode);
+    if (common->cfg.is_stereo_to_mono) {
+      // We need to fetch twice as much data from the Audio framework
+      common->buffer_sz *= 2;
+    }
+  }
+
+  INFO(
+      "got output codec config (update_stream_config=%s): "
+      "sample_rate=0x%x bits_per_sample=0x%x channel_mode=0x%x",
+      update_stream_config ? "true" : "false", codec_config->sample_rate,
+      codec_config->bits_per_sample, codec_config->channel_mode);
+
+  INFO(
+      "got output codec capability: sample_rate=0x%x bits_per_sample=0x%x "
+      "channel_mode=0x%x",
+      codec_capability->sample_rate, codec_capability->bits_per_sample,
+      codec_capability->channel_mode);
+
+  return 0;
+}
+
+static int ha_write_output_audio_config(struct ha_stream_common* common) {
+  btav_a2dp_codec_config_t codec_config;
+
+  if (ha_command(common, HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG) < 0) {
+    ERROR("set ha output audio config failed");
+    return -1;
+  }
+
+  codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+  codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+  codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+
+  switch (common->cfg.rate) {
+    case 44100:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+      break;
+    case 48000:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+      break;
+    case 88200:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+      break;
+    case 96000:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+      break;
+    case 176400:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+      break;
+    case 192000:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+      break;
+    case 16000:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_16000;
+      break;
+    case 24000:
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
+      break;
+    default:
+      ERROR("Invalid sample rate: %" PRIu32, common->cfg.rate);
+      return -1;
+  }
+
+  switch (common->cfg.format) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+      codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+      break;
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+      codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+      break;
+    case AUDIO_FORMAT_PCM_32_BIT:
+      codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+      break;
+    case AUDIO_FORMAT_PCM_8_24_BIT:
+    // FALLTHROUGH
+    // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format
+    default:
+      ERROR("Invalid audio format: 0x%x", common->cfg.format);
+      return -1;
+  }
+
+  switch (common->cfg.channel_mask) {
+    case AUDIO_CHANNEL_OUT_MONO:
+      codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+      break;
+    case AUDIO_CHANNEL_OUT_STEREO:
+      if (common->cfg.is_stereo_to_mono) {
+        codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+      } else {
+        codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+      }
+      break;
+    default:
+      ERROR("Invalid channel mask: 0x%x", common->cfg.channel_mask);
+      return -1;
+  }
+
+  // Send the current codec config that has been selected by us
+  if (ha_ctrl_send(common, &codec_config.sample_rate,
+                   sizeof(btav_a2dp_codec_sample_rate_t)) < 0)
+    return -1;
+  if (ha_ctrl_send(common, &codec_config.bits_per_sample,
+                   sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) {
+    return -1;
+  }
+  if (ha_ctrl_send(common, &codec_config.channel_mode,
+                   sizeof(btav_a2dp_codec_channel_mode_t)) < 0) {
+    return -1;
+  }
+
+  INFO(
+      "sent output codec config: sample_rate=0x%x bits_per_sample=0x%x "
+      "channel_mode=0x%x",
+      codec_config.sample_rate, codec_config.bits_per_sample,
+      codec_config.channel_mode);
+
+  return 0;
+}
+
+static void ha_open_ctrl_path(struct ha_stream_common* common) {
+  int i;
+
+  if (common->ctrl_fd != AUDIO_SKT_DISCONNECTED) return;  // already connected
+
+  /* retry logic to catch any timing variations on control channel */
+  for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) {
+    /* connect control channel if not already connected */
+    if ((common->ctrl_fd = skt_connect(
+             HEARING_AID_CTRL_PATH, AUDIO_STREAM_CONTROL_OUTPUT_BUFFER_SZ)) >=
+        0) {
+      /* success, now check if stack is ready */
+      if (check_ha_ready(common) == 0) break;
+
+      ERROR("error : ha not ready, wait 250 ms and retry");
+      usleep(250000);
+      skt_disconnect(common->ctrl_fd);
+      common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    }
+
+    /* ctrl channel not ready, wait a bit */
+    usleep(250000);
+  }
+}
+
+/*****************************************************************************
+ *
+ * AUDIO DATA PATH
+ *
+ ****************************************************************************/
+
+static void ha_stream_common_init(struct ha_stream_common* common) {
+  FNLOG();
+
+  common->mutex = new std::recursive_mutex;
+
+  common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+  common->audio_fd = AUDIO_SKT_DISCONNECTED;
+  common->state = AUDIO_HA_STATE_STOPPED;
+
+  /* manages max capacity of socket pipe */
+  common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+}
+
+static void ha_stream_common_destroy(struct ha_stream_common* common) {
+  FNLOG();
+
+  delete common->mutex;
+  common->mutex = NULL;
+}
+
+static int start_audio_datapath(struct ha_stream_common* common) {
+  INFO("state %d", common->state);
+
+  int oldstate = common->state;
+  common->state = AUDIO_HA_STATE_STARTING;
+
+  int ha_status = ha_command(common, HEARING_AID_CTRL_CMD_START);
+  if (ha_status < 0) {
+    ERROR("Audiopath start failed (status %d)", ha_status);
+    goto error;
+  } else if (ha_status == HEARING_AID_CTRL_ACK_INCALL_FAILURE) {
+    ERROR("Audiopath start failed - in call, move to suspended");
+    goto error;
+  }
+
+  /* connect socket if not yet connected */
+  if (common->audio_fd == AUDIO_SKT_DISCONNECTED) {
+    common->audio_fd = skt_connect(HEARING_AID_DATA_PATH, common->buffer_sz);
+    if (common->audio_fd < 0) {
+      ERROR("Audiopath start failed - error opening data socket");
+      goto error;
+    }
+  }
+  common->state = (ha_state_t)AUDIO_HA_STATE_STARTED;
+  return 0;
+
+error:
+  common->state = (ha_state_t)oldstate;
+  return -1;
+}
+
+static int stop_audio_datapath(struct ha_stream_common* common) {
+  int oldstate = common->state;
+
+  INFO("state %d", common->state);
+
+  /* prevent any stray output writes from autostarting the stream
+     while stopping audiopath */
+  common->state = AUDIO_HA_STATE_STOPPING;
+
+  if (ha_command(common, HEARING_AID_CTRL_CMD_STOP) < 0) {
+    ERROR("audiopath stop failed");
+    common->state = (ha_state_t)oldstate;
+    return -1;
+  }
+
+  common->state = (ha_state_t)AUDIO_HA_STATE_STOPPED;
+
+  /* disconnect audio path */
+  skt_disconnect(common->audio_fd);
+  common->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+  return 0;
+}
+
+static int suspend_audio_datapath(struct ha_stream_common* common,
+                                  bool standby) {
+  INFO("state %d", common->state);
+
+  if (common->state == AUDIO_HA_STATE_STOPPING) return -1;
+
+  if (ha_command(common, HEARING_AID_CTRL_CMD_SUSPEND) < 0) return -1;
+
+  if (standby)
+    common->state = AUDIO_HA_STATE_STANDBY;
+  else
+    common->state = AUDIO_HA_STATE_SUSPENDED;
+
+  /* disconnect audio path */
+  skt_disconnect(common->audio_fd);
+
+  common->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+  return 0;
+}
+
+/*****************************************************************************
+ *
+ *  audio output callbacks
+ *
+ ****************************************************************************/
+
+static ssize_t out_write(struct audio_stream_out* stream, const void* buffer,
+                         size_t bytes) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+  int sent = -1;
+  size_t write_bytes = bytes;
+
+  DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd);
+
+  std::unique_lock<std::recursive_mutex> lock(*out->common.mutex);
+  if (out->common.state == AUDIO_HA_STATE_SUSPENDED ||
+      out->common.state == AUDIO_HA_STATE_STOPPING) {
+    DEBUG("stream suspended or closing");
+    goto finish;
+  }
+
+  /* only allow autostarting if we are in stopped or standby */
+  if ((out->common.state == AUDIO_HA_STATE_STOPPED) ||
+      (out->common.state == AUDIO_HA_STATE_STANDBY)) {
+    if (start_audio_datapath(&out->common) < 0) {
+      goto finish;
+    }
+  } else if (out->common.state != AUDIO_HA_STATE_STARTED) {
+    ERROR("stream not in stopped or standby");
+    goto finish;
+  }
+
+  // Mix the stereo into mono if necessary
+  if (out->common.cfg.is_stereo_to_mono) {
+    const size_t frames = bytes / audio_stream_out_frame_size(stream);
+    int16_t* src = (int16_t*)buffer;
+    int16_t* dst = (int16_t*)buffer;
+    for (size_t i = 0; i < frames; i++, dst++, src += 2) {
+      *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
+    }
+    write_bytes /= 2;
+    DEBUG("stereo-to-mono mixing: write %zu bytes (fd %d)", write_bytes,
+          out->common.audio_fd);
+  }
+
+  lock.unlock();
+  sent = skt_write(out->common.audio_fd, buffer, write_bytes);
+  lock.lock();
+
+  if (sent == -1) {
+    skt_disconnect(out->common.audio_fd);
+    out->common.audio_fd = AUDIO_SKT_DISCONNECTED;
+    if ((out->common.state != AUDIO_HA_STATE_SUSPENDED) &&
+        (out->common.state != AUDIO_HA_STATE_STOPPING)) {
+      out->common.state = AUDIO_HA_STATE_STOPPED;
+    } else {
+      ERROR("write failed : stream suspended, avoid resetting state");
+    }
+    goto finish;
+  }
+
+finish:;
+  const size_t frames = bytes / audio_stream_out_frame_size(stream);
+  out->frames_rendered += frames;
+  out->frames_presented += frames;
+  lock.unlock();
+
+  // If send didn't work out, sleep to emulate write delay.
+  if (sent == -1) {
+    const int us_delay = calc_audiotime_usec(out->common.cfg, bytes);
+    DEBUG("emulate ha write delay (%d us)", us_delay);
+    usleep(us_delay);
+  }
+  return bytes;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream* stream) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  DEBUG("rate %" PRIu32, out->common.cfg.rate);
+
+  return out->common.cfg.rate;
+}
+
+static int out_set_sample_rate(struct audio_stream* stream, uint32_t rate) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  DEBUG("out_set_sample_rate : %" PRIu32, rate);
+
+  out->common.cfg.rate = rate;
+
+  return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream* stream) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+  // period_size is the AudioFlinger mixer buffer size.
+  const size_t period_size =
+      out->common.buffer_sz / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS;
+
+  DEBUG("socket buffer size: %zu  period size: %zu", out->common.buffer_sz,
+        period_size);
+
+  return period_size;
+}
+
+size_t audio_ha_hw_stream_compute_buffer_size(
+    btav_a2dp_codec_sample_rate_t codec_sample_rate,
+    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
+    btav_a2dp_codec_channel_mode_t codec_channel_mode) {
+  size_t buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;  // Default value
+  const uint64_t time_period_ms = 20;                // Conservative 20ms
+  uint32_t sample_rate;
+  uint32_t bits_per_sample;
+  uint32_t number_of_channels;
+
+  // Check the codec config sample rate
+  switch (codec_sample_rate) {
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+      sample_rate = 44100;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+      sample_rate = 48000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+      sample_rate = 88200;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+      sample_rate = 96000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+      sample_rate = 176400;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+      sample_rate = 192000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+      sample_rate = 16000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+      sample_rate = 24000;
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+    default:
+      ERROR("Invalid sample rate: 0x%x", codec_sample_rate);
+      return buffer_sz;
+  }
+
+  // Check the codec config bits per sample
+  switch (codec_bits_per_sample) {
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+      bits_per_sample = 16;
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      bits_per_sample = 24;
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      bits_per_sample = 32;
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+    default:
+      ERROR("Invalid bits per sample: 0x%x", codec_bits_per_sample);
+      return buffer_sz;
+  }
+
+  // Check the codec config channel mode
+  switch (codec_channel_mode) {
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+      number_of_channels = 1;
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+      number_of_channels = 2;
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+    default:
+      ERROR("Invalid channel mode: 0x%x", codec_channel_mode);
+      return buffer_sz;
+  }
+
+  //
+  // The buffer size is computed by using the following formula:
+  //
+  // AUDIO_STREAM_OUTPUT_BUFFER_SIZE =
+  //    (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
+  //     SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000
+  //
+  // AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is
+  // divided for AudioFlinger data delivery. The AudioFlinger mixer delivers
+  // data in chunks of
+  // (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) .
+  // If the number of periods is 2, the socket buffer represents "double
+  // buffering" of the AudioFlinger mixer buffer.
+  //
+  // Furthermore, the AudioFlinger expects the buffer size to be a multiple
+  // of 16 frames.
+  const size_t divisor = (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 *
+                          number_of_channels * bits_per_sample) /
+                         8;
+
+  buffer_sz = (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
+               sample_rate * number_of_channels * (bits_per_sample / 8)) /
+              1000;
+
+  // Adjust the buffer size so it can be divided by the divisor
+  const size_t remainder = buffer_sz % divisor;
+  if (remainder != 0) {
+    buffer_sz += divisor - remainder;
+  }
+
+  return buffer_sz;
+}
+
+static uint32_t out_get_channels(const struct audio_stream* stream) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_mask);
+
+  return out->common.cfg.channel_mask;
+}
+
+static audio_format_t out_get_format(const struct audio_stream* stream) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+  DEBUG("format 0x%x", out->common.cfg.format);
+  return (audio_format_t)out->common.cfg.format;
+}
+
+static int out_set_format(UNUSED_ATTR struct audio_stream* stream,
+                          UNUSED_ATTR audio_format_t format) {
+  DEBUG("setting format not yet supported (0x%x)", format);
+  return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream* stream) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+  int retVal = 0;
+
+  FNLOG();
+
+  std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+  // Do nothing in SUSPENDED state.
+  if (out->common.state != AUDIO_HA_STATE_SUSPENDED)
+    retVal = suspend_audio_datapath(&out->common, true);
+  out->frames_rendered = 0;  // rendered is reset, presented is not
+
+  return retVal;
+}
+
+static int out_dump(UNUSED_ATTR const struct audio_stream* stream,
+                    UNUSED_ATTR int fd) {
+  FNLOG();
+  return 0;
+}
+
+static int out_set_parameters(struct audio_stream* stream,
+                              const char* kvpairs) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  INFO("state %d kvpairs %s", out->common.state, kvpairs);
+
+  std::unordered_map<std::string, std::string> params =
+      hash_map_utils_new_from_string_params(kvpairs);
+  int status = 0;
+
+  if (params.empty()) return status;
+
+  std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+
+  /* dump params */
+  hash_map_utils_dump_string_keys_string_values(params);
+
+  if (params["closing"].compare("true") == 0) {
+    DEBUG("stream closing, disallow any writes");
+    out->common.state = AUDIO_HA_STATE_STOPPING;
+  }
+
+  if (params["HearingAidSuspended"].compare("true") == 0) {
+    if (out->common.state == AUDIO_HA_STATE_STARTED)
+      status = suspend_audio_datapath(&out->common, false);
+  } else {
+    /* Do not start the streaming automatically. If the phone was streaming
+     * prior to being suspended, the next out_write shall trigger the
+     * AVDTP start procedure */
+    if (out->common.state == AUDIO_HA_STATE_SUSPENDED)
+      out->common.state = AUDIO_HA_STATE_STANDBY;
+    /* Irrespective of the state, return 0 */
+  }
+
+  return status;
+}
+
+static char* out_get_parameters(const struct audio_stream* stream,
+                                const char* keys) {
+  FNLOG();
+
+  btav_a2dp_codec_config_t codec_config;
+  btav_a2dp_codec_config_t codec_capability;
+
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  std::unordered_map<std::string, std::string> params =
+      hash_map_utils_new_from_string_params(keys);
+  std::unordered_map<std::string, std::string> return_params;
+
+  if (params.empty()) return strdup("");
+
+  std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+
+  if (ha_read_output_audio_config(&out->common, &codec_config,
+                                  &codec_capability,
+                                  false /* update_stream_config */) < 0) {
+    ERROR("ha_read_output_audio_config failed");
+    goto done;
+  }
+
+  // Add the format
+  if (params.find(AUDIO_PARAMETER_STREAM_SUP_FORMATS) != params.end()) {
+    std::string param;
+    if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+      if (!param.empty()) param += "|";
+      param += "AUDIO_FORMAT_PCM_16_BIT";
+    }
+    if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+      if (!param.empty()) param += "|";
+      param += "AUDIO_FORMAT_PCM_24_BIT_PACKED";
+    }
+    if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+      if (!param.empty()) param += "|";
+      param += "AUDIO_FORMAT_PCM_32_BIT";
+    }
+    if (param.empty()) {
+      ERROR("Invalid codec capability bits_per_sample=0x%x",
+            codec_capability.bits_per_sample);
+      goto done;
+    } else {
+      return_params[AUDIO_PARAMETER_STREAM_SUP_FORMATS] = param;
+    }
+  }
+
+  // Add the sample rate
+  if (params.find(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES) != params.end()) {
+    std::string param;
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_44100) {
+      if (!param.empty()) param += "|";
+      param += "44100";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_48000) {
+      if (!param.empty()) param += "|";
+      param += "48000";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_88200) {
+      if (!param.empty()) param += "|";
+      param += "88200";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_96000) {
+      if (!param.empty()) param += "|";
+      param += "96000";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_176400) {
+      if (!param.empty()) param += "|";
+      param += "176400";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_192000) {
+      if (!param.empty()) param += "|";
+      param += "192000";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_16000) {
+      if (!param.empty()) param += "|";
+      param += "16000";
+    }
+    if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_24000) {
+      if (!param.empty()) param += "|";
+      param += "24000";
+    }
+    if (param.empty()) {
+      ERROR("Invalid codec capability sample_rate=0x%x",
+            codec_capability.sample_rate);
+      goto done;
+    } else {
+      return_params[AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES] = param;
+    }
+  }
+
+  // Add the channel mask
+  if (params.find(AUDIO_PARAMETER_STREAM_SUP_CHANNELS) != params.end()) {
+    std::string param;
+    if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_MONO) {
+      if (!param.empty()) param += "|";
+      param += "AUDIO_CHANNEL_OUT_MONO";
+    }
+    if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO) {
+      if (!param.empty()) param += "|";
+      param += "AUDIO_CHANNEL_OUT_STEREO";
+    }
+    if (param.empty()) {
+      ERROR("Invalid codec capability channel_mode=0x%x",
+            codec_capability.channel_mode);
+      goto done;
+    } else {
+      return_params[AUDIO_PARAMETER_STREAM_SUP_CHANNELS] = param;
+    }
+  }
+
+done:
+  std::string result;
+  for (const auto& ptr : return_params) {
+    result += ptr.first + "=" + ptr.second + ";";
+  }
+
+  INFO("get parameters result = %s", result.c_str());
+
+  return strdup(result.c_str());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out* stream) {
+  int latency_us;
+
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  FNLOG();
+
+  latency_us =
+      ((out->common.buffer_sz * 1000) /
+       audio_stream_out_frame_size(&out->stream) / out->common.cfg.rate) *
+      1000;
+
+  return (latency_us / 1000) + 200;
+}
+
+static int out_set_volume(UNUSED_ATTR struct audio_stream_out* stream,
+                          UNUSED_ATTR float left, UNUSED_ATTR float right) {
+  FNLOG();
+
+  /* volume controlled in audioflinger mixer (digital) */
+
+  return -ENOSYS;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out* stream,
+                                         uint64_t* frames,
+                                         struct timespec* timestamp) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  FNLOG();
+  if (stream == NULL || frames == NULL || timestamp == NULL) return -EINVAL;
+
+  int ret = -EWOULDBLOCK;
+  std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+  uint64_t latency_frames =
+      (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+  if (out->frames_presented >= latency_frames) {
+    *frames = out->frames_presented - latency_frames;
+    clock_gettime(CLOCK_MONOTONIC,
+                  timestamp);  // could also be associated with out_write().
+    ret = 0;
+  }
+  return ret;
+}
+
+static int out_get_render_position(const struct audio_stream_out* stream,
+                                   uint32_t* dsp_frames) {
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  FNLOG();
+  if (stream == NULL || dsp_frames == NULL) return -EINVAL;
+
+  std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+  uint64_t latency_frames =
+      (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+  if (out->frames_rendered >= latency_frames) {
+    *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames);
+  } else {
+    *dsp_frames = 0;
+  }
+  return 0;
+}
+
+static int out_add_audio_effect(UNUSED_ATTR const struct audio_stream* stream,
+                                UNUSED_ATTR effect_handle_t effect) {
+  FNLOG();
+  return 0;
+}
+
+static int out_remove_audio_effect(
+    UNUSED_ATTR const struct audio_stream* stream,
+    UNUSED_ATTR effect_handle_t effect) {
+  FNLOG();
+  return 0;
+}
+
+/*
+ * AUDIO INPUT STREAM
+ */
+
+static uint32_t in_get_sample_rate(const struct audio_stream* stream) {
+  struct ha_stream_in* in = (struct ha_stream_in*)stream;
+
+  FNLOG();
+  return in->common.cfg.rate;
+}
+
+static int in_set_sample_rate(struct audio_stream* stream, uint32_t rate) {
+  struct ha_stream_in* in = (struct ha_stream_in*)stream;
+
+  FNLOG();
+
+  if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate)
+    return 0;
+  else
+    return -1;
+}
+
+static size_t in_get_buffer_size(
+    UNUSED_ATTR const struct audio_stream* stream) {
+  FNLOG();
+  return 320;
+}
+
+static uint32_t in_get_channels(const struct audio_stream* stream) {
+  struct ha_stream_in* in = (struct ha_stream_in*)stream;
+
+  FNLOG();
+  return in->common.cfg.channel_mask;
+}
+
+static audio_format_t in_get_format(
+    UNUSED_ATTR const struct audio_stream* stream) {
+  FNLOG();
+  return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(UNUSED_ATTR struct audio_stream* stream,
+                         UNUSED_ATTR audio_format_t format) {
+  FNLOG();
+  if (format == AUDIO_FORMAT_PCM_16_BIT)
+    return 0;
+  else
+    return -1;
+}
+
+static int in_standby(UNUSED_ATTR struct audio_stream* stream) {
+  FNLOG();
+  return 0;
+}
+
+static int in_dump(UNUSED_ATTR const struct audio_stream* stream,
+                   UNUSED_ATTR int fd) {
+  FNLOG();
+  return 0;
+}
+
+static int in_set_parameters(UNUSED_ATTR struct audio_stream* stream,
+                             UNUSED_ATTR const char* kvpairs) {
+  FNLOG();
+  return 0;
+}
+
+static char* in_get_parameters(UNUSED_ATTR const struct audio_stream* stream,
+                               UNUSED_ATTR const char* keys) {
+  FNLOG();
+  return strdup("");
+}
+
+static int in_set_gain(UNUSED_ATTR struct audio_stream_in* stream,
+                       UNUSED_ATTR float gain) {
+  FNLOG();
+  return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in* stream, void* buffer,
+                       size_t bytes) {
+  struct ha_stream_in* in = (struct ha_stream_in*)stream;
+  int read;
+  int us_delay;
+
+  DEBUG("read %zu bytes, state: %d", bytes, in->common.state);
+
+  std::unique_lock<std::recursive_mutex> lock(*in->common.mutex);
+  if (in->common.state == AUDIO_HA_STATE_SUSPENDED ||
+      in->common.state == AUDIO_HA_STATE_STOPPING) {
+    DEBUG("stream suspended");
+    goto error;
+  }
+
+  /* only allow autostarting if we are in stopped or standby */
+  if ((in->common.state == AUDIO_HA_STATE_STOPPED) ||
+      (in->common.state == AUDIO_HA_STATE_STANDBY)) {
+    if (start_audio_datapath(&in->common) < 0) {
+      goto error;
+    }
+  } else if (in->common.state != AUDIO_HA_STATE_STARTED) {
+    ERROR("stream not in stopped or standby");
+    goto error;
+  }
+
+  lock.unlock();
+  read = skt_read(in->common.audio_fd, buffer, bytes);
+  lock.lock();
+  if (read == -1) {
+    skt_disconnect(in->common.audio_fd);
+    in->common.audio_fd = AUDIO_SKT_DISCONNECTED;
+    if ((in->common.state != AUDIO_HA_STATE_SUSPENDED) &&
+        (in->common.state != AUDIO_HA_STATE_STOPPING)) {
+      in->common.state = AUDIO_HA_STATE_STOPPED;
+    } else {
+      ERROR("read failed : stream suspended, avoid resetting state");
+    }
+    goto error;
+  } else if (read == 0) {
+    DEBUG("read time out - return zeros");
+    memset(buffer, 0, bytes);
+    read = bytes;
+  }
+  lock.unlock();
+
+  DEBUG("read %d bytes out of %zu bytes", read, bytes);
+  return read;
+
+error:
+  memset(buffer, 0, bytes);
+  us_delay = calc_audiotime_usec(in->common.cfg, bytes);
+  DEBUG("emulate ha read delay (%d us)", us_delay);
+
+  usleep(us_delay);
+  return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(
+    UNUSED_ATTR struct audio_stream_in* stream) {
+  FNLOG();
+  return 0;
+}
+
+static int in_add_audio_effect(UNUSED_ATTR const struct audio_stream* stream,
+                               UNUSED_ATTR effect_handle_t effect) {
+  FNLOG();
+  return 0;
+}
+
+static int in_remove_audio_effect(UNUSED_ATTR const struct audio_stream* stream,
+                                  UNUSED_ATTR effect_handle_t effect) {
+  FNLOG();
+
+  return 0;
+}
+
+static int adev_open_output_stream(struct audio_hw_device* dev,
+                                   UNUSED_ATTR audio_io_handle_t handle,
+                                   UNUSED_ATTR audio_devices_t devices,
+                                   UNUSED_ATTR audio_output_flags_t flags,
+                                   struct audio_config* config,
+                                   struct audio_stream_out** stream_out,
+                                   UNUSED_ATTR const char* address)
+
+{
+  struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev;
+  struct ha_stream_out* out;
+  int ret = 0;
+
+  INFO("opening output");
+  // protect against adev->output and stream_out from being inconsistent
+  std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex);
+  out = (struct ha_stream_out*)calloc(1, sizeof(struct ha_stream_out));
+
+  if (!out) return -ENOMEM;
+
+  out->stream.common.get_sample_rate = out_get_sample_rate;
+  out->stream.common.set_sample_rate = out_set_sample_rate;
+  out->stream.common.get_buffer_size = out_get_buffer_size;
+  out->stream.common.get_channels = out_get_channels;
+  out->stream.common.get_format = out_get_format;
+  out->stream.common.set_format = out_set_format;
+  out->stream.common.standby = out_standby;
+  out->stream.common.dump = out_dump;
+  out->stream.common.set_parameters = out_set_parameters;
+  out->stream.common.get_parameters = out_get_parameters;
+  out->stream.common.add_audio_effect = out_add_audio_effect;
+  out->stream.common.remove_audio_effect = out_remove_audio_effect;
+  out->stream.get_latency = out_get_latency;
+  out->stream.set_volume = out_set_volume;
+  out->stream.write = out_write;
+  out->stream.get_render_position = out_get_render_position;
+  out->stream.get_presentation_position = out_get_presentation_position;
+
+  /* initialize ha specifics */
+  ha_stream_common_init(&out->common);
+
+  // Make sure we always have the feeding parameters configured
+  btav_a2dp_codec_config_t codec_config;
+  btav_a2dp_codec_config_t codec_capability;
+  if (ha_read_output_audio_config(&out->common, &codec_config,
+                                  &codec_capability,
+                                  true /* update_stream_config */) < 0) {
+    ERROR("ha_read_output_audio_config failed");
+    ret = -1;
+    goto err_open;
+  }
+  // ha_read_output_audio_config() opens the socket control path (or fails)
+
+  /* set output config values */
+  if (config != nullptr) {
+    // Try to use the config parameters and send it to the remote side
+    // TODO: Shall we use out_set_format() and similar?
+    if (config->format != 0) out->common.cfg.format = config->format;
+    if (config->sample_rate != 0) out->common.cfg.rate = config->sample_rate;
+    if (config->channel_mask != 0)
+      out->common.cfg.channel_mask = config->channel_mask;
+    if ((out->common.cfg.format != 0) || (out->common.cfg.rate != 0) ||
+        (out->common.cfg.channel_mask != 0)) {
+      if (ha_write_output_audio_config(&out->common) < 0) {
+        ERROR("ha_write_output_audio_config failed");
+        ret = -1;
+        goto err_open;
+      }
+      // Read again and make sure we use the same parameters as the remote side
+      if (ha_read_output_audio_config(&out->common, &codec_config,
+                                      &codec_capability,
+                                      true /* update_stream_config */) < 0) {
+        ERROR("ha_read_output_audio_config failed");
+        ret = -1;
+        goto err_open;
+      }
+    }
+    config->format = out_get_format((const struct audio_stream*)&out->stream);
+    config->sample_rate =
+        out_get_sample_rate((const struct audio_stream*)&out->stream);
+    config->channel_mask =
+        out_get_channels((const struct audio_stream*)&out->stream);
+
+    INFO(
+        "Output stream config: format=0x%x sample_rate=%d channel_mask=0x%x "
+        "buffer_sz=%zu",
+        config->format, config->sample_rate, config->channel_mask,
+        out->common.buffer_sz);
+  }
+  *stream_out = &out->stream;
+  ha_dev->output = out;
+
+  DEBUG("success");
+  /* Delay to ensure Headset is in proper state when START is initiated from
+   * DUT immediately after the connection due to ongoing music playback. */
+  usleep(250000);
+  return 0;
+
+err_open:
+  ha_stream_common_destroy(&out->common);
+  free(out);
+  *stream_out = NULL;
+  ha_dev->output = NULL;
+  ERROR("failed");
+  return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device* dev,
+                                     struct audio_stream_out* stream) {
+  struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev;
+  struct ha_stream_out* out = (struct ha_stream_out*)stream;
+
+  // prevent interference with adev_set_parameters.
+  std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex);
+  {
+    std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+    const ha_state_t state = out->common.state;
+    INFO("closing output (state %d)", (int)state);
+    if ((state == AUDIO_HA_STATE_STARTED) ||
+        (state == AUDIO_HA_STATE_STOPPING)) {
+      stop_audio_datapath(&out->common);
+    }
+
+    skt_disconnect(out->common.ctrl_fd);
+    out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+  }
+
+  ha_stream_common_destroy(&out->common);
+  free(stream);
+  ha_dev->output = NULL;
+
+  DEBUG("done");
+}
+
+static int adev_set_parameters(struct audio_hw_device* dev,
+                               const char* kvpairs) {
+  struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev;
+  int retval = 0;
+
+  // prevent interference with adev_close_output_stream
+  std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex);
+  struct ha_stream_out* out = ha_dev->output;
+
+  if (out == NULL) return retval;
+
+  INFO("state %d", out->common.state);
+
+  retval =
+      out->stream.common.set_parameters((struct audio_stream*)out, kvpairs);
+
+  return retval;
+}
+
+static char* adev_get_parameters(UNUSED_ATTR const struct audio_hw_device* dev,
+                                 const char* keys) {
+  FNLOG();
+
+  std::unordered_map<std::string, std::string> params =
+      hash_map_utils_new_from_string_params(keys);
+  hash_map_utils_dump_string_keys_string_values(params);
+
+  return strdup("");
+}
+
+static int adev_init_check(UNUSED_ATTR const struct audio_hw_device* dev) {
+  FNLOG();
+
+  return 0;
+}
+
+static int adev_set_voice_volume(UNUSED_ATTR struct audio_hw_device* dev,
+                                 UNUSED_ATTR float volume) {
+  FNLOG();
+
+  return -ENOSYS;
+}
+
+static int adev_set_master_volume(UNUSED_ATTR struct audio_hw_device* dev,
+                                  UNUSED_ATTR float volume) {
+  FNLOG();
+
+  return -ENOSYS;
+}
+
+static int adev_set_mode(UNUSED_ATTR struct audio_hw_device* dev,
+                         UNUSED_ATTR audio_mode_t mode) {
+  FNLOG();
+
+  return 0;
+}
+
+static int adev_set_mic_mute(UNUSED_ATTR struct audio_hw_device* dev,
+                             UNUSED_ATTR bool state) {
+  FNLOG();
+
+  return -ENOSYS;
+}
+
+static int adev_get_mic_mute(UNUSED_ATTR const struct audio_hw_device* dev,
+                             UNUSED_ATTR bool* state) {
+  FNLOG();
+
+  return -ENOSYS;
+}
+
+static size_t adev_get_input_buffer_size(
+    UNUSED_ATTR const struct audio_hw_device* dev,
+    UNUSED_ATTR const struct audio_config* config) {
+  FNLOG();
+
+  return 320;
+}
+
+static int adev_open_input_stream(struct audio_hw_device* dev,
+                                  UNUSED_ATTR audio_io_handle_t handle,
+                                  UNUSED_ATTR audio_devices_t devices,
+                                  UNUSED_ATTR struct audio_config* config,
+                                  struct audio_stream_in** stream_in,
+                                  UNUSED_ATTR audio_input_flags_t flags,
+                                  UNUSED_ATTR const char* address,
+                                  UNUSED_ATTR audio_source_t source) {
+  struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev;
+  struct ha_stream_in* in;
+  int ret;
+
+  FNLOG();
+
+  // protect against adev->input and stream_in from being inconsistent
+  std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex);
+  in = (struct ha_stream_in*)calloc(1, sizeof(struct ha_stream_in));
+
+  if (!in) return -ENOMEM;
+
+  in->stream.common.get_sample_rate = in_get_sample_rate;
+  in->stream.common.set_sample_rate = in_set_sample_rate;
+  in->stream.common.get_buffer_size = in_get_buffer_size;
+  in->stream.common.get_channels = in_get_channels;
+  in->stream.common.get_format = in_get_format;
+  in->stream.common.set_format = in_set_format;
+  in->stream.common.standby = in_standby;
+  in->stream.common.dump = in_dump;
+  in->stream.common.set_parameters = in_set_parameters;
+  in->stream.common.get_parameters = in_get_parameters;
+  in->stream.common.add_audio_effect = in_add_audio_effect;
+  in->stream.common.remove_audio_effect = in_remove_audio_effect;
+  in->stream.set_gain = in_set_gain;
+  in->stream.read = in_read;
+  in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+  /* initialize ha specifics */
+  ha_stream_common_init(&in->common);
+
+  *stream_in = &in->stream;
+  ha_dev->input = in;
+
+  if (ha_read_input_audio_config(&in->common) < 0) {
+    ERROR("ha_read_input_audio_config failed (%s)", strerror(errno));
+    ret = -1;
+    goto err_open;
+  }
+  // ha_read_input_audio_config() opens socket control path (or fails)
+
+  DEBUG("success");
+  return 0;
+
+err_open:
+  ha_stream_common_destroy(&in->common);
+  free(in);
+  *stream_in = NULL;
+  ha_dev->input = NULL;
+  ERROR("failed");
+  return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device* dev,
+                                    struct audio_stream_in* stream) {
+  struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev;
+  struct ha_stream_in* in = (struct ha_stream_in*)stream;
+
+  std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex);
+  {
+    std::lock_guard<std::recursive_mutex> lock(*in->common.mutex);
+    const ha_state_t state = in->common.state;
+    INFO("closing input (state %d)", (int)state);
+
+    if ((state == AUDIO_HA_STATE_STARTED) || (state == AUDIO_HA_STATE_STOPPING))
+      stop_audio_datapath(&in->common);
+
+    skt_disconnect(in->common.ctrl_fd);
+    in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+  }
+  ha_stream_common_destroy(&in->common);
+  free(stream);
+  ha_dev->input = NULL;
+
+  DEBUG("done");
+}
+
+static int adev_dump(UNUSED_ATTR const audio_hw_device_t* device,
+                     UNUSED_ATTR int fd) {
+  FNLOG();
+
+  return 0;
+}
+
+static int adev_close(hw_device_t* device) {
+  struct ha_audio_device* ha_dev = (struct ha_audio_device*)device;
+  FNLOG();
+
+  delete ha_dev->mutex;
+  ha_dev->mutex = nullptr;
+  free(device);
+  return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+                     hw_device_t** device) {
+  struct ha_audio_device* adev;
+
+  INFO(" adev_open in ha_hw module");
+  FNLOG();
+
+  if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) {
+    ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
+    return -EINVAL;
+  }
+
+  adev = (struct ha_audio_device*)calloc(1, sizeof(struct ha_audio_device));
+
+  if (!adev) return -ENOMEM;
+
+  adev->mutex = new std::recursive_mutex;
+
+  adev->device.common.tag = HARDWARE_DEVICE_TAG;
+  adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+  adev->device.common.module = (struct hw_module_t*)module;
+  adev->device.common.close = adev_close;
+
+  adev->device.init_check = adev_init_check;
+  adev->device.set_voice_volume = adev_set_voice_volume;
+  adev->device.set_master_volume = adev_set_master_volume;
+  adev->device.set_mode = adev_set_mode;
+  adev->device.set_mic_mute = adev_set_mic_mute;
+  adev->device.get_mic_mute = adev_get_mic_mute;
+  adev->device.set_parameters = adev_set_parameters;
+  adev->device.get_parameters = adev_get_parameters;
+  adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+  adev->device.open_output_stream = adev_open_output_stream;
+  adev->device.close_output_stream = adev_close_output_stream;
+  adev->device.open_input_stream = adev_open_input_stream;
+  adev->device.close_input_stream = adev_close_input_stream;
+  adev->device.dump = adev_dump;
+
+  adev->output = NULL;
+
+  *device = &adev->device.common;
+
+  return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+    .open = adev_open,
+};
+
+__attribute__((
+    visibility("default"))) struct audio_module HAL_MODULE_INFO_SYM = {
+    .common =
+        {
+            .tag = HARDWARE_MODULE_TAG,
+            .version_major = 1,
+            .version_minor = 0,
+            .id = AUDIO_HARDWARE_MODULE_ID,
+            .name = "Hearing Aid Audio HW HAL",
+            .author = "The Android Open Source Project",
+            .methods = &hal_module_methods,
+        },
+};
diff --git a/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc b/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc
new file mode 100644
index 0000000..2354632
--- /dev/null
+++ b/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ *  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 "audio_hearing_aid_hw.h"
+
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+
+const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event) {
+  switch (event) {
+    CASE_RETURN_STR(HEARING_AID_CTRL_CMD_NONE)
+    CASE_RETURN_STR(HEARING_AID_CTRL_CMD_CHECK_READY)
+    CASE_RETURN_STR(HEARING_AID_CTRL_CMD_START)
+    CASE_RETURN_STR(HEARING_AID_CTRL_CMD_STOP)
+    CASE_RETURN_STR(HEARING_AID_CTRL_CMD_SUSPEND)
+    CASE_RETURN_STR(HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG)
+    CASE_RETURN_STR(HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG)
+    CASE_RETURN_STR(HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG)
+    CASE_RETURN_STR(HEARING_AID_CTRL_CMD_OFFLOAD_START)
+    default:
+      break;
+  }
+
+  return "UNKNOWN HEARING_AID_CTRL_CMD";
+}
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
new file mode 100644
index 0000000..c5d0e2b
--- /dev/null
+++ b/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ *  Copyright 2017 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 <gtest/gtest.h>
+
+#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h"
+
+namespace {
+static uint32_t codec_sample_rate2value(
+    btav_a2dp_codec_sample_rate_t codec_sample_rate) {
+  switch (codec_sample_rate) {
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+      return 44100;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+      return 48000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+      return 88200;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+      return 96000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+      return 176400;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+      return 192000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+      return 16000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+      return 24000;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+      break;
+  }
+  return 0;
+}
+
+static uint32_t codec_bits_per_sample2value(
+    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) {
+  switch (codec_bits_per_sample) {
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+      return 16;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      return 24;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      return 32;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+      break;
+  }
+  return 0;
+}
+
+static uint32_t codec_channel_mode2value(
+    btav_a2dp_codec_channel_mode_t codec_channel_mode) {
+  switch (codec_channel_mode) {
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+      return 1;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+      return 2;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+      break;
+  }
+  return 0;
+}
+
+}  // namespace
+
+class AudioA2dpHwTest : public ::testing::Test {
+ protected:
+  AudioA2dpHwTest() {}
+
+ private:
+};
+
+TEST_F(AudioA2dpHwTest, test_compute_buffer_size) {
+  const btav_a2dp_codec_sample_rate_t codec_sample_rate_array[] = {
+      BTAV_A2DP_CODEC_SAMPLE_RATE_NONE,  BTAV_A2DP_CODEC_SAMPLE_RATE_44100,
+      BTAV_A2DP_CODEC_SAMPLE_RATE_48000, BTAV_A2DP_CODEC_SAMPLE_RATE_88200,
+      BTAV_A2DP_CODEC_SAMPLE_RATE_96000, BTAV_A2DP_CODEC_SAMPLE_RATE_176400,
+      BTAV_A2DP_CODEC_SAMPLE_RATE_192000};
+
+  const btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample_array[] = {
+      BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16,
+      BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32};
+
+  const btav_a2dp_codec_channel_mode_t codec_channel_mode_array[] = {
+      BTAV_A2DP_CODEC_CHANNEL_MODE_NONE, BTAV_A2DP_CODEC_CHANNEL_MODE_MONO,
+      BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO};
+
+  for (const auto codec_sample_rate : codec_sample_rate_array) {
+    for (const auto codec_bits_per_sample : codec_bits_per_sample_array) {
+      for (const auto codec_channel_mode : codec_channel_mode_array) {
+        size_t buffer_size = audio_ha_hw_stream_compute_buffer_size(
+            codec_sample_rate, codec_bits_per_sample, codec_channel_mode);
+
+        // Check for invalid input
+        if ((codec_sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) ||
+            (codec_bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) ||
+            (codec_channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) {
+          EXPECT_EQ(buffer_size,
+                    static_cast<size_t>(AUDIO_STREAM_OUTPUT_BUFFER_SZ));
+          continue;
+        }
+
+        uint32_t sample_rate = codec_sample_rate2value(codec_sample_rate);
+        EXPECT_TRUE(sample_rate != 0);
+
+        uint32_t bits_per_sample =
+            codec_bits_per_sample2value(codec_bits_per_sample);
+        EXPECT_TRUE(bits_per_sample != 0);
+
+        uint32_t number_of_channels =
+            codec_channel_mode2value(codec_channel_mode);
+        EXPECT_TRUE(number_of_channels != 0);
+
+        const uint64_t time_period_ms = 20;  // TODO: Must be a parameter
+        size_t expected_buffer_size =
+            (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * sample_rate *
+             number_of_channels * (bits_per_sample / 8)) /
+            1000;
+
+        // Compute the divisor and adjust the buffer size
+        const size_t divisor = (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 *
+                                number_of_channels * bits_per_sample) /
+                               8;
+        const size_t remainder = expected_buffer_size % divisor;
+        if (remainder != 0) {
+          expected_buffer_size += divisor - remainder;
+        }
+
+        EXPECT_EQ(buffer_size, expected_buffer_size);
+      }
+    }
+  }
+}
diff --git a/binder/Android.bp b/binder/Android.bp
new file mode 100644
index 0000000..18428c2
--- /dev/null
+++ b/binder/Android.bp
@@ -0,0 +1,120 @@
+cc_library_shared {
+    name: "libbluetooth-binder",
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+    srcs: [
+        "android/bluetooth/bluetooth_device.cc",
+        "android/bluetooth/IBluetoothSocketManager.aidl",
+        "android/os/parcel_file_descriptor.cc",
+        "android/os/parcel_uuid.cc",
+/* TODO: Uncomment this files as they get converted one-by-one into native implementation
+        "android/bluetooth/IBluetooth.aidl",
+        "android/bluetooth/IBluetoothA2dp.aidl",
+        "android/bluetooth/IBluetoothA2dpSink.aidl",
+        "android/bluetooth/IBluetoothAvrcpController.aidl",
+        "android/bluetooth/IBluetoothAvrcpTarget.aidl",
+        "android/bluetooth/IBluetoothCallback.aidl",
+        "android/bluetooth/IBluetoothProfileServiceConnection.aidl",
+        "android/bluetooth/IBluetoothHeadset.aidl",
+        "android/bluetooth/IBluetoothHeadsetPhone.aidl",
+        "android/bluetooth/IBluetoothHealth.aidl",
+        "android/bluetooth/IBluetoothHealthCallback.aidl",
+        "android/bluetooth/IBluetoothHearingAid.aidl",
+        "android/bluetooth/IBluetoothHidHost.aidl",
+        "android/bluetooth/IBluetoothPan.aidl",
+        "android/bluetooth/IBluetoothManager.aidl",
+        "android/bluetooth/IBluetoothManagerCallback.aidl",
+        "android/bluetooth/IBluetoothMap.aidl",
+        "android/bluetooth/IBluetoothMapClient.aidl",
+        "android/bluetooth/IBluetoothPbap.aidl",
+        "android/bluetooth/IBluetoothPbapClient.aidl",
+        "android/bluetooth/IBluetoothSap.aidl",
+        "android/bluetooth/IBluetoothStateChangeCallback.aidl",
+        "android/bluetooth/IBluetoothHeadsetClient.aidl",
+        "android/bluetooth/IBluetoothHidDevice.aidl",
+        "android/bluetooth/IBluetoothHidDeviceCallback.aidl",
+        "android/bluetooth/IBluetoothGatt.aidl",
+        "android/bluetooth/IBluetoothGattCallback.aidl",
+        "android/bluetooth/IBluetoothGattServerCallback.aidl",
+        "android/bluetooth/le/IAdvertisingSetCallback.aidl",
+        "android/bluetooth/le/IPeriodicAdvertisingCallback.aidl",
+        "android/bluetooth/le/IScannerCallback.aidl"
+*/
+     ],
+    export_include_dirs: [ "./"],
+    aidl: {
+        export_aidl_headers: true,
+        include_dirs: [
+            "frameworks/native/aidl/binder",
+
+             /* required for android.os.ParcelUuid, and android.os.ParcelFileDescriptor */
+            "frameworks/base/core/java",
+            "system/bt/binder",
+        ],
+    },
+    include_dirs: [
+        "libnativehelper/include/nativehelper",
+        "system/bt/types",
+    ],
+    shared_libs: [
+        "libandroid_runtime",
+        "libbinder",
+        "libchrome",
+        "libnativehelper",
+        "libcutils",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libbluetooth-types",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+}
+
+// AIDL interface between libbluetooth-binder and framework.jar
+filegroup {
+    name: "libbluetooth-binder-aidl",
+    srcs: [
+        "android/bluetooth/IBluetooth.aidl",
+        "android/bluetooth/IBluetoothA2dp.aidl",
+        "android/bluetooth/IBluetoothA2dpSink.aidl",
+        "android/bluetooth/IBluetoothAvrcpController.aidl",
+        "android/bluetooth/IBluetoothAvrcpTarget.aidl",
+        "android/bluetooth/IBluetoothCallback.aidl",
+        "android/bluetooth/IBluetoothProfileServiceConnection.aidl",
+        "android/bluetooth/IBluetoothHeadset.aidl",
+        "android/bluetooth/IBluetoothHeadsetPhone.aidl",
+        "android/bluetooth/IBluetoothHealth.aidl",
+        "android/bluetooth/IBluetoothHealthCallback.aidl",
+        "android/bluetooth/IBluetoothHearingAid.aidl",
+        "android/bluetooth/IBluetoothHidHost.aidl",
+        "android/bluetooth/IBluetoothPan.aidl",
+        "android/bluetooth/IBluetoothManager.aidl",
+        "android/bluetooth/IBluetoothManagerCallback.aidl",
+        "android/bluetooth/IBluetoothMap.aidl",
+        "android/bluetooth/IBluetoothMapClient.aidl",
+        "android/bluetooth/IBluetoothPbap.aidl",
+        "android/bluetooth/IBluetoothPbapClient.aidl",
+        "android/bluetooth/IBluetoothSap.aidl",
+        "android/bluetooth/IBluetoothSocketManager.aidl",
+        "android/bluetooth/IBluetoothStateChangeCallback.aidl",
+        "android/bluetooth/IBluetoothHeadsetClient.aidl",
+        "android/bluetooth/IBluetoothHidDevice.aidl",
+        "android/bluetooth/IBluetoothHidDeviceCallback.aidl",
+        "android/bluetooth/IBluetoothGatt.aidl",
+        "android/bluetooth/IBluetoothGattCallback.aidl",
+        "android/bluetooth/IBluetoothGattServerCallback.aidl",
+        "android/bluetooth/le/IAdvertisingSetCallback.aidl",
+        "android/bluetooth/le/IPeriodicAdvertisingCallback.aidl",
+        "android/bluetooth/le/IScannerCallback.aidl",
+    ],
+}
diff --git a/binder/android/bluetooth/BluetoothActivityEnergyInfo.aidl b/binder/android/bluetooth/BluetoothActivityEnergyInfo.aidl
new file mode 100644
index 0000000..1410019
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothActivityEnergyInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothActivityEnergyInfo;
diff --git a/binder/android/bluetooth/BluetoothAudioConfig.aidl b/binder/android/bluetooth/BluetoothAudioConfig.aidl
new file mode 100644
index 0000000..2ef113d
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothAudioConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2009 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAudioConfig;
diff --git a/binder/android/bluetooth/BluetoothAvrcpPlayerSettings.aidl b/binder/android/bluetooth/BluetoothAvrcpPlayerSettings.aidl
new file mode 100644
index 0000000..41b8af6
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothAvrcpPlayerSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2015 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpPlayerSettings;
diff --git a/binder/android/bluetooth/BluetoothClass.aidl b/binder/android/bluetooth/BluetoothClass.aidl
new file mode 100644
index 0000000..8699b1e
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothClass.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017, 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothClass;
diff --git a/binder/android/bluetooth/BluetoothCodecConfig.aidl b/binder/android/bluetooth/BluetoothCodecConfig.aidl
new file mode 100644
index 0000000..5890637
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothCodecConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothCodecConfig;
diff --git a/binder/android/bluetooth/BluetoothCodecStatus.aidl b/binder/android/bluetooth/BluetoothCodecStatus.aidl
new file mode 100644
index 0000000..f674db7
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothCodecStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothCodecStatus;
diff --git a/binder/android/bluetooth/BluetoothDevice.aidl b/binder/android/bluetooth/BluetoothDevice.aidl
new file mode 100644
index 0000000..b9b0589
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2009 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothDevice cpp_header "android/bluetooth/bluetooth_device.h";
diff --git a/binder/android/bluetooth/BluetoothGattCharacteristic.aidl b/binder/android/bluetooth/BluetoothGattCharacteristic.aidl
new file mode 100644
index 0000000..463b7a7
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothGattCharacteristic.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattCharacteristic;
diff --git a/binder/android/bluetooth/BluetoothGattDescriptor.aidl b/binder/android/bluetooth/BluetoothGattDescriptor.aidl
new file mode 100644
index 0000000..6d4cdeb
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothGattDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattDescriptor;
diff --git a/binder/android/bluetooth/BluetoothGattIncludedService.aidl b/binder/android/bluetooth/BluetoothGattIncludedService.aidl
new file mode 100644
index 0000000..d911973
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothGattIncludedService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattIncludedService;
diff --git a/binder/android/bluetooth/BluetoothGattService.aidl b/binder/android/bluetooth/BluetoothGattService.aidl
new file mode 100644
index 0000000..8e72ba9
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothGattService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattService;
diff --git a/binder/android/bluetooth/BluetoothHeadsetClientCall.aidl b/binder/android/bluetooth/BluetoothHeadsetClientCall.aidl
new file mode 100644
index 0000000..5403d51
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothHeadsetClientCall.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2014 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.
+ */
+package android.bluetooth;
+
+parcelable BluetoothHeadsetClientCall;
diff --git a/binder/android/bluetooth/BluetoothHealthAppConfiguration.aidl b/binder/android/bluetooth/BluetoothHealthAppConfiguration.aidl
new file mode 100644
index 0000000..bc9e54f
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothHealthAppConfiguration.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2011, 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.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHealthAppConfiguration;
diff --git a/binder/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl b/binder/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
new file mode 100644
index 0000000..14f9114
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2016, 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.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppQosSettings;
diff --git a/binder/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl b/binder/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
new file mode 100644
index 0000000..87dd10e
--- /dev/null
+++ b/binder/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2016, 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.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppSdpSettings;
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
new file mode 100644
index 0000000..90c34b0
--- /dev/null
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2008, 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothSocketManager;
+import android.bluetooth.IBluetoothStateChangeCallback;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.OobData;
+import android.os.ParcelUuid;
+import android.os.ParcelFileDescriptor;
+import android.os.ResultReceiver;
+
+/**
+ * System private API for talking with the Bluetooth service.
+ *
+ * {@hide}
+ */
+interface IBluetooth
+{
+    boolean isEnabled();
+    int getState();
+    boolean enable();
+    boolean enableNoAutoConnect();
+    boolean disable();
+
+    String getAddress();
+    ParcelUuid[] getUuids();
+    boolean setName(in String name);
+    String getName();
+    BluetoothClass getBluetoothClass();
+    boolean setBluetoothClass(in BluetoothClass bluetoothClass);
+
+    int getScanMode();
+    boolean setScanMode(int mode, int duration);
+
+    int getDiscoverableTimeout();
+    boolean setDiscoverableTimeout(int timeout);
+
+    boolean startDiscovery();
+    boolean cancelDiscovery();
+    boolean isDiscovering();
+    long getDiscoveryEndMillis();
+
+    int getAdapterConnectionState();
+    int getProfileConnectionState(int profile);
+
+    BluetoothDevice[] getBondedDevices();
+    boolean createBond(in BluetoothDevice device, in int transport);
+    boolean createBondOutOfBand(in BluetoothDevice device, in int transport, in OobData oobData);
+    boolean cancelBondProcess(in BluetoothDevice device);
+    boolean removeBond(in BluetoothDevice device);
+    int getBondState(in BluetoothDevice device);
+    boolean isBondingInitiatedLocally(in BluetoothDevice device);
+    long getSupportedProfiles();
+    int getConnectionState(in BluetoothDevice device);
+
+    String getRemoteName(in BluetoothDevice device);
+    int getRemoteType(in BluetoothDevice device);
+    String getRemoteAlias(in BluetoothDevice device);
+    boolean setRemoteAlias(in BluetoothDevice device, in String name);
+    int getRemoteClass(in BluetoothDevice device);
+    ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
+    boolean fetchRemoteUuids(in BluetoothDevice device);
+    boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
+    int getBatteryLevel(in BluetoothDevice device);
+    int getMaxConnectedAudioDevices();
+
+    boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
+    boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
+    passkey);
+    boolean setPairingConfirmation(in BluetoothDevice device, boolean accept);
+
+    int getPhonebookAccessPermission(in BluetoothDevice device);
+    boolean setPhonebookAccessPermission(in BluetoothDevice device, int value);
+    int getMessageAccessPermission(in BluetoothDevice device);
+    boolean setMessageAccessPermission(in BluetoothDevice device, int value);
+    int getSimAccessPermission(in BluetoothDevice device);
+    boolean setSimAccessPermission(in BluetoothDevice device, int value);
+
+    void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
+
+    void registerCallback(in IBluetoothCallback callback);
+    void unregisterCallback(in IBluetoothCallback callback);
+
+    // For Socket
+    IBluetoothSocketManager getSocketManager();
+
+    boolean factoryReset();
+
+    boolean isMultiAdvertisementSupported();
+    boolean isOffloadedFilteringSupported();
+    boolean isOffloadedScanBatchingSupported();
+    boolean isActivityAndEnergyReportingSupported();
+    boolean isLe2MPhySupported();
+    boolean isLeCodedPhySupported();
+    boolean isLeExtendedAdvertisingSupported();
+    boolean isLePeriodicAdvertisingSupported();
+    int getLeMaximumAdvertisingDataLength();
+    BluetoothActivityEnergyInfo reportActivityInfo();
+
+    /**
+     * Requests the controller activity info asynchronously.
+     * The implementor is expected to reply with the
+     * {@link android.bluetooth.BluetoothActivityEnergyInfo} object placed into the Bundle with the
+     * key {@link android.os.BatteryStats#RESULT_RECEIVER_CONTROLLER_KEY}.
+     * The result code is ignored.
+     */
+    oneway void requestActivityInfo(in ResultReceiver result);
+
+    void onLeServiceUp();
+    void onBrEdrDown();
+}
diff --git a/binder/android/bluetooth/IBluetoothA2dp.aidl b/binder/android/bluetooth/IBluetoothA2dp.aidl
new file mode 100644
index 0000000..6606a1b
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothA2dp.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth A2DP service
+ *
+ * @hide
+ */
+interface IBluetoothA2dp {
+    // Public API
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setActiveDevice(in BluetoothDevice device);
+    BluetoothDevice getActiveDevice();
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+    boolean isAvrcpAbsoluteVolumeSupported();
+    oneway void setAvrcpAbsoluteVolume(int volume);
+    boolean isA2dpPlaying(in BluetoothDevice device);
+    BluetoothCodecStatus getCodecStatus(in BluetoothDevice device);
+    oneway void setCodecConfigPreference(in BluetoothDevice device,
+                in BluetoothCodecConfig codecConfig);
+    oneway void enableOptionalCodecs(in BluetoothDevice device);
+    oneway void disableOptionalCodecs(in BluetoothDevice device);
+    int supportsOptionalCodecs(in BluetoothDevice device);
+    int getOptionalCodecsEnabled(in BluetoothDevice device);
+    oneway void setOptionalCodecsEnabled(in BluetoothDevice device, int value);
+}
diff --git a/binder/android/bluetooth/IBluetoothA2dpSink.aidl b/binder/android/bluetooth/IBluetoothA2dpSink.aidl
new file mode 100644
index 0000000..557eefc
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothAudioConfig;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth A2DP sink service
+ *
+ * @hide
+ */
+interface IBluetoothA2dpSink {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+    boolean isA2dpPlaying(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothAvrcpController.aidl b/binder/android/bluetooth/IBluetoothAvrcpController.aidl
new file mode 100644
index 0000000..fc5ff2d
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothAvrcpPlayerSettings;
+import android.bluetooth.BluetoothDevice;
+import android.media.MediaMetadata;
+import android.media.session.PlaybackState;
+
+/**
+ * APIs for Bluetooth AVRCP controller service
+ *
+ * @hide
+ */
+interface IBluetoothAvrcpController {
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    BluetoothAvrcpPlayerSettings getPlayerSettings(in BluetoothDevice device);
+    boolean setPlayerApplicationSetting(in BluetoothAvrcpPlayerSettings plAppSetting);
+    void sendGroupNavigationCmd(in BluetoothDevice device, int keyCode, int keyState);
+}
diff --git a/binder/android/bluetooth/IBluetoothAvrcpTarget.aidl b/binder/android/bluetooth/IBluetoothAvrcpTarget.aidl
new file mode 100644
index 0000000..23f3608
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothAvrcpTarget.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.bluetooth;
+
+/**
+ * API for Bluetooth AVRCP Target Interface
+ *
+ * @hide
+ */
+interface IBluetoothAvrcpTarget {
+    /**
+     * @hide
+     */
+    void sendVolumeChanged(in int volume);
+}
diff --git a/binder/android/bluetooth/IBluetoothCallback.aidl b/binder/android/bluetooth/IBluetoothCallback.aidl
new file mode 100644
index 0000000..3c0680f
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2009, 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.
+ */
+
+package android.bluetooth;
+
+/**
+ * System private API for Bluetooth service callbacks.
+ *
+ * {@hide}
+ */
+interface IBluetoothCallback
+{
+    //void onRfcommChannelFound(int channel);
+    void onBluetoothStateChange(int prevState, int newState);
+}
diff --git a/binder/android/bluetooth/IBluetoothGatt.aidl b/binder/android/bluetooth/IBluetoothGatt.aidl
new file mode 100644
index 0000000..c9e1c4b
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothGatt.aidl
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2013 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.
+ */
+
+package android.bluetooth;
+
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.bluetooth.le.PeriodicAdvertisingParameters;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.bluetooth.le.ResultStorageDescriptor;
+import android.os.ParcelUuid;
+import android.os.WorkSource;
+
+import android.bluetooth.IBluetoothGattCallback;
+import android.bluetooth.IBluetoothGattServerCallback;
+import android.bluetooth.le.IAdvertisingSetCallback;
+import android.bluetooth.le.IPeriodicAdvertisingCallback;
+import android.bluetooth.le.IScannerCallback;
+
+/**
+ * API for interacting with BLE / GATT
+ * @hide
+ */
+interface IBluetoothGatt {
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+
+    void registerScanner(in IScannerCallback callback, in WorkSource workSource);
+    void unregisterScanner(in int scannerId);
+    void startScan(in int scannerId, in ScanSettings settings, in List<ScanFilter> filters,
+                   in List scanStorages, in String callingPackage);
+    void startScanForIntent(in PendingIntent intent, in ScanSettings settings, in List<ScanFilter> filters,
+                            in String callingPackage);
+    void stopScanForIntent(in PendingIntent intent, in String callingPackage);
+    void stopScan(in int scannerId);
+    void flushPendingBatchResults(in int scannerId);
+
+    void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData,
+                                in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters,
+                                in AdvertiseData periodicData, in int duration, in int maxExtAdvEvents,
+                                in IAdvertisingSetCallback callback);
+    void stopAdvertisingSet(in IAdvertisingSetCallback callback);
+
+    void getOwnAddress(in int advertiserId);
+    void enableAdvertisingSet(in int advertiserId, in boolean enable, in int duration, in int maxExtAdvEvents);
+    void setAdvertisingData(in int advertiserId, in AdvertiseData data);
+    void setScanResponseData(in int advertiserId, in AdvertiseData data);
+    void setAdvertisingParameters(in int advertiserId, in AdvertisingSetParameters parameters);
+    void setPeriodicAdvertisingParameters(in int advertiserId, in PeriodicAdvertisingParameters parameters);
+    void setPeriodicAdvertisingData(in int advertiserId, in AdvertiseData data);
+    void setPeriodicAdvertisingEnable(in int advertiserId, in boolean enable);
+
+    void registerSync(in ScanResult scanResult, in int skip, in int timeout, in IPeriodicAdvertisingCallback callback);
+    void unregisterSync(in IPeriodicAdvertisingCallback callback);
+
+    void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
+
+    void unregisterClient(in int clientIf);
+    void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport, in boolean opportunistic, in int phy);
+    void clientDisconnect(in int clientIf, in String address);
+    void clientSetPreferredPhy(in int clientIf, in String address, in int txPhy, in int rxPhy, in int phyOptions);
+    void clientReadPhy(in int clientIf, in String address);
+    void refreshDevice(in int clientIf, in String address);
+    void discoverServices(in int clientIf, in String address);
+    void discoverServiceByUuid(in int clientIf, in String address, in ParcelUuid uuid);
+    void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
+    void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid,
+                           in int startHandle, in int endHandle, in int authReq);
+    void writeCharacteristic(in int clientIf, in String address, in int handle,
+                            in int writeType, in int authReq, in byte[] value);
+    void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
+    void writeDescriptor(in int clientIf, in String address, in int handle,
+                            in int authReq, in byte[] value);
+    void registerForNotification(in int clientIf, in String address, in int handle, in boolean enable);
+    void beginReliableWrite(in int clientIf, in String address);
+    void endReliableWrite(in int clientIf, in String address, in boolean execute);
+    void readRemoteRssi(in int clientIf, in String address);
+    void configureMTU(in int clientIf, in String address, in int mtu);
+    void connectionParameterUpdate(in int clientIf, in String address, in int connectionPriority);
+    void leConnectionUpdate(int clientIf, String address, int minInterval,
+                            int maxInterval, int slaveLatency, int supervisionTimeout,
+                            int minConnectionEventLen, int maxConnectionEventLen);
+
+    void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
+    void unregisterServer(in int serverIf);
+    void serverConnect(in int serverIf, in String address, in boolean isDirect, in int transport);
+    void serverDisconnect(in int serverIf, in String address);
+    void serverSetPreferredPhy(in int clientIf, in String address, in int txPhy, in int rxPhy, in int phyOptions);
+    void serverReadPhy(in int clientIf, in String address);
+    void addService(in int serverIf, in BluetoothGattService service);
+    void removeService(in int serverIf, in int handle);
+    void clearServices(in int serverIf);
+    void sendResponse(in int serverIf, in String address, in int requestId,
+                            in int status, in int offset, in byte[] value);
+    void sendNotification(in int serverIf, in String address, in int handle,
+                            in boolean confirm, in byte[] value);
+    void disconnectAll();
+    void unregAll();
+    int numHwTrackFiltersAvailable();
+}
diff --git a/binder/android/bluetooth/IBluetoothGattCallback.aidl b/binder/android/bluetooth/IBluetoothGattCallback.aidl
new file mode 100644
index 0000000..123a851
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothGattCallback.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 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.
+ */
+package android.bluetooth;
+
+import android.os.ParcelUuid;
+import android.bluetooth.BluetoothGattService;
+
+/**
+ * Callback definitions for interacting with BLE / GATT
+ * @hide
+ */
+oneway interface IBluetoothGattCallback {
+    void onClientRegistered(in int status, in int clientIf);
+    void onClientConnectionState(in int status, in int clientIf,
+                                 in boolean connected, in String address);
+    void onPhyUpdate(in String address, in int txPhy, in int rxPhy, in int status);
+    void onPhyRead(in String address, in int txPhy, in int rxPhy, in int status);
+    void onSearchComplete(in String address, in List<BluetoothGattService> services, in int status);
+    void onCharacteristicRead(in String address, in int status, in int handle, in byte[] value);
+    void onCharacteristicWrite(in String address, in int status, in int handle);
+    void onExecuteWrite(in String address, in int status);
+    void onDescriptorRead(in String address, in int status, in int handle, in byte[] value);
+    void onDescriptorWrite(in String address, in int status, in int handle);
+    void onNotify(in String address, in int handle, in byte[] value);
+    void onReadRemoteRssi(in String address, in int rssi, in int status);
+    void onConfigureMTU(in String address, in int mtu, in int status);
+    void onConnectionUpdated(in String address, in int interval, in int latency,
+                             in int timeout, in int status);
+}
diff --git a/binder/android/bluetooth/IBluetoothGattServerCallback.aidl b/binder/android/bluetooth/IBluetoothGattServerCallback.aidl
new file mode 100644
index 0000000..3f0ee20
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothGattServerCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 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.
+ */
+package android.bluetooth;
+
+import android.bluetooth.BluetoothGattService;
+
+/**
+ * Callback definitions for interacting with BLE / GATT
+ * @hide
+ */
+oneway interface IBluetoothGattServerCallback {
+    void onServerRegistered(in int status, in int serverIf);
+    void onServerConnectionState(in int status, in int serverIf,
+                                 in boolean connected, in String address);
+    void onServiceAdded(in int status, in BluetoothGattService service);
+    void onCharacteristicReadRequest(in String address, in int transId, in int offset,
+                                     in boolean isLong, in int handle);
+    void onDescriptorReadRequest(in String address, in int transId,
+                                     in int offset, in boolean isLong,
+                                     in int handle);
+    void onCharacteristicWriteRequest(in String address, in int transId, in int offset,
+                                     in int length, in boolean isPrep, in boolean needRsp,
+                                     in int handle, in byte[] value);
+    void onDescriptorWriteRequest(in String address, in int transId, in int offset,
+                                     in int length, in boolean isPrep, in boolean needRsp,
+                                     in int handle, in byte[] value);
+    void onExecuteWrite(in String address, in int transId, in boolean execWrite);
+    void onNotificationSent(in String address, in int status);
+    void onMtuChanged(in String address, in int mtu);
+    void onPhyUpdate(in String address, in int txPhy, in int rxPhy, in int status);
+    void onPhyRead(in String address, in int txPhy, in int rxPhy, in int status);
+    void onConnectionUpdated(in String address, in int interval, in int latency,
+                             in int timeout, in int status);
+}
diff --git a/binder/android/bluetooth/IBluetoothHeadset.aidl b/binder/android/bluetooth/IBluetoothHeadset.aidl
new file mode 100644
index 0000000..f8dfb65
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHeadset.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Headset service
+ *
+ * Note before adding anything new:
+ *   Internal interactions within com.android.bluetooth should be handled through
+ *   HeadsetService directly instead of going through binder
+ *
+ * {@hide}
+ */
+interface IBluetoothHeadset {
+    // Public API
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean startVoiceRecognition(in BluetoothDevice device);
+    boolean stopVoiceRecognition(in BluetoothDevice device);
+    boolean isAudioConnected(in BluetoothDevice device);
+    boolean sendVendorSpecificResultCode(in BluetoothDevice device,
+                                         in String command,
+                                         in String arg);
+
+    // Hidden API
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+    int getAudioState(in BluetoothDevice device);
+    boolean isAudioOn();
+    boolean connectAudio();
+    boolean disconnectAudio();
+    void setAudioRouteAllowed(boolean allowed);
+    boolean getAudioRouteAllowed();
+    void setForceScoAudio(boolean forced);
+    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);
+    boolean setActiveDevice(in BluetoothDevice device);
+    BluetoothDevice getActiveDevice();
+    boolean isInbandRingingEnabled();
+}
diff --git a/binder/android/bluetooth/IBluetoothHeadsetClient.aidl b/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
new file mode 100644
index 0000000..13495ae
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClientCall;
+import android.os.Bundle;
+
+/**
+ * API for Bluetooth Headset Client service (HFP HF Role)
+ *
+ * {@hide}
+ */
+interface IBluetoothHeadsetClient {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+
+    boolean startVoiceRecognition(in BluetoothDevice device);
+    boolean stopVoiceRecognition(in BluetoothDevice device);
+
+    List<BluetoothHeadsetClientCall> getCurrentCalls(in BluetoothDevice device);
+    Bundle getCurrentAgEvents(in BluetoothDevice device);
+
+    boolean acceptCall(in BluetoothDevice device, int flag);
+    boolean holdCall(in BluetoothDevice device);
+    boolean rejectCall(in BluetoothDevice device);
+    boolean terminateCall(in BluetoothDevice device, in BluetoothHeadsetClientCall call);
+
+    boolean enterPrivateMode(in BluetoothDevice device, int index);
+    boolean explicitCallTransfer(in BluetoothDevice device);
+
+    BluetoothHeadsetClientCall dial(in BluetoothDevice device, String number);
+
+    boolean sendDTMF(in BluetoothDevice device, byte code);
+    boolean getLastVoiceTagNumber(in BluetoothDevice device);
+
+    int getAudioState(in BluetoothDevice device);
+    boolean connectAudio(in BluetoothDevice device);
+    boolean disconnectAudio(in BluetoothDevice device);
+    void setAudioRouteAllowed(in BluetoothDevice device, boolean allowed);
+    boolean getAudioRouteAllowed(in BluetoothDevice device);
+
+    Bundle getCurrentAgFeatures(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothHeadsetPhone.aidl b/binder/android/bluetooth/IBluetoothHeadsetPhone.aidl
new file mode 100644
index 0000000..8309780
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHeadsetPhone.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 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.
+ */
+
+package android.bluetooth;
+
+/**
+ * API for Bluetooth Headset Phone Service in phone app
+ *
+ * {@hide}
+ */
+interface IBluetoothHeadsetPhone {
+  // Internal functions, not be made public
+  boolean answerCall();
+  boolean hangupCall();
+  boolean sendDtmf(int dtmf);
+  boolean processChld(int chld);
+  String getNetworkOperator();
+  String getSubscriberNumber();
+  boolean listCurrentCalls();
+  boolean queryPhoneState();
+
+  // Internal for phone app to call
+  void updateBtHandsfreeAfterRadioTechnologyChange();
+  void cdmaSwapSecondCallState();
+  void cdmaSetSecondCallState(boolean state);
+}
diff --git a/binder/android/bluetooth/IBluetoothHealth.aidl b/binder/android/bluetooth/IBluetoothHealth.aidl
new file mode 100644
index 0000000..a3be367
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHealth.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHealthAppConfiguration;
+import android.bluetooth.IBluetoothHealthCallback;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * API for Bluetooth Health service
+ *
+ * {@hide}
+ */
+interface IBluetoothHealth
+{
+    boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config,
+        in IBluetoothHealthCallback callback);
+    boolean unregisterAppConfiguration(in BluetoothHealthAppConfiguration config);
+    boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
+    boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
+        int channelType);
+    boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, int id);
+    ParcelFileDescriptor getMainChannelFd(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
+    List<BluetoothDevice> getConnectedHealthDevices();
+    List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
+    int getHealthDeviceConnectionState(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothHealthCallback.aidl b/binder/android/bluetooth/IBluetoothHealthCallback.aidl
new file mode 100644
index 0000000..ef7c191
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHealthCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011, 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHealthAppConfiguration;
+import android.os.ParcelFileDescriptor;
+
+/**
+ *@hide
+ */
+interface IBluetoothHealthCallback
+{
+    void onHealthAppConfigurationStatusChange(in BluetoothHealthAppConfiguration config, int status);
+    void onHealthChannelStateChange(in BluetoothHealthAppConfiguration config,
+        in BluetoothDevice device, int prevState, int newState, in
+        ParcelFileDescriptor fd, int id);
+}
diff --git a/binder/android/bluetooth/IBluetoothHearingAid.aidl b/binder/android/bluetooth/IBluetoothHearingAid.aidl
new file mode 100644
index 0000000..ad14192
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHearingAid.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth Hearing Aid service
+ *
+ * @hide
+ */
+interface IBluetoothHearingAid {
+    // Public API
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setActiveDevice(in BluetoothDevice device);
+    List<BluetoothDevice> getActiveDevices();
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+    void adjustVolume(int direction);
+    void setVolume(int volume);
+    int getVolume();
+
+    const int HI_SYNC_ID_INVALID = 0;
+    long getHiSyncId(in BluetoothDevice device);
+
+    const int SIDE_LEFT = 0;
+    const int SIDE_RIGHT = 1;
+    int getDeviceSide(in BluetoothDevice device);
+
+    const int MODE_MONAURAL = 0;
+    const int MODE_BINAURAL = 1;
+    int getDeviceMode(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothHidDevice.aidl b/binder/android/bluetooth/IBluetoothHidDevice.aidl
new file mode 100644
index 0000000..5246262
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHidDevice.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.IBluetoothHidDeviceCallback;
+import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
+import android.bluetooth.BluetoothHidDeviceAppQosSettings;
+
+/** @hide */
+interface IBluetoothHidDevice {
+    boolean registerApp(in BluetoothHidDeviceAppSdpSettings sdp,
+            in BluetoothHidDeviceAppQosSettings inQos, in BluetoothHidDeviceAppQosSettings outQos,
+            in IBluetoothHidDeviceCallback callback);
+    boolean unregisterApp();
+    boolean sendReport(in BluetoothDevice device, in int id, in byte[] data);
+    boolean replyReport(in BluetoothDevice device, in byte type, in byte id, in byte[] data);
+    boolean reportError(in BluetoothDevice device, byte error);
+    boolean unplug(in BluetoothDevice device);
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    String getUserAppName();
+}
diff --git a/binder/android/bluetooth/IBluetoothHidDeviceCallback.aidl b/binder/android/bluetooth/IBluetoothHidDeviceCallback.aidl
new file mode 100644
index 0000000..8205c67
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHidDeviceCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016, 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/** @hide */
+interface IBluetoothHidDeviceCallback {
+   void onAppStatusChanged(in BluetoothDevice device, boolean registered);
+   void onConnectionStateChanged(in BluetoothDevice device, in int state);
+   void onGetReport(in BluetoothDevice device, in byte type, in byte id, in int bufferSize);
+   void onSetReport(in BluetoothDevice device, in byte type, in byte id, in byte[] data);
+   void onSetProtocol(in BluetoothDevice device, in byte protocol);
+   void onInterruptData(in BluetoothDevice device, in byte reportId, in byte[] data);
+   void onVirtualCableUnplug(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothHidHost.aidl b/binder/android/bluetooth/IBluetoothHidHost.aidl
new file mode 100644
index 0000000..609da1b
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothHidHost.aidl
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth HID service
+ *
+ * {@hide}
+ */
+interface IBluetoothHidHost {
+    // Public API
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+    /**
+    * @hide
+    */
+    boolean getProtocolMode(in BluetoothDevice device);
+    /**
+    * @hide
+    */
+    boolean virtualUnplug(in BluetoothDevice device);
+    /**
+    * @hide
+    */
+    boolean setProtocolMode(in BluetoothDevice device, int protocolMode);
+    /**
+    * @hide
+    */
+    boolean getReport(in BluetoothDevice device, byte reportType, byte reportId, int bufferSize);
+    /**
+    * @hide
+    */
+    boolean setReport(in BluetoothDevice device, byte reportType, String report);
+    /**
+    * @hide
+    */
+    boolean sendData(in BluetoothDevice device, String report);
+    /**
+    * @hide
+    */
+    boolean getIdleTime(in BluetoothDevice device);
+    /**
+    * @hide
+    */
+    boolean setIdleTime(in BluetoothDevice device, byte idleTime);
+}
diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl
new file mode 100644
index 0000000..a3ec1d8
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothManager.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothGatt;
+import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothProfileServiceConnection;
+import android.bluetooth.IBluetoothStateChangeCallback;
+
+/**
+ * System private API for talking with the Bluetooth service.
+ *
+ * {@hide}
+ */
+interface IBluetoothManager
+{
+    IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
+    void unregisterAdapter(in IBluetoothManagerCallback callback);
+    void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
+    void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
+    boolean isEnabled();
+    boolean enable(String packageName);
+    boolean enableNoAutoConnect(String packageName);
+    boolean disable(String packageName, boolean persist);
+    int getState();
+    IBluetoothGatt getBluetoothGatt();
+
+    boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
+    void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
+
+    String getAddress();
+    String getName();
+
+    boolean isBleScanAlwaysAvailable();
+    int updateBleAppCount(IBinder b, boolean enable, String packageName);
+    boolean isBleAppPresent();
+}
+
diff --git a/binder/android/bluetooth/IBluetoothManagerCallback.aidl b/binder/android/bluetooth/IBluetoothManagerCallback.aidl
new file mode 100644
index 0000000..27ad2a0
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothManagerCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetooth;
+
+/**
+ * API for Communication between BluetoothAdapter and BluetoothManager
+ *
+ * {@hide}
+ */
+oneway interface IBluetoothManagerCallback {
+    void onBluetoothServiceUp(in IBluetooth bluetoothService);
+    void onBluetoothServiceDown();
+    void onBrEdrDown();
+}
diff --git a/binder/android/bluetooth/IBluetoothMap.aidl b/binder/android/bluetooth/IBluetoothMap.aidl
new file mode 100644
index 0000000..562490e
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothMap.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth MAP service
+ *
+ * {@hide}
+ */
+interface IBluetoothMap {
+    int getState();
+    BluetoothDevice getClient();
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    boolean isConnected(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothMapClient.aidl b/binder/android/bluetooth/IBluetoothMapClient.aidl
new file mode 100644
index 0000000..7ac91e9
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothMapClient.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothDevice;
+import android.net.Uri;
+
+/**
+ * System private API for Bluetooth MAP MCE service
+ *
+ * {@hide}
+ */
+interface IBluetoothMapClient {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    boolean isConnected(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device,in int priority);
+    int getPriority(in BluetoothDevice device);
+    boolean sendMessage(in BluetoothDevice device, in Uri[] contacts, in  String message,
+        in PendingIntent sentIntent, in PendingIntent deliveryIntent);
+    boolean getUnreadMessages(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothPan.aidl b/binder/android/bluetooth/IBluetoothPan.aidl
new file mode 100644
index 0000000..16b6ddf
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothPan.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Pan service
+ *
+ * {@hide}
+ */
+interface IBluetoothPan {
+    // Public API
+    boolean isTetheringOn();
+    void setBluetoothTethering(boolean value);
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothPbap.aidl b/binder/android/bluetooth/IBluetoothPbap.aidl
new file mode 100644
index 0000000..52caf77
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothPbap.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2008 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth pbap service
+ *
+ * {@hide}
+ */
+interface IBluetoothPbap {
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    void disconnect(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothPbapClient.aidl b/binder/android/bluetooth/IBluetoothPbapClient.aidl
new file mode 100644
index 0000000..52f9845
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothPbapClient.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Phone Book Access Provile Client Side
+ *
+ * {@hide}
+ */
+interface IBluetoothPbapClient {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/binder/android/bluetooth/IBluetoothProfileServiceConnection.aidl
new file mode 100644
index 0000000..e5c3de9
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothProfileServiceConnection.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+
+/**
+ * Callback for bluetooth profile connections.
+ *
+ * {@hide}
+ */
+oneway interface IBluetoothProfileServiceConnection {
+    void onServiceConnected(in ComponentName comp, in IBinder service);
+    void onServiceDisconnected(in ComponentName comp);
+}
diff --git a/binder/android/bluetooth/IBluetoothSap.aidl b/binder/android/bluetooth/IBluetoothSap.aidl
new file mode 100644
index 0000000..0ea7afb
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothSap.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2013 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth SAP service
+ *
+ * {@hide}
+ */
+interface IBluetoothSap {
+    int getState();
+    BluetoothDevice getClient();
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    boolean isConnected(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothSocketManager.aidl b/binder/android/bluetooth/IBluetoothSocketManager.aidl
new file mode 100644
index 0000000..119988e
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothSocketManager.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017, 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.os.ParcelUuid;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * API for Bluetooth Sockets service.
+ *
+ * {@hide}
+ */
+interface IBluetoothSocketManager
+{
+    @nullable ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in @nullable ParcelUuid uuid, int port, int flag);
+    @nullable ParcelFileDescriptor createSocketChannel(int type, in @nullable String serviceName, in @nullable ParcelUuid uuid, int port, int flag);
+    void requestMaximumTxDataLength(in BluetoothDevice device);
+}
diff --git a/binder/android/bluetooth/IBluetoothStateChangeCallback.aidl b/binder/android/bluetooth/IBluetoothStateChangeCallback.aidl
new file mode 100644
index 0000000..1716801
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothStateChangeCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011, 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.
+ */
+
+package android.bluetooth;
+
+/**
+ * System private API for Bluetooth state change callback.
+ *
+ * {@hide}
+ */
+oneway interface IBluetoothStateChangeCallback
+{
+    void onBluetoothStateChange(boolean on);
+}
diff --git a/binder/android/bluetooth/OobData.aidl b/binder/android/bluetooth/OobData.aidl
new file mode 100644
index 0000000..529e0b0
--- /dev/null
+++ b/binder/android/bluetooth/OobData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package android.bluetooth;
+
+parcelable OobData;
diff --git a/binder/android/bluetooth/bluetooth_device.cc b/binder/android/bluetooth/bluetooth_device.cc
new file mode 100644
index 0000000..e291ba2
--- /dev/null
+++ b/binder/android/bluetooth/bluetooth_device.cc
@@ -0,0 +1,46 @@
+//
+//  Copyright 2017, 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 "android/bluetooth/bluetooth_device.h"
+
+#include <utils/String16.h>
+
+using android::OK;
+using android::Parcel;
+using android::status_t;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothDevice::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeString16(String16(address.ToString().c_str()));
+  return status;
+}
+
+status_t BluetoothDevice::readFromParcel(const Parcel* parcel) {
+  String16 tmp;
+
+  status_t status = parcel->readString16(&tmp);
+  if (status != OK) return status;
+
+  RawAddress::FromString(String8(tmp).string(), address);
+  return OK;
+}
+
+}  // namespace bluetooth
+}  // namespace android
\ No newline at end of file
diff --git a/binder/android/bluetooth/bluetooth_device.h b/binder/android/bluetooth/bluetooth_device.h
new file mode 100644
index 0000000..01bc00a
--- /dev/null
+++ b/binder/android/bluetooth/bluetooth_device.h
@@ -0,0 +1,50 @@
+//
+//  Copyright 2017, 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include <raw_address.h>
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothDevice : public android::Parcelable {
+ public:
+  BluetoothDevice() = default;
+  ~BluetoothDevice() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  android::status_t writeToParcel(android::Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  android::status_t readFromParcel(const android::Parcel* parcel) override;
+
+  RawAddress address;
+};
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/binder/android/bluetooth/le/AdvertiseData.aidl b/binder/android/bluetooth/le/AdvertiseData.aidl
new file mode 100644
index 0000000..713635d
--- /dev/null
+++ b/binder/android/bluetooth/le/AdvertiseData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable AdvertiseData;
diff --git a/binder/android/bluetooth/le/AdvertiseSettings.aidl b/binder/android/bluetooth/le/AdvertiseSettings.aidl
new file mode 100644
index 0000000..3677e75
--- /dev/null
+++ b/binder/android/bluetooth/le/AdvertiseSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable AdvertiseSettings;
\ No newline at end of file
diff --git a/binder/android/bluetooth/le/AdvertisingSetParameters.aidl b/binder/android/bluetooth/le/AdvertisingSetParameters.aidl
new file mode 100644
index 0000000..3918864
--- /dev/null
+++ b/binder/android/bluetooth/le/AdvertisingSetParameters.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable AdvertisingSetParameters;
diff --git a/binder/android/bluetooth/le/IAdvertisingSetCallback.aidl b/binder/android/bluetooth/le/IAdvertisingSetCallback.aidl
new file mode 100644
index 0000000..2e3241c
--- /dev/null
+++ b/binder/android/bluetooth/le/IAdvertisingSetCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 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.
+ */
+package android.bluetooth.le;
+
+/**
+ * Callback definitions for interacting with Advertiser
+ * @hide
+ */
+oneway interface IAdvertisingSetCallback {
+  void onAdvertisingSetStarted(in int advertiserId, in int tx_power, in int status);
+  void onOwnAddressRead(in int advertiserId, in int addressType, in String address);
+  void onAdvertisingSetStopped(in int advertiserId);
+  void onAdvertisingEnabled(in int advertiserId, in boolean enable, in int status);
+  void onAdvertisingDataSet(in int advertiserId, in int status);
+  void onScanResponseDataSet(in int advertiserId, in int status);
+  void onAdvertisingParametersUpdated(in int advertiserId, in int tx_power, in int status);
+  void onPeriodicAdvertisingParametersUpdated(in int advertiserId, in int status);
+  void onPeriodicAdvertisingDataSet(in int advertiserId, in int status);
+  void onPeriodicAdvertisingEnabled(in int advertiserId, in boolean enable, in int status);
+}
diff --git a/binder/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl b/binder/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl
new file mode 100644
index 0000000..84bbc14
--- /dev/null
+++ b/binder/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 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.
+ */
+package android.bluetooth.le;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.PeriodicAdvertisingReport;
+
+/**
+ * Callback definitions for interacting with Periodic Advertising
+ * @hide
+ */
+oneway interface IPeriodicAdvertisingCallback {
+
+  void onSyncEstablished(in int syncHandle, in BluetoothDevice device, in int advertisingSid,
+                         in int skip, in int timeout, in int status);
+  void onPeriodicAdvertisingReport(in PeriodicAdvertisingReport report);
+  void onSyncLost(in int syncHandle);
+}
diff --git a/binder/android/bluetooth/le/IScannerCallback.aidl b/binder/android/bluetooth/le/IScannerCallback.aidl
new file mode 100644
index 0000000..025e7ff
--- /dev/null
+++ b/binder/android/bluetooth/le/IScannerCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 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.
+ */
+package android.bluetooth.le;
+
+import android.bluetooth.le.ScanResult;
+
+/**
+ * Callback definitions for interacting with Advertiser
+ * @hide
+ */
+oneway interface IScannerCallback {
+    void onScannerRegistered(in int status, in int scannerId);
+
+    void onScanResult(in ScanResult scanResult);
+    void onBatchScanResults(in List<ScanResult> batchResults);
+    void onFoundOrLost(in boolean onFound, in ScanResult scanResult);
+    void onScanManagerErrorCallback(in int errorCode);
+}
diff --git a/binder/android/bluetooth/le/PeriodicAdvertisingParameters.aidl b/binder/android/bluetooth/le/PeriodicAdvertisingParameters.aidl
new file mode 100644
index 0000000..3f714f0
--- /dev/null
+++ b/binder/android/bluetooth/le/PeriodicAdvertisingParameters.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable PeriodicAdvertisingParameters;
diff --git a/binder/android/bluetooth/le/PeriodicAdvertisingReport.aidl b/binder/android/bluetooth/le/PeriodicAdvertisingReport.aidl
new file mode 100644
index 0000000..986ac61
--- /dev/null
+++ b/binder/android/bluetooth/le/PeriodicAdvertisingReport.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable PeriodicAdvertisingReport;
diff --git a/binder/android/bluetooth/le/ResultStorageDescriptor.aidl b/binder/android/bluetooth/le/ResultStorageDescriptor.aidl
new file mode 100644
index 0000000..afc1b41
--- /dev/null
+++ b/binder/android/bluetooth/le/ResultStorageDescriptor.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth.le;
+
+/**
+ * {@hide}
+ */
+
+parcelable ResultStorageDescriptor;
diff --git a/binder/android/bluetooth/le/ScanFilter.aidl b/binder/android/bluetooth/le/ScanFilter.aidl
new file mode 100644
index 0000000..e3ebd85
--- /dev/null
+++ b/binder/android/bluetooth/le/ScanFilter.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable ScanFilter;
diff --git a/binder/android/bluetooth/le/ScanResult.aidl b/binder/android/bluetooth/le/ScanResult.aidl
new file mode 100644
index 0000000..f16dc18
--- /dev/null
+++ b/binder/android/bluetooth/le/ScanResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable ScanResult;
\ No newline at end of file
diff --git a/binder/android/bluetooth/le/ScanSettings.aidl b/binder/android/bluetooth/le/ScanSettings.aidl
new file mode 100644
index 0000000..e84e078
--- /dev/null
+++ b/binder/android/bluetooth/le/ScanSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 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.
+ */
+
+package android.bluetooth.le;
+
+parcelable ScanSettings;
diff --git a/binder/android/os/parcel_file_descriptor.cc b/binder/android/os/parcel_file_descriptor.cc
new file mode 100644
index 0000000..37bef6d
--- /dev/null
+++ b/binder/android/os/parcel_file_descriptor.cc
@@ -0,0 +1,43 @@
+//
+//  Copyright 2017, 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 "android/os/parcel_file_descriptor.h"
+#include <base/logging.h>
+
+using android::OK;
+using android::Parcel;
+using android::status_t;
+
+namespace android {
+namespace os {
+
+status_t ParcelFileDescriptor::writeToParcel(Parcel* parcel) const {
+  CHECK(fd_ >= 0);
+  return parcel->writeParcelFileDescriptor(fd_, takeOwnership_);
+}
+
+status_t ParcelFileDescriptor::readFromParcel(const Parcel* parcel) {
+  LOG(FATAL) << "Don't know how to read ParcelFileDescriptor";
+  return OK;
+}
+
+void ParcelFileDescriptor::setFileDescriptor(int fd, bool takeOwnership) {
+  fd_ = fd;
+  takeOwnership_ = takeOwnership;
+}
+
+}  // namespace os
+}  // namespace android
diff --git a/binder/android/os/parcel_file_descriptor.h b/binder/android/os/parcel_file_descriptor.h
new file mode 100644
index 0000000..a37b49c
--- /dev/null
+++ b/binder/android/os/parcel_file_descriptor.h
@@ -0,0 +1,52 @@
+//
+//  Copyright 2017, 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+class ParcelFileDescriptor : public android::Parcelable {
+ public:
+  ParcelFileDescriptor() : fd_(-1), takeOwnership_(false) {}
+  ~ParcelFileDescriptor() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  android::status_t writeToParcel(android::Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  android::status_t readFromParcel(const android::Parcel* parcel) override;
+
+  void setFileDescriptor(int fd, bool takeOwnership);
+
+ private:
+  int fd_;
+  bool takeOwnership_;
+};
+
+}  // namespace os
+}  // namespace android
diff --git a/binder/android/os/parcel_uuid.cc b/binder/android/os/parcel_uuid.cc
new file mode 100644
index 0000000..ea97104
--- /dev/null
+++ b/binder/android/os/parcel_uuid.cc
@@ -0,0 +1,81 @@
+//
+//  Copyright 2017, 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 "android/os/parcel_uuid.h"
+
+using android::OK;
+using android::Parcel;
+using android::status_t;
+using ::bluetooth::Uuid;
+
+namespace android {
+namespace os {
+
+namespace {
+static uint64_t uuid_lsb(const Uuid& uuid) {
+  uint64_t lsb = 0;
+
+  auto uu = uuid.To128BitBE();
+  for (int i = 8; i <= 15; i++) {
+    lsb <<= 8;
+    lsb |= uu[i];
+  }
+
+  return lsb;
+}
+
+static uint64_t uuid_msb(const Uuid& uuid) {
+  uint64_t msb = 0;
+
+  auto uu = uuid.To128BitBE();
+  for (int i = 0; i <= 7; i++) {
+    msb <<= 8;
+    msb |= uu[i];
+  }
+
+  return msb;
+}
+}  // namespace
+
+status_t ParcelUuid::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeInt64(uuid_msb(uuid));
+  if (status != OK) return status;
+
+  status = parcel->writeInt64(uuid_lsb(uuid));
+  return status;
+}
+
+status_t ParcelUuid::readFromParcel(const Parcel* parcel) {
+  int64_t uuid_msb, uuid_lsb;
+
+  status_t status = parcel->readInt64(&uuid_msb);
+  if (status != OK) return status;
+
+  status = parcel->readInt64(&uuid_lsb);
+  if (status != OK) return status;
+
+  std::array<uint8_t, Uuid::kNumBytes128> uu;
+  for (int i = 0; i < 8; i++) {
+    uu[7 - i] = (uuid_msb >> (8 * i)) & 0xFF;
+    uu[15 - i] = (uuid_lsb >> (8 * i)) & 0xFF;
+  }
+
+  uuid = Uuid::From128BitBE(uu);
+  return OK;
+}
+
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/binder/android/os/parcel_uuid.h b/binder/android/os/parcel_uuid.h
new file mode 100644
index 0000000..76bf9c4
--- /dev/null
+++ b/binder/android/os/parcel_uuid.h
@@ -0,0 +1,49 @@
+//
+//  Copyright 2017, 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <bluetooth/uuid.h>
+
+namespace android {
+namespace os {
+
+class ParcelUuid : public android::Parcelable {
+ public:
+  ParcelUuid() = default;
+  ~ParcelUuid() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  android::status_t writeToParcel(android::Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  android::status_t readFromParcel(const android::Parcel* parcel) override;
+
+  ::bluetooth::Uuid uuid;
+};
+
+}  // namespace os
+}  // namespace android
diff --git a/bta/Android.bp b/bta/Android.bp
index a69e174..d6919de 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -12,8 +12,10 @@
         "system/bt",
         "system/bt/bta/include",
         "system/bt/btcore/include",
+        "system/bt/btif/avrcp",
+        "system/bt/btif/include",
         "system/bt/hci/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/stack/include",
         "system/bt/stack/btm",
         "system/bt/udrv/include",
@@ -23,6 +25,7 @@
     shared_libs: [
         "libcutils",
     ],
+    header_libs: ["libbluetooth_headers"],
     cflags: ["-DBUILDCFG"],
 }
 
@@ -36,7 +39,6 @@
         "ag/bta_ag_api.cc",
         "ag/bta_ag_at.cc",
         "ag/bta_ag_cfg.cc",
-        "ag/bta_ag_ci.cc",
         "ag/bta_ag_cmd.cc",
         "ag/bta_ag_main.cc",
         "ag/bta_ag_rfc.cc",
@@ -56,16 +58,18 @@
         "dm/bta_dm_ci.cc",
         "dm/bta_dm_main.cc",
         "dm/bta_dm_pm.cc",
-        "dm/bta_dm_sco.cc",
         "gatt/bta_gattc_act.cc",
         "gatt/bta_gattc_api.cc",
         "gatt/bta_gattc_cache.cc",
         "gatt/bta_gattc_main.cc",
+        "gatt/bta_gattc_queue.cc",
         "gatt/bta_gattc_utils.cc",
         "gatt/bta_gatts_act.cc",
         "gatt/bta_gatts_api.cc",
         "gatt/bta_gatts_main.cc",
         "gatt/bta_gatts_utils.cc",
+        "hearing_aid/hearing_aid.cc",
+        "hearing_aid/hearing_aid_audio_source.cc",
         "hf_client/bta_hf_client_act.cc",
         "hf_client/bta_hf_client_api.cc",
         "hf_client/bta_hf_client_at.cc",
@@ -91,7 +95,6 @@
         "jv/bta_jv_act.cc",
         "jv/bta_jv_api.cc",
         "jv/bta_jv_cfg.cc",
-        "jv/bta_jv_main.cc",
         "mce/bta_mce_act.cc",
         "mce/bta_mce_api.cc",
         "mce/bta_mce_cfg.cc",
@@ -108,6 +111,13 @@
         "sys/bta_sys_main.cc",
         "sys/utl.cc",
     ],
+    static_libs: [
+        "avrcp-target-service",
+        "lib-bt-packets",
+    ],
+    whole_static_libs: [
+        "libaudio-hearing-aid-hw-utils",
+    ],
 }
 
 // bta unit tests for target
@@ -117,9 +127,9 @@
     defaults: ["fluoride_bta_defaults"],
     srcs: [
         "test/bta_hf_client_test.cc",
+        "test/gatt_cache_file_test.cc",
     ],
     shared_libs: [
-        "libhardware",
         "liblog",
         "libprotobuf-cpp-lite",
     ],
@@ -127,7 +137,7 @@
         "libbtcore",
         "libbt-bta",
         "libbluetooth-types",
+        "libbt-protos-lite",
         "libosi",
-        "libbt-protos",
     ],
 }
diff --git a/bta/BUILD.gn b/bta/BUILD.gn
index 07779d0..fa85e40 100644
--- a/bta/BUILD.gn
+++ b/bta/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -40,12 +40,12 @@
     "dm/bta_dm_ci.cc",
     "dm/bta_dm_main.cc",
     "dm/bta_dm_pm.cc",
-    "dm/bta_dm_sco.cc",
     "gatt/bta_gattc_act.cc",
     "gatt/bta_gattc_api.cc",
     "gatt/bta_gattc_cache.cc",
     "gatt/bta_gattc_main.cc",
     "gatt/bta_gattc_utils.cc",
+    "gatt/bta_gattc_queue.cc",
     "gatt/bta_gatts_act.cc",
     "gatt/bta_gatts_api.cc",
     "gatt/bta_gatts_main.cc",
@@ -75,7 +75,6 @@
     "jv/bta_jv_act.cc",
     "jv/bta_jv_api.cc",
     "jv/bta_jv_cfg.cc",
-    "jv/bta_jv_main.cc",
     "mce/bta_mce_act.cc",
     "mce/bta_mce_api.cc",
     "mce/bta_mce_cfg.cc",
@@ -103,7 +102,7 @@
     "//",
     "//btcore/include",
     "//hci/include",
-    "//include",
+    "//internal_include",
     "//stack/include",
     "//stack/btm",
     "//udrv/include",
diff --git a/bta/ag/bta_ag_act.cc b/bta/ag/bta_ag_act.cc
index ad40c5d..84860f9 100644
--- a/bta/ag/bta_ag_act.cc
+++ b/bta/ag/bta_ag_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,14 +22,14 @@
  *
  ******************************************************************************/
 
-#include <string.h>
+#include <cstring>
 
 #include "bta_ag_api.h"
-#include "bta_ag_co.h"
 #include "bta_ag_int.h"
 #include "bta_api.h"
 #include "bta_dm_api.h"
 #include "bta_sys.h"
+#include "btif_config.h"
 #include "l2c_api.h"
 #include "osi/include/osi.h"
 #include "port_api.h"
@@ -74,22 +74,16 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_ag_cback_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data,
+static void bta_ag_cback_open(tBTA_AG_SCB* p_scb, const RawAddress& bd_addr,
                               tBTA_AG_STATUS status) {
-  tBTA_AG_OPEN open;
+  tBTA_AG_OPEN open = {};
 
   /* call app callback with open event */
   open.hdr.handle = bta_ag_scb_to_idx(p_scb);
   open.hdr.app_id = p_scb->app_id;
   open.status = status;
   open.service_id = bta_ag_svc_id[p_scb->conn_service];
-  if (p_data) {
-    /* if p_data is provided then we need to pick the bd address from the open
-     * api structure */
-    open.bd_addr = p_data->api_open.bd_addr;
-  } else {
-    open.bd_addr = p_scb->peer_addr;
-  }
+  open.bd_addr = bd_addr;
 
   (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG*)&open);
 }
@@ -105,22 +99,21 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_register(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
-  tBTA_AG_REGISTER reg;
-
+void bta_ag_register(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* initialize control block */
-  p_scb->reg_services = p_data->api_register.services;
-  p_scb->serv_sec_mask = p_data->api_register.sec_mask;
-  p_scb->features = p_data->api_register.features;
-  p_scb->app_id = p_data->api_register.app_id;
+  p_scb->reg_services = data.api_register.services;
+  p_scb->serv_sec_mask = data.api_register.sec_mask;
+  p_scb->features = data.api_register.features;
+  p_scb->app_id = data.api_register.app_id;
 
   /* create SDP records */
-  bta_ag_create_records(p_scb, p_data);
+  bta_ag_create_records(p_scb, data);
 
   /* start RFCOMM servers */
   bta_ag_start_servers(p_scb, p_scb->reg_services);
 
   /* call app callback with register event */
+  tBTA_AG_REGISTER reg = {};
   reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
   reg.hdr.app_id = p_scb->app_id;
   reg.status = BTA_AG_SUCCESS;
@@ -138,12 +131,12 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_deregister(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_deregister(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* set dealloc */
   p_scb->dealloc = true;
 
   /* remove sdp records */
-  bta_ag_del_records(p_scb, p_data);
+  bta_ag_del_records(p_scb);
 
   /* remove rfcomm servers */
   bta_ag_close_servers(p_scb, p_scb->reg_services);
@@ -162,12 +155,12 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* set dealloc */
   p_scb->dealloc = true;
 
   /* remove sdp records */
-  bta_ag_del_records(p_scb, p_data);
+  bta_ag_del_records(p_scb);
 }
 
 /*******************************************************************************
@@ -180,22 +173,20 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_start_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
-  RawAddress pending_bd_addr;
+void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
+  RawAddress pending_bd_addr = {};
 
   /* store parameters */
-  if (p_data) {
-    p_scb->peer_addr = p_data->api_open.bd_addr;
-    p_scb->open_services = p_data->api_open.services;
-    p_scb->cli_sec_mask = p_data->api_open.sec_mask;
-  }
+  p_scb->peer_addr = data.api_open.bd_addr;
+  p_scb->cli_sec_mask = data.api_open.sec_mask;
+  p_scb->open_services = p_scb->reg_services;
 
   /* Check if RFCOMM has any incoming connection to avoid collision. */
   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. */
-    bta_ag_collision_cback(0, BTA_ID_AG, 0, &p_scb->peer_addr);
+    bta_ag_collision_cback(0, BTA_ID_AG, 0, p_scb->peer_addr);
     return;
   }
 
@@ -219,15 +210,14 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   uint16_t event = BTA_AG_DISC_FAIL_EVT;
 
-  APPL_TRACE_DEBUG("bta_ag_disc_int_res: Status: %d",
-                   p_data->disc_result.status);
+  APPL_TRACE_DEBUG("bta_ag_disc_int_res: Status: %d", data.disc_result.status);
 
   /* if found service */
-  if (p_data->disc_result.status == SDP_SUCCESS ||
-      p_data->disc_result.status == SDP_DB_FULL) {
+  if (data.disc_result.status == SDP_SUCCESS ||
+      data.disc_result.status == SDP_DB_FULL) {
     /* get attributes */
     if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services)) {
       /* set connected service */
@@ -239,13 +229,13 @@
   }
 
   /* free discovery db */
-  bta_ag_free_db(p_scb, p_data);
+  bta_ag_free_db(p_scb, data);
 
   /* if service not found check if we should search for other service */
   if ((event == BTA_AG_DISC_FAIL_EVT) &&
-      (p_data->disc_result.status == SDP_SUCCESS ||
-       p_data->disc_result.status == SDP_DB_FULL ||
-       p_data->disc_result.status == SDP_NO_RECS_MATCH)) {
+      (data.disc_result.status == SDP_SUCCESS ||
+       data.disc_result.status == SDP_DB_FULL ||
+       data.disc_result.status == SDP_NO_RECS_MATCH)) {
     if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
         (p_scb->open_services & BTA_HSP_SERVICE_MASK)) {
       /* search for HSP */
@@ -258,11 +248,11 @@
       bta_ag_do_disc(p_scb, p_scb->open_services);
     } else {
       /* send ourselves sdp ok/fail event */
-      bta_ag_sm_execute(p_scb, event, p_data);
+      bta_ag_sm_execute(p_scb, event, data);
     }
   } else {
     /* send ourselves sdp ok/fail event */
-    bta_ag_sm_execute(p_scb, event, p_data);
+    bta_ag_sm_execute(p_scb, event, data);
   }
 }
 
@@ -276,16 +266,16 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* if found service */
-  if (p_data->disc_result.status == SDP_SUCCESS ||
-      p_data->disc_result.status == SDP_DB_FULL) {
+  if (data.disc_result.status == SDP_SUCCESS ||
+      data.disc_result.status == SDP_DB_FULL) {
     /* get attributes */
     bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
   }
 
   /* free discovery db */
-  bta_ag_free_db(p_scb, p_data);
+  bta_ag_free_db(p_scb, data);
 }
 
 /*******************************************************************************
@@ -298,17 +288,19 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_disc_fail(tBTA_AG_SCB* p_scb,
+                      UNUSED_ATTR const tBTA_AG_DATA& data) {
   /* reopen registered servers */
   bta_ag_start_servers(p_scb, p_scb->reg_services);
 
   /* reinitialize stuff */
 
   /* clear the remote BD address */
+  RawAddress peer_addr = p_scb->peer_addr;
   p_scb->peer_addr = RawAddress::kEmpty;
 
   /* call open cback w. failure */
-  bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+  bta_ag_cback_open(p_scb, peer_addr, BTA_AG_FAIL_SDP);
 }
 
 /*******************************************************************************
@@ -321,9 +313,9 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_open_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_open_fail(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* call open cback w. failure */
-  bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+  bta_ag_cback_open(p_scb, data.api_open.bd_addr, BTA_AG_FAIL_RESOURCES);
 }
 
 /*******************************************************************************
@@ -336,7 +328,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+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;
@@ -353,7 +346,7 @@
   bta_ag_start_servers(p_scb, p_scb->reg_services);
 
   /* call open cback w. failure */
-  bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+  bta_ag_cback_open(p_scb, peer_addr, BTA_AG_FAIL_RFCOMM);
 }
 
 /*******************************************************************************
@@ -366,8 +359,9 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
-  tBTA_AG_CLOSE close;
+void bta_ag_rfc_close(tBTA_AG_SCB* p_scb,
+                      UNUSED_ATTR const tBTA_AG_DATA& data) {
+  tBTA_AG_CLOSE close = {};
   tBTA_SERVICE_MASK services;
   int i, num_active_conn = 0;
 
@@ -386,8 +380,12 @@
   p_scb->hsp_version = HSP_VERSION_1_2;
   bta_ag_at_reinit(&p_scb->at_cb);
 
-  memset(&(p_scb->peer_hf_indicators), 0, sizeof(p_scb->peer_hf_indicators));
-  memset(&(p_scb->local_hf_indicators), 0, sizeof(p_scb->local_hf_indicators));
+  for (auto& peer_hf_indicator : p_scb->peer_hf_indicators) {
+    peer_hf_indicator = {};
+  }
+  for (auto& local_hf_indicator : p_scb->local_hf_indicators) {
+    local_hf_indicator = {};
+  }
 
   /* stop timers */
   alarm_cancel(p_scb->ring_timer);
@@ -399,14 +397,15 @@
 
   bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
-  /* call close call-out */
-  bta_ag_co_data_close(close.hdr.handle);
+  if (bta_ag_get_active_device() == p_scb->peer_addr) {
+    bta_clear_active_device();
+  }
 
   /* call close cback */
   (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG*)&close);
 
   /* if not deregistering (deallocating) reopen registered servers */
-  if (p_scb->dealloc == false) {
+  if (!p_scb->dealloc) {
     /* Clear peer bd_addr so instance can be reused */
     p_scb->peer_addr = RawAddress::kEmpty;
 
@@ -421,10 +420,10 @@
     p_scb->conn_handle = 0;
 
     /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
-    bta_ag_sco_shutdown(p_scb, NULL);
+    bta_ag_sco_shutdown(p_scb, tBTA_AG_DATA::kEmpty);
 
     /* Check if all the SLCs are down */
-    for (i = 0; i < BTA_AG_NUM_SCB; i++) {
+    for (i = 0; i < BTA_AG_MAX_NUM_CLIENTS; i++) {
       if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn)
         num_active_conn++;
     }
@@ -451,7 +450,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* initialize AT feature variables */
   p_scb->clip_enabled = false;
   p_scb->ccwa_enabled = false;
@@ -459,23 +458,42 @@
   p_scb->cmee_enabled = false;
   p_scb->inband_enabled =
       ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+  if (p_scb->conn_service == BTA_AG_HFP) {
+    size_t version_value_size = sizeof(p_scb->peer_version);
+    if (!btif_config_get_bin(
+            p_scb->peer_addr.ToString(), HFP_VERSION_CONFIG_KEY,
+            (uint8_t*)&p_scb->peer_version, &version_value_size)) {
+      APPL_TRACE_WARNING("%s: Failed read cached peer HFP version for %s",
+                         __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 */
-  p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD*)bta_ag_at_tbl[p_scb->conn_service];
-  p_scb->at_cb.p_cmd_cback =
-      (tBTA_AG_AT_CMD_CBACK*)bta_ag_at_cback_tbl[p_scb->conn_service];
-  p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK*)bta_ag_at_err_cback;
+  p_scb->at_cb.p_at_tbl = bta_ag_at_tbl[p_scb->conn_service];
+  p_scb->at_cb.p_cmd_cback = bta_ag_at_cback_tbl[p_scb->conn_service];
+  p_scb->at_cb.p_err_cback = bta_ag_at_err_cback;
   p_scb->at_cb.p_user = p_scb;
   p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
   bta_ag_at_init(&p_scb->at_cb);
 
-  /* call app open call-out */
-  bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb),
-                      bta_ag_svc_id[p_scb->conn_service]);
-
   bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
-  bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+  bta_ag_cback_open(p_scb, p_scb->peer_addr, BTA_AG_SUCCESS);
 
   if (p_scb->conn_service == BTA_AG_HFP) {
     /* if hfp start timer for service level conn */
@@ -483,7 +501,7 @@
                         BTA_AG_SVC_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
   } else {
     /* else service level conn is open */
-    bta_ag_svc_conn_open(p_scb, p_data);
+    bta_ag_svc_conn_open(p_scb, data);
   }
 }
 
@@ -497,13 +515,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
-  uint16_t lcid;
-  int i;
-  tBTA_AG_SCB *ag_scb, *other_scb;
-  RawAddress dev_addr;
-  int status;
-
+void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* set role */
   p_scb->role = BTA_AG_ACP;
 
@@ -511,49 +523,59 @@
                    p_scb->serv_handle[0], p_scb->serv_handle[1]);
 
   /* get bd addr of peer */
-  if (PORT_SUCCESS != (status = PORT_CheckConnection(p_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_NUM_SCB; 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)) {
+      VLOG(1) << __func__ << ": cancel collision alarm for "
+              << ag_scb.peer_addr;
+      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);
+      }
+    }
+    if (dev_addr == ag_scb.peer_addr && p_scb != &ag_scb) {
+      VLOG(1) << __func__ << ": fail outgoing connection before accepting "
+              << ag_scb.peer_addr;
+      // 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;
     }
+    VLOG(1) << __func__ << ": dev_addr=" << dev_addr
+            << ", peer_addr=" << ag_scb.peer_addr
+            << ", in_use=" << ag_scb.in_use
+            << ", index=" << bta_ag_scb_to_idx(p_scb);
   }
 
   p_scb->peer_addr = dev_addr;
 
   /* determine connected service from port handle */
-  for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+  for (int 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], p_data->rfc.port_handle);
+        p_scb->serv_handle[i], data.rfc.port_handle);
 
-    if (p_scb->serv_handle[i] == p_data->rfc.port_handle) {
+    if (p_scb->serv_handle[i] == data.rfc.port_handle) {
       p_scb->conn_service = i;
-      p_scb->conn_handle = p_data->rfc.port_handle;
+      p_scb->conn_handle = data.rfc.port_handle;
       break;
     }
   }
@@ -569,7 +591,7 @@
   bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
 
   /* continue with common open processing */
-  bta_ag_rfc_open(p_scb, p_data);
+  bta_ag_rfc_open(p_scb, data);
 }
 
 /*******************************************************************************
@@ -582,11 +604,9 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) {
   uint16_t len;
-  char buf[BTA_AG_RFC_READ_MAX];
-
-  memset(buf, 0, BTA_AG_RFC_READ_MAX);
+  char buf[BTA_AG_RFC_READ_MAX] = "";
 
   APPL_TRACE_DEBUG("%s", __func__);
 
@@ -595,11 +615,13 @@
     /* read data from rfcomm; if bad status, we're done */
     if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) !=
         PORT_SUCCESS) {
+      LOG(ERROR) << __func__ << ": failed to read data " << p_scb->peer_addr;
       break;
     }
 
     /* if no data, we're done */
     if (len == 0) {
+      LOG(WARNING) << __func__ << ": no data for " << p_scb->peer_addr;
       break;
     }
 
@@ -631,7 +653,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_start_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_start_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   /* Take the link out of sniff and set L2C idle time to 0 */
   bta_dm_pm_active(p_scb->peer_addr);
   L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0, BT_TRANSPORT_BR_EDR);
@@ -641,11 +663,11 @@
     p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
   } else {
     p_scb->post_sco = BTA_AG_POST_SCO_NONE;
-    bta_ag_rfc_do_close(p_scb, p_data);
+    bta_ag_rfc_do_close(p_scb, data);
   }
 
   /* always do SCO shutdown to handle all SCO corner cases */
-  bta_ag_sco_shutdown(p_scb, p_data);
+  bta_ag_sco_shutdown(p_scb, data);
 }
 
 /*******************************************************************************
@@ -658,10 +680,10 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   switch (p_scb->post_sco) {
     case BTA_AG_POST_SCO_RING:
-      bta_ag_send_ring(p_scb, p_data);
+      bta_ag_send_ring(p_scb, data);
       p_scb->post_sco = BTA_AG_POST_SCO_NONE;
       break;
 
@@ -685,10 +707,10 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   switch (p_scb->post_sco) {
     case BTA_AG_POST_SCO_CLOSE_RFC:
-      bta_ag_rfc_do_close(p_scb, p_data);
+      bta_ag_rfc_do_close(p_scb, data);
       p_scb->post_sco = BTA_AG_POST_SCO_NONE;
       break;
 
@@ -716,10 +738,10 @@
       if (bta_ag_inband_enabled(p_scb) &&
           !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
         p_scb->post_sco = BTA_AG_POST_SCO_RING;
-        bta_ag_sco_open(p_scb, p_data);
+        bta_ag_sco_open(p_scb, data);
       } else {
         p_scb->post_sco = BTA_AG_POST_SCO_NONE;
-        bta_ag_send_ring(p_scb, p_data);
+        bta_ag_send_ring(p_scb, data);
       }
       break;
 
@@ -739,8 +761,8 @@
  *
  ******************************************************************************/
 void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb,
-                          UNUSED_ATTR tBTA_AG_DATA* p_data) {
-  tBTA_AG_CONN evt;
+                          UNUSED_ATTR const tBTA_AG_DATA& data) {
+  tBTA_AG_CONN evt = {};
 
   if (!p_scb->svc_conn) {
     /* set state variable */
@@ -762,61 +784,15 @@
         (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE)) {
       bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
     }
-
+    if (bta_ag_get_active_device().IsEmpty()) {
+      bta_ag_api_set_active_device(p_scb->peer_addr);
+    }
     (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG*)&evt);
   }
 }
 
 /*******************************************************************************
  *
- * Function         bta_ag_ci_rx_data
- *
- * Description      Send result code
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_ag_ci_rx_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
-  uint16_t len;
-  tBTA_AG_CI_RX_WRITE* p_rx_write_msg = (tBTA_AG_CI_RX_WRITE*)p_data;
-  char* p_data_area =
-      (char*)(p_rx_write_msg + 1); /* Point to data area after header */
-
-  APPL_TRACE_DEBUG("bta_ag_ci_rx_data:");
-  /* send to RFCOMM */
-  bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
-  PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
-  if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb)) {
-    APPL_TRACE_DEBUG("bta_ag_rfc_data, change link policy for SCO");
-    bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
-  } else {
-    bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
-  }
-}
-
-/*******************************************************************************
- *
- * Function         bta_ag_rcvd_slc_ready
- *
- * Description      Handles SLC ready call-in in case of pass-through mode.
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_ag_rcvd_slc_ready(tBTA_AG_SCB* p_scb,
-                           UNUSED_ATTR tBTA_AG_DATA* p_data) {
-  APPL_TRACE_DEBUG("bta_ag_rcvd_slc_ready: handle = %d",
-                   bta_ag_scb_to_idx(p_scb));
-
-  if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
-    /* In pass-through mode, BTA knows that SLC is ready only through call-in.
-     */
-    bta_ag_svc_conn_open(p_scb, NULL);
-  }
-}
-
-/*******************************************************************************
- *
  * Function         bta_ag_setcodec
  *
  * Description      Handle API SetCodec
@@ -825,9 +801,10 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_setcodec(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
-  tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
-  tBTA_AG_VAL val;
+void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
+  tBTA_AG_PEER_CODEC codec_type = data.api_setcodec.codec;
+  tBTA_AG_VAL val = {};
+  val.hdr.handle = bta_ag_scb_to_idx(p_scb);
 
   /* Check if the requested codec type is valid */
   if ((codec_type != BTA_AG_CODEC_NONE) && (codec_type != BTA_AG_CODEC_CVSD) &&
@@ -856,3 +833,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_api.cc b/bta/ag/bta_ag_api.cc
index 4c0e285..7497fa7 100644
--- a/bta/ag/bta_ag_api.cc
+++ b/bta/ag/bta_ag_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,7 +25,8 @@
  ******************************************************************************/
 
 #include "bta_ag_api.h"
-#include <string.h>
+#include <base/bind.h>
+#include <cstring>
 #include "bt_common.h"
 #include "bta_ag_int.h"
 #include "bta_api.h"
@@ -36,6 +37,7 @@
  ****************************************************************************/
 
 static const tBTA_SYS_REG bta_ag_reg = {bta_ag_hdl_event, BTA_AgDisable};
+const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {};
 
 /*******************************************************************************
  *
@@ -50,27 +52,16 @@
  * Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
  *
  ******************************************************************************/
-tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode,
-                         tBTA_AG_CBACK* p_cback) {
+tBTA_STATUS BTA_AgEnable(tBTA_AG_CBACK* p_cback) {
   /* Error if AG is already enabled, or AG is in the middle of disabling. */
-  for (int idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
-    if (bta_ag_cb.scb[idx].in_use) {
+  for (const tBTA_AG_SCB& scb : bta_ag_cb.scb) {
+    if (scb.in_use) {
       APPL_TRACE_ERROR("BTA_AgEnable: FAILED, AG already enabled.");
       return BTA_FAILURE;
     }
   }
-
-  /* register with BTA system manager */
   bta_sys_register(BTA_ID_AG, &bta_ag_reg);
-
-  tBTA_AG_API_ENABLE* p_buf =
-      (tBTA_AG_API_ENABLE*)osi_malloc(sizeof(tBTA_AG_API_ENABLE));
-  p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
-  p_buf->parse_mode = parse_mode;
-  p_buf->p_cback = p_cback;
-
-  bta_sys_sendmsg(p_buf);
-
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_api_enable, p_cback));
   return BTA_SUCCESS;
 }
 
@@ -84,12 +75,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AgDisable(void) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTA_AG_API_DISABLE_EVT;
-
-  bta_sys_sendmsg(p_buf);
+void BTA_AgDisable() {
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_api_disable));
 }
 
 /*******************************************************************************
@@ -103,24 +90,12 @@
  *
  ******************************************************************************/
 void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
-                    tBTA_AG_FEAT features, const char* p_service_names[],
+                    tBTA_AG_FEAT features,
+                    const std::vector<std::string>& service_names,
                     uint8_t app_id) {
-  tBTA_AG_API_REGISTER* p_buf =
-      (tBTA_AG_API_REGISTER*)osi_malloc(sizeof(tBTA_AG_API_REGISTER));
-
-  p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
-  p_buf->features = features;
-  p_buf->sec_mask = sec_mask;
-  p_buf->services = services;
-  p_buf->app_id = app_id;
-  for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
-    if (p_service_names[i])
-      strlcpy(p_buf->p_name[i], p_service_names[i], BTA_SERVICE_NAME_LEN);
-    else
-      p_buf->p_name[i][0] = 0;
-  }
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(&bta_ag_api_register, services, sec_mask, features,
+                            service_names, app_id));
 }
 
 /*******************************************************************************
@@ -134,12 +109,9 @@
  *
  ******************************************************************************/
 void BTA_AgDeregister(uint16_t handle) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTA_AG_API_DEREGISTER_EVT;
-  p_buf->layer_specific = handle;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                              BTA_AG_API_DEREGISTER_EVT, tBTA_AG_DATA::kEmpty));
 }
 
 /*******************************************************************************
@@ -155,18 +127,12 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AgOpen(uint16_t handle, const RawAddress& bd_addr, tBTA_SEC sec_mask,
-                tBTA_SERVICE_MASK services) {
-  tBTA_AG_API_OPEN* p_buf =
-      (tBTA_AG_API_OPEN*)osi_malloc(sizeof(tBTA_AG_API_OPEN));
-
-  p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
-  p_buf->hdr.layer_specific = handle;
-  p_buf->bd_addr = bd_addr;
-  p_buf->services = services;
-  p_buf->sec_mask = sec_mask;
-
-  bta_sys_sendmsg(p_buf);
+void BTA_AgOpen(uint16_t handle, const RawAddress& bd_addr, tBTA_SEC sec_mask) {
+  tBTA_AG_DATA data = {};
+  data.api_open.bd_addr = bd_addr;
+  data.api_open.sec_mask = sec_mask;
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                                         BTA_AG_API_OPEN_EVT, data));
 }
 
 /*******************************************************************************
@@ -181,12 +147,9 @@
  *
  ******************************************************************************/
 void BTA_AgClose(uint16_t handle) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTA_AG_API_CLOSE_EVT;
-  p_buf->layer_specific = handle;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                              BTA_AG_API_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
 }
 
 /*******************************************************************************
@@ -201,12 +164,9 @@
  *
  ******************************************************************************/
 void BTA_AgAudioOpen(uint16_t handle) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
-  p_buf->layer_specific = handle;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                              BTA_AG_API_AUDIO_OPEN_EVT, tBTA_AG_DATA::kEmpty));
 }
 
 /*******************************************************************************
@@ -221,12 +181,9 @@
  *
  ******************************************************************************/
 void BTA_AgAudioClose(uint16_t handle) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
-  p_buf->layer_specific = handle;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                            BTA_AG_API_AUDIO_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
 }
 
 /*******************************************************************************
@@ -242,16 +199,9 @@
  *
  ******************************************************************************/
 void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
-                  tBTA_AG_RES_DATA* p_data) {
-  tBTA_AG_API_RESULT* p_buf =
-      (tBTA_AG_API_RESULT*)osi_malloc(sizeof(tBTA_AG_API_RESULT));
-
-  p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
-  p_buf->hdr.layer_specific = handle;
-  p_buf->result = result;
-  if (p_data) memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
-
-  bta_sys_sendmsg(p_buf);
+                  const tBTA_AG_RES_DATA& data) {
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&bta_ag_api_result, handle, result, data));
 }
 
 /*******************************************************************************
@@ -267,22 +217,17 @@
  *
  ******************************************************************************/
 void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec) {
-  tBTA_AG_API_SETCODEC* p_buf =
-      (tBTA_AG_API_SETCODEC*)osi_malloc(sizeof(tBTA_AG_API_SETCODEC));
-
-  p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
-  p_buf->hdr.layer_specific = handle;
-  p_buf->codec = codec;
-
-  bta_sys_sendmsg(p_buf);
+  tBTA_AG_DATA data = {};
+  data.api_setcodec.codec = codec;
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                                         BTA_AG_API_SETCODEC_EVT, data));
 }
 
 void BTA_AgSetScoAllowed(bool value) {
-  tBTA_AG_API_SET_SCO_ALLOWED* p_buf = (tBTA_AG_API_SET_SCO_ALLOWED*)osi_malloc(
-      sizeof(tBTA_AG_API_SET_SCO_ALLOWED));
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_set_sco_allowed, value));
+}
 
-  p_buf->hdr.event = BTA_AG_API_SET_SCO_ALLOWED_EVT;
-  p_buf->value = value;
-
-  bta_sys_sendmsg(p_buf);
+void BTA_AgSetActiveDevice(const RawAddress& active_device_addr) {
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(&bta_ag_api_set_active_device, active_device_addr));
 }
diff --git a/bta/ag/bta_ag_at.cc b/bta/ag/bta_ag_at.cc
index 3e4868b..ecd9053 100644
--- a/bta/ag/bta_ag_at.cc
+++ b/bta/ag/bta_ag_at.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
  *
  ******************************************************************************/
 
-#include <string.h>
+#include <cstring>
 
 #include "bt_common.h"
 #include "bta_ag_at.h"
@@ -43,7 +43,7 @@
  *
  *****************************************************************************/
 void bta_ag_at_init(tBTA_AG_AT_CB* p_cb) {
-  p_cb->p_cmd_buf = NULL;
+  p_cb->p_cmd_buf = nullptr;
   p_cb->cmd_pos = 0;
 }
 
@@ -129,24 +129,26 @@
         if (int_arg < (int16_t)p_cb->p_at_tbl[idx].min ||
             int_arg > (int16_t)p_cb->p_at_tbl[idx].max) {
           /* arg out of range; error */
-          (*p_cb->p_err_cback)(p_cb->p_user, false, NULL);
+          (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
         } else {
-          (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id,
-                               arg_type, p_arg, int_arg);
+          (*p_cb->p_cmd_cback)((tBTA_AG_SCB*)p_cb->p_user,
+                               p_cb->p_at_tbl[idx].command_id, arg_type, p_arg,
+                               int_arg);
         }
       } else {
-        (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id,
-                             arg_type, p_arg, int_arg);
+        (*p_cb->p_cmd_cback)((tBTA_AG_SCB*)p_cb->p_user,
+                             p_cb->p_at_tbl[idx].command_id, arg_type, p_arg,
+                             int_arg);
       }
     }
     /* else error */
     else {
-      (*p_cb->p_err_cback)(p_cb->p_user, false, NULL);
+      (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
     }
   }
   /* else no match call error callback */
   else {
-    (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf);
+    (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, true, p_cb->p_cmd_buf);
   }
 }
 
@@ -166,7 +168,7 @@
   int i = 0;
   char* p_save;
 
-  if (p_cb->p_cmd_buf == NULL) {
+  if (p_cb->p_cmd_buf == nullptr) {
     p_cb->p_cmd_buf = (char*)osi_malloc(p_cb->cmd_max_len);
     p_cb->cmd_pos = 0;
   }
@@ -197,7 +199,7 @@
       } else if (p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A ||
                  p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
         p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
-        (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf);
+        (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, true, p_cb->p_cmd_buf);
         p_cb->cmd_pos = 0;
       } else {
         ++p_cb->cmd_pos;
diff --git a/bta/ag/bta_ag_at.h b/bta/ag/bta_ag_at.h
index 144bc38..f36e2f2 100644
--- a/bta/ag/bta_ag_at.h
+++ b/bta/ag/bta_ag_at.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -54,16 +54,18 @@
 } tBTA_AG_AT_CMD;
 
 /* callback function executed when command is parsed */
-typedef void(tBTA_AG_AT_CMD_CBACK)(void* p_user, uint16_t command_id,
+struct tBTA_AG_SCB;
+typedef void(tBTA_AG_AT_CMD_CBACK)(tBTA_AG_SCB* p_user, uint16_t command_id,
                                    uint8_t arg_type, char* p_arg,
                                    int16_t int_arg);
 
 /* callback function executed to send "ERROR" result code */
-typedef void(tBTA_AG_AT_ERR_CBACK)(void* p_user, bool unknown, char* p_arg);
+typedef void(tBTA_AG_AT_ERR_CBACK)(tBTA_AG_SCB* p_user, bool unknown,
+                                   const char* p_arg);
 
 /* AT command parsing control block */
 typedef struct {
-  tBTA_AG_AT_CMD* p_at_tbl;          /* AT command table */
+  const tBTA_AG_AT_CMD* p_at_tbl;    /* AT command table */
   tBTA_AG_AT_CMD_CBACK* p_cmd_cback; /* command callback */
   tBTA_AG_AT_ERR_CBACK* p_err_cback; /* error callback */
   void* p_user;                      /* user-defined data */
diff --git a/bta/ag/bta_ag_cfg.cc b/bta/ag/bta_ag_cfg.cc
index bea4768..abb71b4 100644
--- a/bta/ag/bta_ag_cfg.cc
+++ b/bta/ag/bta_ag_cfg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
 #include "bt_common.h"
 #include "bta_ag_api.h"
 #include "bta_ag_int.h"
-#include "bta_api.h"
 
 #ifndef BTA_AG_CIND_INFO
 #define BTA_AG_CIND_INFO                                                       \
@@ -62,11 +61,11 @@
 const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[] = {
     /* The first row contains the number of indicators. Need to be updated
        accordingly */
-    {BTA_AG_NUM_LOCAL_HF_IND, 0, 0, 0, 0},
+    {BTA_AG_NUM_LOCAL_HF_IND, false, false, 0, 0},
 
-    {1, 1, 1, 0,
+    {1, true, true, 0,
      1}, /* Enhanced Driver Status, supported, enabled, range 0 ~ 1 */
-    {2, 1, 1, 0,
+    {2, true, true, 0,
      100} /* Battery Level Status, supported, enabled, range 0 ~ 100 */
 };
 
@@ -75,4 +74,4 @@
                                 BTA_AG_SCO_PKT_TYPES,    BTA_AG_CHLD_VAL_ECC,
                                 BTA_AG_CHLD_VAL};
 
-tBTA_AG_CFG* p_bta_ag_cfg = (tBTA_AG_CFG*)&bta_ag_cfg;
+const tBTA_AG_CFG* p_bta_ag_cfg = &bta_ag_cfg;
diff --git a/bta/ag/bta_ag_ci.cc b/bta/ag/bta_ag_ci.cc
deleted file mode 100644
index 1fde9d8..0000000
--- a/bta/ag/bta_ag_ci.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2003-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- *  This is the implementation file for audio gateway call-in functions.
- *
- ******************************************************************************/
-
-#include <string.h>
-
-#include "bt_common.h"
-#include "bta_ag_api.h"
-#include "bta_ag_ci.h"
-#include "bta_ag_int.h"
-#include "bta_api.h"
-
-/******************************************************************************
- *
- * Function         bta_ag_ci_rx_write
- *
- * Description      This function is called to send data to the AG when the AG
- *                  is configured for AT command pass-through.  The function
- *                  copies data to an event buffer and sends it.
- *
- * Returns          void
- *
- *****************************************************************************/
-void bta_ag_ci_rx_write(uint16_t handle, char* p_data, uint16_t len) {
-  uint16_t len_remaining = len;
-  char* p_data_area;
-
-  if (len > (RFCOMM_DATA_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1))
-    len = RFCOMM_DATA_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
-
-  while (len_remaining) {
-    if (len_remaining < len) len = len_remaining;
-
-    tBTA_AG_CI_RX_WRITE* p_buf =
-        (tBTA_AG_CI_RX_WRITE*)osi_malloc(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1);
-    p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
-    p_buf->hdr.layer_specific = handle;
-
-    p_data_area = (char*)(p_buf + 1); /* Point to data area after header */
-    strncpy(p_data_area, p_data, len);
-    p_data_area[len] = 0;
-
-    bta_sys_sendmsg(p_buf);
-
-    len_remaining -= len;
-    p_data += len;
-  }
-}
-
-/******************************************************************************
- *
- * Function         bta_ag_ci_slc_ready
- *
- * Description      This function is called to notify AG that SLC is up at
- *                  the application. This funcion is only used when the app
- *                  is running in pass-through mode.
- *
- * Returns          void
- *
- *****************************************************************************/
-void bta_ag_ci_slc_ready(uint16_t handle) {
-  tBTA_AG_DATA* p_buf = (tBTA_AG_DATA*)osi_malloc(sizeof(tBTA_AG_DATA));
-
-  p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
-  p_buf->hdr.layer_specific = handle;
-
-  bta_sys_sendmsg(p_buf);
-}
diff --git a/bta/ag/bta_ag_cmd.cc b/bta/ag/bta_ag_cmd.cc
index 79028db..b9cf306 100644
--- a/bta/ag/bta_ag_cmd.cc
+++ b/bta/ag/bta_ag_cmd.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
 
 #define LOG_TAG "bta_ag_cmd"
 
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
+#include <cctype>
+#include <cstdio>
+#include <cstring>
 
 #include "bt_common.h"
 #include "bt_target.h"
@@ -63,7 +63,6 @@
   BTA_AG_LOCAL_EVT_CMER,
   BTA_AG_LOCAL_EVT_BRSF,
   BTA_AG_LOCAL_EVT_CMEE,
-  BTA_AG_LOCAL_EVT_BIA,
   BTA_AG_LOCAL_EVT_BCC,
 };
 
@@ -105,7 +104,7 @@
     {"+COPS", BTA_AG_AT_COPS_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_STR,
      0, 0},
     {"+CMEE", BTA_AG_LOCAL_EVT_CMEE, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
-    {"+BIA", BTA_AG_LOCAL_EVT_BIA, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
+    {"+BIA", BTA_AG_AT_BIA_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
     {"+CBC", BTA_AG_AT_CBC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
     {"+BCC", BTA_AG_LOCAL_EVT_BCC, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
     {"+BCS", BTA_AG_AT_BCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
@@ -173,7 +172,7 @@
        i != sizeof(bta_ag_result_tbl) / sizeof(bta_ag_result_tbl[0]); ++i) {
     if (code == bta_ag_result_tbl[i].result_id) return &bta_ag_result_tbl[i];
   }
-  return 0;
+  return nullptr;
 }
 
 const tBTA_AG_AT_CMD* bta_ag_at_tbl[BTA_AG_NUM_IDX] = {bta_ag_hsp_cmd,
@@ -215,15 +214,14 @@
 static void bta_ag_send_result(tBTA_AG_SCB* p_scb, size_t code,
                                const char* p_arg, int16_t int_arg) {
   const tBTA_AG_RESULT* result = bta_ag_result_by_code(code);
-  if (result == 0) {
+  if (result == nullptr) {
     LOG_ERROR(LOG_TAG, "%s Unable to lookup result for code %zu", __func__,
               code);
     return;
   }
 
-  char buf[BTA_AG_AT_MAX_LEN + 16];
+  char buf[BTA_AG_AT_MAX_LEN + 16] = "";
   char* p = buf;
-  memset(buf, 0, sizeof(buf));
 
   /* init with \r\n */
   *p++ = '\r';
@@ -274,7 +272,7 @@
  *
  ******************************************************************************/
 static void bta_ag_send_ok(tBTA_AG_SCB* p_scb) {
-  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_OK, NULL, 0);
+  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_OK, nullptr, 0);
 }
 
 /*******************************************************************************
@@ -291,9 +289,9 @@
 static void bta_ag_send_error(tBTA_AG_SCB* p_scb, int16_t errcode) {
   /* If HFP and extended audio gateway error codes are enabled */
   if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
-    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CMEE, NULL, errcode);
+    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CMEE, nullptr, errcode);
   else
-    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_ERROR, NULL, 0);
+    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_ERROR, nullptr, 0);
 }
 
 /*******************************************************************************
@@ -321,39 +319,39 @@
   /* Ensure we do not send duplicate indicators if not requested by app */
   /* If it was requested by app, transmit CIEV even if it is duplicate. */
   if (id == BTA_AG_IND_CALL) {
-    if ((value == p_scb->call_ind) && (on_demand == false)) return;
+    if ((value == p_scb->call_ind) && (!on_demand)) return;
 
     p_scb->call_ind = (uint8_t)value;
   }
 
-  if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == false)) {
+  if ((id == BTA_AG_IND_CALLSETUP) && (!on_demand)) {
     if (value == p_scb->callsetup_ind) return;
 
     p_scb->callsetup_ind = (uint8_t)value;
   }
 
-  if ((id == BTA_AG_IND_SERVICE) && (on_demand == false)) {
+  if ((id == BTA_AG_IND_SERVICE) && (!on_demand)) {
     if (value == p_scb->service_ind) return;
 
     p_scb->service_ind = (uint8_t)value;
   }
-  if ((id == BTA_AG_IND_SIGNAL) && (on_demand == false)) {
+  if ((id == BTA_AG_IND_SIGNAL) && (!on_demand)) {
     if (value == p_scb->signal_ind) return;
 
     p_scb->signal_ind = (uint8_t)value;
   }
-  if ((id == BTA_AG_IND_ROAM) && (on_demand == false)) {
+  if ((id == BTA_AG_IND_ROAM) && (!on_demand)) {
     if (value == p_scb->roam_ind) return;
 
     p_scb->roam_ind = (uint8_t)value;
   }
-  if ((id == BTA_AG_IND_BATTCHG) && (on_demand == false)) {
+  if ((id == BTA_AG_IND_BATTCHG) && (!on_demand)) {
     if (value == p_scb->battchg_ind) return;
 
     p_scb->battchg_ind = (uint8_t)value;
   }
 
-  if ((id == BTA_AG_IND_CALLHELD) && (on_demand == false)) {
+  if ((id == BTA_AG_IND_CALLHELD) && (!on_demand)) {
     /* call swap could result in sending callheld=1 multiple times */
     if ((value != 1) && (value == p_scb->callheld_ind)) return;
 
@@ -392,7 +390,7 @@
     *p = 0;
     n[i] = utl_str2int(p_s);
     p_s = p + 1;
-    if (p_s == 0) {
+    if (p_s == nullptr) {
       break;
     }
   }
@@ -424,7 +422,6 @@
  ******************************************************************************/
 static uint8_t bta_ag_parse_chld(UNUSED_ATTR tBTA_AG_SCB* p_scb, char* p_s) {
   uint8_t retval = 0;
-  int16_t idx = -1;
 
   if (!isdigit(p_s[0])) {
     return BTA_AG_INVALID_CHLD;
@@ -432,7 +429,7 @@
 
   if (p_s[1] != 0) {
     /* p_idxstr++;  point to beginning of call number */
-    idx = utl_str2int(&p_s[1]);
+    int16_t idx = utl_str2int(&p_s[1]);
     if (idx != -1 && idx < 255) {
       retval = (uint8_t)idx;
     } else {
@@ -455,7 +452,6 @@
 static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB* p_scb, char* p_s) {
   tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE;
   uint16_t uuid_codec;
-  bool cont = false; /* Continue processing */
   char* p;
 
   while (p_s) {
@@ -463,13 +459,12 @@
     for (p = p_s; *p != ',' && *p != 0; p++)
       ;
 
-    /* get integre value */
+    /* get integer value */
+    bool cont = false;  // Continue processing
     if (*p != 0) {
       *p = 0;
       cont = true;
-    } else
-      cont = false;
-
+    }
     uuid_codec = utl_str2int(p_s);
     switch (uuid_codec) {
       case UUID_CODEC_CVSD:
@@ -505,13 +500,11 @@
  ******************************************************************************/
 
 static void bta_ag_process_unat_res(char* unat_result) {
-  uint8_t str_leng;
-  uint8_t i = 0;
   uint8_t j = 0;
   uint8_t pairs_of_nl_cr;
   char trim_data[BTA_AG_AT_MAX_LEN];
 
-  str_leng = strlen(unat_result);
+  uint8_t str_leng = strlen(unat_result);
 
   /* If no extra CR and LF, just return */
   if (str_leng < 4) return;
@@ -521,19 +514,17 @@
          unat_result[str_leng - 2] == '\r' &&
          unat_result[str_leng - 1] == '\n') {
     pairs_of_nl_cr = 1;
-    for (i = 0; i < (str_leng - 4 * pairs_of_nl_cr); i++) {
+    for (int i = 0; i < (str_leng - 4 * pairs_of_nl_cr); i++) {
       trim_data[j++] = unat_result[i + pairs_of_nl_cr * 2];
     }
     /* Add EOF */
     trim_data[j] = '\0';
     str_leng = str_leng - 4;
     strlcpy(unat_result, trim_data, str_leng + 1);
-    i = 0;
     j = 0;
 
     if (str_leng < 4) return;
   }
-  return;
 }
 
 /*******************************************************************************
@@ -548,11 +539,7 @@
  ******************************************************************************/
 bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb) {
   /* if feature is enabled and no other scbs connected */
-  if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb)) {
-    return true;
-  } else {
-    return false;
-  }
+  return p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb);
 }
 
 /*******************************************************************************
@@ -566,7 +553,7 @@
  *
  ******************************************************************************/
 void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result) {
-  uint8_t call = p_scb->call_ind;
+  uint8_t call;
 
   /* set new call and callsetup values based on BTA_AgResult */
   size_t callsetup = bta_ag_indicator_by_result_code(result);
@@ -603,7 +590,7 @@
 
   bta_ag_send_ok(p_scb);
 
-  tBTA_AG_VAL val;
+  tBTA_AG_VAL val = {};
   val.hdr.handle = bta_ag_scb_to_idx(p_scb);
   val.hdr.app_id = p_scb->app_id;
   val.num = (uint16_t)int_arg;
@@ -678,9 +665,9 @@
  ******************************************************************************/
 static bool bta_ag_parse_bind_set(tBTA_AG_SCB* p_scb, tBTA_AG_VAL val) {
   char* p_token = strtok(val.str, ",");
-  if (p_token == NULL) return false;
+  if (p_token == nullptr) return false;
 
-  while (p_token != NULL) {
+  while (p_token != nullptr) {
     uint16_t rcv_ind_id = atoi(p_token);
     int index = bta_ag_find_empty_hf_ind(p_scb);
     if (index == -1) {
@@ -691,7 +678,7 @@
     p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id;
     APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id);
 
-    p_token = strtok(NULL, ",");
+    p_token = strtok(nullptr, ",");
   }
 
   return true;
@@ -708,8 +695,7 @@
  *
  ******************************************************************************/
 static void bta_ag_bind_response(tBTA_AG_SCB* p_scb, uint8_t arg_type) {
-  char buffer[BTA_AG_AT_MAX_LEN];
-  memset(buffer, 0, BTA_AG_AT_MAX_LEN);
+  char buffer[BTA_AG_AT_MAX_LEN] = "";
 
   if (arg_type == BTA_AG_AT_TEST) {
     int index = 0;
@@ -750,15 +736,15 @@
           p_scb->local_hf_indicators[i].ind_id);
 
       /* Check whether local and peer sides support this indicator */
-      if (p_scb->local_hf_indicators[i].is_supported == true &&
-          peer_index != -1) {
+      if (p_scb->local_hf_indicators[i].is_supported && peer_index != -1) {
         /* In the format of ind, state */
         p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].ind_id, p);
         *p++ = ',';
         p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].is_enable, p);
 
         bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
-
+        // have to use memset here because assigning to "" will not zero
+        // initialize the rest of the buffer
         memset(buffer, 0, sizeof(buffer));
         p = buffer;
       } else {
@@ -770,7 +756,9 @@
     bta_ag_send_ok(p_scb);
 
     /* If the service level connection wan't already open, now it's open */
-    if (!p_scb->svc_conn) bta_ag_svc_conn_open(p_scb, NULL);
+    if (!p_scb->svc_conn) {
+      bta_ag_svc_conn_open(p_scb, tBTA_AG_DATA::kEmpty);
+    }
   }
 }
 
@@ -788,7 +776,7 @@
   char* p_token = strtok(val->str, ",");
   uint16_t rcv_ind_id = atoi(p_token);
 
-  p_token = strtok(NULL, ",");
+  p_token = strtok(nullptr, ",");
   uint16_t rcv_ind_val = atoi(p_token);
 
   APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id,
@@ -805,8 +793,8 @@
   int local_index = bta_ag_find_hf_ind_by_id(
       p_scb->local_hf_indicators, BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id);
   if (local_index == -1 ||
-      p_scb->local_hf_indicators[local_index].is_supported != true ||
-      p_scb->local_hf_indicators[local_index].is_enable != true) {
+      !p_scb->local_hf_indicators[local_index].is_supported ||
+      !p_scb->local_hf_indicators[local_index].is_enable) {
     APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__,
                        rcv_ind_id);
     return false;
@@ -837,11 +825,11 @@
  ******************************************************************************/
 void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type,
                          char* p_arg, int16_t int_arg) {
-  tBTA_AG_VAL val;
+  tBTA_AG_VAL val = {};
   tBTA_AG_SCB* ag_scb;
   uint32_t i, ind_id;
   uint32_t bia_masked_out;
-  if (p_arg == NULL) {
+  if (p_arg == nullptr) {
     APPL_TRACE_ERROR("%s: p_arg is null, send error and return", __func__);
     bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
     return;
@@ -850,11 +838,10 @@
   APPL_TRACE_DEBUG("%s: AT command %d, arg_type %d, int_arg %d, arg %s",
                    __func__, cmd, arg_type, int_arg, p_arg);
 
-  memset(&val, 0, sizeof(tBTA_AG_VAL));
   val.hdr.handle = bta_ag_scb_to_idx(p_scb);
   val.hdr.app_id = p_scb->app_id;
   val.hdr.status = BTA_AG_SUCCESS;
-  val.num = int_arg;
+  val.num = static_cast<uint32_t>(int_arg);
   val.bd_addr = p_scb->peer_addr;
   strlcpy(val.str, p_arg, sizeof(val.str));
 
@@ -865,7 +852,9 @@
    * callback is NOT invoked.
    */
   tBTA_AG_EVT event = 0;
-  if (cmd < BTA_AG_LOCAL_EVT_FIRST) event = cmd;
+  if (cmd < BTA_AG_LOCAL_EVT_FIRST) {
+    event = static_cast<tBTA_AG_EVT>(cmd);
+  }
 
   switch (cmd) {
     case BTA_AG_AT_A_EVT:
@@ -947,7 +936,7 @@
         bta_ag_send_ok(p_scb);
 
         /* if service level conn. not already open, now it's open */
-        bta_ag_svc_conn_open(p_scb, NULL);
+        bta_ag_svc_conn_open(p_scb, tBTA_AG_DATA::kEmpty);
       } else {
         val.idx = bta_ag_parse_chld(p_scb, val.str);
 
@@ -970,7 +959,7 @@
           ** Application will set it back to 1
           ** callheld indicator will be sent across to the peer. */
           if (val.str[0] == '2') {
-            for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB;
+            for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_MAX_NUM_CLIENTS;
                  i++, ag_scb++) {
               if (ag_scb->in_use) {
                 if ((ag_scb->call_ind == BTA_AG_CALL_ACTIVE) &&
@@ -1043,7 +1032,7 @@
         if (!p_scb->svc_conn &&
             !((p_scb->features & BTA_AG_FEAT_3WAY) &&
               (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY))) {
-          bta_ag_svc_conn_open(p_scb, NULL);
+          bta_ag_svc_conn_open(p_scb, tBTA_AG_DATA::kEmpty);
         }
       } else {
         bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
@@ -1090,7 +1079,8 @@
                        p_scb->peer_features, features);
 
       /* send BRSF, send OK */
-      bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t)features);
+      bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, nullptr,
+                         (int16_t)features);
       bta_ag_send_ok(p_scb);
       break;
     }
@@ -1110,10 +1100,10 @@
       if (p_scb->features & BTA_AG_FEAT_BTRH) {
         /* If set command; send response and notify app */
         if (arg_type == BTA_AG_AT_SET) {
-          for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB;
+          for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_MAX_NUM_CLIENTS;
                i++, ag_scb++) {
             if (ag_scb->in_use) {
-              bta_ag_send_result(ag_scb, BTA_AG_BTRH_RES, NULL, int_arg);
+              bta_ag_send_result(ag_scb, BTA_AG_BTRH_RES, nullptr, int_arg);
             }
           }
           bta_ag_send_ok(p_scb);
@@ -1151,32 +1141,37 @@
       event = 0;
       break;
 
-    case BTA_AG_LOCAL_EVT_BIA:
-      /* don't call callback */
-      event = 0;
-
+    case BTA_AG_AT_BIA_EVT:
       bia_masked_out = p_scb->bia_masked_out;
 
       /* Parse the indicator mask */
       for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20);
            i++, ind_id++) {
-        if (val.str[i] == ',') continue;
+        if (val.str[i] == ',') {
+          continue;
+        }
 
-        if (val.str[i] == '0')
+        if (val.str[i] == '0') {
           bia_masked_out |= ((uint32_t)1 << ind_id);
-        else if (val.str[i] == '1')
+        } else if (val.str[i] == '1') {
           bia_masked_out &= ~((uint32_t)1 << ind_id);
-        else
+        } else {
           break;
+        }
 
         i++;
-        if ((val.str[i] == 0) || (val.str[i] != ',')) break;
+        if (val.str[i] != ',') {
+          break;
+        }
       }
       if (val.str[i] == 0) {
         p_scb->bia_masked_out = bia_masked_out;
+        val.num = bia_masked_out;
         bta_ag_send_ok(p_scb);
-      } else
+      } else {
+        event = 0;
         bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+      }
       break;
 
     case BTA_AG_AT_CNUM_EVT:
@@ -1191,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) &&
@@ -1247,20 +1243,23 @@
       else
         codec_sent = p_scb->sco_codec;
 
-      if (codec_type == codec_sent)
-        bta_ag_sco_codec_nego(p_scb, true);
-      else
-        bta_ag_sco_codec_nego(p_scb, false);
+      bta_ag_sco_codec_nego(p_scb, codec_type == codec_sent);
 
       /* send final codec info to callback */
       val.num = codec_sent;
       break;
     }
-    case BTA_AG_LOCAL_EVT_BCC:
+    case BTA_AG_LOCAL_EVT_BCC: {
+      if (!bta_ag_sco_is_active_device(p_scb->peer_addr)) {
+        LOG(WARNING) << __func__ << ": AT+BCC rejected as " << p_scb->peer_addr
+                     << " is not the active device";
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_ALLOWED);
+        break;
+      }
       bta_ag_send_ok(p_scb);
-      bta_ag_sco_open(p_scb, NULL);
+      bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
       break;
-
+    }
     default:
       bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
       break;
@@ -1282,15 +1281,14 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg) {
-  tBTA_AG_VAL val;
-
+void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, const char* p_arg) {
   if (unknown && (!strlen(p_arg))) {
     APPL_TRACE_DEBUG("Empty AT cmd string received");
     bta_ag_send_ok(p_scb);
     return;
   }
 
+  tBTA_AG_VAL val = {};
   /* if unknown AT command and configured to pass these to app */
   if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT)) {
     val.hdr.handle = bta_ag_scb_to_idx(p_scb);
@@ -1314,13 +1312,13 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) {
-  APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result);
+void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, const tBTA_AG_API_RESULT& result) {
+  APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", result.result);
 
-  switch (p_result->result) {
+  switch (result.result) {
     case BTA_AG_SPK_RES:
     case BTA_AG_MIC_RES:
-      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+      bta_ag_send_result(p_scb, result.result, nullptr, result.data.num);
       break;
 
     case BTA_AG_IN_CALL_RES:
@@ -1330,7 +1328,7 @@
       /* if sco already opened or no inband ring send ring now */
       if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
           (p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result);
+        bta_ag_send_ring(p_scb, tBTA_AG_DATA::kEmpty);
       } else {
         /* else open sco, send ring after sco opened */
         /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
@@ -1339,27 +1337,26 @@
         } else {
           p_scb->post_sco = BTA_AG_POST_SCO_RING;
         }
-        bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
       }
       break;
 
     case BTA_AG_IN_CALL_CONN_RES:
     case BTA_AG_OUT_CALL_ORIG_RES:
       /* if incoming call connected stop ring timer */
-      if (p_result->result == BTA_AG_IN_CALL_CONN_RES) {
+      if (result.result == BTA_AG_IN_CALL_CONN_RES) {
         alarm_cancel(p_scb->ring_timer);
       }
 
       if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
         /* if audio connected to this scb AND sco is not opened, open sco */
-        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+        if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
             !bta_ag_sco_is_open(p_scb)) {
-          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
-        }
-        /* else if no audio at call close sco */
-        else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
-                 bta_ag_sco_is_open(p_scb)) {
-          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+          bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
+        } else if (result.data.audio_handle == BTA_AG_HANDLE_NONE &&
+                   bta_ag_sco_is_open(p_scb)) {
+          /* else if no audio at call close sco */
+          bta_ag_sco_close(p_scb, tBTA_AG_DATA::kEmpty);
         }
       }
       break;
@@ -1370,7 +1367,7 @@
       /* close sco */
       if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) &&
           !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        bta_ag_sco_close(p_scb, tBTA_AG_DATA::kEmpty);
       } else {
         /* if av got suspended by this call, let it resume. */
         bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
@@ -1378,17 +1375,17 @@
       break;
 
     case BTA_AG_INBAND_RING_RES:
-      p_scb->inband_enabled = p_result->data.state;
+      p_scb->inband_enabled = result.data.state;
       APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
       break;
 
     case BTA_AG_UNAT_RES:
-      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
-        if (p_result->data.str[0] != 0) {
-          bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+      if (result.data.ok_flag != BTA_AG_OK_ERROR) {
+        if (result.data.str[0] != 0) {
+          bta_ag_send_result(p_scb, result.result, result.data.str, 0);
         }
 
-        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+        if (result.data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
       } else {
         bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
       }
@@ -1410,34 +1407,36 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) {
-  APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
+void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, const tBTA_AG_API_RESULT& result) {
+  APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", result.result);
 
-  switch (p_result->result) {
+  switch (result.result) {
     case BTA_AG_SPK_RES:
     case BTA_AG_MIC_RES:
-      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+      bta_ag_send_result(p_scb, result.result, nullptr, result.data.num);
       break;
 
-    case BTA_AG_IN_CALL_RES:
+    case BTA_AG_IN_CALL_RES: {
       /* tell sys to stop av if any */
       bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
-      /* store caller id string.
-       * append type info at the end.
-       * make sure a valid type info is passed.
-       * otherwise add 129 as default type */
-      if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) ||
-          (p_result->data.num > BTA_AG_CLIP_TYPE_MAX)) {
-        if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
-          p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+      /* Store caller id string.
+       * Append type info at the end.
+       * Make sure a valid type info is passed.
+       * Otherwise add 129 as default type */
+      uint16_t clip_type = result.data.num;
+      if ((clip_type < BTA_AG_CLIP_TYPE_MIN) ||
+          (clip_type > BTA_AG_CLIP_TYPE_MAX)) {
+        if (clip_type != BTA_AG_CLIP_TYPE_VOIP) {
+          clip_type = BTA_AG_CLIP_TYPE_DEFAULT;
+        }
       }
 
-      APPL_TRACE_DEBUG("CLIP type :%d", p_result->data.num);
+      APPL_TRACE_DEBUG("CLIP type :%d", clip_type);
       p_scb->clip[0] = 0;
-      if (p_result->data.str[0] != 0)
-        snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", p_result->data.str,
-                 p_result->data.num);
+      if (result.data.str[0] != 0)
+        snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", result.data.str,
+                 clip_type);
 
       /* send callsetup indicator */
       if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) {
@@ -1445,35 +1444,36 @@
          * close. */
         p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
       } else {
-        bta_ag_send_call_inds(p_scb, p_result->result);
+        bta_ag_send_call_inds(p_scb, result.result);
 
         /* if sco already opened or no inband ring send ring now */
         if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
-            (p_scb->features & BTA_AG_FEAT_NOSCO)) {
-          bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result);
+            (p_scb->features & BTA_AG_FEAT_NOSCO) ||
+            (result.data.audio_handle != bta_ag_scb_to_idx(p_scb))) {
+          bta_ag_send_ring(p_scb, tBTA_AG_DATA::kEmpty);
         } else {
           /* else open sco, send ring after sco opened */
           p_scb->post_sco = BTA_AG_POST_SCO_RING;
-          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+          bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
         }
       }
       break;
-
+    }
     case BTA_AG_IN_CALL_CONN_RES:
       alarm_cancel(p_scb->ring_timer);
 
       /* if sco not opened and we need to open it, send indicators first
       ** then  open sco.
       */
-      bta_ag_send_call_inds(p_scb, p_result->result);
+      bta_ag_send_call_inds(p_scb, result.result);
 
       if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+        if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
             !bta_ag_sco_is_open(p_scb)) {
-          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
-        } else if ((p_result->data.audio_handle == BTA_AG_HANDLE_NONE) &&
+          bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
+        } else if ((result.data.audio_handle == BTA_AG_HANDLE_NONE) &&
                    bta_ag_sco_is_open(p_scb)) {
-          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+          bta_ag_sco_close(p_scb, tBTA_AG_DATA::kEmpty);
         }
       }
       break;
@@ -1481,24 +1481,24 @@
     case BTA_AG_IN_CALL_HELD_RES:
       alarm_cancel(p_scb->ring_timer);
 
-      bta_ag_send_call_inds(p_scb, p_result->result);
+      bta_ag_send_call_inds(p_scb, result.result);
 
       break;
 
     case BTA_AG_OUT_CALL_ORIG_RES:
-      bta_ag_send_call_inds(p_scb, p_result->result);
-      if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+      bta_ag_send_call_inds(p_scb, result.result);
+      if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
           !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
       }
       break;
 
     case BTA_AG_OUT_CALL_ALERT_RES:
       /* send indicators */
-      bta_ag_send_call_inds(p_scb, p_result->result);
-      if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+      bta_ag_send_call_inds(p_scb, result.result);
+      if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
           !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
       }
       break;
 
@@ -1506,30 +1506,31 @@
       /* open SCO at SLC for this three way call */
       APPL_TRACE_DEBUG("Headset Connected in three way call");
       if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
-          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
-        else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
-          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+          bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
+        } else if (result.data.audio_handle == BTA_AG_HANDLE_NONE) {
+          bta_ag_sco_close(p_scb, tBTA_AG_DATA::kEmpty);
+        }
       }
       break;
 
     case BTA_AG_OUT_CALL_CONN_RES:
       /* send indicators */
-      bta_ag_send_call_inds(p_scb, p_result->result);
+      bta_ag_send_call_inds(p_scb, result.result);
 
       /* open or close sco */
       if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
-        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
-          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
-        } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
-          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+          bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty);
+        } else if (result.data.audio_handle == BTA_AG_HANDLE_NONE) {
+          bta_ag_sco_close(p_scb, tBTA_AG_DATA::kEmpty);
         }
       }
       break;
 
     case BTA_AG_CALL_CANCEL_RES:
       /* send indicators */
-      bta_ag_send_call_inds(p_scb, p_result->result);
+      bta_ag_send_call_inds(p_scb, result.result);
       break;
 
     case BTA_AG_END_CALL_RES:
@@ -1539,13 +1540,13 @@
       if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) &&
           !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
         p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
-        bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        bta_ag_sco_close(p_scb, tBTA_AG_DATA::kEmpty);
       } else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL) {
         /* sco closing for outgoing call because of incoming call */
         /* Send only callsetup end indicator after sco close */
         p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
       } else {
-        bta_ag_send_call_inds(p_scb, p_result->result);
+        bta_ag_send_call_inds(p_scb, result.result);
 
         /* if av got suspended by this call, let it resume. */
         bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
@@ -1553,24 +1554,24 @@
       break;
 
     case BTA_AG_INBAND_RING_RES:
-      p_scb->inband_enabled = p_result->data.state;
+      p_scb->inband_enabled = result.data.state;
       APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
-      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+      bta_ag_send_result(p_scb, result.result, nullptr, result.data.state);
       break;
 
     case BTA_AG_CIND_RES:
       /* store local values */
-      p_scb->call_ind = p_result->data.str[0] - '0';
-      p_scb->callsetup_ind = p_result->data.str[2] - '0';
-      p_scb->service_ind = p_result->data.str[4] - '0';
-      p_scb->signal_ind = p_result->data.str[6] - '0';
-      p_scb->roam_ind = p_result->data.str[8] - '0';
-      p_scb->battchg_ind = p_result->data.str[10] - '0';
-      p_scb->callheld_ind = p_result->data.str[12] - '0';
+      p_scb->call_ind = result.data.str[0] - '0';
+      p_scb->callsetup_ind = result.data.str[2] - '0';
+      p_scb->service_ind = result.data.str[4] - '0';
+      p_scb->signal_ind = result.data.str[6] - '0';
+      p_scb->roam_ind = result.data.str[8] - '0';
+      p_scb->battchg_ind = result.data.str[10] - '0';
+      p_scb->callheld_ind = result.data.str[12] - '0';
       APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind,
                        p_scb->callsetup_ind);
 
-      bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+      bta_ag_send_result(p_scb, result.result, result.data.str, 0);
       bta_ag_send_ok(p_scb);
       break;
 
@@ -1578,58 +1579,67 @@
     case BTA_AG_CNUM_RES:
     case BTA_AG_CLCC_RES:
     case BTA_AG_COPS_RES:
-      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
-        if (p_result->data.str[0] != 0) {
-          bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+      if (result.data.ok_flag != BTA_AG_OK_ERROR) {
+        if (result.data.str[0] != 0) {
+          bta_ag_send_result(p_scb, result.result, result.data.str, 0);
         }
 
-        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+        if (result.data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
       } else {
-        bta_ag_send_error(p_scb, p_result->data.errcode);
+        bta_ag_send_error(p_scb, result.data.errcode);
       }
       break;
 
-    case BTA_AG_UNAT_RES:
-      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
-        if (p_result->data.str[0] != 0) {
-          bta_ag_process_unat_res(p_result->data.str);
-          APPL_TRACE_DEBUG("BTA_AG_RES :%s", p_result->data.str);
-          bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+    case BTA_AG_UNAT_RES: {
+      if (result.data.ok_flag != BTA_AG_OK_ERROR) {
+        if (result.data.str[0] != 0) {
+          tBTA_AG_API_RESULT result_copy(result);
+          bta_ag_process_unat_res(result_copy.data.str);
+          APPL_TRACE_DEBUG("BTA_AG_RES :%s", result_copy.data.str);
+          bta_ag_send_result(p_scb, result_copy.result, result_copy.data.str,
+                             0);
         }
-
-        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+        if (result.data.ok_flag == BTA_AG_OK_DONE) {
+          bta_ag_send_ok(p_scb);
+        }
       } else {
-        bta_ag_send_error(p_scb, p_result->data.errcode);
+        bta_ag_send_error(p_scb, result.data.errcode);
       }
       break;
+    }
 
     case BTA_AG_CALL_WAIT_RES:
       if (p_scb->ccwa_enabled) {
-        bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+        bta_ag_send_result(p_scb, result.result, result.data.str, 0);
       }
-      bta_ag_send_call_inds(p_scb, p_result->result);
+      bta_ag_send_call_inds(p_scb, result.result);
       break;
 
     case BTA_AG_IND_RES:
-      bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value,
-                      false);
+      bta_ag_send_ind(p_scb, result.data.ind.id, result.data.ind.value, false);
+      break;
+
+    case BTA_AG_IND_RES_ON_DEMAND:
+      bta_ag_send_ind(p_scb, result.data.ind.id, result.data.ind.value, true);
       break;
 
     case BTA_AG_BVRA_RES:
-      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+      bta_ag_send_result(p_scb, result.result, nullptr, result.data.state);
       break;
 
     case BTA_AG_BTRH_RES:
-      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+      if (result.data.ok_flag != BTA_AG_OK_ERROR) {
         /* Don't respond to read if not in response & hold state */
-        if (p_result->data.num != BTA_AG_BTRH_NO_RESP) {
-          bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+        if (result.data.num != BTA_AG_BTRH_NO_RESP) {
+          bta_ag_send_result(p_scb, result.result, nullptr, result.data.num);
         }
 
         /* In case of a response to a read request we need to send OK */
-        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+        if (result.data.ok_flag == BTA_AG_OK_DONE) {
+          bta_ag_send_ok(p_scb);
+        }
       } else {
-        bta_ag_send_error(p_scb, p_result->data.errcode);
+        bta_ag_send_error(p_scb, result.data.errcode);
       }
       break;
 
@@ -1637,45 +1647,44 @@
       /* Find whether ind_id is supported by local device or not */
       int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
                                                  BTA_AG_MAX_NUM_LOCAL_HF_IND,
-                                                 p_result->data.ind.id);
+                                                 result.data.ind.id);
       if (local_index == -1) {
         APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
-                           p_result->data.ind.id);
+                           result.data.ind.id);
         return;
       }
 
       /* Find whether ind_id is supported by peer device or not */
       int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
                                                 BTA_AG_MAX_NUM_PEER_HF_IND,
-                                                p_result->data.ind.id);
+                                                result.data.ind.id);
       if (peer_index == -1) {
         APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
-                           p_result->data.ind.id);
+                           result.data.ind.id);
         return;
       } else {
         /* If the current state is different from the one upper layer request
            change current state and send out the result */
         if (p_scb->local_hf_indicators[local_index].is_enable !=
-            p_result->data.ind.on_demand) {
+            result.data.ind.on_demand) {
           char buffer[BTA_AG_AT_MAX_LEN] = {0};
           char* p = buffer;
 
           p_scb->local_hf_indicators[local_index].is_enable =
-              p_result->data.ind.on_demand;
-          p += utl_itoa(p_result->data.ind.id, p);
+              result.data.ind.on_demand;
+          p += utl_itoa(result.data.ind.id, p);
           *p++ = ',';
           p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p);
 
-          bta_ag_send_result(p_scb, p_result->result, buffer, 0);
+          bta_ag_send_result(p_scb, result.result, buffer, 0);
         } else {
           APPL_TRACE_DEBUG(
-              "%s HF Indicator %d already %s", p_result->data.ind.id,
-              (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled");
+              "%s HF Indicator %d already %s", result.data.ind.id,
+              (result.data.ind.on_demand) ? "Enabled" : "Disabled");
         }
       }
       break;
     }
-
     default:
       break;
   }
@@ -1691,11 +1700,11 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_result(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   if (p_scb->conn_service == BTA_AG_HSP) {
-    bta_ag_hsp_result(p_scb, &p_data->api_result);
+    bta_ag_hsp_result(p_scb, data.api_result);
   } else {
-    bta_ag_hfp_result(p_scb, &p_data->api_result);
+    bta_ag_hfp_result(p_scb, data.api_result);
   }
 }
 
@@ -1708,7 +1717,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_send_bcs(tBTA_AG_SCB* p_scb) {
   uint16_t codec_uuid;
 
   if (p_scb->codec_fallback) {
@@ -1734,7 +1743,7 @@
 
   /* send +BCS */
   APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid);
-  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, NULL, codec_uuid);
+  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, nullptr, codec_uuid);
 }
 
 /*******************************************************************************
@@ -1747,9 +1756,17 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_send_ring(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_send_ring(tBTA_AG_SCB* p_scb,
+                      UNUSED_ATTR const tBTA_AG_DATA& data) {
+  if ((p_scb->conn_service == BTA_AG_HFP) &&
+      p_scb->callsetup_ind != BTA_AG_CALLSETUP_INCOMING) {
+    LOG(WARNING) << __func__ << ": don't send RING, conn_service="
+                 << std::to_string(p_scb->conn_service)
+                 << ", callsetup_ind=" << std::to_string(p_scb->callsetup_ind);
+    return;
+  }
   /* send RING */
-  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_RING, NULL, 0);
+  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_RING, nullptr, 0);
 
   /* if HFP and clip enabled and clip data send CLIP */
   if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled &&
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index 3ebf369..c6b3230 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,11 +32,6 @@
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
-/* Number of SCBs (AG service instances that can be registered) */
-#ifndef BTA_AG_NUM_SCB
-#define BTA_AG_NUM_SCB 2
-#endif
-
 /* Time to wait for retry in case of collision */
 #ifndef BTA_AG_COLLISION_TIMEOUT_MS
 #define BTA_AG_COLLISION_TIMEOUT_MS (2 * 1000) /* 2 seconds */
@@ -58,14 +53,6 @@
 #define BTA_AG_ACP 0 /* accepted connection */
 #define BTA_AG_INT 1 /* initiating connection */
 
-/* feature mask that matches spec */
-#define BTA_AG_BSRF_FEAT_SPEC                                   \
-  (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_VREC |     \
-   BTA_AG_FEAT_INBAND | BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
-   BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | BTA_AG_FEAT_EXTERR |     \
-   BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO |  \
-   BTA_AG_FEAT_VOIP)
-
 #define BTA_AG_SDP_FEAT_SPEC                                \
   (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_VREC | \
    BTA_AG_FEAT_INBAND | BTA_AG_FEAT_VTAG)
@@ -90,17 +77,10 @@
   BTA_AG_DISC_INT_RES_EVT,
   BTA_AG_DISC_OK_EVT,
   BTA_AG_DISC_FAIL_EVT,
-  BTA_AG_CI_RX_WRITE_EVT,
   BTA_AG_RING_TIMEOUT_EVT,
   BTA_AG_SVC_TIMEOUT_EVT,
-  BTA_AG_CI_SCO_DATA_EVT,
-  BTA_AG_CI_SLC_READY_EVT,
+  BTA_AG_COLLISION_EVT,
   BTA_AG_MAX_EVT,
-
-  /* these events are handled outside of the state machine */
-  BTA_AG_API_ENABLE_EVT,
-  BTA_AG_API_DISABLE_EVT,
-  BTA_AG_API_SET_SCO_ALLOWED_EVT
 };
 
 /* Actions to perform after a SCO event */
@@ -134,16 +114,8 @@
  *  Data types
  ****************************************************************************/
 
-/* data type for BTA_AG_API_ENABLE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_AG_PARSE_MODE parse_mode;
-  tBTA_AG_CBACK* p_cback;
-} tBTA_AG_API_ENABLE;
-
 /* data type for BTA_AG_API_REGISTER_EVT */
 typedef struct {
-  BT_HDR hdr;
   char p_name[2][BTA_SERVICE_NAME_LEN + 1];
   tBTA_SERVICE_MASK services;
   tBTA_SEC sec_mask;
@@ -153,61 +125,58 @@
 
 /* data type for BTA_AG_API_OPEN_EVT */
 typedef struct {
-  BT_HDR hdr;
   RawAddress bd_addr;
-  tBTA_SERVICE_MASK services;
   tBTA_SEC sec_mask;
 } tBTA_AG_API_OPEN;
 
 /* data type for BTA_AG_API_RESULT_EVT */
 typedef struct {
-  BT_HDR hdr;
   tBTA_AG_RES result;
   tBTA_AG_RES_DATA data;
 } tBTA_AG_API_RESULT;
 
 /* data type for BTA_AG_API_SETCODEC_EVT */
 typedef struct {
-  BT_HDR hdr;
   tBTA_AG_PEER_CODEC codec;
 } tBTA_AG_API_SETCODEC;
 
-/* data type for BTA_AG_API_SET_SCO_ALLOWED_EVT */
-typedef struct {
-  BT_HDR hdr;
-  bool value;
-} tBTA_AG_API_SET_SCO_ALLOWED;
-
 /* data type for BTA_AG_DISC_RESULT_EVT */
 typedef struct {
-  BT_HDR hdr;
   uint16_t status;
 } tBTA_AG_DISC_RESULT;
 
 /* data type for RFCOMM events */
 typedef struct {
-  BT_HDR hdr;
   uint16_t port_handle;
 } tBTA_AG_RFC;
 
-/* data type for BTA_AG_CI_RX_WRITE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  //    char            p_data[BTA_AG_MTU+1];
-} tBTA_AG_CI_RX_WRITE;
-
 /* union of all event datatypes */
-typedef union {
-  BT_HDR hdr;
-  tBTA_AG_API_ENABLE api_enable;
+union tBTA_AG_DATA {
   tBTA_AG_API_REGISTER api_register;
   tBTA_AG_API_OPEN api_open;
   tBTA_AG_API_RESULT api_result;
   tBTA_AG_API_SETCODEC api_setcodec;
   tBTA_AG_DISC_RESULT disc_result;
   tBTA_AG_RFC rfc;
-  tBTA_AG_CI_RX_WRITE ci_rx_write;
-} tBTA_AG_DATA;
+  static const tBTA_AG_DATA kEmpty;
+
+  /**
+   * Check if two tBTA_AG_DATA are equal in memory
+   *
+   * @param rhs other tBTA_AG_DATA
+   * @return true if both unions are equal in memory
+   */
+  bool operator==(const tBTA_AG_DATA& rhs) const {
+    return (std::memcmp(this, &rhs, sizeof(tBTA_AG_DATA)) == 0);
+  }
+
+  /**
+   * Check if this union is empty by comparing it to the kEmpty constant
+   *
+   * @return true if this union is empty
+   */
+  bool IsEmpty() const { return *this == kEmpty; }
+};
 
 /* type for each profile */
 typedef struct {
@@ -221,7 +190,7 @@
 } tBTA_AG_SCO_MSBC_SETTINGS;
 
 /* type for each service control block */
-typedef struct {
+struct tBTA_AG_SCB {
   char clip[BTA_AG_AT_MAX_LEN + 1];     /* number string used for CLIP */
   uint16_t serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
   tBTA_AG_AT_CB at_cb;                  /* AT command interpreter */
@@ -234,6 +203,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 */
@@ -262,6 +232,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
@@ -277,7 +248,7 @@
   tBTA_AG_HF_IND
       local_hf_indicators[BTA_AG_MAX_NUM_LOCAL_HF_IND]; /* Local supported
                                                     HF indicators */
-} tBTA_AG_SCB;
+};
 
 /* type for sco data */
 typedef struct {
@@ -291,11 +262,10 @@
 
 /* type for AG control block */
 typedef struct {
-  tBTA_AG_SCB scb[BTA_AG_NUM_SCB];         /* service control blocks */
+  tBTA_AG_SCB scb[BTA_AG_MAX_NUM_CLIENTS]; /* service control blocks */
   tBTA_AG_PROFILE profile[BTA_AG_NUM_IDX]; /* profile-specific data */
   tBTA_AG_SCO_CB sco;                      /* SCO data */
   tBTA_AG_CBACK* p_cback;                  /* application callback */
-  tBTA_AG_PARSE_MODE parse_mode;           /* parse/pass-through mode */
 } tBTA_AG_CB;
 
 /*****************************************************************************
@@ -311,12 +281,24 @@
 extern tBTA_AG_CB bta_ag_cb;
 
 /* config struct */
-extern tBTA_AG_CFG* p_bta_ag_cfg;
+extern const tBTA_AG_CFG* p_bta_ag_cfg;
 extern const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[];
 
 /*****************************************************************************
  *  Function prototypes
  ****************************************************************************/
+bool bta_ag_hdl_event(BT_HDR* p_msg);
+
+/* API functions */
+extern void bta_ag_api_enable(tBTA_AG_CBACK* p_cback);
+extern void bta_ag_api_disable();
+extern void bta_ag_api_set_active_device(const RawAddress& new_active_device);
+extern void bta_ag_api_register(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+                                tBTA_AG_FEAT features,
+                                const std::vector<std::string>& service_names,
+                                uint8_t app_id);
+extern void bta_ag_api_result(uint16_t handle, tBTA_AG_RES result,
+                              const tBTA_AG_RES_DATA& result_data);
 
 /* main functions */
 extern void bta_ag_scb_dealloc(tBTA_AG_SCB* p_scb);
@@ -326,23 +308,23 @@
 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,
-                              tBTA_AG_DATA* p_data);
-extern bool bta_ag_hdl_event(BT_HDR* p_msg);
+                              const tBTA_AG_DATA& data);
+extern void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event,
+                                        const tBTA_AG_DATA& data);
 extern void bta_ag_collision_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                                   uint8_t app_id, const RawAddress* peer_addr);
+                                   uint8_t app_id, const RawAddress& peer_addr);
 extern void bta_ag_resume_open(tBTA_AG_SCB* p_scb);
 
 /* SDP functions */
-extern bool bta_ag_add_record(uint16_t service_uuid, char* p_service_name,
+extern bool bta_ag_add_record(uint16_t service_uuid, const char* p_service_name,
                               uint8_t scn, tBTA_AG_FEAT features,
                               uint32_t sdp_handle);
-extern void bta_ag_create_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_del_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_create_records(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_del_records(tBTA_AG_SCB* p_scb);
 extern bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service);
 extern void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service);
-extern void bta_ag_free_db(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_free_db(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
 
 /* RFCOMM functions */
 extern void bta_ag_start_servers(tBTA_AG_SCB* p_scb,
@@ -350,57 +332,62 @@
 extern void bta_ag_close_servers(tBTA_AG_SCB* p_scb,
                                  tBTA_SERVICE_MASK services);
 extern bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb);
-extern void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
 
 /* SCO functions */
+extern bool bta_ag_sco_is_active_device(const RawAddress& bd_addr);
 extern bool bta_ag_sco_is_open(tBTA_AG_SCB* p_scb);
 extern bool bta_ag_sco_is_opening(tBTA_AG_SCB* p_scb);
 extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb,
-                                tBTM_ESCO_CONN_REQ_EVT_DATA* p_data);
+                                tBTM_ESCO_CONN_REQ_EVT_DATA* data);
 
 /* AT command functions */
 extern void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd,
                                 uint8_t arg_type, char* p_arg, int16_t int_arg);
 extern void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd,
                                 uint8_t arg_type, char* p_arg, int16_t int_arg);
-extern void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown,
+                                const char* p_arg);
 extern bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb);
 extern void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result);
 
 /* Action functions */
-extern void bta_ag_register(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_deregister(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_start_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_start_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_open_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_register(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_deregister(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_start_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_open_fail(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_sco_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_sco_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+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);
 extern void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb);
-extern void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_setcodec(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_send_ring(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_ci_sco_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_ci_rx_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
-extern void bta_ag_set_sco_allowed(tBTA_AG_DATA* p_data);
+extern void bta_ag_send_bcs(tBTA_AG_SCB* p_scb);
+extern void bta_ag_set_sco_allowed(bool value);
+extern const RawAddress& bta_ag_get_active_device();
+extern void bta_clear_active_device();
 
 #endif /* BTA_AG_INT_H */
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index d33247e..996aa25 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@
  *
  ******************************************************************************/
 
+#include <stack/include/bt_types.h>
 #include <string.h>
 
-#include "bta_ag_co.h"
 #include "bta_ag_int.h"
 #include "bta_api.h"
 #include "bta_sys.h"
@@ -34,15 +34,6 @@
 /*****************************************************************************
  * Constants and types
  ****************************************************************************/
-#ifndef BTA_AG_DEBUG
-#define BTA_AG_DEBUG FALSE
-#endif
-
-#if (BTA_AG_DEBUG == TRUE)
-static char* bta_ag_evt_str(uint16_t event, tBTA_AG_RES result);
-static char* bta_ag_state_str(uint8_t state);
-#endif
-
 /* state machine states */
 enum { BTA_AG_INIT_ST, BTA_AG_OPENING_ST, BTA_AG_OPEN_ST, BTA_AG_CLOSING_ST };
 
@@ -77,16 +68,88 @@
   BTA_AG_RESULT,
   BTA_AG_SETCODEC,
   BTA_AG_SEND_RING,
-  BTA_AG_CI_SCO_DATA,
-  BTA_AG_CI_RX_DATA,
-  BTA_AG_RCVD_SLC_READY,
+  BTA_AG_HANDLE_COLLISION,
   BTA_AG_NUM_ACTIONS
 };
 
 #define BTA_AG_IGNORE BTA_AG_NUM_ACTIONS
 
 /* type for action functions */
-typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+
+static const char* bta_ag_res_str(tBTA_AG_RES result) {
+  switch (result) {
+    CASE_RETURN_STR(BTA_AG_SPK_RES)
+    CASE_RETURN_STR(BTA_AG_MIC_RES)
+    CASE_RETURN_STR(BTA_AG_INBAND_RING_RES)
+    CASE_RETURN_STR(BTA_AG_CIND_RES)
+    CASE_RETURN_STR(BTA_AG_BINP_RES)
+    CASE_RETURN_STR(BTA_AG_IND_RES)
+    CASE_RETURN_STR(BTA_AG_BVRA_RES)
+    CASE_RETURN_STR(BTA_AG_CNUM_RES)
+    CASE_RETURN_STR(BTA_AG_BTRH_RES)
+    CASE_RETURN_STR(BTA_AG_CLCC_RES)
+    CASE_RETURN_STR(BTA_AG_COPS_RES)
+    CASE_RETURN_STR(BTA_AG_IN_CALL_RES)
+    CASE_RETURN_STR(BTA_AG_IN_CALL_CONN_RES)
+    CASE_RETURN_STR(BTA_AG_CALL_WAIT_RES)
+    CASE_RETURN_STR(BTA_AG_OUT_CALL_ORIG_RES)
+    CASE_RETURN_STR(BTA_AG_OUT_CALL_ALERT_RES)
+    CASE_RETURN_STR(BTA_AG_OUT_CALL_CONN_RES)
+    CASE_RETURN_STR(BTA_AG_CALL_CANCEL_RES)
+    CASE_RETURN_STR(BTA_AG_END_CALL_RES)
+    CASE_RETURN_STR(BTA_AG_IN_CALL_HELD_RES)
+    CASE_RETURN_STR(BTA_AG_UNAT_RES)
+    CASE_RETURN_STR(BTA_AG_MULTI_CALL_RES)
+    CASE_RETURN_STR(BTA_AG_BIND_RES)
+    CASE_RETURN_STR(BTA_AG_IND_RES_ON_DEMAND)
+    default:
+      return "Unknown AG Result";
+  }
+}
+
+static const char* bta_ag_evt_str(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_AG_API_REGISTER_EVT)
+    CASE_RETURN_STR(BTA_AG_API_DEREGISTER_EVT)
+    CASE_RETURN_STR(BTA_AG_API_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AG_API_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_API_AUDIO_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AG_API_AUDIO_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_API_RESULT_EVT)
+    CASE_RETURN_STR(BTA_AG_API_SETCODEC_EVT)
+    CASE_RETURN_STR(BTA_AG_RFC_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AG_RFC_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_RFC_SRV_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_RFC_DATA_EVT)
+    CASE_RETURN_STR(BTA_AG_SCO_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AG_SCO_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_DISC_ACP_RES_EVT)
+    CASE_RETURN_STR(BTA_AG_DISC_INT_RES_EVT)
+    CASE_RETURN_STR(BTA_AG_DISC_OK_EVT)
+    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";
+  }
+}
+
+static const char* bta_ag_state_str(uint8_t state) {
+  switch (state) {
+    CASE_RETURN_STR(BTA_AG_INIT_ST)
+    CASE_RETURN_STR(BTA_AG_OPENING_ST)
+    CASE_RETURN_STR(BTA_AG_OPEN_ST)
+    CASE_RETURN_STR(BTA_AG_CLOSING_ST)
+    default:
+      return "Unknown AG State";
+  }
+}
 
 /* action functions */
 const tBTA_AG_ACTION bta_ag_action[] = {
@@ -99,8 +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_ci_sco_data,
-    bta_ag_ci_rx_data,     bta_ag_rcvd_slc_ready};
+    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 */
@@ -128,18 +194,16 @@
     /* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
     /* 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},
-    /* CI_RX_WRITE_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},
-    /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
-    /* CI_SLC_READY_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] = {
     /* Event                    Action 1                Action 2 Next state */
     /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
-    /* API_DEREGISTER_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG,
-                              BTA_AG_CLOSING_ST},
+    /* API_DEREGISTER_EVT */
+    {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST},
     /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
     /* API_CLOSE_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
@@ -151,25 +215,24 @@
     /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
     /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
     /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
-    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,
-                         BTA_AG_OPENING_ST},
+    /* SCO_CLOSE_EVT */
+    {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
     /* DISC_ACP_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
-    /* DISC_INT_RES_EVT */ {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE,
-                            BTA_AG_OPENING_ST},
+    /* DISC_INT_RES_EVT */
+    {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
     /* 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},
-    /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_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},
-    /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
-    /* CI_SLC_READY_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] = {
     /* Event                    Action 1                Action 2 Next state */
     /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
-    /* API_DEREGISTER_EVT */ {BTA_AG_START_CLOSE, BTA_AG_START_DEREG,
-                              BTA_AG_CLOSING_ST},
+    /* API_DEREGISTER_EVT */
+    {BTA_AG_START_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST},
     /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
     /* API_CLOSE_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* API_AUDIO_OPEN_EVT */ {BTA_AG_SCO_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
@@ -180,27 +243,24 @@
     /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
     /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
     /* RFC_DATA_EVT */ {BTA_AG_RFC_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
-    /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN,
-                        BTA_AG_OPEN_ST},
-    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,
-                         BTA_AG_OPEN_ST},
+    /* SCO_OPEN_EVT */
+    {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN, BTA_AG_OPEN_ST},
+    /* SCO_CLOSE_EVT */
+    {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_OPEN_ST},
     /* DISC_ACP_RES_EVT */ {BTA_AG_DISC_ACP_RES, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
     /* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
     /* 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},
-    /* CI_RX_WRITE_EVT */ {BTA_AG_CI_RX_DATA, 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},
-    /* CI_SCO_DATA_EVT */ {BTA_AG_CI_SCO_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
-    /* CI_SLC_READY_EVT */
-    {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE, BTA_AG_OPEN_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] = {
     /* Event                    Action 1                Action 2 Next state */
     /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
-    /* API_DEREGISTER_EVT */ {BTA_AG_START_DEREG, BTA_AG_IGNORE,
-                              BTA_AG_CLOSING_ST},
+    /* API_DEREGISTER_EVT */
+    {BTA_AG_START_DEREG, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
@@ -212,17 +272,26 @@
     /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
-    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,
-                         BTA_AG_CLOSING_ST},
+    /* SCO_CLOSE_EVT */
+    {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_CLOSING_ST},
     /* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* DISC_INT_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
     /* 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},
-    /* CI_RX_WRITE_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},
-    /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
-    /* CI_SLC_READY_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];
@@ -237,6 +306,7 @@
 
 /* AG control block */
 tBTA_AG_CB bta_ag_cb;
+const tBTA_AG_DATA tBTA_AG_DATA::kEmpty = {};
 
 /*******************************************************************************
  *
@@ -252,15 +322,19 @@
   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
   int i;
 
-  for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+  for (i = 0; i < BTA_AG_MAX_NUM_CLIENTS; i++, p_scb++) {
     if (!p_scb->in_use) {
       /* 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");
@@ -273,9 +347,9 @@
     }
   }
 
-  if (i == BTA_AG_NUM_SCB) {
+  if (i == BTA_AG_MAX_NUM_CLIENTS) {
     /* out of scbs */
-    p_scb = NULL;
+    p_scb = nullptr;
     APPL_TRACE_WARNING("%s: Out of scbs", __func__);
   }
   return p_scb;
@@ -303,12 +377,12 @@
   alarm_free(p_scb->collision_timer);
 
   /* initialize control block */
-  memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+  *p_scb = {};
   p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
 
   /* If all scbs are deallocated, callback with disable event */
   if (!bta_sys_is_register(BTA_ID_AG)) {
-    for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+    for (idx = 0; idx < BTA_AG_MAX_NUM_CLIENTS; idx++) {
       if (bta_ag_cb.scb[idx].in_use) {
         allocated = true;
         break;
@@ -316,7 +390,7 @@
     }
 
     if (!allocated) {
-      (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+      (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, nullptr);
     }
   }
 }
@@ -328,12 +402,12 @@
  * Description      Given a pointer to an scb, return its index.
  *
  *
- * Returns          Index of scb.
+ * Returns          Index of scb starting from 1
  *
  ******************************************************************************/
 uint16_t bta_ag_scb_to_idx(tBTA_AG_SCB* p_scb) {
   /* use array arithmetic to determine index */
-  return ((uint16_t)(p_scb - bta_ag_cb.scb)) + 1;
+  return static_cast<uint16_t>(p_scb - bta_ag_cb.scb + 1);
 }
 
 /*******************************************************************************
@@ -350,14 +424,14 @@
   tBTA_AG_SCB* p_scb;
 
   /* verify index */
-  if (idx > 0 && idx <= BTA_AG_NUM_SCB) {
+  if (idx > 0 && idx <= BTA_AG_MAX_NUM_CLIENTS) {
     p_scb = &bta_ag_cb.scb[idx - 1];
     if (!p_scb->in_use) {
-      p_scb = NULL;
+      p_scb = nullptr;
       APPL_TRACE_WARNING("ag scb idx %d not allocated", idx);
     }
   } else {
-    p_scb = NULL;
+    p_scb = nullptr;
     APPL_TRACE_DEBUG("ag scb idx %d out of range", idx);
   }
   return p_scb;
@@ -393,10 +467,8 @@
  ******************************************************************************/
 uint16_t bta_ag_idx_by_bdaddr(const RawAddress* peer_addr) {
   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
-  uint16_t i;
-
-  if (peer_addr != NULL) {
-    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+  if (peer_addr != nullptr) {
+    for (uint16_t i = 0; i < BTA_AG_MAX_NUM_CLIENTS; i++, p_scb++) {
       if (p_scb->in_use && *peer_addr == p_scb->peer_addr) {
         return (i + 1);
       }
@@ -420,15 +492,12 @@
  ******************************************************************************/
 bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb) {
   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
-  int i;
-
-  for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+  for (int i = 0; i < BTA_AG_MAX_NUM_CLIENTS; i++, p_scb++) {
     if (p_scb->in_use && p_scb != p_curr_scb &&
         p_scb->state == BTA_AG_OPEN_ST) {
       return true;
     }
   }
-
   /* no other scb found */
   APPL_TRACE_DEBUG("No other ag scb open");
   return false;
@@ -445,57 +514,8 @@
  *
  ******************************************************************************/
 bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb) {
-  if (p_curr_scb && p_curr_scb->in_use && p_curr_scb->state == BTA_AG_OPEN_ST) {
-    return true;
-  }
-
-  return false;
-}
-
-/*******************************************************************************
- *
- * 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_NUM_SCB; 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 NULL;
-}
-
-/*******************************************************************************
- *
- * 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);
+  return p_curr_scb && p_curr_scb->in_use &&
+         p_curr_scb->state == BTA_AG_OPEN_ST;
 }
 
 /*******************************************************************************
@@ -510,41 +530,23 @@
  ******************************************************************************/
 void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, uint8_t id,
                             UNUSED_ATTR uint8_t app_id,
-                            const RawAddress* peer_addr) {
-  uint16_t handle;
-  tBTA_AG_SCB* p_scb;
-
+                            const RawAddress& peer_addr) {
   /* Check if we have opening scb for the peer device. */
-  handle = bta_ag_idx_by_bdaddr(peer_addr);
-  p_scb = bta_ag_scb_by_idx(handle);
+  uint16_t handle = bta_ag_idx_by_bdaddr(&peer_addr);
+  tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle);
 
   if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
-    if (id == BTA_ID_SYS) /* ACL collision */
-    {
-      APPL_TRACE_WARNING("AG found collision (ACL) ...");
-    } else if (id == BTA_ID_AG) /* RFCOMM collision */
-    {
-      APPL_TRACE_WARNING("AG found collision (RFCOMM) ...");
+    if (id == BTA_ID_SYS) {
+      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 "
+                   << unsigned(handle) << " device " << peer_addr;
     } else {
-      APPL_TRACE_WARNING("AG found collision (\?\?\?) ...");
+      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) {
-      (void)SDP_CancelServiceSearch(p_scb->p_disc_db);
-      bta_ag_free_db(p_scb, NULL);
-    }
-
-    /* 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);
   }
 }
 
@@ -559,17 +561,15 @@
  *
  ******************************************************************************/
 void bta_ag_resume_open(tBTA_AG_SCB* p_scb) {
-  if (p_scb) {
-    APPL_TRACE_DEBUG("bta_ag_resume_open, Handle(%d)",
-                     bta_ag_scb_to_idx(p_scb));
-
-    /* resume opening process.  */
-    if (p_scb->state == BTA_AG_INIT_ST) {
-      p_scb->state = BTA_AG_OPENING_ST;
-      bta_ag_start_open(p_scb, NULL);
-    }
+  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.sec_mask = p_scb->cli_sec_mask};
+    bta_ag_sm_execute(p_scb, BTA_AG_API_OPEN_EVT, open_data);
   } else {
-    APPL_TRACE_ERROR("bta_ag_resume_open, Null p_scb");
+    VLOG(1) << __func__ << ": device " << p_scb->peer_addr
+            << " is already in state " << std::to_string(p_scb->state);
   }
 }
 
@@ -583,26 +583,25 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_ag_api_enable(tBTA_AG_DATA* p_data) {
+void bta_ag_api_enable(tBTA_AG_CBACK* p_cback) {
   /* initialize control block */
-  for (size_t i = 0; i < BTA_AG_NUM_SCB; i++) {
-    alarm_free(bta_ag_cb.scb[i].ring_timer);
-    alarm_free(bta_ag_cb.scb[i].codec_negotiation_timer);
-    alarm_free(bta_ag_cb.scb[i].collision_timer);
+  for (tBTA_AG_SCB& scb : bta_ag_cb.scb) {
+    alarm_free(scb.ring_timer);
+    alarm_free(scb.codec_negotiation_timer);
+    alarm_free(scb.collision_timer);
+    scb = {};
   }
-  memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
 
   /* store callback function */
-  bta_ag_cb.p_cback = p_data->api_enable.p_cback;
-  bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+  bta_ag_cb.p_cback = p_cback;
 
   /* call init call-out */
-  bta_ag_co_init();
+  BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
 
   bta_sys_collision_register(BTA_ID_AG, bta_ag_collision_cback);
 
   /* call callback with enable event */
-  (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+  (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, nullptr);
 }
 
 /*******************************************************************************
@@ -615,7 +614,7 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_ag_api_disable(tBTA_AG_DATA* p_data) {
+void bta_ag_api_disable() {
   /* deregister all scbs in use */
   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
   bool do_dereg = false;
@@ -629,19 +628,19 @@
   /* De-register with BTA system manager */
   bta_sys_deregister(BTA_ID_AG);
 
-  for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+  for (i = 0; i < BTA_AG_MAX_NUM_CLIENTS; i++, p_scb++) {
     if (p_scb->in_use) {
-      bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+      bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, tBTA_AG_DATA::kEmpty);
       do_dereg = true;
     }
   }
 
   if (!do_dereg) {
     /* Done, send callback evt to app */
-    (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+    (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, nullptr);
   }
 
-  bta_sys_collision_register(BTA_ID_AG, NULL);
+  bta_sys_collision_register(BTA_ID_AG, nullptr);
 }
 
 /*******************************************************************************
@@ -654,18 +653,31 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_ag_api_register(tBTA_AG_DATA* p_data) {
-  tBTA_AG_SCB* p_scb;
-  tBTA_AG_REGISTER reg;
-
-  /* allocate an scb */
-  p_scb = bta_ag_scb_alloc();
-  if (p_scb != NULL) {
+void bta_ag_api_register(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+                         tBTA_AG_FEAT features,
+                         const std::vector<std::string>& service_names,
+                         uint8_t app_id) {
+  tBTA_AG_SCB* p_scb = bta_ag_scb_alloc();
+  if (p_scb) {
     APPL_TRACE_DEBUG("bta_ag_api_register: p_scb 0x%08x ", p_scb);
-    bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+    tBTA_AG_DATA data = {};
+    data.api_register.features = features;
+    data.api_register.sec_mask = sec_mask;
+    data.api_register.services = services;
+    data.api_register.app_id = app_id;
+    for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
+      if (!service_names[i].empty()) {
+        strlcpy(data.api_register.p_name[i], service_names[i].c_str(),
+                BTA_SERVICE_NAME_LEN);
+      } else {
+        data.api_register.p_name[i][0] = 0;
+      }
+    }
+    bta_ag_sm_execute(p_scb, BTA_AG_API_REGISTER_EVT, data);
   } else {
-    reg.status = BTA_AG_FAIL_RESOURCES;
-    (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG*)&reg);
+    tBTA_AG bta_ag = {};
+    bta_ag.reg.status = BTA_AG_FAIL_RESOURCES;
+    (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, &bta_ag);
   }
 }
 
@@ -679,21 +691,27 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_ag_api_result(tBTA_AG_DATA* p_data) {
+void bta_ag_api_result(uint16_t handle, tBTA_AG_RES result,
+                       const tBTA_AG_RES_DATA& result_data) {
+  tBTA_AG_DATA event_data = {};
+  event_data.api_result.result = result;
+  event_data.api_result.data = result_data;
   tBTA_AG_SCB* p_scb;
-  int i;
-
-  if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL) {
-    p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific);
-    if (p_scb != NULL) {
+  if (handle != BTA_AG_HANDLE_ALL) {
+    p_scb = bta_ag_scb_by_idx(handle);
+    if (p_scb) {
       APPL_TRACE_DEBUG("bta_ag_api_result: p_scb 0x%08x ", p_scb);
-      bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+      bta_ag_sm_execute(p_scb, static_cast<uint16_t>(BTA_AG_API_RESULT_EVT),
+                        event_data);
     }
   } else {
-    for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+    int i;
+    for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_MAX_NUM_CLIENTS;
+         i++, p_scb++) {
       if (p_scb->in_use && p_scb->svc_conn) {
         APPL_TRACE_DEBUG("bta_ag_api_result p_scb 0x%08x ", p_scb);
-        bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+        bta_ag_sm_execute(p_scb, static_cast<uint16_t>(BTA_AG_API_RESULT_EVT),
+                          event_data);
       }
     }
   }
@@ -710,30 +728,19 @@
  *
  ******************************************************************************/
 void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
-                       tBTA_AG_DATA* p_data) {
+                       const tBTA_AG_DATA& data) {
   tBTA_AG_ST_TBL state_table;
   uint8_t action;
   int i;
-#if (BTA_AG_DEBUG == TRUE)
   uint16_t previous_event = event;
   uint8_t previous_state = p_scb->state;
 
-  /* Ignore displaying of AT results when not connected (Ignored in state
-   * machine) */
-  if ((previous_event != BTA_AG_API_RESULT_EVT ||
-       p_scb->state == BTA_AG_OPEN_ST) &&
-      event != BTA_AG_CI_SCO_DATA_EVT) {
-    APPL_TRACE_EVENT("%s: Handle 0x%04x, State %d (%s), Event 0x%04x (%s)",
-                     __func__, bta_ag_scb_to_idx(p_scb), p_scb->state,
-                     bta_ag_state_str(p_scb->state), event,
-                     bta_ag_evt_str(event, p_data->api_result.result));
-  }
-#else
-  if (event != BTA_AG_CI_SCO_DATA_EVT) {
-    APPL_TRACE_EVENT("%s: Handle 0x%04x, State %d, Event 0x%04x", __func__,
-                     bta_ag_scb_to_idx(p_scb), p_scb->state, event);
-  }
-#endif
+  APPL_TRACE_EVENT(
+      "%s: handle=0x%04x, bd_addr=%s, state=%s(0x%02x), "
+      "event=%s(0x%04x), result=%s(0x%02x)",
+      __func__, bta_ag_scb_to_idx(p_scb), p_scb->peer_addr.ToString().c_str(),
+      bta_ag_state_str(p_scb->state), p_scb->state, bta_ag_evt_str(event),
+      event, bta_ag_res_str(data.api_result.result), data.api_result.result);
 
   event &= 0x00FF;
   if (event >= (BTA_AG_MAX_EVT & 0x00FF)) {
@@ -751,182 +758,50 @@
   for (i = 0; i < BTA_AG_ACTIONS; i++) {
     action = state_table[event][i];
     if (action != BTA_AG_IGNORE) {
-      (*bta_ag_action[action])(p_scb, p_data);
+      (*bta_ag_action[action])(p_scb, data);
     } else {
       break;
     }
   }
-#if (BTA_AG_DEBUG == TRUE)
   if (p_scb->state != previous_state) {
-    APPL_TRACE_EVENT("%s: State Change: [%s] -> [%s] after Event [%s]",
-                     __func__, bta_ag_state_str(previous_state),
-                     bta_ag_state_str(p_scb->state),
-                     bta_ag_evt_str(previous_event, p_data->api_result.result));
+    APPL_TRACE_EVENT(
+        "%s: handle=0x%04x, bd_addr=%s, state_change[%s(0x%02x)]->[%s(0x%02x)],"
+        " event[%s(0x%04x)], result[%s(0x%02x)]",
+        __func__, bta_ag_scb_to_idx(p_scb), p_scb->peer_addr.ToString().c_str(),
+        bta_ag_state_str(previous_state), previous_state,
+        bta_ag_state_str(p_scb->state), p_scb->state,
+        bta_ag_evt_str(previous_event), previous_event,
+        bta_ag_res_str(data.api_result.result), data.api_result.result);
   }
-#endif
 }
 
-/*******************************************************************************
+void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event,
+                                 const tBTA_AG_DATA& data) {
+  tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle);
+  if (p_scb) {
+    APPL_TRACE_DEBUG("%s: p_scb 0x%08x ", __func__, p_scb);
+    bta_ag_sm_execute(p_scb, event, data);
+  }
+}
+
+/**
+ * Handles event from bta_sys_sendmsg(). It is here to support legacy alarm
+ * implementation that is mainly for timeouts.
  *
- * Function         bta_ag_hdl_event
- *
- * Description      Data gateway main event handling function.
- *
- *
- * Returns          bool
- *
- ******************************************************************************/
+ * @param p_msg event message
+ * @return True to free p_msg, or False if p_msg is freed within this function
+ */
 bool bta_ag_hdl_event(BT_HDR* p_msg) {
-  tBTA_AG_SCB* p_scb;
-
-  APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event);
   switch (p_msg->event) {
-    case BTA_AG_API_ENABLE_EVT:
-      bta_ag_api_enable((tBTA_AG_DATA*)p_msg);
+    case BTA_AG_RING_TIMEOUT_EVT:
+    case BTA_AG_SVC_TIMEOUT_EVT:
+      bta_ag_sm_execute_by_handle(p_msg->layer_specific, p_msg->event,
+                                  tBTA_AG_DATA::kEmpty);
       break;
-
-    case BTA_AG_API_DISABLE_EVT:
-      bta_ag_api_disable((tBTA_AG_DATA*)p_msg);
-      break;
-
-    case BTA_AG_API_REGISTER_EVT:
-      bta_ag_api_register((tBTA_AG_DATA*)p_msg);
-      break;
-
-    case BTA_AG_API_RESULT_EVT:
-      bta_ag_api_result((tBTA_AG_DATA*)p_msg);
-      break;
-
-    case BTA_AG_API_SET_SCO_ALLOWED_EVT:
-      bta_ag_set_sco_allowed((tBTA_AG_DATA*)p_msg);
-      break;
-
-    /* all others reference scb by handle */
     default:
-      p_scb = bta_ag_scb_by_idx(p_msg->layer_specific);
-      if (p_scb != NULL) {
-        APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", p_scb);
-        bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA*)p_msg);
-      }
+      LOG(FATAL) << __func__ << ": bad event " << p_msg->event
+                 << " layer_specific=" << p_msg->layer_specific;
       break;
   }
   return true;
 }
-
-#if (BTA_AG_DEBUG == TRUE)
-static char* bta_ag_evt_str(uint16_t event, tBTA_AG_RES result) {
-  switch (event) {
-    case BTA_AG_API_REGISTER_EVT:
-      return "Register Request";
-    case BTA_AG_API_DEREGISTER_EVT:
-      return "Deregister Request";
-    case BTA_AG_API_OPEN_EVT:
-      return "Open SLC Request";
-    case BTA_AG_API_CLOSE_EVT:
-      return "Close SLC Request";
-    case BTA_AG_API_AUDIO_OPEN_EVT:
-      return "Open Audio Request";
-    case BTA_AG_API_AUDIO_CLOSE_EVT:
-      return "Close Audio Request";
-    case BTA_AG_API_RESULT_EVT:
-      switch (result) {
-        case BTA_AG_SPK_RES:
-          return ("AT Result  BTA_AG_SPK_RES");
-        case BTA_AG_MIC_RES:
-          return ("AT Result  BTA_AG_MIC_RES");
-        case BTA_AG_INBAND_RING_RES:
-          return ("AT Result  BTA_AG_INBAND_RING_RES");
-        case BTA_AG_CIND_RES:
-          return ("AT Result  BTA_AG_CIND_RES");
-        case BTA_AG_BINP_RES:
-          return ("AT Result  BTA_AG_BINP_RES");
-        case BTA_AG_IND_RES:
-          return ("AT Result  BTA_AG_IND_RES");
-        case BTA_AG_BVRA_RES:
-          return ("AT Result  BTA_AG_BVRA_RES");
-        case BTA_AG_CNUM_RES:
-          return ("AT Result  BTA_AG_CNUM_RES");
-        case BTA_AG_BTRH_RES:
-          return ("AT Result  BTA_AG_BTRH_RES");
-        case BTA_AG_CLCC_RES:
-          return ("AT Result  BTA_AG_CLCC_RES");
-        case BTA_AG_COPS_RES:
-          return ("AT Result  BTA_AG_COPS_RES");
-        case BTA_AG_IN_CALL_RES:
-          return ("AT Result  BTA_AG_IN_CALL_RES");
-        case BTA_AG_IN_CALL_CONN_RES:
-          return ("AT Result  BTA_AG_IN_CALL_CONN_RES");
-        case BTA_AG_CALL_WAIT_RES:
-          return ("AT Result  BTA_AG_CALL_WAIT_RES");
-        case BTA_AG_OUT_CALL_ORIG_RES:
-          return ("AT Result  BTA_AG_OUT_CALL_ORIG_RES");
-        case BTA_AG_OUT_CALL_ALERT_RES:
-          return ("AT Result  BTA_AG_OUT_CALL_ALERT_RES");
-        case BTA_AG_OUT_CALL_CONN_RES:
-          return ("AT Result  BTA_AG_OUT_CALL_CONN_RES");
-        case BTA_AG_CALL_CANCEL_RES:
-          return ("AT Result  BTA_AG_CALL_CANCEL_RES");
-        case BTA_AG_END_CALL_RES:
-          return ("AT Result  BTA_AG_END_CALL_RES");
-        case BTA_AG_UNAT_RES:
-          return ("AT Result  BTA_AG_UNAT_RES");
-        default:
-          return ("Unknown AG Result");
-      }
-    case BTA_AG_API_SETCODEC_EVT:
-      return "Set Codec Request";
-    case BTA_AG_RFC_OPEN_EVT:
-      return "RFC Opened";
-    case BTA_AG_RFC_CLOSE_EVT:
-      return "RFC Closed";
-    case BTA_AG_RFC_SRV_CLOSE_EVT:
-      return "RFC SRV Closed";
-    case BTA_AG_RFC_DATA_EVT:
-      return "RFC Data";
-    case BTA_AG_SCO_OPEN_EVT:
-      return "Audio Opened";
-    case BTA_AG_SCO_CLOSE_EVT:
-      return "Audio Closed";
-    case BTA_AG_DISC_ACP_RES_EVT:
-      return "Discovery ACP Result";
-    case BTA_AG_DISC_INT_RES_EVT:
-      return "Discovery INT Result";
-    case BTA_AG_DISC_OK_EVT:
-      return "Discovery OK";
-    case BTA_AG_DISC_FAIL_EVT:
-      return "Discovery Failed";
-    case BTA_AG_CI_RX_WRITE_EVT:
-      return "CI RX Write";
-    case BTA_AG_RING_TIMEOUT_EVT:
-      return "Ring Timeout";
-    case BTA_AG_SVC_TIMEOUT_EVT:
-      return "Service Timeout";
-    case BTA_AG_API_ENABLE_EVT:
-      return "Enable AG";
-    case BTA_AG_API_DISABLE_EVT:
-      return "Disable AG";
-    case BTA_AG_CI_SCO_DATA_EVT:
-      return "SCO data Callin";
-    case BTA_AG_CI_SLC_READY_EVT:
-      return "SLC Ready Callin";
-    default:
-      return "Unknown AG Event";
-  }
-}
-
-static char* bta_ag_state_str(uint8_t state) {
-  switch (state) {
-    case BTA_AG_INIT_ST:
-      return "Initial";
-    case BTA_AG_OPENING_ST:
-      return "Opening";
-    case BTA_AG_OPEN_ST:
-      return "Open";
-    case BTA_AG_CLOSING_ST:
-      return "Closing";
-    default:
-      return "Unknown AG State";
-  }
-}
-
-#endif
diff --git a/bta/ag/bta_ag_rfc.cc b/bta/ag/bta_ag_rfc.cc
index 02729d5..ba9bd7f 100644
--- a/bta/ag/bta_ag_rfc.cc
+++ b/bta/ag/bta_ag_rfc.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,14 +23,13 @@
  *
  ******************************************************************************/
 
-#include <string.h>
+#include <cstring>
+
+#include <base/bind.h>
 
 #include "bt_common.h"
 #include "bta_ag_api.h"
-#include "bta_ag_co.h"
 #include "bta_ag_int.h"
-#include "bta_api.h"
-#include "bta_sys.h"
 #include "btm_api.h"
 #include "osi/include/osi.h"
 #include "port_api.h"
@@ -44,26 +43,25 @@
 void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle);
 void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle);
 void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle);
-
+void bta_ag_port_cback_4(uint32_t code, uint16_t port_handle);
+void bta_ag_port_cback_5(uint32_t code, uint16_t port_handle);
+void bta_ag_port_cback_6(uint32_t code, uint16_t port_handle);
 void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle);
 void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle);
 void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle);
-
-int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len);
-int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len);
-int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len);
+void bta_ag_mgmt_cback_4(uint32_t code, uint16_t port_handle);
+void bta_ag_mgmt_cback_5(uint32_t code, uint16_t port_handle);
+void bta_ag_mgmt_cback_6(uint32_t code, uint16_t port_handle);
 
 /* rfcomm callback function tables */
 typedef tPORT_CALLBACK* tBTA_AG_PORT_CBACK;
 const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] = {
-    bta_ag_port_cback_1, bta_ag_port_cback_2, bta_ag_port_cback_3};
+    bta_ag_port_cback_1, bta_ag_port_cback_2, bta_ag_port_cback_3,
+    bta_ag_port_cback_4, bta_ag_port_cback_5, bta_ag_port_cback_6};
 
 const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = {
-    bta_ag_mgmt_cback_1, bta_ag_mgmt_cback_2, bta_ag_mgmt_cback_3};
-
-typedef tPORT_DATA_CALLBACK* tBTA_AG_DATA_CBACK;
-const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] = {
-    bta_ag_data_cback_1, bta_ag_data_cback_2, bta_ag_data_cback_3};
+    bta_ag_mgmt_cback_1, bta_ag_mgmt_cback_2, bta_ag_mgmt_cback_3,
+    bta_ag_mgmt_cback_4, bta_ag_mgmt_cback_5, bta_ag_mgmt_cback_6};
 
 /*******************************************************************************
  *
@@ -77,22 +75,23 @@
  ******************************************************************************/
 static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle,
                               uint16_t handle) {
-  tBTA_AG_SCB* p_scb;
-
-  p_scb = bta_ag_scb_by_idx(handle);
-  if (p_scb != NULL) {
+  tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle);
+  if (p_scb != nullptr) {
     /* ignore port events for port handles other than connected handle */
     if (port_handle != p_scb->conn_handle) {
-      APPL_TRACE_DEBUG(
+      APPL_TRACE_ERROR(
           "ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
           port_handle, p_scb->conn_handle, handle);
       return;
     }
-
-    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-    p_buf->event = BTA_AG_RFC_DATA_EVT;
-    p_buf->layer_specific = handle;
-    bta_sys_sendmsg(p_buf);
+    if (!bta_ag_scb_open(p_scb)) {
+      LOG(ERROR) << __func__ << ": rfcomm data on an unopened control block "
+                 << handle << " peer_addr " << p_scb->peer_addr << " state "
+                 << std::to_string(p_scb->state);
+    }
+    do_in_bta_thread(FROM_HERE,
+                     base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                                BTA_AG_RFC_DATA_EVT, tBTA_AG_DATA::kEmpty));
   }
 }
 
@@ -108,78 +107,61 @@
  ******************************************************************************/
 static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle,
                               uint16_t handle) {
-  tBTA_AG_SCB* p_scb;
+  tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle);
+  APPL_TRACE_DEBUG("%s: code=%d, port_handle=%d, scb_handle=%d, p_scb=0x%08x",
+                   __func__, code, port_handle, handle, p_scb);
+  if (p_scb == nullptr) {
+    LOG(WARNING) << __func__ << ": cannot find scb, code=" << code
+                 << ", port_handle=" << port_handle << ", handle=" << handle;
+    return;
+  }
+  /* ignore close event for port handles other than connected handle */
+  if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) {
+    LOG(WARNING) << __func__ << ": ignore open failure for unmatched "
+                 << "port_handle " << port_handle << ", scb_handle=" << handle;
+    return;
+  }
   uint16_t event;
-  uint8_t i;
-  bool found_handle = false;
-
-  APPL_TRACE_DEBUG("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
-                   code, port_handle, handle);
-
-  p_scb = bta_ag_scb_by_idx(handle);
-  if (p_scb != NULL) {
-    /* ignore close event for port handles other than connected handle */
-    if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) {
-      APPL_TRACE_DEBUG("ag_mgmt_cback ignoring handle:%d", port_handle);
-      return;
-    }
-
-    if (code == PORT_SUCCESS) {
-      if (p_scb->conn_handle) /* Outgoing connection */
-      {
-        if (port_handle == p_scb->conn_handle) found_handle = true;
-      } else /* Incoming connection */
-      {
-        for (i = 0; i < BTA_AG_NUM_IDX; i++) {
-          if (port_handle == p_scb->serv_handle[i]) found_handle = true;
+  if (code == PORT_SUCCESS) {
+    bool found_handle = false;
+    if (p_scb->conn_handle) {
+      /* Outgoing connection */
+      if (port_handle == p_scb->conn_handle) {
+        found_handle = true;
+      }
+    } else {
+      /* Incoming connection */
+      for (uint16_t service_port_handle : p_scb->serv_handle) {
+        if (port_handle == service_port_handle) {
+          found_handle = true;
+          break;
         }
       }
-
-      if (!found_handle) {
-        APPL_TRACE_ERROR(
-            "bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d",
-            port_handle);
-        return;
-      }
-
-      event = BTA_AG_RFC_OPEN_EVT;
     }
+    if (!found_handle) {
+      LOG(ERROR) << __func__ << ": port opened successfully, but port_handle "
+                 << port_handle << " is unknown"
+                 << ", scb_handle=" << handle;
+      return;
+    }
+    event = BTA_AG_RFC_OPEN_EVT;
+  } else if (port_handle == p_scb->conn_handle) {
     /* distinguish server close events */
-    else if (port_handle == p_scb->conn_handle) {
-      event = BTA_AG_RFC_CLOSE_EVT;
-    } else {
-      event = BTA_AG_RFC_SRV_CLOSE_EVT;
-    }
-
-    tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC));
-    p_buf->hdr.event = event;
-    p_buf->hdr.layer_specific = handle;
-    p_buf->port_handle = port_handle;
-    bta_sys_sendmsg(p_buf);
+    event = BTA_AG_RFC_CLOSE_EVT;
+  } else {
+    event = BTA_AG_RFC_SRV_CLOSE_EVT;
   }
+
+  tBTA_AG_DATA data = {};
+  data.rfc.port_handle = port_handle;
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, event, data));
 }
 
 /*******************************************************************************
  *
- * Function         bta_ag_data_cback
- *
- * Description      RFCOMM data callback
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-static int bta_ag_data_cback(UNUSED_ATTR uint16_t port_handle, void* p_data,
-                             uint16_t len, uint16_t handle) {
-  /* call data call-out directly */
-  bta_ag_co_tx_write(handle, (uint8_t*)p_data, len);
-  return 0;
-}
-
-/*******************************************************************************
- *
- * Function         bta_ag_port_cback_1 to 3
- *                  bta_ag_mgmt_cback_1 to 3
+ * Function         bta_ag_port_cback_1 to 6
+ *                  bta_ag_mgmt_cback_1 to 6
  *
  * Description      RFCOMM callback functions.  This is an easy way to
  *                  distinguish scb from the callback.
@@ -188,44 +170,41 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_mgmt_cback_1(uint32_t code, uint16_t handle) {
-  bta_ag_mgmt_cback(code, handle, 1);
+void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle) {
+  bta_ag_mgmt_cback(code, port_handle, 1);
 }
-void bta_ag_mgmt_cback_2(uint32_t code, uint16_t handle) {
-  bta_ag_mgmt_cback(code, handle, 2);
+void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle) {
+  bta_ag_mgmt_cback(code, port_handle, 2);
 }
-void bta_ag_mgmt_cback_3(uint32_t code, uint16_t handle) {
-  bta_ag_mgmt_cback(code, handle, 3);
+void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle) {
+  bta_ag_mgmt_cback(code, port_handle, 3);
 }
-void bta_ag_port_cback_1(uint32_t code, uint16_t handle) {
-  bta_ag_port_cback(code, handle, 1);
+void bta_ag_mgmt_cback_4(uint32_t code, uint16_t port_handle) {
+  bta_ag_mgmt_cback(code, port_handle, 4);
 }
-void bta_ag_port_cback_2(uint32_t code, uint16_t handle) {
-  bta_ag_port_cback(code, handle, 2);
+void bta_ag_mgmt_cback_5(uint32_t code, uint16_t port_handle) {
+  bta_ag_mgmt_cback(code, port_handle, 5);
 }
-void bta_ag_port_cback_3(uint32_t code, uint16_t handle) {
-  bta_ag_port_cback(code, handle, 3);
+void bta_ag_mgmt_cback_6(uint32_t code, uint16_t port_handle) {
+  bta_ag_mgmt_cback(code, port_handle, 6);
 }
-
-/*******************************************************************************
- *
- * Function         bta_ag_data_cback_1 to 3
- *
- * Description      RFCOMM data callback functions.  This is an easy way to
- *                  distinguish scb from the callback.
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len) {
-  return bta_ag_data_cback(port_handle, p_data, len, 1);
+void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle) {
+  bta_ag_port_cback(code, port_handle, 1);
 }
-int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len) {
-  return bta_ag_data_cback(port_handle, p_data, len, 2);
+void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle) {
+  bta_ag_port_cback(code, port_handle, 2);
 }
-int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len) {
-  return bta_ag_data_cback(port_handle, p_data, len, 3);
+void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle) {
+  bta_ag_port_cback(code, port_handle, 3);
+}
+void bta_ag_port_cback_4(uint32_t code, uint16_t port_handle) {
+  bta_ag_port_cback(code, port_handle, 4);
+}
+void bta_ag_port_cback_5(uint32_t code, uint16_t port_handle) {
+  bta_ag_port_cback(code, port_handle, 5);
+}
+void bta_ag_port_cback_6(uint32_t code, uint16_t port_handle) {
+  bta_ag_port_cback(code, port_handle, 6);
 }
 
 /*******************************************************************************
@@ -239,15 +218,17 @@
  *
  ******************************************************************************/
 void bta_ag_setup_port(tBTA_AG_SCB* p_scb, uint16_t handle) {
-  uint16_t i = bta_ag_scb_to_idx(p_scb) - 1;
-
-  /* set up data callback if using pass through mode */
-  if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
-    PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
-  }
-
+  int port_callback_index = bta_ag_scb_to_idx(p_scb) - 1;
+  CHECK_GE(port_callback_index, 0)
+      << "invalid callback index, handle=" << handle << ", bd_addr"
+      << p_scb->peer_addr;
+  CHECK_LT(port_callback_index,
+           static_cast<int>(sizeof(bta_ag_port_cback_tbl) /
+                            sizeof(bta_ag_port_cback_tbl[0])))
+      << "callback index out of bound, handle=" << handle << ", bd_addr"
+      << p_scb->peer_addr;
   PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
-  PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+  PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[port_callback_index]);
 }
 
 /*******************************************************************************
@@ -261,30 +242,36 @@
  *
  ******************************************************************************/
 void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
-  int i;
-  int bta_ag_port_status;
-
   services >>= BTA_HSP_SERVICE_ID;
-  for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+  for (int i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
     /* if service is set in mask */
     if (services & 1) {
       BTM_SetSecurityLevel(false, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
                            BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
                            bta_ag_cb.profile[i].scn);
-
-      bta_ag_port_status = RFCOMM_CreateConnection(
+      int management_callback_index = bta_ag_scb_to_idx(p_scb) - 1;
+      CHECK_GE(management_callback_index, 0)
+          << "invalid callback index, services=" << loghex(services)
+          << ", bd_addr=" << p_scb->peer_addr;
+      CHECK_LT(management_callback_index,
+               static_cast<int>(sizeof(bta_ag_mgmt_cback_tbl) /
+                                sizeof(bta_ag_mgmt_cback_tbl[0])))
+          << "callback index out of bound, services=" << loghex(services)
+          << ", bd_addr" << p_scb->peer_addr;
+      int status = RFCOMM_CreateConnection(
           bta_ag_uuid[i], bta_ag_cb.profile[i].scn, true, BTA_AG_MTU,
           RawAddress::kAny, &(p_scb->serv_handle[i]),
-          bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
-
-      if (bta_ag_port_status == PORT_SUCCESS) {
+          bta_ag_mgmt_cback_tbl[management_callback_index]);
+      if (status == PORT_SUCCESS) {
         bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
       } else {
         /* TODO: CR#137125 to handle to error properly */
-        APPL_TRACE_DEBUG(
-            "bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d",
-            bta_ag_port_status);
+        LOG(ERROR) << __func__ << ": RFCOMM_CreateConnection ERROR " << status
+                   << ", p_scb=" << p_scb << ", services=" << loghex(services)
+                   << ", mgmt_cback_index=" << management_callback_index;
       }
+      APPL_TRACE_DEBUG("%s: p_scb=0x%08x, services=0x%04x, mgmt_cback_index=%d",
+                       __func__, p_scb, services, management_callback_index);
     }
   }
 }
@@ -300,10 +287,8 @@
  *
  ******************************************************************************/
 void bta_ag_close_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
-  int i;
-
   services >>= BTA_HSP_SERVICE_ID;
-  for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+  for (int i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
     /* if service is set in mask */
     if (services & 1) {
       RFCOMM_RemoveServer(p_scb->serv_handle[i]);
@@ -343,23 +328,27 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   BTM_SetSecurityLevel(true, "", bta_ag_sec_id[p_scb->conn_service],
                        p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
                        p_scb->peer_scn);
 
-  if (RFCOMM_CreateConnection(
-          bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU,
-          p_scb->peer_addr, &(p_scb->conn_handle),
-          bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) ==
-      PORT_SUCCESS) {
+  int management_callback_index = bta_ag_scb_to_idx(p_scb) - 1;
+  int status = RFCOMM_CreateConnection(
+      bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU,
+      p_scb->peer_addr, &(p_scb->conn_handle),
+      bta_ag_mgmt_cback_tbl[management_callback_index]);
+  APPL_TRACE_DEBUG(
+      "%s: p_scb=0x%08x, conn_handle=%d, mgmt_cback_index=%d,"
+      " status=%d",
+      __func__, p_scb, p_scb->conn_handle, management_callback_index, status);
+  if (status == PORT_SUCCESS) {
     bta_ag_setup_port(p_scb, p_scb->conn_handle);
-    APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d",
-                     p_scb->conn_handle);
-  }
-  /* RFCOMM create connection failed; send ourselves RFCOMM close event */
-  else {
-    bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+  } else {
+    /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+    LOG(ERROR) << __func__ << ": RFCOMM_CreateConnection ERROR " << status
+               << " for " << p_scb->peer_addr;
+    bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, data);
   }
 }
 
@@ -373,17 +362,18 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb,
+                         UNUSED_ATTR const tBTA_AG_DATA& data) {
   if (p_scb->conn_handle) {
     RFCOMM_RemoveConnection(p_scb->conn_handle);
   } else {
     /* Close API was called while AG is in Opening state.               */
     /* Need to trigger the state machine to send callback to the app    */
     /* and move back to INIT state.                                     */
-    tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC));
-    p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
-    p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
-    bta_sys_sendmsg(p_buf);
+    do_in_bta_thread(
+        FROM_HERE,
+        base::Bind(&bta_ag_sm_execute_by_handle, bta_ag_scb_to_idx(p_scb),
+                   BTA_AG_RFC_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
 
     /* Cancel SDP if it had been started. */
     /*
diff --git a/bta/ag/bta_ag_sco.cc b/bta/ag/bta_ag_sco.cc
index f118988..083108b 100644
--- a/bta/ag/bta_ag_sco.cc
+++ b/bta/ag/bta_ag_sco.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,41 +22,25 @@
  *
  ******************************************************************************/
 
-#include <stddef.h>
+#include <cstddef>
 
 #include "bt_common.h"
 #include "bta_ag_api.h"
-#include "bta_ag_co.h"
 #include "bta_ag_int.h"
 #include "bta_api.h"
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-#include "bta_dm_co.h"
-#endif
 #include "btm_api.h"
 #include "device/include/controller.h"
 #include "device/include/esco_parameters.h"
 #include "osi/include/osi.h"
 #include "utl.h"
 
-#ifndef BTA_AG_SCO_DEBUG
-#define BTA_AG_SCO_DEBUG FALSE
-#endif
-
 /* Codec negotiation timeout */
 #ifndef BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS
 #define BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS (3 * 1000) /* 3 seconds */
 #endif
 
-#if (BTA_AG_SCO_DEBUG == TRUE)
-static char* bta_ag_sco_evt_str(uint8_t event);
-static char* bta_ag_sco_state_str(uint8_t state);
-#endif
-
 static bool sco_allowed = true;
-
-#define BTA_AG_NO_EDR_ESCO                                       \
-  (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
-   ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
+static RawAddress active_device_addr = {};
 
 /* sco events */
 enum {
@@ -69,9 +53,57 @@
   BTA_AG_SCO_SHUTDOWN_E,   /* shutdown request */
   BTA_AG_SCO_CONN_OPEN_E,  /* sco open */
   BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */
-  BTA_AG_SCO_CI_DATA_E     /* SCO data ready */
 };
 
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+
+static const char* bta_ag_sco_evt_str(uint8_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_AG_SCO_LISTEN_E)
+    CASE_RETURN_STR(BTA_AG_SCO_OPEN_E)
+    CASE_RETURN_STR(BTA_AG_SCO_XFER_E)
+    CASE_RETURN_STR(BTA_AG_SCO_CN_DONE_E)
+    CASE_RETURN_STR(BTA_AG_SCO_REOPEN_E)
+    CASE_RETURN_STR(BTA_AG_SCO_CLOSE_E)
+    CASE_RETURN_STR(BTA_AG_SCO_SHUTDOWN_E)
+    CASE_RETURN_STR(BTA_AG_SCO_CONN_OPEN_E)
+    CASE_RETURN_STR(BTA_AG_SCO_CONN_CLOSE_E)
+    default:
+      return "Unknown SCO Event";
+  }
+}
+
+static const char* bta_ag_sco_state_str(uint8_t state) {
+  switch (state) {
+    CASE_RETURN_STR(BTA_AG_SCO_SHUTDOWN_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_LISTEN_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_CODEC_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_OPENING_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_OPEN_CL_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_OPEN_XFER_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_OPEN_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_CLOSING_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_CLOSE_OP_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_CLOSE_XFER_ST)
+    CASE_RETURN_STR(BTA_AG_SCO_SHUTTING_ST)
+    default:
+      return "Unknown SCO State";
+  }
+}
+
+/**
+ * Check if bd_addr is the current active device.
+ *
+ * @param bd_addr target device address
+ * @return True if bd_addr is the current active device, False otherwise or if
+ * no active device is set (i.e. active_device_addr is empty)
+ */
+bool bta_ag_sco_is_active_device(const RawAddress& bd_addr) {
+  return !active_device_addr.IsEmpty() && active_device_addr == bd_addr;
+}
+
 static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local);
 
 /*******************************************************************************
@@ -89,7 +121,7 @@
   tBTA_AG_SCB* p_scb;
 
   /* match callback to scb; first check current sco scb */
-  if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) {
+  if (bta_ag_cb.sco.p_curr_scb != nullptr && bta_ag_cb.sco.p_curr_scb->in_use) {
     handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
   }
   /* then check for scb connected to this peer */
@@ -101,13 +133,12 @@
   }
 
   if (handle != 0) {
-    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-    p_buf->event = BTA_AG_SCO_OPEN_EVT;
-    p_buf->layer_specific = handle;
-    bta_sys_sendmsg(p_buf);
+    do_in_bta_thread(FROM_HERE,
+                     base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                                BTA_AG_SCO_OPEN_EVT, tBTA_AG_DATA::kEmpty));
   } else {
     /* no match found; disconnect sco, init sco variables */
-    bta_ag_cb.sco.p_curr_scb = NULL;
+    bta_ag_cb.sco.p_curr_scb = nullptr;
     bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
     BTM_RemoveSco(sco_idx);
   }
@@ -143,7 +174,7 @@
       bta_ag_cb.scb[1].state);
 
   /* match callback to scb */
-  if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) {
+  if (bta_ag_cb.sco.p_curr_scb != nullptr && bta_ag_cb.sco.p_curr_scb->in_use) {
     /* We only care about callbacks for the active SCO */
     if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx) {
       if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF) return;
@@ -152,14 +183,6 @@
   }
 
   if (handle != 0) {
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-
-    tBTM_STATUS status =
-        BTM_ConfigScoPath(ESCO_DATA_PATH_PCM, NULL, NULL, true);
-    APPL_TRACE_DEBUG("%s: sco close config status = %d", __func__, status);
-    /* SCO clean up here */
-    bta_dm_sco_co_close();
-#endif
 
     /* Restore settings */
     if (bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC) {
@@ -193,43 +216,22 @@
 
     bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
 
-    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-    p_buf->event = BTA_AG_SCO_CLOSE_EVT;
-    p_buf->layer_specific = handle;
-    bta_sys_sendmsg(p_buf);
+    do_in_bta_thread(FROM_HERE,
+                     base::Bind(&bta_ag_sm_execute_by_handle, handle,
+                                BTA_AG_SCO_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
   } else {
     /* no match found */
     APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
 
     /* sco could be closed after scb dealloc'ed */
-    if (bta_ag_cb.sco.p_curr_scb != NULL) {
+    if (bta_ag_cb.sco.p_curr_scb != nullptr) {
       bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
-      bta_ag_cb.sco.p_curr_scb = NULL;
+      bta_ag_cb.sco.p_curr_scb = nullptr;
       bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
     }
   }
 }
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-/*******************************************************************************
- *
- * Function         bta_ag_sco_read_cback
- *
- * Description      Callback function is the callback function for incoming
- *                  SCO data over HCI.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_ag_sco_read_cback(uint16_t sco_inx, BT_HDR* p_data,
-                                  tBTM_SCO_DATA_FLAG status) {
-  if (status != BTM_SCO_DATA_CORRECT) {
-    APPL_TRACE_DEBUG("%s: status %d", __func__, status);
-  }
 
-  /* Callout function must free the data. */
-  bta_dm_sco_co_in_data(p_data, status);
-}
-#endif
 /*******************************************************************************
  *
  * Function         bta_ag_remove_sco
@@ -272,14 +274,13 @@
  ******************************************************************************/
 static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event,
                                       tBTM_ESCO_EVT_DATA* p_data) {
-  tBTA_AG_SCB* p_scb;
-  uint16_t handle;
-  uint16_t sco_inx = p_data->conn_evt.sco_inx;
-
   /* Only process connection requests */
   if (event == BTM_ESCO_CONN_REQ_EVT) {
-    if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
-        ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn) {
+    uint16_t sco_inx = p_data->conn_evt.sco_inx;
+    const RawAddress* remote_bda = BTM_ReadScoBdAddr(sco_inx);
+    tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(bta_ag_idx_by_bdaddr(remote_bda));
+    if (remote_bda && bta_ag_sco_is_active_device(*remote_bda) && p_scb &&
+        p_scb->svc_conn) {
       p_scb->sco_idx = sco_inx;
 
       /* If no other SCO active, allow this one */
@@ -302,18 +303,20 @@
           APPL_TRACE_ERROR(
               "%s: Nothing to remove,so accept Conn Request(sco_inx 0x%04x)",
               __func__, sco_inx);
-          bta_ag_cb.sco.p_xfer_scb = NULL;
+          bta_ag_cb.sco.p_xfer_scb = nullptr;
           bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
 
           bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
         }
       }
     } else {
-      /* If error occurred send reject response immediately */
-      APPL_TRACE_WARNING(
-          "no scb for bta_ag_esco_connreq_cback or no resources");
+      LOG(WARNING) << __func__
+                   << ": reject incoming SCO connection, remote_bda="
+                   << (remote_bda ? *remote_bda : RawAddress::kEmpty)
+                   << ", active_bda=" << active_device_addr << ", current_bda="
+                   << (p_scb ? p_scb->peer_addr : RawAddress::kEmpty);
       BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
-                      (enh_esco_params_t*)NULL);
+                      (enh_esco_params_t*)nullptr);
     }
   } else if (event == BTM_ESCO_CHG_EVT) {
     /* Received a change in the esco link */
@@ -337,11 +340,9 @@
  *
  ******************************************************************************/
 static void bta_ag_cback_sco(tBTA_AG_SCB* p_scb, uint8_t event) {
-  tBTA_AG_HDR sco;
-
+  tBTA_AG_HDR sco = {};
   sco.handle = bta_ag_scb_to_idx(p_scb);
   sco.app_id = p_scb->app_id;
-
   /* call close cback */
   (*bta_ag_cb.p_cback)(event, (tBTA_AG*)&sco);
 }
@@ -360,15 +361,21 @@
 static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
   APPL_TRACE_DEBUG(
       "%s: BEFORE codec_updated=%d, codec_fallback=%d, "
-      "sco_codec=%d, peer_codec=%d, msbc_settings=%d",
+      "sco_codec=%d, peer_codec=%d, msbc_settings=%d, device=%s",
       __func__, p_scb->codec_updated, p_scb->codec_fallback, p_scb->sco_codec,
-      p_scb->peer_codecs, p_scb->codec_msbc_settings);
+      p_scb->peer_codecs, p_scb->codec_msbc_settings,
+      p_scb->peer_addr.ToString().c_str());
   tBTA_AG_PEER_CODEC esco_codec = BTA_AG_CODEC_CVSD;
 
+  if (!bta_ag_sco_is_active_device(p_scb->peer_addr)) {
+    LOG(WARNING) << __func__ << ": device " << p_scb->peer_addr
+                 << " is not active, active_device=" << active_device_addr;
+    return;
+  }
   /* Make sure this SCO handle is not already in use */
   if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) {
-    APPL_TRACE_ERROR("%s: Index 0x%04x already in use!", __func__,
-                     p_scb->sco_idx);
+    APPL_TRACE_ERROR("%s: device %s, index 0x%04x already in use!", __func__,
+                     p_scb->peer_addr.ToString().c_str(), p_scb->sco_idx);
     return;
   }
 
@@ -423,13 +430,16 @@
 
     /* Send pending commands to create SCO connection to peer */
     bta_ag_create_pending_sco(p_scb, bta_ag_cb.sco.is_local);
+    APPL_TRACE_API("%s: orig %d, inx 0x%04x, pkt types 0x%04x", __func__,
+                   is_orig, p_scb->sco_idx, params.packet_types);
   } else {
     /* Not initiating, go to listen mode */
     tBTM_STATUS status = BTM_CreateSco(
         &p_scb->peer_addr, false, params.packet_types, &p_scb->sco_idx,
         bta_ag_sco_conn_cback, bta_ag_sco_disc_cback);
-    if (status == BTM_CMD_STARTED)
+    if (status == BTM_CMD_STARTED) {
       BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+    }
 
     APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
                    __func__, is_orig, p_scb->sco_idx, status,
@@ -437,9 +447,10 @@
   }
   APPL_TRACE_DEBUG(
       "%s: AFTER codec_updated=%d, codec_fallback=%d, "
-      "sco_codec=%d, peer_codec=%d, msbc_settings=%d",
+      "sco_codec=%d, peer_codec=%d, msbc_settings=%d, device=%s",
       __func__, p_scb->codec_updated, p_scb->codec_fallback, p_scb->sco_codec,
-      p_scb->peer_codecs, p_scb->codec_msbc_settings);
+      p_scb->peer_codecs, p_scb->codec_msbc_settings,
+      p_scb->peer_addr.ToString().c_str());
 }
 
 /*******************************************************************************
@@ -456,7 +467,7 @@
  ******************************************************************************/
 static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) {
   tBTA_AG_PEER_CODEC esco_codec = p_scb->inuse_codec;
-  enh_esco_params_t params;
+  enh_esco_params_t params = {};
   bta_ag_cb.sco.p_curr_scb = p_scb;
   bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
 
@@ -479,26 +490,20 @@
     /* Bypass voice settings if enhanced SCO setup command is supported */
     if (!(controller_get_interface()
               ->supports_enhanced_setup_synchronous_connection())) {
-      if (esco_codec == BTA_AG_CODEC_MSBC)
+      if (esco_codec == BTA_AG_CODEC_MSBC) {
         BTM_WriteVoiceSettings(BTM_VOICE_SETTING_TRANS);
-      else
+      } else {
         BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD);
+      }
     }
 
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-    /* initialize SCO setup, no voice setting for AG, data rate <==> sample
-     * rate */
-    BTM_ConfigScoPath(params.input_data_path, bta_ag_sco_read_cback, NULL,
-                      TRUE);
-#endif
-
-    tBTM_STATUS status = BTM_CreateSco(
-        &p_scb->peer_addr, true, params.packet_types, &p_scb->sco_idx,
-        bta_ag_sco_conn_cback, bta_ag_sco_disc_cback);
-    if (status == BTM_CMD_STARTED) {
+    if (BTM_CreateSco(&p_scb->peer_addr, true, params.packet_types,
+                      &p_scb->sco_idx, bta_ag_sco_conn_cback,
+                      bta_ag_sco_disc_cback) == BTM_CMD_STARTED) {
       /* Initiating the connection, set the current sco handle */
       bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
     }
+    APPL_TRACE_DEBUG("%s: initiated SCO connection", __func__);
   } else {
     /* Local device accepted SCO connection from peer */
     params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
@@ -509,6 +514,7 @@
     }
 
     BTM_EScoConnRsp(p_scb->sco_idx, HCI_SUCCESS, &params);
+    APPL_TRACE_DEBUG("%s: listening for SCO connection", __func__);
   }
 }
 
@@ -547,13 +553,21 @@
   APPL_TRACE_DEBUG("%s", __func__);
   bta_ag_cb.sco.p_curr_scb = p_scb;
 
+  // Workaround for misbehaving HFs such as Sony XAV AX100 car kit and Sony
+  // MW600 Headset, which indicate WBS support in SDP, but no codec
+  // negotiation support in BRSF. In this case, using mSBC codec can result
+  // background noise or no audio. Thus, defaulting to CVSD instead.
+  if (!(p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
+    p_scb->sco_codec = UUID_CODEC_CVSD;
+  }
+
   if ((p_scb->codec_updated || p_scb->codec_fallback) &&
       (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
     /* Change the power mode to Active until SCO open is completed. */
     bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
     /* Send +BCS to the peer */
-    bta_ag_send_bcs(p_scb, NULL);
+    bta_ag_send_bcs(p_scb);
 
     /* Start timer to handle timeout */
     alarm_set_on_mloop(p_scb->codec_negotiation_timer,
@@ -580,42 +594,12 @@
  ******************************************************************************/
 static void bta_ag_sco_event(tBTA_AG_SCB* p_scb, uint8_t event) {
   tBTA_AG_SCO_CB* p_sco = &bta_ag_cb.sco;
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  BT_HDR* p_buf;
-#endif
-
-#if (BTA_AG_SCO_DEBUG == TRUE)
-  uint8_t in_state = p_sco->state;
-
-  if (event != BTA_AG_SCO_CI_DATA_E) {
-    APPL_TRACE_EVENT("%s: SCO Index 0x%04x, State %d (%s), Event %d (%s)",
-                     __func__, p_scb->sco_idx, p_sco->state,
-                     bta_ag_sco_state_str(p_sco->state), event,
-                     bta_ag_sco_evt_str(event));
-  }
-#else
-  if (event != BTA_AG_SCO_CI_DATA_E) {
-    APPL_TRACE_EVENT("%s: SCO Index 0x%04x, State %d, Event %d", __func__,
-                     p_scb->sco_idx, p_sco->state, event);
-  }
-#endif
-
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  if (event == BTA_AG_SCO_CI_DATA_E) {
-    while (true) {
-      bta_dm_sco_co_out_data(&p_buf);
-      if (p_buf) {
-        if (p_sco->state == BTA_AG_SCO_OPEN_ST)
-          BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
-        else
-          osi_free(p_buf);
-      } else
-        break;
-    }
-
-    return;
-  }
-#endif
+  uint8_t previous_state = p_sco->state;
+  APPL_TRACE_EVENT("%s: index=0x%04x, device=%s, state=%s[%d], event=%s[%d]",
+                   __func__, p_scb->sco_idx,
+                   p_scb->peer_addr.ToString().c_str(),
+                   bta_ag_sco_state_str(p_sco->state), p_sco->state,
+                   bta_ag_sco_evt_str(event), event);
 
   switch (p_sco->state) {
     case BTA_AG_SCO_SHUTDOWN_ST:
@@ -627,8 +611,9 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING(
+              "%s: BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %s[%d]", __func__,
+              bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -653,7 +638,7 @@
           /* remove listening connection */
           bta_ag_remove_sco(p_scb, false);
 
-          if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+          if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = nullptr;
 
           /* If last SCO instance then finish shutting down */
           if (!bta_ag_other_scb_open(p_scb)) {
@@ -665,8 +650,8 @@
           /* remove listening connection */
           /* Ignore the event. Keep listening SCO for the active SLC
            */
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_LISTEN_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_LISTEN_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
 
         case BTA_AG_SCO_CONN_CLOSE_E:
@@ -676,8 +661,8 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_LISTEN_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_LISTEN_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -705,7 +690,7 @@
           /* remove listening connection */
           bta_ag_remove_sco(p_scb, false);
 
-          if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+          if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = nullptr;
 
           /* If last SCO instance then finish shutting down */
           if (!bta_ag_other_scb_open(p_scb)) {
@@ -725,8 +710,8 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_CODEC_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_CODEC_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -778,8 +763,8 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPENING_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPENING_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -821,8 +806,8 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_CL_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -853,12 +838,13 @@
           p_sco->state = BTA_AG_SCO_OPENING_ST;
           p_sco->p_curr_scb = p_sco->p_xfer_scb;
           p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
-          p_sco->p_xfer_scb = NULL;
+          p_sco->p_xfer_scb = nullptr;
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING(
+              "%s: BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %s[%d]", __func__,
+              bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -907,8 +893,8 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -951,8 +937,8 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSING_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSING_ST: Ignoring event %s[%d]",
+                             __func__, bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -981,8 +967,9 @@
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING(
+              "%s: BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %s[%d]", __func__,
+              bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -997,14 +984,14 @@
 
         case BTA_AG_SCO_CLOSE_E:
           /* clear xfer scb */
-          p_sco->p_xfer_scb = NULL;
+          p_sco->p_xfer_scb = nullptr;
 
           p_sco->state = BTA_AG_SCO_CLOSING_ST;
           break;
 
         case BTA_AG_SCO_SHUTDOWN_E:
           /* clear xfer scb */
-          p_sco->p_xfer_scb = NULL;
+          p_sco->p_xfer_scb = nullptr;
 
           p_sco->state = BTA_AG_SCO_SHUTTING_ST;
           break;
@@ -1019,14 +1006,15 @@
           /* start codec negotiation */
           p_sco->state = BTA_AG_SCO_CODEC_ST;
           tBTA_AG_SCB* p_cn_scb = p_sco->p_xfer_scb;
-          p_sco->p_xfer_scb = NULL;
+          p_sco->p_xfer_scb = nullptr;
           bta_ag_codec_negotiate(p_cn_scb);
           break;
         }
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING(
+              "%s: BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %s[%d]", __func__,
+              bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -1056,7 +1044,7 @@
 
           if (p_scb == p_sco->p_curr_scb) {
             p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
-            p_sco->p_curr_scb = NULL;
+            p_sco->p_curr_scb = nullptr;
           }
           break;
 
@@ -1077,13 +1065,14 @@
 
           if (p_scb == p_sco->p_curr_scb) {
             p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
-            p_sco->p_curr_scb = NULL;
+            p_sco->p_curr_scb = nullptr;
           }
           break;
 
         default:
-          APPL_TRACE_WARNING("%s: BTA_AG_SCO_SHUTTING_ST: Ignoring event %d",
-                             __func__, event);
+          APPL_TRACE_WARNING(
+              "%s: BTA_AG_SCO_SHUTTING_ST: Ignoring event %s[%d]", __func__,
+              bta_ag_sco_evt_str(event), event);
           break;
       }
       break;
@@ -1091,14 +1080,14 @@
     default:
       break;
   }
-#if (BTA_AG_SCO_DEBUG == TRUE)
-  if (p_sco->state != in_state) {
-    APPL_TRACE_EVENT("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
-                     bta_ag_sco_state_str(in_state),
-                     bta_ag_sco_state_str(p_sco->state),
-                     bta_ag_sco_evt_str(event));
+  if (p_sco->state != previous_state) {
+    APPL_TRACE_EVENT(
+        "%s: SCO_state_change: [%s(0x%02x)]->[%s(0x%02x)] "
+        "after event [%s(0x%02x)]",
+        __func__, bta_ag_sco_state_str(previous_state), previous_state,
+        bta_ag_sco_state_str(p_sco->state), p_sco->state,
+        bta_ag_sco_evt_str(event), event);
   }
-#endif
 }
 
 /*******************************************************************************
@@ -1142,7 +1131,9 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_sco_listen(tBTA_AG_SCB* p_scb,
+                       UNUSED_ATTR const tBTA_AG_DATA& data) {
+  LOG(INFO) << __func__ << ": " << p_scb->peer_addr;
   bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
 }
 
@@ -1156,24 +1147,21 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_sco_open(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
-  uint8_t event;
-
+void bta_ag_sco_open(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) {
   if (!sco_allowed) {
-    APPL_TRACE_DEBUG("%s not opening sco, by policy", __func__);
+    LOG(INFO) << __func__ << ": not opening sco, by policy";
     return;
   }
-
   /* if another scb using sco, this is a transfer */
-  if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb) {
-    event = BTA_AG_SCO_XFER_E;
+  if (bta_ag_cb.sco.p_curr_scb && bta_ag_cb.sco.p_curr_scb != p_scb) {
+    LOG(INFO) << __func__ << ": tranfer " << bta_ag_cb.sco.p_curr_scb->peer_addr
+              << " -> " << p_scb->peer_addr;
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_XFER_E);
+  } else {
+    /* else it is an open */
+    LOG(INFO) << __func__ << ": open " << p_scb->peer_addr;
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_OPEN_E);
   }
-  /* else it is an open */
-  else {
-    event = BTA_AG_SCO_OPEN_E;
-  }
-
-  bta_ag_sco_event(p_scb, event);
 }
 
 /*******************************************************************************
@@ -1186,13 +1174,13 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_sco_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
-/* if scb is in use */
+void bta_ag_sco_close(tBTA_AG_SCB* p_scb,
+                      UNUSED_ATTR const tBTA_AG_DATA& data) {
+  /* if scb is in use */
   /* sco_idx is not allocated in SCO_CODEC_ST, still need to move to listen
    * state. */
   if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) ||
-      (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
-  {
+      (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST)) {
     APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
     bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
   }
@@ -1209,15 +1197,16 @@
  *
  ******************************************************************************/
 void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result) {
-  if (result == true) {
+  if (result) {
     /* Subsequent SCO connection will skip codec negotiation */
-    APPL_TRACE_DEBUG("%s: Succeeded for index 0x%04x", __func__,
-                     p_scb->sco_idx);
+    APPL_TRACE_DEBUG("%s: Succeeded for index 0x%04x, device %s", __func__,
+                     p_scb->sco_idx, p_scb->peer_addr.ToString().c_str());
     p_scb->codec_updated = false;
     bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
   } else {
     /* codec negotiation failed */
-    APPL_TRACE_ERROR("%s: Failed for index 0x%04x", __func__, p_scb->sco_idx);
+    APPL_TRACE_ERROR("%s: Failed for index 0x%04x, device %s", __func__,
+                     p_scb->sco_idx, p_scb->peer_addr.ToString().c_str());
     bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
   }
 }
@@ -1232,7 +1221,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb,
+                         UNUSED_ATTR const tBTA_AG_DATA& data) {
   bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
 }
 
@@ -1247,17 +1237,11 @@
  *
  ******************************************************************************/
 void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb,
-                          UNUSED_ATTR tBTA_AG_DATA* p_data) {
+                          UNUSED_ATTR const tBTA_AG_DATA& data) {
   bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
 
   bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  /* open SCO codec if SCO is routed through transport */
-  bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE,
-                     BTA_AG_CI_SCO_DATA_EVT);
-#endif
-
   /* call app callback */
   bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
 
@@ -1276,9 +1260,9 @@
  *
  ******************************************************************************/
 void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb,
-                           UNUSED_ATTR tBTA_AG_DATA* p_data) {
+                           UNUSED_ATTR const tBTA_AG_DATA& data) {
   /* clear current scb */
-  bta_ag_cb.sco.p_curr_scb = NULL;
+  bta_ag_cb.sco.p_curr_scb = nullptr;
   p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
 
   /* codec_fallback is set when AG is initiator and connection failed for mSBC.
@@ -1333,10 +1317,6 @@
     /* tell sys to stop av if any */
     bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
     /* When HS initiated SCO, it cannot be WBS. */
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-    /* Configure the transport being used */
-    BTM_ConfigScoPath(resp.input_data_path, bta_ag_sco_read_cback, NULL, TRUE);
-#endif
   }
 
   /* If SCO open was initiated from HS, it must be CVSD */
@@ -1345,87 +1325,19 @@
   bta_ag_create_pending_sco(p_scb, bta_ag_cb.sco.is_local);
 }
 
-/*******************************************************************************
- *
- * Function         bta_ag_ci_sco_data
- *
- * Description      Process the SCO data ready callin event
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_ag_ci_sco_data(UNUSED_ATTR tBTA_AG_SCB* p_scb,
-                        UNUSED_ATTR tBTA_AG_DATA* p_data) {
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
-#endif
-}
-
-void bta_ag_set_sco_allowed(tBTA_AG_DATA* p_data) {
-  sco_allowed = ((tBTA_AG_API_SET_SCO_ALLOWED*)p_data)->value;
+void bta_ag_set_sco_allowed(bool value) {
+  sco_allowed = value;
   APPL_TRACE_DEBUG(sco_allowed ? "sco now allowed" : "sco now not allowed");
 }
 
-/*******************************************************************************
- *  Debugging functions
- ******************************************************************************/
+const RawAddress& bta_ag_get_active_device() { return active_device_addr; }
 
-#if (BTA_AG_SCO_DEBUG == TRUE)
-static char* bta_ag_sco_evt_str(uint8_t event) {
-  switch (event) {
-    case BTA_AG_SCO_LISTEN_E:
-      return "Listen Request";
-    case BTA_AG_SCO_OPEN_E:
-      return "Open Request";
-    case BTA_AG_SCO_XFER_E:
-      return "Transfer Request";
-    case BTA_AG_SCO_CN_DONE_E:
-      return "Codec Negotiation Done";
-    case BTA_AG_SCO_REOPEN_E:
-      return "Reopen Request";
-    case BTA_AG_SCO_CLOSE_E:
-      return "Close Request";
-    case BTA_AG_SCO_SHUTDOWN_E:
-      return "Shutdown Request";
-    case BTA_AG_SCO_CONN_OPEN_E:
-      return "Opened";
-    case BTA_AG_SCO_CONN_CLOSE_E:
-      return "Closed";
-    case BTA_AG_SCO_CI_DATA_E:
-      return "Sco Data";
-    default:
-      return "Unknown SCO Event";
+void bta_clear_active_device() { active_device_addr = RawAddress::kEmpty; }
+
+void bta_ag_api_set_active_device(const RawAddress& new_active_device) {
+  if (new_active_device.IsEmpty()) {
+    APPL_TRACE_ERROR("%s: empty device", __func__);
+    return;
   }
+  active_device_addr = new_active_device;
 }
-
-static char* bta_ag_sco_state_str(uint8_t state) {
-  switch (state) {
-    case BTA_AG_SCO_SHUTDOWN_ST:
-      return "Shutdown";
-    case BTA_AG_SCO_LISTEN_ST:
-      return "Listening";
-    case BTA_AG_SCO_CODEC_ST:
-      return "Codec Negotiation";
-    case BTA_AG_SCO_OPENING_ST:
-      return "Opening";
-    case BTA_AG_SCO_OPEN_CL_ST:
-      return "Open while closing";
-    case BTA_AG_SCO_OPEN_XFER_ST:
-      return "Opening while Transferring";
-    case BTA_AG_SCO_OPEN_ST:
-      return "Open";
-    case BTA_AG_SCO_CLOSING_ST:
-      return "Closing";
-    case BTA_AG_SCO_CLOSE_OP_ST:
-      return "Close while Opening";
-    case BTA_AG_SCO_CLOSE_XFER_ST:
-      return "Close while Transferring";
-    case BTA_AG_SCO_SHUTTING_ST:
-      return "Shutting Down";
-    default:
-      return "Unknown SCO State";
-  }
-}
-
-#endif /* (BTA_AG_SCO_DEBUG) */
diff --git a/bta/ag/bta_ag_sdp.cc b/bta/ag/bta_ag_sdp.cc
index ae3c973..8ff39fd 100644
--- a/bta/ag/bta_ag_sdp.cc
+++ b/bta/ag/bta_ag_sdp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,18 +23,23 @@
  *
  ******************************************************************************/
 
-#include <string.h>
+#include <cstring>
+
+#include <base/bind.h>
 
 #include "bt_common.h"
 #include "bta_ag_api.h"
 #include "bta_ag_int.h"
 #include "bta_api.h"
 #include "bta_sys.h"
+#include "btif_config.h"
 #include "btm_api.h"
 #include "osi/include/osi.h"
 #include "sdp_api.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
+
 /* Number of protocol elements in protocol element list. */
 #define BTA_AG_NUM_PROTO_ELEMS 2
 
@@ -50,11 +55,15 @@
 void bta_ag_sdp_cback_1(uint16_t status);
 void bta_ag_sdp_cback_2(uint16_t status);
 void bta_ag_sdp_cback_3(uint16_t status);
+void bta_ag_sdp_cback_4(uint16_t status);
+void bta_ag_sdp_cback_5(uint16_t status);
+void bta_ag_sdp_cback_6(uint16_t status);
 
 /* SDP callback function table */
 typedef tSDP_DISC_CMPL_CB* tBTA_AG_SDP_CBACK;
 const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] = {
-    bta_ag_sdp_cback_1, bta_ag_sdp_cback_2, bta_ag_sdp_cback_3};
+    bta_ag_sdp_cback_1, bta_ag_sdp_cback_2, bta_ag_sdp_cback_3,
+    bta_ag_sdp_cback_4, bta_ag_sdp_cback_5, bta_ag_sdp_cback_6};
 
 /*******************************************************************************
  *
@@ -67,32 +76,25 @@
  *
  ******************************************************************************/
 static void bta_ag_sdp_cback(uint16_t status, uint8_t idx) {
-  uint16_t event;
-  tBTA_AG_SCB* p_scb;
-
   APPL_TRACE_DEBUG("%s status:0x%x", __func__, status);
-
-  p_scb = bta_ag_scb_by_idx(idx);
-  if (p_scb != NULL) {
+  tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(idx);
+  if (p_scb) {
+    uint16_t event;
     /* set event according to int/acp */
     if (p_scb->role == BTA_AG_ACP) {
       event = BTA_AG_DISC_ACP_RES_EVT;
     } else {
       event = BTA_AG_DISC_INT_RES_EVT;
     }
-
-    tBTA_AG_DISC_RESULT* p_buf =
-        (tBTA_AG_DISC_RESULT*)osi_malloc(sizeof(tBTA_AG_DISC_RESULT));
-    p_buf->hdr.event = event;
-    p_buf->hdr.layer_specific = idx;
-    p_buf->status = status;
-    bta_sys_sendmsg(p_buf);
+    tBTA_AG_DATA disc_result = {.disc_result.status = status};
+    do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, idx,
+                                           event, disc_result));
   }
 }
 
 /*******************************************************************************
  *
- * Function         bta_ag_sdp_cback_1 to 3
+ * Function         bta_ag_sdp_cback_1 to 6
  *
  * Description      SDP callback functions.  Since there is no way to
  *                  distinguish scb from the callback we need separate
@@ -105,6 +107,9 @@
 void bta_ag_sdp_cback_1(uint16_t status) { bta_ag_sdp_cback(status, 1); }
 void bta_ag_sdp_cback_2(uint16_t status) { bta_ag_sdp_cback(status, 2); }
 void bta_ag_sdp_cback_3(uint16_t status) { bta_ag_sdp_cback(status, 3); }
+void bta_ag_sdp_cback_4(uint16_t status) { bta_ag_sdp_cback(status, 4); }
+void bta_ag_sdp_cback_5(uint16_t status) { bta_ag_sdp_cback(status, 5); }
+void bta_ag_sdp_cback_6(uint16_t status) { bta_ag_sdp_cback(status, 6); }
 
 /******************************************************************************
  *
@@ -119,8 +124,9 @@
  *                  false if function execution failed.
  *
  *****************************************************************************/
-bool bta_ag_add_record(uint16_t service_uuid, char* p_service_name, uint8_t scn,
-                       tBTA_AG_FEAT features, uint32_t sdp_handle) {
+bool bta_ag_add_record(uint16_t service_uuid, const char* p_service_name,
+                       uint8_t scn, tBTA_AG_FEAT features,
+                       uint32_t sdp_handle) {
   tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
   uint16_t svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
   uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
@@ -133,8 +139,9 @@
 
   APPL_TRACE_DEBUG("%s uuid: %x", __func__, service_uuid);
 
-  memset(proto_elem_list, 0,
-         BTA_AG_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+  for (auto& proto_element : proto_elem_list) {
+    proto_element = {};
+  }
 
   /* add the protocol element sequence */
   proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
@@ -162,7 +169,7 @@
   result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
 
   /* add service name */
-  if (p_service_name != NULL && p_service_name[0] != 0) {
+  if (p_service_name != nullptr && p_service_name[0] != 0) {
     result &= SDP_AddAttribute(
         sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
         (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
@@ -203,7 +210,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_create_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+void bta_ag_create_records(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   int i;
   tBTA_SERVICE_MASK services;
 
@@ -215,16 +222,13 @@
       if (bta_ag_cb.profile[i].sdp_handle == 0) {
         bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
         bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
-        bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
-                          bta_ag_cb.profile[i].scn,
-                          p_data->api_register.features,
+        bta_ag_add_record(bta_ag_uuid[i], data.api_register.p_name[i],
+                          bta_ag_cb.profile[i].scn, data.api_register.features,
                           bta_ag_cb.profile[i].sdp_handle);
         bta_sys_add_uuid(bta_ag_uuid[i]);
       }
     }
   }
-
-  p_scb->hsp_version = HSP_VERSION_1_2;
 }
 
 /*******************************************************************************
@@ -237,7 +241,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_del_records(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_del_records(tBTA_AG_SCB* p_scb) {
   tBTA_AG_SCB* p = &bta_ag_cb.scb[0];
   tBTA_SERVICE_MASK services;
   tBTA_SERVICE_MASK others = 0;
@@ -249,7 +253,7 @@
       continue;
     }
 
-    if (p->in_use && p->dealloc == false) {
+    if (p->in_use && !p->dealloc) {
       others |= p->reg_services;
     }
   }
@@ -285,7 +289,7 @@
  *
  ******************************************************************************/
 bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
-  tSDP_DISC_REC* p_rec = NULL;
+  tSDP_DISC_REC* p_rec = nullptr;
   tSDP_DISC_ATTR* p_attr;
   tSDP_PROTOCOL_ELEM pe;
   uint16_t uuid;
@@ -293,25 +297,29 @@
 
   if (service & BTA_HFP_SERVICE_MASK) {
     uuid = UUID_SERVCLASS_HF_HANDSFREE;
-    p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
+    /* If there is no cached peer version, use default one */
+    if (p_scb->peer_version == HFP_HSP_VERSION_UNKNOWN) {
+      p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
+    }
   } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
     uuid = UUID_SERVCLASS_HEADSET_HS;
     p_scb->peer_version = HSP_VERSION_1_2; /* Default version */
   } else {
-    return result;
+    uuid = UUID_SERVCLASS_HEADSET_HS;
+    p_scb->peer_version = HSP_VERSION_1_0;
   }
 
   /* loop through all records we found */
   while (true) {
     /* get next record; if none found, we're done */
     p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec);
-    if (p_rec == NULL) {
+    if (p_rec == nullptr) {
       if (uuid == UUID_SERVCLASS_HEADSET_HS) {
         /* Search again in case the peer device uses the old HSP UUID */
         uuid = UUID_SERVCLASS_HEADSET;
         p_scb->peer_version = HSP_VERSION_1_0;
         p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec);
-        if (p_rec == NULL) {
+        if (p_rec == nullptr) {
           break;
         }
       } else
@@ -328,26 +336,66 @@
     }
 
     /* get profile version (if failure, version parameter is not updated) */
-    if (!SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version)) {
+    uint16_t peer_version = HFP_HSP_VERSION_UNKNOWN;
+    if (!SDP_FindProfileVersionInRec(p_rec, uuid, &peer_version)) {
       APPL_TRACE_WARNING("%s: Get peer_version failed, using default 0x%04x",
                          __func__, p_scb->peer_version);
+      peer_version = p_scb->peer_version;
     }
 
-    /* get features if HFP */
     if (service & BTA_HFP_SERVICE_MASK) {
+      /* Update cached peer version if the new one is different */
+      if (peer_version != p_scb->peer_version) {
+        p_scb->peer_version = peer_version;
+        if (btif_config_set_bin(
+                p_scb->peer_addr.ToString(), HFP_VERSION_CONFIG_KEY,
+                (const uint8_t*)&peer_version, sizeof(peer_version))) {
+          btif_config_save();
+        } else {
+          APPL_TRACE_WARNING("%s: Failed to store peer HFP version for %s",
+                             __func__, p_scb->peer_addr.ToString().c_str());
+        }
+      }
+      /* get features if HFP */
       p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
-      if (p_attr != NULL) {
+      if (p_attr != nullptr) {
         /* 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 /* HSP */
-    {
+    } else {
+      /* No peer version caching for HSP, use discovered one directly */
+      p_scb->peer_version = peer_version;
+      /* get features if HSP */
       p_attr =
           SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL);
-      if (p_attr != NULL) {
+      if (p_attr != nullptr) {
         /* Remote volume control of HSP */
         if (p_attr->attr_value.v.u8)
           p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
@@ -374,11 +422,10 @@
  *
  ******************************************************************************/
 void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
-  tSDP_UUID uuid_list[1];
+  Uuid uuid_list[1];
   uint16_t num_uuid = 1;
   uint16_t attr_list[4];
   uint8_t num_attr;
-  bool db_inited = false;
 
   /* HFP initiator; get proto list and features */
   if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
@@ -387,7 +434,7 @@
     attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
     attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
     num_attr = 4;
-    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+    uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);
   }
   /* HFP acceptor; get features */
   else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) {
@@ -395,7 +442,7 @@
     attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
     attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
     num_attr = 3;
-    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+    uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);
   }
   /* HSP initiator; get proto list */
   else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
@@ -409,36 +456,47 @@
     // UUID_SERVCLASS_HEADSET (0x1108) to store its service record. However,
     // most of such devices are HSP 1.0 devices.
     if (p_scb->hsp_version >= HSP_VERSION_1_2) {
-      uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+      uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_HEADSET_HS);
     } else {
-      uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET;
+      uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_HEADSET);
     }
-  }
-  /* HSP acceptor; no discovery */
-  else {
-    return;
+  } else {
+    /* HSP acceptor; get features */
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+    attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+    num_attr = 4;
+
+    if (p_scb->hsp_version >= HSP_VERSION_1_2) {
+      uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_HEADSET_HS);
+      num_uuid = 2;
+    } else {
+      /* Legacy from HSP v1.0 */
+      uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_HEADSET);
+    }
   }
 
   /* allocate buffer for sdp database */
   p_scb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AG_DISC_BUF_SIZE);
   /* set up service discovery database; attr happens to be attr_list len */
-  uuid_list[0].len = LEN_UUID_16;
-  db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE,
-                                  num_uuid, uuid_list, num_attr, attr_list);
-
-  if (db_inited) {
-    /*Service discovery not initiated */
-    db_inited = SDP_ServiceSearchAttributeRequest(
-        p_scb->peer_addr, p_scb->p_disc_db,
-        bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+  if (SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid,
+                          uuid_list, num_attr, attr_list)) {
+    if (SDP_ServiceSearchAttributeRequest(
+            p_scb->peer_addr, p_scb->p_disc_db,
+            bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1])) {
+      return;
+    } else {
+      LOG(ERROR) << __func__ << ": failed to start SDP discovery for "
+                 << p_scb->peer_addr;
+    }
+  } else {
+    LOG(ERROR) << __func__ << ": failed to init SDP discovery database for "
+               << p_scb->peer_addr;
   }
-
-  if (!db_inited) {
-    /*free discover db */
-    bta_ag_free_db(p_scb, NULL);
-    /* sent failed event */
-    bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
-  }
+  // Failure actions
+  bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
+  bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, tBTA_AG_DATA::kEmpty);
 }
 
 /*******************************************************************************
@@ -451,6 +509,6 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ag_free_db(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+void bta_ag_free_db(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
   osi_free_and_reset((void**)&p_scb->p_disc_db);
 }
diff --git a/bta/ar/bta_ar.cc b/bta/ar/bta_ar.cc
index 3b93e97..bcfa89d 100644
--- a/bta/ar/bta_ar.cc
+++ b/bta/ar/bta_ar.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -73,13 +73,14 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_ar_avdt_cback(uint8_t handle, const RawAddress* bd_addr,
-                              uint8_t event, tAVDT_CTRL* p_data) {
+static void bta_ar_avdt_cback(uint8_t handle, const RawAddress& bd_addr,
+                              uint8_t event, tAVDT_CTRL* p_data,
+                              uint8_t scb_index) {
   /* route the AVDT registration callback to av or avk */
   if (bta_ar_cb.p_av_conn_cback)
-    (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data);
+    (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data, scb_index);
   if (bta_ar_cb.p_avk_conn_cback)
-    (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data);
+    (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data, scb_index);
 }
 
 /*******************************************************************************
@@ -91,7 +92,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ar_reg_avdt(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback,
+void bta_ar_reg_avdt(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback,
                      tBTA_SYS_ID sys_id) {
   uint8_t mask = 0;
 
@@ -153,17 +154,18 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, const RawAddress& bd_addr) {
+void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, const RawAddress& bd_addr,
+                      uint8_t scb_index) {
   uint8_t event = BTA_AR_AVDT_CONN_EVT;
   tAVDT_CTRL data;
 
   if (sys_id == BTA_ID_AV) {
     if (bta_ar_cb.p_avk_conn_cback) {
-      (*bta_ar_cb.p_avk_conn_cback)(0, &bd_addr, event, &data);
+      (*bta_ar_cb.p_avk_conn_cback)(0, bd_addr, event, &data, scb_index);
     }
   } else if (sys_id == BTA_ID_AVK) {
     if (bta_ar_cb.p_av_conn_cback) {
-      (*bta_ar_cb.p_av_conn_cback)(0, &bd_addr, event, &data);
+      (*bta_ar_cb.p_av_conn_cback)(0, bd_addr, event, &data, scb_index);
     }
   }
 }
diff --git a/bta/ar/bta_ar_int.h b/bta/ar/bta_ar_int.h
index 4661e74..ece8378 100644
--- a/bta/ar/bta_ar_int.h
+++ b/bta/ar/bta_ar_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 12f8b24..297bba4 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,27 +24,36 @@
  *
  ******************************************************************************/
 
+#define LOG_TAG "bt_bta_av"
+
 #include "bt_target.h"
 
 #include <base/logging.h>
 #include <string.h>
 #include <vector>
 
+#include "a2dp_sbc.h"
 #include "avdt_api.h"
+#include "avrcp_service.h"
 #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"
 #include "device/include/interop.h"
 #include "l2c_api.h"
 #include "l2cdefs.h"
+#include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "osi/include/properties.h"
 #include "utl.h"
-
 #if (BTA_AR_INCLUDED == TRUE)
 #include "bta_ar_api.h"
 #endif
+#include "btif/include/btif_av.h"
+#include "btif/include/btif_hf.h"
 
 /*****************************************************************************
  *  Constants
@@ -70,6 +79,11 @@
 /* ACL quota we are letting FW use for A2DP Offload Tx. */
 #define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
 
+#define MAX_2MBPS_AVDTP_MTU 663
+#define BTIF_A2DP_MAX_BITPOOL_MQ 35
+
+static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb,
+                                         tBT_A2DP_OFFLOAD* p_a2dp_offload);
 static void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb,
                                UNUSED_ATTR tBTA_AV_DATA* p_data);
 
@@ -84,13 +98,18 @@
 };
 
 /* the call out functions for audio stream */
-const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos = {
-    bta_av_co_audio_init,          bta_av_co_audio_disc_res,
-    bta_av_co_audio_getconfig,     bta_av_co_audio_setconfig,
-    bta_av_co_audio_open,          bta_av_co_audio_close,
-    bta_av_co_audio_start,         bta_av_co_audio_stop,
-    bta_av_co_audio_src_data_path, bta_av_co_audio_delay,
-    bta_av_co_audio_update_mtu};
+const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos = {bta_av_co_audio_init,
+                                           bta_av_co_audio_disc_res,
+                                           bta_av_co_audio_getconfig,
+                                           bta_av_co_audio_setconfig,
+                                           bta_av_co_audio_open,
+                                           bta_av_co_audio_close,
+                                           bta_av_co_audio_start,
+                                           bta_av_co_audio_stop,
+                                           bta_av_co_audio_source_data_path,
+                                           bta_av_co_audio_delay,
+                                           bta_av_co_audio_update_mtu,
+                                           bta_av_co_content_protect_is_active};
 
 /* ssm action functions for audio stream */
 const tBTA_AV_SACT bta_av_a2dp_action[] = {
@@ -166,10 +185,8 @@
     BTA_AV_STR_WRITE_CFM_EVT,    /* AVDT_WRITE_CFM_EVT */
     BTA_AV_AVDT_CONNECT_EVT,     /* AVDT_CONNECT_IND_EVT */
     BTA_AV_AVDT_DISCONNECT_EVT,  /* AVDT_DISCONNECT_IND_EVT */
-#if (AVDT_REPORTING == TRUE)
     BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
     BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
-#endif
     BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
     0                          /* AVDT_DELAY_REPORT_CFM_EVT */
 };
@@ -193,55 +210,12 @@
     BTA_AV_STR_WRITE_CFM_EVT,    /* AVDT_WRITE_CFM_EVT */
     BTA_AV_AVDT_CONNECT_EVT,     /* AVDT_CONNECT_IND_EVT */
     BTA_AV_AVDT_DISCONNECT_EVT,  /* AVDT_DISCONNECT_IND_EVT */
-#if (AVDT_REPORTING == TRUE)
     BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
     BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
-#endif
     BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
     0                          /* AVDT_DELAY_REPORT_CFM_EVT */
 };
 
-static void bta_av_stream0_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data);
-static void bta_av_stream1_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data);
-#if BTA_AV_NUM_STRS > 2
-static void bta_av_stream2_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data);
-#endif
-#if BTA_AV_NUM_STRS > 3
-static void bta_av_stream3_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data);
-#endif
-#if BTA_AV_NUM_STRS > 4
-static void bta_av_stream4_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data);
-#endif
-#if BTA_AV_NUM_STRS > 5
-static void bta_av_stream5_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data);
-#endif
-/* the array of callback functions to receive events from AVDT control channel
- */
-tAVDT_CTRL_CBACK* const bta_av_dt_cback[] = {bta_av_stream0_cback,
-                                             bta_av_stream1_cback
-#if BTA_AV_NUM_STRS > 2
-                                             ,
-                                             bta_av_stream2_cback
-#endif
-#if BTA_AV_NUM_STRS > 3
-                                             ,
-                                             bta_av_stream3_cback
-#endif
-#if BTA_AV_NUM_STRS > 4
-                                             ,
-                                             bta_av_stream4_cback
-#endif
-#if BTA_AV_NUM_STRS > 5
-                                             ,
-                                             bta_av_stream5_cback
-#endif
-};
 /***********************************************
  *
  * Function         bta_get_scb_handle
@@ -291,11 +265,14 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& b) {
-  APPL_TRACE_DEBUG("%s: r:%d, s:%d", __func__, p_scb->recfg_sup,
+static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& bd_addr) {
+  APPL_TRACE_DEBUG("%s: peer=%s recfg_sup:%d, suspend_sup:%d", __func__,
+                   bd_addr.ToString().c_str(), 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;
@@ -303,7 +280,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);
 }
 
 /*******************************************************************************
@@ -317,6 +294,9 @@
  *
  ******************************************************************************/
 static void notify_start_failed(tBTA_AV_SCB* p_scb) {
+  LOG_ERROR(LOG_TAG, "%s: peer %s role:0x%x channel:%d handle:0x%x", __func__,
+            p_scb->PeerAddress().ToString().c_str(), p_scb->role, p_scb->chnl,
+            p_scb->hndl);
   tBTA_AV_START start;
   /* if start failed, clear role */
   p_scb->role &= ~BTA_AV_ROLE_START_INT;
@@ -348,7 +328,7 @@
   /* for outgoing RC connection as INT/CT */
   if ((p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) &&
       /* (bta_av_cb.features & BTA_AV_FEAT_RCCT) && */
-      (p_scb->use_rc == true || (p_scb->role & BTA_AV_ROLE_AD_ACP))) {
+      (p_scb->use_rc || (p_scb->role & BTA_AV_ROLE_AD_ACP))) {
     if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) {
       bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
                           BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
@@ -370,7 +350,6 @@
  ******************************************************************************/
 static bool bta_av_next_getcap(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   int i;
-  tAVDT_GETCAP_REQ* p_req;
   bool sent_cmd = false;
   uint16_t uuid_int = p_scb->uuid_int;
   uint8_t sep_requested = 0;
@@ -382,22 +361,16 @@
 
   for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++) {
     /* steam not in use, is a sink, and is the right media type (audio/video) */
-    if ((p_scb->sep_info[i].in_use == false) &&
+    if ((!p_scb->sep_info[i].in_use) &&
         (p_scb->sep_info[i].tsep == sep_requested) &&
         (p_scb->sep_info[i].media_type == p_scb->media_type)) {
       p_scb->sep_info_idx = i;
 
       /* we got a stream; get its capabilities */
-      if (p_scb->p_cap == NULL)
-        p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
-      if ((p_scb->avdt_version >= AVDT_VERSION_1_3) &&
-          (A2DP_GetAvdtpVersion() >= AVDT_VERSION_1_3)) {
-        p_req = AVDT_GetAllCapReq;
-      } else {
-        p_req = AVDT_GetCapReq;
-      }
-      (*p_req)(p_scb->peer_addr, p_scb->sep_info[i].seid, p_scb->p_cap,
-               bta_av_dt_cback[p_scb->hdi]);
+      bool get_all_cap = (p_scb->AvdtpVersion() >= AVDT_VERSION_1_3) &&
+                         (A2DP_GetAvdtpVersion() >= AVDT_VERSION_1_3);
+      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;
     }
@@ -406,7 +379,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);
   }
 
@@ -422,11 +395,16 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_av_proc_stream_evt(uint8_t handle, const RawAddress* bd_addr,
-                                   uint8_t event, tAVDT_CTRL* p_data,
-                                   int index) {
+void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr,
+                            uint8_t event, tAVDT_CTRL* p_data,
+                            uint8_t scb_index) {
+  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;
-  tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[index];
+
+  APPL_TRACE_EVENT(
+      "%s: peer_address: %s avdt_handle: %d event=0x%x scb_index=%d p_scb=%p",
+      __func__, bd_addr.ToString().c_str(), handle, event, scb_index, p_scb);
 
   if (p_data) {
     if (event == AVDT_SECURITY_IND_EVT) {
@@ -447,64 +425,17 @@
     /* copy event data, bd addr, and handle to event message buffer */
     p_msg->hdr.offset = 0;
 
-    if (bd_addr != NULL) {
-      p_msg->bd_addr = *bd_addr;
-      VLOG(1) << __func__ << ": bd_addr:" << bd_addr;
-    }
+    p_msg->bd_addr = bd_addr;
+    p_msg->scb_index = scb_index;
+    APPL_TRACE_EVENT("%s: stream event bd_addr: %s scb_index: %u", __func__,
+                     p_msg->bd_addr.ToString().c_str(), scb_index);
 
     if (p_data != NULL) {
       memcpy(&p_msg->msg, p_data, sizeof(tAVDT_CTRL));
       /* copy config params to event message buffer */
       switch (event) {
-        case AVDT_RECONFIG_CFM_EVT:
-          if (p_msg->msg.hdr.err_code == 0) {
-            APPL_TRACE_DEBUG(
-                "%s: reconfig cfm event codec info = 0x%06x-%06x-%06x-%02x",
-                __func__,
-                (p_msg->msg.reconfig_cfm.p_cfg->codec_info[0] << 16) +
-                    (p_msg->msg.reconfig_cfm.p_cfg->codec_info[1] << 8) +
-                    p_msg->msg.reconfig_cfm.p_cfg->codec_info[2],
-                (p_msg->msg.reconfig_cfm.p_cfg->codec_info[3] << 16) +
-                    (p_msg->msg.reconfig_cfm.p_cfg->codec_info[4] << 8) +
-                    p_msg->msg.reconfig_cfm.p_cfg->codec_info[5],
-                (p_msg->msg.reconfig_cfm.p_cfg->codec_info[6] << 16) +
-                    (p_msg->msg.reconfig_cfm.p_cfg->codec_info[7] << 8) +
-                    p_msg->msg.reconfig_cfm.p_cfg->codec_info[8],
-                p_msg->msg.reconfig_cfm.p_cfg->codec_info[9]);
-          }
-          break;
-
         case AVDT_CONFIG_IND_EVT:
-          /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on
-           * one L2CAP.
-           * If we already have a signalling connection with the bd_addr and the
-           * streaming
-           * SST is at INIT state, change it to INCOMING state to handle the
-           * signalling
-           * from the 2nd SEP. */
-          if ((bta_av_find_lcb(*bd_addr, BTA_AV_LCB_FIND) != NULL) &&
-              (bta_av_is_scb_init(p_scb))) {
-            bta_av_set_scb_sst_incoming(p_scb);
-
-            /* When ACP_CONNECT_EVT was received, we put first available scb to
-             * incoming state.
-             * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and
-             * set its state to
-             * incoming which we do it above.
-             * We also have to set the old p_scb state to init to be used later
-             */
-            for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
-              if ((bta_av_cb.p_scb[i]) && (i != index)) {
-                if (bta_av_cb.p_scb[i]->state == BTA_AV_INCOMING_SST) {
-                  bta_av_cb.p_scb[i]->state = BTA_AV_INIT_SST;
-                  bta_av_cb.p_scb[i]->coll_mask = 0;
-                  break;
-                }
-              }
-            }
-          }
-
-          memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG));
+          p_msg->cfg = *p_data->config_ind.p_cfg;
           break;
 
         case AVDT_SECURITY_IND_EVT:
@@ -533,8 +464,9 @@
         default:
           break;
       }
-    } else
+    } else {
       p_msg->msg.hdr.err_code = 0;
+    }
 
     /* look up application event */
     if ((p_data == NULL) || (p_data->hdr.err_code == 0)) {
@@ -546,7 +478,7 @@
     p_msg->initiator = false;
     if (event == AVDT_SUSPEND_CFM_EVT) p_msg->initiator = true;
 
-    APPL_TRACE_VERBOSE("%s: hndl:x%x", __func__, p_scb->hndl);
+    APPL_TRACE_VERBOSE("%s: hndl:0x%x", __func__, p_scb->hndl);
     p_msg->hdr.layer_specific = p_scb->hndl;
     p_msg->handle = handle;
     p_msg->avdt_event = event;
@@ -554,7 +486,7 @@
   }
 
   if (p_data) {
-    bta_av_conn_cback(handle, bd_addr, event, p_data);
+    bta_av_conn_cback(handle, bd_addr, event, p_data, scb_index);
   } else {
     APPL_TRACE_ERROR("%s: p_data is null", __func__);
   }
@@ -600,104 +532,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_av_stream0_cback
- *
- * Description      This is the AVDTP callback function for stream events.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_av_stream0_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data) {
-  APPL_TRACE_VERBOSE("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
-  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0);
-}
-
-/*******************************************************************************
- *
- * Function         bta_av_stream1_cback
- *
- * Description      This is the AVDTP callback function for stream events.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_av_stream1_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data) {
-  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
-  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1);
-}
-
-#if BTA_AV_NUM_STRS > 2
-/*******************************************************************************
- *
- * Function         bta_av_stream2_cback
- *
- * Description      This is the AVDTP callback function for stream events.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_av_stream2_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data) {
-  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
-  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2);
-}
-#endif
-
-#if BTA_AV_NUM_STRS > 3
-/*******************************************************************************
- *
- * Function         bta_av_stream3_cback
- *
- * Description      This is the AVDTP callback function for stream events.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_av_stream3_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data) {
-  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
-  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3);
-}
-#endif
-
-/*******************************************************************************
- *
- * Function         bta_av_stream4_cback
- *
- * Description      This is the AVDTP callback function for stream events.
- *
- * Returns          void
- *
- ******************************************************************************/
-#if BTA_AV_NUM_STRS > 4
-static void bta_av_stream4_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data) {
-  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
-  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4);
-}
-#endif
-
-/*******************************************************************************
- *
- * Function         bta_av_stream5_cback
- *
- * Description      This is the AVDTP callback function for stream events.
- *
- * Returns          void
- *
- ******************************************************************************/
-#if BTA_AV_NUM_STRS > 5
-static void bta_av_stream5_cback(uint8_t handle, const RawAddress* bd_addr,
-                                 uint8_t event, tAVDT_CTRL* p_data) {
-  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
-  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5);
-}
-#endif
-
-/*******************************************************************************
- *
  * Function         bta_av_a2dp_sdp_cback
  *
  * Description      A2DP service discovery callback.
@@ -705,23 +539,51 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service) {
-  tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
+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) {
     APPL_TRACE_ERROR("%s: no scb found for handle(0x%x)", __func__,
                      bta_av_cb.handle);
     return;
   }
 
+  if (!found) {
+    APPL_TRACE_ERROR("%s: peer %s A2DP service discovery failed", __func__,
+                     p_scb->PeerAddress().ToString().c_str());
+  }
+  APPL_TRACE_DEBUG("%s: peer %s found=%s", __func__,
+                   p_scb->PeerAddress().ToString().c_str(),
+                   (found) ? "true" : "false");
+
   tBTA_AV_SDP_RES* p_msg =
       (tBTA_AV_SDP_RES*)osi_malloc(sizeof(tBTA_AV_SDP_RES));
-  p_msg->hdr.event =
-      (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT;
-  if (found && (p_service != NULL))
-    p_scb->avdt_version = p_service->avdt_version;
-  else
-    p_scb->avdt_version = 0x00;
+  if (found) {
+    p_msg->hdr.event = BTA_AV_SDP_DISC_OK_EVT;
+  } 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->PeerAddress().ToString().c_str());
+  }
+  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);
@@ -767,7 +629,8 @@
   tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE;
   tBTA_AV_API_OPEN* p_buf = &p_scb->q_info.open;
 
-  APPL_TRACE_DEBUG("%s: wait:x%x", __func__, p_scb->wait);
+  APPL_TRACE_DEBUG("%s: peer %s wait:0x%x", __func__,
+                   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;
 
@@ -786,6 +649,8 @@
     }
   } else {
     /* report failure on OPEN */
+    APPL_TRACE_ERROR("%s: peer %s role switch failed (wait=0x%x)", __func__,
+                     p_scb->PeerAddress().ToString().c_str(), p_scb->wait);
     switch_res = BTA_AV_RS_FAIL;
   }
 
@@ -813,7 +678,8 @@
 void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   bool initiator = false;
 
-  APPL_TRACE_DEBUG("%s: q_tag:%d, wait:x%x, role:x%x", __func__, p_scb->q_tag,
+  APPL_TRACE_DEBUG("%s: peer %s q_tag:%d, wait:0x%x, role:0x%x", __func__,
+                   p_scb->PeerAddress().ToString().c_str(), p_scb->q_tag,
                    p_scb->wait, p_scb->role);
   if (p_scb->role & BTA_AV_ROLE_START_INT) initiator = true;
 
@@ -822,7 +688,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;
@@ -845,7 +711,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;
@@ -864,12 +730,14 @@
       }
     } else {
       APPL_TRACE_WARNING(
-          "%s: unexpected role switch event: q_tag = %d wait = %d", __func__,
-          p_scb->q_tag, p_scb->wait);
+          "%s: peer %s unexpected role switch event: q_tag = %d wait = 0x%x",
+          __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->q_tag,
+          p_scb->wait);
     }
   }
 
-  APPL_TRACE_DEBUG("%s: wait:x%x, role:x%x", __func__, p_scb->wait,
+  APPL_TRACE_DEBUG("%s: peer %s wait:0x%x, role:0x%x", __func__,
+                   p_scb->PeerAddress().ToString().c_str(), p_scb->wait,
                    p_scb->role);
 }
 
@@ -884,7 +752,11 @@
  *
  ******************************************************************************/
 void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
-  p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay);
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d delay:%d", __func__,
+                   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->PeerAddress(),
+                      p_data->str_msg.msg.delay_rpt_cmd.delay);
 }
 
 /*******************************************************************************
@@ -904,7 +776,8 @@
                           ATTR_ID_BT_PROFILE_DESC_LIST};
   uint16_t sdp_uuid = 0; /* UUID for which SDP has to be done */
 
-  APPL_TRACE_DEBUG("%s: use_rc: %d rs:%d, oc:%d", __func__,
+  APPL_TRACE_DEBUG("%s: peer_addr: %s use_rc: %d switch_res:%d, oc:%d",
+                   __func__, p_data->api_open.bd_addr.ToString().c_str(),
                    p_data->api_open.use_rc, p_data->api_open.switch_res,
                    bta_av_cb.audio_open_cnt);
 
@@ -928,7 +801,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;
 
@@ -947,7 +820,7 @@
       break;
   }
 
-  APPL_TRACE_DEBUG("%s: ok_continue: %d wait:x%x, q_tag: %d", __func__,
+  APPL_TRACE_DEBUG("%s: ok_continue: %d wait:0x%x, q_tag: %d", __func__,
                    ok_continue, p_scb->wait, p_scb->q_tag);
   if (!ok_continue) return;
 
@@ -973,19 +846,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);
-
-  if (p_scb->skip_sdp == true) {
-    tA2DP_Service a2dp_ser;
-    a2dp_ser.avdt_version = AVDT_VERSION;
-    p_scb->skip_sdp = false;
-    p_scb->uuid_int = p_data->api_open.uuid;
-    /* only one A2DP find service is active at a time */
-    bta_av_cb.handle = p_scb->hndl;
-    APPL_TRACE_WARNING("%s: Skip Sdp for incoming A2dp connection", __func__);
-    bta_av_a2dp_sdp_cback(true, &a2dp_ser);
-    return;
-  }
+  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;
@@ -1001,15 +862,21 @@
   else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
     sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
 
-  APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
-                   p_scb->uuid_int, sdp_uuid);
-  if (A2DP_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
-                       bta_av_a2dp_sdp_cback) == A2DP_SUCCESS)
-    return;
-
-  /* when the code reaches here, either the DB is NULL
-   * or A2DP_FindService is not successful */
-  bta_av_a2dp_sdp_cback(false, NULL);
+  APPL_TRACE_DEBUG(
+      "%s: Initiate SDP discovery for peer %s : uuid_int=0x%x "
+      "sdp_uuid=0x%x",
+      __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->uuid_int,
+      sdp_uuid);
+  tA2DP_STATUS find_service_status = A2DP_FindService(
+      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->PeerAddress().ToString().c_str(), p_scb->uuid_int,
+        sdp_uuid, find_service_status);
+    bta_av_a2dp_sdp_cback(false, nullptr, RawAddress::kEmpty);
+  }
 }
 
 /*******************************************************************************
@@ -1025,12 +892,12 @@
   tBTA_AV_CONN_CHG msg;
   uint8_t role = BTA_AV_ROLE_AD_INT;
 
-  APPL_TRACE_DEBUG("%s", __func__);
+  LOG_INFO(LOG_TAG, "%s peer %s", __func__,
+           p_scb->PeerAddress().ToString().c_str());
 
   /* free any buffers */
-  osi_free_and_reset((void**)&p_scb->p_cap);
   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;
@@ -1038,7 +905,8 @@
   /* if de-registering shut everything down */
   msg.hdr.layer_specific = p_scb->hndl;
   p_scb->started = false;
-  p_scb->current_codec = nullptr;
+  p_scb->offload_started = false;
+  p_scb->use_rtp_header_marker_bit = false;
   p_scb->cong = false;
   p_scb->role = role;
   p_scb->cur_psc_mask = 0;
@@ -1059,8 +927,7 @@
 
   p_scb->offload_start_pending = false;
 
-  p_scb->skip_sdp = false;
-  if (p_scb->deregistring) {
+  if (p_scb->deregistering) {
     /* remove stream */
     for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
       if (p_scb->seps[i].av_handle) AVDT_RemoveStream(p_scb->seps[i].av_handle);
@@ -1071,7 +938,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);
   }
 }
@@ -1101,7 +968,7 @@
 void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   tBTA_AV_CI_SETCONFIG setconfig;
   tAVDT_SEP_INFO* p_info;
-  tAVDT_CFG* p_evt_cfg = &p_data->str_msg.cfg;
+  const AvdtpSepConfig* p_evt_cfg = &p_data->str_msg.cfg;
   uint8_t psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
   uint8_t
       local_sep; /* sep type of local handle on which connection was received */
@@ -1110,8 +977,11 @@
   local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle);
   p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
 
-  APPL_TRACE_DEBUG("%s: local_sep = %d", __func__, local_sep);
-  A2DP_DumpCodecInfo(p_evt_cfg->codec_info);
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d local_sep:%d", __func__,
+                   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());
 
   memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
   bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
@@ -1155,15 +1025,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_evt_cfg->codec_info, p_info->seid,
-                           p_scb->peer_addr, 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_evt_cfg->codec_info, p_info->seid,
-                           p_scb->peer_addr, 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);
     }
   }
 }
@@ -1182,7 +1052,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);
@@ -1190,7 +1061,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_dt_cback[p_scb->hdi]);
+    AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt);
   } else {
     bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
   }
@@ -1252,14 +1123,15 @@
   /* we like this codec_type. find the sep_idx */
   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: sep_idx: %d cur_psc_mask:0x%x", __func__,
+  APPL_TRACE_DEBUG("%s: peer %s handle: sep_idx: %d cur_psc_mask:0x%x",
+                   __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);
@@ -1274,14 +1146,14 @@
     p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
     if (p_data->ci_setconfig.recfg_needed)
       p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT;
-    APPL_TRACE_DEBUG("%s: recfg_needed:%d role:x%x num:%d", __func__,
+    APPL_TRACE_DEBUG("%s: recfg_needed:%d role:0x%x num:%d", __func__,
                      p_data->ci_setconfig.recfg_needed, p_scb->role, num);
     /* callout module tells BTA the number of "good" SEPs and their SEIDs.
      * getcap on these SEID */
     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) {
@@ -1291,7 +1163,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, num, num, 0, p_scb->peer_addr,
+        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
@@ -1331,11 +1203,13 @@
 void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   tBTA_AV_CONN_CHG msg;
   uint8_t* p;
-  uint16_t mtu;
+
+  APPL_TRACE_DEBUG("%s: peer %s handle: %d", __func__,
+                   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 */
@@ -1344,20 +1218,18 @@
 
   p_scb->stream_mtu =
       p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
-  mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
-  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;
+  APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d", __func__, p_scb->l2c_cid,
+                   p_scb->stream_mtu);
 
   /* Set the media channel as high priority */
   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, mtu);
+  p_scb->p_cos->open(p_scb->hndl, p_scb->PeerAddress(), p_scb->stream_mtu);
 
   {
     /* TODO check if other audio channel is open.
@@ -1371,23 +1243,24 @@
      */
     /* 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;
         }
       }
     }
 #if (BTA_AR_INCLUDED == TRUE)
-    bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
+    bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr, p_scb->hdi);
 #endif
     if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC) {
       open.sep = AVDT_TSEP_SNK;
@@ -1486,7 +1359,7 @@
 
   /* close stream */
   p_scb->started = false;
-  p_scb->current_codec = nullptr;
+  p_scb->use_rtp_header_marker_bit = false;
 
   /* drop the buffers queued in L2CAP */
   L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
@@ -1511,6 +1384,8 @@
  *
  ******************************************************************************/
 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->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.    */
@@ -1522,8 +1397,8 @@
     return;
   }
 
-  AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
-                  bta_av_dt_cback[p_scb->hdi]);
+  AVDT_ConnectReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sec_mask,
+                  &bta_av_proc_stream_evt);
 }
 
 /*******************************************************************************
@@ -1537,7 +1412,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;
@@ -1563,13 +1438,16 @@
   /* our uuid in case we initiate connection */
   uint16_t uuid_int = p_scb->uuid_int;
 
-  APPL_TRACE_DEBUG("%s: initiator UUID 0x%x", __func__, uuid_int);
+  APPL_TRACE_DEBUG("%s: peer %s handle: %d initiator UUID 0x%x", __func__,
+                   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;
 
   for (i = 0; i < p_scb->num_seps; i++) {
     /* steam not in use, is a sink, and is audio */
-    if ((p_scb->sep_info[i].in_use == false) &&
+    if ((!p_scb->sep_info[i].in_use) &&
         (p_scb->sep_info[i].media_type == p_scb->media_type)) {
       if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
           (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE))
@@ -1581,8 +1459,8 @@
     }
   }
 
-  p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, num_srcs,
-                         p_scb->peer_addr, uuid_int);
+  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;
 
@@ -1597,7 +1475,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);
   }
 }
@@ -1616,6 +1494,9 @@
 void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   uint8_t num_snks = 0, i;
 
+  APPL_TRACE_DEBUG("%s: peer %s handle: %d", __func__,
+                   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;
 
@@ -1627,8 +1508,8 @@
       num_snks++;
     }
   }
-  p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0,
-                         p_scb->peer_addr, UUID_SERVCLASS_AUDIO_SOURCE);
+  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;
 
@@ -1643,7 +1524,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);
   }
 }
@@ -1658,36 +1539,47 @@
  *
  ******************************************************************************/
 void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
-  tAVDT_CFG cfg;
+  AvdtpSepConfig cfg;
   tAVDT_SEP_INFO* p_info = &p_scb->sep_info[p_scb->sep_info_idx];
   uint8_t old_wait = p_scb->wait;
   bool getcap_done = false;
 
-  APPL_TRACE_DEBUG("%s: num_seps:%d sep_info_idx:%d wait:x%x", __func__,
-                   p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
-  A2DP_DumpCodecInfo(p_scb->p_cap->codec_info);
+  APPL_TRACE_DEBUG(
+      "%s: peer %s handle:%d num_seps:%d sep_info_idx:%d wait:0x%x", __func__,
+      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());
 
-  memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
+  cfg = p_scb->peer_cap;
   /* let application know the capability of the SNK */
-  p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
-                       p_info->seid, &cfg.num_protect, cfg.protect_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++;
+    APPL_TRACE_DEBUG("%s: result: next sep_info_idx:%d", __func__,
+                     p_scb->sep_info_idx);
+  } else {
+    // All capabilities found
+    getcap_done = true;
+    APPL_TRACE_DEBUG("%s: result: done sep_info_idx:%d", __func__,
+                     p_scb->sep_info_idx);
+  }
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(cfg.codec_info).c_str());
 
-  p_scb->sep_info_idx++;
-  APPL_TRACE_DEBUG("%s: result: sep_info_idx:%d", __func__,
-                   p_scb->sep_info_idx);
-  A2DP_DumpCodecInfo(cfg.codec_info);
-
-  if (p_scb->num_seps > p_scb->sep_info_idx) {
+  if (p_scb->num_seps > p_scb->sep_info_idx && !getcap_done) {
     /* Some devices have seps at the end of the discover list, which is not */
     /* matching media type(video not audio).                                */
     /* In this case, we are done with getcap without sending another        */
     /* request to AVDT.                                                     */
     if (!bta_av_next_getcap(p_scb, p_data)) getcap_done = true;
-  } else
+  } else {
     getcap_done = true;
+  }
 
   if (getcap_done) {
-    APPL_TRACE_DEBUG("%s: getcap_done: num_seps:%d sep_info_idx:%d wait:x%x",
+    APPL_TRACE_DEBUG("%s: getcap_done: num_seps:%d sep_info_idx:%d wait:0x%x",
                      __func__, p_scb->num_seps, p_scb->sep_info_idx,
                      p_scb->wait);
     p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON | BTA_AV_WAIT_ACP_CAPS_STARTED);
@@ -1720,11 +1612,9 @@
  *
  ******************************************************************************/
 void bta_av_cco_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
-  uint16_t mtu;
-
-  mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
-
-  p_scb->p_cos->close(p_scb->hndl);
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d", __func__,
+                   p_scb->PeerAddress().ToString().c_str(), p_scb->hndl);
+  p_scb->p_cos->close(p_scb->hndl, p_scb->PeerAddress());
 }
 
 /*******************************************************************************
@@ -1742,25 +1632,25 @@
   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);
 
   /* check whether there is already an opened audio or video connection with the
    * same device */
-  for (idx = 0; (idx < BTA_AV_NUM_STRS) && (is_av_opened == false); idx++) {
+  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;
   }
 
   /* if there is already an active AV connnection with the same bd_addr,
      don't send disconnect req, just report the open event with
      BTA_AV_FAIL_GET_CAP status */
-  if (is_av_opened == true) {
+  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;
@@ -1785,7 +1675,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_dt_cback[p_scb->hdi]);
+    AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt);
   }
 }
 
@@ -1801,36 +1691,40 @@
  *
  ******************************************************************************/
 void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
-  tAVDT_CFG cfg;
-  uint8_t media_type;
+  AvdtpSepConfig cfg = p_scb->cfg;
+  uint8_t media_type = A2DP_GetMediaType(p_scb->peer_cap.codec_info);
   tAVDT_SEP_INFO* p_info = &p_scb->sep_info[p_scb->sep_info_idx];
-  uint16_t uuid_int; /* UUID for which connection was initiatied */
 
-  memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
   cfg.num_codec = 1;
-  cfg.num_protect = p_scb->p_cap->num_protect;
-  memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
-  memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE);
-  media_type = A2DP_GetMediaType(p_scb->p_cap->codec_info);
+  cfg.num_protect = p_scb->peer_cap.num_protect;
+  memcpy(cfg.codec_info, p_scb->peer_cap.codec_info, AVDT_CODEC_SIZE);
+  memcpy(cfg.protect_info, p_scb->peer_cap.protect_info, AVDT_PROTECT_SIZE);
 
-  APPL_TRACE_DEBUG("%s: num_codec %d", __func__, p_scb->p_cap->num_codec);
-  APPL_TRACE_DEBUG("%s: media type x%x, x%x", __func__, media_type,
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d num_codec:%d psc_mask=0x%x", __func__,
+                   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);
-  A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str());
 
   /* if codec present and we get a codec configuration */
-  if ((p_scb->p_cap->num_codec != 0) && (media_type == p_scb->media_type) &&
-      (p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
-                            p_info->seid, &cfg.num_protect,
+  if ((p_scb->peer_cap.num_codec != 0) && (media_type == p_scb->media_type) &&
+      (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;
+
     /* save copy of codec configuration */
-    memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
+    p_scb->cfg = cfg;
 
     APPL_TRACE_DEBUG("%s: result: sep_info_idx=%d", __func__,
                      p_scb->sep_info_idx);
-    A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+    APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                     A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str());
 
-    uuid_int = p_scb->uuid_int;
     APPL_TRACE_DEBUG("%s: initiator UUID = 0x%x", __func__, uuid_int);
     if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
       bta_av_adjust_seps_idx(p_scb,
@@ -1840,14 +1734,19 @@
                              bta_av_get_scb_handle(p_scb, AVDT_TSEP_SNK));
 
     /* use only the services peer supports */
-    cfg.psc_mask &= p_scb->p_cap->psc_mask;
+    cfg.psc_mask &= p_scb->peer_cap.psc_mask;
     p_scb->cur_psc_mask = cfg.psc_mask;
+    APPL_TRACE_DEBUG(
+        "%s: peer %s handle:%d sep_idx:%d sep_info_idx:%d "
+        "cur_psc_mask:0x%x",
+        __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);
@@ -1858,13 +1757,8 @@
     }
 
     /* open the stream */
-    AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
-                 p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
-
-    if (!bta_av_is_rcfg_sst(p_scb)) {
-      /* free capabilities buffer */
-      osi_free_and_reset((void**)&p_scb->p_cap);
-    }
+    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 */
     p_scb->sep_info_idx++;
@@ -1909,8 +1803,8 @@
 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->sep_info, BTA_AV_NUM_SEPS,
-                   bta_av_dt_cback[p_scb->hdi]);
+  AVDT_DiscoverReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sep_info,
+                   BTA_AV_NUM_SEPS, &bta_av_proc_stream_evt);
 }
 
 /*******************************************************************************
@@ -1924,7 +1818,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);
@@ -1940,11 +1834,14 @@
  *
  ******************************************************************************/
 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:x%x, started:%d", __func__,
-                   bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
+  LOG_INFO(LOG_TAG,
+           "%s: peer %s sco_occupied:%s role:0x%x started:%s wait:0x%x",
+           __func__, p_scb->PeerAddress().ToString().c_str(),
+           logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+           logbool(p_scb->started).c_str(), p_scb->wait);
   if (bta_av_cb.sco_occupied) {
     bta_av_start_failed(p_scb, p_data);
     return;
@@ -1953,31 +1850,57 @@
   /* 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 == false) &&
-      ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) {
+  if (p_scb->started) {
     p_scb->role |= BTA_AV_ROLE_START_INT;
-    bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
-
-    AVDT_StartReq(&p_scb->avdt_handle, 1);
-  } else if (p_scb->started) {
-    p_scb->role |= BTA_AV_ROLE_START_INT;
-    if (p_scb->wait == 0) {
-      if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
-        notify_start_failed(p_scb);
-      } else {
-        bta_av_start_ok(p_scb, NULL);
-      }
+    if (p_scb->wait != 0) {
+      LOG_WARN(
+          LOG_TAG,
+          "%s: peer %s start stream request ignored: "
+          "already waiting: sco_occupied:%s role:0x%x started:%s wait:0x%x",
+          __func__, p_scb->PeerAddress().ToString().c_str(),
+          logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+          logbool(p_scb->started).c_str(), p_scb->wait);
+      return;
     }
+    if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
+      notify_start_failed(p_scb);
+    } else {
+      bta_av_start_ok(p_scb, NULL);
+    }
+    return;
   }
-  APPL_TRACE_DEBUG("%s: started %d role:x%x", __func__, p_scb->started,
-                   p_scb->role);
+
+  if ((p_scb->role & BTA_AV_ROLE_START_INT) != 0) {
+    LOG_WARN(
+        LOG_TAG,
+        "%s: peer %s start stream request ignored: "
+        "already initiated: sco_occupied:%s role:0x%x started:%s wait:0x%x",
+        __func__, p_scb->PeerAddress().ToString().c_str(),
+        logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+        logbool(p_scb->started).c_str(), p_scb->wait);
+    return;
+  }
+
+  p_scb->role |= BTA_AV_ROLE_START_INT;
+  bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
+  uint16_t result = AVDT_StartReq(&p_scb->avdt_handle, 1);
+  if (result != AVDT_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: AVDT_StartReq failed for peer %s result:%d",
+              __func__, p_scb->PeerAddress().ToString().c_str(), result);
+  }
+  LOG_INFO(LOG_TAG,
+           "%s: peer %s start requested: sco_occupied:%s role:0x%x "
+           "started:%s wait:0x%x",
+           __func__, p_scb->PeerAddress().ToString().c_str(),
+           logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+           logbool(p_scb->started).c_str(), p_scb->wait);
 }
 
 /*******************************************************************************
@@ -1994,35 +1917,31 @@
   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: audio_open_cnt=%d, p_data %p", __func__,
-                   bta_av_cb.audio_open_cnt, p_data);
+  APPL_TRACE_ERROR(
+      "%s: peer %s handle:%d audio_open_cnt:%d, p_data %p start:%d", __func__,
+      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) {
-    /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
-    vendor_get_interface()->send_command(
-        (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
-    if (p_scb->offload_start_pending) {
-      tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
-      tBTA_AV bta_av_data;
-      bta_av_data.status = status;
-      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
+    if (p_scb->offload_started) {
+      bta_av_vendor_offload_stop();
+      p_scb->offload_started = false;
     }
-    p_scb->offload_start_pending = false;
-    */
 
     bta_av_stream_chg(p_scb, false);
     p_scb->co_started = false;
 
-    p_scb->p_cos->stop(p_scb->hndl);
-    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 */
@@ -2042,7 +1961,8 @@
   suspend_rsp.hndl = p_scb->hndl;
 
   if (p_data && p_data->api_stop.suspend) {
-    APPL_TRACE_DEBUG("%s: suspending: %d, sup:%d", __func__, start,
+    APPL_TRACE_DEBUG("%s: peer %s suspending: %d, sup:%d", __func__,
+                     p_scb->PeerAddress().ToString().c_str(), start,
                      p_scb->suspend_sup);
     if ((start) && (p_scb->suspend_sup)) {
       sus_evt = false;
@@ -2088,7 +2008,7 @@
  *
  ******************************************************************************/
 void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
-  tAVDT_CFG* p_cfg;
+  AvdtpSepConfig* p_cfg;
   tBTA_AV_API_STOP stop;
   tBTA_AV_API_RCFG* p_rcfg = &p_data->api_reconfig;
 
@@ -2097,8 +2017,6 @@
 
   p_scb->num_recfg = 0;
   /* store the new configuration in control block */
-  if (p_scb->p_cap == NULL)
-    p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
   p_cfg = &p_scb->cfg;
 
   alarm_cancel(p_scb->avrc_ct_timer);
@@ -2106,9 +2024,12 @@
   APPL_TRACE_DEBUG(
       "%s: p_scb->sep_info_idx=%d p_scb->rcfg_idx=%d p_rcfg->sep_info_idx=%d",
       __func__, p_scb->sep_info_idx, p_scb->rcfg_idx, p_rcfg->sep_info_idx);
-  A2DP_DumpCodecInfo(p_scb->p_cap->codec_info);
-  A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
-  A2DP_DumpCodecInfo(p_rcfg->codec_info);
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_scb->peer_cap.codec_info).c_str());
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str());
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_rcfg->codec_info).c_str());
 
   p_cfg->num_protect = p_rcfg->num_protect;
   memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
@@ -2131,7 +2052,8 @@
     } else {
       // Reconfigure
       APPL_TRACE_DEBUG("%s: reconfig", __func__);
-      A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+      APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                       A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str());
       AVDT_ReconfigReq(p_scb->avdt_handle, &p_scb->cfg);
       p_scb->cfg.psc_mask = p_scb->cur_psc_mask;
     }
@@ -2181,7 +2103,7 @@
 
   if (p_scb->cong) return;
 
-  if (p_scb->current_codec->useRtpHeaderMarkerBit()) {
+  if (p_scb->use_rtp_header_marker_bit) {
     m_pt |= AVDT_MARKER_SET;
   }
 
@@ -2197,7 +2119,7 @@
   } else {
     new_buf = true;
     /* A2DP_list empty, call co_data, dup data to other channels */
-    p_buf = (BT_HDR*)p_scb->p_cos->data(p_scb->cfg.codec_info, &timestamp);
+    p_buf = p_scb->p_cos->data(p_scb->cfg.codec_info, &timestamp);
 
     if (p_buf) {
       /* use the offset area for the time stamp */
@@ -2217,7 +2139,7 @@
 
       /* opt is a bit mask, it could have several options set */
       opt = AVDT_DATA_OPT_NONE;
-      if (p_scb->no_rtp_hdr) {
+      if (p_scb->no_rtp_header) {
         opt |= AVDT_DATA_OPT_NO_RTP;
       }
 
@@ -2279,7 +2201,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);
+          bta_av_co_audio_drop(p_scb->hndl, p_scb->PeerAddress());
           osi_free(p_buf);
         }
       }
@@ -2302,14 +2224,23 @@
   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: wait:x%x, role:x%x", __func__, p_scb->wait,
-                   p_scb->role);
+  LOG_INFO(LOG_TAG, "%s: peer %s handle:%d wait:0x%x role:0x%x local_tsep:%d",
+           __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+           p_scb->wait, p_scb->role, local_tsep);
 
   p_scb->started = true;
-  p_scb->current_codec = bta_av_get_a2dp_current_codec();
+
+  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->PeerAddress());
+    CHECK(codec_config != nullptr);
+    p_scb->use_rtp_header_marker_bit = codec_config->useRtpHeaderMarkerBit();
+  }
 
   if (p_scb->sco_suspend) {
     p_scb->sco_suspend = false;
@@ -2319,23 +2250,30 @@
 
   /* for A2DP SINK we do not send get_caps */
   if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle) &&
-      (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) {
+      (local_tsep == AVDT_TSEP_SNK)) {
     p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON);
     APPL_TRACE_DEBUG("%s: local SEP type is SNK new wait is 0x%x", __func__,
                      p_scb->wait);
   }
   if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) {
     /* role switch has failed */
+    APPL_TRACE_ERROR(
+        "%s: peer %s role switch failed: handle:%d wait:0x%x, role:0x%x",
+        __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: wait:x%x", __func__, p_scb->wait);
+  APPL_TRACE_DEBUG("%s: peer %s wait:0x%x use_rtp_header_marker_bit:%s",
+                   __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;
@@ -2367,8 +2305,9 @@
   }
 
   if (p_scb->wait) {
-    APPL_TRACE_ERROR("%s: wait:x%x q_tag:%d- not started", __func__,
-                     p_scb->wait, p_scb->q_tag);
+    APPL_TRACE_ERROR("%s: peer %s wait:0x%x q_tag:%d not started", __func__,
+                     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
      * as
@@ -2380,9 +2319,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,
@@ -2394,9 +2333,9 @@
     p_scb->co_started = bta_av_cb.audio_open_cnt;
     flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1];
   } else {
-    flush_to = p_bta_av_cfg->video_flush_to;
+    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;
@@ -2420,23 +2359,25 @@
        * 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;
     p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
     p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
 
-    p_scb->no_rtp_hdr = false;
-    p_scb->p_cos->start(p_scb->hndl, p_scb->cfg.codec_info, &p_scb->no_rtp_hdr);
+    p_scb->no_rtp_header = false;
+    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: suspending: %d, role:x%x, init %d", __func__, suspend,
+    APPL_TRACE_DEBUG("%s: peer %s suspending: %d, role:0x%x, init %d", __func__,
+                     p_scb->PeerAddress().ToString().c_str(), suspend,
                      p_scb->role, initiator);
 
     tBTA_AV_START start;
@@ -2454,7 +2395,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->p_cos->stop(p_scb->hndl, p_scb->PeerAddress());
       p_scb->co_started = false;
       stop.flush = false;
       stop.suspend = true;
@@ -2474,14 +2415,20 @@
  *
  ******************************************************************************/
 void bta_av_start_failed(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
-  if (p_scb->started == false && p_scb->co_started == false) {
-    bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+  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->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;
 }
 
@@ -2497,17 +2444,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_addr=%s open_status=%d chnl=%d hndl=%d co_started=%d", __func__,
-      p_scb->peer_addr.ToString().c_str(), p_scb->open_status, p_scb->chnl,
-      p_scb->hndl, p_scb->co_started);
+      "%s: peer %s handle:%d open_status:%d chnl:%d co_started:%d", __func__,
+      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);
@@ -2515,7 +2463,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;
@@ -2528,7 +2476,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 {
@@ -2538,12 +2486,12 @@
     }
 
     {
-      p_scb->p_cos->close(p_scb->hndl);
+      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);
     }
@@ -2560,7 +2508,10 @@
  *
  ******************************************************************************/
 void bta_av_clr_cong(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
-  if (p_scb->co_started) p_scb->cong = false;
+  APPL_TRACE_DEBUG("%s", __func__);
+  if (p_scb->co_started) {
+    p_scb->cong = false;
+  }
 }
 
 /*******************************************************************************
@@ -2575,12 +2526,13 @@
 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: audio_open_cnt = %d, err_code = %d", __func__,
-                   bta_av_cb.audio_open_cnt, err_code);
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d audio_open_cnt:%d err_code:%d",
+                   __func__, p_scb->PeerAddress().ToString().c_str(),
+                   p_scb->hndl, bta_av_cb.audio_open_cnt, err_code);
 
-  if (p_scb->started == false) {
+  if (!p_scb->started) {
     /* handle the condition where there is a collision of SUSPEND req from
      *either side
      ** Second SUSPEND req could be rejected. Do not treat this as a failure
@@ -2612,33 +2564,26 @@
     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) {
-    /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
-    vendor_get_interface()->send_command(
-        (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
-    if (p_scb->offload_start_pending) {
-      tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
-      tBTA_AV bta_av_data;
-      bta_av_data.status = status;
-      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
+    if (p_scb->offload_started) {
+      bta_av_vendor_offload_stop();
+      p_scb->offload_started = false;
     }
-    p_scb->offload_start_pending = false;
-    */
-
     bta_av_stream_chg(p_scb, false);
 
     {
       p_scb->co_started = false;
-      p_scb->p_cos->stop(p_scb->hndl);
+      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);
   }
 
   {
@@ -2662,22 +2607,22 @@
  ******************************************************************************/
 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: l2c_cid: %d", __func__, p_scb->l2c_cid);
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d l2c_cid:%d", __func__,
+                   p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+                   p_scb->l2c_cid);
 
   if (p_data != NULL) {
     // p_data could be NULL if the reconfig was triggered by the local device
     p_scb->stream_mtu =
         p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
-    uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
-    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, mtu);
+    APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d", __func__,
+                     p_scb->l2c_cid, p_scb->stream_mtu);
+    p_scb->p_cos->update_mtu(p_scb->hndl, p_scb->PeerAddress(),
+                             p_scb->stream_mtu);
   }
 
   /* rc listen */
   bta_av_st_rc_timer(p_scb, NULL);
-  osi_free_and_reset((void**)&p_scb->p_cap);
 
   /* No need to keep the role bits once reconfig is done. */
   p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
@@ -2708,7 +2653,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);
@@ -2726,7 +2671,7 @@
     /* open failed. try again */
     p_scb->num_recfg++;
     if (bta_av_cb.conn_lcb) {
-      AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+      AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt);
     } else {
       bta_av_connect_req(p_scb, NULL);
     }
@@ -2743,15 +2688,18 @@
  *
  ******************************************************************************/
 void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
   p_scb->cong = false;
   p_scb->num_recfg++;
   APPL_TRACE_DEBUG("%s: num_recfg: %d", __func__, p_scb->num_recfg);
   if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
     /* let bta_av_rcfg_failed report fail */
     bta_av_rcfg_failed(p_scb, NULL);
-  } else
-    AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
-                    bta_av_dt_cback[p_scb->hdi]);
+  } else {
+    AVDT_ConnectReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sec_mask,
+                    &bta_av_proc_stream_evt);
+  }
 }
 
 /*******************************************************************************
@@ -2766,7 +2714,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) {
@@ -2780,9 +2728,10 @@
     (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, &bta_av_data);
     /* 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->sec_mask,
-                    bta_av_dt_cback[p_scb->hdi]);
+  } else {
+    AVDT_ConnectReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sec_mask,
+                    &bta_av_proc_stream_evt);
+  }
 }
 
 /*******************************************************************************
@@ -2798,6 +2747,8 @@
 void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
 
+  APPL_TRACE_DEBUG("%s: err_code=%d", __func__, err_code);
+
   p_scb->started = false;
   p_scb->cong = false;
   if (err_code) {
@@ -2809,7 +2760,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__);
@@ -2827,7 +2778,8 @@
     APPL_TRACE_DEBUG("%s: calling AVDT_ReconfigReq", __func__);
     /* reconfig the stream */
 
-    A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+    APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                     A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str());
     AVDT_ReconfigReq(p_scb->avdt_handle, &p_scb->cfg);
     p_scb->cfg.psc_mask = p_scb->cur_psc_mask;
   }
@@ -2852,13 +2804,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)) {
-        VLOG(1) << __func__ << ": disable AVDTP RECONFIGURE: interop matched "
-                               "name "
-                << remote_name << " address " << 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->PeerAddress().ToString().c_str());
         disable_avdtp_reconfigure = true;
       }
     }
@@ -2899,18 +2854,21 @@
  *
  ******************************************************************************/
 void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
-  APPL_TRACE_DEBUG("%s: num_disc_snks = %d", __func__, p_scb->num_disc_snks);
+  APPL_TRACE_DEBUG("%s: peer %s handle:%d num_disc_snks:%d", __func__,
+                   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->p_cos->stop(p_scb->hndl, p_scb->PeerAddress());
 
     /* send avdtp discover request */
-    AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS,
-                     bta_av_dt_cback[p_scb->hdi]);
+    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__);
-    A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+    APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                     A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str());
 
     /* we may choose to use a different SEP at reconfig.
      * adjust the sep_idx now */
@@ -2918,7 +2876,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,
+    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);
   }
 }
@@ -2950,29 +2908,41 @@
  ******************************************************************************/
 void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb,
                           UNUSED_ATTR tBTA_AV_DATA* p_data) {
-  tBTA_AV_SCB* p_scbi;
-  int i;
-  bool new_started = false;
+  LOG_INFO(LOG_TAG,
+           "%s: peer %s channel:%d bta_av_cb.audio_open_cnt:%d role:0x%x "
+           "features:0x%x",
+           __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->chnl,
+           bta_av_cb.audio_open_cnt, p_scb->role, bta_av_cb.features);
 
-  if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2)) {
-    /* more than one audio channel is connected */
+  if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2) &&
+      (((p_scb->role & BTA_AV_ROLE_AD_ACP) == 0) ||  // Outgoing connection or
+       (bta_av_cb.features & BTA_AV_FEAT_ACP_START))) {  // Auto-starting option
+    // More than one audio channel is connected.
     if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT)) {
-      /* this channel does not need to be reconfigured.
-       * if there is other channel streaming, start the stream now */
-      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
-        p_scbi = bta_av_cb.p_scb[i];
+      // This channel does not need to be reconfigured.
+      // If there is other channel streaming, start the stream now.
+      bool new_started = false;
+      for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
+        tBTA_AV_SCB* p_scbi = bta_av_cb.p_scb[i];
+        if (p_scb == p_scbi) {
+          continue;
+        }
         if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
           if (!new_started) {
-            /* start the new stream */
+            // Start the new stream
             new_started = true;
+            LOG_INFO(LOG_TAG,
+                     "%s: starting new stream for peer %s because peer %s "
+                     "already started",
+                     __func__, p_scb->PeerAddress().ToString().c_str(),
+                     p_scbi->PeerAddress().ToString().c_str());
             bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
           }
-          /* may need to update the flush timeout of this already started stream
-           */
+          // May need to update the flush timeout of this already started stream
           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]);
           }
         }
@@ -2991,7 +2961,7 @@
  *
  ******************************************************************************/
 void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
-  APPL_TRACE_DEBUG("%s: use_rc: %d, wait: x%x role:x%x", __func__,
+  APPL_TRACE_DEBUG("%s: use_rc: %d, wait: 0x%x role: 0x%x", __func__,
                    p_scb->use_rc, p_scb->wait, p_scb->role);
   if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) &&
       (p_scb->q_tag == BTA_AV_Q_TAG_START)) {
@@ -3021,7 +2991,7 @@
     return;
   }
 
-  if (p_scb->use_rc == true || (p_scb->role & BTA_AV_ROLE_AD_ACP)) {
+  if (p_scb->use_rc || (p_scb->role & BTA_AV_ROLE_AD_ACP)) {
     if (bta_av_cb.disc) {
       /* AVRC discover db is in use */
       if (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) {
@@ -3035,7 +3005,13 @@
       }
     } else {
       /* use main SM for AVRC SDP activities */
-      bta_av_rc_disc((uint8_t)(p_scb->hdi + 1));
+      if (is_new_avrcp_enabled()) {
+        APPL_TRACE_WARNING("%s: Using the new AVRCP Profile", __func__);
+        bluetooth::avrcp::AvrcpService::Get()->ConnectDevice(
+            p_scb->PeerAddress());
+      } else {
+        bta_av_rc_disc((uint8_t)(p_scb->hdi + 1));
+      }
     }
   } else {
     if (BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle) {
@@ -3059,6 +3035,9 @@
 void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   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->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;
 
@@ -3073,11 +3052,71 @@
     tBTA_AV_API_OPEN* p_buf =
         (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
     memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
-    p_scb->skip_sdp = true;
     bta_sys_sendmsg(p_buf);
   }
 }
 
+void offload_vendor_callback(tBTM_VSC_CMPL* param) {
+  uint8_t status = 0;
+  uint8_t sub_opcode = 0;
+  if (param->param_len) {
+    APPL_TRACE_DEBUG("%s: param_len = %d status = %d", __func__,
+                     param->param_len, param->p_param_buf[0]);
+    status = param->p_param_buf[0];
+  }
+  if (status == 0) {
+    sub_opcode = param->p_param_buf[1];
+    APPL_TRACE_DEBUG("%s: subopcode = %d", __func__, sub_opcode);
+    switch (sub_opcode) {
+      case VS_HCI_A2DP_OFFLOAD_STOP:
+        APPL_TRACE_DEBUG("%s: VS_HCI_STOP_A2DP_MEDIA successful", __func__);
+        break;
+      case VS_HCI_A2DP_OFFLOAD_START:
+        (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+        break;
+      default:
+        break;
+    }
+  } else {
+    APPL_TRACE_DEBUG("%s: Offload failed for subopcode= %d", __func__,
+                     sub_opcode);
+    if (param->opcode != VS_HCI_A2DP_OFFLOAD_STOP)
+      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+  }
+}
+
+void bta_av_vendor_offload_start(tBTA_AV_SCB* p_scb,
+                                 tBT_A2DP_OFFLOAD* offload_start) {
+  uint8_t param[sizeof(tBT_A2DP_OFFLOAD)];
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  uint8_t* p_param = param;
+  *p_param++ = VS_HCI_A2DP_OFFLOAD_START;
+
+  UINT32_TO_STREAM(p_param, offload_start->codec_type);
+  UINT16_TO_STREAM(p_param, offload_start->max_latency);
+  UINT16_TO_STREAM(p_param, offload_start->scms_t_enable);
+  UINT32_TO_STREAM(p_param, offload_start->sample_rate);
+  UINT8_TO_STREAM(p_param, offload_start->bits_per_sample);
+  UINT8_TO_STREAM(p_param, offload_start->ch_mode);
+  UINT32_TO_STREAM(p_param, offload_start->encoded_audio_bitrate);
+  UINT16_TO_STREAM(p_param, offload_start->acl_hdl);
+  UINT16_TO_STREAM(p_param, offload_start->l2c_rcid);
+  UINT16_TO_STREAM(p_param, offload_start->mtu);
+  ARRAY_TO_STREAM(p_param, offload_start->codec_info,
+                  (int8_t)sizeof(offload_start->codec_info));
+  p_scb->offload_started = true;
+  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, p_param - param,
+                            param, offload_vendor_callback);
+}
+
+void bta_av_vendor_offload_stop() {
+  uint8_t param[sizeof(tBT_A2DP_OFFLOAD)];
+  APPL_TRACE_DEBUG("%s", __func__);
+  param[0] = VS_HCI_A2DP_OFFLOAD_STOP;
+  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, 1, param,
+                            offload_vendor_callback);
+}
 /*******************************************************************************
  *
  * Function         bta_av_offload_req
@@ -3091,58 +3130,59 @@
 void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES;
 
+  tBT_A2DP_OFFLOAD offload_start;
   APPL_TRACE_DEBUG("%s: stream %s, audio channels open %d", __func__,
                    p_scb->started ? "STARTED" : "STOPPED",
                    bta_av_cb.audio_open_cnt);
-
   /* Check if stream has already been started. */
   /* Support offload if only one audio source stream is open. */
   if (p_scb->started != true) {
     status = BTA_AV_FAIL_STREAM;
+  } else {
+    bta_av_offload_codec_builder(p_scb, &offload_start);
+    bta_av_vendor_offload_start(p_scb, &offload_start);
+    return;
   }
-
-  /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
-   uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
-   else if (bta_av_cb.audio_open_cnt == 1 &&
-              p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC &&
-              p_scb->chnl == BTA_AV_CHNL_AUDIO) {
-     bt_vendor_op_a2dp_offload_t a2dp_offload_start;
-
-     if (L2CA_GetConnectionConfig(
-             p_scb->l2c_cid, &a2dp_offload_start.acl_data_size,
-             &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) {
-       APPL_TRACE_DEBUG("%s: l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle
-   0x%02X",
-                        __func__, a2dp_offload_start.acl_data_size,
-                        p_scb->l2c_cid, a2dp_offload_start.remote_cid,
-                        a2dp_offload_start.lm_handle);
-
-       a2dp_offload_start.bta_av_handle = p_scb->hndl;
-       a2dp_offload_start.xmit_quota = BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA;
-       a2dp_offload_start.stream_mtu =
-           (mtu < p_scb->stream_mtu) ? mtu : p_scb->stream_mtu;
-       a2dp_offload_start.local_cid = p_scb->l2c_cid;
-       a2dp_offload_start.is_flushable = true;
-       a2dp_offload_start.stream_source =
-           ((uint32_t)(p_scb->cfg.codec_info[1] | p_scb->cfg.codec_info[2]));
-
-       memcpy(a2dp_offload_start.codec_info, p_scb->cfg.codec_info,
-              sizeof(a2dp_offload_start.codec_info));
-
-       if (!vendor_get_interface()->send_command(
-               (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_START,
-               &a2dp_offload_start)) {
-         status = BTA_AV_SUCCESS;
-         p_scb->offload_start_pending = true;
-       }
-     }
-   }
-   */
   if (status != BTA_AV_SUCCESS) {
     tBTA_AV bta_av_data;
     bta_av_data.status = status;
     (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
   }
+  /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
+  else if (bta_av_cb.audio_open_cnt == 1 &&
+             p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC &&
+             p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+    bt_vendor_op_a2dp_offload_t a2dp_offload_start;
+
+    if (L2CA_GetConnectionConfig(
+            p_scb->l2c_cid, &a2dp_offload_start.acl_data_size,
+            &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) {
+      APPL_TRACE_DEBUG("%s: l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle
+  0x%02X",
+                      __func__, a2dp_offload_start.acl_data_size,
+                       p_scb->l2c_cid, a2dp_offload_start.remote_cid,
+                       a2dp_offload_start.lm_handle);
+
+      a2dp_offload_start.bta_av_handle = p_scb->hndl;
+      a2dp_offload_start.xmit_quota = BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA;
+      a2dp_offload_start.stream_mtu = p_scb->stream_mtu;
+      a2dp_offload_start.local_cid = p_scb->l2c_cid;
+      a2dp_offload_start.is_flushable = true;
+      a2dp_offload_start.stream_source =
+          ((uint32_t)(p_scb->cfg.codec_info[1] | p_scb->cfg.codec_info[2]));
+
+      memcpy(a2dp_offload_start.codec_info, p_scb->cfg.codec_info,
+             sizeof(a2dp_offload_start.codec_info));
+
+      if (!vendor_get_interface()->send_command(
+              (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_START,
+              &a2dp_offload_start)) {
+        status = BTA_AV_SUCCESS;
+        p_scb->offload_start_pending = true;
+      }
+    }
+  }
+ */
 }
 
 /*******************************************************************************
@@ -3172,3 +3212,85 @@
   bta_av_data.status = status;
   (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
 }
+
+static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb,
+                                         tBT_A2DP_OFFLOAD* p_a2dp_offload) {
+  A2dpCodecConfig* CodecConfig = bta_av_get_a2dp_current_codec();
+  btav_a2dp_codec_index_t codec_index =
+      A2DP_SourceCodecIndex(p_scb->cfg.codec_info);
+  uint32_t codec_type = 0;
+  uint16_t mtu = p_scb->stream_mtu;
+  APPL_TRACE_DEBUG("%s:codec_index = %d", __func__, codec_index);
+  switch (codec_index) {
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+      codec_type = BTA_AV_CODEC_TYPE_SBC;
+      if (A2DP_GetMaxBitpoolSbc(p_scb->cfg.codec_info) <=
+          BTIF_A2DP_MAX_BITPOOL_MQ) {
+        APPL_TRACE_WARNING("%s: Restricting streaming MTU size for MQ Bitpool",
+                           __func__);
+        mtu = MAX_2MBPS_AVDTP_MTU;
+      }
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      codec_type = BTA_AV_CODEC_TYPE_AAC;
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+      codec_type = BTA_AV_CODEC_TYPE_APTX;
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+      codec_type = BTA_AV_CODEC_TYPE_APTXHD;
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+      codec_type = BTA_AV_CODEC_TYPE_LDAC;
+      break;
+    default:
+      APPL_TRACE_ERROR("%s: Unknown Codec type ", __func__);
+      return;
+  }
+  if (mtu > BTA_AV_MAX_A2DP_MTU) mtu = BTA_AV_MAX_A2DP_MTU;
+  p_a2dp_offload->codec_type = codec_type;
+  p_a2dp_offload->max_latency = 0;
+  p_a2dp_offload->mtu = mtu;
+  p_a2dp_offload->acl_hdl =
+      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);
+
+  switch (A2DP_GetTrackSampleRate(p_scb->cfg.codec_info)) {
+    case 44100:
+      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+      break;
+    case 48000:
+      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+      break;
+    case 88200:
+      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+      break;
+    case 96000:
+      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+      break;
+  }
+  if (L2CA_GetIdentifiers(p_scb->l2c_cid, &p_a2dp_offload->l2c_rcid, NULL) ==
+      false) {
+    APPL_TRACE_ERROR("%s: Failed to fetch l2c rcid", __func__);
+    return;
+  }
+  switch (CodecConfig->getAudioBitsPerSample()) {
+    case 16:
+      p_a2dp_offload->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+      break;
+    case 24:
+      p_a2dp_offload->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+      break;
+    case 32:
+      p_a2dp_offload->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+      break;
+  }
+  p_a2dp_offload->ch_mode = A2DP_GetTrackChannelCount(p_scb->cfg.codec_info);
+  p_a2dp_offload->encoded_audio_bitrate = CodecConfig->getTrackBitRate();
+  if (!CodecConfig->getCodecSpecificConfig(p_a2dp_offload)) {
+    APPL_TRACE_ERROR("%s: not a valid codec info", __func__);
+  }
+}
diff --git a/bta/av/bta_av_act.cc b/bta/av/bta_av_act.cc
index 4125b6c..ad3bf3d 100644
--- a/bta/av/bta_av_act.cc
+++ b/bta/av/bta_av_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2016 Broadcom Corporation
+ *  Copyright 2004-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
 #include <string.h>
 
 #include "avdt_api.h"
+#include "avrcp_service.h"
 #include "bta_av_api.h"
 #include "bta_av_int.h"
 #include "l2c_api.h"
@@ -109,7 +110,7 @@
         p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
       }
       if (p_scb) {
-        APPL_TRACE_DEBUG("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d",
+        APPL_TRACE_DEBUG("%s: shdl:%d, srch:%d rc_handle:%d", __func__,
                          p_rcb->shdl, p_scb->rc_handle, p_rcb->handle);
         if (p_scb->rc_handle == p_rcb->handle)
           p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
@@ -120,10 +121,9 @@
       }
     }
 
-    APPL_TRACE_EVENT(
-        "bta_av_del_rc  handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
-        p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle,
-        bta_av_cb.rc_acp_idx);
+    APPL_TRACE_EVENT("%s: handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
+                     __func__, p_rcb->handle, p_rcb->status,
+                     bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx);
     rc_handle = p_rcb->handle;
     if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
         ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) {
@@ -137,8 +137,9 @@
     if (rc_handle == bta_av_cb.rc_acp_handle)
       bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
     APPL_TRACE_EVENT(
-        "end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d",
-        p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx);
+        "%s: end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d",
+        __func__, p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle,
+        p_rcb->lidx);
   }
 }
 
@@ -155,7 +156,7 @@
   int i;
 
   for (i = 0; i < BTA_AV_NUM_RCB; i++) {
-    if ((p_cb->disabling == true) || (bta_av_cb.rcb[i].shdl != 0))
+    if ((p_cb->disabling) || (bta_av_cb.rcb[i].shdl != 0))
       bta_av_del_rc(&bta_av_cb.rcb[i]);
   }
 }
@@ -207,7 +208,7 @@
                                  const RawAddress* peer_addr) {
   uint16_t msg_event = 0;
 
-  APPL_TRACE_EVENT("%s handle: %d event=0x%x", __func__, handle, event);
+  APPL_TRACE_EVENT("%s: handle: %d event=0x%x", __func__, handle, event);
   if (event == AVRC_OPEN_IND_EVT) {
     /* save handle of opened connection
     bta_av_cb.rc_handle = handle;*/
@@ -245,7 +246,7 @@
   uint8_t* p_data_src = NULL;
   uint16_t data_len = 0;
 
-  APPL_TRACE_DEBUG("%s handle: %u opcode=0x%x", __func__, handle, opcode);
+  APPL_TRACE_DEBUG("%s: handle: %u opcode=0x%x", __func__, handle, opcode);
 
   /* Copy avrc packet into BTA message buffer (for sending to BTA state machine)
    */
@@ -303,6 +304,12 @@
  ******************************************************************************/
 uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,
                          uint8_t lidx) {
+  if (is_new_avrcp_enabled()) {
+    APPL_TRACE_WARNING("%s: Skipping RC creation for the old AVRCP profile",
+                       __func__);
+    return BTA_AV_RC_HANDLE_NONE;
+  }
+
   tAVRC_CONN_CB ccb;
   RawAddress bda = RawAddress::kAny;
   uint8_t status = BTA_AV_RC_ROLE_ACP;
@@ -312,18 +319,18 @@
   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);
     if (p_rcb != NULL) {
-      APPL_TRACE_ERROR("bta_av_rc_create ACP handle exist for shdl:%d", shdl);
+      APPL_TRACE_ERROR("%s: ACP handle exist for shdl:%d", __func__, shdl);
       return p_rcb->handle;
     }
   }
 
-  ccb.p_ctrl_cback = bta_av_rc_ctrl_cback;
-  ccb.p_msg_cback = bta_av_rc_msg_cback;
+  ccb.ctrl_cback = base::Bind(bta_av_rc_ctrl_cback);
+  ccb.msg_cback = base::Bind(bta_av_rc_msg_cback);
   ccb.company_id = p_bta_av_cfg->company_id;
   ccb.conn = role;
   /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL
@@ -338,7 +345,7 @@
   p_rcb = &p_cb->rcb[i];
 
   if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
-    APPL_TRACE_ERROR("bta_av_rc_create found duplicated handle:%d", rc_handle);
+    APPL_TRACE_ERROR("%s: found duplicated handle:%d", __func__, rc_handle);
   }
 
   p_rcb->handle = rc_handle;
@@ -350,12 +357,12 @@
     /* this LIDX is reserved for the AVRCP ACP connection */
     p_cb->rc_acp_handle = p_rcb->handle;
     p_cb->rc_acp_idx = (i + 1);
-    APPL_TRACE_DEBUG("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle,
-                     p_cb->rc_acp_idx);
+    APPL_TRACE_DEBUG("%s: rc_acp_handle:%d idx:%d", __func__,
+                     p_cb->rc_acp_handle, p_cb->rc_acp_idx);
   }
   APPL_TRACE_DEBUG(
-      "create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x", i,
-      role, shdl, p_rcb->handle, lidx, p_rcb->status);
+      "%s: create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x",
+      __func__, i, role, shdl, p_rcb->handle, lidx, p_rcb->status);
 
   return rc_handle;
 }
@@ -366,12 +373,12 @@
  *
  * Description      Check if it is Group Navigation Msg for Metadata
  *
- * Returns          BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL.
+ * Returns          AVRC_RSP_ACCEPT or AVRC_RSP_NOT_IMPL
  *
  ******************************************************************************/
 static tBTA_AV_CODE bta_av_group_navi_supported(uint8_t len, uint8_t* p_data,
                                                 bool is_inquiry) {
-  tBTA_AV_CODE ret = BTA_AV_RSP_NOT_IMPL;
+  tBTA_AV_CODE ret = AVRC_RSP_NOT_IMPL;
   uint8_t* p_ptr = p_data;
   uint16_t u16;
   uint32_t u32;
@@ -382,12 +389,12 @@
 
     if (u32 == AVRC_CO_METADATA) {
       if (is_inquiry) {
-        if (u16 <= AVRC_PDU_PREV_GROUP) ret = BTA_AV_RSP_IMPL_STBL;
+        if (u16 <= AVRC_PDU_PREV_GROUP) ret = AVRC_RSP_IMPL_STBL;
       } else {
         if (u16 <= AVRC_PDU_PREV_GROUP)
-          ret = BTA_AV_RSP_ACCEPT;
+          ret = AVRC_RSP_ACCEPT;
         else
-          ret = BTA_AV_RSP_REJ;
+          ret = AVRC_RSP_REJ;
       }
     }
   }
@@ -401,24 +408,24 @@
  *
  * Description      Check if remote control operation is supported.
  *
- * Returns          BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not.
+ * Returns          AVRC_RSP_ACCEPT of supported, AVRC_RSP_NOT_IMPL if not.
  *
  ******************************************************************************/
 static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id, bool is_inquiry) {
-  tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL;
+  tBTA_AV_CODE ret_code = AVRC_RSP_NOT_IMPL;
 
   if (p_bta_av_rc_id) {
     if (is_inquiry) {
       if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
-        ret_code = BTA_AV_RSP_IMPL_STBL;
+        ret_code = AVRC_RSP_IMPL_STBL;
       }
     } else {
       if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
-        ret_code = BTA_AV_RSP_ACCEPT;
-      } else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) &&
+        ret_code = AVRC_RSP_ACCEPT;
+      } else if ((p_bta_av_cfg->rc_pass_rsp == AVRC_RSP_INTERIM) &&
                  p_bta_av_rc_id_ac) {
         if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
-          ret_code = BTA_AV_RSP_INTERIM;
+          ret_code = AVRC_RSP_INTERIM;
         }
       }
     }
@@ -441,13 +448,15 @@
   uint8_t mask;
   tBTA_AV_LCB* p_lcb = NULL;
 
+  APPL_TRACE_DEBUG("%s: address: %s op:%d", __func__, addr.ToString().c_str(),
+                   op);
   for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
     mask = 1 << xx; /* the used mask for this lcb */
     if ((mask & p_cb->conn_lcb) && p_cb->lcb[xx].addr == addr) {
       p_lcb = &p_cb->lcb[xx];
       if (op == BTA_AV_LCB_FREE) {
         p_cb->conn_lcb &= ~mask; /* clear the connect mask */
-        APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+        APPL_TRACE_DEBUG("%s: conn_lcb: 0x%x", __func__, p_cb->conn_lcb);
       }
       break;
     }
@@ -477,12 +486,12 @@
   /* 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("bta_av_rc_opened shdl:%d, srch %d", i + 1,
+      APPL_TRACE_DEBUG("%s: shdl:%d, srch %d", __func__, i + 1,
                        p_scb->rc_handle);
       shdl = i + 1;
-      LOG_INFO(LOG_TAG, "%s allow incoming AVRCP connections:%d", __func__,
+      LOG_INFO(LOG_TAG, "%s: allow incoming AVRCP connections:%d", __func__,
                p_scb->use_rc);
       alarm_cancel(p_scb->avrc_ct_timer);
       disc = p_scb->hndl;
@@ -492,11 +501,11 @@
 
   i = p_data->rc_conn_chg.handle;
   if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE) {
-    APPL_TRACE_ERROR("not a valid handle:%d any more", i);
+    APPL_TRACE_ERROR("%s: not a valid handle:%d any more", __func__, i);
     return;
   }
 
-  APPL_TRACE_DEBUG("%s local features %d peer features %d", __func__,
+  APPL_TRACE_DEBUG("%s: local features %d peer features %d", __func__,
                    p_cb->features, p_cb->rcb[i].peer_features);
 
   /* listen to browsing channel when the connection is open,
@@ -515,14 +524,14 @@
       p_cb->rcb[i].lidx = tmp;
       p_cb->rc_acp_handle = p_rcb->handle;
       p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1;
-      APPL_TRACE_DEBUG("switching RCB rc_acp_handle:%d idx:%d",
+      APPL_TRACE_DEBUG("%s: switching RCB rc_acp_handle:%d idx:%d", __func__,
                        p_cb->rc_acp_handle, p_cb->rc_acp_idx);
     }
   }
 
   p_cb->rcb[i].shdl = shdl;
   rc_open.rc_handle = i;
-  APPL_TRACE_ERROR("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d", i, shdl,
+  APPL_TRACE_ERROR("%s: rcb[%d] shdl:%d lidx:%d/%d", __func__, i, shdl,
                    p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
   p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
 
@@ -531,19 +540,19 @@
      * update the index to the extra LCB */
     p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
     p_lcb->addr = p_data->rc_conn_chg.peer_addr;
-    VLOG(1) << "rc_only bd_addr:" << p_lcb->addr;
     p_lcb->lidx = BTA_AV_NUM_LINKS + 1;
     p_cb->rcb[i].lidx = p_lcb->lidx;
     p_lcb->conn_msk = 1;
-    APPL_TRACE_ERROR("rcb[%d].lidx=%d, lcb.conn_msk=x%x", i, p_cb->rcb[i].lidx,
-                     p_lcb->conn_msk);
+    APPL_TRACE_ERROR("%s: bd_addr: %s rcb[%d].lidx=%d, lcb.conn_msk=x%x",
+                     __func__, p_lcb->addr.ToString().c_str(), i,
+                     p_cb->rcb[i].lidx, p_lcb->conn_msk);
     disc = p_data->rc_conn_chg.handle | BTA_AV_CHNL_MSK;
   }
 
   rc_open.peer_addr = p_data->rc_conn_chg.peer_addr;
   rc_open.peer_features = p_cb->rcb[i].peer_features;
   rc_open.status = BTA_AV_SUCCESS;
-  APPL_TRACE_DEBUG("%s local features:x%x peer_features:x%x", __func__,
+  APPL_TRACE_DEBUG("%s: local features:x%x peer_features:x%x", __func__,
                    p_cb->features, rc_open.peer_features);
   if (rc_open.peer_features == 0) {
     /* we have not done SDP on peer RC capabilities.
@@ -566,7 +575,7 @@
   if ((p_cb->features & BTA_AV_FEAT_BROWSE) &&
       (rc_open.peer_features & BTA_AV_FEAT_BROWSE) &&
       ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) {
-    APPL_TRACE_DEBUG("%s opening AVRC Browse channel", __func__);
+    APPL_TRACE_DEBUG("%s: opening AVRC Browse channel", __func__);
     AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT);
   }
 }
@@ -743,7 +752,6 @@
   uint16_t u16;
   tAVRC_MSG_VENDOR* p_vendor = &p_msg->msg.vendor;
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
   pdu = *(p_vendor->p_vendor_data);
   p_rc_rsp->pdu = pdu;
   *p_ctype = AVRC_RSP_REJ;
@@ -752,21 +760,22 @@
   if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE) {
     /* reject it */
     p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
-    APPL_TRACE_ERROR("%s Invalid meta-command length: %d", __func__,
+    APPL_TRACE_ERROR("%s: Invalid meta-command length: %d", __func__,
                      p_vendor->vendor_len);
     return 0;
   }
 
   /* Metadata messages only use PANEL sub-unit type */
   if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) {
-    APPL_TRACE_DEBUG("SUBUNIT must be PANEL");
+    APPL_TRACE_DEBUG("%s: SUBUNIT must be PANEL", __func__);
     /* reject it */
     evt = 0;
-    p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+    p_vendor->hdr.ctype = AVRC_RSP_NOT_IMPL;
     p_vendor->vendor_len = 0;
     p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
   } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype)) {
-    APPL_TRACE_DEBUG("Invalid pdu/ctype: 0x%x, %d", pdu, p_vendor->hdr.ctype);
+    APPL_TRACE_DEBUG("%s: Invalid pdu/ctype: 0x%x, %d", __func__, pdu,
+                     p_vendor->hdr.ctype);
     /* reject invalid message without reporting to app */
     evt = 0;
     p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
@@ -795,7 +804,7 @@
             memcpy(p_rc_rsp->get_caps.param.event_id,
                    p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids);
           } else {
-            APPL_TRACE_DEBUG("Invalid capability ID: 0x%x", u8);
+            APPL_TRACE_DEBUG("%s: Invalid capability ID: 0x%x", __func__, u8);
             /* reject - unknown capability ID */
             p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
           }
@@ -809,12 +818,6 @@
         break;
     }
   }
-#else
-  APPL_TRACE_DEBUG("AVRCP 1.3 Metadata not supporteed. Reject command.");
-  /* reject invalid message without reporting to app */
-  evt = 0;
-  p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
-#endif
 
   return evt;
 }
@@ -835,15 +838,13 @@
   tAVRC_MSG_VENDOR* p_vendor = &p_data->rc_msg.msg.vendor;
   bool is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
                      p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
-#if (AVRC_METADATA_INCLUDED == TRUE)
   uint8_t ctype = 0;
   tAVRC_RESPONSE rc_rsp;
 
   rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
-#endif
 
   if (NULL == p_data) {
-    APPL_TRACE_ERROR("Message from peer with no data in %s", __func__);
+    APPL_TRACE_ERROR("%s: Message from peer with no data", __func__);
     return;
   }
 
@@ -860,32 +861,30 @@
       osi_property_get("bluetooth.pts.avrcp_ct.support", avrcp_ct_support,
                        "false");
       if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) {
-        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
-#if (AVRC_METADATA_INCLUDED == TRUE)
+        p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_NOT_IMPL;
         if (p_cb->features & BTA_AV_FEAT_METADATA)
           p_data->rc_msg.msg.hdr.ctype = bta_av_group_navi_supported(
               p_data->rc_msg.msg.pass.pass_len,
               p_data->rc_msg.msg.pass.p_pass_data, is_inquiry);
-#endif
       } else if (((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_UP) ||
                   (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_DOWN)) &&
                  !strcmp(avrcp_ct_support, "true")) {
-        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_ACCEPT;
+        p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_ACCEPT;
       } else {
         p_data->rc_msg.msg.hdr.ctype =
             bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
       }
 
-      APPL_TRACE_DEBUG("ctype %d", p_data->rc_msg.msg.hdr.ctype)
+      APPL_TRACE_DEBUG("%s: ctype %d", __func__, p_data->rc_msg.msg.hdr.ctype)
 
       /* send response */
-      if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM)
+      if (p_data->rc_msg.msg.hdr.ctype != AVRC_RSP_INTERIM)
         AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
                      &p_data->rc_msg.msg.pass);
 
       /* set up for callback if supported */
-      if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT ||
-          p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM) {
+      if (p_data->rc_msg.msg.hdr.ctype == AVRC_RSP_ACCEPT ||
+          p_data->rc_msg.msg.hdr.ctype == AVRC_RSP_INTERIM) {
         evt = BTA_AV_REMOTE_CMD_EVT;
         av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id;
         av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state;
@@ -910,7 +909,7 @@
           (p_data->rc_msg.msg.pass.pass_len > 0)) {
         av.remote_rsp.p_data =
             (uint8_t*)osi_malloc(p_data->rc_msg.msg.pass.pass_len);
-        APPL_TRACE_DEBUG("Vendor Unique data len = %d",
+        APPL_TRACE_DEBUG("%s: Vendor Unique data len = %d", __func__,
                          p_data->rc_msg.msg.pass.pass_len);
         memcpy(av.remote_rsp.p_data, p_data->rc_msg.msg.pass.p_pass_data,
                p_data->rc_msg.msg.pass.pass_len);
@@ -918,7 +917,7 @@
     }
     /* must be a bad ctype -> reject*/
     else {
-      p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+      p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_REJ;
       AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
                    &p_data->rc_msg.msg.pass);
     }
@@ -935,38 +934,34 @@
     /* if configured to support vendor specific and it's a command */
     if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
         p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
-#if (AVRC_METADATA_INCLUDED == TRUE)
       if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
           (p_vendor->company_id == AVRC_CO_METADATA)) {
         av.meta_msg.p_msg = &p_data->rc_msg.msg;
         rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
         evt = bta_av_proc_meta_cmd(&rc_rsp, &p_data->rc_msg, &ctype);
-      } else
-#endif
+      } else {
         evt = BTA_AV_VENDOR_CMD_EVT;
-    }
-    /* else if configured to support vendor specific and it's a response */
-    else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
-             p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {
-#if (AVRC_METADATA_INCLUDED == TRUE)
+      }
+    } else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+               p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {
+      /* else if configured to support vendor specific and it's a response */
       if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
           (p_vendor->company_id == AVRC_CO_METADATA)) {
         av.meta_msg.p_msg = &p_data->rc_msg.msg;
         evt = BTA_AV_META_MSG_EVT;
-      } else
-#endif
+      } else {
         evt = BTA_AV_VENDOR_RSP_EVT;
-
-    }
-    /* else if not configured to support vendor specific and it's a command */
-    else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&
-             p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
+      }
+    } else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&
+               p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
+      /* else if not configured to support vendor specific and it's a command */
       if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID) {
         /* reject it */
-        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+        p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_REJ;
         p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD;
-      } else
-        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+      } else {
+        p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_NOT_IMPL;
+      }
       AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
                      &p_data->rc_msg.msg.vendor);
     }
@@ -982,7 +977,6 @@
     evt = BTA_AV_META_MSG_EVT;
   }
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
   if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP) {
     if (!p_pkt) {
       rc_rsp.rsp.opcode = p_data->rc_msg.opcode;
@@ -991,7 +985,6 @@
     if (p_pkt)
       AVRC_MsgReq(p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt);
   }
-#endif
 
   /* call callback */
   if (evt != 0) {
@@ -1019,7 +1012,7 @@
   if (handle < BTA_AV_NUM_RCB) {
     p_rcb = &p_cb->rcb[handle];
 
-    APPL_TRACE_DEBUG("%s handle: %d, status=0x%x", __func__, p_rcb->handle,
+    APPL_TRACE_DEBUG("%s: handle: %d, status=0x%x", __func__, p_rcb->handle,
                      p_rcb->status);
     if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
       if (p_rcb->shdl) {
@@ -1047,7 +1040,7 @@
  *
  ******************************************************************************/
 void bta_av_rc_browse_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
-  APPL_TRACE_WARNING("%s empty placeholder does nothing!", __func__);
+  APPL_TRACE_WARNING("%s: empty placeholder does nothing!", __func__);
 }
 
 /*******************************************************************************
@@ -1080,54 +1073,20 @@
  *
  ******************************************************************************/
 void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) {
-  uint8_t started_msk;
-  int i;
-  uint8_t* p_streams;
-  bool no_streams = false;
-  tBTA_AV_SCB* p_scbi;
+  uint8_t started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
 
-  started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
-  APPL_TRACE_DEBUG("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x",
-                   started, started_msk, p_scb->chnl);
-  if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
-    p_streams = &bta_av_cb.audio_streams;
-  else
-    p_streams = &bta_av_cb.video_streams;
+  APPL_TRACE_DEBUG("%s: peer %s started:%s started_msk:0x%x", __func__,
+                   p_scb->PeerAddress().ToString().c_str(),
+                   logbool(started).c_str(), started_msk);
 
   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);
-    (*p_streams) |= started_msk;
+    L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_HIGH);
   } else {
-    (*p_streams) &= ~started_msk;
-  }
-
-  if (!started) {
-    i = 0;
-    if (BTA_AV_CHNL_AUDIO == p_scb->chnl) {
-      if (bta_av_cb.video_streams == 0) no_streams = true;
-    } else {
-      no_streams = true;
-      if (bta_av_cb.audio_streams) {
-        for (; i < BTA_AV_NUM_STRS; i++) {
-          p_scbi = bta_av_cb.p_scb[i];
-          /* scb is used and started */
-          if (p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i)) &&
-              p_scbi->peer_addr == p_scb->peer_addr) {
-            no_streams = false;
-            break;
-          }
-        }
-      }
-    }
-
-    APPL_TRACE_DEBUG("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x",
-                     no_streams, i, bta_av_cb.audio_streams,
-                     bta_av_cb.video_streams);
-    if (no_streams) {
-      /* Let L2CAP know this channel is processed with low priority */
-      L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL);
-    }
+    bta_av_cb.audio_streams &= ~started_msk;
+    /* Let L2CAP know this channel is processed with low priority */
+    L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_NORMAL);
   }
 }
 
@@ -1171,39 +1130,35 @@
           if (bta_av_cb.rcb[i].lidx == p_lcb->lidx) {
             bta_av_cb.rcb[i].shdl = index + 1;
             APPL_TRACE_DEBUG(
-                "conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
-                bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+                "%s: conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d",
+                __func__, i, bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
                 bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
             break;
           }
         }
       }
-      if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
-        old_msk = p_cb->conn_audio;
-        p_cb->conn_audio |= mask;
-      } else {
-        old_msk = p_cb->conn_video;
-        p_cb->conn_video |= mask;
-      }
+      old_msk = p_cb->conn_audio;
+      p_cb->conn_audio |= mask;
 
       if ((old_msk & mask) == 0) {
         /* increase the audio open count, if not set yet */
         bta_av_cb.audio_open_cnt++;
       }
 
-      APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle,
-                       p_cb->rc_acp_idx);
+      APPL_TRACE_DEBUG("%s: rc_acp_handle:%d rc_acp_idx:%d", __func__,
+                       p_cb->rc_acp_handle, p_cb->rc_acp_idx);
       /* check if the AVRCP ACP channel is already connected */
       if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE &&
           p_cb->rc_acp_idx) {
         p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
         APPL_TRACE_DEBUG(
-            "rc_acp is connected && conn_chg on same addr "
+            "%s: rc_acp is connected && conn_chg on same addr "
             "p_lcb_rc->conn_msk:x%x",
-            p_lcb_rc->conn_msk);
+            __func__, p_lcb_rc->conn_msk);
         /* check if the RC is connected to the scb addr */
-        VLOG(1) << "p_lcb_rc->addr: " << p_lcb_rc->addr
-                << " conn_chg.peer_addr:" << p_data->conn_chg.peer_addr;
+        LOG_INFO(LOG_TAG, "%s: p_lcb_rc->addr: %s conn_chg.peer_addr: %s",
+                 __func__, p_lcb_rc->addr.ToString().c_str(),
+                 p_data->conn_chg.peer_addr.ToString().c_str());
 
         if (p_lcb_rc->conn_msk &&
             p_lcb_rc->addr == p_data->conn_chg.peer_addr) {
@@ -1214,23 +1169,25 @@
           p_scb->rc_handle = p_cb->rc_acp_handle;
           p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1];
           p_rcb->shdl = bta_av_get_shdl(p_scb);
-          APPL_TRACE_DEBUG("update rc_acp shdl:%d/%d srch:%d", index + 1,
-                           p_rcb->shdl, p_scb->rc_handle);
+          APPL_TRACE_DEBUG("%s: update rc_acp shdl:%d/%d srch:%d", __func__,
+                           index + 1, p_rcb->shdl, p_scb->rc_handle);
 
           p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl);
           if (p_rcb2) {
             /* found the RCB that was created to associated with this SCB */
             p_cb->rc_acp_handle = p_rcb2->handle;
             p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1;
-            APPL_TRACE_DEBUG("new rc_acp_handle:%d, idx:%d",
+            APPL_TRACE_DEBUG("%s: new rc_acp_handle:%d, idx:%d", __func__,
                              p_cb->rc_acp_handle, p_cb->rc_acp_idx);
             p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1);
-            APPL_TRACE_DEBUG("rc2 handle:%d lidx:%d/%d", p_rcb2->handle,
-                             p_rcb2->lidx, p_cb->lcb[p_rcb2->lidx - 1].lidx);
+            APPL_TRACE_DEBUG("%s: rc2 handle:%d lidx:%d/%d", __func__,
+                             p_rcb2->handle, p_rcb2->lidx,
+                             p_cb->lcb[p_rcb2->lidx - 1].lidx);
           }
           p_rcb->lidx = p_lcb->lidx;
-          APPL_TRACE_DEBUG("rc handle:%d lidx:%d/%d", p_rcb->handle,
-                           p_rcb->lidx, p_cb->lcb[p_rcb->lidx - 1].lidx);
+          APPL_TRACE_DEBUG("%s: rc handle:%d lidx:%d/%d", __func__,
+                           p_rcb->handle, p_rcb->lidx,
+                           p_cb->lcb[p_rcb->lidx - 1].lidx);
         }
       }
     }
@@ -1242,12 +1199,9 @@
 
     /* clear the conned mask for this channel */
     p_cb->conn_audio &= ~mask;
-    p_cb->conn_video &= ~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;
@@ -1262,11 +1216,12 @@
       }
     }
 
-    APPL_TRACE_DEBUG("bta_av_conn_chg shdl:%d", index + 1);
+    APPL_TRACE_DEBUG("%s: shdl:%d", __func__, index + 1);
     for (i = 0; i < BTA_AV_NUM_RCB; i++) {
-      APPL_TRACE_DEBUG("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
-                       bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
-                       bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+      APPL_TRACE_DEBUG("%s: conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d",
+                       __func__, i, bta_av_cb.rcb[i].handle,
+                       bta_av_cb.rcb[i].status, bta_av_cb.rcb[i].shdl,
+                       bta_av_cb.rcb[i].lidx);
       if (bta_av_cb.rcb[i].shdl == index + 1) {
         bta_av_del_rc(&bta_av_cb.rcb[i]);
         /* since the connection is already down and info was removed, clean
@@ -1276,7 +1231,7 @@
       }
     }
 
-    if (p_cb->conn_audio == 0 && p_cb->conn_video == 0) {
+    if (p_cb->conn_audio == 0) {
       /* if both channels are not connected,
        * close all RC channels */
       bta_av_close_all_rc(p_cb);
@@ -1289,10 +1244,10 @@
   }
 
   APPL_TRACE_DEBUG(
-      "bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d "
+      "%s: audio:%x up:%d conn_msk:0x%x chk_restore:%d "
       "audio_open_cnt:%d",
-      p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk,
-      chk_restore, p_cb->audio_open_cnt);
+      __func__, p_cb->conn_audio, p_data->conn_chg.is_up, conn_msk, chk_restore,
+      p_cb->audio_open_cnt);
 
   if (chk_restore) {
     if (p_cb->audio_open_cnt == 1) {
@@ -1312,7 +1267,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]);
           }
         }
@@ -1369,6 +1324,56 @@
   alarm_cancel(bta_av_cb.link_signalling_timer);
 }
 
+/**
+ * Find the index for the free LCB entry to use.
+ *
+ * The selection order is:
+ * (1) Find the index if there is already SCB entry for the peer address
+ * (2) If there is no SCB entry for the peer address, find the first
+ * SCB entry that is not assigned.
+ *
+ * @param peer_address the peer address to use
+ * @return the index for the free LCB entry to use or BTA_AV_NUM_LINKS
+ * if no entry is found
+ */
+static uint8_t bta_av_find_lcb_index_by_scb_and_address(
+    const RawAddress& peer_address) {
+  APPL_TRACE_DEBUG("%s: peer_address: %s conn_lcb: 0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_cb.conn_lcb);
+
+  // Find the index if there is already SCB entry for the peer address
+  for (uint8_t index = 0; index < BTA_AV_NUM_LINKS; index++) {
+    uint8_t mask = 1 << index;
+    if (mask & bta_av_cb.conn_lcb) {
+      continue;
+    }
+    tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[index];
+    if (p_scb == nullptr) {
+      continue;
+    }
+    if (p_scb->PeerAddress() == peer_address) {
+      return index;
+    }
+  }
+
+  // Find the first SCB entry that is not assigned.
+  for (uint8_t index = 0; index < BTA_AV_NUM_LINKS; index++) {
+    uint8_t mask = 1 << index;
+    if (mask & bta_av_cb.conn_lcb) {
+      continue;
+    }
+    tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[index];
+    if (p_scb == nullptr) {
+      continue;
+    }
+    if (!p_scb->IsAssigned()) {
+      return index;
+    }
+  }
+
+  return BTA_AV_NUM_LINKS;
+}
+
 /*******************************************************************************
  *
  * Function         bta_av_sig_chg
@@ -1385,67 +1390,67 @@
   uint8_t mask;
   tBTA_AV_LCB* p_lcb = NULL;
 
-  APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event);
+  APPL_TRACE_DEBUG("%s: event: %d", __func__, event);
   if (event == AVDT_CONNECT_IND_EVT) {
+    APPL_TRACE_DEBUG("%s: AVDT_CONNECT_IND_EVT: peer %s", __func__,
+                     p_data->str_msg.bd_addr.ToString().c_str());
+
     p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
     if (!p_lcb) {
       /* if the address does not have an LCB yet, alloc one */
-      for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
-        mask = 1 << xx;
-        APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
-        /* look for a p_lcb with its p_scb registered */
-        if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL)) {
-          p_lcb = &p_cb->lcb[xx];
-          p_lcb->lidx = xx + 1;
-          p_lcb->addr = p_data->str_msg.bd_addr;
-          p_lcb->conn_msk = 0; /* clear the connect mask */
-          /* start listening when the signal channel is open */
-          if (p_cb->features & BTA_AV_FEAT_RCTG) {
-            bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx);
-          }
-          /* this entry is not used yet. */
-          p_cb->conn_lcb |= mask; /* mark it as used */
-          APPL_TRACE_DEBUG("start sig timer %d", p_data->hdr.offset);
-          if (p_data->hdr.offset == AVDT_ACP) {
-            APPL_TRACE_DEBUG("Incoming L2CAP acquired, set state as incoming",
-                             NULL);
-            p_cb->p_scb[xx]->peer_addr = 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);
-
-            /* The Pending Event should be sent as soon as the L2CAP signalling
-             * channel
-             * is set up, which is NOW. Earlier this was done only after
-             * BTA_AV_SIGNALLING_TIMEOUT_MS.
-             * The following function shall send the event and start the
-             * recurring timer
-             */
-            bta_av_signalling_timer(NULL);
-
-            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);
-            /* Possible collision : need to avoid outgoing processing while the
-             * timer is running */
-            p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
-            alarm_set_on_mloop(p_cb->accept_signalling_timer,
-                               BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
-                               bta_av_accept_signalling_timer_cback,
-                               UINT_TO_PTR(xx));
-          }
-          break;
-        }
-      }
+      xx = bta_av_find_lcb_index_by_scb_and_address(p_data->str_msg.bd_addr);
 
       /* check if we found something */
-      if (xx == BTA_AV_NUM_LINKS) {
+      if (xx >= BTA_AV_NUM_LINKS) {
         /* We do not have scb for this avdt connection.     */
         /* Silently close the connection.                   */
-        APPL_TRACE_ERROR("av scb not available for avdt connection");
+        APPL_TRACE_ERROR("%s: av scb not available for avdt connection for %s",
+                         __func__, p_data->str_msg.bd_addr.ToString().c_str());
         AVDT_DisconnectReq(p_data->str_msg.bd_addr, NULL);
         return;
       }
+      LOG_INFO(LOG_TAG,
+               "%s: AVDT_CONNECT_IND_EVT: peer %s selected lcb_index %d",
+               __func__, p_data->str_msg.bd_addr.ToString().c_str(), xx);
+
+      tBTA_AV_SCB* p_scb = p_cb->p_scb[xx];
+      mask = 1 << xx;
+      p_lcb = &p_cb->lcb[xx];
+      p_lcb->lidx = xx + 1;
+      p_lcb->addr = p_data->str_msg.bd_addr;
+      p_lcb->conn_msk = 0; /* clear the connect mask */
+      /* start listening when the signal channel is open */
+      if (p_cb->features & BTA_AV_FEAT_RCTG) {
+        bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx);
+      }
+      /* this entry is not used yet. */
+      p_cb->conn_lcb |= mask; /* mark it as used */
+      APPL_TRACE_DEBUG("%s: start sig timer %d", __func__, p_data->hdr.offset);
+      if (p_data->hdr.offset == AVDT_ACP) {
+        APPL_TRACE_DEBUG("%s: Incoming L2CAP acquired, set state as incoming",
+                         __func__);
+        p_scb->OnConnected(p_data->str_msg.bd_addr);
+        p_scb->use_rc = true; /* allowing RC for incoming connection */
+        bta_av_ssm_execute(p_scb, BTA_AV_ACP_CONNECT_EVT, p_data);
+
+        /* The Pending Event should be sent as soon as the L2CAP signalling
+         * channel
+         * is set up, which is NOW. Earlier this was done only after
+         * BTA_AV_SIGNALLING_TIMEOUT_MS.
+         * The following function shall send the event and start the
+         * recurring timer
+         */
+        bta_av_signalling_timer(NULL);
+
+        APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__);
+        bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
+        /* Possible collision : need to avoid outgoing processing while the
+         * timer is running */
+        p_scb->coll_mask = BTA_AV_COLL_INC_TMR;
+        alarm_set_on_mloop(
+            p_cb->accept_signalling_timer, BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
+            bta_av_accept_signalling_timer_cback, UINT_TO_PTR(xx));
+      }
     }
   }
 #if (BTA_AR_INCLUDED == TRUE)
@@ -1460,22 +1465,22 @@
 
     p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
     if (p_lcb && (p_lcb->conn_msk || bta_av_cb.conn_lcb)) {
-      APPL_TRACE_DEBUG("conn_msk: 0x%x", p_lcb->conn_msk);
+      APPL_TRACE_DEBUG("%s: conn_msk: 0x%x", __func__, p_lcb->conn_msk);
       /* 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);
         }
       }
@@ -1502,12 +1507,16 @@
   uint8_t mask;
   tBTA_AV_LCB* p_lcb = NULL;
 
-  APPL_TRACE_DEBUG("%s", __func__);
+  APPL_TRACE_DEBUG("%s: conn_lcb=0x%x", __func__, p_cb->conn_lcb);
   for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+    p_lcb = &p_cb->lcb[xx];
     mask = 1 << xx;
+    APPL_TRACE_DEBUG(
+        "%s: index=%d conn_lcb=0x%x peer=%s conn_mask=0x%x lidx=%d", __func__,
+        xx, p_cb->conn_lcb, p_lcb->addr.ToString().c_str(), p_lcb->conn_msk,
+        p_lcb->lidx);
     if (mask & p_cb->conn_lcb) {
       /* this entry is used. check if it is connected */
-      p_lcb = &p_cb->lcb[xx];
       if (!p_lcb->conn_msk) {
         bta_sys_start_timer(p_cb->link_signalling_timer,
                             BTA_AV_SIGNALLING_TIMEOUT_MS,
@@ -1516,6 +1525,10 @@
         pend.bd_addr = p_lcb->addr;
         tBTA_AV bta_av_data;
         bta_av_data.pend = pend;
+        APPL_TRACE_DEBUG(
+            "%s: BTA_AV_PENDING_EVT for %s index=%d conn_mask=0x%x lidx=%d",
+            __func__, pend.bd_addr.ToString().c_str(), xx, p_lcb->conn_msk,
+            p_lcb->lidx);
         (*p_cb->p_cback)(BTA_AV_PENDING_EVT, &bta_av_data);
       }
     }
@@ -1540,7 +1553,7 @@
     p_scb = p_cb->p_scb[inx];
   }
   if (p_scb) {
-    APPL_TRACE_DEBUG("%s coll_mask = 0x%02X", __func__, p_scb->coll_mask);
+    APPL_TRACE_DEBUG("%s: coll_mask = 0x%02X", __func__, p_scb->coll_mask);
 
     if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
       p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR;
@@ -1597,7 +1610,7 @@
   uint16_t peer_rc_version = 0;
   uint16_t categories = 0;
 
-  APPL_TRACE_DEBUG("bta_av_check_peer_features service_uuid:x%x", service_uuid);
+  APPL_TRACE_DEBUG("%s: service_uuid:x%x", __func__, service_uuid);
   /* loop through all records we found */
   while (true) {
     /* get next record; if none found, we're done */
@@ -1623,7 +1636,7 @@
       /* get profile version (if failure, version parameter is not updated) */
       SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
                                   &peer_rc_version);
-      APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version);
+      APPL_TRACE_DEBUG("%s: peer_rc_version 0x%x", __func__, peer_rc_version);
 
       if (peer_rc_version >= AVRC_REV_1_3)
         peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
@@ -1641,7 +1654,7 @@
       }
     }
   }
-  APPL_TRACE_DEBUG("peer_features:x%x", peer_features);
+  APPL_TRACE_DEBUG("%s: peer_features:x%x", __func__, peer_features);
   return peer_features;
 }
 
@@ -1659,13 +1672,14 @@
   tBTA_AV_FEAT peer_features = 0;
   tBTA_AV_CB* p_cb = &bta_av_cb;
 
-  APPL_TRACE_DEBUG("%s service_uuid:x%x", __func__, service_uuid);
+  APPL_TRACE_DEBUG("%s: service_uuid:x%x", __func__, service_uuid);
 
   /* loop through all records we found */
   tSDP_DISC_REC* p_rec =
       SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL);
   while (p_rec) {
-    APPL_TRACE_DEBUG("%s found Service record for x%x", __func__, service_uuid);
+    APPL_TRACE_DEBUG("%s: found Service record for x%x", __func__,
+                     service_uuid);
 
     if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) !=
         NULL) {
@@ -1685,7 +1699,7 @@
       uint16_t peer_rc_version = 0;
       bool val = SDP_FindProfileVersionInRec(
           p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
-      APPL_TRACE_DEBUG("%s peer_rc_version for TG 0x%x, profile_found %d",
+      APPL_TRACE_DEBUG("%s: peer_rc_version for TG 0x%x, profile_found %d",
                        __func__, peer_rc_version, val);
 
       if (peer_rc_version >= AVRC_REV_1_3)
@@ -1716,7 +1730,7 @@
     /* get next record; if none found, we're done */
     p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
   }
-  APPL_TRACE_DEBUG("%s peer_features:x%x", __func__, peer_features);
+  APPL_TRACE_DEBUG("%s: peer_features:x%x", __func__, peer_features);
   return peer_features;
 }
 
@@ -1737,7 +1751,7 @@
   uint8_t rc_handle;
   tBTA_AV_FEAT peer_features = 0; /* peer features mask */
 
-  APPL_TRACE_DEBUG("%s bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc);
+  APPL_TRACE_DEBUG("%s: bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc);
   if (!p_cb->disc) {
     return;
   }
@@ -1758,13 +1772,13 @@
     }
   }
 
-  APPL_TRACE_DEBUG("%s rc_handle %d", __func__, rc_handle);
+  APPL_TRACE_DEBUG("%s: rc_handle %d", __func__, rc_handle);
 #if (BTA_AV_SINK_INCLUDED == TRUE)
   if (p_cb->sdp_a2dp_snk_handle) {
     /* This is Sink + CT + TG(Abs Vol) */
     peer_features =
         bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
-    APPL_TRACE_DEBUG("%s populating rem ctrl target features %d", __func__,
+    APPL_TRACE_DEBUG("%s: populating rem ctrl target features %d", __func__,
                      peer_features);
     if (BTA_AV_FEAT_ADV_CTRL &
         bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
@@ -1795,9 +1809,9 @@
       SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
                                   &peer_rc_version);
       if (peer_rc_version <= AVRC_REV_1_3) {
-        APPL_TRACE_DEBUG("%s Using AVRCP 1.3 Capabilities with remote device",
+        APPL_TRACE_DEBUG("%s: Using AVRCP 1.3 Capabilities with remote device",
                          __func__);
-        p_bta_av_cfg = (tBTA_AV_CFG*)&bta_av_cfg_compatibility;
+        p_bta_av_cfg = &bta_av_cfg_compatibility;
       }
     }
   }
@@ -1805,8 +1819,8 @@
   p_cb->disc = 0;
   osi_free_and_reset((void**)&p_cb->p_disc_db);
 
-  APPL_TRACE_DEBUG("peer_features 0x%x, features 0x%x", peer_features,
-                   p_cb->features);
+  APPL_TRACE_DEBUG("%s: peer_features 0x%x, features 0x%x", __func__,
+                   peer_features, p_cb->features);
 
   /* if we have no rc connection */
   if (rc_handle == BTA_AV_RC_HANDLE_NONE) {
@@ -1816,19 +1830,19 @@
             (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);
           p_cb->rcb[rc_handle].peer_features = peer_features;
         } else {
-          APPL_TRACE_ERROR("can not find LCB!!");
+          APPL_TRACE_ERROR("%s: can not find LCB!!", __func__);
         }
       } else if (p_scb->use_rc) {
         /* 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;
@@ -1849,7 +1863,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;
@@ -1878,32 +1892,35 @@
 
   rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE;
   p_scb = NULL;
-  APPL_TRACE_DEBUG("bta_av_rc_closed rc_handle:%d", p_msg->handle);
+  APPL_TRACE_DEBUG("%s: rc_handle:%d", __func__, p_msg->handle);
   for (i = 0; i < BTA_AV_NUM_RCB; i++) {
     p_rcb = &p_cb->rcb[i];
-    APPL_TRACE_DEBUG("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i,
+    APPL_TRACE_DEBUG("%s: rcb[%d] rc_handle:%d, status=0x%x", __func__, i,
                      p_rcb->handle, p_rcb->status);
     if (p_rcb->handle == p_msg->handle) {
       rc_close.rc_handle = i;
       p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
       p_rcb->peer_features = 0;
-      APPL_TRACE_DEBUG("       shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
+      APPL_TRACE_DEBUG("%s: shdl:%d, lidx:%d", __func__, p_rcb->shdl,
+                       p_rcb->lidx);
       if (p_rcb->shdl) {
         if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {
           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("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
+          APPL_TRACE_DEBUG("%s: shdl:%d, srch:%d", __func__, p_rcb->shdl,
+                           p_scb->rc_handle);
         }
         p_rcb->shdl = 0;
       } else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1)) {
         /* if the RCB uses the extra LCB, use the addr for event and clean it */
         p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
         rc_close.peer_addr = p_msg->peer_addr;
-        VLOG(1) << "rc_only closed bd_addr:" << p_msg->peer_addr;
+        LOG_INFO(LOG_TAG, "%s: rc_only closed bd_addr: %s", __func__,
+                 p_msg->peer_addr.ToString().c_str());
         p_lcb->conn_msk = 0;
         p_lcb->lidx = 0;
       }
@@ -1957,8 +1974,8 @@
   tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
   tBTA_AV_RC_BROWSE_OPEN rc_browse_open;
 
-  VLOG(1) << "bta_av_rc_browse_opened bd_addr:" << p_msg->peer_addr;
-  APPL_TRACE_DEBUG("bta_av_rc_browse_opened rc_handle:%d", p_msg->handle);
+  LOG_INFO(LOG_TAG, "%s: peer_addr: %s rc_handle:%d", __func__,
+           p_msg->peer_addr.ToString().c_str(), p_msg->handle);
 
   rc_browse_open.status = BTA_AV_SUCCESS;
   rc_browse_open.rc_handle = p_msg->handle;
@@ -1983,8 +2000,8 @@
   tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
   tBTA_AV_RC_BROWSE_CLOSE rc_browse_close;
 
-  VLOG(1) << "bta_av_rc_browse_closed bd_addr:" << p_msg->peer_addr;
-  APPL_TRACE_DEBUG("bta_av_rc_browse_closed rc_handle:%d", p_msg->handle);
+  LOG_INFO(LOG_TAG, "%s: peer_addr: %s rc_handle:%d", __func__,
+           p_msg->peer_addr.ToString().c_str(), p_msg->handle);
 
   rc_browse_close.rc_handle = p_msg->handle;
   rc_browse_close.peer_addr = p_msg->peer_addr;
@@ -2011,29 +2028,30 @@
                           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("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc);
+  APPL_TRACE_DEBUG("%s: disc: 0x%x, bta_av_cb.disc: 0x%x", __func__, disc,
+                   bta_av_cb.disc);
   if ((bta_av_cb.disc != 0) || (disc == 0)) return;
 
   if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) {
     /* 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;
     p_scb = p_cb->p_scb[hdi];
 
     if (p_scb) {
-      APPL_TRACE_DEBUG("rc_handle %d", p_scb->rc_handle);
-      p_addr = &p_scb->peer_addr;
+      APPL_TRACE_DEBUG("%s: rc_handle %d", __func__, p_scb->rc_handle);
+      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);
@@ -2045,10 +2063,11 @@
     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,
-                         bta_av_avrc_sdp_cback) == AVRC_SUCCESS) {
+    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("disc %d", p_cb->disc);
+      APPL_TRACE_DEBUG("%s: disc 0x%x", __func__, p_cb->disc);
     }
   }
 }
@@ -2073,62 +2092,52 @@
   p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
 
   if (p_scb) {
-    APPL_TRACE_DEBUG("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
+    APPL_TRACE_DEBUG("%s: deregistered %d(h%d)", __func__, p_scb->chnl,
+                     p_scb->hndl);
     mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
-    if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
-      p_cb->reg_audio &= ~mask;
-      if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) {
-        /* this channel is still marked as open. decrease the count */
-        bta_av_cb.audio_open_cnt--;
-      }
-      p_cb->conn_audio &= ~mask;
+    p_cb->reg_audio &= ~mask;
+    if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) {
+      /* this channel is still marked as open. decrease the count */
+      bta_av_cb.audio_open_cnt--;
+    }
+    p_cb->conn_audio &= ~mask;
 
-      if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM && p_scb->a2dp_list) {
-        /* make sure no buffers are in a2dp_list */
-        while (!list_is_empty(p_scb->a2dp_list)) {
-          p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
-          list_remove(p_scb->a2dp_list, p_buf);
-          osi_free(p_buf);
-        }
+    if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM && p_scb->a2dp_list) {
+      /* make sure no buffers are in a2dp_list */
+      while (!list_is_empty(p_scb->a2dp_list)) {
+        p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+        list_remove(p_scb->a2dp_list, p_buf);
+        osi_free(p_buf);
       }
-
-      /* remove the A2DP SDP record, if no more audio stream is left */
-      if (!p_cb->reg_audio) {
-#if (BTA_AR_INCLUDED == TRUE)
-        bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
-#endif
-        if (p_cb->sdp_a2dp_handle) {
-          bta_av_del_sdp_rec(&p_cb->sdp_a2dp_handle);
-          p_cb->sdp_a2dp_handle = 0;
-          bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
-        }
-
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-        if (p_cb->sdp_a2dp_snk_handle) {
-          bta_av_del_sdp_rec(&p_cb->sdp_a2dp_snk_handle);
-          p_cb->sdp_a2dp_snk_handle = 0;
-          bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
-        }
-#endif
-      }
-    } else {
-      p_cb->reg_video &= ~mask;
-      /* make sure that this channel is not connected */
-      p_cb->conn_video &= ~mask;
-      /* remove the VDP SDP record, (only one video stream at most) */
-      bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle);
-      bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE);
     }
 
-    /* make sure that the timer is not active */
-    alarm_cancel(p_scb->avrc_ct_timer);
-    osi_free_and_reset((void**)&p_cb->p_scb[p_scb->hdi]);
+    /* remove the A2DP SDP record, if no more audio stream is left */
+    if (!p_cb->reg_audio) {
+#if (BTA_AR_INCLUDED == TRUE)
+      bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
+#endif
+      if (p_cb->sdp_a2dp_handle) {
+        bta_av_del_sdp_rec(&p_cb->sdp_a2dp_handle);
+        p_cb->sdp_a2dp_handle = 0;
+        bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+      }
+
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+      if (p_cb->sdp_a2dp_snk_handle) {
+        bta_av_del_sdp_rec(&p_cb->sdp_a2dp_snk_handle);
+        p_cb->sdp_a2dp_snk_handle = 0;
+        bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+      }
+#endif
+    }
+
+    bta_av_free_scb(p_scb);
   }
 
-  APPL_TRACE_DEBUG("audio 0x%x, video: 0x%x, disable:%d", p_cb->reg_audio,
-                   p_cb->reg_video, p_cb->disabling);
+  APPL_TRACE_DEBUG("%s: audio 0x%x, disable:%d", __func__, p_cb->reg_audio,
+                   p_cb->disabling);
   /* if no stream control block is active */
-  if ((p_cb->reg_audio + p_cb->reg_video) == 0) {
+  if (p_cb->reg_audio == 0) {
 #if (BTA_AR_INCLUDED == TRUE)
     /* deregister from AVDT */
     bta_ar_dereg_avdt(BTA_ID_AV);
diff --git a/bta/av/bta_av_api.cc b/bta/av/bta_av_api.cc
index 82ed10c..bb5cca4 100644
--- a/bta/av/bta_av_api.cc
+++ b/bta/av/bta_av_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2011-2012 Broadcom Corporation
+ *  Copyright 2011-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
  *
  ******************************************************************************/
 
+#define LOG_TAG "bt_bta_av"
+
 #include <base/logging.h>
 
 #include "bt_target.h"
@@ -36,6 +38,7 @@
 #include "bta_sys.h"
 
 #include "osi/include/allocator.h"
+#include "osi/include/log.h"
 
 /*****************************************************************************
  *  Constants
@@ -153,6 +156,10 @@
  ******************************************************************************/
 void BTA_AvOpen(const RawAddress& bd_addr, tBTA_AV_HNDL handle, bool use_rc,
                 tBTA_SEC sec_mask, uint16_t uuid) {
+  LOG_INFO(LOG_TAG, "%s: peer %s handle:0x%x use_rc=%s sec_mask=0x%x uuid=0x%x",
+           __func__, bd_addr.ToString().c_str(), handle,
+           (use_rc) ? "true" : "false", sec_mask, uuid);
+
   tBTA_AV_API_OPEN* p_buf =
       (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
 
@@ -177,6 +184,8 @@
  *
  ******************************************************************************/
 void BTA_AvClose(tBTA_AV_HNDL handle) {
+  LOG_INFO(LOG_TAG, "%s: handle:0x%x", __func__, handle);
+
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
 
   p_buf->event = BTA_AV_API_CLOSE_EVT;
@@ -195,6 +204,8 @@
  *
  ******************************************************************************/
 void BTA_AvDisconnect(const RawAddress& bd_addr) {
+  LOG_INFO(LOG_TAG, "%s: peer %s", __func__, bd_addr.ToString().c_str());
+
   tBTA_AV_API_DISCNT* p_buf =
       (tBTA_AV_API_DISCNT*)osi_malloc(sizeof(tBTA_AV_API_DISCNT));
 
@@ -213,10 +224,13 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AvStart(void) {
+void BTA_AvStart(tBTA_AV_HNDL handle) {
+  LOG_INFO(LOG_TAG, "%s: handle=%d", __func__, handle);
+
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
 
   p_buf->event = BTA_AV_API_START_EVT;
+  p_buf->layer_specific = handle;
 
   bta_sys_sendmsg(p_buf);
 }
@@ -231,6 +245,8 @@
  *
  ******************************************************************************/
 void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) {
+  LOG_INFO(LOG_TAG, "%s: handle=%d", __func__, hndl);
+
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
 
   p_buf->event = BTA_AV_API_OFFLOAD_START_EVT;
@@ -270,11 +286,15 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AvStop(bool suspend) {
+void BTA_AvStop(tBTA_AV_HNDL handle, bool suspend) {
+  LOG_INFO(LOG_TAG, "%s: handle=%d suspend=%s", __func__, handle,
+           logbool(suspend).c_str());
+
   tBTA_AV_API_STOP* p_buf =
       (tBTA_AV_API_STOP*)osi_malloc(sizeof(tBTA_AV_API_STOP));
 
   p_buf->hdr.event = BTA_AV_API_STOP_EVT;
+  p_buf->hdr.layer_specific = handle;
   p_buf->flush = true;
   p_buf->suspend = suspend;
   p_buf->reconfig_stop = false;
@@ -298,6 +318,9 @@
 void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx,
                     uint8_t* p_codec_info, uint8_t num_protect,
                     const uint8_t* p_protect_info) {
+  LOG_INFO(LOG_TAG, "%s: handle=%d suspend=%s sep_info_idx=%d", __func__, hndl,
+           logbool(suspend).c_str(), sep_info_idx);
+
   tBTA_AV_API_RCFG* p_buf =
       (tBTA_AV_API_RCFG*)osi_malloc(sizeof(tBTA_AV_API_RCFG) + num_protect);
 
diff --git a/bta/av/bta_av_cfg.cc b/bta/av/bta_av_cfg.cc
index 688af45..76c9454 100644
--- a/bta/av/bta_av_cfg.cc
+++ b/bta/av/bta_av_cfg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2016 Broadcom Corporation
+ *  Copyright 2005-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
 #endif
 
 #ifndef BTA_AV_RC_PASS_RSP_CODE
-#define BTA_AV_RC_PASS_RSP_CODE BTA_AV_RSP_NOT_IMPL
+#define BTA_AV_RC_PASS_RSP_CODE AVRC_RSP_NOT_IMPL
 #endif
 
 const uint32_t bta_av_meta_caps_co_ids[] = {AVRC_CO_METADATA, AVRC_CO_BROADCOM};
@@ -74,13 +74,9 @@
 /* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be true
  */
 #ifndef BTA_AV_RC_SUPF_TG
-#if (AVRC_METADATA_INCLUDED == TRUE)
 #define BTA_AV_RC_SUPF_TG                          \
   (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_MULTI_PLAYER | \
    AVRC_SUPF_TG_BROWSE) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
-#else
-#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
-#endif
 #endif
 
 /*
@@ -132,24 +128,16 @@
 
 /* This configuration to be used when we are Src + TG + CT( only for abs vol) */
 const tBTA_AV_CFG bta_av_cfg = {
-    BTA_AV_RC_COMP_ID, /* AVRCP Company ID */
-#if (AVRC_METADATA_INCLUDED == TRUE)
-    512,                  /* AVRCP MTU at L2CAP for control channel */
-    BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
-#else
-    48,                   /* AVRCP MTU at L2CAP for control channel */
-    BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
-#endif
+    BTA_AV_RC_COMP_ID,     /* AVRCP Company ID */
+    512,                   /* AVRCP MTU at L2CAP for control channel */
+    BTA_AV_MAX_RC_BR_MTU,  /* AVRCP MTU at L2CAP for browsing channel */
     BTA_AV_RC_SUPF_CT,     /* AVRCP controller categories */
     BTA_AV_RC_SUPF_TG,     /* AVRCP target categories */
     672,                   /* AVDTP signaling channel MTU at L2CAP */
-    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP
-                              */
+    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP */
     bta_av_audio_flush_to, /* AVDTP audio transport channel flush
                               timeout */
     6,                     /* AVDTP audio channel max data queue size */
-    BTA_AV_MAX_VDP_MTU,    /* AVDTP video transport channel MTU at L2CAP */
-    600,                   /* AVDTP video transport channel flush timeout */
     false, /* true, to accept AVRC 1.3 group nevigation command */
     2,     /* company id count in p_meta_co_ids */
     BTA_AV_NUM_RC_EVT_IDS,    /* event id count in p_meta_evt_ids */
@@ -159,8 +147,7 @@
                                  for company id */
     bta_av_meta_caps_evt_ids, /* the the metadata Get Capabilities
                                  response for event id */
-    NULL,                     /* the action function table for VDP stream */
-    NULL,                     /* action function to register VDP */
+    NULL,                     /* the action function table for audio stream */
     BTA_AV_RC_CT_NAME,        /* Default AVRCP controller name */
     BTA_AV_RC_TG_NAME         /* Default AVRCP target name */
 };
@@ -168,23 +155,15 @@
 /* This configuration to be used when we are Sink + CT + TG( only for abs vol)
  */
 const tBTA_AV_CFG bta_avk_cfg = {
-    AVRC_CO_METADATA, /* AVRCP Company ID */
-#if (AVRC_METADATA_INCLUDED == TRUE)
-    512, /* AVRCP MTU at L2CAP for control channel */
-#else
-    48,                   /* AVRCP MTU at L2CAP for control channel */
-#endif
+    AVRC_CO_METADATA,      /* AVRCP Company ID */
+    512,                   /* AVRCP MTU at L2CAP for control channel */
     BTA_AV_MAX_RC_BR_MTU,  /* AVRCP MTU at L2CAP for browsing channel */
     BTA_AVK_RC_SUPF_CT,    /* AVRCP controller categories */
     BTA_AVK_RC_SUPF_TG,    /* AVRCP target categories */
     672,                   /* AVDTP signaling channel MTU at L2CAP */
-    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP
-                              */
-    bta_av_audio_flush_to, /* AVDTP audio transport channel flush
-                              timeout */
+    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP */
+    bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
     6,                     /* AVDTP audio channel max data queue size */
-    BTA_AV_MAX_VDP_MTU,    /* AVDTP video transport channel MTU at L2CAP */
-    600,                   /* AVDTP video transport channel flush timeout */
     false, /* true, to accept AVRC 1.3 group nevigation command */
     2,     /* company id count in p_meta_co_ids */
     BTA_AVK_NUM_RC_EVT_IDS,    /* event id count in p_meta_evt_ids */
@@ -194,49 +173,38 @@
                                   for company id */
     bta_avk_meta_caps_evt_ids, /* the the metadata Get Capabilities
                                   response for event id */
-    NULL,                      /* the action function table for VDP stream */
-    NULL,                      /* action function to register VDP */
+    NULL,                      /* the action function table for audio stream */
     {0},                       /* Default AVRCP controller name */
     {0},                       /* Default AVRCP target name */
 };
 
 /* This configuration to be used when we are using AVRCP1.3 */
 const tBTA_AV_CFG bta_av_cfg_compatibility = {
-    BTA_AV_RC_COMP_ID, /* AVRCP Company ID */
-#if (AVRC_METADATA_INCLUDED == TRUE)
-    512,                  /* AVRCP MTU at L2CAP for control channel */
-    BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
-#else
-    48,                   /* AVRCP MTU at L2CAP for control channel */
-    BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
-#endif
-    BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
-    AVRC_SUPF_TG_CAT1, /* Only support CAT1 for AVRCP1.3 */
-    672,               /* AVDTP signaling channel MTU at L2CAP */
-    BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP
-                          */
-    bta_av_audio_flush_to, /* AVDTP audio transport channel flush
-                              timeout */
-    6,                  /* AVDTP audio channel max data queue size */
-    BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */
-    600,                /* AVDTP video transport channel flush timeout */
-    false,              /* true, to accept AVRC 1.3 group nevigation command */
-    2,                  /* company id count in p_meta_co_ids */
-    BTA_AV_NUM_RC_EVT_IDS_AVRCP13,    /* event id count for AVRCP1.3*/
+    BTA_AV_RC_COMP_ID,     /* AVRCP Company ID */
+    512,                   /* AVRCP MTU at L2CAP for control channel */
+    BTA_AV_MAX_RC_BR_MTU,  /* AVRCP MTU at L2CAP for browsing channel */
+    BTA_AV_RC_SUPF_CT,     /* AVRCP controller categories */
+    AVRC_SUPF_TG_CAT1,     /* Only support CAT1 for AVRCP1.3 */
+    672,                   /* AVDTP signaling channel MTU at L2CAP */
+    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP */
+    bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
+    6,                     /* AVDTP audio channel max data queue size */
+    false, /* true, to accept AVRC 1.3 group nevigation command */
+    2,     /* company id count in p_meta_co_ids */
+    BTA_AV_NUM_RC_EVT_IDS_AVRCP13,    /* event id count for AVRCP1.3 */
     BTA_AV_RC_PASS_RSP_CODE,          /* the default response code for pass
                                          through commands */
     bta_av_meta_caps_co_ids,          /* the metadata Get Capabilities response
                                          for company id */
     bta_av_meta_caps_evt_ids_avrcp13, /* the the metadata Get Capabilities
                                          response for event id, compatible
-                                         with AVRCP1.3*/
-    NULL,              /* the action function table for VDP stream */
-    NULL,              /* action function to register VDP */
+                                         with AVRCP1.3 */
+    NULL,              /* the action function table for audio stream */
     BTA_AV_RC_CT_NAME, /* Default AVRCP controller name */
     BTA_AV_RC_TG_NAME  /* Default AVRCP target name */
 };
 
-tBTA_AV_CFG* p_bta_av_cfg = NULL;
+const tBTA_AV_CFG* p_bta_av_cfg = NULL;
 
 const uint16_t bta_av_rc_id[] = {
     0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
@@ -264,15 +232,11 @@
  * bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, 4=PLAY, 5=STOP,
              6=PAUSE, 7=RECORD, 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
              12=BACKWARD */
-#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+#if (BTA_AV_RC_PASS_RSP_CODE == AVRC_RSP_INTERIM)
     0x0070, /* PLAY | STOP | PAUSE */
-#else       /* BTA_AV_RC_PASS_RSP_CODE != BTA_AV_RSP_INTERIM */
-#if (BTA_AVRCP_FF_RW_SUPPORT == TRUE)
+#else       /* BTA_AV_RC_PASS_RSP_CODE != AVRC_RSP_INTERIM */
     0x1b7E, /* PLAY | STOP | PAUSE | FF | RW | VOL_UP | VOL_DOWN | MUTE | FW |
                BACK */
-#else  /* BTA_AVRCP_FF_RW_SUPPORT == FALSE */
-    0x187E, /* PLAY | STOP | PAUSE | VOL_UP | VOL_DOWN | MUTE | FW | BACK */
-#endif /* BTA_AVRCP_FF_RW_SUPPORT */
 #endif /* BTA_AV_RC_PASS_RSP_CODE */
 
     0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
@@ -283,7 +247,7 @@
                         4=F4, 5=F5 */
 };
 
-#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+#if (BTA_AV_RC_PASS_RSP_CODE == AVRC_RSP_INTERIM)
 const uint16_t bta_av_rc_id_ac[] = {
     0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
                          4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN,
diff --git a/bta/av/bta_av_ci.cc b/bta/av/bta_av_ci.cc
index a215046..a3d552d 100644
--- a/bta/av/bta_av_ci.cc
+++ b/bta/av/bta_av_ci.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +23,10 @@
  *
  ******************************************************************************/
 
+#define LOG_TAG "bt_bta_av"
+
+#include "osi/include/log.h"
+
 #include "bta_av_ci.h"
 #include "bta_api.h"
 #include "bta_av_int.h"
@@ -36,7 +40,7 @@
  *
  * Description      This function sends an event to the AV indicating that
  *                  the phone has audio stream data ready to send and AV
- *                  should call bta_av_co_audio_src_data_path().
+ *                  should call bta_av_co_audio_source_data_path().
  *
  * Returns          void
  *
@@ -63,13 +67,19 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, uint8_t err_code, uint8_t category,
-                         uint8_t num_seid, uint8_t* p_seid, bool recfg_needed,
-                         uint8_t avdt_handle) {
+void bta_av_ci_setconfig(tBTA_AV_HNDL bta_av_handle, uint8_t err_code,
+                         uint8_t category, uint8_t num_seid, uint8_t* p_seid,
+                         bool recfg_needed, uint8_t avdt_handle) {
+  LOG_DEBUG(LOG_TAG,
+            "%s: bta_av_handle=%d err_code=%d category=%d "
+            "num_seid=%d recfg_needed=%s avdt_handle=%d",
+            __func__, bta_av_handle, err_code, category, num_seid,
+            recfg_needed ? "true" : "false", avdt_handle);
+
   tBTA_AV_CI_SETCONFIG* p_buf =
       (tBTA_AV_CI_SETCONFIG*)osi_malloc(sizeof(tBTA_AV_CI_SETCONFIG));
 
-  p_buf->hdr.layer_specific = hndl;
+  p_buf->hdr.layer_specific = bta_av_handle;
   p_buf->hdr.event = (err_code == A2DP_SUCCESS) ? BTA_AV_CI_SETCONFIG_OK_EVT
                                                 : BTA_AV_CI_SETCONFIG_FAIL_EVT;
   p_buf->err_code = err_code;
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
index 963a84a..17c4bf3 100644
--- a/bta/av/bta_av_int.h
+++ b/bta/av/bta_av_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -101,9 +101,7 @@
   BTA_AV_AVRC_BROWSE_CLOSE_EVT,
   BTA_AV_CONN_CHG_EVT,
   BTA_AV_DEREG_COMP_EVT,
-#if (AVDT_REPORTING == TRUE)
   BTA_AV_AVDT_RPT_CONN_EVT,
-#endif
   BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as
                            the *AP_*EVT */
   BTA_AV_API_STOP_EVT
@@ -133,7 +131,7 @@
 #define BTA_AV_RC_HANDLE_NONE 0xFF
 
 /* size of database for service discovery */
-#define BTA_AV_DISC_BUF_SIZE 1000
+#define BTA_AV_DISC_BUF_SIZE 2000
 
 /* maximum length of AVDTP security data */
 #define BTA_AV_SECURITY_MAX_LEN 400
@@ -158,30 +156,43 @@
 
 /* function types for call-out functions */
 typedef bool (*tBTA_AV_CO_INIT)(btav_a2dp_codec_index_t codec_index,
-                                tAVDT_CFG* p_cfg);
-typedef void (*tBTA_AV_CO_DISC_RES)(tBTA_AV_HNDL hndl, uint8_t num_seps,
-                                    uint8_t num_snk, uint8_t num_src,
-                                    const RawAddress& addr,
-                                    uint16_t uuid_local);
-typedef tA2DP_STATUS (*tBTA_AV_CO_GETCFG)(tBTA_AV_HNDL hndl,
+                                AvdtpSepConfig* p_cfg);
+typedef void (*tBTA_AV_CO_DISC_RES)(tBTA_AV_HNDL bta_av_handle,
+                                    const RawAddress& peer_addr,
+                                    uint8_t num_seps, uint8_t num_snk,
+                                    uint8_t num_src, uint16_t uuid_local);
+typedef tA2DP_STATUS (*tBTA_AV_CO_GETCFG)(tBTA_AV_HNDL bta_av_handle,
+                                          const RawAddress& peer_addr,
                                           uint8_t* p_codec_info,
                                           uint8_t* p_sep_info_idx, uint8_t seid,
                                           uint8_t* p_num_protect,
                                           uint8_t* p_protect_info);
-typedef void (*tBTA_AV_CO_SETCFG)(tBTA_AV_HNDL hndl,
+typedef void (*tBTA_AV_CO_SETCFG)(tBTA_AV_HNDL bta_av_handle,
+                                  const RawAddress& peer_addr,
                                   const uint8_t* p_codec_info, uint8_t seid,
-                                  const RawAddress& addr, uint8_t num_protect,
+                                  uint8_t num_protect,
                                   const uint8_t* p_protect_info,
                                   uint8_t t_local_sep, uint8_t avdt_handle);
-typedef void (*tBTA_AV_CO_OPEN)(tBTA_AV_HNDL hndl, uint16_t mtu);
-typedef void (*tBTA_AV_CO_CLOSE)(tBTA_AV_HNDL hndl);
-typedef void (*tBTA_AV_CO_START)(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
-                                 bool* p_no_rtp_hdr);
-typedef void (*tBTA_AV_CO_STOP)(tBTA_AV_HNDL hndl);
-typedef void* (*tBTA_AV_CO_DATAPATH)(const uint8_t* p_codec_info,
-                                     uint32_t* p_timestamp);
-typedef void (*tBTA_AV_CO_DELAY)(tBTA_AV_HNDL hndl, uint16_t delay);
-typedef void (*tBTA_AV_CO_UPDATE_MTU)(tBTA_AV_HNDL hndl, uint16_t mtu);
+typedef void (*tBTA_AV_CO_OPEN)(tBTA_AV_HNDL bta_av_handle,
+                                const RawAddress& peer_addr, uint16_t mtu);
+typedef void (*tBTA_AV_CO_CLOSE)(tBTA_AV_HNDL bta_av_handle,
+                                 const RawAddress& peer_addr);
+typedef void (*tBTA_AV_CO_START)(tBTA_AV_HNDL bta_av_handle,
+                                 const RawAddress& peer_addr,
+                                 const uint8_t* p_codec_info,
+                                 bool* p_no_rtp_header);
+typedef void (*tBTA_AV_CO_STOP)(tBTA_AV_HNDL bta_av_handle,
+                                const RawAddress& peer_addr);
+typedef BT_HDR* (*tBTA_AV_CO_DATAPATH)(const uint8_t* p_codec_info,
+                                       uint32_t* p_timestamp);
+typedef void (*tBTA_AV_CO_DELAY)(tBTA_AV_HNDL bta_av_handle,
+                                 const RawAddress& peer_addr, uint16_t delay);
+typedef void (*tBTA_AV_CO_UPDATE_MTU)(tBTA_AV_HNDL bta_av_handle,
+                                      const RawAddress& peer_addr,
+                                      uint16_t mtu);
+
+typedef bool (*tBTA_AV_CO_CONTENT_PROTECT_IS_ACTIVE)(
+    const RawAddress& peer_addr);
 
 /* the call-out functions for one stream */
 typedef struct {
@@ -196,6 +207,7 @@
   tBTA_AV_CO_DATAPATH data;
   tBTA_AV_CO_DELAY delay;
   tBTA_AV_CO_UPDATE_MTU update_mtu;
+  tBTA_AV_CO_CONTENT_PROTECT_IS_ACTIVE cp_is_active;
 } tBTA_AV_CO_FUNCTS;
 
 /* data type for BTA_AV_API_ENABLE_EVT */
@@ -315,9 +327,10 @@
 /* data type for all stream events from AVDTP */
 typedef struct {
   BT_HDR hdr;
-  tAVDT_CFG cfg;   /* configuration/capabilities parameters */
+  AvdtpSepConfig cfg; /* configuration/capabilities parameters */
   tAVDT_CTRL msg;  /* AVDTP callback message parameters */
   RawAddress bd_addr; /* bd address */
+  uint8_t scb_index;
   uint8_t handle;
   uint8_t avdt_event;
   bool initiator; /* true, if local device initiates the SUSPEND */
@@ -356,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 */
@@ -386,7 +398,7 @@
 #define BTA_AV_ROLE_SUSPEND_OPT 0x40 /* Suspend on Start option is set */
 
 /* union of all event datatypes */
-typedef union {
+union tBTA_AV_DATA {
   BT_HDR hdr;
   tBTA_AV_API_ENABLE api_enable;
   tBTA_AV_API_REG api_reg;
@@ -407,7 +419,7 @@
   tBTA_AV_SDP_RES sdp_res;
   tBTA_AV_API_META_RSP api_meta_rsp;
   tBTA_AV_API_STATUS_RSP api_status_rsp;
-} tBTA_AV_DATA;
+};
 
 typedef union {
   tBTA_AV_API_OPEN open; /* used only before open and role switch
@@ -443,21 +455,21 @@
   0x02 /* API open was called while incoming timer is running */
 
 /* type for AV stream control block */
-typedef struct {
+// 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 */
   tBTA_AV_SEP seps[BTAV_A2DP_CODEC_INDEX_MAX];
-  tAVDT_CFG* p_cap;  /* buffer used for get capabilities */
+  AvdtpSepConfig peer_cap; /* buffer used for get capabilities */
   list_t* a2dp_list; /* used for audio channels only */
   tBTA_AV_Q_INFO q_info;
   tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */
-  tAVDT_CFG cfg;                            /* local SEP configuration */
+  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 */
@@ -483,24 +495,67 @@
   uint8_t rc_handle; /* connected AVRCP handle */
   bool use_rc;       /* true if AVRCP is allowed */
   bool started;      /* true if stream started */
-  A2dpCodecConfig* current_codec; /* The current A2DP codec */
+  bool use_rtp_header_marker_bit; /* true if the encoded data packets have RTP
+                                   * headers, and the Marker bit in the header
+                                   * is set according to RFC 6416 */
   uint8_t
       co_started;    /* non-zero, if stream started from call-out perspective */
   bool recfg_sup;    /* true if the first attempt to reconfigure the stream was
                         successfull, else False if command fails */
   bool suspend_sup;  /* true if Suspend stream is supported, else false if
                         suspend command fails */
-  bool deregistring; /* true if deregistering */
+  bool deregistering; /* true if deregistering */
   bool sco_suspend;  /* true if SUSPEND is issued automatically for SCO */
   uint8_t coll_mask; /* Mask to check incoming and outgoing collision */
   tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */
   uint8_t wait;  /* set 0x1, when getting Caps as ACP, set 0x2, when started */
   uint8_t q_tag; /* identify the associated q_info union member */
-  bool no_rtp_hdr;   /* true if add no RTP header*/
+  bool no_rtp_header; /* true if add no RTP header */
   uint16_t uuid_int; /*intended UUID of Initiator to connect to */
   bool offload_start_pending;
-  bool skip_sdp; /* Decides if sdp to be done prior to profile connection */
-} tBTA_AV_SCB;
+  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);
+
+  /**
+   * Check whether the entry is assigned and currenty used.
+   *
+   * @return true if the entry is assigned and currently used
+   */
+  bool IsAssigned() const { return !peer_address_.IsEmpty(); }
+
+ private:
+  RawAddress peer_address_;  // Peer address
+  uint16_t avdtp_version_;   // The AVDTP version of the peer device
+};
 
 #define BTA_AV_RC_ROLE_MASK 0x10
 #define BTA_AV_RC_ROLE_INT 0x00
@@ -543,7 +598,6 @@
       accept_signalling_timer;  /* timer to monitor signalling when accepting */
   uint32_t sdp_a2dp_handle;     /* SDP record handle for audio src */
   uint32_t sdp_a2dp_snk_handle; /* SDP record handle for audio snk */
-  uint32_t sdp_vdp_handle;      /* SDP record handle for video src */
   tBTA_AV_FEAT features;        /* features mask */
   tBTA_SEC sec_mask;            /* security mask */
   tBTA_AV_HNDL handle;          /* the handle for SDP activity */
@@ -551,21 +605,38 @@
   uint8_t
       disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */
   uint8_t state;          /* state machine state */
-  uint8_t conn_rc;        /* handle mask of connected RCP channels */
   uint8_t conn_audio;     /* handle mask of connected audio channels */
-  uint8_t conn_video;     /* handle mask of connected video channels */
   uint8_t conn_lcb;       /* index mask of used LCBs */
   uint8_t audio_open_cnt; /* number of connected audio channels */
   uint8_t reg_audio;      /* handle mask of registered audio channels */
-  uint8_t reg_video;      /* handle mask of registered video channels */
   uint8_t rc_acp_handle;
   uint8_t rc_acp_idx; /* (index + 1) to RCB */
   uint8_t rs_idx;    /* (index + 1) to SCB for the one waiting for RS on open */
   bool sco_occupied; /* true if SCO is being used or call is in progress */
   uint8_t audio_streams; /* handle mask of streaming audio channels */
-  uint8_t video_streams; /* handle mask of streaming video channels */
 } tBTA_AV_CB;
 
+// A2DP offload VSC parameters
+class tBT_A2DP_OFFLOAD {
+ public:
+  uint32_t codec_type;            /* codec types ex: SBC/AAC/LDAC/APTx */
+  uint16_t max_latency;           /* maximum latency */
+  uint16_t scms_t_enable;         /* content protection enable */
+  uint32_t sample_rate;           /* Sample rates ex: 44.1/48/88.2/96 Khz */
+  uint8_t bits_per_sample;        /* bits per sample ex: 16/24/32 */
+  uint8_t ch_mode;                /* None:0 Left:1 Right:2 */
+  uint32_t encoded_audio_bitrate; /* encoder audio bitrates */
+  uint16_t acl_hdl;               /* connection handle */
+  uint16_t l2c_rcid;              /* l2cap channel id */
+  uint16_t mtu;                   /* MTU size */
+  uint8_t codec_info[32];         /* Codec specific information */
+};
+
+/* Vendor OFFLOAD VSC */
+#define HCI_VSQC_CONTROLLER_A2DP_OPCODE 0x000A
+
+#define VS_HCI_A2DP_OFFLOAD_START 0x01
+#define VS_HCI_A2DP_OFFLOAD_STOP 0x02
 /*****************************************************************************
  *  Global data
  ****************************************************************************/
@@ -574,7 +645,7 @@
 extern tBTA_AV_CB bta_av_cb;
 
 /* config struct */
-extern tBTA_AV_CFG* p_bta_av_cfg;
+extern const tBTA_AV_CFG* p_bta_av_cfg;
 extern const tBTA_AV_CFG bta_avk_cfg;
 extern const tBTA_AV_CFG bta_av_cfg;
 extern const tBTA_AV_CFG bta_av_cfg_compatibility;
@@ -585,7 +656,6 @@
 
 extern const tBTA_AV_SACT bta_av_a2dp_action[];
 extern const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos;
-extern tAVDT_CTRL_CBACK* const bta_av_dt_cback[];
 extern void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt,
                                    uint32_t time_stamp, uint8_t m_pt);
 
@@ -596,9 +666,9 @@
 extern tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle);
 extern bool bta_av_chk_start(tBTA_AV_SCB* p_scb);
 extern void bta_av_restore_switch(void);
-extern uint16_t bta_av_chk_mtu(tBTA_AV_SCB* p_scb, uint16_t mtu);
-extern void bta_av_conn_cback(uint8_t handle, const RawAddress* bd_addr,
-                              uint8_t event, tAVDT_CTRL* p_data);
+extern void bta_av_conn_cback(uint8_t handle, const RawAddress& bd_addr,
+                              uint8_t event, tAVDT_CTRL* p_data,
+                              uint8_t scb_index);
 extern uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,
                                 uint8_t lidx);
 extern void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started);
@@ -608,6 +678,8 @@
 extern bool bta_av_is_scb_init(tBTA_AV_SCB* p_scb);
 extern void bta_av_set_scb_sst_incoming(tBTA_AV_SCB* p_scb);
 extern tBTA_AV_LCB* bta_av_find_lcb(const RawAddress& addr, uint8_t op);
+extern const char* bta_av_sst_code(uint8_t state);
+extern void bta_av_free_scb(tBTA_AV_SCB* p_scb);
 
 /* main functions */
 extern void bta_av_api_deregister(tBTA_AV_DATA* p_data);
@@ -620,7 +692,6 @@
 extern const char* bta_av_evt_code(uint16_t evt_code);
 extern bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb);
 extern bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits);
-extern bool bta_av_is_rcfg_sst(tBTA_AV_SCB* p_scb);
 
 /* nsm action functions */
 extern void bta_av_api_disconnect(tBTA_AV_DATA* p_data);
@@ -649,6 +720,10 @@
 extern tBTA_AV_RCB* bta_av_get_rcb_by_shdl(uint8_t shdl);
 extern void bta_av_del_rc(tBTA_AV_RCB* p_rcb);
 
+extern void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr,
+                                   uint8_t event, tAVDT_CTRL* p_data,
+                                   uint8_t scb_index);
+
 /* ssm action functions */
 extern void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
 extern void bta_av_cleanup(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
@@ -701,5 +776,6 @@
 extern void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
 extern void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
 extern void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_vendor_offload_stop(void);
 
 #endif /* BTA_AV_INT_H */
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index 0d7c360..3679469 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -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"
@@ -84,6 +85,10 @@
 #define AVRCP_1_3_STRING "avrcp13"
 #endif
 
+#ifndef AVRCP_DEFAULT_VERSION
+#define AVRCP_DEFAULT_VERSION AVRCP_1_4_STRING
+#endif
+
 /* state machine states */
 enum { BTA_AV_INIT_ST, BTA_AV_OPEN_ST };
 
@@ -165,15 +170,13 @@
 static void bta_av_api_enable(tBTA_AV_DATA* p_data);
 static void bta_av_api_register(tBTA_AV_DATA* p_data);
 static void bta_av_ci_data(tBTA_AV_DATA* p_data);
-#if (AVDT_REPORTING == TRUE)
 static void bta_av_rpc_conn(tBTA_AV_DATA* p_data);
-#endif
 static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data);
 
 static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                                 uint8_t app_id, const RawAddress* peer_addr);
+                                 uint8_t app_id, const RawAddress& peer_addr);
 static void bta_av_sys_rs_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                                uint8_t app_id, const RawAddress* peer_addr);
+                                uint8_t app_id, const RawAddress& peer_addr);
 
 /* action functions */
 const tBTA_AV_NSM_ACT bta_av_nsm_act[] = {
@@ -190,9 +193,7 @@
     bta_av_rc_browse_closed, /* BTA_AV_AVRC_BROWSE_CLOSE_EVT */
     bta_av_conn_chg,         /* BTA_AV_CONN_CHG_EVT */
     bta_av_dereg_comp,       /* BTA_AV_DEREG_COMP_EVT */
-#if (AVDT_REPORTING == TRUE)
     bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
-#endif
     bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
     bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
 };
@@ -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;
       }
@@ -276,6 +277,27 @@
   return p_scb;
 }
 
+int BTA_AvObtainPeerChannelIndex(const RawAddress& peer_address) {
+  // Find the entry for the peer (if exists)
+  tBTA_AV_SCB* p_scb = bta_av_addr_to_scb(peer_address);
+  if (p_scb != nullptr) {
+    return p_scb->hdi;
+  }
+
+  // Find the index for an entry that is not used
+  for (int index = 0; index < BTA_AV_NUM_STRS; index++) {
+    tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[index];
+    if (p_scb == nullptr) {
+      continue;
+    }
+    if (p_scb->PeerAddress().IsEmpty()) {
+      return p_scb->hdi;
+    }
+  }
+
+  return -1;
+}
+
 /*******************************************************************************
  *
  * Function         bta_av_hndl_to_scb
@@ -308,49 +330,79 @@
  *
  ******************************************************************************/
 static tBTA_AV_SCB* bta_av_alloc_scb(tBTA_AV_CHNL chnl) {
-  tBTA_AV_SCB* p_ret = NULL;
-  int xx;
-  tBTA_AV_STATUS sts = BTA_AV_SUCCESS;
-
-  if (chnl == BTA_AV_CHNL_VIDEO) {
-    if (p_bta_av_cfg->p_act_tbl == NULL || p_bta_av_cfg->p_reg == NULL) {
-      APPL_TRACE_ERROR("Video streaming not supported");
-      sts = BTA_AV_FAIL;
-    } else {
-      /* allow only one Video channel */
-      if (bta_av_cb.reg_video) {
-        APPL_TRACE_ERROR("Already registered");
-        sts = BTA_AV_FAIL;
-      }
-    }
-  } else if (chnl != BTA_AV_CHNL_AUDIO) {
-    APPL_TRACE_ERROR("bad channel: %d", chnl);
-    sts = BTA_AV_FAIL;
+  if (chnl != BTA_AV_CHNL_AUDIO) {
+    APPL_TRACE_ERROR("%s: bad channel: %d", __func__, chnl);
+    return nullptr;
   }
 
-  if (sts == BTA_AV_SUCCESS) {
-    for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
-      if (bta_av_cb.p_scb[xx] == NULL) {
-        /* found an empty spot */
-        p_ret = (tBTA_AV_SCB*)osi_calloc(sizeof(tBTA_AV_SCB));
-        p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE;
-        p_ret->chnl = chnl;
-        p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl);
-        p_ret->hdi = xx;
-        p_ret->a2dp_list = list_new(NULL);
-        p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");
-        bta_av_cb.p_scb[xx] = p_ret;
-        break;
-      }
-    }
+  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;
+    p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl);
+    p_ret->hdi = xx;
+    p_ret->a2dp_list = list_new(nullptr);
+    p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");
+    bta_av_cb.p_scb[xx] = p_ret;
+    return p_ret;
   }
-  return p_ret;
+
+  return nullptr;
+}
+
+void bta_av_free_scb(tBTA_AV_SCB* p_scb) {
+  if (p_scb == nullptr) return;
+  uint8_t scb_index = p_scb->hdi;
+  CHECK(scb_index < BTA_AV_NUM_STRS);
+
+  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,
-                       uint8_t event, tAVDT_CTRL* p_data) {
+void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, const RawAddress& bd_addr,
+                       uint8_t event, tAVDT_CTRL* p_data, uint8_t scb_index) {
   uint16_t evt = 0;
   tBTA_AV_SCB* p_scb = NULL;
 
@@ -363,7 +415,7 @@
   {
     evt = BTA_AV_SIG_CHG_EVT;
     if (event == AVDT_DISCONNECT_IND_EVT) {
-      p_scb = bta_av_addr_to_scb(*bd_addr);
+      p_scb = bta_av_addr_to_scb(bd_addr);
     } else if (event == AVDT_CONNECT_IND_EVT) {
       APPL_TRACE_DEBUG("%s: CONN_IND is ACP:%d", __func__,
                        p_data->hdr.err_param);
@@ -374,16 +426,18 @@
     p_msg->hdr.event = evt;
     p_msg->hdr.layer_specific = event;
     p_msg->hdr.offset = p_data->hdr.err_param;
-    p_msg->bd_addr = *bd_addr;
+    p_msg->bd_addr = bd_addr;
+    p_msg->scb_index = scb_index;
     if (p_scb) {
-      APPL_TRACE_DEBUG("scb hndl x%x, role x%x", p_scb->hndl, p_scb->role);
+      APPL_TRACE_DEBUG("%s: scb hndl x%x, role x%x", __func__, p_scb->hndl,
+                       p_scb->role);
     }
-    VLOG(1) << "conn_cback bd_addr:" << bd_addr;
+    LOG_INFO(LOG_TAG, "%s: conn_cback bd_addr: %s", __func__,
+             bd_addr.ToString().c_str());
     bta_sys_sendmsg(p_msg);
   }
 }
 
-#if (AVDT_REPORTING == TRUE)
 /*******************************************************************************
  *
  * Function         bta_av_a2dp_report_cback
@@ -399,7 +453,6 @@
   /* Do not need to handle report data for now.
    * This empty function is here for conformance reasons. */
 }
-#endif
 
 /*******************************************************************************
  *
@@ -415,43 +468,45 @@
 static void bta_av_api_register(tBTA_AV_DATA* p_data) {
   tBTA_AV_REGISTER registr;
   tBTA_AV_SCB* p_scb; /* stream control block */
-  tAVDT_REG reg;
-  tAVDT_CS cs;
+  AvdtpRcb reg;
+  AvdtpStreamConfig avdtp_stream_config;
   char* p_service_name;
   tBTA_UTL_COD cod;
 
-  memset(&cs, 0, sizeof(tAVDT_CS));
+  avdtp_stream_config.Reset();
 
   registr.status = BTA_AV_FAIL_RESOURCES;
   registr.app_id = p_data->api_reg.app_id;
   registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
 
   char avrcp_version[PROPERTY_VALUE_MAX] = {0};
-  osi_property_get(AVRCP_VERSION_PROPERTY, avrcp_version, AVRCP_1_4_STRING);
-  LOG_INFO(LOG_TAG, "AVRCP version used for sdp: \"%s\"", avrcp_version);
+  osi_property_get(AVRCP_VERSION_PROPERTY, avrcp_version,
+                   AVRCP_DEFAULT_VERSION);
+  LOG_INFO(LOG_TAG, "%s: AVRCP version used for sdp: \"%s\"", __func__,
+           avrcp_version);
 
   uint16_t profile_initialized = p_data->api_reg.service_uuid;
   if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
-    p_bta_av_cfg = (tBTA_AV_CFG*)&bta_avk_cfg;
+    p_bta_av_cfg = &bta_avk_cfg;
   } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
-    p_bta_av_cfg = (tBTA_AV_CFG*)&bta_av_cfg;
+    p_bta_av_cfg = &bta_av_cfg;
 
     if (!strncmp(AVRCP_1_3_STRING, avrcp_version, sizeof(AVRCP_1_3_STRING))) {
-      LOG_INFO(LOG_TAG, "AVRCP 1.3 capabilites used");
-      p_bta_av_cfg = (tBTA_AV_CFG*)&bta_av_cfg_compatibility;
+      LOG_INFO(LOG_TAG, "%s: AVRCP 1.3 capabilites used", __func__);
+      p_bta_av_cfg = &bta_av_cfg_compatibility;
     }
   }
 
   APPL_TRACE_DEBUG("%s: profile: 0x%x", __func__, profile_initialized);
   if (p_bta_av_cfg == NULL) {
-    APPL_TRACE_ERROR("AV configuration is null!");
+    APPL_TRACE_ERROR("%s: AV configuration is null!", __func__);
     return;
   }
 
   do {
     p_scb = bta_av_alloc_scb(registr.chnl);
     if (p_scb == NULL) {
-      APPL_TRACE_ERROR("failed to alloc SCB");
+      APPL_TRACE_ERROR("%s: failed to alloc SCB", __func__);
       break;
     }
 
@@ -461,13 +516,14 @@
     /* initialize the stream control block */
     registr.status = BTA_AV_SUCCESS;
 
-    if ((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0) {
+    if (bta_av_cb.reg_audio == 0) {
       /* the first channel registered. register to AVDTP */
       reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
       reg.ret_tout = BTA_AV_RET_TOUT;
       reg.sig_tout = BTA_AV_SIG_TOUT;
       reg.idle_tout = BTA_AV_IDLE_TOUT;
       reg.sec_mask = bta_av_cb.sec_mask;
+      reg.scb_index = p_scb->hdi;
 #if (BTA_AR_INCLUDED == TRUE)
       bta_ar_reg_avdt(&reg, bta_av_conn_cback, BTA_ID_AV);
 #endif
@@ -486,26 +542,21 @@
                         BTA_ID_AV);
 #endif
 
-        /* For the Audio Sink role we support additional TG 1.3 to support
+        /* For the Audio Sink role we support additional TG to support
          * absolute volume.
          */
         uint16_t profile_version = AVRC_REV_1_0;
 
-        if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
-          if (!strncmp(AVRCP_1_6_STRING, avrcp_version,
-                       sizeof(AVRCP_1_6_STRING))) {
-            profile_version = AVRC_REV_1_6;
-          } else if (!strncmp(AVRCP_1_5_STRING, avrcp_version,
-                              sizeof(AVRCP_1_5_STRING))) {
-            profile_version = AVRC_REV_1_5;
-          } else if (!strncmp(AVRCP_1_3_STRING, avrcp_version,
-                              sizeof(AVRCP_1_3_STRING))) {
-            profile_version = AVRC_REV_1_3;
-          } else {
-            profile_version = AVRC_REV_1_4;
-          }
-        } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
-          // Initialize AVRCP1.4 to provide Absolute Volume control.
+        if (!strncmp(AVRCP_1_6_STRING, avrcp_version,
+                     sizeof(AVRCP_1_6_STRING))) {
+          profile_version = AVRC_REV_1_6;
+        } else if (!strncmp(AVRCP_1_5_STRING, avrcp_version,
+                            sizeof(AVRCP_1_5_STRING))) {
+          profile_version = AVRC_REV_1_5;
+        } else if (!strncmp(AVRCP_1_3_STRING, avrcp_version,
+                            sizeof(AVRCP_1_3_STRING))) {
+          profile_version = AVRC_REV_1_3;
+        } else {
           profile_version = AVRC_REV_1_4;
         }
 
@@ -525,11 +576,13 @@
     } /* if 1st channel */
 
     /* get stream configuration and create stream */
-    cs.cfg.num_codec = 1;
-    cs.nsc_mask =
-        AVDT_NSC_RECONFIG |
-        ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
-    APPL_TRACE_DEBUG("nsc_mask: 0x%x", cs.nsc_mask);
+    avdtp_stream_config.cfg.num_codec = 1;
+    avdtp_stream_config.nsc_mask = AvdtpStreamConfig::AVDT_NSC_RECONFIG;
+    if (!(bta_av_cb.features & BTA_AV_FEAT_PROTECT)) {
+      avdtp_stream_config.nsc_mask |= AvdtpStreamConfig::AVDT_NSC_SECURITY;
+    }
+    APPL_TRACE_DEBUG("%s: nsc_mask: 0x%x", __func__,
+                     avdtp_stream_config.nsc_mask);
 
     if (p_data->api_reg.p_service_name[0] == 0) {
       p_service_name = NULL;
@@ -539,144 +592,132 @@
 
     p_scb->suspend_sup = true;
     p_scb->recfg_sup = true;
-    p_scb->skip_sdp = false;
 
-    cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi];
-    if (registr.chnl == BTA_AV_CHNL_AUDIO) {
-      /* set up the audio stream control block */
-      p_scb->p_act_tbl = (const tBTA_AV_ACT*)bta_av_a2dp_action;
-      p_scb->p_cos = &bta_av_a2dp_cos;
-      p_scb->media_type = AVDT_MEDIA_TYPE_AUDIO;
-      cs.cfg.psc_mask = AVDT_PSC_TRANS;
-      cs.media_type = AVDT_MEDIA_TYPE_AUDIO;
-      cs.mtu = p_bta_av_cfg->audio_mtu;
-      cs.flush_to = L2CAP_DEFAULT_FLUSH_TO;
-      btav_a2dp_codec_index_t codec_index_min =
-          BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;
-      btav_a2dp_codec_index_t codec_index_max =
-          BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;
+    avdtp_stream_config.scb_index = p_scb->hdi;
+    avdtp_stream_config.p_avdt_ctrl_cback = &bta_av_proc_stream_evt;
 
-#if (AVDT_REPORTING == TRUE)
-      if (bta_av_cb.features & BTA_AV_FEAT_REPORT) {
-        cs.cfg.psc_mask |= AVDT_PSC_REPORT;
-        cs.p_report_cback = bta_av_a2dp_report_cback;
+    /* set up the audio stream control block */
+    p_scb->p_act_tbl = (const tBTA_AV_ACT*)bta_av_a2dp_action;
+    p_scb->p_cos = &bta_av_a2dp_cos;
+    p_scb->media_type = AVDT_MEDIA_TYPE_AUDIO;
+    avdtp_stream_config.cfg.psc_mask = AVDT_PSC_TRANS;
+    avdtp_stream_config.media_type = AVDT_MEDIA_TYPE_AUDIO;
+    avdtp_stream_config.mtu = p_bta_av_cfg->audio_mtu;
+    avdtp_stream_config.flush_to = L2CAP_DEFAULT_FLUSH_TO;
+    btav_a2dp_codec_index_t codec_index_min = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;
+    btav_a2dp_codec_index_t codec_index_max = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;
+
+    if (bta_av_cb.features & BTA_AV_FEAT_REPORT) {
+      avdtp_stream_config.cfg.psc_mask |= AVDT_PSC_REPORT;
+      avdtp_stream_config.p_report_cback = bta_av_a2dp_report_cback;
+    }
+    if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
+      avdtp_stream_config.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
+
+    if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+      avdtp_stream_config.tsep = AVDT_TSEP_SRC;
+      codec_index_min = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;
+      codec_index_max = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;
+    } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+      avdtp_stream_config.tsep = AVDT_TSEP_SNK;
+      avdtp_stream_config.p_sink_data_cback = bta_av_sink_data_cback;
+      codec_index_min = BTAV_A2DP_CODEC_INDEX_SINK_MIN;
+      codec_index_max = BTAV_A2DP_CODEC_INDEX_SINK_MAX;
+    }
+
+    /* Initialize handles to zero */
+    for (int xx = 0; xx < BTAV_A2DP_CODEC_INDEX_MAX; xx++) {
+      p_scb->seps[xx].av_handle = 0;
+    }
+
+    /* keep the configuration in the stream control block */
+    p_scb->cfg = avdtp_stream_config.cfg;
+    for (int i = codec_index_min; i < codec_index_max; i++) {
+      btav_a2dp_codec_index_t codec_index =
+          static_cast<btav_a2dp_codec_index_t>(i);
+      if (!(*bta_av_a2dp_cos.init)(codec_index, &avdtp_stream_config.cfg)) {
+        continue;
       }
-#endif
-      if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
-        cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
-
-      if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
-        cs.tsep = AVDT_TSEP_SRC;
-        codec_index_min = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;
-        codec_index_max = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;
-      } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
-        cs.tsep = AVDT_TSEP_SNK;
-        cs.p_sink_data_cback = bta_av_sink_data_cback;
-        codec_index_min = BTAV_A2DP_CODEC_INDEX_SINK_MIN;
-        codec_index_max = BTAV_A2DP_CODEC_INDEX_SINK_MAX;
+      if (AVDT_CreateStream(p_scb->app_id, &p_scb->seps[codec_index].av_handle,
+                            avdtp_stream_config) != AVDT_SUCCESS) {
+        continue;
       }
-
-      /* Initialize handles to zero */
-      for (int xx = 0; xx < BTAV_A2DP_CODEC_INDEX_MAX; xx++) {
-        p_scb->seps[xx].av_handle = 0;
-      }
-
-      /* keep the configuration in the stream control block */
-      memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
-      for (int i = codec_index_min; i < codec_index_max; i++) {
-        btav_a2dp_codec_index_t codec_index =
-            static_cast<btav_a2dp_codec_index_t>(i);
-        if (!(*bta_av_a2dp_cos.init)(codec_index, &cs.cfg)) {
-          continue;
-        }
-        if (AVDT_CreateStream(&p_scb->seps[codec_index].av_handle, &cs) !=
-            AVDT_SUCCESS) {
-          continue;
-        }
-        /* Save a copy of the codec */
-        memcpy(p_scb->seps[codec_index].codec_info, cs.cfg.codec_info,
-               AVDT_CODEC_SIZE);
-        p_scb->seps[codec_index].tsep = cs.tsep;
-        if (cs.tsep == AVDT_TSEP_SNK) {
-          p_scb->seps[codec_index].p_app_sink_data_cback =
-              p_data->api_reg.p_app_sink_data_cback;
-        } else {
-          /* In case of A2DP SOURCE we don't need a callback to
-           * handle media packets.
-           */
-          p_scb->seps[codec_index].p_app_sink_data_cback = NULL;
-        }
-      }
-
-      if (!bta_av_cb.reg_audio) {
-        bta_av_cb.sdp_a2dp_handle = 0;
-        bta_av_cb.sdp_a2dp_snk_handle = 0;
-        if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
-          /* create the SDP records on the 1st audio channel */
-          bta_av_cb.sdp_a2dp_handle = SDP_CreateRecord();
-          A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
-                         A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_handle);
-          bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
-        } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
-#if (BTA_AV_SINK_INCLUDED == TRUE)
-          bta_av_cb.sdp_a2dp_snk_handle = SDP_CreateRecord();
-          A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
-                         A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_snk_handle);
-          bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
-#endif
-        }
-        /* start listening when A2DP is registered */
-        if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
-          bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
-
-        /* if the AV and AVK are both supported, it cannot support the CT role
+      /* Save a copy of the codec */
+      memcpy(p_scb->seps[codec_index].codec_info,
+             avdtp_stream_config.cfg.codec_info, AVDT_CODEC_SIZE);
+      p_scb->seps[codec_index].tsep = avdtp_stream_config.tsep;
+      if (avdtp_stream_config.tsep == AVDT_TSEP_SNK) {
+        p_scb->seps[codec_index].p_app_sink_data_cback =
+            p_data->api_reg.p_app_sink_data_cback;
+      } else {
+        /* In case of A2DP SOURCE we don't need a callback to
+         * handle media packets.
          */
-        if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) {
-          /* if TG is not supported, we need to register to AVCT now */
-          if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) {
+        p_scb->seps[codec_index].p_app_sink_data_cback = NULL;
+      }
+    }
+
+    if (!bta_av_cb.reg_audio) {
+      bta_av_cb.sdp_a2dp_handle = 0;
+      bta_av_cb.sdp_a2dp_snk_handle = 0;
+      if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+        /* create the SDP records on the 1st audio channel */
+        bta_av_cb.sdp_a2dp_handle = SDP_CreateRecord();
+        A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
+                       A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_handle);
+        bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+      } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+        bta_av_cb.sdp_a2dp_snk_handle = SDP_CreateRecord();
+        A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
+                       A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_snk_handle);
+        bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
+#endif
+      }
+      /* start listening when A2DP is registered */
+      if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+        bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+
+      /* if the AV and AVK are both supported, it cannot support the CT role
+       */
+      if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) {
+        /* if TG is not supported, we need to register to AVCT now */
+        if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) {
 #if (BTA_AR_INCLUDED == TRUE)
 #if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
-            bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
-                            bta_av_cb.sec_mask, BTA_ID_AV);
+          bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+                          bta_av_cb.sec_mask, BTA_ID_AV);
 #else
-            bta_ar_reg_avct(
-                p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
-                (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)),
-                BTA_ID_AV);
+          bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+                          (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)),
+                          BTA_ID_AV);
 #endif
 #endif
-            bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
-          }
-#if (BTA_AR_INCLUDED == TRUE)
-          /* create an SDP record as AVRC CT. We create 1.3 for SOURCE
-           * because we rely on feature bits being scanned by external
-           * devices more than the profile version itself.
-           *
-           * We create 1.4 for SINK since we support browsing.
-           */
-          if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
-            bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
-                            p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
-                            (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
-                            AVRC_REV_1_3);
-          } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
-            bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
-                            p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
-                            (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
-                            AVRC_REV_1_6);
-          }
-#endif
+          bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
         }
+#if (BTA_AR_INCLUDED == TRUE)
+        /* create an SDP record as AVRC CT. We create 1.3 for SOURCE
+         * because we rely on feature bits being scanned by external
+         * devices more than the profile version itself.
+         *
+         * We create 1.4 for SINK since we support browsing.
+         */
+        if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+          bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+                          p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+                          (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
+                          AVRC_REV_1_3);
+        } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+          bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+                          p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+                          (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
+                          AVRC_REV_1_6);
+        }
+#endif
       }
-      bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
-      APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
-    } else {
-      bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
-      bta_av_cb.sdp_vdp_handle = SDP_CreateRecord();
-      /* register the video channel */
-      /* no need to verify the function pointer here. it's verified prior */
-      (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb);
     }
+    bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+    APPL_TRACE_DEBUG("%s: reg_audio: 0x%x", __func__, bta_av_cb.reg_audio);
   } while (0);
 
   /* call callback with register event */
@@ -699,7 +740,7 @@
   tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
 
   if (p_scb) {
-    p_scb->deregistring = true;
+    p_scb->deregistering = true;
     bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data);
   } else {
     bta_av_dereg_comp(p_data);
@@ -740,9 +781,7 @@
  * Returns          void
  *
  ******************************************************************************/
-#if (AVDT_REPORTING == TRUE)
 static void bta_av_rpc_conn(UNUSED_ATTR tBTA_AV_DATA* p_data) {}
-#endif
 
 /*******************************************************************************
  *
@@ -755,12 +794,13 @@
  *
  ******************************************************************************/
 static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data) {
-  int xx;
   uint16_t event =
       p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT;
+  tBTA_AV_HNDL handle = p_data->hdr.layer_specific;
+  tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(handle);
 
-  for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
-    bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+  if (p_scb != nullptr) {
+    bta_av_ssm_execute(p_scb, event, p_data);
   }
 }
 
@@ -770,41 +810,42 @@
  *
  * Description      if this is audio channel, check if more than one audio
  *                  channel is connected & already started.
+ *                  This function needs to be kept very similar to
+ *                  bta_av_chk_2nd_start
  *
  * Returns          true, if need api_start
  *
  ******************************************************************************/
 bool bta_av_chk_start(tBTA_AV_SCB* p_scb) {
   bool start = false;
-  tBTA_AV_SCB* p_scbi;
-  int i;
 
-  if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
-    if ((bta_av_cb.audio_open_cnt >= 2) &&
-        ((0 ==
-          (p_scb->role & BTA_AV_ROLE_AD_ACP)) || /* Outgoing connection or   */
-         (bta_av_cb.features &
-          BTA_AV_FEAT_ACP_START))) /* auto-starting option     */
-    {
-      /* more than one audio channel is connected */
-      /* if this is the 2nd stream as ACP, give INT a chance to issue the START
-       * command */
-      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
-        p_scbi = bta_av_cb.p_scb[i];
-        if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
-          start = true;
-          /* may need to update the flush timeout of this already started stream
-           */
-          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_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
-          }
+  if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2) &&
+      (((p_scb->role & BTA_AV_ROLE_AD_ACP) == 0) ||  // Outgoing connection or
+       (bta_av_cb.features & BTA_AV_FEAT_ACP_START))) {  // Auto-starting option
+    // More than one audio channel is connected.
+    // If this is the 2nd stream as ACP, give INT a chance to issue the START
+    // command.
+    for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
+      tBTA_AV_SCB* p_scbi = bta_av_cb.p_scb[i];
+      if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+        start = true;
+        // May need to update the flush timeout of this already started stream
+        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->PeerAddress(),
+              p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
         }
       }
     }
   }
+
+  LOG_INFO(LOG_TAG,
+           "%s: peer %s channel:%d bta_av_cb.audio_open_cnt:%d role:0x%x "
+           "features:0x%x start:%s",
+           __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->chnl,
+           bta_av_cb.audio_open_cnt, p_scb->role, bta_av_cb.features,
+           logbool(start).c_str());
   return start;
 }
 
@@ -822,14 +863,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("reg_audio: 0x%x", bta_av_cb.reg_audio);
+  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;
     }
@@ -847,28 +889,32 @@
  ******************************************************************************/
 static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
                                 uint8_t id, uint8_t app_id,
-                                const RawAddress* peer_addr) {
+                                const RawAddress& peer_addr) {
   int i;
   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("bta_av_sys_rs_cback: %d", bta_av_cb.rs_idx);
+  APPL_TRACE_DEBUG(
+      "%s: peer %s new_role:%d hci_status:0x%x bta_av_cb.rs_idx:%d", __func__,
+      peer_addr.ToString().c_str(), id, app_id, bta_av_cb.rs_idx);
+
   for (i = 0; i < BTA_AV_NUM_STRS; i++) {
     /* loop through all the SCBs to find matching peer addresses and report the
      * 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("new_role:%d, hci_status:x%x hndl: x%x", id, app_id,
-                       p_scb->hndl);
+      APPL_TRACE_DEBUG(
+          "%s: peer %s found: new_role:%d, hci_status:0x%x hndl:0x%x", __func__,
+          peer_addr.ToString().c_str(), id, app_id, p_scb->hndl);
       /*
       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;
@@ -883,9 +929,9 @@
 
   /* restore role switch policy, if role switch failed */
   if ((HCI_SUCCESS != app_id) &&
-      (BTM_GetRole(*peer_addr, &cur_role) == BTM_SUCCESS) &&
+      (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
@@ -896,13 +942,20 @@
       p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1];
     }
     if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
-      APPL_TRACE_DEBUG("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
+      APPL_TRACE_DEBUG("%s: peer %s rs_idx:%d, hndl:0x%x q_tag:%d", __func__,
+                       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)
+      if (HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id) {
         p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
-      else
+      } else {
+        APPL_TRACE_ERROR(
+            "%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->PeerAddress().ToString().c_str(), id, app_id);
         p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
+      }
 
       /* Continue av open process */
       bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)&(p_scb->q_info.open));
@@ -925,12 +978,12 @@
  ******************************************************************************/
 static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
                                  UNUSED_ATTR uint8_t app_id,
-                                 UNUSED_ATTR const RawAddress* peer_addr) {
+                                 UNUSED_ATTR const RawAddress& peer_addr) {
   tBTA_AV_SCB* p_scb;
   int i;
   tBTA_AV_API_STOP stop;
 
-  APPL_TRACE_DEBUG("bta_av_sco_chg_cback:%d status:%d", id, status);
+  APPL_TRACE_DEBUG("%s: id:%d status:%d", __func__, id, status);
   if (id) {
     bta_av_cb.sco_occupied = true;
 
@@ -938,8 +991,8 @@
     for (i = 0; i < BTA_AV_NUM_STRS; i++) {
       p_scb = bta_av_cb.p_scb[i];
 
-      if (p_scb && p_scb->co_started && (p_scb->sco_suspend == false)) {
-        APPL_TRACE_DEBUG("suspending scb:%d", i);
+      if (p_scb && p_scb->co_started && (!p_scb->sco_suspend)) {
+        APPL_TRACE_DEBUG("%s: suspending scb:%d", __func__, i);
         /* scb is used and started, not suspended automatically */
         p_scb->sco_suspend = true;
         stop.flush = false;
@@ -956,7 +1009,7 @@
 
       if (p_scb && p_scb->sco_suspend) /* scb is used and suspended for SCO */
       {
-        APPL_TRACE_DEBUG("starting scb:%d", i);
+        APPL_TRACE_DEBUG("%s: starting scb:%d", __func__, i);
         bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
       }
     }
@@ -975,6 +1028,10 @@
  *
  ******************************************************************************/
 bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb) {
+  // TODO: A workaround for devices that are connected first, become
+  // Master, and block follow-up role changes - b/72122792 .
+  return false;
+#if 0
   uint8_t role;
   bool needed = false;
   tBTA_AV_SCB* p_scbi;
@@ -984,19 +1041,18 @@
   for (i = 0; i < BTA_AV_NUM_STRS; i++) {
     mask = BTA_AV_HNDL_TO_MSK(i);
     p_scbi = bta_av_cb.p_scb[i];
-    if (p_scbi && (p_scb->hdi != i) &&    /* not the original channel */
-        ((bta_av_cb.conn_audio & mask) || /* connected audio */
-         (bta_av_cb.conn_video & mask)))  /* connected video */
+    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 */
@@ -1011,6 +1067,7 @@
     }
   }
   return needed;
+#endif
 }
 
 /*******************************************************************************
@@ -1027,20 +1084,26 @@
   uint8_t role;
   bool is_ok = true;
 
-  if (BTM_GetRole(p_scb->peer_addr, &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,
-             bta_av_cb.features);
+  if (BTM_GetRole(p_scb->PeerAddress(), &role) == BTM_SUCCESS) {
+    LOG_INFO(
+        LOG_TAG,
+        "%s: peer %s hndl:0x%x role:%d conn_audio:0x%x bits:%d features:0x%x",
+        __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, role,
+        bta_av_cb.conn_audio, bits, bta_av_cb.features);
     if (BTM_ROLE_MASTER != role &&
         (A2DP_BitsSet(bta_av_cb.conn_audio) > bits ||
          (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)) {
+      tBTM_STATUS status =
+          BTM_SwitchRole(p_scb->PeerAddress(), BTM_ROLE_MASTER, NULL);
+      if (status != BTM_CMD_STARTED) {
         /* can not switch role on SCB - start the timer on SCB */
+        LOG_ERROR(LOG_TAG,
+                  "%s: peer %s BTM_SwitchRole(BTM_ROLE_MASTER) error: %d",
+                  __func__, p_scb->PeerAddress().ToString().c_str(), status);
       }
       is_ok = false;
       p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
@@ -1052,46 +1115,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_av_chk_mtu
- *
- * Description      if this is audio channel, check if more than one audio
- *                  channel is connected.
- *
- * Returns          The smallest mtu of the connected audio channels
- *
- ******************************************************************************/
-uint16_t bta_av_chk_mtu(tBTA_AV_SCB* p_scb, UNUSED_ATTR uint16_t mtu) {
-  uint16_t ret_mtu = BTA_AV_MAX_A2DP_MTU;
-  tBTA_AV_SCB* p_scbi;
-  int i;
-  uint8_t mask;
-
-  /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets
-   */
-  if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
-    if (bta_av_cb.audio_open_cnt >= 2) {
-      /* more than one audio channel is connected */
-      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
-        p_scbi = bta_av_cb.p_scb[i];
-        if ((p_scb != p_scbi) && p_scbi &&
-            (p_scbi->chnl == BTA_AV_CHNL_AUDIO)) {
-          mask = BTA_AV_HNDL_TO_MSK(i);
-          APPL_TRACE_DEBUG("[%d] mtu: %d, mask:0x%x", i, p_scbi->stream_mtu,
-                           mask);
-          if (bta_av_cb.conn_audio & mask) {
-            if (ret_mtu > p_scbi->stream_mtu) ret_mtu = p_scbi->stream_mtu;
-          }
-        }
-      }
-    }
-    APPL_TRACE_DEBUG("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d",
-                     bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu);
-  }
-  return ret_mtu;
-}
-
-/*******************************************************************************
- *
  * Function         bta_av_dup_audio_buf
  *
  * Description      dup the audio data to the q_info.a2dp of other audio
@@ -1121,7 +1144,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);
+      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);
@@ -1154,12 +1177,13 @@
 
   /* set next state */
   p_cb->state = state_table[event][BTA_AV_NEXT_STATE];
-  APPL_TRACE_EVENT("next state=%d event offset:%d", p_cb->state, event);
+  APPL_TRACE_EVENT("%s: next state=%d event offset:%d", __func__, p_cb->state,
+                   event);
 
   /* execute action functions */
   action = state_table[event][BTA_AV_ACTION_COL];
   if (action != BTA_AV_IGNORE) {
-    APPL_TRACE_EVENT("%s action executed %d", __func__, action);
+    APPL_TRACE_EVENT("%s: action executed %d", __func__, action);
     (*bta_av_action[action])(p_cb, p_data);
   }
 }
@@ -1191,7 +1215,7 @@
     /* state machine events */
     bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA*)p_msg);
   } else {
-    APPL_TRACE_VERBOSE("handle=0x%x", p_msg->layer_specific);
+    APPL_TRACE_VERBOSE("%s: handle=0x%x", __func__, p_msg->layer_specific);
     /* stream state machine events */
     bta_av_ssm_execute(bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event,
                        (tBTA_AV_DATA*)p_msg);
@@ -1346,10 +1370,8 @@
       return "CONN_CHG";
     case BTA_AV_DEREG_COMP_EVT:
       return "DEREG_COMP";
-#if (AVDT_REPORTING == TRUE)
     case BTA_AV_AVDT_RPT_CONN_EVT:
       return "RPT_CONN";
-#endif
     case BTA_AV_API_START_EVT:
       return "API_START";
     case BTA_AV_API_STOP_EVT:
@@ -1358,3 +1380,109 @@
       return "unknown";
   }
 }
+
+void bta_debug_av_dump(int fd) {
+  dprintf(fd, "\nBTA AV State:\n");
+  dprintf(fd, "  State Machine State: %s\n", bta_av_st_code(bta_av_cb.state));
+  dprintf(fd, "  Link signalling timer: %s\n",
+          alarm_is_scheduled(bta_av_cb.link_signalling_timer)
+              ? "Scheduled"
+              : "Not scheduled");
+  dprintf(fd, "  Accept signalling timer: %s\n",
+          alarm_is_scheduled(bta_av_cb.accept_signalling_timer)
+              ? "Scheduled"
+              : "Not scheduled");
+  dprintf(fd, "  SDP A2DP source handle: %d\n", bta_av_cb.sdp_a2dp_handle);
+  dprintf(fd, "  SDP A2DP sink handle: %d\n", bta_av_cb.sdp_a2dp_snk_handle);
+  dprintf(fd, "  Features: 0x%x\n", bta_av_cb.features);
+  dprintf(fd, "  Security mask: 0x%x\n", bta_av_cb.sec_mask);
+  dprintf(fd, "  SDP handle: %d\n", bta_av_cb.handle);
+  dprintf(fd, "  Disabling: %s\n", bta_av_cb.disabling ? "true" : "false");
+  dprintf(fd, "  SCO occupied: %s\n",
+          bta_av_cb.sco_occupied ? "true" : "false");
+  dprintf(fd, "  Connected audio channels: %d\n", bta_av_cb.audio_open_cnt);
+  dprintf(fd, "  Connected audio channels mask: 0x%x\n", bta_av_cb.conn_audio);
+  dprintf(fd, "  Streaming audio channels mask: 0x%x\n",
+          bta_av_cb.audio_streams);
+  dprintf(fd, "  Registered audio channels mask: 0x%x\n", bta_av_cb.reg_audio);
+  dprintf(fd, "  Connected LCBs mask: 0x%x\n", bta_av_cb.conn_lcb);
+
+  for (size_t i = 0; i < sizeof(bta_av_cb.lcb) / sizeof(bta_av_cb.lcb[0]);
+       i++) {
+    const tBTA_AV_LCB& lcb = bta_av_cb.lcb[i];
+    dprintf(fd, "\n  Link control block: %zu peer: %s\n", i,
+            lcb.addr.ToString().c_str());
+    dprintf(fd, "    Connected stream handle mask: 0x%x\n", lcb.conn_msk);
+    dprintf(fd, "    Index(+1) to LCB: %d\n", lcb.lidx);
+  }
+  for (size_t i = 0; i < BTA_AV_NUM_STRS; i++) {
+    const tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[i];
+    if (p_scb == nullptr) {
+      continue;
+    }
+    dprintf(fd, "\n  BTA ID: %zu peer: %s\n", i,
+            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++) {
+      const tBTA_AV_SEP& sep = p_scb->seps[j];
+      dprintf(fd, "    SEP ID: %zu\n", j);
+      dprintf(fd, "      SEP AVDTP handle: %d\n", sep.av_handle);
+      dprintf(fd, "      Local SEP type: %d\n", sep.tsep);
+      dprintf(fd, "      Codec: %s\n", A2DP_CodecName(sep.codec_info));
+    }
+    dprintf(fd, "    BTA info tag: %d\n", p_scb->q_tag);
+    dprintf(fd, "    API Open peer: %s\n",
+            p_scb->q_info.open.bd_addr.ToString().c_str());
+    dprintf(fd, "      Use AVRCP: %s\n",
+            p_scb->q_info.open.use_rc ? "true" : "false");
+    dprintf(fd, "      Security mask: 0x%x\n", p_scb->q_info.open.sec_mask);
+    dprintf(fd, "      Switch result: %d\n", p_scb->q_info.open.switch_res);
+    dprintf(fd, "      Initiator UUID: 0x%x\n", p_scb->q_info.open.uuid);
+    dprintf(fd, "    Saved API Open peer: %s\n",
+            p_scb->open_api.bd_addr.ToString().c_str());
+    dprintf(fd, "      Use AVRCP: %s\n",
+            p_scb->open_api.use_rc ? "true" : "false");
+    dprintf(fd, "      Security mask: 0x%x\n", p_scb->open_api.sec_mask);
+    dprintf(fd, "      Switch result: %d\n", p_scb->open_api.switch_res);
+    dprintf(fd, "      Initiator UUID: 0x%x\n", p_scb->open_api.uuid);
+    // 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->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");
+    dprintf(fd, "    Open status: %d\n", p_scb->open_status);
+    dprintf(fd, "    Channel: %d\n", p_scb->chnl);
+    dprintf(fd, "    BTA handle: 0x%x\n", p_scb->hndl);
+    dprintf(fd, "    Protocol service capabilities mask: 0x%x\n",
+            p_scb->cur_psc_mask);
+    dprintf(fd, "    AVDTP handle: %d\n", p_scb->avdt_handle);
+    dprintf(fd, "    Stream control block index: %d\n", p_scb->hdi);
+    dprintf(fd, "    State machine state: %s(%d)\n",
+            bta_av_sst_code(p_scb->state), p_scb->state);
+    dprintf(fd, "    AVDTP label: 0x%x\n", p_scb->avdt_label);
+    dprintf(fd, "    Application ID: %d\n", p_scb->app_id);
+    dprintf(fd, "    Role: 0x%x\n", p_scb->role);
+    dprintf(fd, "    Queued L2CAP buffers: %d\n", p_scb->l2c_bufs);
+    dprintf(fd, "    AVRCP allowed: %s\n", p_scb->use_rc ? "true" : "false");
+    dprintf(fd, "    Stream started: %s\n", p_scb->started ? "true" : "false");
+    dprintf(fd, "    Stream call-out started: %d\n", p_scb->co_started);
+    dprintf(fd, "    AVDTP Reconfig supported: %s\n",
+            p_scb->recfg_sup ? "true" : "false");
+    dprintf(fd, "    AVDTP Suspend supported: %s\n",
+            p_scb->suspend_sup ? "true" : "false");
+    dprintf(fd, "    Deregistering: %s\n",
+            p_scb->deregistering ? "true" : "false");
+    dprintf(fd, "    SCO automatic Suspend: %s\n",
+            p_scb->sco_suspend ? "true" : "false");
+    dprintf(fd, "    Incoming/outgoing connection collusion mask: 0x%x\n",
+            p_scb->coll_mask);
+    dprintf(fd, "    Wait mask: 0x%x\n", p_scb->wait);
+    dprintf(fd, "    Don't use RTP header: %s\n",
+            p_scb->no_rtp_header ? "true" : "false");
+    dprintf(fd, "    Intended UUID of Initiator to connect to: 0x%x\n",
+            p_scb->uuid_int);
+  }
+}
diff --git a/bta/av/bta_av_ssm.cc b/bta/av/bta_av_ssm.cc
index 3036e712..6c384e0 100644
--- a/bta/av/bta_av_ssm.cc
+++ b/bta/av/bta_av_ssm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -107,8 +107,8 @@
 /* state table for init state */
 static const uint8_t bta_av_sst_init[][BTA_AV_NUM_COLS] = {
     /* Event                     Action 1               Action 2 Next state */
-    /* AP_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* AP_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* API_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
@@ -117,8 +117,8 @@
     /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
-    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                 BTA_AV_INIT_SST},
+    /* CI_SETCONFIG_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
@@ -130,179 +130,180 @@
     /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
-    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
-                              BTA_AV_INIT_SST},
-    /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_INIT_SST},
-    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_INIT_SST},
+    /* STR_CONFIG_IND_EVT */
+    {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_SECURITY_IND_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_SECURITY_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
-    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_INIT_SST},
+    /* STR_RECONFIG_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
-    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
-                                 BTA_AV_INIT_SST},
-    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
-                                     BTA_AV_INIT_SST}};
+    /* API_OFFLOAD_START_EVT */
+    {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* API_OFFLOAD_START_RSP_EVT */
+    {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_INIT_SST}};
 
 /* state table for incoming state */
 static const uint8_t bta_av_sst_incoming[][BTA_AV_NUM_COLS] = {
     /* Event                     Action 1               Action 2 Next state */
-    /* AP_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
-    /* AP_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ,
-                        BTA_AV_CLOSING_SST},
+    /* API_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE,
+                        BTA_AV_INCOMING_SST},
+    /* API_CLOSE_EVT */
+    {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ, BTA_AV_CLOSING_SST},
     /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
     /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
-    /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                            BTA_AV_INCOMING_SST},
-    /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
-                               BTA_AV_INCOMING_SST},
-    /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
-                               BTA_AV_INCOMING_SST},
-    /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                            BTA_AV_INCOMING_SST},
-    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_INCOMING_SST},
-    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER,
-                               BTA_AV_INCOMING_SST},
-    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_CLEANUP,
-                                 BTA_AV_INIT_SST},
-    /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE,
-                           BTA_AV_INCOMING_SST},
-    /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE,
-                             BTA_AV_INCOMING_SST},
-    /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP, BTA_AV_SIGNORE,
-                           BTA_AV_INCOMING_SST},
-    /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_INCOMING_SST},
-    /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE,
-                             BTA_AV_INCOMING_SST},
-    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_INCOMING_SST},
+    /* API_RECONFIG_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_PROTECT_REQ_EVT */
+    {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_PROTECT_RSP_EVT */
+    {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_RC_OPEN_EVT  */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* SRC_DATA_READY_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* CI_SETCONFIG_OK_EVT */
+    {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER, BTA_AV_INCOMING_SST},
+    /* CI_SETCONFIG_FAIL_EVT */
+    {BTA_AV_SETCONFIG_REJ, BTA_AV_CLEANUP, BTA_AV_INIT_SST},
+    /* SDP_DISC_OK_EVT */
+    {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* SDP_DISC_FAIL_EVT */
+    {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_DISC_OK_EVT */
+    {BTA_AV_DISC_RES_AS_ACP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_DISC_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_GETCAP_OK_EVT */
+    {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_GETCAP_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
     /* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_INCOMING_SST},
-    /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                            BTA_AV_INCOMING_SST},
-    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_INCOMING_SST},
+    /* STR_OPEN_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_START_OK_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_START_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
     /* STR_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST},
-    /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE,
-                              BTA_AV_INCOMING_SST},
-    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
-                                BTA_AV_INCOMING_SST},
-    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
-                                BTA_AV_INCOMING_SST},
-    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_INCOMING_SST},
-    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_INCOMING_SST},
-    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_INCOMING_SST},
+    /* STR_CONFIG_IND_EVT */
+    {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_SECURITY_IND_EVT */
+    {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_SECURITY_CFM_EVT */
+    {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_WRITE_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_SUSPEND_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_RECONFIG_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
     /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
-    /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                            BTA_AV_INCOMING_SST},
-    /* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ,
-                               BTA_AV_CLOSING_SST},
+    /* AVDT_CONNECT_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* AVDT_DISCONNECT_EVT */
+    {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ, BTA_AV_CLOSING_SST},
     /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
-    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE,
-                              BTA_AV_INCOMING_SST},
+    /* AVDT_DELAY_RPT_EVT */
+    {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
     /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
-    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
-                                 BTA_AV_INCOMING_SST},
-    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
-                                     BTA_AV_INCOMING_SST}};
+    /* API_OFFLOAD_START_EVT */
+    {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_OFFLOAD_START_RSP_EVT */
+    {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST}};
 
 /* state table for opening state */
 static const uint8_t bta_av_sst_opening[][BTA_AV_NUM_COLS] = {
     /* Event                     Action 1               Action 2 Next state */
-    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
     /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
     /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
-                               BTA_AV_OPENING_SST},
-    /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
-                               BTA_AV_OPENING_SST},
+    /* API_PROTECT_REQ_EVT */
+    {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_PROTECT_RSP_EVT */
+    {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
     /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_OPENING_SST},
-    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_OPENING_SST},
-    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                 BTA_AV_OPENING_SST},
-    /* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE,
-                           BTA_AV_OPENING_SST},
-    /* SDP_DISC_FAIL_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE,
-                             BTA_AV_OPENING_SST},
-    /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE,
-                           BTA_AV_OPENING_SST},
-    /* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
-                             BTA_AV_CLOSING_SST},
-    /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE,
-                             BTA_AV_OPENING_SST},
-    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
-                               BTA_AV_CLOSING_SST},
-    /* STR_OPEN_OK_EVT */ {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED,
-                           BTA_AV_OPEN_SST},
-    /* STR_OPEN_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
-                             BTA_AV_CLOSING_SST},
+    /* SRC_DATA_READY_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* CI_SETCONFIG_OK_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* CI_SETCONFIG_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* SDP_DISC_OK_EVT */
+    {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* SDP_DISC_FAIL_EVT */
+    {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_DISC_OK_EVT */
+    {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_DISC_FAIL_EVT */
+    {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_GETCAP_OK_EVT */
+    {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_GETCAP_FAIL_EVT */
+    {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_OPEN_OK_EVT */
+    {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED, BTA_AV_OPEN_SST},
+    /* STR_OPEN_FAIL_EVT */
+    {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_OPENING_SST},
+    /* STR_START_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
     /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE,
-                              BTA_AV_INCOMING_SST},
-    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
-                                BTA_AV_OPENING_SST},
-    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
-                                BTA_AV_OPENING_SST},
-    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_OPENING_SST},
-    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_OPENING_SST},
-    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_OPENING_SST},
-    /* AVRC_TIMER_EVT */ {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE,
-                          BTA_AV_OPENING_SST},
-    /* AVDT_CONNECT_EVT */ {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE,
-                            BTA_AV_OPENING_SST},
-    /* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE,
-                               BTA_AV_INIT_SST},
+    /* STR_CONFIG_IND_EVT */
+    {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* STR_SECURITY_IND_EVT */
+    {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_SECURITY_CFM_EVT */
+    {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_WRITE_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_SUSPEND_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_RECONFIG_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AVRC_TIMER_EVT */
+    {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AVDT_CONNECT_EVT */
+    {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AVDT_DISCONNECT_EVT */
+    {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE,
-                              BTA_AV_OPENING_SST},
+    /* AVDT_DELAY_RPT_EVT */
+    {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
     /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
-    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
-                                 BTA_AV_OPENING_SST},
-    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
-                                     BTA_AV_OPENING_SST}};
+    /* API_OFFLOAD_START_EVT */
+    {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_OFFLOAD_START_RSP_EVT */
+    {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_OPENING_SST}};
 
 /* state table for open state */
 static const uint8_t bta_av_sst_open[][BTA_AV_NUM_COLS] = {
     /* Event                     Action 1               Action 2 Next state */
-    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* API_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AP_START_EVT */ {BTA_AV_DO_START, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* AP_STOP_EVT */ {BTA_AV_STR_STOPPED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
-                               BTA_AV_OPEN_SST},
-    /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
-                               BTA_AV_OPEN_SST},
+    /* API_PROTECT_REQ_EVT */
+    {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* API_PROTECT_RSP_EVT */
+    {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* API_RC_OPEN_EVT  */ {BTA_AV_SET_USE_RC, BTA_AV_OPEN_RC, BTA_AV_OPEN_SST},
-    /* SRC_DATA_READY_EVT */ {BTA_AV_DATA_PATH, BTA_AV_SIGNORE,
-                              BTA_AV_OPEN_SST},
+    /* SRC_DATA_READY_EVT */
+    {BTA_AV_DATA_PATH, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                 BTA_AV_OPEN_SST},
+    /* CI_SETCONFIG_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
@@ -312,40 +313,40 @@
     /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* STR_START_OK_EVT */ {BTA_AV_START_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* STR_START_FAIL_EVT */ {BTA_AV_START_FAILED, BTA_AV_SIGNORE,
-                              BTA_AV_OPEN_SST},
+    /* STR_START_FAIL_EVT */
+    {BTA_AV_START_FAILED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* STR_CLOSE_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
-    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
-                              BTA_AV_OPEN_SST},
-    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
-                                BTA_AV_OPEN_SST},
-    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
-                                BTA_AV_OPEN_SST},
-    /* STR_WRITE_CFM_EVT */ {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH,
-                             BTA_AV_OPEN_SST},
-    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE,
-                               BTA_AV_OPEN_SST},
-    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_OPEN_SST},
-    /* AVRC_TIMER_EVT */ {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START,
-                          BTA_AV_OPEN_SST},
+    /* STR_CONFIG_IND_EVT */
+    {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_SECURITY_IND_EVT */
+    {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_SECURITY_CFM_EVT */
+    {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_WRITE_CFM_EVT */
+    {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH, BTA_AV_OPEN_SST},
+    /* STR_SUSPEND_CFM_EVT */
+    {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_RECONFIG_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* AVRC_TIMER_EVT */
+    {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST},
     /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
-                               BTA_AV_INIT_SST},
+    /* AVDT_DISCONNECT_EVT */
+    {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
     /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
-                                 BTA_AV_OPEN_SST},
-    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
-                                     BTA_AV_OPEN_SST}};
+    /* API_OFFLOAD_START_EVT */
+    {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* API_OFFLOAD_START_RSP_EVT */
+    {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_OPEN_SST}};
 
 /* state table for reconfig state */
 static const uint8_t bta_av_sst_rcfg[][BTA_AV_NUM_COLS] = {
     /* Event                     Action 1               Action 2 Next state */
-    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
-                        BTA_AV_CLOSING_SST},
+    /* API_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_CLOSE_EVT */
+    {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
@@ -354,109 +355,109 @@
     /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                 BTA_AV_RCFG_SST},
+    /* CI_SETCONFIG_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE,
-                           BTA_AV_RCFG_SST},
-    /* STR_DISC_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
-                             BTA_AV_INIT_SST},
-    /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE,
-                             BTA_AV_RCFG_SST},
-    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
-                               BTA_AV_INIT_SST},
+    /* STR_DISC_OK_EVT */
+    {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_DISC_FAIL_EVT */
+    {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_GETCAP_OK_EVT */
+    {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_GETCAP_FAIL_EVT */
+    {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_OPEN_OK_EVT */ {BTA_AV_RCFG_STR_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
-    /* STR_OPEN_FAIL_EVT */ {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE,
-                             BTA_AV_RCFG_SST},
+    /* STR_OPEN_FAIL_EVT */
+    {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* STR_CLOSE_EVT */ {BTA_AV_RCFG_CONNECT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
-                              BTA_AV_RCFG_SST},
-    /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_RCFG_SST},
-    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_RCFG_SST},
+    /* STR_CONFIG_IND_EVT */
+    {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_SECURITY_IND_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_SECURITY_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SUSPEND_CONT,
-                               BTA_AV_RCFG_SST},
-    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE,
-                                BTA_AV_RCFG_SST},
+    /* STR_SUSPEND_CFM_EVT */
+    {BTA_AV_SUSPEND_CFM, BTA_AV_SUSPEND_CONT, BTA_AV_RCFG_SST},
+    /* STR_RECONFIG_CFM_EVT */
+    {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE,
-                               BTA_AV_RCFG_SST},
+    /* AVDT_DISCONNECT_EVT */
+    {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
     /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
-    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
-                                 BTA_AV_RCFG_SST},
-    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
-                                     BTA_AV_RCFG_SST}};
+    /* API_OFFLOAD_START_EVT */
+    {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_OFFLOAD_START_RSP_EVT */
+    {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_RCFG_SST}};
 
 /* state table for closing state */
 static const uint8_t bta_av_sst_closing[][BTA_AV_NUM_COLS] = {
     /* Event                     Action 1               Action 2 Next state */
-    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
-                        BTA_AV_CLOSING_SST},
+    /* API_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_CLOSE_EVT */
+    {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_CLOSING_SST},
-    /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_CLOSING_SST},
+    /* API_PROTECT_REQ_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_PROTECT_RSP_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_CLOSING_SST},
-    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_CLOSING_SST},
-    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                 BTA_AV_CLOSING_SST},
+    /* SRC_DATA_READY_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* CI_SETCONFIG_OK_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* CI_SETCONFIG_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* SDP_DISC_OK_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
-    /* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE,
-                             BTA_AV_INIT_SST},
+    /* SDP_DISC_FAIL_EVT */
+    {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_CLOSING_SST},
-    /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_CLOSING_SST},
-    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_CLOSING_SST},
+    /* STR_DISC_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_GETCAP_OK_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_GETCAP_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* STR_OPEN_OK_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* STR_OPEN_FAIL_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
-                             BTA_AV_CLOSING_SST},
+    /* STR_OPEN_FAIL_EVT */
+    {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_CLOSING_SST},
-    /* STR_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
-                         BTA_AV_CLOSING_SST},
-    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
-                              BTA_AV_CLOSING_SST},
-    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE,
-                                BTA_AV_CLOSING_SST},
-    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_CLOSING_SST},
-    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                             BTA_AV_CLOSING_SST},
-    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                               BTA_AV_CLOSING_SST},
-    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                                BTA_AV_CLOSING_SST},
+    /* STR_START_FAIL_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_CLOSE_EVT */
+    {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_CONFIG_IND_EVT */
+    {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_SECURITY_IND_EVT */
+    {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_SECURITY_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_WRITE_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_SUSPEND_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_RECONFIG_CFM_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
-                               BTA_AV_INIT_SST},
+    /* AVDT_DISCONNECT_EVT */
+    {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
     /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
-                              BTA_AV_CLOSING_SST},
+    /* AVDT_DELAY_RPT_EVT */
+    {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
     /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
-    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
-                                 BTA_AV_CLOSING_SST},
-    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
-                                     BTA_AV_CLOSING_SST}};
+    /* API_OFFLOAD_START_EVT */
+    {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_OFFLOAD_START_RSP_EVT */
+    {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST}};
 
 /* type for state table */
 typedef const uint8_t (*tBTA_AV_SST_TBL)[BTA_AV_NUM_COLS];
@@ -466,27 +467,6 @@
     bta_av_sst_init, bta_av_sst_incoming, bta_av_sst_opening,
     bta_av_sst_open, bta_av_sst_rcfg,     bta_av_sst_closing};
 
-static const char* bta_av_sst_code(uint8_t state);
-
-/*******************************************************************************
- *
- * Function         bta_av_is_rcfg_sst
- *
- * Description      Check if stream state machine is in reconfig state.
- *
- *
- * Returns          true if stream state machine is in reconfig state.
- *
- ******************************************************************************/
-bool bta_av_is_rcfg_sst(tBTA_AV_SCB* p_scb) {
-  bool is_rcfg_sst = false;
-
-  if (p_scb != NULL) {
-    if (p_scb->state == BTA_AV_RCFG_SST) is_rcfg_sst = true;
-  }
-
-  return is_rcfg_sst;
-}
 
 /*******************************************************************************
  *
@@ -500,49 +480,32 @@
  ******************************************************************************/
 void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event,
                         tBTA_AV_DATA* p_data) {
-  tBTA_AV_SST_TBL state_table;
-  uint8_t action;
-  int i, xx;
-
   if (p_scb == NULL) {
     /* this stream is not registered */
-    APPL_TRACE_EVENT("AV channel not registered");
+    APPL_TRACE_EVENT("%s: AV channel not registered", __func__);
     return;
   }
 
-  /* In case incoming connection is for VDP, we need to swap scb.        */
-  /* When ACP_CONNECT_EVT was received, we put first available scb to    */
-  /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we     */
-  /* know if it is A2DP or VDP.                                          */
-  if ((p_scb->state == BTA_AV_INIT_SST) &&
-      (event == BTA_AV_STR_CONFIG_IND_EVT)) {
-    for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
-      if (bta_av_cb.p_scb[xx]) {
-        if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) {
-          bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
-          bta_av_cb.p_scb[xx]->coll_mask = 0;
-          p_scb->state = BTA_AV_INCOMING_SST;
-          break;
-        }
-      }
-    }
-  }
-
-  APPL_TRACE_VERBOSE("%s: AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", __func__,
-                     p_scb->hndl, event, bta_av_evt_code(event), p_scb->state,
-                     bta_av_sst_code(p_scb->state));
+  APPL_TRACE_VERBOSE(
+      "%s: peer %s AV event(0x%x)=0x%x(%s) state=%d(%s) p_scb=%p", __func__,
+      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);
 
   /* look up the state table for the current state */
-  state_table = bta_av_sst_tbl[p_scb->state];
-
-  event -= BTA_AV_FIRST_SSM_EVT;
+  tBTA_AV_SST_TBL state_table = bta_av_sst_tbl[p_scb->state];
 
   /* set next state */
+  event -= BTA_AV_FIRST_SSM_EVT;
   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->PeerAddress().ToString().c_str(), p_scb->state,
+                     bta_av_sst_code(p_scb->state), p_scb);
+
   /* execute action functions */
-  for (i = 0; i < BTA_AV_SACTIONS; i++) {
-    action = state_table[event][i];
+  for (int i = 0; i < BTA_AV_SACTIONS; i++) {
+    uint8_t action = state_table[event][i];
     if (action != BTA_AV_SIGNORE) {
       (*p_scb->p_act_tbl[action])(p_scb, p_data);
     } else
@@ -601,9 +564,19 @@
  *
  ******************************************************************************/
 void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb) {
-  if (p_scb) {
-    p_scb->state = BTA_AV_INIT_SST;
+  if (p_scb == nullptr) {
+    return;
   }
+
+  uint8_t next_state = BTA_AV_INIT_SST;
+
+  APPL_TRACE_VERBOSE(
+      "%s: peer %s AV (hndl=0x%x) state=%d(%s) next state=%d(%s) p_scb=%p",
+      __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;
 }
 
 /*******************************************************************************
@@ -654,7 +627,7 @@
  * Returns          char *
  *
  ******************************************************************************/
-static const char* bta_av_sst_code(uint8_t state) {
+const char* bta_av_sst_code(uint8_t state) {
   switch (state) {
     case BTA_AV_INIT_SST:
       return "INIT";
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index eaa61ab..5abda87 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2014 Broadcom Corporation
+ *  Copyright 2003-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@
 #include <base/bind.h>
 #include <base/callback.h>
 #include <base/logging.h>
-#include <cutils/log.h>
 #include <string.h>
 
 #include "bt_common.h"
@@ -53,12 +52,14 @@
 #include "gap_api.h"
 #endif
 
+using bluetooth::Uuid;
+
 static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir,
                                   uint16_t eir_len);
 static void bta_dm_inq_cmpl_cb(void* p_result);
 static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr,
                                                 DEV_CLASS dc, BD_NAME bd_name);
-static void bta_dm_remname_cback(tBTM_REMOTE_DEV_NAME* p_remote_name);
+static void bta_dm_remname_cback(void* p);
 static void bta_dm_find_services(const RawAddress& bd_addr);
 static void bta_dm_discover_next_device(void);
 static void bta_dm_sdp_callback(uint16_t sdp_status);
@@ -75,17 +76,15 @@
                                                     DEV_CLASS dev_class,
                                                     BD_NAME bd_name,
                                                     int result);
-static void bta_dm_local_name_cback(const RawAddress& bd_addr);
+static void bta_dm_local_name_cback(void* p_name);
 static bool bta_dm_check_av(uint16_t event);
 static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data);
 
 static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                                uint8_t app_id, const RawAddress* peer_addr);
+                                uint8_t app_id, const RawAddress& peer_addr);
 
 /* Extended Inquiry Response */
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
 static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
-#endif
 
 static void bta_dm_set_eir(char* local_name);
 
@@ -96,7 +95,7 @@
 static void bta_dm_search_timer_cback(void* data);
 static void bta_dm_disable_conn_down_timer_cback(void* data);
 static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                            uint8_t app_id, const RawAddress* peer_addr);
+                            uint8_t app_id, const RawAddress& peer_addr);
 static void bta_dm_adjust_roles(bool delay_role_switch);
 static char* bta_dm_get_remname(void);
 static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result);
@@ -147,8 +146,6 @@
 #define BTA_DM_SWITCH_DELAY_TIMER_MS 500
 #endif
 
-#define BTA_MAX_SERVICES 32
-
 static void bta_dm_reset_sec_dev_pending(const RawAddress& remote_bd_addr);
 static void bta_dm_remove_sec_dev_entry(const RawAddress& remote_bd_addr);
 static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir,
@@ -239,11 +236,7 @@
                                      &bta_dm_new_link_key_cback,
                                      &bta_dm_authentication_complete_cback,
                                      &bta_dm_bond_cancel_complete_cback,
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
                                      &bta_dm_sp_cback,
-#else
-                                     NULL,
-#endif
                                      &bta_dm_ble_smp_cback,
                                      &bta_dm_ble_id_key_cback};
 
@@ -252,28 +245,16 @@
 
 extern DEV_CLASS local_device_default_class;
 
-/*******************************************************************************
- *
- * Function         bta_dm_enable
- *
- * Description      Initialises the BT device manager
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_enable(tBTA_DM_MSG* p_data) {
-  tBTA_DM_ENABLE enable_event;
-
+/** Initialises the BT device manager */
+void bta_dm_enable(tBTA_DM_SEC_CBACK* p_sec_cback) {
   /* if already in use, return an error */
-  if (bta_dm_cb.is_bta_dm_active == true) {
+  if (bta_dm_cb.is_bta_dm_active) {
+    tBTA_DM_SEC enable_event;
     APPL_TRACE_WARNING("%s Device already started by another application",
                        __func__);
-    memset(&enable_event, 0, sizeof(tBTA_DM_ENABLE));
-    enable_event.status = BTA_FAILURE;
-    if (p_data->enable.p_sec_cback != NULL)
-      p_data->enable.p_sec_cback(BTA_DM_ENABLE_EVT,
-                                 (tBTA_DM_SEC*)&enable_event);
+    memset(&enable_event, 0, sizeof(tBTA_DM_SEC));
+    enable_event.enable.status = BTA_FAILURE;
+    if (p_sec_cback != NULL) p_sec_cback(BTA_DM_ENABLE_EVT, &enable_event);
     return;
   }
 
@@ -283,8 +264,7 @@
   /* make sure security callback is saved - if no callback, do not erase the
   previous one,
   it could be an error recovery mechanism */
-  if (p_data->enable.p_sec_cback != NULL)
-    bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback;
+  if (p_sec_cback != NULL) bta_dm_cb.p_sec_cback = p_sec_cback;
   /* notify BTA DM is now active */
   bta_dm_cb.is_bta_dm_active = true;
 
@@ -430,9 +410,9 @@
       BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ID,
                            (tBTM_BLE_LOCAL_KEYS*)&id_key);
     }
-    bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+    bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
 
-    BTM_SecRegister((tBTM_APPL_INFO*)&bta_security);
+    BTM_SecRegister(&bta_security);
     BTM_SetDefaultLinkSuperTout(p_bta_dm_cfg->link_timeout);
     BTM_WritePageTimeout(p_bta_dm_cfg->page_timeout);
     bta_dm_cb.cur_policy = p_bta_dm_cfg->policy_settings;
@@ -459,15 +439,14 @@
        which forces
        the DM_ENABLE_EVT to be sent only after all the init steps are complete
        */
-    BTM_ReadLocalDeviceNameFromController(
-        (tBTM_CMPL_CB*)bta_dm_local_name_cback);
+    BTM_ReadLocalDeviceNameFromController(bta_dm_local_name_cback);
 
-    bta_sys_rm_register((tBTA_SYS_CONN_CBACK*)bta_dm_rm_cback);
+    bta_sys_rm_register(bta_dm_rm_cback);
 
     /* initialize bluetooth low power manager */
     bta_dm_init_pm();
 
-    bta_sys_policy_register((tBTA_SYS_CONN_CBACK*)bta_dm_policy_cback);
+    bta_sys_policy_register(bta_dm_policy_cback);
 
     bta_dm_gattc_register();
 
@@ -475,17 +454,8 @@
     APPL_TRACE_DEBUG(" --- ignored event");
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_disable
- *
- * Description      Disables the BT device manager
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_disable(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+/** Disables the BT device manager */
+void bta_dm_disable() {
   /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after
    * last channel is closed) */
   L2CA_SetIdleTimeoutByBdAddr(RawAddress::kAny, 0, BT_TRANSPORT_BR_EDR);
@@ -566,32 +536,16 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_set_dev_name
- *
- * Description      Sets local device name
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_set_dev_name(tBTA_DM_MSG* p_data) {
-  BTM_SetLocalDeviceName((char*)p_data->set_name.name);
-  bta_dm_set_eir((char*)p_data->set_name.name);
+/** Sets local device name */
+void bta_dm_set_dev_name(const std::vector<uint8_t>& name) {
+  BTM_SetLocalDeviceName((char*)name.data());
+  bta_dm_set_eir((char*)name.data());
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_set_visibility
- *
- * Description      Sets discoverability, connectability and pairability
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_set_visibility(tBTA_DM_MSG* p_data) {
+/** Sets discoverability, connectability and pairability */
+void bta_dm_set_visibility(tBTA_DM_DISC disc_mode_param,
+                           tBTA_DM_CONN conn_mode_param, uint8_t pairable_mode,
+                           uint8_t conn_paired_only) {
   uint16_t window, interval;
   uint16_t le_disc_mode = BTM_BleReadDiscoverability();
   uint16_t le_conn_mode = BTM_BleReadConnectability();
@@ -599,55 +553,44 @@
   uint16_t conn_mode = BTM_ReadConnectability(&window, &interval);
 
   /* set modes for Discoverability and connectability if not ignore */
-  if (p_data->set_visibility.disc_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
-    if ((p_data->set_visibility.disc_mode & BTA_DM_LE_IGNORE) ==
-        BTA_DM_LE_IGNORE)
-      p_data->set_visibility.disc_mode =
-          ((p_data->set_visibility.disc_mode & ~BTA_DM_LE_IGNORE) |
-           le_disc_mode);
-    if ((p_data->set_visibility.disc_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE)
-      p_data->set_visibility.disc_mode =
-          ((p_data->set_visibility.disc_mode & ~BTA_DM_IGNORE) | disc_mode);
+  if (disc_mode_param != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
+    if ((disc_mode_param & BTA_DM_LE_IGNORE) == BTA_DM_LE_IGNORE)
+      disc_mode_param = ((disc_mode_param & ~BTA_DM_LE_IGNORE) | le_disc_mode);
+    if ((disc_mode_param & BTA_DM_IGNORE) == BTA_DM_IGNORE)
+      disc_mode_param = ((disc_mode_param & ~BTA_DM_IGNORE) | disc_mode);
 
-    BTM_SetDiscoverability(p_data->set_visibility.disc_mode,
-                           bta_dm_cb.inquiry_scan_window,
+    BTM_SetDiscoverability(disc_mode_param, bta_dm_cb.inquiry_scan_window,
                            bta_dm_cb.inquiry_scan_interval);
   }
 
-  if (p_data->set_visibility.conn_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
-    if ((p_data->set_visibility.conn_mode & BTA_DM_LE_IGNORE) ==
-        BTA_DM_LE_IGNORE)
-      p_data->set_visibility.conn_mode =
-          ((p_data->set_visibility.conn_mode & ~BTA_DM_LE_IGNORE) |
-           le_conn_mode);
-    if ((p_data->set_visibility.conn_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE)
-      p_data->set_visibility.conn_mode =
-          ((p_data->set_visibility.conn_mode & ~BTA_DM_IGNORE) | conn_mode);
+  if (conn_mode_param != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
+    if ((conn_mode_param & BTA_DM_LE_IGNORE) == BTA_DM_LE_IGNORE)
+      conn_mode_param = ((conn_mode_param & ~BTA_DM_LE_IGNORE) | le_conn_mode);
+    if ((conn_mode_param & BTA_DM_IGNORE) == BTA_DM_IGNORE)
+      conn_mode_param = ((conn_mode_param & ~BTA_DM_IGNORE) | conn_mode);
 
-    BTM_SetConnectability(p_data->set_visibility.conn_mode,
-                          bta_dm_cb.page_scan_window,
+    BTM_SetConnectability(conn_mode_param, bta_dm_cb.page_scan_window,
                           bta_dm_cb.page_scan_interval);
   }
 
   /* Send False or True if not ignore */
-  if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE) {
-    if (p_data->set_visibility.pair_mode == BTA_DM_NON_PAIRABLE)
+  if (pairable_mode != BTA_DM_IGNORE) {
+    if (pairable_mode == BTA_DM_NON_PAIRABLE)
       bta_dm_cb.disable_pair_mode = true;
     else
       bta_dm_cb.disable_pair_mode = false;
   }
 
   /* Send False or True if not ignore */
-  if (p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) {
-    if (p_data->set_visibility.conn_paired_only == BTA_DM_CONN_ALL)
+  if (conn_paired_only != BTA_DM_IGNORE) {
+    if (conn_paired_only == BTA_DM_CONN_ALL)
       bta_dm_cb.conn_paired_only = false;
     else
       bta_dm_cb.conn_paired_only = true;
   }
 
   /* Change mode if either mode is not ignore */
-  if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE ||
-      p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE)
+  if (pairable_mode != BTA_DM_IGNORE || conn_paired_only != BTA_DM_IGNORE)
     BTM_SetPairableMode((bool)(!(bta_dm_cb.disable_pair_mode)),
                         bta_dm_cb.conn_paired_only);
 }
@@ -678,45 +621,30 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_remove_device
- *
- * Description      Removes device, disconnects ACL link if required.
- ***
- ******************************************************************************/
-void bta_dm_remove_device(tBTA_DM_MSG* p_data) {
-  tBTA_DM_API_REMOVE_DEVICE* p_dev = &p_data->remove_dev;
-  bool continue_delete_other_dev = false;
-  if (p_dev == NULL) return;
-
-  RawAddress other_address = p_dev->bd_addr;
-
+/** Removes device, disconnects ACL link if required */
+void bta_dm_remove_device(const RawAddress& bd_addr) {
   /* If ACL exists for the device in the remove_bond message*/
-  bool continue_delete_dev = false;
-  uint8_t other_transport = BT_TRANSPORT_INVALID;
+  bool is_bd_addr_connected =
+      BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) ||
+      BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR);
 
-  if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
-      BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR)) {
-    APPL_TRACE_DEBUG("%s: ACL Up count  %d", __func__,
+  uint8_t other_transport = BT_TRANSPORT_INVALID;
+  if (is_bd_addr_connected) {
+    APPL_TRACE_DEBUG("%s: ACL Up count: %d", __func__,
                      bta_dm_cb.device_list.count);
-    continue_delete_dev = false;
 
     /* Take the link down first, and mark the device for removal when
      * disconnected */
     for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
-      if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == p_dev->bd_addr) {
-        uint8_t transport = BT_TRANSPORT_BR_EDR;
-
-        transport = bta_dm_cb.device_list.peer_device[i].transport;
-        bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
-        btm_remove_acl(p_dev->bd_addr, transport);
-        APPL_TRACE_DEBUG("%s:transport = %d", __func__,
-                         bta_dm_cb.device_list.peer_device[i].transport);
+      auto& peer_device = bta_dm_cb.device_list.peer_device[i];
+      if (peer_device.peer_bdaddr == bd_addr) {
+        peer_device.conn_state = BTA_DM_UNPAIRING;
+        btm_remove_acl(bd_addr, peer_device.transport);
+        APPL_TRACE_DEBUG("%s: transport: %d", __func__, peer_device.transport);
 
         /* save the other transport to check if device is connected on
          * other_transport */
-        if (bta_dm_cb.device_list.peer_device[i].transport == BT_TRANSPORT_LE)
+        if (peer_device.transport == BT_TRANSPORT_LE)
           other_transport = BT_TRANSPORT_BR_EDR;
         else
           other_transport = BT_TRANSPORT_LE;
@@ -724,39 +652,44 @@
         break;
       }
     }
-  } else {
-    continue_delete_dev = true;
   }
+
+  RawAddress other_address = bd_addr;
+  RawAddress other_address2 = bd_addr;
+
   // If it is DUMO device and device is paired as different address, unpair that
   // device
-  // if different address
-  if ((other_transport &&
-       (BTM_ReadConnectedTransportAddress(&other_address, other_transport))) ||
-      (!other_transport &&
-       (BTM_ReadConnectedTransportAddress(&other_address,
-                                          BT_TRANSPORT_BR_EDR) ||
-        BTM_ReadConnectedTransportAddress(&other_address, BT_TRANSPORT_LE)))) {
-    continue_delete_other_dev = false;
+  bool other_address_connected =
+      (other_transport)
+          ? BTM_ReadConnectedTransportAddress(&other_address, other_transport)
+          : (BTM_ReadConnectedTransportAddress(&other_address,
+                                               BT_TRANSPORT_BR_EDR) ||
+             BTM_ReadConnectedTransportAddress(&other_address2,
+                                               BT_TRANSPORT_LE));
+  if (other_address == bd_addr) other_address = other_address2;
+
+  if (other_address_connected) {
     /* Take the link down first, and mark the device for removal when
      * disconnected */
     for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
-      if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == other_address) {
-        bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
-        btm_remove_acl(other_address,
-                       bta_dm_cb.device_list.peer_device[i].transport);
+      auto& peer_device = bta_dm_cb.device_list.peer_device[i];
+      if (peer_device.peer_bdaddr == other_address) {
+        peer_device.conn_state = BTA_DM_UNPAIRING;
+        btm_remove_acl(other_address, peer_device.transport);
         break;
       }
     }
-  } else {
-    APPL_TRACE_DEBUG("%s: continue to delete the other dev ", __func__);
-    continue_delete_other_dev = true;
   }
+
   /* Delete the device mentioned in the msg */
-  if (continue_delete_dev) bta_dm_process_remove_device(p_dev->bd_addr);
+  if (!is_bd_addr_connected) {
+    bta_dm_process_remove_device(bd_addr);
+  }
 
   /* Delete the other paired device too */
-  if (continue_delete_other_dev && !other_address.IsEmpty())
+  if (!other_address_connected && !other_address.IsEmpty()) {
     bta_dm_process_remove_device(other_address);
+  }
 }
 
 /*******************************************************************************
@@ -768,8 +701,7 @@
  *                  required information stored in the NVRAM.
  ***
  ******************************************************************************/
-void bta_dm_add_device(tBTA_DM_MSG* p_data) {
-  tBTA_DM_API_ADD_DEVICE* p_dev = &p_data->add_dev;
+void bta_dm_add_device(std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg) {
   uint8_t* p_dc = NULL;
   uint8_t* p_lc = NULL;
   uint32_t trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
@@ -779,86 +711,71 @@
   memset(trusted_services_mask, 0, sizeof(trusted_services_mask));
 
   /* If not all zeros, the device class has been specified */
-  if (p_dev->dc_known) p_dc = (uint8_t*)p_dev->dc;
+  if (msg->dc_known) p_dc = (uint8_t*)msg->dc;
 
-  if (p_dev->link_key_known) p_lc = (uint8_t*)p_dev->link_key;
+  if (msg->link_key_known) p_lc = (uint8_t*)msg->link_key;
 
-  if (p_dev->is_trusted) {
+  if (msg->is_trusted) {
     /* covert BTA service mask to BTM mask */
-    while (p_dev->tm && (index < BTA_MAX_SERVICE_ID)) {
-      if (p_dev->tm & (uint32_t)(1 << index)) {
+    while (msg->tm && (index < BTA_MAX_SERVICE_ID)) {
+      if (msg->tm & (uint32_t)(1 << index)) {
         btm_mask_index =
             bta_service_id_to_btm_srv_id_lkup_tbl[index] / BTM_SEC_ARRAY_BITS;
         trusted_services_mask[btm_mask_index] |=
             (uint32_t)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[index] -
                              (uint32_t)(btm_mask_index * 32)));
 
-        p_dev->tm &= (uint32_t)(~(1 << index));
+        msg->tm &= (uint32_t)(~(1 << index));
       }
       index++;
     }
   }
 
-  if (!BTM_SecAddDevice(p_dev->bd_addr, p_dc, p_dev->bd_name, p_dev->features,
-                        trusted_services_mask, p_lc, p_dev->key_type,
-                        p_dev->io_cap, p_dev->pin_length)) {
-    LOG(ERROR) << "BTA_DM: Error adding device " << p_dev->bd_addr;
+  if (!BTM_SecAddDevice(msg->bd_addr, p_dc, msg->bd_name, msg->features,
+                        trusted_services_mask, p_lc, msg->key_type, msg->io_cap,
+                        msg->pin_length)) {
+    LOG(ERROR) << "BTA_DM: Error adding device " << msg->bd_addr;
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_close_acl
- *
- * Description      This function forces to close the connection to a remote
- *                  device and optionaly remove the device from security
- *                  database if required.
- ***
- ******************************************************************************/
-void bta_dm_close_acl(tBTA_DM_MSG* p_data) {
-  tBTA_DM_API_REMOVE_ACL* p_remove_acl = &p_data->remove_acl;
+/** This function forces to close the connection to a remote device and
+ * optionaly remove the device from security database if required. */
+void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev,
+                      tBTA_TRANSPORT transport) {
   uint8_t index;
 
   APPL_TRACE_DEBUG("bta_dm_close_acl");
 
-  if (BTM_IsAclConnectionUp(p_remove_acl->bd_addr, p_remove_acl->transport)) {
+  if (BTM_IsAclConnectionUp(bd_addr, transport)) {
     for (index = 0; index < bta_dm_cb.device_list.count; index++) {
-      if (bta_dm_cb.device_list.peer_device[index].peer_bdaddr ==
-          p_remove_acl->bd_addr)
+      if (bta_dm_cb.device_list.peer_device[index].peer_bdaddr == bd_addr)
         break;
     }
     if (index != bta_dm_cb.device_list.count) {
-      if (p_remove_acl->remove_dev)
+      if (remove_dev)
         bta_dm_cb.device_list.peer_device[index].remove_dev_pending = true;
     } else {
       APPL_TRACE_ERROR("unknown device, remove ACL failed");
     }
     /* Disconnect the ACL link */
-    btm_remove_acl(p_remove_acl->bd_addr, p_remove_acl->transport);
+    btm_remove_acl(bd_addr, transport);
   }
   /* if to remove the device from security database ? do it now */
-  else if (p_remove_acl->remove_dev) {
-    if (!BTM_SecDeleteDevice(p_remove_acl->bd_addr)) {
+  else if (remove_dev) {
+    if (!BTM_SecDeleteDevice(bd_addr)) {
       APPL_TRACE_ERROR("delete device from security database failed.");
     }
     /* need to remove all pending background connection if any */
-    BTA_GATTC_CancelOpen(0, p_remove_acl->bd_addr, false);
+    BTA_GATTC_CancelOpen(0, bd_addr, false);
     /* remove all cached GATT information */
-    BTA_GATTC_Refresh(p_remove_acl->bd_addr);
+    BTA_GATTC_Refresh(bd_addr);
   }
   /* otherwise, no action needed */
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_remove_all_acl
- *
- * Description      This function forces to close all the ACL links specified by
- *                  link type
- ***
- ******************************************************************************/
-void bta_dm_remove_all_acl(tBTA_DM_MSG* p_data) {
-  const tBTA_DM_LINK_TYPE link_type = p_data->remove_all_acl.link_type;
+// TODO: this is unused. remove?
+/** This function forces to close all the ACL links specified by link type */
+void bta_dm_remove_all_acl(const tBTA_DM_LINK_TYPE link_type) {
   tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
 
   APPL_TRACE_DEBUG("%s link type = %d", __func__, link_type);
@@ -877,31 +794,21 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_bond
- *
- * Description      Bonds with peer device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_bond(tBTA_DM_MSG* p_data) {
+/** Bonds with peer device */
+void bta_dm_bond(const RawAddress& bd_addr, tBTA_TRANSPORT transport) {
   tBTM_STATUS status;
   tBTA_DM_SEC sec_event;
   char* p_name;
 
-  if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN)
-    status = BTM_SecBond(p_data->bond.bd_addr, 0, NULL, 0);
+  if (transport == BTA_TRANSPORT_UNKNOWN)
+    status = BTM_SecBond(bd_addr, 0, NULL, 0);
   else
-    status = BTM_SecBondByTransport(p_data->bond.bd_addr,
-                                    p_data->bond.transport, 0, NULL, 0);
+    status = BTM_SecBondByTransport(bd_addr, transport, 0, NULL, 0);
 
   if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) {
     memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
-    sec_event.auth_cmpl.bd_addr = p_data->bond.bd_addr;
-    p_name = BTM_SecReadDevName(p_data->bond.bd_addr);
+    sec_event.auth_cmpl.bd_addr = bd_addr;
+    p_name = BTM_SecReadDevName(bd_addr);
     if (p_name != NULL) {
       memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN - 1));
       sec_event.auth_cmpl.bd_name[BD_NAME_LEN - 1] = 0;
@@ -916,28 +823,19 @@
       sec_event.auth_cmpl.success = true;
     } else {
       /* delete this device entry from Sec Dev DB */
-      bta_dm_remove_sec_dev_entry(p_data->bond.bd_addr);
+      bta_dm_remove_sec_dev_entry(bd_addr);
     }
     bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_bond_cancel
- *
- * Description      Cancels bonding with a peer device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_bond_cancel(tBTA_DM_MSG* p_data) {
+/** Cancels bonding with a peer device */
+void bta_dm_bond_cancel(const RawAddress& bd_addr) {
   tBTM_STATUS status;
   tBTA_DM_SEC sec_event;
 
   APPL_TRACE_EVENT(" bta_dm_bond_cancel ");
-  status = BTM_SecBondCancel(p_data->bond_cancel.bd_addr);
+  status = BTM_SecBondCancel(bd_addr);
 
   if (bta_dm_cb.p_sec_cback &&
       (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) {
@@ -947,35 +845,22 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_pin_reply
- *
- * Description      Send the pin_reply to a request from BTM
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_pin_reply(tBTA_DM_MSG* p_data) {
+/** Send the pin_reply to a request from BTM */
+void bta_dm_pin_reply(std::unique_ptr<tBTA_DM_API_PIN_REPLY> msg) {
   uint32_t trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
-  uint32_t* current_trusted_mask;
 
-  current_trusted_mask = BTM_ReadTrustedMask(p_data->pin_reply.bd_addr);
-
+  uint32_t* current_trusted_mask = BTM_ReadTrustedMask(msg->bd_addr);
   if (current_trusted_mask) {
     memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask));
   } else {
     memset(trusted_mask, 0, sizeof(trusted_mask));
   }
 
-  if (p_data->pin_reply.accept) {
-    BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_SUCCESS,
-                     p_data->pin_reply.pin_len, p_data->pin_reply.p_pin,
+  if (msg->accept) {
+    BTM_PINCodeReply(msg->bd_addr, BTM_SUCCESS, msg->pin_len, msg->p_pin,
                      trusted_mask);
   } else {
-    BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL,
-                     trusted_mask);
+    BTM_PINCodeReply(msg->bd_addr, BTM_NOT_AUTHORIZED, 0, NULL, trusted_mask);
   }
 }
 
@@ -989,12 +874,14 @@
  *
  ******************************************************************************/
 static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                                uint8_t app_id, const RawAddress* peer_addr) {
+                                uint8_t app_id, const RawAddress& peer_addr) {
   tBTA_DM_PEER_DEVICE* p_dev = NULL;
   uint16_t policy = app_id;
   uint32_t mask = (uint32_t)(1 << id);
 
-  if (peer_addr) p_dev = bta_dm_find_peer_device(*peer_addr);
+  if (peer_addr != RawAddress::kEmpty) {
+    p_dev = bta_dm_find_peer_device(peer_addr);
+  }
 
   APPL_TRACE_DEBUG(" bta_dm_policy_cback cmd:%d, policy:0x%x", status, policy);
   switch (status) {
@@ -1036,67 +923,22 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_confirm
- *
- * Description      Send the user confirm request reply in response to a
- *                  request from BTM
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_confirm(tBTA_DM_MSG* p_data) {
-  tBTM_STATUS res = BTM_NOT_AUTHORIZED;
-
-  if (p_data->confirm.accept == true) res = BTM_SUCCESS;
-  BTM_ConfirmReqReply(res, p_data->confirm.bd_addr);
+/** Send the user confirm request reply in response to a request from BTM */
+void bta_dm_confirm(const RawAddress& bd_addr, bool accept) {
+  BTM_ConfirmReqReply(accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, bd_addr);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_loc_oob
- *
- * Description      Retrieve the OOB data from the local LM
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_loc_oob(UNUSED_ATTR tBTA_DM_MSG* p_data) { BTM_ReadLocalOobData(); }
-
-/*******************************************************************************
- *
- * Function         bta_dm_ci_io_req_act
- *
- * Description      respond to the IO capabilities request from BTM
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_ci_io_req_act(tBTA_DM_MSG* p_data) {
-  tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
-  if (p_data->ci_io_req.auth_req) auth_req = BTM_AUTH_AP_YES;
-  BTM_IoCapRsp(p_data->ci_io_req.bd_addr, p_data->ci_io_req.io_cap,
-               p_data->ci_io_req.oob_data, auth_req);
+/** respond to the IO capabilities request from BTM */
+void bta_dm_ci_io_req_act(const RawAddress& bd_addr, tBTA_IO_CAP io_cap,
+                          tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req) {
+  BTM_IoCapRsp(bd_addr, io_cap, oob_data,
+               auth_req ? BTM_AUTH_AP_YES : BTM_AUTH_AP_NO);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_ci_rmt_oob_act
- *
- * Description      respond to the OOB data request for the remote device from
- *                  BTM
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG* p_data) {
-  tBTM_STATUS res = BTM_NOT_AUTHORIZED;
-
-  if (p_data->ci_rmt_oob.accept == true) res = BTM_SUCCESS;
-  BTM_RemoteOobDataReply(res, p_data->ci_rmt_oob.bd_addr, p_data->ci_rmt_oob.c,
-                         p_data->ci_rmt_oob.r);
+/** respond to the OOB data request for the remote device from BTM */
+void bta_dm_ci_rmt_oob_act(std::unique_ptr<tBTA_DM_CI_RMT_OOB> msg) {
+  BTM_RemoteOobDataReply(msg->accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED,
+                         msg->bd_addr, msg->c, msg->r);
 }
 
 /*******************************************************************************
@@ -1110,9 +952,9 @@
  *
  ******************************************************************************/
 void bta_dm_search_start(tBTA_DM_MSG* p_data) {
-  tBTM_INQUIRY_CMPL result;
+  tBTM_INQUIRY_CMPL result = {};
 
-  size_t len = sizeof(tBT_UUID) * p_data->search.num_uuid;
+  size_t len = sizeof(Uuid) * p_data->search.num_uuid;
   bta_dm_gattc_register();
 
   APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__,
@@ -1121,11 +963,12 @@
   if (p_bta_dm_cfg->avoid_scatter &&
       (p_data->search.rs_res == BTA_DM_RS_NONE) &&
       bta_dm_check_av(BTA_DM_API_SEARCH_EVT)) {
+    LOG(INFO) << __func__ << ": delay search to avoid scatter";
     memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH));
     return;
   }
 
-  BTM_ClearInqDb(NULL);
+  BTM_ClearInqDb(nullptr);
   /* save search params */
   bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
   bta_dm_search_cb.services = p_data->search.services;
@@ -1133,16 +976,17 @@
   osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
 
   if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 &&
-      p_data->search.p_uuid != NULL) {
-    bta_dm_search_cb.p_srvc_uuid = (tBT_UUID*)osi_malloc(len);
-    memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len);
+      p_data->search.p_uuid != nullptr) {
+    bta_dm_search_cb.p_srvc_uuid = (Uuid*)osi_malloc(len);
+    *bta_dm_search_cb.p_srvc_uuid = *p_data->search.p_uuid;
   }
   result.status = BTM_StartInquiry((tBTM_INQ_PARMS*)&p_data->search.inq_params,
-                                   bta_dm_inq_results_cb,
-                                   (tBTM_CMPL_CB*)bta_dm_inq_cmpl_cb);
+                                   bta_dm_inq_results_cb, bta_dm_inq_cmpl_cb);
 
   APPL_TRACE_EVENT("%s status=%d", __func__, result.status);
   if (result.status != BTM_CMD_STARTED) {
+    LOG(ERROR) << __func__ << ": BTM_StartInquiry returned "
+               << std::to_string(result.status);
     result.num_resp = 0;
     bta_dm_inq_cmpl_cb((void*)&result);
   }
@@ -1205,7 +1049,7 @@
  *
  ******************************************************************************/
 void bta_dm_discover(tBTA_DM_MSG* p_data) {
-  size_t len = sizeof(tBT_UUID) * p_data->discover.num_uuid;
+  size_t len = sizeof(Uuid) * p_data->discover.num_uuid;
   APPL_TRACE_EVENT("%s services_to_search=0x%04X, sdp_search=%d", __func__,
                    p_data->discover.services, p_data->discover.sdp_search);
 
@@ -1216,8 +1060,8 @@
   osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
   if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 &&
       p_data->discover.p_uuid != NULL) {
-    bta_dm_search_cb.p_srvc_uuid = (tBT_UUID*)osi_malloc(len);
-    memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len);
+    bta_dm_search_cb.p_srvc_uuid = (Uuid*)osi_malloc(len);
+    *bta_dm_search_cb.p_srvc_uuid = *p_data->discover.p_uuid;
   }
   bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
 
@@ -1232,7 +1076,7 @@
   bta_dm_search_cb.transport = p_data->discover.transport;
 
   bta_dm_search_cb.name_discover_done = false;
-  memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID));
+  bta_dm_search_cb.uuid = p_data->discover.uuid;
   bta_dm_discover_device(p_data->discover.bd_addr);
 }
 
@@ -1361,9 +1205,8 @@
   bta_dm_search_cb.peer_bdaddr = bd_addr;
   bta_dm_search_cb.peer_name[0] = 0;
 
-  btm_status =
-      BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
-                               (tBTM_CMPL_CB*)bta_dm_remname_cback, transport);
+  btm_status = BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
+                                        bta_dm_remname_cback, transport);
 
   if (btm_status == BTM_CMD_STARTED) {
     APPL_TRACE_DEBUG("%s: BTM_ReadRemoteDeviceName is started", __func__);
@@ -1484,12 +1327,10 @@
   uint16_t service = 0xFFFF;
   tSDP_PROTOCOL_ELEM pe;
 
-  tBT_UUID* p_uuid = bta_dm_search_cb.p_srvc_uuid;
+  Uuid* p_uuid = bta_dm_search_cb.p_srvc_uuid;
   tBTA_DM_SEARCH result;
-  tBT_UUID service_uuid;
 
-  uint32_t num_uuids = 0;
-  uint8_t uuid_list[BTA_MAX_SERVICES][MAX_UUID_SIZE];  // assuming a max of 32 services
+  std::vector<Uuid> uuid_list;
 
   if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) ||
       (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) ||
@@ -1499,7 +1340,7 @@
       p_sdp_rec = NULL;
       if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) {
         p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db,
-                                            &bta_dm_search_cb.uuid, p_sdp_rec);
+                                            bta_dm_search_cb.uuid, p_sdp_rec);
 
         if (p_sdp_rec && SDP_FindProtocolListElemInRec(
                              p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
@@ -1519,7 +1360,7 @@
           p_uuid +=
               (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search);
           /* only support 16 bits UUID for now */
-          service = p_uuid->uu.uuid16;
+          service = p_uuid->As16Bit();
         }
         /* all GATT based services */
         do {
@@ -1527,14 +1368,14 @@
           p_sdp_rec =
               SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, 0, p_sdp_rec);
           if (p_sdp_rec) {
+            Uuid service_uuid;
             if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
               /* send result back to app now, one by one */
               result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
               strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
                       BD_NAME_LEN);
-              result.disc_ble_res.service.len = service_uuid.len;
-              result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16;
 
+              result.disc_ble_res.service = service_uuid;
               bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
             }
           }
@@ -1549,20 +1390,14 @@
              bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) ||
             (p_sdp_rec != NULL)) {
           if (service != UUID_SERVCLASS_PNP_INFORMATION) {
-            uint16_t tmp_svc = 0xFFFF;
             bta_dm_search_cb.services_found |=
                 (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(
                     bta_dm_search_cb.service_index - 1));
-            tmp_svc =
+            uint16_t tmp_svc =
                 bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index -
                                                 1];
             /* Add to the list of UUIDs */
-            if (num_uuids < BTA_MAX_SERVICES) {
-              sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]);
-              num_uuids++;
-            } else {
-              android_errorWriteLog(0x534e4554, "74016921");
-            }
+            uuid_list.push_back(Uuid::From16Bit(tmp_svc));
           }
         }
       }
@@ -1588,18 +1423,14 @@
     if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
       p_sdp_rec = NULL;
       do {
-        tBT_UUID temp_uuid;
         /* find a service record, report it */
         p_sdp_rec =
             SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec);
         if (p_sdp_rec) {
+          // SDP_FindServiceUUIDInRec_128bit is used only once, refactor?
+          Uuid temp_uuid;
           if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) {
-            if (num_uuids < BTA_MAX_SERVICES) {
-              memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE);
-              num_uuids++;
-            } else {
-              android_errorWriteLog(0x534e4554, "74016921");
-            }
+            uuid_list.push_back(temp_uuid);
           }
         }
       } while (p_sdp_rec);
@@ -1620,13 +1451,15 @@
       p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
       p_msg->disc_result.result.disc_res.p_raw_data = NULL;
       p_msg->disc_result.result.disc_res.raw_data_size = 0;
-      p_msg->disc_result.result.disc_res.num_uuids = num_uuids;
+      p_msg->disc_result.result.disc_res.num_uuids = uuid_list.size();
       p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
-      if (num_uuids > 0) {
+      if (uuid_list.size() > 0) {
+        // TODO(jpawlowski): make p_uuid_list into vector, and just copy
+        // vectors, but first get rid of bta_sys_sendmsg below.
         p_msg->disc_result.result.disc_res.p_uuid_list =
-            (uint8_t*)osi_malloc(num_uuids * MAX_UUID_SIZE);
-        memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list,
-               num_uuids * MAX_UUID_SIZE);
+            (Uuid*)osi_malloc(uuid_list.size() * sizeof(Uuid));
+        memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list.data(),
+               uuid_list.size() * sizeof(Uuid));
       }
       // Copy the raw_data to the discovery result structure
       if (bta_dm_search_cb.p_sdp_db != NULL &&
@@ -1921,11 +1754,9 @@
  *
  ******************************************************************************/
 static void bta_dm_find_services(const RawAddress& bd_addr) {
-  tSDP_UUID uuid;
-
-  memset(&uuid, 0, sizeof(tSDP_UUID));
 
   while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
+    Uuid uuid = Uuid::kEmpty;
     if (bta_dm_search_cb.services_to_search &
         (tBTA_SERVICE_MASK)(
             BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) {
@@ -1938,10 +1769,10 @@
         LOG_INFO(LOG_TAG, "%s services_to_search=%08x", __func__,
                  bta_dm_search_cb.services_to_search);
         if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) {
-          uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0];
+          uuid = Uuid::From16Bit(bta_service_id_to_uuid_lkup_tbl[0]);
           bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
         } else {
-          uuid.uu.uuid16 = UUID_PROTOCOL_L2CAP;
+          uuid = Uuid::From16Bit(UUID_PROTOCOL_L2CAP);
           bta_dm_search_cb.services_to_search = 0;
         }
       } else {
@@ -1949,15 +1780,14 @@
         if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) {
           if (bta_dm_search_cb.uuid_to_search > 0 &&
               bta_dm_search_cb.p_srvc_uuid) {
-            memcpy(&uuid, (const void*)(bta_dm_search_cb.p_srvc_uuid +
-                                        bta_dm_search_cb.num_uuid -
-                                        bta_dm_search_cb.uuid_to_search),
-                   sizeof(tBT_UUID));
+            uuid = *(bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
+                     bta_dm_search_cb.uuid_to_search);
 
             bta_dm_search_cb.uuid_to_search--;
           } else {
-            uuid.uu.uuid16 =
-                bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+            uuid = Uuid::From16Bit(
+                bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb
+                                                    .service_index]);
           }
 
           /* last one? clear the BLE service bit if all discovery has been done
@@ -1971,18 +1801,17 @@
           /* remove the service from services to be searched  */
           bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
               BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
-          uuid.uu.uuid16 =
-              bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+          uuid = Uuid::From16Bit(
+              bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]);
         }
       }
 
-      if (uuid.len == 0) uuid.len = LEN_UUID_16;
-
       if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID) {
-        memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID));
+        uuid = bta_dm_search_cb.uuid;
       }
 
-      LOG_INFO(LOG_TAG, "%s search UUID = %04x", __func__, uuid.uu.uuid16);
+      LOG_INFO(LOG_TAG, "%s search UUID = %s", __func__,
+               uuid.ToString().c_str());
       SDP_InitDiscoveryDb(bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1,
                           &uuid, 0, NULL);
 
@@ -2111,8 +1940,7 @@
       ((bta_dm_search_cb.p_btm_inq_info == NULL) ||
        (bta_dm_search_cb.p_btm_inq_info &&
         (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) {
-    if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr,
-                                       transport) == true)
+    if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, transport))
       return;
 
     /* starting name discovery failed */
@@ -2128,7 +1956,7 @@
     bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
     if ((bta_dm_search_cb.p_btm_inq_info != NULL) &&
         bta_dm_search_cb.services != BTA_USER_SERVICE_MASK &&
-        (bta_dm_search_cb.sdp_search == false)) {
+        (!bta_dm_search_cb.sdp_search)) {
       /* check if EIR provides the information of supported services */
       bta_dm_eir_search_services(&bta_dm_search_cb.p_btm_inq_info->results,
                                  &bta_dm_search_cb.services_to_search,
@@ -2272,7 +2100,7 @@
 
   APPL_TRACE_DEBUG("%s", __func__);
 
-  if (bta_dm_search_cb.cancel_pending == false) {
+  if (!bta_dm_search_cb.cancel_pending) {
     p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
     p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
   } else {
@@ -2315,9 +2143,9 @@
     bta_dm_remname_cback(&rem_name);
   } else {
     /* get name of device */
-    btm_status = BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
-                                          (tBTM_CMPL_CB*)bta_dm_remname_cback,
-                                          BT_TRANSPORT_BR_EDR);
+    btm_status =
+        BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
+                                 bta_dm_remname_cback, BT_TRANSPORT_BR_EDR);
     if (btm_status == BTM_BUSY) {
       /* wait for next chance(notification of remote name discovery done) */
       APPL_TRACE_DEBUG("%s: BTM_ReadRemoteDeviceName is busy", __func__);
@@ -2343,7 +2171,8 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_dm_remname_cback(tBTM_REMOTE_DEV_NAME* p_remote_name) {
+static void bta_dm_remname_cback(void* p) {
+  tBTM_REMOTE_DEV_NAME* p_remote_name = (tBTM_REMOTE_DEV_NAME*)p;
   APPL_TRACE_DEBUG("bta_dm_remname_cback len = %d name=<%s>",
                    p_remote_name->length, p_remote_name->remote_bd_name);
 
@@ -2452,6 +2281,12 @@
 
     /* 1 additional event data fields for this event */
     sec_event.cfm_req.just_works = bta_dm_cb.just_works;
+    /* retrieve the loc and rmt caps */
+    sec_event.cfm_req.loc_io_caps = bta_dm_cb.loc_io_caps;
+    sec_event.cfm_req.rmt_io_caps = bta_dm_cb.rmt_io_caps;
+    sec_event.cfm_req.loc_auth_req = bta_dm_cb.loc_auth_req;
+    sec_event.cfm_req.rmt_auth_req = bta_dm_cb.rmt_auth_req;
+
   } else {
     /* Retrieved saved device class and bd_addr */
     sec_event.pin_req.bd_addr = bta_dm_cb.pin_bd_addr;
@@ -2608,7 +2443,6 @@
   return BTM_SUCCESS;
 }
 
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
 /*******************************************************************************
  *
  * Function         bta_dm_sp_cback
@@ -2629,16 +2463,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
       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
       break;
 
     case BTM_SP_CFM_REQ_EVT:
@@ -2651,10 +2489,12 @@
       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
       bta_dm_cb.num_val = sec_event.key_notif.passkey =
           p_data->key_notif.passkey;
 
@@ -2664,6 +2504,11 @@
         if (p_data->cfm_req.bd_name[0] == 0) {
           bta_dm_cb.pin_evt = pin_evt;
           bta_dm_cb.pin_bd_addr = p_data->cfm_req.bd_addr;
+          bta_dm_cb.rmt_io_caps = sec_event.cfm_req.rmt_io_caps;
+          bta_dm_cb.loc_io_caps = sec_event.cfm_req.loc_io_caps;
+          bta_dm_cb.rmt_auth_req = sec_event.cfm_req.rmt_auth_req;
+          bta_dm_cb.loc_auth_req = sec_event.cfm_req.loc_auth_req;
+
           BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
                                 p_data->cfm_req.dev_class);
           if ((BTM_ReadRemoteDeviceName(
@@ -2766,7 +2611,6 @@
   APPL_TRACE_EVENT("dm status: %d", status);
   return status;
 }
-#endif
 
 /*******************************************************************************
  *
@@ -2778,7 +2622,7 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_dm_local_name_cback(UNUSED_ATTR const RawAddress& p_name) {
+static void bta_dm_local_name_cback(UNUSED_ATTR void* p_name) {
   tBTA_DM_SEC sec_event;
 
   sec_event.enable.status = BTA_SUCCESS;
@@ -2787,51 +2631,226 @@
     bta_dm_cb.p_sec_cback(BTA_DM_ENABLE_EVT, &sec_event);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_bl_change_cback
- *
- * Description      Callback from btm when acl connection goes up or down
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data) {
-  tBTA_DM_ACL_CHANGE* p_msg =
-      (tBTA_DM_ACL_CHANGE*)osi_malloc(sizeof(tBTA_DM_ACL_CHANGE));
+static void send_busy_level_update(uint8_t busy_level,
+                                   uint8_t busy_level_flags) {
+  if (!bta_dm_cb.p_sec_cback) return;
 
-  p_msg->event = p_data->event;
-  p_msg->is_new = false;
+  tBTA_DM_SEC conn;
+  memset(&conn, 0, sizeof(tBTA_DM_SEC));
+  conn.busy_level.level = busy_level;
+  conn.busy_level.level_flags = busy_level_flags;
+  bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);
+}
 
-  switch (p_msg->event) {
-    case BTM_BL_CONN_EVT:
-      p_msg->is_new = true;
-      p_msg->bd_addr = *p_data->conn.p_bda;
-      p_msg->transport = p_data->conn.transport;
-      p_msg->handle = p_data->conn.handle;
+static void handle_role_change(const RawAddress& bd_addr, uint8_t new_role,
+                               uint8_t hci_status) {
+  tBTA_DM_SEC conn;
+  memset(&conn, 0, sizeof(tBTA_DM_SEC));
+
+  tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr);
+  if (!p_dev) return;
+  LOG_INFO(LOG_TAG,
+           "%s: peer %s info:0x%x new_role:0x%x dev count:%d hci_status=%d",
+           __func__, bd_addr.ToString().c_str(), p_dev->info, new_role,
+           bta_dm_cb.device_list.count, hci_status);
+  if (p_dev->info & BTA_DM_DI_AV_ACTIVE) {
+    bool need_policy_change = false;
+
+    /* there's AV activity on this link */
+    if (new_role == HCI_ROLE_SLAVE && bta_dm_cb.device_list.count > 1 &&
+        hci_status == HCI_SUCCESS) {
+      /* more than one connections and the AV connection is role switched
+       * to slave
+       * switch it back to master and remove the switch policy */
+      BTM_SwitchRole(bd_addr, BTM_ROLE_MASTER, NULL);
+      need_policy_change = true;
+    } else if (p_bta_dm_cfg->avoid_scatter && (new_role == HCI_ROLE_MASTER)) {
+      /* if the link updated to be master include AV activities, remove
+       * the switch policy */
+      need_policy_change = true;
+    }
+
+    if (need_policy_change) {
+      bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+                          p_dev->peer_bdaddr);
+    }
+  } else {
+    /* there's AV no activity on this link and role switch happened
+     * check if AV is active
+     * if so, make sure the AV link is master */
+    bta_dm_check_av(0);
+  }
+  bta_sys_notify_role_chg(bd_addr, new_role, hci_status);
+  conn.role_chg.bd_addr = bd_addr;
+  conn.role_chg.new_role = (uint8_t)new_role;
+  if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, &conn);
+}
+
+static void bta_dm_acl_change(bool is_new, const RawAddress& bd_addr,
+                              tBT_TRANSPORT transport, uint16_t handle) {
+  bool issue_unpair_cb = false;
+
+  tBTA_DM_SEC conn;
+  memset(&conn, 0, sizeof(tBTA_DM_SEC));
+
+  if (is_new) {
+    uint8_t i;
+    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == bd_addr &&
+          bta_dm_cb.device_list.peer_device[i].conn_handle == handle)
+        break;
+    }
+
+    if (i == bta_dm_cb.device_list.count) {
+      if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) {
+        bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
+            .peer_bdaddr = bd_addr;
+        bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
+            .link_policy = bta_dm_cb.cur_policy;
+        bta_dm_cb.device_list.count++;
+        bta_dm_cb.device_list.peer_device[i].conn_handle = handle;
+        if (transport == BT_TRANSPORT_LE) bta_dm_cb.device_list.le_count++;
+      } else {
+        APPL_TRACE_ERROR("%s max active connection reached, no resources",
+                         __func__);
+        return;
+      }
+    }
+
+    bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED;
+    bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE;
+    conn.link_up.bd_addr = bd_addr;
+    bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE;
+    conn.link_up.link_type = transport;
+    bta_dm_cb.device_list.peer_device[i].transport = transport;
+
+    uint8_t* p;
+    if (((NULL != (p = BTM_ReadLocalFeatures())) &&
+         HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+        ((NULL != (p = BTM_ReadRemoteFeatures(bd_addr))) &&
+         HCI_SNIFF_SUB_RATE_SUPPORTED(p))) {
+      /* both local and remote devices support SSR */
+      bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR;
+    }
+    APPL_TRACE_WARNING("%s info: 0x%x", __func__,
+                       bta_dm_cb.device_list.peer_device[i].info);
+
+    if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, &conn);
+  } else {
+    for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr != bd_addr ||
+          bta_dm_cb.device_list.peer_device[i].transport != transport)
+        continue;
+
+      if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING) {
+        if (BTM_SecDeleteDevice(
+                bta_dm_cb.device_list.peer_device[i].peer_bdaddr))
+          issue_unpair_cb = true;
+
+        APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ", __func__,
+                         issue_unpair_cb);
+      }
+
+      conn.link_down.is_removed =
+          bta_dm_cb.device_list.peer_device[i].remove_dev_pending;
+
+      // Iterate to the one before the last when shrinking the list,
+      // otherwise we memcpy garbage data into the record.
+      // Then clear out the last item in the list since we are shrinking.
+      for (; i < bta_dm_cb.device_list.count - 1; i++) {
+        memcpy(&bta_dm_cb.device_list.peer_device[i],
+               &bta_dm_cb.device_list.peer_device[i + 1],
+               sizeof(bta_dm_cb.device_list.peer_device[i]));
+      }
+      if (bta_dm_cb.device_list.count > 0) {
+        int clear_index = bta_dm_cb.device_list.count - 1;
+        memset(&bta_dm_cb.device_list.peer_device[clear_index], 0,
+               sizeof(bta_dm_cb.device_list.peer_device[clear_index]));
+      }
       break;
-    case BTM_BL_DISCN_EVT:
-      p_msg->bd_addr = *p_data->discn.p_bda;
-      p_msg->transport = p_data->discn.transport;
-      p_msg->handle = p_data->discn.handle;
-      break;
-    case BTM_BL_UPDATE_EVT:
-      p_msg->busy_level = p_data->update.busy_level;
-      p_msg->busy_level_flags = p_data->update.busy_level_flags;
-      break;
-    case BTM_BL_ROLE_CHG_EVT:
-      p_msg->new_role = p_data->role_chg.new_role;
-      p_msg->hci_status = p_data->role_chg.hci_status;
-      p_msg->bd_addr = *p_data->role_chg.p_bda;
-      break;
-    case BTM_BL_COLLISION_EVT:
-      p_msg->bd_addr = *p_data->conn.p_bda;
-      break;
+    }
+    if (bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--;
+    if ((transport == BT_TRANSPORT_LE) && (bta_dm_cb.device_list.le_count))
+      bta_dm_cb.device_list.le_count--;
+    conn.link_down.link_type = transport;
+
+    if (bta_dm_search_cb.wait_disc && bta_dm_search_cb.peer_bdaddr == bd_addr) {
+      bta_dm_search_cb.wait_disc = false;
+
+      if (bta_dm_search_cb.sdp_results) {
+        APPL_TRACE_EVENT(" timer stopped  ");
+        alarm_cancel(bta_dm_search_cb.search_timer);
+        bta_dm_discover_next_device();
+      }
+    }
+
+    if (bta_dm_cb.disabling) {
+      if (!BTM_GetNumAclLinks()) {
+        /*
+         * Start a timer to make sure that the profiles
+         * get the disconnect event.
+         */
+        alarm_set_on_mloop(bta_dm_cb.disable_timer,
+                           BTA_DM_DISABLE_CONN_DOWN_TIMER_MS,
+                           bta_dm_disable_conn_down_timer_cback, NULL);
+      }
+    }
+    if (conn.link_down.is_removed) {
+      BTM_SecDeleteDevice(bd_addr);
+      /* need to remove all pending background connection */
+      BTA_GATTC_CancelOpen(0, bd_addr, false);
+      /* remove all cached GATT information */
+      BTA_GATTC_Refresh(bd_addr);
+    }
+
+    conn.link_down.bd_addr = bd_addr;
+    conn.link_down.status = (uint8_t)btm_get_acl_disc_reason_code();
+    if (bta_dm_cb.p_sec_cback) {
+      bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn);
+      if (issue_unpair_cb)
+        bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn);
+    }
   }
 
-  p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
-  bta_sys_sendmsg(p_msg);
+  bta_dm_adjust_roles(true);
+}
+
+/** Callback from btm when acl connection goes up or down */
+static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data) {
+  switch (p_data->event) {
+    case BTM_BL_CONN_EVT:
+      /* connection up */
+      do_in_bta_thread(FROM_HERE,
+                       base::Bind(bta_dm_acl_change, true, *p_data->conn.p_bda,
+                                  p_data->conn.transport, p_data->conn.handle));
+      break;
+    case BTM_BL_DISCN_EVT:
+      /* connection down */
+      do_in_bta_thread(
+          FROM_HERE, base::Bind(bta_dm_acl_change, false, *p_data->discn.p_bda,
+                                p_data->discn.transport, p_data->discn.handle));
+      break;
+
+    case BTM_BL_UPDATE_EVT: {
+      /* busy level update */
+      do_in_bta_thread(FROM_HERE, base::Bind(send_busy_level_update,
+                                             p_data->update.busy_level,
+                                             p_data->update.busy_level_flags));
+      return;
+    }
+    case BTM_BL_ROLE_CHG_EVT: {
+      const auto& tmp = p_data->role_chg;
+      do_in_bta_thread(FROM_HERE, base::Bind(handle_role_change, *tmp.p_bda,
+                                             tmp.new_role, tmp.hci_status));
+      return;
+    }
+
+    case BTM_BL_COLLISION_EVT:
+      /* Collision report from Stack: Notify profiles */
+      do_in_bta_thread(
+          FROM_HERE, base::Bind(bta_sys_notify_collision, *p_data->conn.p_bda));
+      return;
+  }
 }
 
 /*******************************************************************************
@@ -2843,7 +2862,7 @@
  * Returns
  *
  ******************************************************************************/
-static void bta_dm_rs_cback(UNUSED_ATTR tBTM_ROLE_SWITCH_CMPL* p1) {
+static void bta_dm_rs_cback(UNUSED_ATTR void* p1) {
   APPL_TRACE_WARNING("bta_dm_rs_cback:%d", bta_dm_cb.rs_event);
   if (bta_dm_cb.rs_event == BTA_DM_API_SEARCH_EVT) {
     bta_dm_cb.search_msg.rs_res =
@@ -2885,18 +2904,18 @@
       APPL_TRACE_WARNING("[%d]: state:%d, info:x%x, avoid_rs %d", i,
                          p_dev->conn_state, p_dev->info, avoid_roleswitch);
       if ((p_dev->conn_state == BTA_DM_CONNECTED) &&
-          (p_dev->info & BTA_DM_DI_AV_ACTIVE) && (avoid_roleswitch == false)) {
+          (p_dev->info & BTA_DM_DI_AV_ACTIVE) && (!avoid_roleswitch)) {
         /* make master and take away the role switch policy */
         if (BTM_CMD_STARTED == BTM_SwitchRole(p_dev->peer_bdaddr,
                                               HCI_ROLE_MASTER,
-                                              (tBTM_CMPL_CB*)bta_dm_rs_cback)) {
+                                              bta_dm_rs_cback)) {
           /* the role switch command is actually sent */
           bta_dm_cb.rs_event = event;
           switching = true;
         }
         /* else either already master or can not switch for some reasons */
         bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH,
-                            &p_dev->peer_bdaddr);
+                            p_dev->peer_bdaddr);
         break;
       }
     }
@@ -2906,216 +2925,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_dm_acl_change
- *
- * Description      Process BTA_DM_ACL_CHANGE_EVT
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_acl_change(tBTA_DM_MSG* p_data) {
-  uint8_t i;
-  uint8_t* p;
-  tBTA_DM_SEC conn;
-  bool is_new = p_data->acl_change.is_new;
-  const RawAddress& p_bda = p_data->acl_change.bd_addr;
-  bool need_policy_change = false;
-  bool issue_unpair_cb = false;
-
-  tBTA_DM_PEER_DEVICE* p_dev;
-  memset(&conn, 0, sizeof(tBTA_DM_SEC));
-
-  switch (p_data->acl_change.event) {
-    case BTM_BL_UPDATE_EVT: /* busy level update */
-      if (bta_dm_cb.p_sec_cback) {
-        conn.busy_level.level = p_data->acl_change.busy_level;
-        conn.busy_level.level_flags = p_data->acl_change.busy_level_flags;
-        bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);
-      }
-      return;
-
-    case BTM_BL_ROLE_CHG_EVT: /* role change event */
-      p_dev = bta_dm_find_peer_device(p_bda);
-      if (p_dev) {
-        APPL_TRACE_DEBUG(
-            "bta_dm_acl_change role chg info:x%x new_role:%d dev count:%d",
-            p_dev->info, p_data->acl_change.new_role,
-            bta_dm_cb.device_list.count);
-        if (p_dev->info & BTA_DM_DI_AV_ACTIVE) {
-          /* there's AV activity on this link */
-          if (p_data->acl_change.new_role == HCI_ROLE_SLAVE &&
-              bta_dm_cb.device_list.count > 1 &&
-              p_data->acl_change.hci_status == HCI_SUCCESS) {
-            /* more than one connections and the AV connection is role switched
-             * to slave
-             * switch it back to master and remove the switch policy */
-            BTM_SwitchRole(p_bda, BTM_ROLE_MASTER, NULL);
-            need_policy_change = true;
-          } else if (p_bta_dm_cfg->avoid_scatter &&
-                     (p_data->acl_change.new_role == HCI_ROLE_MASTER)) {
-            /* if the link updated to be master include AV activities, remove
-             * the switch policy */
-            need_policy_change = true;
-          }
-
-          if (need_policy_change) {
-            bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0,
-                                HCI_ENABLE_MASTER_SLAVE_SWITCH,
-                                &p_dev->peer_bdaddr);
-          }
-        } else {
-          /* there's AV no activity on this link and role switch happened
-           * check if AV is active
-           * if so, make sure the AV link is master */
-          bta_dm_check_av(0);
-        }
-        bta_sys_notify_role_chg(p_data->acl_change.bd_addr,
-                                p_data->acl_change.new_role,
-                                p_data->acl_change.hci_status);
-        conn.role_chg.bd_addr = p_bda;
-        conn.role_chg.new_role = (uint8_t)p_data->acl_change.new_role;
-        if (bta_dm_cb.p_sec_cback)
-          bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, (tBTA_DM_SEC*)&conn);
-      }
-      return;
-  }
-
-  /* Collision report from Stack: Notify profiles */
-  if (p_data->acl_change.event == BTM_BL_COLLISION_EVT) {
-    bta_sys_notify_collision(p_bda);
-    return;
-  }
-
-  if (is_new) {
-    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
-      if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == p_bda &&
-          bta_dm_cb.device_list.peer_device[i].conn_handle ==
-              p_data->acl_change.handle)
-        break;
-    }
-
-    if (i == bta_dm_cb.device_list.count) {
-      if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) {
-        bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
-            .peer_bdaddr = p_bda;
-        bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
-            .link_policy = bta_dm_cb.cur_policy;
-        bta_dm_cb.device_list.count++;
-        bta_dm_cb.device_list.peer_device[i].conn_handle =
-            p_data->acl_change.handle;
-        if (p_data->acl_change.transport == BT_TRANSPORT_LE)
-          bta_dm_cb.device_list.le_count++;
-      } else {
-        APPL_TRACE_ERROR("%s max active connection reached, no resources",
-                         __func__);
-        return;
-      }
-    }
-
-    bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED;
-    bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE;
-    conn.link_up.bd_addr = p_bda;
-    bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE;
-    conn.link_up.link_type = p_data->acl_change.transport;
-    bta_dm_cb.device_list.peer_device[i].transport =
-        p_data->acl_change.transport;
-
-    if (((NULL != (p = BTM_ReadLocalFeatures())) &&
-         HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
-        ((NULL != (p = BTM_ReadRemoteFeatures(p_bda))) &&
-         HCI_SNIFF_SUB_RATE_SUPPORTED(p))) {
-      /* both local and remote devices support SSR */
-      bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR;
-    }
-    APPL_TRACE_WARNING("%s info: 0x%x", __func__,
-                       bta_dm_cb.device_list.peer_device[i].info);
-
-    if (bta_dm_cb.p_sec_cback)
-      bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC*)&conn);
-  } else {
-    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
-      if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr != p_bda ||
-          bta_dm_cb.device_list.peer_device[i].transport !=
-              p_data->acl_change.transport)
-        continue;
-
-      if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING) {
-        if (BTM_SecDeleteDevice(
-                bta_dm_cb.device_list.peer_device[i].peer_bdaddr))
-          issue_unpair_cb = true;
-
-        APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ", __func__,
-                         issue_unpair_cb);
-      }
-
-      conn.link_down.is_removed =
-          bta_dm_cb.device_list.peer_device[i].remove_dev_pending;
-
-      // Iterate to the one before the last when shrinking the list,
-      // otherwise we memcpy garbage data into the record.
-      // Then clear out the last item in the list since we are shrinking.
-      for (; i < bta_dm_cb.device_list.count - 1; i++) {
-        memcpy(&bta_dm_cb.device_list.peer_device[i],
-               &bta_dm_cb.device_list.peer_device[i + 1],
-               sizeof(bta_dm_cb.device_list.peer_device[i]));
-      }
-      if (bta_dm_cb.device_list.count > 0) {
-        int clear_index = bta_dm_cb.device_list.count - 1;
-        memset(&bta_dm_cb.device_list.peer_device[clear_index], 0,
-               sizeof(bta_dm_cb.device_list.peer_device[clear_index]));
-      }
-      break;
-    }
-    if (bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--;
-    if ((p_data->acl_change.transport == BT_TRANSPORT_LE) &&
-        (bta_dm_cb.device_list.le_count))
-      bta_dm_cb.device_list.le_count--;
-    conn.link_down.link_type = p_data->acl_change.transport;
-
-    if (bta_dm_search_cb.wait_disc && bta_dm_search_cb.peer_bdaddr == p_bda) {
-      bta_dm_search_cb.wait_disc = false;
-
-      if (bta_dm_search_cb.sdp_results) {
-        APPL_TRACE_EVENT(" timer stopped  ");
-        alarm_cancel(bta_dm_search_cb.search_timer);
-        bta_dm_discover_next_device();
-      }
-    }
-
-    if (bta_dm_cb.disabling) {
-      if (!BTM_GetNumAclLinks()) {
-        /*
-         * Start a timer to make sure that the profiles
-         * get the disconnect event.
-         */
-        alarm_set_on_mloop(bta_dm_cb.disable_timer,
-                           BTA_DM_DISABLE_CONN_DOWN_TIMER_MS,
-                           bta_dm_disable_conn_down_timer_cback, NULL);
-      }
-    }
-    if (conn.link_down.is_removed) {
-      BTM_SecDeleteDevice(p_bda);
-      /* need to remove all pending background connection */
-      BTA_GATTC_CancelOpen(0, p_bda, false);
-      /* remove all cached GATT information */
-      BTA_GATTC_Refresh(p_bda);
-    }
-
-    conn.link_down.bd_addr = p_bda;
-    conn.link_down.status = (uint8_t)btm_get_acl_disc_reason_code();
-    if (bta_dm_cb.p_sec_cback) {
-      bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn);
-      if (issue_unpair_cb)
-        bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn);
-    }
-  }
-
-  bta_dm_adjust_roles(true);
-}
-
-/*******************************************************************************
- *
  * Function         bta_dm_disable_conn_down_timer_cback
  *
  * Description      Sends disable event to application
@@ -3153,12 +2962,12 @@
  *
  ******************************************************************************/
 static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                            uint8_t app_id, const RawAddress* peer_addr) {
+                            uint8_t app_id, const RawAddress& peer_addr) {
   uint8_t j;
   tBTA_PREF_ROLES role;
   tBTA_DM_PEER_DEVICE* p_dev;
 
-  p_dev = bta_dm_find_peer_device(*peer_addr);
+  p_dev = bta_dm_find_peer_device(peer_addr);
   if (status == BTA_SYS_CONN_OPEN) {
     if (p_dev) {
       /* Do not set to connected if we are in the middle of unpairing. When AV
@@ -3326,7 +3135,7 @@
 
           if (bta_dm_cb.device_list.peer_device[i].pref_role !=
                   BTA_SLAVE_ROLE_ONLY &&
-              delay_role_switch == false) {
+              !delay_role_switch) {
             BTM_SwitchRole(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
                            HCI_ROLE_MASTER, NULL);
           } else {
@@ -3477,16 +3286,16 @@
   if (local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len) {
 /* get number of UUID 16-bit list */
 #if (BTA_EIR_CANNED_UUID_LIST == TRUE)
-    num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+    num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16;
 #else   // BTA_EIR_CANNED_UUID_LIST
-    max_num_uuid = (free_eir_length - 2) / LEN_UUID_16;
+    max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16;
     data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
                                             max_num_uuid, &num_uuid);
     p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */
 #endif  // BTA_EIR_CANNED_UUID_LIST
 
     /* if UUID doesn't fit remaing space, shorten local name */
-    if (local_name_len > (free_eir_length - 4 - num_uuid * LEN_UUID_16)) {
+    if (local_name_len > (free_eir_length - 4 - num_uuid * Uuid::kNumBytes16)) {
       local_name_len = find_utf8_char_boundary(
           local_name, p_bta_dm_eir_cfg->bta_dm_eir_min_name_len);
       APPL_TRACE_WARNING("%s local name is shortened (%d)", __func__,
@@ -3510,23 +3319,24 @@
   /* if UUID list is provided as static data in configuration */
   if ((p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0) &&
       (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) {
-    if (free_eir_length > LEN_UUID_16 + 2) {
+    if (free_eir_length > Uuid::kNumBytes16 + 2) {
       free_eir_length -= 2;
 
       if (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) {
-        num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+        num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16;
         data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
       } else /* not enough room for all UUIDs */
       {
         APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
-        num_uuid = free_eir_length / LEN_UUID_16;
+        num_uuid = free_eir_length / Uuid::kNumBytes16;
         data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
       }
-      UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1);
+      UINT8_TO_STREAM(p, num_uuid * Uuid::kNumBytes16 + 1);
       UINT8_TO_STREAM(p, data_type);
-      memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16);
-      p += num_uuid * LEN_UUID_16;
-      free_eir_length -= num_uuid * LEN_UUID_16;
+      memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16,
+             num_uuid * Uuid::kNumBytes16);
+      p += num_uuid * Uuid::kNumBytes16;
+      free_eir_length -= num_uuid * Uuid::kNumBytes16;
     }
   }
 #else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
@@ -3536,7 +3346,7 @@
     p_type = p++;
     num_uuid = 0;
 
-    max_num_uuid = (free_eir_length - 2) / LEN_UUID_16;
+    max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16;
     data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
                                             max_num_uuid, &num_uuid);
 
@@ -3548,10 +3358,10 @@
       for (custom_uuid_idx = 0;
            custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
            custom_uuid_idx++) {
-        if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) {
+        const Uuid& curr = bta_dm_cb.custom_uuid[custom_uuid_idx];
+        if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes16) {
           if (num_uuid < max_num_uuid) {
-            UINT16_TO_STREAM(p,
-                             bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16);
+            UINT16_TO_STREAM(p, curr.As16Bit());
             num_uuid++;
           } else {
             data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
@@ -3563,9 +3373,9 @@
     }
 #endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
 
-    UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1);
+    UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes16 + 1);
     UINT8_TO_STREAM(p_type, data_type);
-    free_eir_length -= num_uuid * LEN_UUID_16 + 2;
+    free_eir_length -= num_uuid * Uuid::kNumBytes16 + 2;
   }
 #endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
 
@@ -3577,13 +3387,14 @@
     num_uuid = 0;
     data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
 
-    max_num_uuid = (free_eir_length - 2) / LEN_UUID_32;
+    max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes32;
 
     for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
          custom_uuid_idx++) {
-      if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) {
+      const Uuid& curr = bta_dm_cb.custom_uuid[custom_uuid_idx];
+      if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes32) {
         if (num_uuid < max_num_uuid) {
-          UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32);
+          UINT32_TO_STREAM(p, curr.As32Bit());
           num_uuid++;
         } else {
           data_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
@@ -3593,9 +3404,9 @@
       }
     }
 
-    UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1);
+    UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes32 + 1);
     UINT8_TO_STREAM(p_type, data_type);
-    free_eir_length -= num_uuid * LEN_UUID_32 + 2;
+    free_eir_length -= num_uuid * Uuid::kNumBytes32 + 2;
   }
 
   /* Adding 128-bit UUID list */
@@ -3605,14 +3416,14 @@
     num_uuid = 0;
     data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
 
-    max_num_uuid = (free_eir_length - 2) / LEN_UUID_128;
+    max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes128;
 
     for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
          custom_uuid_idx++) {
-      if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) {
+      const Uuid& curr = bta_dm_cb.custom_uuid[custom_uuid_idx];
+      if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes128) {
         if (num_uuid < max_num_uuid) {
-          ARRAY16_TO_STREAM(p,
-                            bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128);
+          ARRAY16_TO_STREAM(p, curr.To128BitBE().data());
           num_uuid++;
         } else {
           data_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
@@ -3622,9 +3433,9 @@
       }
     }
 
-    UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1);
+    UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes128 + 1);
     UINT8_TO_STREAM(p_type, data_type);
-    free_eir_length -= num_uuid * LEN_UUID_128 + 2;
+    free_eir_length -= num_uuid * Uuid::kNumBytes128 + 2;
   }
 #endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE \
           )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
@@ -3767,54 +3578,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_dm_enable_test_mode
- *
- * Description      enable test mode
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_enable_test_mode(UNUSED_ATTR tBTA_DM_MSG* p_data) {
-  BTM_EnableTestMode();
-}
-
-/*******************************************************************************
- *
- * Function         bta_dm_disable_test_mode
- *
- * Description      disable test mode
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_disable_test_mode(UNUSED_ATTR tBTA_DM_MSG* p_data) {
-  BTM_DeviceReset(NULL);
-}
-
-/*******************************************************************************
- *
- * Function         bta_dm_execute_callback
- *
- * Description      Just execute a generic call back in the context of the
- *                  BTU/BTA tack
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_execute_callback(tBTA_DM_MSG* p_data) {
-  /* sanity check */
-  if (p_data->exec_cback.p_exec_cback == NULL) {
-    return;
-  }
-
-  p_data->exec_cback.p_exec_cback(p_data->exec_cback.p_param);
-}
-
-/*******************************************************************************
- *
  * Function         bta_dm_encrypt_cback
  *
  * Description      link encryption complete callback.
@@ -3864,44 +3627,32 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_set_encryption
- *
- * Description      This function to encrypt the link
- *
- * Returns          None
- *
- ******************************************************************************/
-void bta_dm_set_encryption(tBTA_DM_MSG* p_data) {
+/**This function to encrypt the link */
+void bta_dm_set_encryption(const RawAddress& bd_addr, tBTA_TRANSPORT transport,
+                           tBTA_DM_ENCRYPT_CBACK* p_callback,
+                           tBTA_DM_BLE_SEC_ACT sec_act) {
   uint8_t i;
 
   APPL_TRACE_DEBUG("bta_dm_set_encryption");  // todo
-  if (!p_data->set_encryption.p_callback) {
+  if (!p_callback) {
     APPL_TRACE_ERROR("bta_dm_set_encryption callback is not provided");
     return;
   }
   for (i = 0; i < bta_dm_cb.device_list.count; i++) {
-    if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr ==
-            p_data->set_encryption.bd_addr &&
+    if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == bd_addr &&
         bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED)
       break;
   }
   if (i < bta_dm_cb.device_list.count) {
     if (bta_dm_cb.device_list.peer_device[i].p_encrypt_cback) {
       APPL_TRACE_ERROR("earlier enc was not done for same device");
-      (*p_data->set_encryption.p_callback)(p_data->set_encryption.bd_addr,
-                                           p_data->set_encryption.transport,
-                                           BTA_BUSY);
+      (*p_callback)(bd_addr, transport, BTA_BUSY);
       return;
     }
 
-    if (BTM_SetEncryption(p_data->set_encryption.bd_addr,
-                          p_data->set_encryption.transport,
-                          bta_dm_encrypt_cback, NULL,
-                          p_data->set_encryption.sec_act) == BTM_CMD_STARTED) {
-      bta_dm_cb.device_list.peer_device[i].p_encrypt_cback =
-          p_data->set_encryption.p_callback;
+    if (BTM_SetEncryption(bd_addr, transport, bta_dm_encrypt_cback, NULL,
+                          sec_act) == BTM_CMD_STARTED) {
+      bta_dm_cb.device_list.peer_device[i].p_encrypt_cback = p_callback;
     }
   }
 }
@@ -4157,12 +3908,10 @@
  * Parameters:
  *
  ******************************************************************************/
-void bta_dm_add_blekey(tBTA_DM_MSG* p_data) {
-  if (!BTM_SecAddBleKey(p_data->add_ble_key.bd_addr,
-                        (tBTM_LE_KEY_VALUE*)&p_data->add_ble_key.blekey,
-                        p_data->add_ble_key.key_type)) {
-    LOG(ERROR) << "BTA_DM: Error adding BLE Key for device "
-               << p_data->add_ble_key.bd_addr;
+void bta_dm_add_blekey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE blekey,
+                       tBTA_LE_KEY_TYPE key_type) {
+  if (!BTM_SecAddBleKey(bd_addr, (tBTM_LE_KEY_VALUE*)&blekey, key_type)) {
+    LOG(ERROR) << "BTA_DM: Error adding BLE Key for device " << bd_addr;
   }
 }
 
@@ -4178,12 +3927,10 @@
  * Parameters:
  *
  ******************************************************************************/
-void bta_dm_add_ble_device(tBTA_DM_MSG* p_data) {
-  if (!BTM_SecAddBleDevice(p_data->add_ble_device.bd_addr, NULL,
-                           p_data->add_ble_device.dev_type,
-                           p_data->add_ble_device.addr_type)) {
-    LOG(ERROR) << "BTA_DM: Error adding BLE Device for device "
-               << p_data->add_ble_device.bd_addr;
+void bta_dm_add_ble_device(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
+                           tBT_DEVICE_TYPE dev_type) {
+  if (!BTM_SecAddBleDevice(bd_addr, NULL, dev_type, addr_type)) {
+    LOG(ERROR) << "BTA_DM: Error adding BLE Device for device " << bd_addr;
   }
 }
 
@@ -4199,152 +3946,76 @@
  * Parameters:
  *
  ******************************************************************************/
-void bta_dm_ble_passkey_reply(tBTA_DM_MSG* p_data) {
-  if (p_data->pin_reply.accept) {
-    BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_SUCCESS,
-                        p_data->ble_passkey_reply.passkey);
-  } else {
-    BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED,
-                        p_data->ble_passkey_reply.passkey);
-  }
+void bta_dm_ble_passkey_reply(const RawAddress& bd_addr, bool accept,
+                              uint32_t passkey) {
+  BTM_BlePasskeyReply(bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED,
+                      passkey);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_confirm_reply
- *
- * Description      This is response to SM numeric comparison request submitted
- *                  to application.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_confirm_reply(tBTA_DM_MSG* p_data) {
-  if (p_data->confirm.accept) {
-    BTM_BleConfirmReply(p_data->confirm.bd_addr, BTM_SUCCESS);
-  } else {
-    BTM_BleConfirmReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED);
-  }
+/** This is response to SM numeric comparison request submitted to application.
+ */
+void bta_dm_ble_confirm_reply(const RawAddress& bd_addr, bool accept) {
+  BTM_BleConfirmReply(bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_security_grant
- *
- * Description      This function grant SMP security request access.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_security_grant(tBTA_DM_MSG* p_data) {
-  BTM_SecurityGrant(p_data->ble_sec_grant.bd_addr, p_data->ble_sec_grant.res);
+/** This function set the preferred connection parameters */
+void bta_dm_ble_set_conn_params(const RawAddress& bd_addr,
+                                uint16_t conn_int_min, uint16_t conn_int_max,
+                                uint16_t slave_latency,
+                                uint16_t supervision_tout) {
+  L2CA_AdjustConnectionIntervals(&conn_int_min, &conn_int_max,
+                                 BTM_BLE_CONN_INT_MIN);
+
+  BTM_BleSetPrefConnParams(bd_addr, conn_int_min, conn_int_max, slave_latency,
+                           supervision_tout);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_set_bg_conn_type
- *
- * Description      This function set the BLE background connection type
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_set_bg_conn_type(tBTA_DM_MSG* p_data) {
-  BTM_BleStartAutoConn();
+/** This function set the preferred connection scan parameters */
+void bta_dm_ble_set_conn_scan_params(uint32_t scan_interval,
+                                     uint32_t scan_window) {
+  BTM_BleSetConnScanParams(scan_interval, scan_window);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_set_conn_params
- *
- * Description      This function set the preferred connection parameters.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_set_conn_params(tBTA_DM_MSG* p_data) {
-  BTM_BleSetPrefConnParams(p_data->ble_set_conn_params.peer_bda,
-                           p_data->ble_set_conn_params.conn_int_min,
-                           p_data->ble_set_conn_params.conn_int_max,
-                           p_data->ble_set_conn_params.slave_latency,
-                           p_data->ble_set_conn_params.supervision_tout);
-}
+/** This function update LE connection parameters */
+void bta_dm_ble_update_conn_params(const RawAddress& bd_addr, uint16_t min_int,
+                                   uint16_t max_int, uint16_t latency,
+                                   uint16_t timeout, uint16_t min_ce_len,
+                                   uint16_t max_ce_len) {
+  L2CA_AdjustConnectionIntervals(&min_int, &max_int, BTM_BLE_CONN_INT_MIN);
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_set_conn_scan_params
- *
- * Description      This function set the preferred connection scan parameters.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_set_conn_scan_params(tBTA_DM_MSG* p_data) {
-  BTM_BleSetConnScanParams(p_data->ble_set_conn_scan_params.scan_int,
-                           p_data->ble_set_conn_scan_params.scan_window);
-}
-/*******************************************************************************
- *
- * Function         bta_dm_ble_update_conn_params
- *
- * Description      This function update LE connection parameters.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_update_conn_params(tBTA_DM_MSG* p_data) {
-  if (!L2CA_UpdateBleConnParams(p_data->ble_update_conn_params.bd_addr,
-                                p_data->ble_update_conn_params.min_int,
-                                p_data->ble_update_conn_params.max_int,
-                                p_data->ble_update_conn_params.latency,
-                                p_data->ble_update_conn_params.timeout)) {
+  if (!L2CA_UpdateBleConnParams(bd_addr, min_int, max_int, latency, timeout,
+                                min_ce_len, max_ce_len)) {
     APPL_TRACE_ERROR("Update connection parameters failed!");
   }
 }
 
 #if (BLE_PRIVACY_SPT == TRUE)
-/*******************************************************************************
- *
- * Function         bta_dm_ble_config_local_privacy
- *
- * Description      This function set the local device LE privacy settings.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_config_local_privacy(tBTA_DM_MSG* p_data) {
-  BTM_BleConfigPrivacy(p_data->ble_local_privacy.privacy_enable);
+/** This function set the local device LE privacy settings. */
+void bta_dm_ble_config_local_privacy(bool privacy_enable) {
+  BTM_BleConfigPrivacy(privacy_enable);
 }
 #endif
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_observe
- *
- * Description      This function set the preferred connection scan parameters.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_observe(tBTA_DM_MSG* p_data) {
-  tBTM_STATUS status;
-  if (p_data->ble_observe.start) {
-    /*Save the  callback to be called when a scan results are available */
-    bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback;
-    status = BTM_BleObserve(true, p_data->ble_observe.duration,
-                            bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb);
-    if (status != BTM_CMD_STARTED) {
-      tBTA_DM_SEARCH data;
-      APPL_TRACE_WARNING(" %s BTM_BleObserve  failed. status %d", __func__,
-                         status);
-      data.inq_cmpl.num_resps = 0;
-      if (bta_dm_search_cb.p_scan_cback) {
-        bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
-      }
-    }
-  } else {
+void bta_dm_ble_observe(bool start, uint8_t duration,
+                        tBTA_DM_SEARCH_CBACK* p_cback) {
+  if (!start) {
     bta_dm_search_cb.p_scan_cback = NULL;
     BTM_BleObserve(false, 0, NULL, NULL);
+    return;
+  }
+
+  /*Save the  callback to be called when a scan results are available */
+  bta_dm_search_cb.p_scan_cback = p_cback;
+  tBTM_STATUS status = BTM_BleObserve(true, duration, bta_dm_observe_results_cb,
+                                      bta_dm_observe_cmpl_cb);
+  if (status != BTM_CMD_STARTED) {
+    tBTA_DM_SEARCH data;
+    APPL_TRACE_WARNING(" %s BTM_BleObserve  failed. status %d", __func__,
+                       status);
+    data.inq_cmpl.num_resps = 0;
+    if (bta_dm_search_cb.p_scan_cback) {
+      bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
+    }
   }
 }
 /*******************************************************************************
@@ -4362,19 +4033,10 @@
                       BTA_DM_BLE_ADV_CHNL_MAP);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_set_data_length
- *
- * Description      This function set the maximum transmission packet size
- *
- * Parameters
- *
- ******************************************************************************/
-void bta_dm_ble_set_data_length(tBTA_DM_MSG* p_data) {
-  if (BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda,
-                           p_data->ble_set_data_length.tx_data_length) !=
-      BTM_SUCCESS) {
+/** This function set the maximum transmission packet size */
+void bta_dm_ble_set_data_length(const RawAddress& bd_addr,
+                                uint16_t tx_data_length) {
+  if (BTM_SetBleDataLength(bd_addr, tx_data_length) != BTM_SUCCESS) {
     APPL_TRACE_ERROR("%s failed", __func__);
   }
 }
@@ -4404,20 +4066,11 @@
                                   ctrl_state, st);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_ble_get_energy_info
- *
- * Description      This function obtains the energy info
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_get_energy_info(tBTA_DM_MSG* p_data) {
-  tBTM_STATUS btm_status = 0;
-
-  bta_dm_cb.p_energy_info_cback = p_data->ble_energy_info.p_energy_info_cback;
-  btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl);
+/** This function obtains the energy info */
+void bta_dm_ble_get_energy_info(
+    tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback) {
+  bta_dm_cb.p_energy_info_cback = p_energy_info_cback;
+  tBTM_STATUS btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl);
   if (BTM_CMD_STARTED != btm_status)
     bta_ble_energy_info_cmpl(0, 0, 0, 0, btm_status);
 }
@@ -4440,7 +4093,7 @@
   if (bta_dm_search_cb.client_if == BTA_GATTS_INVALID_IF) {
     BTA_GATTC_AppRegister(bta_dm_gattc_callback,
                           base::Bind([](uint8_t client_id, uint8_t status) {
-                            if (status == BTA_GATT_OK)
+                            if (status == GATT_SUCCESS)
                               bta_dm_search_cb.client_if = client_id;
                             else
                               bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
@@ -4459,11 +4112,8 @@
  *
  ******************************************************************************/
 static void btm_dm_start_disc_gatt_services(uint16_t conn_id) {
-  tBT_UUID* p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
-                     bta_dm_search_cb.uuid_to_search;
-
-  p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
-           bta_dm_search_cb.uuid_to_search;
+  Uuid* p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
+                 bta_dm_search_cb.uuid_to_search;
 
   /* always search for all services */
   BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid);
@@ -4490,11 +4140,14 @@
   if (bta_dm_search_cb.ble_raw_used + sizeof(tBTA_GATT_ID) <
       bta_dm_search_cb.ble_raw_size) {
     APPL_TRACE_DEBUG(
-        "ADDING BLE SERVICE uuid=0x%x, ble_ptr = 0x%x, ble_raw_used = 0x%x",
-        service_id.uuid.uu.uuid16, bta_dm_search_cb.p_ble_rawdata,
+        "ADDING BLE SERVICE uuid=%s, ble_ptr = 0x%x, ble_raw_used = 0x%x",
+        service_id.uuid.ToString().c_str(), bta_dm_search_cb.p_ble_rawdata,
         bta_dm_search_cb.ble_raw_used);
 
     if (bta_dm_search_cb.p_ble_rawdata) {
+      // TODO(jpawlowski): the p_ble_raw data is only sent to btif_dm.cc, but is
+      // never used there. Get rid of this code completly, or implement the
+      // TODOs from btif_dm.cc
       memcpy((bta_dm_search_cb.p_ble_rawdata + bta_dm_search_cb.ble_raw_used),
              &service_id, sizeof(service_id));
 
@@ -4510,14 +4163,14 @@
         __func__, bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used);
   }
 
-  LOG_INFO(LOG_TAG, "%s service_id_uuid_len=%d ", __func__,
-           service_id.uuid.len);
+  LOG_INFO(LOG_TAG, "%s service_id_uuid_len=%zu", __func__,
+           service_id.uuid.GetShortestRepresentationSize());
   if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) {
     /* send result back to app now, one by one */
     result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
     strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
             BD_NAME_LEN);
-    memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID));
+    result.disc_ble_res.service = service_id.uuid;
 
     bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
   }
@@ -4532,13 +4185,12 @@
  * Parameters:
  *
  ******************************************************************************/
-static void bta_dm_gatt_disc_complete(uint16_t conn_id,
-                                      tBTA_GATT_STATUS status) {
+static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) {
   APPL_TRACE_DEBUG("%s conn_id = %d", __func__, conn_id);
 
   if (bta_dm_search_cb.uuid_to_search > 0) bta_dm_search_cb.uuid_to_search--;
 
-  if (status == BTA_GATT_OK && bta_dm_search_cb.uuid_to_search > 0) {
+  if (status == GATT_SUCCESS && bta_dm_search_cb.uuid_to_search > 0) {
     btm_dm_start_disc_gatt_services(conn_id);
   } else {
     tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
@@ -4548,7 +4200,7 @@
     /* no more services to be discovered */
     p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
     p_msg->disc_result.result.disc_res.result =
-        (status == BTA_GATT_OK) ? BTA_SUCCESS : BTA_FAILURE;
+        (status == GATT_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
     APPL_TRACE_DEBUG("%s service found: 0x%08x", __func__,
                      bta_dm_search_cb.services_found);
     p_msg->disc_result.result.disc_res.services =
@@ -4576,7 +4228,7 @@
 
     bta_sys_sendmsg(p_msg);
 
-    if (conn_id != BTA_GATT_INVALID_CONN_ID) {
+    if (conn_id != GATT_INVALID_CONN_ID) {
       /* start a GATT channel close delay timer */
       bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer,
                           BTA_DM_GATT_CLOSE_DELAY_TOUT,
@@ -4598,11 +4250,11 @@
  *
  ******************************************************************************/
 void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data) {
-  if (bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID)
+  if (bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID)
     BTA_GATTC_Close(bta_dm_search_cb.conn_id);
 
   bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty;
-  bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+  bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID;
 }
 /*******************************************************************************
  *
@@ -4619,17 +4271,17 @@
 
   /* connection is already open */
   if (bta_dm_search_cb.pending_close_bda == bd_addr &&
-      bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID) {
+      bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID) {
     bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty;
     alarm_cancel(bta_dm_search_cb.gatt_close_timer);
     btm_dm_start_disc_gatt_services(bta_dm_search_cb.conn_id);
   } else {
     if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
       BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, true,
-                     BTA_GATT_TRANSPORT_LE, true);
+                     GATT_TRANSPORT_LE, true);
     } else {
       BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, true,
-                     BTA_GATT_TRANSPORT_LE, false);
+                     GATT_TRANSPORT_LE, false);
     }
   }
 }
@@ -4644,12 +4296,11 @@
  *
  ******************************************************************************/
 static void bta_dm_cancel_gatt_discovery(const RawAddress& bd_addr) {
-  if (bta_dm_search_cb.conn_id == BTA_GATT_INVALID_CONN_ID) {
+  if (bta_dm_search_cb.conn_id == GATT_INVALID_CONN_ID) {
     BTA_GATTC_CancelOpen(bta_dm_search_cb.client_if, bd_addr, true);
   }
 
-  bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id,
-                            (tBTA_GATT_STATUS)BTA_GATT_ERROR);
+  bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id, (tGATT_STATUS)GATT_ERROR);
 }
 
 /*******************************************************************************
@@ -4671,10 +4322,10 @@
 
   bta_dm_search_cb.conn_id = p_data->conn_id;
 
-  if (p_data->status == BTA_GATT_OK) {
+  if (p_data->status == GATT_SUCCESS) {
     btm_dm_start_disc_gatt_services(p_data->conn_id);
   } else {
-    bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status);
+    bta_dm_gatt_disc_complete(GATT_INVALID_CONN_ID, p_data->status);
   }
 }
 
@@ -4711,8 +4362,8 @@
       if ((bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) &&
           (bta_dm_search_cb.state != BTA_DM_SEARCH_ACTIVE) &&
           p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) {
-        bta_dm_gatt_disc_complete((uint16_t)BTA_GATT_INVALID_CONN_ID,
-                                  (tBTA_GATT_STATUS)BTA_GATT_ERROR);
+        bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID,
+                                  (tGATT_STATUS)GATT_ERROR);
       }
       break;
 
diff --git a/bta/dm/bta_dm_api.cc b/bta/dm/bta_dm_api.cc
index c06de60..e968bd1 100644
--- a/bta/dm/bta_dm_api.cc
+++ b/bta/dm/bta_dm_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2014 Broadcom Corporation
+ *  Copyright 2003-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,12 +35,12 @@
 #include "osi/include/osi.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
 
-static const tBTA_SYS_REG bta_dm_reg = {bta_dm_sm_execute, bta_dm_sm_disable};
-
 static const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute,
                                                bta_dm_search_sm_disable};
 
@@ -59,19 +59,12 @@
   /* Bluetooth disabling is in progress */
   if (bta_dm_cb.disabling) return BTA_FAILURE;
 
-  bta_sys_register(BTA_ID_DM, &bta_dm_reg);
   bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg);
 
   /* if UUID list is not provided as static data */
   bta_sys_eir_register(bta_dm_eir_update_uuid);
 
-  tBTA_DM_API_ENABLE* p_msg =
-      (tBTA_DM_API_ENABLE*)osi_malloc(sizeof(tBTA_DM_API_ENABLE));
-  p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
-  p_msg->p_sec_cback = p_cback;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_enable, p_cback));
   return BTA_SUCCESS;
 }
 
@@ -86,99 +79,37 @@
  *
  ******************************************************************************/
 tBTA_STATUS BTA_DisableBluetooth(void) {
-  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_msg->event = BTA_DM_API_DISABLE_EVT;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_disable));
   return BTA_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         BTA_EnableTestMode
- *
- * Description      Enables bluetooth device under test mode
- *
- *
- * Returns          tBTA_STATUS
- *
- ******************************************************************************/
-tBTA_STATUS BTA_EnableTestMode(void) {
-  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->event = BTA_DM_API_ENABLE_TEST_MODE_EVT;
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_SUCCESS;
+/** Enables bluetooth device under test mode */
+void BTA_EnableTestMode(void) {
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(base::IgnoreResult(BTM_EnableTestMode)));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DisableTestMode
- *
- * Description      Disable bluetooth device under test mode
- *
- *
- * Returns          None
- *
- ******************************************************************************/
+/** Disable bluetooth device under test mode */
 void BTA_DisableTestMode(void) {
-  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->event = BTA_DM_API_DISABLE_TEST_MODE_EVT;
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(BTM_DeviceReset, nullptr));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmSetDeviceName
- *
- * Description      This function sets the Bluetooth name of local device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** This function sets the Bluetooth name of local device */
 void BTA_DmSetDeviceName(char* p_name) {
-  tBTA_DM_API_SET_NAME* p_msg =
-      (tBTA_DM_API_SET_NAME*)osi_malloc(sizeof(tBTA_DM_API_SET_NAME));
+  std::vector<uint8_t> name(BD_NAME_LEN);
+  strlcpy((char*)name.data(), p_name, BD_NAME_LEN);
 
-  p_msg->hdr.event = BTA_DM_API_SET_NAME_EVT;
-  strlcpy((char*)p_msg->name, p_name, BD_NAME_LEN);
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_set_dev_name, name));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmSetVisibility
- *
- * Description      This function sets the Bluetooth connectable,
- *                  discoverable, pairable and conn paired only modes of local
- *                  device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** This function sets the Bluetooth connectable, discoverable, pairable and
+ * conn paired only modes of local device
+ */
 void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode,
-                         uint8_t pairable_mode, uint8_t conn_filter) {
-  tBTA_DM_API_SET_VISIBILITY* p_msg =
-      (tBTA_DM_API_SET_VISIBILITY*)osi_malloc(sizeof(tBTA_DM_MSG));
-
-  p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT;
-  p_msg->disc_mode = disc_mode;
-  p_msg->conn_mode = conn_mode;
-  p_msg->pair_mode = pairable_mode;
-  p_msg->conn_paired_only = conn_filter;
-
-  bta_sys_sendmsg(p_msg);
+                         uint8_t pairable_mode, uint8_t conn_paired_only) {
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_set_visibility, disc_mode, conn_mode,
+                              pairable_mode, conn_paired_only));
 }
 
 /*******************************************************************************
@@ -260,7 +191,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_DmDiscoverUUID(const RawAddress& bd_addr, tSDP_UUID* uuid,
+void BTA_DmDiscoverUUID(const RawAddress& bd_addr, const Uuid& uuid,
                         tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
   tBTA_DM_API_DISCOVER* p_msg =
       (tBTA_DM_API_DISCOVER*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER));
@@ -273,76 +204,27 @@
 
   p_msg->num_uuid = 0;
   p_msg->p_uuid = NULL;
-
-  memcpy(&p_msg->uuid, uuid, sizeof(tSDP_UUID));
+  p_msg->uuid = uuid;
 
   bta_sys_sendmsg(p_msg);
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmBond
- *
- * Description      This function initiates a bonding procedure with a peer
- *                  device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** This function initiates a bonding procedure with a peer device */
 void BTA_DmBond(const RawAddress& bd_addr) {
-  tBTA_DM_API_BOND* p_msg =
-      (tBTA_DM_API_BOND*)osi_malloc(sizeof(tBTA_DM_API_BOND));
-
-  p_msg->hdr.event = BTA_DM_API_BOND_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->transport = BTA_TRANSPORT_UNKNOWN;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_bond, bd_addr, BTA_TRANSPORT_UNKNOWN));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmBondByTransports
- *
- * Description      This function initiates a bonding procedure with a peer
- *                  device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** This function initiates a bonding procedure with a peer device */
 void BTA_DmBondByTransport(const RawAddress& bd_addr,
                            tBTA_TRANSPORT transport) {
-  tBTA_DM_API_BOND* p_msg =
-      (tBTA_DM_API_BOND*)osi_malloc(sizeof(tBTA_DM_API_BOND));
-
-  p_msg->hdr.event = BTA_DM_API_BOND_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->transport = transport;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, transport));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmBondCancel
- *
- * Description      This function cancels the bonding procedure with a peer
- *                  device
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** This function cancels the bonding procedure with a peer device
+ */
 void BTA_DmBondCancel(const RawAddress& bd_addr) {
-  tBTA_DM_API_BOND_CANCEL* p_msg =
-      (tBTA_DM_API_BOND_CANCEL*)osi_malloc(sizeof(tBTA_DM_API_BOND_CANCEL));
-
-  p_msg->hdr.event = BTA_DM_API_BOND_CANCEL_EVT;
-  p_msg->bd_addr = bd_addr;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_bond_cancel, bd_addr));
 }
 
 /*******************************************************************************
@@ -357,21 +239,18 @@
  *
  ******************************************************************************/
 void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len,
-                    uint8_t* p_pin)
+                    uint8_t* p_pin) {
+  std::unique_ptr<tBTA_DM_API_PIN_REPLY> msg =
+      std::make_unique<tBTA_DM_API_PIN_REPLY>();
 
-{
-  tBTA_DM_API_PIN_REPLY* p_msg =
-      (tBTA_DM_API_PIN_REPLY*)osi_malloc(sizeof(tBTA_DM_API_PIN_REPLY));
-
-  p_msg->hdr.event = BTA_DM_API_PIN_REPLY_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->accept = accept;
+  msg->bd_addr = bd_addr;
+  msg->accept = accept;
   if (accept) {
-    p_msg->pin_len = pin_len;
-    memcpy(p_msg->p_pin, p_pin, pin_len);
+    msg->pin_len = pin_len;
+    memcpy(msg->p_pin, p_pin, pin_len);
   }
 
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_pin_reply, base::Passed(&msg)));
 }
 
 /*******************************************************************************
@@ -388,11 +267,7 @@
  *
  ******************************************************************************/
 void BTA_DmLocalOob(void) {
-  tBTA_DM_API_LOC_OOB* p_msg =
-      (tBTA_DM_API_LOC_OOB*)osi_malloc(sizeof(tBTA_DM_API_LOC_OOB));
-
-  p_msg->hdr.event = BTA_DM_API_LOC_OOB_EVT;
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(BTM_ReadLocalOobData));
 }
 
 /*******************************************************************************
@@ -406,14 +281,7 @@
  *
  ******************************************************************************/
 void BTA_DmConfirm(const RawAddress& bd_addr, bool accept) {
-  tBTA_DM_API_CONFIRM* p_msg =
-      (tBTA_DM_API_CONFIRM*)osi_malloc(sizeof(tBTA_DM_API_CONFIRM));
-
-  p_msg->hdr.event = BTA_DM_API_CONFIRM_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->accept = accept;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_confirm, bd_addr, accept));
 }
 
 /*******************************************************************************
@@ -431,55 +299,38 @@
                      LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
                      bool is_trusted, uint8_t key_type, tBTA_IO_CAP io_cap,
                      uint8_t pin_length) {
-  tBTA_DM_API_ADD_DEVICE* p_msg =
-      (tBTA_DM_API_ADD_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_ADD_DEVICE));
+  std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg =
+      std::make_unique<tBTA_DM_API_ADD_DEVICE>();
 
-  p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->tm = trusted_mask;
-  p_msg->is_trusted = is_trusted;
-  p_msg->io_cap = io_cap;
+  msg->bd_addr = bd_addr;
+  msg->tm = trusted_mask;
+  msg->is_trusted = is_trusted;
+  msg->io_cap = io_cap;
 
   if (link_key) {
-    p_msg->link_key_known = true;
-    p_msg->key_type = key_type;
-    memcpy(p_msg->link_key, link_key, LINK_KEY_LEN);
+    msg->link_key_known = true;
+    msg->key_type = key_type;
+    memcpy(msg->link_key, link_key, LINK_KEY_LEN);
   }
 
   /* Load device class if specified */
   if (dev_class) {
-    p_msg->dc_known = true;
-    memcpy(p_msg->dc, dev_class, DEV_CLASS_LEN);
+    msg->dc_known = true;
+    memcpy(msg->dc, dev_class, DEV_CLASS_LEN);
   }
 
-  memset(p_msg->bd_name, 0, BD_NAME_LEN + 1);
-  memset(p_msg->features, 0, sizeof(p_msg->features));
-  p_msg->pin_length = pin_length;
+  memset(msg->bd_name, 0, BD_NAME_LEN + 1);
+  memset(msg->features, 0, sizeof(msg->features));
+  msg->pin_length = pin_length;
 
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_add_device, base::Passed(&msg)));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmRemoveDevice
- *
- * Description      This function removes a device fromthe security database
- *                  list of peer device. It manages unpairing even while
- *                  connected.
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** This function removes a device fromthe security database list of peer
+ * device. It manages unpairing even while connected */
 tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) {
-  tBTA_DM_API_REMOVE_DEVICE* p_msg =
-      (tBTA_DM_API_REMOVE_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_DEVICE));
-
-  p_msg->hdr.event = BTA_DM_API_REMOVE_DEVICE_EVT;
-  p_msg->bd_addr = bd_addr;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_remove_device, bd_addr));
   return BTA_SUCCESS;
 }
 
@@ -500,11 +351,11 @@
                        tBTA_SERVICE_MASK* p_services) {
   uint8_t xx, yy;
   uint8_t num_uuid, max_num_uuid = 32;
-  uint8_t uuid_list[32 * LEN_UUID_16];
+  uint8_t uuid_list[32 * Uuid::kNumBytes16];
   uint16_t* p_uuid16 = (uint16_t*)uuid_list;
   tBTA_SERVICE_MASK mask;
 
-  BTM_GetEirUuidList(p_eir, eir_len, LEN_UUID_16, &num_uuid, uuid_list,
+  BTM_GetEirUuidList(p_eir, eir_len, Uuid::kNumBytes16, &num_uuid, uuid_list,
                      max_num_uuid);
   for (xx = 0; xx < num_uuid; xx++) {
     mask = 1;
@@ -576,29 +427,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_dmexecutecallback
- *
- * Description      This function will request BTA to execute a call back in the
- *                  context of BTU task.
- *                  This API was named in lower case because it is only intended
- *                  for the internal customers(like BTIF).
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dmexecutecallback(tBTA_DM_EXEC_CBACK* p_callback, void* p_param) {
-  tBTA_DM_API_EXECUTE_CBACK* p_msg =
-      (tBTA_DM_API_EXECUTE_CBACK*)osi_malloc(sizeof(tBTA_DM_MSG));
-
-  p_msg->hdr.event = BTA_DM_API_EXECUTE_CBACK_EVT;
-  p_msg->p_param = p_param;
-  p_msg->p_exec_cback = p_callback;
-
-  bta_sys_sendmsg(p_msg);
-}
-
-/*******************************************************************************
- *
  * Function         BTA_DmAddBleKey
  *
  * Description      Add/modify LE device information.  This function will be
@@ -615,15 +443,8 @@
  ******************************************************************************/
 void BTA_DmAddBleKey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE* p_le_key,
                      tBTA_LE_KEY_TYPE key_type) {
-  tBTA_DM_API_ADD_BLEKEY* p_msg =
-      (tBTA_DM_API_ADD_BLEKEY*)osi_calloc(sizeof(tBTA_DM_API_ADD_BLEKEY));
-
-  p_msg->hdr.event = BTA_DM_API_ADD_BLEKEY_EVT;
-  p_msg->key_type = key_type;
-  p_msg->bd_addr = bd_addr;
-  memcpy(&p_msg->blekey, p_le_key, sizeof(tBTA_LE_KEY_VALUE));
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_add_blekey, bd_addr, *p_le_key, key_type));
 }
 
 /*******************************************************************************
@@ -643,15 +464,8 @@
  ******************************************************************************/
 void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
                         tBT_DEVICE_TYPE dev_type) {
-  tBTA_DM_API_ADD_BLE_DEVICE* p_msg = (tBTA_DM_API_ADD_BLE_DEVICE*)osi_calloc(
-      sizeof(tBTA_DM_API_ADD_BLE_DEVICE));
-
-  p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->addr_type = addr_type;
-  p_msg->dev_type = dev_type;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_add_ble_device, bd_addr,
+                                         addr_type, dev_type));
 }
 
 /*******************************************************************************
@@ -670,16 +484,8 @@
  ******************************************************************************/
 void BTA_DmBlePasskeyReply(const RawAddress& bd_addr, bool accept,
                            uint32_t passkey) {
-  tBTA_DM_API_PASSKEY_REPLY* p_msg =
-      (tBTA_DM_API_PASSKEY_REPLY*)osi_calloc(sizeof(tBTA_DM_API_PASSKEY_REPLY));
-
-  p_msg->hdr.event = BTA_DM_API_BLE_PASSKEY_REPLY_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->accept = accept;
-
-  if (accept) p_msg->passkey = passkey;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ble_passkey_reply, bd_addr,
+                                         accept, accept ? passkey : 0));
 }
 
 /*******************************************************************************
@@ -696,14 +502,8 @@
  *
  ******************************************************************************/
 void BTA_DmBleConfirmReply(const RawAddress& bd_addr, bool accept) {
-  tBTA_DM_API_CONFIRM* p_msg =
-      (tBTA_DM_API_CONFIRM*)osi_calloc(sizeof(tBTA_DM_API_CONFIRM));
-
-  p_msg->hdr.event = BTA_DM_API_BLE_CONFIRM_REPLY_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->accept = accept;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_ble_confirm_reply, bd_addr, accept));
 }
 
 /*******************************************************************************
@@ -720,14 +520,7 @@
  ******************************************************************************/
 void BTA_DmBleSecurityGrant(const RawAddress& bd_addr,
                             tBTA_DM_BLE_SEC_GRANT res) {
-  tBTA_DM_API_BLE_SEC_GRANT* p_msg =
-      (tBTA_DM_API_BLE_SEC_GRANT*)osi_calloc(sizeof(tBTA_DM_API_BLE_SEC_GRANT));
-
-  p_msg->hdr.event = BTA_DM_API_BLE_SEC_GRANT_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->res = res;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(BTM_SecurityGrant, bd_addr, res));
 }
 
 /*******************************************************************************
@@ -753,17 +546,9 @@
                                 uint16_t min_conn_int, uint16_t max_conn_int,
                                 uint16_t slave_latency,
                                 uint16_t supervision_tout) {
-  tBTA_DM_API_BLE_CONN_PARAMS* p_msg = (tBTA_DM_API_BLE_CONN_PARAMS*)osi_calloc(
-      sizeof(tBTA_DM_API_BLE_CONN_PARAMS));
-
-  p_msg->hdr.event = BTA_DM_API_BLE_CONN_PARAM_EVT;
-  p_msg->peer_bda = bd_addr;
-  p_msg->conn_int_max = max_conn_int;
-  p_msg->conn_int_min = min_conn_int;
-  p_msg->slave_latency = slave_latency;
-  p_msg->supervision_tout = supervision_tout;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_ble_set_conn_params, bd_addr, min_conn_int,
+                              max_conn_int, slave_latency, supervision_tout));
 }
 
 /*******************************************************************************
@@ -780,25 +565,13 @@
  *
  ******************************************************************************/
 void BTA_DmSetBleConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
-  tBTA_DM_API_BLE_SCAN_PARAMS* p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS*)osi_calloc(
-      sizeof(tBTA_DM_API_BLE_SCAN_PARAMS));
-
-  p_msg->hdr.event = BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT;
-  p_msg->scan_int = scan_interval;
-  p_msg->scan_window = scan_window;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ble_set_conn_scan_params,
+                                         scan_interval, scan_window));
 }
 
-/**
- * Set BLE connectable mode to auto connect
- */
+/** Set BLE connectable mode to auto connect */
 void BTA_DmBleStartAutoConn() {
-  tBTA_DM_API_SET_NAME* p_msg =
-      (tBTA_DM_API_SET_NAME*)osi_calloc(sizeof(tBTA_DM_API_SET_NAME));
-
-  p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE;
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(BTM_BleStartAutoConn));
 }
 
 /*******************************************************************************
@@ -815,9 +588,10 @@
                                      tBTA_DM_SEARCH_CBACK* p_cback,
                                      bool sdp_search,
                                      tBTA_TRANSPORT transport) {
-  const size_t len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) +
-                                   sizeof(tBT_UUID) * p_services->num_uuid)
-                                : sizeof(tBTA_DM_API_DISCOVER);
+  const size_t len =
+      p_services
+          ? (sizeof(tBTA_DM_API_DISCOVER) + sizeof(Uuid) * p_services->num_uuid)
+          : sizeof(tBTA_DM_API_DISCOVER);
   tBTA_DM_API_DISCOVER* p_msg = (tBTA_DM_API_DISCOVER*)osi_calloc(len);
 
   p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
@@ -830,9 +604,9 @@
     p_msg->services = p_services->srvc_mask;
     p_msg->num_uuid = p_services->num_uuid;
     if (p_services->num_uuid != 0) {
-      p_msg->p_uuid = (tBT_UUID*)(p_msg + 1);
+      p_msg->p_uuid = (Uuid*)(p_msg + 1);
       memcpy(p_msg->p_uuid, p_services->p_uuid,
-             sizeof(tBT_UUID) * p_services->num_uuid);
+             sizeof(Uuid) * p_services->num_uuid);
     }
   }
 
@@ -906,9 +680,10 @@
  ******************************************************************************/
 void BTA_DmSearchExt(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK_EXT* p_services,
                      tBTA_DM_SEARCH_CBACK* p_cback) {
-  const size_t len = p_services ? (sizeof(tBTA_DM_API_SEARCH) +
-                                   sizeof(tBT_UUID) * p_services->num_uuid)
-                                : sizeof(tBTA_DM_API_SEARCH);
+  const size_t len =
+      p_services
+          ? (sizeof(tBTA_DM_API_SEARCH) + sizeof(Uuid) * p_services->num_uuid)
+          : sizeof(tBTA_DM_API_SEARCH);
   tBTA_DM_API_SEARCH* p_msg = (tBTA_DM_API_SEARCH*)osi_calloc(len);
 
   p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
@@ -921,9 +696,9 @@
     p_msg->num_uuid = p_services->num_uuid;
 
     if (p_services->num_uuid != 0) {
-      p_msg->p_uuid = (tBT_UUID*)(p_msg + 1);
+      p_msg->p_uuid = (Uuid*)(p_msg + 1);
       memcpy(p_msg->p_uuid, p_services->p_uuid,
-             sizeof(tBT_UUID) * p_services->num_uuid);
+             sizeof(Uuid) * p_services->num_uuid);
     } else {
       p_msg->p_uuid = NULL;
     }
@@ -950,21 +725,13 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_DmBleUpdateConnectionParam(const RawAddress& bd_addr, uint16_t min_int,
-                                    uint16_t max_int, uint16_t latency,
-                                    uint16_t timeout) {
-  tBTA_DM_API_UPDATE_CONN_PARAM* p_msg =
-      (tBTA_DM_API_UPDATE_CONN_PARAM*)osi_calloc(
-          sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
-
-  p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->min_int = min_int;
-  p_msg->max_int = max_int;
-  p_msg->latency = latency;
-  p_msg->timeout = timeout;
-
-  bta_sys_sendmsg(p_msg);
+void BTA_DmBleUpdateConnectionParams(const RawAddress& bd_addr,
+                                     uint16_t min_int, uint16_t max_int,
+                                     uint16_t latency, uint16_t timeout,
+                                     uint16_t min_ce_len, uint16_t max_ce_len) {
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(bta_dm_ble_update_conn_params, bd_addr, min_int,
+                            max_int, latency, timeout, min_ce_len, max_ce_len));
 }
 
 /*******************************************************************************
@@ -980,13 +747,8 @@
  ******************************************************************************/
 void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) {
 #if (BLE_PRIVACY_SPT == TRUE)
-  tBTA_DM_API_LOCAL_PRIVACY* p_msg = (tBTA_DM_API_LOCAL_PRIVACY*)osi_calloc(
-      sizeof(tBTA_DM_API_ENABLE_PRIVACY));
-
-  p_msg->hdr.event = BTA_DM_API_LOCAL_PRIVACY_EVT;
-  p_msg->privacy_enable = privacy_enable;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_ble_config_local_privacy, privacy_enable));
 #else
   UNUSED(privacy_enable);
 #endif
@@ -1004,73 +766,15 @@
  *
  ******************************************************************************/
 void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback) {
-  const size_t len = sizeof(tBTA_DM_API_ENERGY_INFO) + sizeof(tBLE_BD_ADDR);
-  tBTA_DM_API_ENERGY_INFO* p_msg = (tBTA_DM_API_ENERGY_INFO*)osi_calloc(len);
-
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_DM_API_BLE_ENERGY_INFO_EVT;
-  p_msg->p_energy_info_cback = p_cmpl_cback;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_ble_get_energy_info, p_cmpl_cback));
 }
 
-/*******************************************************************************
- *
- * Function         BTA_DmBleUpdateConnectionParams
- *
- * Description      Update connection parameters, can only be used when
- *                  connection is up.
- *
- * Parameters:      bd_addr   - BD address of the peer
- *                  min_int   -     minimum connection interval,
- *                                  [0x0004 ~ 0x4000]
- *                  max_int   -     maximum connection interval,
- *                                  [0x0004 ~ 0x4000]
- *                  latency   -     slave latency [0 ~ 500]
- *                  timeout   -     supervision timeout [0x000a ~ 0xc80]
- *
- * Returns          void
- *
- ******************************************************************************/
-void BTA_DmBleUpdateConnectionParams(const RawAddress& bd_addr,
-                                     uint16_t min_int, uint16_t max_int,
-                                     uint16_t latency, uint16_t timeout) {
-  tBTA_DM_API_UPDATE_CONN_PARAM* p_msg =
-      (tBTA_DM_API_UPDATE_CONN_PARAM*)osi_calloc(
-          sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
-
-  p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->min_int = min_int;
-  p_msg->max_int = max_int;
-  p_msg->latency = latency;
-  p_msg->timeout = timeout;
-
-  bta_sys_sendmsg(p_msg);
-}
-
-/*******************************************************************************
- *
- * Function         BTA_DmBleSetDataLength
- *
- * Description      This function is to set maximum LE data packet size
- *
- * Returns          void
- *
- *
- ******************************************************************************/
+/** This function is to set maximum LE data packet size */
 void BTA_DmBleSetDataLength(const RawAddress& remote_device,
                             uint16_t tx_data_length) {
-  tBTA_DM_API_BLE_SET_DATA_LENGTH* p_msg =
-      (tBTA_DM_API_BLE_SET_DATA_LENGTH*)osi_malloc(
-          sizeof(tBTA_DM_API_BLE_SET_DATA_LENGTH));
-
-  p_msg->remote_bda = remote_device;
-  p_msg->hdr.event = BTA_DM_API_SET_DATA_LENGTH_EVT;
-  p_msg->tx_data_length = tx_data_length;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ble_set_data_length,
+                                         remote_device, tx_data_length));
 }
 
 /*******************************************************************************
@@ -1098,18 +802,9 @@
 void BTA_DmSetEncryption(const RawAddress& bd_addr, tBTA_TRANSPORT transport,
                          tBTA_DM_ENCRYPT_CBACK* p_callback,
                          tBTA_DM_BLE_SEC_ACT sec_act) {
-  tBTA_DM_API_SET_ENCRYPTION* p_msg = (tBTA_DM_API_SET_ENCRYPTION*)osi_calloc(
-      sizeof(tBTA_DM_API_SET_ENCRYPTION));
-
   APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_DM_API_SET_ENCRYPTION_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->transport = transport;
-  p_msg->p_callback = p_callback;
-  p_msg->sec_act = sec_act;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_set_encryption, bd_addr,
+                                         transport, p_callback, sec_act));
 }
 
 /*******************************************************************************
@@ -1127,17 +822,8 @@
  ******************************************************************************/
 void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev,
                     tBTA_TRANSPORT transport) {
-  tBTA_DM_API_REMOVE_ACL* p_msg =
-      (tBTA_DM_API_REMOVE_ACL*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_ACL));
-
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_DM_API_REMOVE_ACL_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->remove_dev = remove_dev;
-  p_msg->transport = transport;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(bta_dm_close_acl, bd_addr, remove_dev, transport));
 }
 
 /*******************************************************************************
@@ -1157,17 +843,9 @@
  ******************************************************************************/
 extern void BTA_DmBleObserve(bool start, uint8_t duration,
                              tBTA_DM_SEARCH_CBACK* p_results_cb) {
-  tBTA_DM_API_BLE_OBSERVE* p_msg =
-      (tBTA_DM_API_BLE_OBSERVE*)osi_calloc(sizeof(tBTA_DM_API_BLE_OBSERVE));
-
   APPL_TRACE_API("%s:start = %d ", __func__, start);
-
-  p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT;
-  p_msg->start = start;
-  p_msg->duration = duration;
-  p_msg->p_cback = p_results_cb;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(bta_dm_ble_observe, start, duration, p_results_cb));
 }
 
 /*******************************************************************************
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 4202975..91053a1 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -111,9 +111,9 @@
     {BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE},
     {BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE}};
 
-tBTA_DM_CFG* p_bta_dm_cfg = (tBTA_DM_CFG*)&bta_dm_cfg;
+const tBTA_DM_CFG* p_bta_dm_cfg = &bta_dm_cfg;
 
-tBTA_DM_RM* p_bta_dm_rm_cfg = (tBTA_DM_RM*)&bta_dm_rm_cfg;
+const tBTA_DM_RM* p_bta_dm_rm_cfg = &bta_dm_rm_cfg[0];
 
 #define BTA_DM_NUM_PM_ENTRY \
   23 /* number of entries in bta_dm_pm_cfg except the first */
@@ -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},
@@ -288,7 +288,7 @@
          {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
          {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
          {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
-         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTC_IDLE_TO_SNIFF_DELAY_MS},
           {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
          {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
          {{BTA_DM_PM_NO_ACTION, 0},
@@ -559,12 +559,12 @@
     {360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
 };
 
-tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC*)&bta_dm_ssr_spec;
+tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = &bta_dm_ssr_spec[0];
 #endif
 
-tBTA_DM_PM_CFG* p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG*)&bta_dm_pm_cfg;
-tBTA_DM_PM_SPEC* p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC*)&bta_dm_pm_spec;
-tBTM_PM_PWR_MD* p_bta_dm_pm_md = (tBTM_PM_PWR_MD*)&bta_dm_pm_md;
+const tBTA_DM_PM_CFG* p_bta_dm_pm_cfg = &bta_dm_pm_cfg[0];
+const tBTA_DM_PM_SPEC* p_bta_dm_pm_spec = &bta_dm_pm_spec[0];
+const tBTM_PM_PWR_MD* p_bta_dm_pm_md = &bta_dm_pm_md[0];
 
 /* The performance impact of EIR packet size
  *
@@ -620,4 +620,4 @@
     0,    /* length of additional data in bytes */
     NULL  /* additional data */
 };
-tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg;
+const tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg = &bta_dm_eir_cfg;
diff --git a/bta/dm/bta_dm_ci.cc b/bta/dm/bta_dm_ci.cc
index 7ff9da2..3d40480 100644
--- a/bta/dm/bta_dm_ci.cc
+++ b/bta/dm/bta_dm_ci.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,14 +21,15 @@
  *  This is the API implementation file for the BTA device manager.
  *
  ******************************************************************************/
-#include <string.h>
-
 #include "bt_common.h"
 #include "bta_api.h"
 #include "bta_dm_ci.h"
 #include "bta_dm_int.h"
 #include "bta_sys.h"
 
+#include <base/bind.h>
+#include <memory>
+
 /*******************************************************************************
  *
  * Function         bta_dm_ci_io_req
@@ -44,16 +45,8 @@
                       tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req)
 
 {
-  tBTA_DM_CI_IO_REQ* p_msg =
-      (tBTA_DM_CI_IO_REQ*)osi_malloc(sizeof(tBTA_DM_CI_IO_REQ));
-
-  p_msg->hdr.event = BTA_DM_CI_IO_REQ_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->io_cap = io_cap;
-  p_msg->oob_data = oob_data;
-  p_msg->auth_req = auth_req;
-
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ci_io_req_act, bd_addr, io_cap,
+                                         oob_data, auth_req));
 }
 
 /*******************************************************************************
@@ -69,40 +62,15 @@
  ******************************************************************************/
 void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr, BT_OCTET16 c,
                        BT_OCTET16 r) {
-  tBTA_DM_CI_RMT_OOB* p_msg =
-      (tBTA_DM_CI_RMT_OOB*)osi_malloc(sizeof(tBTA_DM_CI_RMT_OOB));
+  std::unique_ptr<tBTA_DM_CI_RMT_OOB> msg =
+      std::make_unique<tBTA_DM_CI_RMT_OOB>();
 
-  p_msg->hdr.event = BTA_DM_CI_RMT_OOB_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->accept = accept;
-  memcpy(p_msg->c, c, BT_OCTET16_LEN);
-  memcpy(p_msg->r, r, BT_OCTET16_LEN);
+  msg->bd_addr = bd_addr;
+  msg->accept = accept;
+  memcpy(msg->c, c, BT_OCTET16_LEN);
+  memcpy(msg->r, r, BT_OCTET16_LEN);
 
-  bta_sys_sendmsg(p_msg);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(bta_dm_ci_rmt_oob_act, base::Passed(&msg)));
 }
 
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-/*******************************************************************************
- *
- * Function         bta_dm_sco_ci_data_ready
- *
- * Description      This function sends an event to indicating that the phone
- *                  has SCO data ready.
- *
- * Parameters       event: is obtained from bta_dm_sco_co_open() function, which
- *                          is the BTA event we want to send back to BTA module
- *                          when there is encoded data ready.
- *                  sco_handle: is the BTA sco handle which indicate a specific
- *                           SCO connection.
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_sco_ci_data_ready(uint16_t event, uint16_t sco_handle) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = event;
-  p_buf->layer_specific = sco_handle;
-
-  bta_sys_sendmsg(p_buf);
-}
-#endif
diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h
index 12a4074..6aafd7d 100644
--- a/bta/dm/bta_dm_int.h
+++ b/bta/dm/bta_dm_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -45,60 +45,6 @@
 
 #define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
 
-/* DM events */
-enum {
-  /* device manager local device API events */
-  BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),
-  BTA_DM_API_DISABLE_EVT,
-  BTA_DM_API_SET_NAME_EVT,
-  BTA_DM_API_SET_VISIBILITY_EVT,
-
-  BTA_DM_ACL_CHANGE_EVT,
-  BTA_DM_API_ADD_DEVICE_EVT,
-  BTA_DM_API_REMOVE_ACL_EVT,
-
-  /* security API events */
-  BTA_DM_API_BOND_EVT,
-  BTA_DM_API_BOND_CANCEL_EVT,
-  BTA_DM_API_PIN_REPLY_EVT,
-
-  /* power manger events */
-  BTA_DM_PM_BTM_STATUS_EVT,
-  BTA_DM_PM_TIMER_EVT,
-
-  /* simple pairing events */
-  BTA_DM_API_CONFIRM_EVT,
-
-  BTA_DM_API_SET_ENCRYPTION_EVT,
-
-  BTA_DM_API_LOC_OOB_EVT,
-  BTA_DM_CI_IO_REQ_EVT,
-  BTA_DM_CI_RMT_OOB_EVT,
-
-  BTA_DM_API_ADD_BLEKEY_EVT,
-  BTA_DM_API_ADD_BLEDEVICE_EVT,
-  BTA_DM_API_BLE_PASSKEY_REPLY_EVT,
-  BTA_DM_API_BLE_CONFIRM_REPLY_EVT,
-  BTA_DM_API_BLE_SEC_GRANT_EVT,
-  BTA_DM_API_BLE_SET_BG_CONN_TYPE,
-  BTA_DM_API_BLE_CONN_PARAM_EVT,
-  BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT,
-  BTA_DM_API_BLE_OBSERVE_EVT,
-  BTA_DM_API_UPDATE_CONN_PARAM_EVT,
-#if (BLE_PRIVACY_SPT == TRUE)
-  BTA_DM_API_LOCAL_PRIVACY_EVT,
-#endif
-  BTA_DM_API_SET_DATA_LENGTH_EVT,
-  BTA_DM_API_BLE_ENERGY_INFO_EVT,
-
-  BTA_DM_API_ENABLE_TEST_MODE_EVT,
-  BTA_DM_API_DISABLE_TEST_MODE_EVT,
-  BTA_DM_API_EXECUTE_CBACK_EVT,
-  BTA_DM_API_REMOVE_ALL_ACL_EVT,
-  BTA_DM_API_REMOVE_DEVICE_EVT,
-  BTA_DM_MAX_EVT
-};
-
 /* DM search events */
 enum {
   /* DM search API events */
@@ -115,27 +61,6 @@
 
 };
 
-/* data type for BTA_DM_API_ENABLE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_DM_SEC_CBACK* p_sec_cback;
-} tBTA_DM_API_ENABLE;
-
-/* data type for BTA_DM_API_SET_NAME_EVT */
-typedef struct {
-  BT_HDR hdr;
-  BD_NAME name; /* max 248 bytes name, plus must be Null terminated */
-} tBTA_DM_API_SET_NAME;
-
-/* data type for BTA_DM_API_SET_VISIBILITY_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_DM_DISC disc_mode;
-  tBTA_DM_CONN conn_mode;
-  uint8_t pair_mode;
-  uint8_t conn_paired_only;
-} tBTA_DM_API_SET_VISIBILITY;
-
 enum {
   BTA_DM_RS_NONE, /* straight API call */
   BTA_DM_RS_OK,   /* the role switch result - successful */
@@ -151,7 +76,7 @@
   tBTA_DM_SEARCH_CBACK* p_cback;
   tBTA_DM_RS_RES rs_res;
   uint8_t num_uuid;
-  tBT_UUID* p_uuid;
+  bluetooth::Uuid* p_uuid;
 } tBTA_DM_API_SEARCH;
 
 /* data type for BTA_DM_API_DISCOVER_EVT */
@@ -163,8 +88,8 @@
   bool sdp_search;
   tBTA_TRANSPORT transport;
   uint8_t num_uuid;
-  tBT_UUID* p_uuid;
-  tSDP_UUID uuid;
+  bluetooth::Uuid* p_uuid;
+  bluetooth::Uuid uuid;
 } tBTA_DM_API_DISCOVER;
 
 /* data type for BTA_DM_API_DI_DISC_EVT */
@@ -176,40 +101,13 @@
   tBTA_DM_SEARCH_CBACK* p_cback;
 } tBTA_DM_API_DI_DISC;
 
-/* data type for BTA_DM_API_BOND_EVT */
 typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBTA_TRANSPORT transport;
-} tBTA_DM_API_BOND;
-
-/* data type for BTA_DM_API_BOND_CANCEL_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBTA_TRANSPORT transport;
-} tBTA_DM_API_BOND_CANCEL;
-
-/* data type for BTA_DM_API_PIN_REPLY_EVT */
-typedef struct {
-  BT_HDR hdr;
   RawAddress bd_addr;
   bool accept;
   uint8_t pin_len;
   uint8_t p_pin[PIN_CODE_LEN];
 } tBTA_DM_API_PIN_REPLY;
 
-/* data type for BTA_DM_API_LOC_OOB_EVT */
-typedef struct { BT_HDR hdr; } tBTA_DM_API_LOC_OOB;
-
-/* data type for BTA_DM_API_CONFIRM_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  bool accept;
-} tBTA_DM_API_CONFIRM;
-
-/* data type for BTA_DM_CI_IO_REQ_EVT */
 typedef struct {
   BT_HDR hdr;
   RawAddress bd_addr;
@@ -218,9 +116,7 @@
   tBTA_AUTH_REQ auth_req;
 } tBTA_DM_CI_IO_REQ;
 
-/* data type for BTA_DM_CI_RMT_OOB_EVT */
 typedef struct {
-  BT_HDR hdr;
   RawAddress bd_addr;
   BT_OCTET16 c;
   BT_OCTET16 r;
@@ -251,40 +147,7 @@
   uint16_t sdp_result;
 } tBTA_DM_SDP_RESULT;
 
-/* data type for BTA_DM_ACL_CHANGE_EVT */
 typedef struct {
-  BT_HDR hdr;
-  tBTM_BL_EVENT event;
-  uint8_t busy_level;
-  uint8_t busy_level_flags;
-  bool is_new;
-  uint8_t new_role;
-  RawAddress bd_addr;
-  uint8_t hci_status;
-  uint16_t handle;
-  tBT_TRANSPORT transport;
-} tBTA_DM_ACL_CHANGE;
-
-/* data type for BTA_DM_PM_BTM_STATUS_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBTM_PM_STATUS status;
-  uint16_t value;
-  uint8_t hci_status;
-
-} tBTA_DM_PM_BTM_STATUS;
-
-/* data type for BTA_DM_PM_TIMER_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBTA_DM_PM_ACTION pm_request;
-} tBTA_DM_PM_TIMER;
-
-/* data type for BTA_DM_API_ADD_DEVICE_EVT */
-typedef struct {
-  BT_HDR hdr;
   RawAddress bd_addr;
   DEV_CLASS dc;
   LINK_KEY link_key;
@@ -300,176 +163,20 @@
   uint8_t pin_length;
 } tBTA_DM_API_ADD_DEVICE;
 
-/* data type for BTA_DM_API_REMOVE_ACL_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-} tBTA_DM_API_REMOVE_DEVICE;
-
-/* data type for BTA_DM_API_EXECUTE_CBACK_EVT */
-typedef struct {
-  BT_HDR hdr;
-  void* p_param;
-  tBTA_DM_EXEC_CBACK* p_exec_cback;
-} tBTA_DM_API_EXECUTE_CBACK;
-
-/* data type for tBTA_DM_API_SET_ENCRYPTION */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_TRANSPORT transport;
-  tBTA_DM_ENCRYPT_CBACK* p_callback;
-  tBTA_DM_BLE_SEC_ACT sec_act;
-  RawAddress bd_addr;
-} tBTA_DM_API_SET_ENCRYPTION;
-
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBTA_LE_KEY_VALUE blekey;
-  tBTA_LE_KEY_TYPE key_type;
-
-} tBTA_DM_API_ADD_BLEKEY;
-
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBT_DEVICE_TYPE dev_type;
-  tBLE_ADDR_TYPE addr_type;
-
-} tBTA_DM_API_ADD_BLE_DEVICE;
-
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  bool accept;
-  uint32_t passkey;
-} tBTA_DM_API_PASSKEY_REPLY;
-
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  tBTA_DM_BLE_SEC_GRANT res;
-} tBTA_DM_API_BLE_SEC_GRANT;
-
-/* set prefered BLE connection parameters for a device */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress peer_bda;
-  uint16_t conn_int_min;
-  uint16_t conn_int_max;
-  uint16_t supervision_tout;
-  uint16_t slave_latency;
-
-} tBTA_DM_API_BLE_CONN_PARAMS;
-
-typedef struct {
-  BT_HDR hdr;
-  RawAddress peer_bda;
-  bool privacy_enable;
-
-} tBTA_DM_API_ENABLE_PRIVACY;
-
-typedef struct {
-  BT_HDR hdr;
-  bool privacy_enable;
-} tBTA_DM_API_LOCAL_PRIVACY;
-
-/* set scan parameter for BLE connections */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_GATTC_IF client_if;
-  uint32_t scan_int;
-  uint32_t scan_window;
-  tBLE_SCAN_MODE scan_mode;
-  tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback;
-} tBTA_DM_API_BLE_SCAN_PARAMS;
-
-/* set scan parameter for BLE connections */
-typedef struct {
-  BT_HDR hdr;
-  uint16_t scan_int;
-  uint16_t scan_window;
-} tBTA_DM_API_BLE_CONN_SCAN_PARAMS;
-
-/* Data type for start/stop observe */
-typedef struct {
-  BT_HDR hdr;
-  bool start;
-  uint16_t duration;
-  tBTA_DM_SEARCH_CBACK* p_cback;
-} tBTA_DM_API_BLE_OBSERVE;
-
-typedef struct {
-  BT_HDR hdr;
-  RawAddress remote_bda;
-  uint16_t tx_data_length;
-} tBTA_DM_API_BLE_SET_DATA_LENGTH;
-
-/* set adv parameter for BLE advertising */
-
 typedef struct {
   BT_HDR hdr;
   bool enable;
-
 } tBTA_DM_API_BLE_FEATURE;
 
-typedef struct {
-  BT_HDR hdr;
-  tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback;
-} tBTA_DM_API_ENERGY_INFO;
-
-/* data type for BTA_DM_API_REMOVE_ACL_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  bool remove_dev;
-  tBTA_TRANSPORT transport;
-} tBTA_DM_API_REMOVE_ACL;
-
-/* data type for BTA_DM_API_REMOVE_ALL_ACL_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_DM_LINK_TYPE link_type;
-
-} tBTA_DM_API_REMOVE_ALL_ACL;
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  uint16_t min_int;
-  uint16_t max_int;
-  uint16_t latency;
-  uint16_t timeout;
-} tBTA_DM_API_UPDATE_CONN_PARAM;
-
 /* union of all data types */
 typedef union {
   /* GKI event buffer header */
   BT_HDR hdr;
-  tBTA_DM_API_ENABLE enable;
-
-  tBTA_DM_API_SET_NAME set_name;
-
-  tBTA_DM_API_SET_VISIBILITY set_visibility;
-
-  tBTA_DM_API_ADD_DEVICE add_dev;
-
-  tBTA_DM_API_REMOVE_DEVICE remove_dev;
 
   tBTA_DM_API_SEARCH search;
 
   tBTA_DM_API_DISCOVER discover;
 
-  tBTA_DM_API_BOND bond;
-
-  tBTA_DM_API_BOND_CANCEL bond_cancel;
-
-  tBTA_DM_API_PIN_REPLY pin_reply;
-
-  tBTA_DM_API_LOC_OOB loc_oob;
-  tBTA_DM_API_CONFIRM confirm;
-  tBTA_DM_CI_IO_REQ ci_io_req;
-  tBTA_DM_CI_RMT_OOB ci_rmt_oob;
-
   tBTA_DM_REM_NAME rem_name;
 
   tBTA_DM_DISC_RESULT disc_result;
@@ -478,35 +185,8 @@
 
   tBTA_DM_SDP_RESULT sdp_event;
 
-  tBTA_DM_ACL_CHANGE acl_change;
-
-  tBTA_DM_PM_BTM_STATUS pm_status;
-
-  tBTA_DM_PM_TIMER pm_timer;
-
   tBTA_DM_API_DI_DISC di_disc;
 
-  tBTA_DM_API_EXECUTE_CBACK exec_cback;
-
-  tBTA_DM_API_SET_ENCRYPTION set_encryption;
-
-  tBTA_DM_API_ADD_BLEKEY add_ble_key;
-  tBTA_DM_API_ADD_BLE_DEVICE add_ble_device;
-  tBTA_DM_API_PASSKEY_REPLY ble_passkey_reply;
-  tBTA_DM_API_BLE_SEC_GRANT ble_sec_grant;
-  tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params;
-  tBTA_DM_API_BLE_CONN_SCAN_PARAMS ble_set_conn_scan_params;
-  tBTA_DM_API_BLE_OBSERVE ble_observe;
-  tBTA_DM_API_ENABLE_PRIVACY ble_remote_privacy;
-  tBTA_DM_API_LOCAL_PRIVACY ble_local_privacy;
-  tBTA_DM_API_UPDATE_CONN_PARAM ble_update_conn_params;
-  tBTA_DM_API_BLE_SET_DATA_LENGTH ble_set_data_length;
-
-  tBTA_DM_API_ENERGY_INFO ble_energy_info;
-
-  tBTA_DM_API_REMOVE_ACL remove_acl;
-  tBTA_DM_API_REMOVE_ALL_ACL remove_all_acl;
-
 } tBTA_DM_MSG;
 
 #define BTA_DM_NUM_PEER_DEVICE 7
@@ -634,6 +314,10 @@
   RawAddress pin_bd_addr;
   DEV_CLASS pin_dev_class;
   tBTA_DM_SEC_EVT pin_evt;
+  tBTA_IO_CAP loc_io_caps;    /* IO Capabilities of local device */
+  tBTA_IO_CAP rmt_io_caps;    /* IO Capabilities of remote device */
+  tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+  tBTA_AUTH_REQ rmt_auth_req;
   uint32_t num_val; /* the numeric value for comparison. If just_works, do not
                        show this number to UI */
   bool just_works;  /* true, if "Just Works" association model */
@@ -641,7 +325,7 @@
   /* store UUID list for EIR */
   uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
 #if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
-  tBT_UUID custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID];
+  bluetooth::Uuid custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID];
 #endif
 
 #endif
@@ -669,15 +353,15 @@
                                   cancel stored here */
   bool wait_disc;
   bool sdp_results;
-  tSDP_UUID uuid;
+  bluetooth::Uuid uuid;
   uint8_t peer_scn;
   bool sdp_search;
   bool cancel_pending; /* inquiry cancel is pending */
   tBTA_TRANSPORT transport;
   tBTA_DM_SEARCH_CBACK* p_scan_cback;
-  tBTA_GATTC_IF client_if;
+  tGATT_IF client_if;
   uint8_t num_uuid;
-  tBT_UUID* p_srvc_uuid;
+  bluetooth::Uuid* p_srvc_uuid;
   uint8_t uuid_to_search;
   bool gatt_disc_active;
   uint16_t conn_id;
@@ -727,8 +411,8 @@
 
 } tBTA_DM_RM;
 
-extern tBTA_DM_CFG* p_bta_dm_cfg;
-extern tBTA_DM_RM* p_bta_dm_rm_cfg;
+extern const tBTA_DM_CFG* p_bta_dm_cfg;
+extern const tBTA_DM_RM* p_bta_dm_rm_cfg;
 
 typedef struct {
   uint8_t id;
@@ -766,16 +450,16 @@
 
 extern const uint16_t bta_service_id_to_uuid_lkup_tbl[];
 
-extern tBTA_DM_PM_CFG* p_bta_dm_pm_cfg;
-extern tBTA_DM_PM_SPEC* p_bta_dm_pm_spec;
-extern tBTM_PM_PWR_MD* p_bta_dm_pm_md;
+extern const tBTA_DM_PM_CFG* p_bta_dm_pm_cfg;
+extern const tBTA_DM_PM_SPEC* p_bta_dm_pm_spec;
+extern const tBTM_PM_PWR_MD* p_bta_dm_pm_md;
 #if (BTM_SSR_INCLUDED == TRUE)
 extern tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec;
 #endif
 
 /* update dynamic BRCM Aware EIR data */
 extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg;
-extern tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg;
+extern const tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg;
 
 /* DM control block */
 extern tBTA_DM_CB bta_dm_cb;
@@ -786,56 +470,61 @@
 /* DI control block */
 extern tBTA_DM_DI_CB bta_dm_di_cb;
 
-extern bool bta_dm_sm_execute(BT_HDR* p_msg);
-extern void bta_dm_sm_disable(void);
 extern bool bta_dm_search_sm_execute(BT_HDR* p_msg);
 extern void bta_dm_search_sm_disable(void);
 
-extern void bta_dm_enable(tBTA_DM_MSG* p_data);
-extern void bta_dm_disable(tBTA_DM_MSG* p_data);
+extern void bta_dm_enable(tBTA_DM_SEC_CBACK*);
+extern void bta_dm_disable();
 extern void bta_dm_init_cb(void);
-extern void bta_dm_set_dev_name(tBTA_DM_MSG* p_data);
-extern void bta_dm_set_visibility(tBTA_DM_MSG* p_data);
-
+extern void bta_dm_set_dev_name(const std::vector<uint8_t>&);
+extern void bta_dm_set_visibility(tBTA_DM_DISC, tBTA_DM_CONN, uint8_t, uint8_t);
 extern void bta_dm_set_scan_config(tBTA_DM_MSG* p_data);
 extern void bta_dm_vendor_spec_command(tBTA_DM_MSG* p_data);
-extern void bta_dm_bond(tBTA_DM_MSG* p_data);
-extern void bta_dm_bond_cancel(tBTA_DM_MSG* p_data);
-extern void bta_dm_pin_reply(tBTA_DM_MSG* p_data);
-extern void bta_dm_acl_change(tBTA_DM_MSG* p_data);
-extern void bta_dm_add_device(tBTA_DM_MSG* p_data);
-extern void bta_dm_remove_device(tBTA_DM_MSG* p_data);
-extern void bta_dm_close_acl(tBTA_DM_MSG* p_data);
+extern void bta_dm_bond(const RawAddress&, tBTA_TRANSPORT);
+extern void bta_dm_bond_cancel(const RawAddress&);
+extern void bta_dm_pin_reply(std::unique_ptr<tBTA_DM_API_PIN_REPLY> msg);
+extern void bta_dm_add_device(std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg);
+extern void bta_dm_remove_device(const RawAddress& bd_addr);
+extern void bta_dm_close_acl(const RawAddress&, bool, tBTA_TRANSPORT);
 
-extern void bta_dm_pm_btm_status(tBTA_DM_MSG* p_data);
-extern void bta_dm_pm_timer(tBTA_DM_MSG* p_data);
+extern void bta_dm_pm_btm_status(const RawAddress&, tBTM_PM_STATUS, uint16_t,
+                                 uint8_t);
+extern void bta_dm_pm_timer(const RawAddress&, tBTA_DM_PM_ACTION);
 extern void bta_dm_add_ampkey(tBTA_DM_MSG* p_data);
 
-extern void bta_dm_add_blekey(tBTA_DM_MSG* p_data);
-extern void bta_dm_add_ble_device(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_passkey_reply(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_confirm_reply(tBTA_DM_MSG* p_data);
-extern void bta_dm_security_grant(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_set_bg_conn_type(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_set_conn_params(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_set_conn_scan_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_blekey(const RawAddress& bd_addr,
+                              tBTA_LE_KEY_VALUE blekey,
+                              tBTA_LE_KEY_TYPE key_type);
+extern void bta_dm_add_ble_device(const RawAddress& bd_addr,
+                                  tBLE_ADDR_TYPE addr_type,
+                                  tBT_DEVICE_TYPE dev_type);
+extern void bta_dm_ble_passkey_reply(const RawAddress& bd_addr, bool accept,
+                                     uint32_t passkey);
+extern void bta_dm_ble_confirm_reply(const RawAddress&, bool);
+extern void bta_dm_ble_set_conn_params(const RawAddress&, uint16_t, uint16_t,
+                                       uint16_t, uint16_t);
+extern void bta_dm_ble_set_conn_scan_params(uint32_t, uint32_t);
 extern void bta_dm_close_gatt_conn(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_observe(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_update_conn_params(tBTA_DM_MSG* p_data);
-extern void bta_dm_ble_config_local_privacy(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_observe(bool, uint8_t, tBTA_DM_SEARCH_CBACK*);
+extern void bta_dm_ble_update_conn_params(const RawAddress&, uint16_t, uint16_t,
+                                          uint16_t, uint16_t, uint16_t,
+                                          uint16_t);
+extern void bta_dm_ble_config_local_privacy(bool);
 extern void bta_dm_ble_set_adv_params(uint16_t adv_int_min,
                                       uint16_t adv_int_max,
                                       tBLE_BD_ADDR* p_dir_bda);
 
-extern void bta_dm_ble_set_data_length(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_data_length(const RawAddress&, uint16_t);
 
-extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_get_energy_info(tBTA_BLE_ENERGY_INFO_CBACK*);
 
-extern void bta_dm_set_encryption(tBTA_DM_MSG* p_data);
-extern void bta_dm_confirm(tBTA_DM_MSG* p_data);
-extern void bta_dm_loc_oob(tBTA_DM_MSG* p_data);
-extern void bta_dm_ci_io_req_act(tBTA_DM_MSG* p_data);
-extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG* p_data);
+extern void bta_dm_set_encryption(const RawAddress&, tBTA_TRANSPORT,
+                                  tBTA_DM_ENCRYPT_CBACK*, tBTA_DM_BLE_SEC_ACT);
+extern void bta_dm_confirm(const RawAddress&, bool);
+extern void bta_dm_ci_io_req_act(const RawAddress& bd_addr, tBTA_IO_CAP io_cap,
+                                 tBTA_OOB_DATA oob_data,
+                                 tBTA_AUTH_REQ auth_req);
+extern void bta_dm_ci_rmt_oob_act(std::unique_ptr<tBTA_DM_CI_RMT_OOB> msg);
 
 extern void bta_dm_init_pm(void);
 extern void bta_dm_disable_pm(void);
@@ -865,9 +554,5 @@
 
 void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding);
 
-extern void bta_dm_enable_test_mode(tBTA_DM_MSG* p_data);
-extern void bta_dm_disable_test_mode(tBTA_DM_MSG* p_data);
-extern void bta_dm_execute_callback(tBTA_DM_MSG* p_data);
-
-extern void bta_dm_remove_all_acl(tBTA_DM_MSG* p_data);
+extern void bta_dm_remove_all_acl(const tBTA_DM_LINK_TYPE);
 #endif /* BTA_DM_INT_H */
diff --git a/bta/dm/bta_dm_main.cc b/bta/dm/bta_dm_main.cc
index d91eaba..f9bffe6 100644
--- a/bta/dm/bta_dm_main.cc
+++ b/bta/dm/bta_dm_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,60 +39,6 @@
 /* type for action functions */
 typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG* p_data);
 
-/* action function list */
-const tBTA_DM_ACTION bta_dm_action[] = {
-
-    /* device manager local device API events */
-    bta_dm_enable,         /* 0  BTA_DM_API_ENABLE_EVT */
-    bta_dm_disable,        /* 1  BTA_DM_API_DISABLE_EVT */
-    bta_dm_set_dev_name,   /* 2  BTA_DM_API_SET_NAME_EVT */
-    bta_dm_set_visibility, /* 3  BTA_DM_API_SET_VISIBILITY_EVT */
-    bta_dm_acl_change,     /* 8  BTA_DM_ACL_CHANGE_EVT */
-    bta_dm_add_device,     /* 9  BTA_DM_API_ADD_DEVICE_EVT */
-    bta_dm_close_acl,      /* 10  BTA_DM_API_ADD_DEVICE_EVT */
-
-    /* security API events */
-    bta_dm_bond,        /* 11  BTA_DM_API_BOND_EVT */
-    bta_dm_bond_cancel, /* 12  BTA_DM_API_BOND_CANCEL_EVT */
-    bta_dm_pin_reply,   /* 13 BTA_DM_API_PIN_REPLY_EVT */
-
-    /* power manger events */
-    bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */
-    bta_dm_pm_timer,      /* 17 BTA_DM_PM_TIMER_EVT*/
-
-    /* simple pairing events */
-    bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */
-
-    bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */
-
-    /* out of band pairing events */
-    bta_dm_loc_oob,        /* 20 BTA_DM_API_LOC_OOB_EVT */
-    bta_dm_ci_io_req_act,  /* 21 BTA_DM_CI_IO_REQ_EVT */
-    bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */
-
-    bta_dm_add_blekey,        /*  BTA_DM_API_ADD_BLEKEY_EVT           */
-    bta_dm_add_ble_device,    /*  BTA_DM_API_ADD_BLEDEVICE_EVT        */
-    bta_dm_ble_passkey_reply, /*  BTA_DM_API_BLE_PASSKEY_REPLY_EVT    */
-    bta_dm_ble_confirm_reply, /*  BTA_DM_API_BLE_CONFIRM_REPLY_EVT    */
-    bta_dm_security_grant, bta_dm_ble_set_bg_conn_type,
-    bta_dm_ble_set_conn_params,      /* BTA_DM_API_BLE_CONN_PARAM_EVT */
-    bta_dm_ble_set_conn_scan_params, /* BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT */
-    bta_dm_ble_observe,
-    bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */
-#if (BLE_PRIVACY_SPT == TRUE)
-    bta_dm_ble_config_local_privacy, /* BTA_DM_API_LOCAL_PRIVACY_EVT */
-#endif
-    bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */
-    bta_dm_ble_get_energy_info,    /* BTA_DM_API_BLE_ENERGY_INFO_EVT */
-
-    bta_dm_enable_test_mode,  /*  BTA_DM_API_ENABLE_TEST_MODE_EVT     */
-    bta_dm_disable_test_mode, /*  BTA_DM_API_DISABLE_TEST_MODE_EVT    */
-    bta_dm_execute_callback,  /*  BTA_DM_API_EXECUTE_CBACK_EVT        */
-
-    bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */
-    bta_dm_remove_device,  /* BTA_DM_API_REMOVE_DEVICE_EVT */
-};
-
 /* state machine action enumeration list */
 enum {
   BTA_DM_API_SEARCH,                 /* 0 bta_dm_search_start */
@@ -261,41 +207,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_dm_sm_disable
- *
- * Description     unregister BTA DM
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_sm_disable() { bta_sys_deregister(BTA_ID_DM); }
-
-/*******************************************************************************
- *
- * Function         bta_dm_sm_execute
- *
- * Description      State machine event handling function for DM
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-bool bta_dm_sm_execute(BT_HDR* p_msg) {
-  uint16_t event = p_msg->event & 0x00ff;
-
-  APPL_TRACE_EVENT("bta_dm_sm_execute event:0x%x", event);
-
-  /* execute action functions */
-  if (event < BTA_DM_NUM_ACTIONS) {
-    (*bta_dm_action[event])((tBTA_DM_MSG*)p_msg);
-  }
-
-  return true;
-}
-
-/*******************************************************************************
- *
  * Function         bta_dm_sm_search_disable
  *
  * Description     unregister BTA SEARCH DM
diff --git a/bta/dm/bta_dm_pm.cc b/bta/dm/bta_dm_pm.cc
index 23716c1..731d253 100644
--- a/bta/dm/bta_dm_pm.cc
+++ b/bta/dm/bta_dm_pm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
  *
  ******************************************************************************/
 
+#include <base/bind.h>
 #include <base/logging.h>
 #include <string.h>
 
@@ -47,7 +48,9 @@
 static bool bta_dm_pm_park(const RawAddress& peer_addr);
 static bool bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index);
 static bool bta_dm_pm_is_sco_active();
+#if (BTM_SSR_INCLUDED == TRUE)
 static int bta_dm_get_sco_index();
+#endif
 static void bta_dm_pm_hid_check(bool bScoActive);
 static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE* p_dev,
                                        bool bDisable);
@@ -83,7 +86,7 @@
 
   /* if there are no power manger entries, so not register */
   if (p_bta_dm_pm_cfg[0].app_id != 0) {
-    bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback);
+    bta_sys_pm_register(bta_dm_pm_cback);
 
     BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,
                    bta_dm_pm_btm_cback);
@@ -113,7 +116,7 @@
    * Deregister the PM callback from the system handling to prevent
    * re-enabling the PM timers after this call if the callback is invoked.
    */
-  bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)NULL);
+  bta_sys_pm_register(NULL);
 
   /* Need to stop all active timers. */
   for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
@@ -331,14 +334,9 @@
 static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
                             uint8_t app_id, const RawAddress& peer_addr) {
   uint8_t i, j;
-  uint8_t* p = NULL;
   tBTA_DM_PEER_DEVICE* p_dev;
   tBTA_DM_PM_REQ pm_req = BTA_DM_PM_NEW_REQ;
 
-#if (BTM_SSR_INCLUDED == TRUE)
-  int index = BTA_DM_PM_SSR0;
-#endif
-
   APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id,
                    app_id);
 
@@ -360,6 +358,7 @@
 
 #if (BTM_SSR_INCLUDED == TRUE)
   /* set SSR parameters on SYS CONN OPEN */
+  int index = BTA_DM_PM_SSR0;
   if ((BTA_SYS_CONN_OPEN == status) && p_dev &&
       (p_dev->info & BTA_DM_DI_USE_SSR)) {
     index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
@@ -448,6 +447,7 @@
       ) {
     bta_dm_pm_ssr(peer_addr);
   } else {
+    uint8_t* p = NULL;
     if (((NULL != (p = BTM_ReadLocalFeatures())) &&
          HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
         ((NULL != (p = BTM_ReadRemoteFeatures(peer_addr))) &&
@@ -506,9 +506,10 @@
   tBTA_DM_PEER_DEVICE* p_peer_device = NULL;
   tBTA_DM_PM_ACTION allowed_modes = 0;
   tBTA_DM_PM_ACTION pref_modes = 0;
-  tBTA_DM_PM_CFG* p_pm_cfg;
-  tBTA_DM_PM_SPEC* p_pm_spec;
-  tBTA_DM_PM_ACTN *p_act0, *p_act1;
+  const tBTA_DM_PM_CFG* p_pm_cfg;
+  const tBTA_DM_PM_SPEC* p_pm_spec;
+  const tBTA_DM_PM_ACTN* p_act0;
+  const tBTA_DM_PM_ACTN* p_act1;
   tBTA_DM_SRVCS* p_srvcs = NULL;
   bool timer_started = false;
   uint8_t timer_idx, available_timer = BTA_DM_PM_MODE_TIMER_MAX;
@@ -691,25 +692,16 @@
   tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
   tBTM_PM_PWR_MD pwr_md;
   tBTM_STATUS status;
-#if (BTM_SSR_INCLUDED == TRUE)
-  uint8_t* p_rem_feat = NULL;
-#endif
 
   BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode);
-  p_rem_feat = BTM_ReadRemoteFeatures(p_peer_dev->peer_bdaddr);
 #if (BTM_SSR_INCLUDED == TRUE)
+  uint8_t* p_rem_feat = BTM_ReadRemoteFeatures(p_peer_dev->peer_bdaddr);
   APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index,
                    p_peer_dev->info);
   if (mode != BTM_PM_MD_SNIFF ||
       (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures()) && p_rem_feat &&
        HCI_SNIFF_SUB_RATE_SUPPORTED(p_rem_feat) &&
-       !(p_peer_dev->info & BTA_DM_DI_USE_SSR)))
-#else
-  APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d", mode, index);
-  if (mode != BTM_PM_MD_SNIFF)
-#endif
-  {
-#if (BTM_SSR_INCLUDED == TRUE)
+       !(p_peer_dev->info & BTA_DM_DI_USE_SSR))) {
     /* Dont initiate Sniff if controller has alreay accepted
      * remote sniff params. This avoid sniff loop issue with
      * some agrresive headsets who use sniff latencies more than
@@ -718,6 +710,9 @@
       APPL_TRACE_DEBUG("%s: already in remote initiate sniff", __func__);
       return true;
     }
+#else
+  APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d", mode, index);
+  if (mode != BTM_PM_MD_SNIFF) {
 #endif
     /* if the current mode is not sniff, issue the sniff command.
      * If sniff, but SSR is not used in this link, still issue the command */
@@ -756,53 +751,48 @@
  ******************************************************************************/
 #if (BTM_SSR_INCLUDED == TRUE)
 static void bta_dm_pm_ssr(const RawAddress& peer_addr) {
-  tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur;
-  uint8_t i, j;
-  int ssr = BTA_DM_PM_SSR0;
+  int current_ssr_index;
+  int ssr_index = BTA_DM_PM_SSR0;
+  tBTA_DM_SSR_SPEC* p_spec = &p_bta_dm_ssr_spec[ssr_index];
 
   /* go through the connected services */
-  for (i = 0; i < bta_dm_conn_srvcs.count; i++) {
-    if (bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr == peer_addr) {
-      /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
-      for (j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) {
-        /* find the associated p_bta_dm_pm_cfg */
-        if ((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id) &&
-            ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID) ||
-             (p_bta_dm_pm_cfg[j].app_id ==
-              bta_dm_conn_srvcs.conn_srvc[i].app_id))) {
-          APPL_TRACE_WARNING("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d",
-                             bta_dm_conn_srvcs.conn_srvc[i].id,
-                             bta_dm_conn_srvcs.conn_srvc[i].app_id);
-          break;
-        }
+  for (int i = 0; i < bta_dm_conn_srvcs.count; i++) {
+    const tBTA_DM_SRVCS& service = bta_dm_conn_srvcs.conn_srvc[i];
+    if (service.peer_bdaddr != peer_addr) {
+      continue;
+    }
+    /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+    for (int j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) {
+      /* find the associated p_bta_dm_pm_cfg */
+      const tBTA_DM_PM_CFG& config = p_bta_dm_pm_cfg[j];
+      current_ssr_index = p_bta_dm_pm_spec[config.spec_idx].ssr;
+      if ((config.id == service.id) && ((config.app_id == BTA_ALL_APP_ID) ||
+                                        (config.app_id == service.app_id))) {
+        APPL_TRACE_WARNING("%s: conn_srvc id:%d, app_id:%d", __func__,
+                           service.id, service.app_id);
+        break;
       }
-
-      /* find the ssr index with the smallest max latency. */
-      p_spec_cur =
-          &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr];
-      p_spec = &p_bta_dm_ssr_spec[ssr];
-
+    }
+    /* find the ssr index with the smallest max latency. */
+    tBTA_DM_SSR_SPEC* p_spec_cur = &p_bta_dm_ssr_spec[current_ssr_index];
 #if (BTA_HH_INCLUDED == TRUE)
-      /* HH has the per connection SSR preference, already read the SSR params
-       * from BTA HH */
-      if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr ==
-          BTA_DM_PM_SSR_HH) {
-        if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat,
-                                  &p_spec_cur->min_rmt_to) == BTA_HH_ERR)
-          continue;
+    /* HH has the per connection SSR preference, already read the SSR params
+     * from BTA HH */
+    if (current_ssr_index == BTA_DM_PM_SSR_HH) {
+      if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat,
+                                &p_spec_cur->min_rmt_to) == BTA_HH_ERR) {
+        continue;
       }
+    }
 #endif
-      if (p_spec_cur->max_lat < p_spec->max_lat ||
-          (ssr == BTA_DM_PM_SSR0 &&
-           p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr !=
-               BTA_DM_PM_SSR0)) {
-        ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr;
-      }
+    if (p_spec_cur->max_lat < p_spec->max_lat ||
+        (ssr_index == BTA_DM_PM_SSR0 && current_ssr_index != BTA_DM_PM_SSR0)) {
+      ssr_index = current_ssr_index;
+      p_spec = &p_bta_dm_ssr_spec[ssr_index];
     }
   }
 
-  p_spec = &p_bta_dm_ssr_spec[ssr];
-  APPL_TRACE_WARNING("%s ssr:%d, lat:%d", __func__, ssr, p_spec->max_lat);
+  APPL_TRACE_WARNING("%s ssr:%d, lat:%d", __func__, ssr_index, p_spec->max_lat);
 
   if (p_spec->max_lat) {
     /* Avoid SSR reset on device which has SCO connected */
@@ -843,29 +833,12 @@
   BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr, &pm);
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_pm_btm_cback
- *
- * Description      BTM power manager callback.
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** BTM power manager callback */
 static void bta_dm_pm_btm_cback(const RawAddress& bd_addr,
                                 tBTM_PM_STATUS status, uint16_t value,
                                 uint8_t hci_status) {
-  tBTA_DM_PM_BTM_STATUS* p_buf =
-      (tBTA_DM_PM_BTM_STATUS*)osi_malloc(sizeof(tBTA_DM_PM_BTM_STATUS));
-
-  p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT;
-  p_buf->status = status;
-  p_buf->value = value;
-  p_buf->hci_status = hci_status;
-  p_buf->bd_addr = bd_addr;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_pm_btm_status, bd_addr, status,
+                                         value, hci_status));
 }
 
 /*******************************************************************************
@@ -905,51 +878,35 @@
   /* no more timers */
   if (i == BTA_DM_NUM_PM_TIMER) return;
 
-  tBTA_DM_PM_TIMER* p_buf =
-      (tBTA_DM_PM_TIMER*)osi_malloc(sizeof(tBTA_DM_PM_TIMER));
-  p_buf->hdr.event = BTA_DM_PM_TIMER_EVT;
-  p_buf->pm_request = bta_dm_cb.pm_timer[i].pm_action[j];
-  p_buf->bd_addr = bta_dm_cb.pm_timer[i].peer_bdaddr;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(
+      FROM_HERE, base::Bind(bta_dm_pm_timer, bta_dm_cb.pm_timer[i].peer_bdaddr,
+                            bta_dm_cb.pm_timer[i].pm_action[j]));
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_pm_btm_status
- *
- * Description      Process pm status event from btm
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_pm_btm_status(tBTA_DM_MSG* p_data) {
-  APPL_TRACE_DEBUG("%s status: %d", __func__, p_data->pm_status.status);
+/** Process pm status event from btm */
+void bta_dm_pm_btm_status(const RawAddress& bd_addr, tBTM_PM_STATUS status,
+                          uint16_t value, uint8_t hci_status) {
+  APPL_TRACE_DEBUG("%s status: %d", __func__, status);
 
-  tBTA_DM_PEER_DEVICE* p_dev =
-      bta_dm_find_peer_device(p_data->pm_status.bd_addr);
+  tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr);
   if (NULL == p_dev) return;
 
   tBTA_DM_DEV_INFO info = p_dev->info;
   /* check new mode */
-  switch (p_data->pm_status.status) {
+  switch (status) {
     case BTM_PM_STS_ACTIVE:
       /* if our sniff or park attempt failed
       we should not try it again*/
-      if (p_data->pm_status.hci_status != 0) {
-        APPL_TRACE_ERROR("%s hci_status=%d", __func__,
-                         p_data->pm_status.hci_status);
+      if (hci_status != 0) {
+        APPL_TRACE_ERROR("%s hci_status=%d", __func__, hci_status);
         p_dev->info &=
             ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
 
         if (p_dev->pm_mode_attempted & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) {
           p_dev->pm_mode_failed |=
               ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted);
-          bta_dm_pm_stop_timer_by_mode(p_data->pm_status.bd_addr,
-                                       p_dev->pm_mode_attempted);
-          bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION,
-                             BTA_DM_PM_RESTART);
+          bta_dm_pm_stop_timer_by_mode(bd_addr, p_dev->pm_mode_attempted);
+          bta_dm_pm_set_mode(bd_addr, BTA_DM_PM_NO_ACTION, BTA_DM_PM_RESTART);
         }
       } else {
 #if (BTM_SSR_INCLUDED == TRUE)
@@ -961,9 +918,8 @@
 #endif
         /* link to active mode, need to restart the timer for next low power
          * mode if needed */
-        bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
-        bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION,
-                           BTA_DM_PM_RESTART);
+        bta_dm_pm_stop_timer(bd_addr);
+        bta_dm_pm_set_mode(bd_addr, BTA_DM_PM_NO_ACTION, BTA_DM_PM_RESTART);
       }
       break;
 
@@ -973,26 +929,25 @@
       /* save the previous low power mode - for SSR.
        * SSR parameters are sent to controller on "conn open".
        * the numbers stay good until park/hold/detach */
-      if (p_dev->info & BTA_DM_DI_USE_SSR)
-        p_dev->prev_low = p_data->pm_status.status;
+      if (p_dev->info & BTA_DM_DI_USE_SSR) p_dev->prev_low = status;
       break;
 
     case BTM_PM_STS_SSR:
-      if (p_data->pm_status.value)
+      if (value)
         p_dev->info |= BTA_DM_DI_USE_SSR;
       else
         p_dev->info &= ~BTA_DM_DI_USE_SSR;
       break;
 #endif
     case BTM_PM_STS_SNIFF:
-      if (p_data->pm_status.hci_status == 0) {
+      if (hci_status == 0) {
         /* Stop PM timer now if already active for
          * particular device since link is already
          * put in sniff mode by remote device, and
          * PM timer sole purpose is to put the link
          * in sniff mode from host side.
          */
-        bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+        bta_dm_pm_stop_timer(bd_addr);
       } else {
         p_dev->info &=
             ~(BTA_DM_DI_SET_SNIFF | BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF);
@@ -1012,20 +967,10 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_pm_timer
- *
- * Description      Process pm timer event from btm
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_pm_timer(tBTA_DM_MSG* p_data) {
+/** Process pm timer event from btm */
+void bta_dm_pm_timer(const RawAddress& bd_addr, tBTA_DM_PM_ACTION pm_request) {
   APPL_TRACE_EVENT("%s", __func__);
-  bta_dm_pm_set_mode(p_data->pm_timer.bd_addr, p_data->pm_timer.pm_request,
-                     BTA_DM_PM_EXECUTE);
+  bta_dm_pm_set_mode(bd_addr, pm_request, BTA_DM_PM_EXECUTE);
 }
 
 /*******************************************************************************
@@ -1075,6 +1020,7 @@
   return bScoActive;
 }
 
+#if (BTM_SSR_INCLUDED == TRUE)
 /*******************************************************************************
  *
  * Function        bta_dm_get_sco_index
@@ -1094,6 +1040,7 @@
   }
   return -1;
 }
+#endif
 
 /*******************************************************************************
  *
diff --git a/bta/dm/bta_dm_sco.cc b/bta/dm/bta_dm_sco.cc
deleted file mode 100644
index 4757a53..0000000
--- a/bta/dm/bta_dm_sco.cc
+++ /dev/null
@@ -1,667 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2003-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- *  This file contains the down sampling utility to convert PCM samples in
- *  16k/32k/48k/44.1k/22050/11025 sampling rate into 8K/16bits samples
- *  required for SCO channel format. One API function isprovided and only
- *  possible to be used when transmitting SCO data is sent via HCI
- *  interface.
- *
- ******************************************************************************/
-#include <string.h>
-
-#include "bta_api.h"
-#include "bta_sys.h"
-
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-
-#ifndef BTA_DM_SCO_DEBUG
-#define BTA_DM_SCO_DEBUG false
-#endif
-/*****************************************************************************
- *  Constants
- ****************************************************************************/
-
-#define BTA_DM_PCM_OVERLAP_SIZE 48
-
-#define BTA_DM_PCM_SMPL_RATE_44100 44100
-#define BTA_DM_PCM_SMPL_RATE_22050 22050
-#define BTA_DM_PCM_SMPL_RATE_11025 11025
-
-/*****************************************************************************
- *  Data types for PCM Resampling utility
- ****************************************************************************/
-
-typedef int32_t (*PCONVERT_TO_BT_FILTERED)(uint8_t* pSrc, void* pDst,
-                                           uint32_t dwSrcSamples,
-                                           uint32_t dwSrcSps,
-                                           int32_t* pLastCurPos,
-                                           uint8_t* pOverlapArea);
-typedef int32_t (*PCONVERT_TO_BT_NOFILTER)(void* pSrc, void* pDst,
-                                           uint32_t dwSrcSamples,
-                                           uint32_t dwSrcSps);
-typedef struct {
-  uint8_t overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4];
-  uint32_t cur_pos;                 /* current position */
-  uint32_t src_sps;                 /* samples per second (source audio data) */
-  PCONVERT_TO_BT_FILTERED filter;   /* the action function to do the
-                             conversion 44100, 22050, 11025*/
-  PCONVERT_TO_BT_NOFILTER nofilter; /* the action function to do
-                               the conversion 48000, 32000, 16000*/
-  uint32_t bits;                    /* number of bits per pcm sample */
-  uint32_t n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */
-  uint32_t sample_size;
-  uint32_t can_be_filtered;
-  uint32_t divisor;
-} tBTA_DM_PCM_RESAMPLE_CB;
-
-tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb;
-
-/*****************************************************************************
- *  Macro Definition
- ****************************************************************************/
-
-#define CHECK_SATURATION16(x) \
-  do {                        \
-    if ((x) > 32767)          \
-      (x) = 32767;            \
-    else if ((x) < -32768)    \
-      (x) = -32768;           \
-  } while (0)
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd)          \
-  do {                                                    \
-    int32_t out1, out2, out3, out4, out5;                 \
-    SRC_TYPE* pS = (SRC_TYPE*)(pStart);                   \
-    SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd);                  \
-                                                          \
-    while (pS < pSEnd) {                                  \
-      CurrentPos -= 8000;                                 \
-                                                          \
-      if (CurrentPos >= 0) {                              \
-        pS += SRC_CHANNELS;                               \
-        continue;                                         \
-      }                                                   \
-      CurrentPos += dwSrcSps;                             \
-                                                          \
-      out1 = (SRC_SAMPLE(0) * 1587) +                     \
-             ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522) +  \
-             ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337) +  \
-             ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058);   \
-                                                          \
-      out1 = out1 / 30000;                                \
-                                                          \
-      out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725) +   \
-             ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384) +   \
-             ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79);     \
-                                                          \
-      out2 = out2 / 30000;                                \
-                                                          \
-      out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156) +   \
-             ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298) +   \
-             ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345);    \
-                                                          \
-      out3 = out3 / 30000;                                \
-                                                          \
-      out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306) + \
-             ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207) + \
-             ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78);   \
-                                                          \
-      out4 = out4 / 30000;                                \
-                                                          \
-      out5 = out1 + out2 - out3 - out4;                   \
-                                                          \
-      CHECK_SATURATION16(out5);                           \
-      *psBtOut++ = (int16_t)out5;                         \
-                                                          \
-      pS += SRC_CHANNELS;                                 \
-    }                                                     \
-  } while (0)
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd)         \
-  do {                                                   \
-    int32_t out1, out2, out3, out4, out5;                \
-    SRC_TYPE* pS = (SRC_TYPE*)(pStart);                  \
-    SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd);                 \
-                                                         \
-    while (pS < pSEnd) {                                 \
-      CurrentPos -= 8000;                                \
-                                                         \
-      if (CurrentPos >= 0) {                             \
-        pS += SRC_CHANNELS;                              \
-        continue;                                        \
-      }                                                  \
-      CurrentPos += dwSrcSps;                            \
-                                                         \
-      out1 = (SRC_SAMPLE(0) * 2993) +                    \
-             ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568) + \
-             ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509) + \
-             ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331);   \
-                                                         \
-      out1 = out1 / 30000;                               \
-                                                         \
-      out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454) +  \
-             ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620) +  \
-             ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305);   \
-                                                         \
-      out2 = out2 / 30000;                               \
-                                                         \
-      out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127) +  \
-             ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350) +  \
-             ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265) +  \
-             ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6);   \
-                                                         \
-      out3 = out3 / 30000;                               \
-                                                         \
-      out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201); \
-                                                         \
-      out4 = out4 / 30000;                               \
-                                                         \
-      out5 = out1 - out2 + out3 - out4;                  \
-                                                         \
-      CHECK_SATURATION16(out5);                          \
-      *psBtOut++ = (int16_t)out5;                        \
-                                                         \
-      pS += SRC_CHANNELS;                                \
-    }                                                    \
-  } while (0)
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd)         \
-  do {                                                   \
-    int32_t out1;                                        \
-    SRC_TYPE* pS = (SRC_TYPE*)(pStart);                  \
-    SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd);                 \
-                                                         \
-    while (pS < pSEnd) {                                 \
-      CurrentPos -= 8000;                                \
-                                                         \
-      if (CurrentPos >= 0) {                             \
-        pS += SRC_CHANNELS;                              \
-        continue;                                        \
-      }                                                  \
-      CurrentPos += dwSrcSps;                            \
-                                                         \
-      out1 = (SRC_SAMPLE(0) * 6349) +                    \
-             ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874) - \
-             ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148) - \
-             ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287) +  \
-             ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675) -  \
-             ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258) -  \
-             ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206) +  \
-             ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266);   \
-                                                         \
-      out1 = out1 / 30000;                               \
-                                                         \
-      CHECK_SATURATION16(out1);                          \
-      *psBtOut++ = (int16_t)out1;                        \
-                                                         \
-      pS += SRC_CHANNELS;                                \
-    }                                                    \
-  } while (0)
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#undef SRC_CHANNELS
-#undef SRC_SAMPLE
-#undef SRC_TYPE
-
-#define SRC_TYPE uint8_t
-#define SRC_CHANNELS 1
-#define SRC_SAMPLE(x) ((pS[x] - 0x80) << 8)
-
-/*****************************************************************************
- *  Local Function
- ****************************************************************************/
-int32_t Convert_8M_ToBT_Filtered(uint8_t* pSrc, void* pDst,
-                                 uint32_t dwSrcSamples, uint32_t dwSrcSps,
-                                 int32_t* pLastCurPos, uint8_t* pOverlapArea) {
-  int32_t CurrentPos = *pLastCurPos;
-  SRC_TYPE *pIn, *pInEnd;
-  SRC_TYPE *pOv, *pOvEnd;
-  int16_t* psBtOut = (int16_t*)pDst;
-#if (BTA_DM_SCO_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("Convert_8M_ToBT_Filtered,  CurrentPos %d\n", CurrentPos);
-#endif
-  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
-  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
-
-  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
-  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                       BTA_DM_PCM_OVERLAP_SIZE);
-
-  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
-    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
-    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
-    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
-  }
-
-  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  *pLastCurPos = CurrentPos;
-
-  return (psBtOut - (int16_t*)pDst);
-}
-
-int32_t Convert_8M_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
-                                 uint32_t dwSrcSps) {
-  int32_t CurrentPos;
-  uint8_t* pbSrc = (uint8_t*)pSrc;
-  int16_t* psDst = (int16_t*)pDst;
-  int16_t sWorker;
-
-  //      start at dwSpsSrc / 2, decrement by 8000
-  //
-  CurrentPos = (dwSrcSps >> 1);
-
-  while (dwSrcSamples--) {
-    CurrentPos -= 8000;
-
-    if (CurrentPos >= 0)
-      pbSrc++;
-    else {
-      sWorker = *pbSrc++;
-      sWorker -= 0x80;
-      sWorker <<= 8;
-
-      *psDst++ = sWorker;
-
-      CurrentPos += dwSrcSps;
-    }
-  }
-
-  return (psDst - (int16_t*)pDst);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#undef SRC_CHANNELS
-#undef SRC_SAMPLE
-#undef SRC_TYPE
-
-#define SRC_TYPE int16_t
-#define SRC_CHANNELS 1
-#define SRC_SAMPLE(x) pS[x]
-
-int32_t Convert_16M_ToBT_Filtered(uint8_t* pSrc, void* pDst,
-                                  uint32_t dwSrcSamples, uint32_t dwSrcSps,
-                                  int32_t* pLastCurPos, uint8_t* pOverlapArea) {
-  int32_t CurrentPos = *pLastCurPos;
-  SRC_TYPE *pIn, *pInEnd;
-  SRC_TYPE *pOv, *pOvEnd;
-  int16_t* psBtOut = (int16_t*)pDst;
-
-  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
-  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
-
-  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
-  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                       BTA_DM_PCM_OVERLAP_SIZE);
-
-  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
-    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
-    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
-    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
-  }
-
-  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  *pLastCurPos = CurrentPos;
-
-  return (psBtOut - (int16_t*)pDst);
-}
-
-int32_t Convert_16M_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
-                                  uint32_t dwSrcSps) {
-  int32_t CurrentPos;
-  int16_t* psSrc = (int16_t*)pSrc;
-  int16_t* psDst = (int16_t*)pDst;
-
-  //      start at dwSpsSrc / 2, decrement by 8000
-  //
-  CurrentPos = (dwSrcSps >> 1);
-
-  while (dwSrcSamples--) {
-    CurrentPos -= 8000;
-
-    if (CurrentPos >= 0)
-      psSrc++;
-    else {
-      *psDst++ = *psSrc++;
-
-      CurrentPos += dwSrcSps;
-    }
-  }
-
-  return (psDst - (int16_t*)pDst);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#undef SRC_CHANNELS
-#undef SRC_SAMPLE
-#undef SRC_TYPE
-
-#define SRC_TYPE uint8_t
-#define SRC_CHANNELS 2
-#define SRC_SAMPLE(x) \
-  ((((pS[x * 2] - 0x80) << 8) + ((pS[(x * 2) + 1] - 0x80) << 8)) >> 1)
-
-int32_t Convert_8S_ToBT_Filtered(uint8_t* pSrc, void* pDst,
-                                 uint32_t dwSrcSamples, uint32_t dwSrcSps,
-                                 int32_t* pLastCurPos, uint8_t* pOverlapArea) {
-  int32_t CurrentPos = *pLastCurPos;
-  SRC_TYPE *pIn, *pInEnd;
-  SRC_TYPE *pOv, *pOvEnd;
-  int16_t* psBtOut = (int16_t*)pDst;
-
-#if (BTA_DM_SCO_DEBUG == TRUE)
-  APPL_TRACE_DEBUG(
-      "Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \
-        dwSrcSamples %d,  dwSrcSps %d",
-      CurrentPos, sizeof(SRC_TYPE), SRC_CHANNELS, dwSrcSamples, dwSrcSps);
-#endif
-  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
-  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
-
-  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
-  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                       BTA_DM_PCM_OVERLAP_SIZE);
-
-  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
-    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
-    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
-    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
-  }
-
-  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  *pLastCurPos = CurrentPos;
-
-  return (psBtOut - (int16_t*)pDst);
-}
-
-int32_t Convert_8S_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
-                                 uint32_t dwSrcSps) {
-  int32_t CurrentPos;
-  uint8_t* pbSrc = (uint8_t*)pSrc;
-  int16_t* psDst = (int16_t*)pDst;
-  int16_t sWorker, sWorker2;
-
-  //      start at dwSpsSrc / 2, decrement by 8000
-  //
-  CurrentPos = (dwSrcSps >> 1);
-
-  while (dwSrcSamples--) {
-    CurrentPos -= 8000;
-
-    if (CurrentPos >= 0)
-      pbSrc += 2;
-    else {
-      sWorker = *(unsigned char*)pbSrc;
-      sWorker -= 0x80;
-      sWorker <<= 8;
-      pbSrc++;
-
-      sWorker2 = *(unsigned char*)pbSrc;
-      sWorker2 -= 0x80;
-      sWorker2 <<= 8;
-      pbSrc++;
-
-      sWorker += sWorker2;
-      sWorker >>= 1;
-
-      *psDst++ = sWorker;
-
-      CurrentPos += dwSrcSps;
-    }
-  }
-
-  return (psDst - (int16_t*)pDst);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-#undef SRC_CHANNELS
-#undef SRC_SAMPLE
-#undef SRC_TYPE
-
-#define SRC_TYPE int16_t
-#define SRC_CHANNELS 2
-#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1)
-
-int32_t Convert_16S_ToBT_Filtered(uint8_t* pSrc, void* pDst,
-                                  uint32_t dwSrcSamples, uint32_t dwSrcSps,
-                                  int32_t* pLastCurPos, uint8_t* pOverlapArea) {
-  int32_t CurrentPos = *pLastCurPos;
-  SRC_TYPE *pIn, *pInEnd;
-  SRC_TYPE *pOv, *pOvEnd;
-  int16_t* psBtOut = (int16_t*)pDst;
-
-  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
-  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
-
-  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
-  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                       BTA_DM_PCM_OVERLAP_SIZE);
-
-  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
-    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
-    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
-  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
-    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
-    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
-  }
-
-  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
-                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
-         BTA_DM_PCM_OVERLAP_SIZE * 2);
-
-  *pLastCurPos = CurrentPos;
-
-  return (psBtOut - (int16_t*)pDst);
-}
-
-int32_t Convert_16S_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
-                                  uint32_t dwSrcSps) {
-  int32_t CurrentPos;
-  int16_t* psSrc = (int16_t*)pSrc;
-  int16_t* psDst = (int16_t*)pDst;
-  int16_t sWorker;
-
-  //      start at dwSpsSrc / 2, decrement by 8000
-  //
-  CurrentPos = (dwSrcSps >> 1);
-
-  while (dwSrcSamples--) {
-    CurrentPos -= 8000;
-
-    if (CurrentPos >= 0)
-      psSrc += 2;
-    else {
-      /* CR 82894, to avoid overflow, divide before add */
-      sWorker = ((*psSrc) >> 1);
-      psSrc++;
-      sWorker += ((*psSrc) >> 1);
-      psSrc++;
-
-      *psDst++ = sWorker;
-
-      CurrentPos += dwSrcSps;
-    }
-  }
-
-  return (psDst - (int16_t*)pDst);
-}
-
-/*******************************************************************************
- *
- * Function         BTA_DmPcmInitSamples
- *
- * Description      initialize the down sample converter.
- *
- *                  src_sps: original samples per second (source audio data)
- *                            (ex. 44100, 48000)
- *                  bits: number of bits per pcm sample (16)
- *                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
- *
- * Returns          none
- *
- ******************************************************************************/
-void BTA_DmPcmInitSamples(uint32_t src_sps, uint32_t bits,
-                          uint32_t n_channels) {
-  tBTA_DM_PCM_RESAMPLE_CB* p_cb = &bta_dm_pcm_cb;
-
-  p_cb->cur_pos = src_sps / 2;
-  p_cb->src_sps = src_sps;
-  p_cb->bits = bits;
-  p_cb->n_channels = n_channels;
-  p_cb->sample_size = 2;
-  p_cb->divisor = 2;
-
-  memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area));
-
-  if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) ||
-      (src_sps == BTA_DM_PCM_SMPL_RATE_22050) ||
-      (src_sps == BTA_DM_PCM_SMPL_RATE_11025))
-    p_cb->can_be_filtered = 1;
-  else
-    p_cb->can_be_filtered = 0;
-
-#if (BTA_DM_SCO_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("bta_dm_pcm_init_samples: n_channels = %d bits = %d",
-                   n_channels, bits);
-#endif
-  if (n_channels == 1) {
-    /* mono */
-    if (bits == 8) {
-      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_8M_ToBT_Filtered;
-      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_8M_ToBT_NoFilter;
-      p_cb->divisor = 1;
-    } else {
-      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_16M_ToBT_Filtered;
-      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_16M_ToBT_NoFilter;
-    }
-  } else {
-    /* stereo */
-    if (bits == 8) {
-      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_8S_ToBT_Filtered;
-      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_8S_ToBT_NoFilter;
-    } else {
-      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_16S_ToBT_Filtered;
-      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_16S_ToBT_NoFilter;
-      p_cb->divisor = 4;
-    }
-  }
-
-#if (BTA_DM_SCO_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d",
-                   p_cb->cur_pos, p_cb->src_sps);
-  APPL_TRACE_DEBUG(
-      "bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ",
-      p_cb->bits, p_cb->n_channels, p_cb->sample_size);
-  APPL_TRACE_DEBUG(
-      "bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \
-        divisor %d",
-      p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor);
-#endif
-}
-
-/*******************************************************************************
- * Function         BTA_DmPcmResample
- *
- * Description      Down sampling utility to convert higher sampling rate into
- *                  8K/16bits PCM samples.
- *
- * Parameters       p_src: pointer to the buffer where the original sampling PCM
- *                              are stored.
- *                  in_bytes:  Length of the input PCM sample buffer in byte.
- *                  p_dst:      pointer to the buffer which is to be used to
- *                              store the converted PCM samples.
- *
- *
- * Returns          int32_t: number of samples converted.
- *
- ******************************************************************************/
-int32_t BTA_DmPcmResample(void* p_src, uint32_t in_bytes, void* p_dst) {
-  uint32_t out_sample;
-
-#if (BTA_DM_SCO_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("bta_pcm_resample : insamples  %d",
-                   (in_bytes / bta_dm_pcm_cb.divisor));
-#endif
-  if (bta_dm_pcm_cb.can_be_filtered) {
-    out_sample = (*bta_dm_pcm_cb.filter)(
-        p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps,
-        (int32_t*)&bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area);
-  } else {
-    out_sample = (*bta_dm_pcm_cb.nofilter)(p_src, p_dst,
-                                           (in_bytes / bta_dm_pcm_cb.divisor),
-                                           bta_dm_pcm_cb.src_sps);
-  }
-
-#if (BTA_DM_SCO_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("bta_pcm_resample : outsamples  %d", out_sample);
-#endif
-
-  return (out_sample * bta_dm_pcm_cb.sample_size);
-}
-#endif
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index 8b482b8..8a137dc 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -44,6 +44,9 @@
 #include "bta_hh_int.h"
 #endif
 
+using base::StringPrintf;
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
@@ -56,7 +59,7 @@
                                  tGATT_STATUS status,
                                  tGATT_CL_COMPLETE* p_data);
 static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op,
-                                   tBTA_GATT_STATUS status,
+                                   tGATT_STATUS status,
                                    tGATT_CL_COMPLETE* p_data);
 
 static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg);
@@ -81,79 +84,74 @@
 
 /* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */
 static uint16_t bta_gattc_opcode_to_int_evt[] = {
-    BTA_GATTC_API_READ_EVT, BTA_GATTC_API_WRITE_EVT, BTA_GATTC_API_EXEC_EVT,
-    BTA_GATTC_API_CFG_MTU_EVT};
+    /* Skip: GATTC_OPTYPE_NONE */
+    /* Skip: GATTC_OPTYPE_DISCOVERY */
+    BTA_GATTC_API_READ_EVT,   /* GATTC_OPTYPE_READ */
+    BTA_GATTC_API_WRITE_EVT,  /* GATTC_OPTYPE_WRITE */
+    BTA_GATTC_API_EXEC_EVT,   /* GATTC_OPTYPE_EXE_WRITE */
+    BTA_GATTC_API_CFG_MTU_EVT /* GATTC_OPTYPE_CONFIG */
+};
 
 static const char* bta_gattc_op_code_name[] = {
-    "Unknown", "Discovery", "Read",         "Write",
-    "Exec",    "Config",    "Notification", "Indication"};
+    "Unknown",      /* GATTC_OPTYPE_NONE */
+    "Discovery",    /* GATTC_OPTYPE_DISCOVERY */
+    "Read",         /* GATTC_OPTYPE_READ */
+    "Write",        /* GATTC_OPTYPE_WRITE */
+    "Exec",         /* GATTC_OPTYPE_EXE_WRITE */
+    "Config",       /* GATTC_OPTYPE_CONFIG */
+    "Notification", /* GATTC_OPTYPE_NOTIFICATION */
+    "Indication"    /* GATTC_OPTYPE_INDICATION */
+};
+
 /*****************************************************************************
  *  Action Functions
  ****************************************************************************/
 
-void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
-                                 tBTA_GATT_STATUS status);
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb, tGATT_STATUS status);
 
-/*******************************************************************************
- *
- * Function         bta_gattc_enable
- *
- * Description      Enables GATTC module
- *
- *
- * Returns          void
- *
- ******************************************************************************/
+/** Enables GATTC module */
 static void bta_gattc_enable() {
-  APPL_TRACE_DEBUG("%s", __func__);
+  VLOG(1) << __func__;
 
   if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
     /* initialize control block */
-    memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB));
+    bta_gattc_cb = tBTA_GATTC_CB();
     bta_gattc_cb.state = BTA_GATTC_STATE_ENABLED;
   } else {
-    APPL_TRACE_DEBUG("GATTC is already enabled");
+    VLOG(1) << "GATTC is already enabled";
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_disable
- *
- * Description      Disable GATTC module by cleaning up all active connections
- *                  and deregister all application.
- *
- * Returns          void
- *
- ******************************************************************************/
+/** Disable GATTC module by cleaning up all active connections and deregister
+ * all application */
 void bta_gattc_disable() {
   uint8_t i;
 
-  APPL_TRACE_DEBUG("%s", __func__);
+  VLOG(1) << __func__;
 
   if (bta_gattc_cb.state != BTA_GATTC_STATE_ENABLED) {
-    APPL_TRACE_ERROR("not enabled, or disabled in progress");
+    LOG(ERROR) << "not enabled, or disabled in progress";
     return;
   }
 
   for (i = 0; i < BTA_GATTC_CL_MAX; i++) {
-    if (bta_gattc_cb.cl_rcb[i].in_use) {
-      bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING;
+    if (!bta_gattc_cb.cl_rcb[i].in_use) continue;
+
+    bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING;
 /* don't deregister HH GATT IF */
 /* HH GATT IF will be deregistered by bta_hh_le_deregister when disable HH */
 #if (BTA_HH_LE_INCLUDED == TRUE)
-      if (!bta_hh_le_is_hh_gatt_if(bta_gattc_cb.cl_rcb[i].client_if)) {
+    if (!bta_hh_le_is_hh_gatt_if(bta_gattc_cb.cl_rcb[i].client_if)) {
 #endif
-        bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]);
+      bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]);
 #if (BTA_HH_LE_INCLUDED == TRUE)
-      }
-#endif
     }
+#endif
   }
 
   /* no registered apps, indicate disable completed */
   if (bta_gattc_cb.state != BTA_GATTC_STATE_DISABLING) {
-    memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB));
+    bta_gattc_cb = tBTA_GATTC_CB();
     bta_gattc_cb.state = BTA_GATTC_STATE_DISABLED;
   }
 }
@@ -161,7 +159,7 @@
 /** start an application interface */
 void bta_gattc_start_if(uint8_t client_if) {
   if (!bta_gattc_cl_get_regcb(client_if)) {
-    APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d", client_if);
+    LOG(ERROR) << "Unable to start app.: Unknown client_if=" << +client_if;
     return;
   }
 
@@ -169,11 +167,11 @@
 }
 
 /** Register a GATT client application with BTA */
-void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_cback,
+void bta_gattc_register(const Uuid& app_uuid, tBTA_GATTC_CBACK* p_cback,
                         BtaAppRegisterCallback cb) {
-  tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+  tGATT_STATUS status = GATT_NO_RESOURCES;
   uint8_t client_if = 0;
-  APPL_TRACE_DEBUG("%s: state %d", __func__, bta_gattc_cb.state);
+  VLOG(1) << __func__ << ": state:" << +bta_gattc_cb.state;
 
   /* check if  GATTC module is already enabled . Else enable */
   if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
@@ -182,22 +180,21 @@
   /* todo need to check duplicate uuid */
   for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) {
     if (!bta_gattc_cb.cl_rcb[i].in_use) {
-      if ((p_app_uuid == NULL) ||
-          (bta_gattc_cb.cl_rcb[i].client_if =
-               GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0) {
-        APPL_TRACE_ERROR("Register with GATT stack failed.");
-        status = BTA_GATT_ERROR;
+      if ((bta_gattc_cb.cl_rcb[i].client_if =
+               GATT_Register(app_uuid, &bta_gattc_cl_cback)) == 0) {
+        LOG(ERROR) << "Register with GATT stack failed.";
+        status = GATT_ERROR;
       } else {
         bta_gattc_cb.cl_rcb[i].in_use = true;
         bta_gattc_cb.cl_rcb[i].p_cback = p_cback;
-        memcpy(&bta_gattc_cb.cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));
+        bta_gattc_cb.cl_rcb[i].app_uuid = app_uuid;
 
         /* BTA use the same client interface as BTE GATT statck */
         client_if = bta_gattc_cb.cl_rcb[i].client_if;
 
         do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_start_if, client_if));
 
-        status = BTA_GATT_OK;
+        status = GATT_SUCCESS;
         break;
       }
     }
@@ -206,202 +203,150 @@
   if (!cb.is_null()) cb.Run(client_if, status);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_deregister
- *
- * Description      De-Register a GATT client application with BTA.
- *
- * Returns          void
- *
- ******************************************************************************/
+/** De-Register a GATT client application with BTA */
 void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) {
-  uint8_t i;
-  BT_HDR buf;
-
-  if (p_clreg != NULL) {
-    /* remove bg connection associated with this rcb */
-    for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++) {
-      if (bta_gattc_cb.bg_track[i].in_use) {
-        if (bta_gattc_cb.bg_track[i].cif_mask &
-            (1 << (p_clreg->client_if - 1))) {
-          bta_gattc_mark_bg_conn(p_clreg->client_if,
-                                 bta_gattc_cb.bg_track[i].remote_bda, false);
-          GATT_CancelConnect(p_clreg->client_if,
-                             bta_gattc_cb.bg_track[i].remote_bda, false);
-        }
-      }
-    }
-
-    if (p_clreg->num_clcb > 0) {
-      /* close all CLCB related to this app */
-      for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
-        if (bta_gattc_cb.clcb[i].in_use &&
-            (bta_gattc_cb.clcb[i].p_rcb == p_clreg)) {
-          p_clreg->dereg_pending = true;
-
-          buf.event = BTA_GATTC_API_CLOSE_EVT;
-          buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id;
-          bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf);
-        }
-      }
-    } else
-      bta_gattc_deregister_cmpl(p_clreg);
-  } else {
-    APPL_TRACE_ERROR("%s: Deregister Failed unknown client cif", __func__);
+  if (!p_clreg) {
+    LOG(ERROR) << __func__ << ": Deregister Failed unknown client cif";
     bta_hh_cleanup_disable(BTA_HH_OK);
+    return;
+  }
+
+  /* remove bg connection associated with this rcb */
+  for (uint8_t i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++) {
+    if (!bta_gattc_cb.bg_track[i].in_use) continue;
+
+    if (bta_gattc_cb.bg_track[i].cif_mask & (1 << (p_clreg->client_if - 1))) {
+      bta_gattc_mark_bg_conn(p_clreg->client_if,
+                             bta_gattc_cb.bg_track[i].remote_bda, false);
+      GATT_CancelConnect(p_clreg->client_if,
+                         bta_gattc_cb.bg_track[i].remote_bda, false);
+    }
+  }
+
+  if (p_clreg->num_clcb == 0) {
+    bta_gattc_deregister_cmpl(p_clreg);
+    return;
+  }
+
+  /* close all CLCB related to this app */
+  for (uint8_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+    if (!bta_gattc_cb.clcb[i].in_use || (bta_gattc_cb.clcb[i].p_rcb != p_clreg))
+      continue;
+
+    p_clreg->dereg_pending = true;
+
+    BT_HDR buf;
+    buf.event = BTA_GATTC_API_CLOSE_EVT;
+    buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id;
+    bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_process_api_open
- *
- * Description      process connect API request.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** process connect API request */
 void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg) {
   uint16_t event = ((BT_HDR*)p_msg)->event;
-  tBTA_GATTC_CLCB* p_clcb = NULL;
+
   tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);
+  if (!p_clreg) {
+    LOG(ERROR) << __func__
+               << ": Failed, unknown client_if=" << +p_msg->api_conn.client_if;
+    return;
+  }
 
-  if (p_clreg != NULL) {
-    if (p_msg->api_conn.is_direct) {
-      p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if,
-                                         p_msg->api_conn.remote_bda,
-                                         p_msg->api_conn.transport);
-      if (p_clcb != NULL) {
-        bta_gattc_sm_execute(p_clcb, event, p_msg);
-      } else {
-        APPL_TRACE_ERROR("No resources to open a new connection.");
+  if (!p_msg->api_conn.is_direct) {
+    bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
+    return;
+  }
 
-        bta_gattc_send_open_cback(
-            p_clreg, BTA_GATT_NO_RESOURCES, p_msg->api_conn.remote_bda,
-            BTA_GATT_INVALID_CONN_ID, p_msg->api_conn.transport, 0);
-      }
-    } else {
-      bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
-    }
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_alloc_clcb(
+      p_msg->api_conn.client_if, p_msg->api_conn.remote_bda,
+      p_msg->api_conn.transport);
+  if (p_clcb != NULL) {
+    bta_gattc_sm_execute(p_clcb, event, p_msg);
   } else {
-    APPL_TRACE_ERROR("%s: Failed, unknown client_if: %d", __func__,
-                     p_msg->api_conn.client_if);
+    LOG(ERROR) << "No resources to open a new connection.";
+
+    bta_gattc_send_open_cback(p_clreg, GATT_NO_RESOURCES,
+                              p_msg->api_conn.remote_bda, GATT_INVALID_CONN_ID,
+                              p_msg->api_conn.transport, 0);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_process_api_open_cancel
- *
- * Description      process connect API request.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** process connect API request */
 void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg) {
   uint16_t event = ((BT_HDR*)p_msg)->event;
-  tBTA_GATTC_CLCB* p_clcb = NULL;
-  tBTA_GATTC_RCB* p_clreg;
-  tBTA_GATTC cb_data;
 
-  if (p_msg->api_cancel_conn.is_direct) {
-    p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if,
-                                        p_msg->api_cancel_conn.remote_bda,
-                                        BTA_GATT_TRANSPORT_LE);
-    if (p_clcb != NULL) {
-      bta_gattc_sm_execute(p_clcb, event, p_msg);
-    } else {
-      APPL_TRACE_ERROR("No such connection need to be cancelled");
-
-      p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if);
-
-      if (p_clreg && p_clreg->p_cback) {
-        cb_data.status = BTA_GATT_ERROR;
-        (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
-      }
-    }
-  } else {
+  if (!p_msg->api_cancel_conn.is_direct) {
     bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn);
+    return;
+  }
+
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_cif(
+      p_msg->api_cancel_conn.client_if, p_msg->api_cancel_conn.remote_bda,
+      GATT_TRANSPORT_LE);
+  if (p_clcb != NULL) {
+    bta_gattc_sm_execute(p_clcb, event, p_msg);
+    return;
+  }
+
+  LOG(ERROR) << "No such connection need to be cancelled";
+
+  tBTA_GATTC_RCB* p_clreg =
+      bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if);
+
+  if (p_clreg && p_clreg->p_cback) {
+    tBTA_GATTC cb_data;
+    cb_data.status = GATT_ERROR;
+    (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
   }
 }
 
 /** process encryption complete message */
 void bta_gattc_process_enc_cmpl(tGATT_IF client_if, const RawAddress& bda) {
-  tBTA_GATTC_RCB* p_clreg;
+  tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(client_if);
+
+  if (!p_clreg || !p_clreg->p_cback) return;
+
   tBTA_GATTC cb_data;
+  memset(&cb_data, 0, sizeof(tBTA_GATTC));
 
-  p_clreg = bta_gattc_cl_get_regcb(client_if);
+  cb_data.enc_cmpl.client_if = client_if;
+  cb_data.enc_cmpl.remote_bda = bda;
 
-  if (p_clreg && p_clreg->p_cback) {
-    memset(&cb_data, 0, sizeof(tBTA_GATTC));
-
-    cb_data.enc_cmpl.client_if = client_if;
-    cb_data.enc_cmpl.remote_bda = bda;
-
-    (*p_clreg->p_cback)(BTA_GATTC_ENC_CMPL_CB_EVT, &cb_data);
-  }
+  (*p_clreg->p_cback)(BTA_GATTC_ENC_CMPL_CB_EVT, &cb_data);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_cancel_open_error
- *
- * Description
- *
- * Returns          void
- *
- ******************************************************************************/
 void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
                                  UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC cb_data;
 
-  cb_data.status = BTA_GATT_ERROR;
+  cb_data.status = GATT_ERROR;
 
   if (p_clcb && p_clcb->p_rcb && p_clcb->p_rcb->p_cback)
     (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_open_error
- *
- * Description
- *
- * Returns          void
- *
- ******************************************************************************/
 void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
                           UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
-  APPL_TRACE_ERROR("Connection already opened. wrong state");
+  LOG(ERROR) << "Connection already opened. wrong state";
 
-  bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_OK, p_clcb->bda,
+  bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_SUCCESS, p_clcb->bda,
                             p_clcb->bta_conn_id, p_clcb->transport, 0);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_open_fail
- *
- * Description
- *
- * Returns          void
- *
- ******************************************************************************/
+
 void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
                          UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
-  bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_ERROR, p_clcb->bda,
+  LOG(WARNING) << __func__ << ": Cannot establish Connection. conn_id="
+               << +p_clcb->bta_conn_id << ". Return GATT_ERROR(" << +GATT_ERROR
+               << ")";
+
+  bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_ERROR, p_clcb->bda,
                             p_clcb->bta_conn_id, p_clcb->transport, 0);
   /* open failure, remove clcb */
   bta_gattc_clcb_dealloc(p_clcb);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_open
- *
- * Description      Process API connection function.
- *
- * Returns          void
- *
- ******************************************************************************/
+/** Process API connection function */
 void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC_DATA gattc_data;
 
@@ -409,91 +354,72 @@
   if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, true,
                     p_data->api_conn.transport, p_data->api_conn.opportunistic,
                     p_data->api_conn.initiating_phys)) {
-    APPL_TRACE_ERROR("Connection open failure");
+    LOG(ERROR) << "Connection open failure";
 
     bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data);
-  } else {
-    /* a connected remote device */
-    if (GATT_GetConnIdIfConnected(
-            p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda,
-            &p_clcb->bta_conn_id, p_data->api_conn.transport)) {
-      gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id;
-
-      bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
-    }
-    /* else wait for the callback event */
+    return;
   }
+
+  /* a connected remote device */
+  if (GATT_GetConnIdIfConnected(
+          p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda,
+          &p_clcb->bta_conn_id, p_data->api_conn.transport)) {
+    gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id;
+
+    bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+  }
+  /* else wait for the callback event */
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_init_bk_conn
- *
- * Description      Process API Open for a background connection
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** Process API Open for a background connection */
 void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
                             tBTA_GATTC_RCB* p_clreg) {
-  tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+  if (!bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, true)) {
+    bta_gattc_send_open_cback(p_clreg, GATT_NO_RESOURCES, p_data->remote_bda,
+                              GATT_INVALID_CONN_ID, GATT_TRANSPORT_LE, 0);
+    return;
+  }
+
+  /* always call open to hold a connection */
+  if (!GATT_Connect(p_data->client_if, p_data->remote_bda, false,
+                    p_data->transport, false)) {
+    LOG(ERROR) << __func__
+               << " unable to connect to remote bd_addr=" << p_data->remote_bda;
+    bta_gattc_send_open_cback(p_clreg, GATT_ERROR, p_data->remote_bda,
+                              GATT_INVALID_CONN_ID, GATT_TRANSPORT_LE, 0);
+    return;
+  }
+
   uint16_t conn_id;
-  tBTA_GATTC_CLCB* p_clcb;
+  /* if is not a connected remote device */
+  if (!GATT_GetConnIdIfConnected(p_data->client_if, p_data->remote_bda,
+                                 &conn_id, p_data->transport)) {
+    return;
+  }
+
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_alloc_clcb(
+      p_data->client_if, p_data->remote_bda, GATT_TRANSPORT_LE);
+  if (!p_clcb) return;
+
   tBTA_GATTC_DATA gattc_data;
+  gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
 
-  if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, true)) {
-    /* always call open to hold a connection */
-    if (!GATT_Connect(p_data->client_if, p_data->remote_bda, false,
-                      p_data->transport, false)) {
-      status = BTA_GATT_ERROR;
-      LOG(ERROR) << __func__ << " unable to connect to remote bd_addr:"
-                 << p_data->remote_bda;
-
-    } else {
-      status = BTA_GATT_OK;
-
-      /* if is a connected remote device */
-      if (GATT_GetConnIdIfConnected(p_data->client_if, p_data->remote_bda,
-                                    &conn_id, p_data->transport)) {
-        p_clcb = bta_gattc_find_alloc_clcb(
-            p_data->client_if, p_data->remote_bda, BTA_GATT_TRANSPORT_LE);
-        if (p_clcb != NULL) {
-          gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
-
-          /* open connection */
-          bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
-          status = BTA_GATT_OK;
-        }
-      }
-    }
-  }
-
-  /* open failure, report OPEN_EVT */
-  if (status != BTA_GATT_OK) {
-    bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda,
-                              BTA_GATT_INVALID_CONN_ID, BTA_GATT_TRANSPORT_LE,
-                              0);
-  }
+  /* open connection */
+  bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_cancel_bk_conn
- *
- * Description      Process API Cancel Open for a background connection
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** Process API Cancel Open for a background connection */
 void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data) {
   tBTA_GATTC_RCB* p_clreg;
   tBTA_GATTC cb_data;
-  cb_data.status = BTA_GATT_ERROR;
+  cb_data.status = GATT_ERROR;
 
   /* remove the device from the bg connection mask */
   if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, false)) {
     if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, false)) {
-      cb_data.status = BTA_GATT_OK;
+      cb_data.status = GATT_SUCCESS;
     } else {
-      APPL_TRACE_ERROR("%s: failed", __func__);
+      LOG(ERROR) << __func__ << ": failed";
     }
   }
   p_clreg = bta_gattc_cl_get_regcb(p_data->client_if);
@@ -502,35 +428,19 @@
     (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_int_cancel_open_ok
- *
- * Description
- *
- * Returns          void
- *
- ******************************************************************************/
+
 void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
                               UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC cb_data;
 
   if (p_clcb->p_rcb->p_cback) {
-    cb_data.status = BTA_GATT_OK;
+    cb_data.status = GATT_SUCCESS;
     (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
   }
 
   bta_gattc_clcb_dealloc(p_clcb);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_cancel_open
- *
- * Description
- *
- * Returns          void
- *
- ******************************************************************************/
+
 void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC cb_data;
 
@@ -539,27 +449,19 @@
     bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data);
   } else {
     if (p_clcb->p_rcb->p_cback) {
-      cb_data.status = BTA_GATT_ERROR;
+      cb_data.status = GATT_ERROR;
       (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
     }
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_conn
- *
- * Description      receive connection callback from stack
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** receive connection callback from stack */
 void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
-  tBTA_GATTC_IF gatt_if;
-  APPL_TRACE_DEBUG("%s: server cache state=%d", __func__,
-                   p_clcb->p_srcb->state);
+  tGATT_IF gatt_if;
+  VLOG(1) << __func__ << ": server cache state=" << +p_clcb->p_srcb->state;
 
   if (p_data != NULL) {
-    APPL_TRACE_DEBUG("%s: conn_id=%d", __func__, p_data->hdr.layer_specific);
+    VLOG(1) << __func__ << ": conn_id=" << +p_data->hdr.layer_specific;
     p_clcb->bta_conn_id = p_data->int_conn.hdr.layer_specific;
 
     GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda,
@@ -571,13 +473,13 @@
   if (p_clcb->p_srcb->mtu == 0) p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE;
 
   /* start database cache if needed */
-  if (p_clcb->p_srcb->p_srvc_cache == NULL ||
+  if (p_clcb->p_srcb->srvc_cache.empty() ||
       p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) {
     if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) {
       p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
       if (bta_gattc_cache_load(p_clcb)) {
         p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
-        bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK);
+        bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
       } else {
         p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC;
         /* cache load failure, start discovery */
@@ -601,20 +503,13 @@
     if (p_clcb->transport == BTA_TRANSPORT_BR_EDR)
       bta_sys_conn_open(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
 
-    bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_OK, p_clcb->bda,
+    bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_SUCCESS, p_clcb->bda,
                               p_clcb->bta_conn_id, p_clcb->transport,
                               p_clcb->p_srcb->mtu);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_close_fail
- *
- * Description      close a  connection.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** close a  connection */
 void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC cb_data;
 
@@ -623,27 +518,23 @@
     cb_data.close.client_if = p_clcb->p_rcb->client_if;
     cb_data.close.conn_id = p_data->hdr.layer_specific;
     cb_data.close.remote_bda = p_clcb->bda;
-    cb_data.close.status = BTA_GATT_ERROR;
+    cb_data.close.status = GATT_ERROR;
     cb_data.close.reason = BTA_GATT_CONN_NONE;
 
+    LOG(WARNING) << __func__ << ": conn_id=" << loghex(cb_data.close.conn_id)
+                 << ". Returns GATT_ERROR(" << +GATT_ERROR << ").";
+
     (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_api_close
- *
- * Description      close a GATTC connection.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** close a GATTC connection */
 void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC_CBACK* p_cback = p_clcb->p_rcb->p_cback;
   tBTA_GATTC_RCB* p_clreg = p_clcb->p_rcb;
   tBTA_GATTC cb_data;
 
-  APPL_TRACE_DEBUG("%s: conn_id=%d", __func__, p_clcb->bta_conn_id);
+  VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
 
   cb_data.close.client_if = p_clcb->p_rcb->client_if;
   cb_data.close.conn_id = p_clcb->bta_conn_id;
@@ -669,20 +560,10 @@
     bta_gattc_deregister_cmpl(p_clreg);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_reset_discover_st
- *
- * Description      when a SRCB finished discovery, tell all related clcb.
- *
- * Returns          None.
- *
- ******************************************************************************/
-void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
-                                 tBTA_GATT_STATUS status) {
-  uint8_t i;
 
-  for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+/** when a SRCB finished discovery, tell all related clcb */
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb, tGATT_STATUS status) {
+  for (uint8_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
     if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
       bta_gattc_cb.clcb[i].status = status;
       bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT,
@@ -690,21 +571,13 @@
     }
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_disc_close
- *
- * Description      close a GATTC connection while in discovery state.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** close a GATTC connection while in discovery state */
 void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
-  APPL_TRACE_DEBUG("%s: Discovery cancel conn_id=%d", __func__,
-                   p_clcb->bta_conn_id);
+  VLOG(1) << __func__ << ": Discovery cancel conn_id=" << +p_clcb->bta_conn_id;
 
   if (p_clcb->disc_active)
-    bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_ERROR);
+    bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_ERROR);
   else
     p_clcb->state = BTA_GATTC_CONN_ST;
 
@@ -712,88 +585,55 @@
   // while in the BTA_GATTC_DISCOVER_ST state. Once the state changes, the
   // connection itself still needs to be closed to resolve the original event.
   if (p_clcb->state == BTA_GATTC_CONN_ST) {
-    APPL_TRACE_DEBUG(
-        "State is back to BTA_GATTC_CONN_ST. "
-        "Trigger connection close");
+    VLOG(1) << "State is back to BTA_GATTC_CONN_ST. Trigger connection close";
     bta_gattc_close(p_clcb, p_data);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_set_discover_st
- *
- * Description      when a SRCB start discovery, tell all related clcb and set
- *                  the state.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** when a SRCB start discovery, tell all related clcb and set the state */
 void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) {
   uint8_t i;
 
   L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, false);
   for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
     if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
-      bta_gattc_cb.clcb[i].status = BTA_GATT_OK;
+      bta_gattc_cb.clcb[i].status = GATT_SUCCESS;
       bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST;
     }
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_restart_discover
- *
- * Description      process service change in discovery state, mark up the auto
- *                  update flag and set status to be discovery cancel for
- *                  current discovery.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** process service change in discovery state, mark up the auto update flag and
+ * set status to be discovery cancel for current discovery.
+ */
 void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
                                 UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
-  p_clcb->status = BTA_GATT_CANCEL;
+  p_clcb->status = GATT_CANCEL;
   p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_cfg_mtu
- *
- * Description      Configure MTU size on the GATT connection.
- *
- * Returns          None.
- *
- ******************************************************************************/
+/** Configure MTU size on the GATT connection */
 void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
-  tBTA_GATT_STATUS status;
+  if (!bta_gattc_enqueue(p_clcb, p_data)) return;
 
-  if (bta_gattc_enqueue(p_clcb, p_data)) {
-    status = GATTC_ConfigureMTU(p_clcb->bta_conn_id, p_data->api_mtu.mtu);
+  tGATT_STATUS status =
+      GATTC_ConfigureMTU(p_clcb->bta_conn_id, p_data->api_mtu.mtu);
 
-    /* if failed, return callback here */
-    if (status != GATT_SUCCESS && status != GATT_CMD_STARTED) {
-      /* Dequeue the data, if it was enqueued */
-      if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+  /* if failed, return callback here */
+  if (status != GATT_SUCCESS && status != GATT_CMD_STARTED) {
+    /* Dequeue the data, if it was enqueued */
+    if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
 
-      bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status,
-                             NULL);
-    }
+    bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status,
+                           NULL);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_start_discover
- *
- * Description      Start a discovery on server.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** Start a discovery on server */
 void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
                               UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
-  APPL_TRACE_DEBUG("%s: conn_id=%d p_clcb->p_srcb->state = %d ", __func__,
-                   p_clcb->bta_conn_id, p_clcb->p_srcb->state);
+  VLOG(1) << __func__ << ": conn_id:" << +p_clcb->bta_conn_id
+          << " p_clcb->p_srcb->state:" << +p_clcb->p_srcb->state;
 
   if (((p_clcb->p_q_cmd == NULL ||
         p_clcb->auto_update == BTA_GATTC_REQ_WAITING) &&
@@ -816,17 +656,17 @@
       bta_gattc_set_discover_st(p_clcb->p_srcb);
 
       p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb);
-      if (p_clcb->status == BTA_GATT_OK) {
+      if (p_clcb->status == GATT_SUCCESS) {
         p_clcb->status = bta_gattc_discover_pri_service(
             p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
       }
-      if (p_clcb->status != BTA_GATT_OK) {
-        APPL_TRACE_ERROR("discovery on server failed");
+      if (p_clcb->status != GATT_SUCCESS) {
+        LOG(ERROR) << "discovery on server failed";
         bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
       } else
         p_clcb->disc_active = true;
     } else {
-      APPL_TRACE_ERROR("unknown device, can not start discovery");
+      LOG(ERROR) << "unknown device, can not start discovery";
     }
   }
   /* pending operation, wait until it finishes */
@@ -837,20 +677,13 @@
       p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_disc_cmpl
- *
- * Description      discovery on server is finished
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** discovery on server is finished */
 void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
                          UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
   tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;
 
-  APPL_TRACE_DEBUG("%s: conn_id=%d", __func__, p_clcb->bta_conn_id);
+  VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
 
   if (p_clcb->transport == BTA_TRANSPORT_LE)
     L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, true);
@@ -859,17 +692,17 @@
 
   if (p_clcb->status != GATT_SUCCESS) {
     /* clean up cache */
-    if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
-      list_free(p_clcb->p_srcb->p_srvc_cache);
-      p_clcb->p_srcb->p_srvc_cache = NULL;
+    if (p_clcb->p_srcb) {
+      // clear reallocating
+      std::vector<tBTA_GATTC_SERVICE>().swap(p_clcb->p_srcb->srvc_cache);
     }
 
     /* used to reset cache in application */
     bta_gattc_cache_reset(p_clcb->p_srcb->server_bda);
   }
-  if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_list) {
+  if (p_clcb->p_srcb) {
     /* release pending attribute list buffer */
-    osi_free_and_reset((void**)&p_clcb->p_srcb->p_srvc_list);
+    p_clcb->p_srcb->pending_discovery.clear();
   }
 
   if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
@@ -881,7 +714,8 @@
   else if (p_q_cmd != NULL) {
     p_clcb->p_q_cmd = NULL;
     /* execute pending operation of link block still present */
-    if (l2cu_find_lcb_by_bd_addr(p_clcb->p_srcb->server_bda, BT_TRANSPORT_LE)) {
+    if (l2cu_find_lcb_by_bd_addr(p_clcb->p_srcb->server_bda,
+                                 p_clcb->transport)) {
       bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd);
     }
     /* if the command executed requeued the cmd, we don't
@@ -891,19 +725,12 @@
     if (p_q_cmd != p_clcb->p_q_cmd) osi_free_and_reset((void**)&p_q_cmd);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_read
- *
- * Description      Read an attribute
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** Read an attribute */
 void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   if (!bta_gattc_enqueue(p_clcb, p_data)) return;
 
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   if (p_data->api_read.handle != 0) {
     tGATT_READ_PARAM read_param;
     memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
@@ -922,7 +749,7 @@
   }
 
   /* read fail */
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     /* Dequeue the data, if it was enqueued */
     if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
 
@@ -930,53 +757,36 @@
                            NULL);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_read_multi
- *
- * Description      read multiple
- *
- * Returns          None.
- ******************************************************************************/
+
+/** read multiple */
 void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
-  tBTA_GATT_STATUS status = BTA_GATT_OK;
+  if (!bta_gattc_enqueue(p_clcb, p_data)) return;
+
   tGATT_READ_PARAM read_param;
+  memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
 
-  if (bta_gattc_enqueue(p_clcb, p_data)) {
-    memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
+  read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr;
+  read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req;
+  memcpy(&read_param.read_multiple.handles, p_data->api_read_multi.handles,
+         sizeof(uint16_t) * p_data->api_read_multi.num_attr);
 
-    if (status == BTA_GATT_OK) {
-      read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr;
-      read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req;
-      memcpy(&read_param.read_multiple.handles, p_data->api_read_multi.handles,
-             sizeof(uint16_t) * p_data->api_read_multi.num_attr);
+  tGATT_STATUS status =
+      GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param);
+  /* read fail */
+  if (status != GATT_SUCCESS) {
+    /* Dequeue the data, if it was enqueued */
+    if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
 
-      status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param);
-    }
-
-    /* read fail */
-    if (status != BTA_GATT_OK) {
-      /* Dequeue the data, if it was enqueued */
-      if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
-
-      bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status,
-                             NULL);
-    }
+    bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status,
+                           NULL);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_write
- *
- * Description      Write an attribute
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** Write an attribute */
 void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   if (!bta_gattc_enqueue(p_clcb, p_data)) return;
 
-  tBTA_GATT_STATUS status = BTA_GATT_OK;
+  tGATT_STATUS status = GATT_SUCCESS;
   tGATT_VALUE attr;
 
   attr.conn_id = p_clcb->bta_conn_id;
@@ -992,7 +802,7 @@
       GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
 
   /* write fail */
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     /* Dequeue the data, if it was enqueued */
     if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
 
@@ -1000,45 +810,29 @@
                            NULL);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_execute
- *
- * Description      send execute write
- *
- * Returns          None.
- ******************************************************************************/
+
+/** send execute write */
 void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
-  tBTA_GATT_STATUS status;
+  if (!bta_gattc_enqueue(p_clcb, p_data)) return;
 
-  if (bta_gattc_enqueue(p_clcb, p_data)) {
-    status =
-        GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute);
+  tGATT_STATUS status =
+      GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute);
+  if (status != GATT_SUCCESS) {
+    /* Dequeue the data, if it was enqueued */
+    if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
 
-    if (status != BTA_GATT_OK) {
-      /* Dequeue the data, if it was enqueued */
-      if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
-
-      bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE,
-                             status, NULL);
-    }
+    bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE, status,
+                           NULL);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_confirm
- *
- * Description      send handle value confirmation
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** send handle value confirmation */
 void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   uint16_t handle = p_data->api_confirm.handle;
 
   if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific,
                                    handle) != GATT_SUCCESS) {
-    APPL_TRACE_ERROR("%s: to handle [0x%04x] failed", __func__, handle);
+    LOG(ERROR) << __func__ << ": to handle=" << loghex(handle) << " failed";
   } else {
     /* if over BR_EDR, inform PM for mode change */
     if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) {
@@ -1047,15 +841,8 @@
     }
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_read_cmpl
- *
- * Description      read complete
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** read complete */
 void bta_gattc_read_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
   GATT_READ_OP_CB cb = p_clcb->p_q_cmd->api_read.read_cb;
   void* my_cb_data = p_clcb->p_q_cmd->api_read.read_cb_data;
@@ -1074,15 +861,8 @@
        my_cb_data);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_write_cmpl
- *
- * Description      write complete
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** write complete */
 void bta_gattc_write_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
   GATT_WRITE_OP_CB cb = p_clcb->p_q_cmd->api_write.write_cb;
   void* my_cb_data = p_clcb->p_q_cmd->api_write.write_cb_data;
@@ -1094,20 +874,13 @@
        my_cb_data);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_exec_cmpl
- *
- * Description      execute write complete
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** execute write complete */
 void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
   tBTA_GATTC cb_data;
 
   osi_free_and_reset((void**)&p_clcb->p_q_cmd);
-  p_clcb->status = BTA_GATT_OK;
+  p_clcb->status = GATT_SUCCESS;
 
   /* execute complete, callback */
   cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id;
@@ -1116,22 +889,14 @@
   (*p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_cfg_mtu_cmpl
- *
- * Description      configure MTU operation complete
- *
- * Returns          None.
- *
- ******************************************************************************/
+/** configure MTU operation complete */
 void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB* p_clcb,
                             tBTA_GATTC_OP_CMPL* p_data) {
   tBTA_GATTC cb_data;
 
   osi_free_and_reset((void**)&p_clcb->p_q_cmd);
 
-  if (p_data->p_cmpl && p_data->status == BTA_GATT_OK)
+  if (p_data->p_cmpl && p_data->status == GATT_SUCCESS)
     p_clcb->p_srcb->mtu = p_data->p_cmpl->mtu;
 
   /* configure MTU complete, callback */
@@ -1142,100 +907,83 @@
 
   (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CFG_MTU_EVT, &cb_data);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_op_cmpl
- *
- * Description      operation completed.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** operation completed */
 void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   uint8_t op = (uint8_t)p_data->op_cmpl.op_code;
   uint8_t mapped_op = 0;
 
-  APPL_TRACE_DEBUG("%s: op = %d", __func__, op);
+  VLOG(1) << __func__ << ": op:" << +op;
 
   if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) {
-    APPL_TRACE_ERROR("unexpected operation, ignored");
-  } else if (op >= GATTC_OPTYPE_READ) {
-    if (p_clcb->p_q_cmd == NULL) {
-      APPL_TRACE_ERROR("No pending command");
-      return;
-    }
-    if (p_clcb->p_q_cmd->hdr.event !=
-        bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) {
-      mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT +
-                  GATTC_OPTYPE_READ;
-      if (mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0;
+    LOG(ERROR) << "unexpected operation, ignored";
+    return;
+  }
 
-      APPL_TRACE_ERROR(
-          "expect op:(%s :0x%04x), receive unexpected operation (%s).",
-          bta_gattc_op_code_name[mapped_op], p_clcb->p_q_cmd->hdr.event,
-          bta_gattc_op_code_name[op]);
-      return;
-    }
+  if (op < GATTC_OPTYPE_READ) return;
 
-    /* Except for MTU configuration, discard responses if service change
-     * indication is received before operation completed
-     */
-    if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING &&
-        p_clcb->p_srcb->srvc_hdl_chg && op != GATTC_OPTYPE_CONFIG) {
-      APPL_TRACE_DEBUG(
-          "Discard all responses when service change indication is received.");
-      p_data->op_cmpl.status = GATT_ERROR;
-    }
+  if (p_clcb->p_q_cmd == NULL) {
+    LOG(ERROR) << "No pending command";
+    return;
+  }
 
-    /* service handle change void the response, discard it */
-    if (op == GATTC_OPTYPE_READ)
-      bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl);
+  if (p_clcb->p_q_cmd->hdr.event !=
+      bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) {
+    mapped_op =
+        p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ;
+    if (mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0;
 
-    else if (op == GATTC_OPTYPE_WRITE)
-      bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl);
+    LOG(ERROR) << StringPrintf(
+        "expect op:(%s :0x%04x), receive unexpected operation (%s).",
+        bta_gattc_op_code_name[mapped_op], p_clcb->p_q_cmd->hdr.event,
+        bta_gattc_op_code_name[op]);
+    return;
+  }
 
-    else if (op == GATTC_OPTYPE_EXE_WRITE)
-      bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl);
+  /* Except for MTU configuration, discard responses if service change
+   * indication is received before operation completed
+   */
+  if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING &&
+      p_clcb->p_srcb->srvc_hdl_chg && op != GATTC_OPTYPE_CONFIG) {
+    VLOG(1) << "Discard all responses when service change indication is "
+               "received.";
+    p_data->op_cmpl.status = GATT_ERROR;
+  }
 
-    else if (op == GATTC_OPTYPE_CONFIG)
-      bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl);
+  /* service handle change void the response, discard it */
+  if (op == GATTC_OPTYPE_READ)
+    bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl);
 
-    if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
-      p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
-      bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
-    }
+  else if (op == GATTC_OPTYPE_WRITE)
+    bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl);
+
+  else if (op == GATTC_OPTYPE_EXE_WRITE)
+    bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl);
+
+  else if (op == GATTC_OPTYPE_CONFIG)
+    bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl);
+
+  if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
+    p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
+    bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_op_cmpl
- *
- * Description      operation completed.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** operation completed */
 void bta_gattc_ignore_op_cmpl(UNUSED_ATTR tBTA_GATTC_CLCB* p_clcb,
                               tBTA_GATTC_DATA* p_data) {
   /* receive op complete when discovery is started, ignore the response,
       and wait for discovery finish and resent */
-  APPL_TRACE_DEBUG("%s: op = %d", __func__, p_data->hdr.layer_specific);
+  VLOG(1) << __func__ << ": op = " << +p_data->hdr.layer_specific;
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_search
- *
- * Description      start a search in the local server cache
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** start a search in the local server cache */
 void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
-  tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR;
+  tGATT_STATUS status = GATT_INTERNAL_ERROR;
   tBTA_GATTC cb_data;
-  APPL_TRACE_DEBUG("%s: conn_id=%d", __func__, p_clcb->bta_conn_id);
-  if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
-    status = BTA_GATT_OK;
+  VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
+  if (p_clcb->p_srcb && !p_clcb->p_srcb->srvc_cache.empty()) {
+    status = GATT_SUCCESS;
     /* search the local cache of a server device */
     bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid);
   }
@@ -1245,48 +993,24 @@
   /* end of search or no server cache available */
   (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_q_cmd
- *
- * Description      enqueue a command into control block, usually because
- *                  discovery operation is busy.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** enqueue a command into control block, usually because discovery operation is
+ * busy */
 void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
   bta_gattc_enqueue(p_clcb, p_data);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_fail
- *
- * Description      report API call failure back to apps
- *
- * Returns          None.
- *
- ******************************************************************************/
+/** report API call failure back to apps */
 void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb,
                     UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
-  if (p_clcb->status == BTA_GATT_OK) {
-    APPL_TRACE_ERROR("operation not supported at current state [%d]",
-                     p_clcb->state);
+  if (p_clcb->status == GATT_SUCCESS) {
+    LOG(ERROR) << "operation not supported at current state " << +p_clcb->state;
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_deregister_cmpl
- *
- * Description      De-Register a GATT client application with BTA completed.
- *
- * Returns          void
- *
- ******************************************************************************/
+/* De-Register a GATT client application with BTA completed */
 static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg) {
-  tBTA_GATTC_IF client_if = p_clreg->client_if;
+  tGATT_IF client_if = p_clreg->client_if;
   tBTA_GATTC cb_data;
   tBTA_GATTC_CBACK* p_cback = p_clreg->p_cback;
 
@@ -1296,7 +1020,7 @@
   memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB));
 
   cb_data.reg_oper.client_if = client_if;
-  cb_data.reg_oper.status = BTA_GATT_OK;
+  cb_data.reg_oper.status = GATT_SUCCESS;
 
   if (p_cback) /* callback with de-register event */
     (*p_cback)(BTA_GATTC_DEREG_EVT, &cb_data);
@@ -1306,22 +1030,16 @@
     bta_gattc_cb.state = BTA_GATTC_STATE_DISABLED;
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_conn_cback
- *
- * Description      callback functions to GATT client stack.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** callback functions to GATT client stack */
 static void bta_gattc_conn_cback(tGATT_IF gattc_if, const RawAddress& bdaddr,
                                  uint16_t conn_id, bool connected,
                                  tGATT_DISCONN_REASON reason,
                                  tBT_TRANSPORT transport) {
   if (reason != 0) {
-    APPL_TRACE_WARNING("%s() - cif=%d connected=%d conn_id=%d reason=0x%04x",
-                       __func__, gattc_if, connected, conn_id, reason);
+    LOG(WARNING) << __func__ << ": cif=" << +gattc_if
+                 << " connected=" << connected << " conn_id=" << loghex(conn_id)
+                 << " reason=" << loghex(reason);
   }
 
   if (connected)
@@ -1343,18 +1061,10 @@
   bta_sys_sendmsg(p_buf);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_enc_cmpl_cback
- *
- * Description      encryption complete callback function to GATT client stack.
- *
- * Returns          void
- *
- ******************************************************************************/
+/** encryption complete callback function to GATT client stack */
 static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, const RawAddress& bda) {
   tBTA_GATTC_CLCB* p_clcb =
-      bta_gattc_find_clcb_by_cif(gattc_if, bda, BTA_GATT_TRANSPORT_LE);
+      bta_gattc_find_clcb_by_cif(gattc_if, bda, GATT_TRANSPORT_LE);
 
   if (p_clcb == NULL) return;
 
@@ -1368,32 +1078,22 @@
   }
 #endif
 
-  APPL_TRACE_DEBUG("%s: cif = %d", __func__, gattc_if);
+  VLOG(1) << __func__ << ": cif:" << +gattc_if;
 
   do_in_bta_thread(FROM_HERE,
                    base::Bind(&bta_gattc_process_enc_cmpl, gattc_if, bda));
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_process_api_refresh
- *
- * Description      process refresh API to delete cache and start a new
- *                  discovery if currently connected.
- *
- * Returns          None.
- *
- ******************************************************************************/
+/** process refresh API to delete cache and start a new discovery if currently
+ * connected */
 void bta_gattc_process_api_refresh(const RawAddress& remote_bda) {
   tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_srvr_cache(remote_bda);
-  tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
-  bool found = false;
-  uint8_t i;
-
-  if (p_srvc_cb != NULL) {
+  if (p_srvc_cb) {
     /* try to find a CLCB */
     if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) {
-      for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+      bool found = false;
+      tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+      for (uint8_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
         if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) {
           found = true;
           break;
@@ -1405,108 +1105,91 @@
       }
     }
     /* in all other cases, mark it and delete the cache */
-    if (p_srvc_cb->p_srvc_cache != NULL) {
-      list_free(p_srvc_cb->p_srvc_cache);
-      p_srvc_cb->p_srvc_cache = NULL;
-    }
+
+    // clear reallocating
+    std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
   }
+
   /* used to reset cache in application */
   bta_gattc_cache_reset(remote_bda);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_process_srvc_chg_ind
- *
- * Description      process service change indication.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** process service change indication */
 bool bta_gattc_process_srvc_chg_ind(uint16_t conn_id, tBTA_GATTC_RCB* p_clrcb,
                                     tBTA_GATTC_SERV* p_srcb,
                                     tBTA_GATTC_CLCB* p_clcb,
                                     tBTA_GATTC_NOTIFY* p_notify,
                                     tGATT_VALUE* att_value) {
-  tBT_UUID gattp_uuid, srvc_chg_uuid;
-  bool processed = false;
-  uint8_t i;
 
-  gattp_uuid.len = 2;
-  gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
-
-  srvc_chg_uuid.len = 2;
-  srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+  Uuid gattp_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
+  Uuid srvc_chg_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
 
   const tBTA_GATTC_CHARACTERISTIC* p_char =
       bta_gattc_get_characteristic_srcb(p_srcb, p_notify->handle);
-  if (p_char &&
-      bta_gattc_uuid_compare(&p_char->service->uuid, &gattp_uuid, true) &&
-      bta_gattc_uuid_compare(&p_char->uuid, &srvc_chg_uuid, true)) {
-    if (att_value->len != BTA_GATTC_SERVICE_CHANGED_LEN) {
-      APPL_TRACE_ERROR(
-          "%s: received malformed service changed indication, skipping",
-          __func__);
-      return false;
-    }
-
-    uint8_t* p = att_value->value;
-    uint16_t s_handle = ((uint16_t)(*(p)) + (((uint16_t)(*(p + 1))) << 8));
-    uint16_t e_handle = ((uint16_t)(*(p + 2)) + (((uint16_t)(*(p + 3))) << 8));
-
-    APPL_TRACE_ERROR("%s: service changed s_handle:0x%04x e_handle:0x%04x",
-                     __func__, s_handle, e_handle);
-
-    processed = true;
-    /* mark service handle change pending */
-    p_srcb->srvc_hdl_chg = true;
-    /* clear up all notification/indication registration */
-    bta_gattc_clear_notif_registration(p_srcb, conn_id, s_handle, e_handle);
-    /* service change indication all received, do discovery update */
-    if (++p_srcb->update_count == bta_gattc_num_reg_app()) {
-      /* not an opened connection; or connection busy */
-      /* search for first available clcb and start discovery */
-      if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) {
-        for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
-          if (bta_gattc_cb.clcb[i].in_use &&
-              bta_gattc_cb.clcb[i].p_srcb == p_srcb &&
-              bta_gattc_cb.clcb[i].p_q_cmd == NULL) {
-            p_clcb = &bta_gattc_cb.clcb[i];
-            break;
-          }
-        }
-      }
-      /* send confirmation here if this is an indication, it should always be */
-      GATTC_SendHandleValueConfirm(conn_id, att_value->handle);
-
-      /* if connection available, refresh cache by doing discovery now */
-      if (p_clcb != NULL)
-        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
-    }
-    /* notify applicationf or service change */
-    if (p_clrcb->p_cback != NULL) {
-      tBTA_GATTC bta_gattc;
-      bta_gattc.remote_bda = p_srcb->server_bda;
-      (*p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, &bta_gattc);
-    }
+  if (!p_char) return false;
+  const tBTA_GATTC_SERVICE* p_svc =
+      bta_gattc_get_service_for_handle_srcb(p_srcb, p_char->value_handle);
+  if (!p_svc || p_svc->uuid != gattp_uuid || p_char->uuid != srvc_chg_uuid) {
+    return false;
   }
 
-  return processed;
+  if (att_value->len != BTA_GATTC_SERVICE_CHANGED_LEN) {
+    LOG(ERROR) << __func__
+               << ": received malformed service changed indication, skipping";
+    return false;
+  }
+
+  uint8_t* p = att_value->value;
+  uint16_t s_handle = ((uint16_t)(*(p)) + (((uint16_t)(*(p + 1))) << 8));
+  uint16_t e_handle = ((uint16_t)(*(p + 2)) + (((uint16_t)(*(p + 3))) << 8));
+
+  LOG(ERROR) << __func__ << ": service changed s_handle=" << loghex(s_handle)
+             << ", e_handle=" << loghex(e_handle);
+
+  /* mark service handle change pending */
+  p_srcb->srvc_hdl_chg = true;
+  /* clear up all notification/indication registration */
+  bta_gattc_clear_notif_registration(p_srcb, conn_id, s_handle, e_handle);
+  /* service change indication all received, do discovery update */
+  if (++p_srcb->update_count == bta_gattc_num_reg_app()) {
+    /* not an opened connection; or connection busy */
+    /* search for first available clcb and start discovery */
+    if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) {
+      for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+        if (bta_gattc_cb.clcb[i].in_use &&
+            bta_gattc_cb.clcb[i].p_srcb == p_srcb &&
+            bta_gattc_cb.clcb[i].p_q_cmd == NULL) {
+          p_clcb = &bta_gattc_cb.clcb[i];
+          break;
+        }
+      }
+    }
+    /* send confirmation here if this is an indication, it should always be */
+    GATTC_SendHandleValueConfirm(conn_id, att_value->handle);
+
+    /* if connection available, refresh cache by doing discovery now */
+    if (p_clcb) bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+  }
+
+  /* notify applicationf or service change */
+  if (p_clrcb->p_cback) {
+    tBTA_GATTC bta_gattc;
+    bta_gattc.remote_bda = p_srcb->server_bda;
+    (*p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, &bta_gattc);
+  }
+
+  return true;
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_proc_other_indication
- *
- * Description      process all non-service change indication/notification.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** process all non-service change indication/notification */
 void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB* p_clcb, uint8_t op,
                                      tGATT_CL_COMPLETE* p_data,
                                      tBTA_GATTC_NOTIFY* p_notify) {
-  APPL_TRACE_DEBUG("%s: check p_data->att_value.handle=%d p_data->handle=%d",
-                   __func__, p_data->att_value.handle, p_data->handle);
-  APPL_TRACE_DEBUG("is_notify", p_notify->is_notify);
+  VLOG(1) << __func__
+          << StringPrintf(
+                 ": check p_data->att_value.handle=%d p_data->handle=%d",
+                 p_data->att_value.handle, p_data->handle);
+  VLOG(1) << "is_notify", p_notify->is_notify;
 
   p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? false : true;
   p_notify->len = p_data->att_value.len;
@@ -1520,98 +1203,81 @@
     (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, &bta_gattc);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_process_indicate
- *
- * Description      process indication/notification.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** process indication/notification */
 void bta_gattc_process_indicate(uint16_t conn_id, tGATTC_OPTYPE op,
                                 tGATT_CL_COMPLETE* p_data) {
   uint16_t handle = p_data->att_value.handle;
-  tBTA_GATTC_CLCB* p_clcb;
-  tBTA_GATTC_RCB* p_clrcb = NULL;
-  tBTA_GATTC_SERV* p_srcb = NULL;
   tBTA_GATTC_NOTIFY notify;
   RawAddress remote_bda;
-  tBTA_GATTC_IF gatt_if;
+  tGATT_IF gatt_if;
   tBTA_TRANSPORT transport;
 
   if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) {
-    APPL_TRACE_ERROR("%s indication/notif for unknown app", __func__);
+    LOG(ERROR) << __func__ << ": indication/notif for unknown app";
     if (op == GATTC_OPTYPE_INDICATION)
       GATTC_SendHandleValueConfirm(conn_id, handle);
     return;
   }
 
-  p_clrcb = bta_gattc_cl_get_regcb(gatt_if);
+  tBTA_GATTC_RCB* p_clrcb = bta_gattc_cl_get_regcb(gatt_if);
   if (p_clrcb == NULL) {
-    APPL_TRACE_ERROR("%s indication/notif for unregistered app", __func__);
+    LOG(ERROR) << __func__ << ": indication/notif for unregistered app";
     if (op == GATTC_OPTYPE_INDICATION)
       GATTC_SendHandleValueConfirm(conn_id, handle);
     return;
   }
 
-  p_srcb = bta_gattc_find_srcb(remote_bda);
+  tBTA_GATTC_SERV* p_srcb = bta_gattc_find_srcb(remote_bda);
   if (p_srcb == NULL) {
-    APPL_TRACE_ERROR("%s indication/notif for unknown device, ignore",
-                     __func__);
+    LOG(ERROR) << __func__ << ": indication/notif for unknown device, ignore";
     if (op == GATTC_OPTYPE_INDICATION)
       GATTC_SendHandleValueConfirm(conn_id, handle);
     return;
   }
 
-  p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
 
   notify.handle = handle;
-  /* if non-service change indication/notification, forward to application */
-  if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, &notify,
-                                      &p_data->att_value)) {
-    /* if app registered for the notification */
-    if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, &notify)) {
-      /* connection not open yet */
+
+  /* if service change indication/notification, don't forward to application */
+  if (bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, &notify,
+                                     &p_data->att_value))
+    return;
+
+  /* if app registered for the notification */
+  if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, &notify)) {
+    /* connection not open yet */
+    if (p_clcb == NULL) {
+      p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport);
+
       if (p_clcb == NULL) {
-        p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport);
-
-        if (p_clcb == NULL) {
-          APPL_TRACE_ERROR("No resources");
-          return;
-        }
-
-        p_clcb->bta_conn_id = conn_id;
-        p_clcb->transport = transport;
-
-        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL);
+        LOG(ERROR) << "No resources";
+        return;
       }
 
-      if (p_clcb != NULL)
-        bta_gattc_proc_other_indication(p_clcb, op, p_data, &notify);
+      p_clcb->bta_conn_id = conn_id;
+      p_clcb->transport = transport;
+
+      bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL);
     }
-    /* no one intersted and need ack? */
-    else if (op == GATTC_OPTYPE_INDICATION) {
-      APPL_TRACE_DEBUG("%s no one interested, ack now", __func__);
-      GATTC_SendHandleValueConfirm(conn_id, handle);
-    }
+
+    if (p_clcb != NULL)
+      bta_gattc_proc_other_indication(p_clcb, op, p_data, &notify);
+  }
+  /* no one intersted and need ack? */
+  else if (op == GATTC_OPTYPE_INDICATION) {
+    VLOG(1) << __func__ << " no one interested, ack now";
+    GATTC_SendHandleValueConfirm(conn_id, handle);
   }
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_cmpl_cback
- *
- * Description      client operation complete callback register with BTE GATT.
- *
- * Returns          None.
- *
- ******************************************************************************/
+
+/** client operation complete callback register with BTE GATT */
 static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
                                  tGATT_STATUS status,
                                  tGATT_CL_COMPLETE* p_data) {
-  tBTA_GATTC_CLCB* p_clcb;
-  APPL_TRACE_DEBUG("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d",
-                   conn_id, op, status);
+  VLOG(1) << __func__ << ": conn_id:" << +conn_id << " op:" << +op
+          << " status:" << +status;
 
   /* notification and indication processed right away */
   if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION) {
@@ -1619,13 +1285,11 @@
     return;
   }
   /* for all other operation, not expected if w/o connection */
-  else {
-    p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
-    if (p_clcb == NULL) {
-      APPL_TRACE_ERROR("%s: unknown conn_id =  %d, ignore data", __func__,
-                       conn_id);
-      return;
-    }
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  if (!p_clcb) {
+    LOG(ERROR) << __func__ << ": unknown conn_id=" << loghex(conn_id)
+               << " ignore data";
+    return;
   }
 
   /* if over BR_EDR, inform PM for mode change */
@@ -1637,17 +1301,9 @@
   bta_gattc_cmpl_sendmsg(conn_id, op, status, p_data);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_cmpl_sendmsg
- *
- * Description      client operation complete send message
- *
- * Returns          None.
- *
- ******************************************************************************/
+/** client operation complete send message */
 static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op,
-                                   tBTA_GATT_STATUS status,
+                                   tGATT_STATUS status,
                                    tGATT_CL_COMPLETE* p_data) {
   const size_t len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE);
   tBTA_GATTC_OP_CMPL* p_buf = (tBTA_GATTC_OP_CMPL*)osi_calloc(len);
@@ -1657,7 +1313,7 @@
   p_buf->status = status;
   p_buf->op_code = op;
 
-  if (p_data != NULL) {
+  if (p_data) {
     p_buf->p_cmpl = (tGATT_CL_COMPLETE*)(p_buf + 1);
     memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE));
   }
@@ -1665,28 +1321,16 @@
   bta_sys_sendmsg(p_buf);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_cong_cback
- *
- * Description      congestion callback for BTA GATT client.
- *
- * Returns          void
- *
- ******************************************************************************/
+/** congestion callback for BTA GATT client */
 static void bta_gattc_cong_cback(uint16_t conn_id, bool congested) {
-  tBTA_GATTC_CLCB* p_clcb;
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  if (!p_clcb || !p_clcb->p_rcb->p_cback) return;
+
   tBTA_GATTC cb_data;
+  cb_data.congest.conn_id = conn_id;
+  cb_data.congest.congested = congested;
 
-  p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
-  if (p_clcb != NULL) {
-    if (p_clcb->p_rcb->p_cback) {
-      cb_data.congest.conn_id = conn_id;
-      cb_data.congest.congested = congested;
-
-      (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CONGEST_EVT, &cb_data);
-    }
-  }
+  (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CONGEST_EVT, &cb_data);
 }
 
 static void bta_gattc_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
@@ -1695,7 +1339,7 @@
   tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(gatt_if);
 
   if (!p_clreg || !p_clreg->p_cback) {
-    APPL_TRACE_ERROR("%s: client_if=%d not found", __func__, gatt_if);
+    LOG(ERROR) << __func__ << ": client_if=" << +gatt_if << " not found";
     return;
   }
 
@@ -1714,7 +1358,7 @@
   tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(gatt_if);
 
   if (!p_clreg || !p_clreg->p_cback) {
-    APPL_TRACE_ERROR("%s: client_if=%d not found", __func__, gatt_if);
+    LOG(ERROR) << __func__ << ": client_if=" << gatt_if << " not found";
     return;
   }
 
diff --git a/bta/gatt/bta_gattc_api.cc b/bta/gatt/bta_gattc_api.cc
index 4815f24..bec0081 100644
--- a/bta/gatt/bta_gattc_api.cc
+++ b/bta/gatt/bta_gattc_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2010-2012 Broadcom Corporation
+ *  Copyright 2010-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@
 #include "bta_sys.h"
 #include "device/include/controller.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
@@ -55,8 +57,8 @@
  *
  ******************************************************************************/
 void BTA_GATTC_Disable(void) {
-  if (bta_sys_is_register(BTA_ID_GATTC) == false) {
-    APPL_TRACE_WARNING("GATTC Module not enabled/already disabled");
+  if (!bta_sys_is_register(BTA_ID_GATTC)) {
+    LOG(WARNING) << "GATTC Module not enabled/already disabled";
     return;
   }
 
@@ -64,14 +66,6 @@
   bta_sys_deregister(BTA_ID_GATTC);
 }
 
-static void create_random_uuid(tBT_UUID* uuid) {
-  uuid->len = LEN_UUID_128;
-
-  for (int i = 0; i < 16; ++i) {
-    uuid->uu.uuid128[i] = (uint8_t)(rand() % 256);
-  }
-}
-
 /**
  * This function is called to register application callbacks with BTA GATTC
  * module. |client_cb| pointer to the application callback function.
@@ -79,17 +73,14 @@
  */
 void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
                            BtaAppRegisterCallback cb) {
-  if (bta_sys_is_register(BTA_ID_GATTC) == false)
+  if (!bta_sys_is_register(BTA_ID_GATTC))
     bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
 
-  // base::Owned will own and free app_uuid
-  tBT_UUID* uuid = new tBT_UUID;
-  create_random_uuid(uuid);
-  do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_register, base::Owned(uuid),
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_register, Uuid::GetRandom(),
                                          p_client_cb, std::move(cb)));
 }
 
-static void app_deregister_impl(tBTA_GATTC_IF client_if) {
+static void app_deregister_impl(tGATT_IF client_if) {
   bta_gattc_deregister(bta_gattc_cl_get_regcb(client_if));
 }
 /*******************************************************************************
@@ -104,7 +95,7 @@
  * Returns          None
  *
  ******************************************************************************/
-void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) {
+void BTA_GATTC_AppDeregister(tGATT_IF client_if) {
   do_in_bta_thread(FROM_HERE, base::Bind(&app_deregister_impl, client_if));
 }
 
@@ -125,16 +116,16 @@
  *                                 and don't impact the disconnection timer
  *
  ******************************************************************************/
-void BTA_GATTC_Open(tBTA_GATTC_IF client_if, const RawAddress& remote_bda,
-                    bool is_direct, tBTA_GATT_TRANSPORT transport,
+void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda,
+                    bool is_direct, tGATT_TRANSPORT transport,
                     bool opportunistic) {
   uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
   BTA_GATTC_Open(client_if, remote_bda, is_direct, transport, opportunistic,
                  phy);
 }
 
-void BTA_GATTC_Open(tBTA_GATTC_IF client_if, const RawAddress& remote_bda,
-                    bool is_direct, tBTA_GATT_TRANSPORT transport,
+void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda,
+                    bool is_direct, tGATT_TRANSPORT transport,
                     bool opportunistic, uint8_t initiating_phys) {
   tBTA_GATTC_API_OPEN* p_buf =
       (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
@@ -165,7 +156,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, const RawAddress& remote_bda,
+void BTA_GATTC_CancelOpen(tGATT_IF client_if, const RawAddress& remote_bda,
                           bool is_direct) {
   tBTA_GATTC_API_CANCEL_OPEN* p_buf = (tBTA_GATTC_API_CANCEL_OPEN*)osi_malloc(
       sizeof(tBTA_GATTC_API_CANCEL_OPEN));
@@ -239,15 +230,15 @@
  * Returns          None
  *
  ******************************************************************************/
-void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id, tBT_UUID* p_srvc_uuid) {
-  const size_t len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID);
+void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id, Uuid* p_srvc_uuid) {
+  const size_t len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(Uuid);
   tBTA_GATTC_API_SEARCH* p_buf = (tBTA_GATTC_API_SEARCH*)osi_calloc(len);
 
   p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT;
   p_buf->hdr.layer_specific = conn_id;
   if (p_srvc_uuid) {
-    p_buf->p_srvc_uuid = (tBT_UUID*)(p_buf + 1);
-    memcpy(p_buf->p_srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID));
+    p_buf->p_srvc_uuid = (Uuid*)(p_buf + 1);
+    *p_buf->p_srvc_uuid = *p_srvc_uuid;
   } else {
     p_buf->p_srvc_uuid = NULL;
   }
@@ -255,11 +246,12 @@
   bta_sys_sendmsg(p_buf);
 }
 
-void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id, tBT_UUID* p_srvc_uuid) {
+void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
+                                     const Uuid& p_srvc_uuid) {
   tGATT_DISC_PARAM* param = new tGATT_DISC_PARAM;
   param->s_handle = 0x0001;
   param->e_handle = 0xFFFF;
-  param->service = *p_srvc_uuid;
+  param->service = p_srvc_uuid;
   do_in_bta_thread(FROM_HERE,
                    base::Bind(base::IgnoreResult(&GATTC_Discover), conn_id,
                               GATT_DISC_SRVC_BY_UUID, base::Owned(param)));
@@ -274,10 +266,10 @@
  *
  * Parameters       conn_id: connection ID which identify the server.
  *
- * Returns          returns list_t of tBTA_GATTC_SERVICE or NULL.
+ * Returns          returns list of tBTA_GATTC_SERVICE or NULL.
  *
  ******************************************************************************/
-const list_t* BTA_GATTC_GetServices(uint16_t conn_id) {
+const std::vector<tBTA_GATTC_SERVICE>* BTA_GATTC_GetServices(uint16_t conn_id) {
   return bta_gattc_get_services(conn_id);
 }
 
@@ -317,6 +309,20 @@
   return bta_gattc_get_descriptor(conn_id, handle);
 }
 
+/* Return characteristic that owns descriptor with handle equal to |handle|, or
+ * NULL */
+const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetOwningCharacteristic(
+    uint16_t conn_id, uint16_t handle) {
+  return bta_gattc_get_owning_characteristic(conn_id, handle);
+}
+
+/* Return service that owns descriptor or characteristic with handle equal to
+ * |handle|, or NULL */
+const tBTA_GATTC_SERVICE* BTA_GATTC_GetOwningService(uint16_t conn_id,
+                                                     uint16_t handle) {
+  return bta_gattc_get_service_for_handle(conn_id, handle);
+}
+
 /*******************************************************************************
  *
  * Function         BTA_GATTC_GetGattDb
@@ -348,7 +354,7 @@
  *
  ******************************************************************************/
 void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle,
-                                  tBTA_GATT_AUTH_REQ auth_req,
+                                  tGATT_AUTH_REQ auth_req,
                                   GATT_READ_OP_CB callback, void* cb_data) {
   tBTA_GATTC_API_READ* p_buf =
       (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
@@ -367,9 +373,9 @@
  * This function is called to read a value of characteristic with uuid equal to
  * |uuid|
  */
-void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, tBT_UUID uuid,
+void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, const Uuid& uuid,
                                  uint16_t s_handle, uint16_t e_handle,
-                                 tBTA_GATT_AUTH_REQ auth_req,
+                                 tGATT_AUTH_REQ auth_req,
                                  GATT_READ_OP_CB callback, void* cb_data) {
   tBTA_GATTC_API_READ* p_buf =
       (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
@@ -400,8 +406,8 @@
  *
  ******************************************************************************/
 void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle,
-                             tBTA_GATT_AUTH_REQ auth_req,
-                             GATT_READ_OP_CB callback, void* cb_data) {
+                             tGATT_AUTH_REQ auth_req, GATT_READ_OP_CB callback,
+                             void* cb_data) {
   tBTA_GATTC_API_READ* p_buf =
       (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
 
@@ -429,7 +435,7 @@
  *
  ******************************************************************************/
 void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI* p_read_multi,
-                            tBTA_GATT_AUTH_REQ auth_req) {
+                            tGATT_AUTH_REQ auth_req) {
   tBTA_GATTC_API_READ_MULTI* p_buf =
       (tBTA_GATTC_API_READ_MULTI*)osi_calloc(sizeof(tBTA_GATTC_API_READ_MULTI));
 
@@ -460,9 +466,9 @@
  *
  ******************************************************************************/
 void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle,
-                              tBTA_GATTC_WRITE_TYPE write_type,
+                              tGATT_WRITE_TYPE write_type,
                               std::vector<uint8_t> value,
-                              tBTA_GATT_AUTH_REQ auth_req,
+                              tGATT_AUTH_REQ auth_req,
                               GATT_WRITE_OP_CB callback, void* cb_data) {
   tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
       sizeof(tBTA_GATTC_API_WRITE) + value.size());
@@ -499,7 +505,7 @@
  ******************************************************************************/
 void BTA_GATTC_WriteCharDescr(uint16_t conn_id, uint16_t handle,
                               std::vector<uint8_t> value,
-                              tBTA_GATT_AUTH_REQ auth_req,
+                              tGATT_AUTH_REQ auth_req,
                               GATT_WRITE_OP_CB callback, void* cb_data) {
   tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
       sizeof(tBTA_GATTC_API_WRITE) + value.size());
@@ -508,7 +514,7 @@
   p_buf->hdr.layer_specific = conn_id;
   p_buf->auth_req = auth_req;
   p_buf->handle = handle;
-  p_buf->write_type = BTA_GATTC_TYPE_WRITE;
+  p_buf->write_type = GATT_WRITE;
   p_buf->write_cb = callback;
   p_buf->write_cb_data = cb_data;
 
@@ -537,8 +543,7 @@
  *
  ******************************************************************************/
 void BTA_GATTC_PrepareWrite(uint16_t conn_id, uint16_t handle, uint16_t offset,
-                            std::vector<uint8_t> value,
-                            tBTA_GATT_AUTH_REQ auth_req,
+                            std::vector<uint8_t> value, tGATT_AUTH_REQ auth_req,
                             GATT_WRITE_OP_CB callback, void* cb_data) {
   tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
       sizeof(tBTA_GATTC_API_WRITE) + value.size());
@@ -602,7 +607,8 @@
   tBTA_GATTC_API_CONFIRM* p_buf =
       (tBTA_GATTC_API_CONFIRM*)osi_calloc(sizeof(tBTA_GATTC_API_CONFIRM));
 
-  APPL_TRACE_API("%s conn_id=%d handle=0x%04x", __func__, conn_id, handle);
+  VLOG(1) << __func__ << ": conn_id=" << +conn_id << " handle=0x" << std::hex
+          << +handle;
 
   p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT;
   p_buf->hdr.layer_specific = conn_id;
@@ -625,15 +631,15 @@
  * Returns          OK if registration succeed, otherwise failed.
  *
  ******************************************************************************/
-tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications(tBTA_GATTC_IF client_if,
-                                                    const RawAddress& bda,
-                                                    uint16_t handle) {
+tGATT_STATUS BTA_GATTC_RegisterForNotifications(tGATT_IF client_if,
+                                                const RawAddress& bda,
+                                                uint16_t handle) {
   tBTA_GATTC_RCB* p_clreg;
-  tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+  tGATT_STATUS status = GATT_ILLEGAL_PARAMETER;
   uint8_t i;
 
   if (!handle) {
-    APPL_TRACE_ERROR("deregistration failed, handle is 0");
+    LOG(ERROR) << "deregistration failed, handle is 0";
     return status;
   }
 
@@ -643,12 +649,12 @@
       if (p_clreg->notif_reg[i].in_use &&
           p_clreg->notif_reg[i].remote_bda == bda &&
           p_clreg->notif_reg[i].handle == handle) {
-        APPL_TRACE_WARNING("notification already registered");
-        status = BTA_GATT_OK;
+        LOG(WARNING) << "notification already registered";
+        status = GATT_SUCCESS;
         break;
       }
     }
-    if (status != BTA_GATT_OK) {
+    if (status != GATT_SUCCESS) {
       for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
         if (!p_clreg->notif_reg[i].in_use) {
           memset((void*)&p_clreg->notif_reg[i], 0,
@@ -658,17 +664,17 @@
           p_clreg->notif_reg[i].remote_bda = bda;
 
           p_clreg->notif_reg[i].handle = handle;
-          status = BTA_GATT_OK;
+          status = GATT_SUCCESS;
           break;
         }
       }
       if (i == BTA_GATTC_NOTIF_REG_MAX) {
-        status = BTA_GATT_NO_RESOURCES;
-        APPL_TRACE_ERROR("Max Notification Reached, registration failed.");
+        status = GATT_NO_RESOURCES;
+        LOG(ERROR) << "Max Notification Reached, registration failed.";
       }
     }
   } else {
-    APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if);
+    LOG(ERROR) << "client_if=" << +client_if << " Not Registered";
   }
 
   return status;
@@ -688,33 +694,33 @@
  * Returns          OK if deregistration succeed, otherwise failed.
  *
  ******************************************************************************/
-tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(tBTA_GATTC_IF client_if,
-                                                      const RawAddress& bda,
-                                                      uint16_t handle) {
+tGATT_STATUS BTA_GATTC_DeregisterForNotifications(tGATT_IF client_if,
+                                                  const RawAddress& bda,
+                                                  uint16_t handle) {
   if (!handle) {
-    APPL_TRACE_ERROR("%s: deregistration failed, handle is 0", __func__);
-    return BTA_GATT_ILLEGAL_PARAMETER;
+    LOG(ERROR) << __func__ << ": deregistration failed, handle is 0";
+    return GATT_ILLEGAL_PARAMETER;
   }
 
   tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(client_if);
   if (p_clreg == NULL) {
-    LOG(ERROR) << __func__ << " client_if: " << +client_if
-               << " not registered bd_addr:" << bda;
-    return BTA_GATT_ILLEGAL_PARAMETER;
+    LOG(ERROR) << __func__ << " client_if=" << +client_if
+               << " not registered bd_addr=" << bda;
+    return GATT_ILLEGAL_PARAMETER;
   }
 
   for (int i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
     if (p_clreg->notif_reg[i].in_use &&
         p_clreg->notif_reg[i].remote_bda == bda &&
         p_clreg->notif_reg[i].handle == handle) {
-      VLOG(1) << __func__ << " deregistered bd_addr:" << bda;
+      VLOG(1) << __func__ << " deregistered bd_addr=" << bda;
       memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
-      return BTA_GATT_OK;
+      return GATT_SUCCESS;
     }
   }
 
-  LOG(ERROR) << __func__ << " registration not found bd_addr:" << bda;
-  return BTA_GATT_ERROR;
+  LOG(ERROR) << __func__ << " registration not found bd_addr=" << bda;
+  return GATT_ERROR;
 }
 
 /*******************************************************************************
diff --git a/bta/gatt/bta_gattc_cache.cc b/bta/gatt/bta_gattc_cache.cc
index 110e534..60224a3 100644
--- a/bta/gatt/bta_gattc_cache.cc
+++ b/bta/gatt/bta_gattc_cache.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -44,24 +44,24 @@
 #include "sdpdefs.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
+using base::StringPrintf;
+
 static void bta_gattc_cache_write(const RawAddress& server_bda,
                                   uint16_t num_attr, tBTA_GATTC_NV_ATTR* attr);
 static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
                                            tBTA_GATTC_SERV* p_srvc_cb);
-static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(
-    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb);
-extern void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src);
-tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(const list_t* services,
-                                                    uint16_t handle);
-tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
-                                                     uint16_t handle);
+static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
+                                               tBTA_GATTC_SERV* p_server_cb);
+const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle);
 tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
     tBTA_GATTC_SERV* p_srcb, uint16_t handle);
 
 #define BTA_GATT_SDP_DB_SIZE 4096
 
 #define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
-#define GATT_CACHE_VERSION 2
+#define GATT_CACHE_VERSION 4
 
 static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
                                                const RawAddress& bda) {
@@ -80,73 +80,54 @@
 } tBTA_GATTC_CB_DATA;
 
 #if (BTA_GATT_DEBUG == TRUE)
-static char* bta_gattc_attr_type[] = {
-    "I", /* Included Service */
-    "C", /* Characteristic */
-    "D"  /* Characteristic Descriptor */
-};
 /* utility functions */
 
-bool display_cache_attribute(void* data, void* context) {
-  tBTA_GATTC_CACHE_ATTR* p_attr = data;
-  APPL_TRACE_ERROR("\t Attr handle[%d] uuid[0x%04x] type[%s] prop[0x%1x]",
-                   p_attr->handle, p_attr->uuid.uu.uuid16,
-                   bta_gattc_attr_type[p_attr->attr_type], p_attr->property);
-  return true;
-}
+/* debug function to display the server cache */
+static void display_db(const std::vector<tBTA_GATTC_SERVICE>& cache) {
+  for (const tBTA_GATTC_SERVICE& service : cache) {
+    LOG(ERROR) << "Service: s_handle=" << loghex(service.s_handle)
+               << ", e_handle=" << loghex(service.e_handle)
+               << ", inst=" << loghex(service.handle)
+               << ", uuid=" << service.uuid;
 
-bool display_cache_service(void* data, void* context) {
-  tBTA_GATTC_SERVICE* p_cur_srvc = data;
-  APPL_TRACE_ERROR("Service: handle[%d ~ %d] %s[0x%04x] inst[%d]",
-                   p_cur_srvc->s_handle, p_cur_srvc->e_handle,
-                   ((p_cur_srvc->uuid.len == 2) ? "uuid16" : "uuid128"),
-                   p_cur_srvc->uuid.uu.uuid16, p_cur_srvc->handle);
+    if (service.characteristics.empty()) {
+      LOG(ERROR) << "\t No characteristics";
+      continue;
+    }
 
-  if (p_cur_srvc->characteristics != NULL) {
-    list_foreach(p_cur_srvc->characteristics, display_cache_attribute, NULL);
+    for (const tBTA_GATTC_CHARACTERISTIC& c : service.characteristics) {
+      LOG(ERROR) << "\t Characteristic value_handle=" << loghex(c.value_handle)
+                 << ", uuid=" << c.uuid << ", prop=" << loghex(c.properties);
+
+      if (c.descriptors.empty()) {
+        LOG(ERROR) << "\t\t No descriptors";
+        continue;
+      }
+
+      for (const tBTA_GATTC_DESCRIPTOR& d : c.descriptors) {
+        LOG(ERROR) << "\t\t Descriptor handle=" << loghex(d.handle)
+                   << ", uuid=" << d.uuid;
+      }
+    }
   }
-
-  return true;
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_display_cache_server
- *
- * Description      debug function to display the server cache.
- *
- * Returns          none.
- *
- ******************************************************************************/
-static void bta_gattc_display_cache_server(list_t* p_cache) {
-  APPL_TRACE_ERROR("<================Start Server Cache =============>");
-  list_foreach(p_cache, display_cache_service, NULL);
-  APPL_TRACE_ERROR("<================End Server Cache =============>");
-  APPL_TRACE_ERROR(" ");
+/* debug function to display the server cache */
+static void bta_gattc_display_cache_server(
+    const std::vector<tBTA_GATTC_SERVICE>& cache) {
+  LOG(ERROR) << "<================Start Server Cache =============>";
+  display_db(cache);
+  LOG(ERROR) << "<================End Server Cache =============>";
+  LOG(ERROR) << " ";
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_display_explore_record
- *
- * Description      debug function to display the exploration list
- *
- * Returns          none.
- *
- ******************************************************************************/
-static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC* p_rec,
-                                             uint8_t num_rec) {
-  uint8_t i;
-  tBTA_GATTC_ATTR_REC* pp = p_rec;
-
-  APPL_TRACE_ERROR("<================Start Explore Queue =============>");
-  for (i = 0; i < num_rec; i++, pp++) {
-    APPL_TRACE_ERROR(
-        "\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]",
-        i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary);
-  }
-  APPL_TRACE_ERROR("<================ End Explore Queue =============>");
-  APPL_TRACE_ERROR(" ");
+/** debug function to display the exploration list */
+static void bta_gattc_display_explore_record(
+    const std::vector<tBTA_GATTC_SERVICE>& cache) {
+  LOG(ERROR) << "<================Start Explore Queue =============>";
+  display_db(cache);
+  LOG(ERROR) << "<================ End Explore Queue =============>";
+  LOG(ERROR) << " ";
 }
 #endif /* BTA_GATT_DEBUG == TRUE */
 
@@ -160,91 +141,56 @@
  * Returns          status
  *
  ******************************************************************************/
-tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
-  if (p_srvc_cb->p_srvc_cache != NULL) {
-    list_free(p_srvc_cb->p_srvc_cache);
-    p_srvc_cb->p_srvc_cache = NULL;
+tGATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
+  // clear reallocating
+  std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
+  std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->pending_discovery);
+  return GATT_SUCCESS;
+}
+
+tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(
+    std::vector<tBTA_GATTC_SERVICE>& services, uint16_t handle) {
+  for (tBTA_GATTC_SERVICE& service : services) {
+    if (handle >= service.s_handle && handle <= service.e_handle)
+      return &service;
   }
 
-  osi_free(p_srvc_cb->p_srvc_list);
-  p_srvc_cb->p_srvc_list =
-      (tBTA_GATTC_ATTR_REC*)osi_malloc(BTA_GATTC_ATTR_LIST_SIZE);
-  p_srvc_cb->total_srvc = 0;
-  p_srvc_cb->cur_srvc_idx = 0;
-  p_srvc_cb->cur_char_idx = 0;
-  p_srvc_cb->next_avail_idx = 0;
-
-  return BTA_GATT_OK;
+  return nullptr;
 }
 
-static void characteristic_free(void* ptr) {
-  tBTA_GATTC_CHARACTERISTIC* p_char = (tBTA_GATTC_CHARACTERISTIC*)ptr;
-  list_free(p_char->descriptors);
-  osi_free(p_char);
-}
-
-static void service_free(void* ptr) {
-  tBTA_GATTC_SERVICE* srvc = (tBTA_GATTC_SERVICE*)ptr;
-  list_free(srvc->characteristics);
-  list_free(srvc->included_svc);
-  osi_free(srvc);
-}
-
-/*******************************************************************************
- *
- * Function         bta_gattc_add_srvc_to_cache
- *
- * Description      Add a service into database cache.
- *
- * Returns          status
- *
- ******************************************************************************/
-static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV* p_srvc_cb,
-                                                    uint16_t s_handle,
-                                                    uint16_t e_handle,
-                                                    tBT_UUID* p_uuid,
-                                                    bool is_primary) {
+/** Add a service into GATT database */
+static void add_service_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
+                                   uint16_t s_handle, uint16_t e_handle,
+                                   const Uuid& uuid, bool is_primary) {
 #if (BTA_GATT_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("Add a service into Service");
+  VLOG(1) << "Add a service into GATT DB";
 #endif
 
-  tBTA_GATTC_SERVICE* p_new_srvc =
-      (tBTA_GATTC_SERVICE*)osi_malloc(sizeof(tBTA_GATTC_SERVICE));
-
-  /* update service information */
-  p_new_srvc->s_handle = s_handle;
-  p_new_srvc->e_handle = e_handle;
-  p_new_srvc->is_primary = is_primary;
-  memcpy(&p_new_srvc->uuid, p_uuid, sizeof(tBT_UUID));
-  p_new_srvc->handle = s_handle;
-  p_new_srvc->characteristics = list_new(characteristic_free);
-  p_new_srvc->included_svc = list_new(osi_free);
-
-  if (p_srvc_cb->p_srvc_cache == NULL) {
-    p_srvc_cb->p_srvc_cache = list_new(service_free);
-  }
-
-  list_append(p_srvc_cb->p_srvc_cache, p_new_srvc);
-  return BTA_GATT_OK;
+  gatt_db.emplace_back(tBTA_GATTC_SERVICE{
+      .s_handle = s_handle,
+      .e_handle = e_handle,
+      .is_primary = is_primary,
+      .uuid = uuid,
+      .handle = s_handle,
+  });
 }
 
-static tBTA_GATT_STATUS bta_gattc_add_char_to_cache(tBTA_GATTC_SERV* p_srvc_cb,
-                                                    uint16_t attr_handle,
-                                                    uint16_t value_handle,
-                                                    tBT_UUID* p_uuid,
-                                                    uint8_t property) {
+/** Add a characteristic into GATT database */
+static void add_characteristic_to_gatt_db(
+    std::vector<tBTA_GATTC_SERVICE>& gatt_db, uint16_t attr_handle,
+    uint16_t value_handle, const Uuid& uuid, uint8_t property) {
 #if (BTA_GATT_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("%s: Add a characteristic into Service", __func__);
-  APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x", value_handle,
-                   p_uuid->uu.uuid16, property);
+  VLOG(1) << __func__
+          << ": Add a characteristic into service. handle:" << +value_handle
+          << " uuid:" << uuid << " property=0x" << std::hex << +property;
 #endif
 
   tBTA_GATTC_SERVICE* service =
-      bta_gattc_find_matching_service(p_srvc_cb->p_srvc_cache, attr_handle);
+      bta_gattc_find_matching_service(gatt_db, attr_handle);
   if (!service) {
-    APPL_TRACE_ERROR(
-        "Illegal action to add char/descr/incl srvc for non-existing service!");
-    return GATT_WRONG_STATE;
+    LOG(ERROR) << "Illegal action to add char/descr/incl srvc for non-existing "
+                  "service!";
+    return;
   }
 
   /* TODO(jpawlowski): We should use attribute handle, not value handle to refer
@@ -253,258 +199,148 @@
   */
   if (service->e_handle < value_handle) service->e_handle = value_handle;
 
-  tBTA_GATTC_CHARACTERISTIC* characteristic =
-      (tBTA_GATTC_CHARACTERISTIC*)osi_malloc(sizeof(tBTA_GATTC_CHARACTERISTIC));
-
-  characteristic->handle = value_handle;
-  characteristic->properties = property;
-  characteristic->descriptors = list_new(osi_free);
-  memcpy(&characteristic->uuid, p_uuid, sizeof(tBT_UUID));
-
-  characteristic->service = service;
-  list_append(service->characteristics, characteristic);
-
-  return BTA_GATT_OK;
+  service->characteristics.emplace_back(
+      tBTA_GATTC_CHARACTERISTIC{.declaration_handle = attr_handle,
+                                .value_handle = value_handle,
+                                .properties = property,
+                                .uuid = uuid});
+  return;
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_add_attr_to_cache
- *
- * Description      Add an attribute into database cache buffer.
- *
- * Returns          status
- *
- ******************************************************************************/
-static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(
-    tBTA_GATTC_SERV* p_srvc_cb, uint16_t handle, tBT_UUID* p_uuid,
-    uint8_t property, uint16_t incl_srvc_s_handle, tBTA_GATTC_ATTR_TYPE type) {
+/* Add an descriptor into database cache buffer */
+static void add_descriptor_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
+                                      uint16_t handle, const Uuid& uuid) {
 #if (BTA_GATT_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("%s: Add a [%s] into Service", __func__,
-                   bta_gattc_attr_type[type]);
-  APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x type=%d", handle,
-                   p_uuid->uu.uuid16, property, type);
+  VLOG(1) << __func__ << ": add descriptor, handle=" << loghex(handle)
+          << ", uuid=" << uuid;
 #endif
 
   tBTA_GATTC_SERVICE* service =
-      bta_gattc_find_matching_service(p_srvc_cb->p_srvc_cache, handle);
+      bta_gattc_find_matching_service(gatt_db, handle);
   if (!service) {
-    APPL_TRACE_ERROR(
-        "Illegal action to add char/descr/incl srvc for non-existing service!");
-    return GATT_WRONG_STATE;
-  }
-
-  if (type == BTA_GATTC_ATTR_TYPE_INCL_SRVC) {
-    tBTA_GATTC_INCLUDED_SVC* isvc =
-        (tBTA_GATTC_INCLUDED_SVC*)osi_malloc(sizeof(tBTA_GATTC_INCLUDED_SVC));
-
-    isvc->handle = handle;
-    memcpy(&isvc->uuid, p_uuid, sizeof(tBT_UUID));
-
-    isvc->owning_service = service;
-    isvc->included_service = bta_gattc_find_matching_service(
-        p_srvc_cb->p_srvc_cache, incl_srvc_s_handle);
-    if (!isvc->included_service) {
-      APPL_TRACE_ERROR(
-          "%s: Illegal action to add non-existing included service!", __func__);
-      osi_free(isvc);
-      return GATT_WRONG_STATE;
-    }
-
-    list_append(service->included_svc, isvc);
-  } else if (type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) {
-    tBTA_GATTC_DESCRIPTOR* descriptor =
-        (tBTA_GATTC_DESCRIPTOR*)osi_malloc(sizeof(tBTA_GATTC_DESCRIPTOR));
-
-    descriptor->handle = handle;
-    memcpy(&descriptor->uuid, p_uuid, sizeof(tBT_UUID));
-
-    if (service->characteristics == NULL ||
-        list_is_empty(service->characteristics)) {
-      APPL_TRACE_ERROR(
-          "%s: Illegal action to add descriptor before adding a "
-          "characteristic!",
-          __func__);
-      osi_free(descriptor);
-      return GATT_WRONG_STATE;
-    }
-
-    tBTA_GATTC_CHARACTERISTIC* char_node =
-        (tBTA_GATTC_CHARACTERISTIC*)list_back(service->characteristics);
-
-    descriptor->characteristic = char_node;
-    list_append(char_node->descriptors, descriptor);
-  }
-  return BTA_GATT_OK;
-}
-
-/*******************************************************************************
- *
- * Function         bta_gattc_get_disc_range
- *
- * Description      get discovery stating and ending handle range.
- *
- * Returns          None.
- *
- ******************************************************************************/
-void bta_gattc_get_disc_range(tBTA_GATTC_SERV* p_srvc_cb, uint16_t* p_s_hdl,
-                              uint16_t* p_e_hdl, bool is_srvc) {
-  tBTA_GATTC_ATTR_REC* p_rec = NULL;
-
-  if (is_srvc) {
-    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
-    *p_s_hdl = p_rec->s_handle;
-  } else {
-    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
-    *p_s_hdl = p_rec->s_handle + 1;
-  }
-
-  *p_e_hdl = p_rec->e_handle;
-#if (BTA_GATT_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("discover range [%d ~ %d]", p_rec->s_handle,
-                   p_rec->e_handle);
-#endif
-  return;
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_discover_pri_service
- *
- * Description      Start primary service discovery
- *
- * Returns          status of the operation.
- *
- ******************************************************************************/
-tBTA_GATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
-                                                tBTA_GATTC_SERV* p_server_cb,
-                                                uint8_t disc_type) {
-  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
-  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
-
-  if (p_clcb) {
-    if (p_clcb->transport == BTA_TRANSPORT_LE)
-      status = bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type);
-    else
-      status = bta_gattc_sdp_service_disc(conn_id, p_server_cb);
-  }
-
-  return status;
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_discover_procedure
- *
- * Description      Start a particular type of discovery procedure on server.
- *
- * Returns          status of the operation.
- *
- ******************************************************************************/
-tBTA_GATT_STATUS bta_gattc_discover_procedure(uint16_t conn_id,
-                                              tBTA_GATTC_SERV* p_server_cb,
-                                              uint8_t disc_type) {
-  tGATT_DISC_PARAM param;
-  bool is_service = true;
-
-  memset(&param, 0, sizeof(tGATT_DISC_PARAM));
-
-  if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) {
-    param.s_handle = 1;
-    param.e_handle = 0xFFFF;
-  } else {
-    if (disc_type == GATT_DISC_CHAR_DSCPT) is_service = false;
-
-    bta_gattc_get_disc_range(p_server_cb, &param.s_handle, &param.e_handle,
-                             is_service);
-
-    if (param.s_handle > param.e_handle) {
-      return GATT_ERROR;
-    }
-  }
-  return GATTC_Discover(conn_id, disc_type, &param);
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_start_disc_include_srvc
- *
- * Description      Start discovery for included service
- *
- * Returns          status of the operation.
- *
- ******************************************************************************/
-tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(uint16_t conn_id,
-                                                   tBTA_GATTC_SERV* p_srvc_cb) {
-  return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC);
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_start_disc_char
- *
- * Description      Start discovery for characteristic
- *
- * Returns          status of the operation.
- *
- ******************************************************************************/
-tBTA_GATT_STATUS bta_gattc_start_disc_char(uint16_t conn_id,
-                                           tBTA_GATTC_SERV* p_srvc_cb) {
-  p_srvc_cb->total_char = 0;
-
-  return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR);
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_start_disc_char_dscp
- *
- * Description      Start discovery for characteristic descriptor
- *
- * Returns          none.
- *
- ******************************************************************************/
-void bta_gattc_start_disc_char_dscp(uint16_t conn_id,
-                                    tBTA_GATTC_SERV* p_srvc_cb) {
-  APPL_TRACE_DEBUG("starting discover characteristics descriptor");
-
-  if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) !=
-      0)
-    bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_explore_srvc
- *
- * Description      process the service discovery complete event
- *
- * Returns          status
- *
- ******************************************************************************/
-static void bta_gattc_explore_srvc(uint16_t conn_id,
-                                   tBTA_GATTC_SERV* p_srvc_cb) {
-  tBTA_GATTC_ATTR_REC* p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
-  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
-
-  APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d",
-                   p_srvc_cb->cur_srvc_idx);
-
-  p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;
-
-  if (p_clcb == NULL) {
-    APPL_TRACE_ERROR("unknown connection ID");
+    LOG(ERROR) << "Illegal action to add descriptor for non-existing service!";
     return;
   }
-  /* start expore a service if there is service not been explored */
-  if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc) {
-    /* add the first service into cache */
-    if (bta_gattc_add_srvc_to_cache(p_srvc_cb, p_rec->s_handle, p_rec->e_handle,
-                                    &p_rec->uuid, p_rec->is_primary) == 0) {
-      /* start discovering included services */
-      bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);
-      return;
-    }
+
+  if (service->characteristics.empty()) {
+    LOG(ERROR) << __func__
+               << ": Illegal action to add descriptor before adding a "
+                  "characteristic!";
+    return;
   }
+
+  tBTA_GATTC_CHARACTERISTIC* char_node = &service->characteristics.front();
+  for (auto it = service->characteristics.begin();
+       it != service->characteristics.end(); it++) {
+    if (it->value_handle > handle) break;
+    char_node = &(*it);
+  }
+
+  char_node->descriptors.emplace_back(
+      tBTA_GATTC_DESCRIPTOR{.handle = handle, .uuid = uuid});
+}
+
+/* Add an attribute into database cache buffer */
+static void add_incl_srvc_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
+                                     uint16_t handle, const Uuid& uuid,
+                                     uint16_t incl_srvc_s_handle) {
+#if (BTA_GATT_DEBUG == TRUE)
+  VLOG(1) << __func__ << ": add included service, handle=" << loghex(handle)
+          << ", uuid=" << uuid;
+#endif
+
+  tBTA_GATTC_SERVICE* service =
+      bta_gattc_find_matching_service(gatt_db, handle);
+  if (!service) {
+    LOG(ERROR) << "Illegal action to add incl srvc for non-existing service!";
+    return;
+  }
+
+  tBTA_GATTC_SERVICE* included_service =
+      bta_gattc_find_matching_service(gatt_db, incl_srvc_s_handle);
+  if (!included_service) {
+    LOG(ERROR) << __func__
+               << ": Illegal action to add non-existing included service!";
+    return;
+  }
+
+  service->included_svc.emplace_back(tBTA_GATTC_INCLUDED_SVC{
+      .handle = handle,
+      .uuid = uuid,
+      .owning_service = service,
+      .included_service = included_service,
+  });
+}
+
+/** Start primary service discovery */
+tGATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
+                                            tBTA_GATTC_SERV* p_server_cb,
+                                            uint8_t disc_type) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  if (!p_clcb) return GATT_ERROR;
+
+  if (p_clcb->transport == BTA_TRANSPORT_LE) {
+    tGATT_DISC_PARAM param{.s_handle = 0x0001, .e_handle = 0xFFFF};
+    return GATTC_Discover(conn_id, disc_type, &param);
+  }
+
+  return bta_gattc_sdp_service_disc(conn_id, p_server_cb);
+}
+
+/** Start discovery for characteristic descriptor */
+void bta_gattc_start_disc_char_dscp(uint16_t conn_id,
+                                    tBTA_GATTC_SERV* p_srvc_cb) {
+  VLOG(1) << "starting discover characteristics descriptor";
+  auto& characteristic = p_srvc_cb->pending_char;
+
+  uint16_t end_handle = 0xFFFF;
+  // if there are more characteristics in the service
+  if (std::next(p_srvc_cb->pending_char) !=
+      p_srvc_cb->pending_service->characteristics.end()) {
+    // end at beginning of next characteristic
+    end_handle = std::next(p_srvc_cb->pending_char)->declaration_handle - 1;
+  } else {
+    // end at the end of current service
+    end_handle = p_srvc_cb->pending_service->e_handle;
+  }
+
+  tGATT_DISC_PARAM param{
+      .s_handle = (uint16_t)(characteristic->value_handle + 1),
+      .e_handle = end_handle};
+  if (GATTC_Discover(conn_id, GATT_DISC_CHAR_DSCPT, &param) != 0) {
+    bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+  }
+}
+
+/** process the service discovery complete event */
+static void bta_gattc_explore_srvc(uint16_t conn_id,
+                                   tBTA_GATTC_SERV* p_srvc_cb) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  if (!p_clcb) {
+    LOG(ERROR) << "unknown conn_id=" << +conn_id;
+    return;
+  }
+
+  /* start expore a service if there is service not been explored */
+  if (p_srvc_cb->pending_service != p_srvc_cb->pending_discovery.end()) {
+    auto& service = *p_srvc_cb->pending_service;
+    VLOG(1) << "Start service discovery";
+
+    /* start discovering included services */
+    tGATT_DISC_PARAM param = {.s_handle = service.s_handle,
+                              .e_handle = service.e_handle};
+    GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, &param);
+    return;
+  }
+
   /* no service found at all, the end of server discovery*/
-  LOG_WARN(LOG_TAG, "%s no more services found", __func__);
+  LOG(INFO) << __func__ << ": no more services found";
+
+  p_srvc_cb->srvc_cache.swap(p_srvc_cb->pending_discovery);
+  std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->pending_discovery);
 
 #if (BTA_GATT_DEBUG == TRUE)
-  bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+  bta_gattc_display_cache_server(p_srvc_cb->srvc_cache);
 #endif
   /* save cache to NV */
   p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
@@ -513,191 +349,42 @@
     bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id);
   }
 
-  bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK);
+  bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_incl_srvc_disc_cmpl
- *
- * Description      process the relationship discovery complete event
- *
- * Returns          status
- *
- ******************************************************************************/
-static void bta_gattc_incl_srvc_disc_cmpl(uint16_t conn_id,
-                                          tBTA_GATTC_SERV* p_srvc_cb) {
-  p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc;
 
-  /* start discoverying characteristic */
-  bta_gattc_start_disc_char(conn_id, p_srvc_cb);
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_char_disc_cmpl
- *
- * Description      process the characteristic discovery complete event
- *
- * Returns          status
- *
- ******************************************************************************/
-static void bta_gattc_char_disc_cmpl(uint16_t conn_id,
-                                     tBTA_GATTC_SERV* p_srvc_cb) {
-  tBTA_GATTC_ATTR_REC* p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
-
-  /* if there are characteristic needs to be explored */
-  if (p_srvc_cb->total_char > 0) {
-    /* add the first characteristic into cache */
-    bta_gattc_add_char_to_cache(p_srvc_cb, p_rec->char_decl_handle,
-                                p_rec->s_handle, &p_rec->uuid, p_rec->property);
-
-    /* start discoverying characteristic descriptor , if failed, disc for next
-     * char*/
-    bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
-  } else /* otherwise start with next service */
-  {
-    p_srvc_cb->cur_srvc_idx++;
-
-    bta_gattc_explore_srvc(conn_id, p_srvc_cb);
-  }
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_char_dscpt_disc_cmpl
- *
- * Description      process the char descriptor discovery complete event
- *
- * Returns          status
- *
- ******************************************************************************/
+/** process the char descriptor discovery complete event */
 static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
                                            tBTA_GATTC_SERV* p_srvc_cb) {
-  tBTA_GATTC_ATTR_REC* p_rec = NULL;
-
-  if (--p_srvc_cb->total_char > 0) {
-    p_rec = p_srvc_cb->p_srvc_list + (++p_srvc_cb->cur_char_idx);
-    /* add the next characteristic into cache */
-    bta_gattc_add_char_to_cache(p_srvc_cb, p_rec->char_decl_handle,
-                                p_rec->s_handle, &p_rec->uuid, p_rec->property);
-
+  ++p_srvc_cb->pending_char;
+  if (p_srvc_cb->pending_char !=
+      p_srvc_cb->pending_service->characteristics.end()) {
     /* start discoverying next characteristic for char descriptor */
     bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
-  } else
+    return;
+  }
+
   /* all characteristic has been explored, start with next service if any */
-  {
 #if (BTA_GATT_DEBUG == TRUE)
-    APPL_TRACE_ERROR("all char has been explored");
+  LOG(ERROR) << "all char has been explored";
 #endif
-    p_srvc_cb->cur_srvc_idx++;
-    bta_gattc_explore_srvc(conn_id, p_srvc_cb);
-  }
+  p_srvc_cb->pending_service++;
+  bta_gattc_explore_srvc(conn_id, p_srvc_cb);
 }
-static bool bta_gattc_srvc_in_list(tBTA_GATTC_SERV* p_srvc_cb,
-                                   uint16_t s_handle, uint16_t e_handle,
-                                   UNUSED_ATTR tBT_UUID uuid) {
-  tBTA_GATTC_ATTR_REC* p_rec = NULL;
-  uint8_t i;
-  bool exist_srvc = false;
 
+static bool bta_gattc_srvc_in_list(std::vector<tBTA_GATTC_SERVICE>& services,
+                                   uint16_t s_handle, uint16_t e_handle, Uuid) {
   if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) {
-    APPL_TRACE_ERROR("invalid included service handle: [0x%04x ~ 0x%04x]",
-                     s_handle, e_handle);
-    exist_srvc = true;
-  } else {
-    for (i = 0; i < p_srvc_cb->next_avail_idx; i++) {
-      p_rec = p_srvc_cb->p_srvc_list + i;
-
-      /* a new service should not have any overlap with other service handle
-       * range */
-      if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle) {
-        exist_srvc = true;
-        break;
-      }
-    }
+    LOG(ERROR) << "invalid included service s_handle=" << loghex(s_handle)
+               << ", e_handle=" << loghex(e_handle);
+    return true;
   }
-  return exist_srvc;
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_add_srvc_to_list
- *
- * Description      Add a service into explore pending list
- *
- * Returns          status
- *
- ******************************************************************************/
-static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV* p_srvc_cb,
-                                                   uint16_t s_handle,
-                                                   uint16_t e_handle,
-                                                   tBT_UUID uuid,
-                                                   bool is_primary) {
-  tBTA_GATTC_ATTR_REC* p_rec = NULL;
-  tBTA_GATT_STATUS status = BTA_GATT_OK;
 
-  if (p_srvc_cb->p_srvc_list &&
-      p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) {
-    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
-
-    APPL_TRACE_DEBUG("%s handle=%d, service type=0x%04x", __func__, s_handle,
-                     uuid.uu.uuid16);
-
-    p_rec->s_handle = s_handle;
-    p_rec->e_handle = e_handle;
-    p_rec->is_primary = is_primary;
-    memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
-
-    p_srvc_cb->total_srvc++;
-    p_srvc_cb->next_avail_idx++;
-  } else { /* allocate bigger buffer ?? */
-    status = GATT_DB_FULL;
-
-    APPL_TRACE_ERROR("service not added, no resources or wrong state");
+  for (tBTA_GATTC_SERVICE& service : services) {
+    if (service.s_handle == s_handle || service.e_handle == e_handle)
+      return true;
   }
-  return status;
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_add_char_to_list
- *
- * Description      Add a characteristic into explore pending list
- *
- * Returns          status
- *
- ******************************************************************************/
-static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV* p_srvc_cb,
-                                                   uint16_t decl_handle,
-                                                   uint16_t value_handle,
-                                                   tBT_UUID uuid,
-                                                   uint8_t property) {
-  tBTA_GATTC_ATTR_REC* p_rec = NULL;
-  tBTA_GATT_STATUS status = BTA_GATT_OK;
 
-  if (p_srvc_cb->p_srvc_list == NULL) {
-    APPL_TRACE_ERROR("No service available, unexpected char discovery result");
-    status = BTA_GATT_INTERNAL_ERROR;
-  } else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) {
-    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
-
-    p_srvc_cb->total_char++;
-
-    p_rec->s_handle = value_handle;
-    p_rec->char_decl_handle = decl_handle;
-    p_rec->property = property;
-    p_rec->e_handle =
-        (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle;
-    memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
-
-    /* update the endind handle of pervious characteristic if available */
-    if (p_srvc_cb->total_char > 1) {
-      p_rec -= 1;
-      p_rec->e_handle = decl_handle - 1;
-    }
-    p_srvc_cb->next_avail_idx++;
-  } else {
-    APPL_TRACE_ERROR("char not added, no resources");
-    /* allocate bigger buffer ?? */
-    status = BTA_GATT_DB_FULL;
-  }
-  return status;
+  return false;
 }
 
 /*******************************************************************************
@@ -710,51 +397,56 @@
  *
  ******************************************************************************/
 void bta_gattc_sdp_callback(uint16_t sdp_status, void* user_data) {
-  tSDP_DISC_REC* p_sdp_rec = NULL;
-  tBT_UUID service_uuid;
-  tSDP_PROTOCOL_ELEM pe;
-  uint16_t start_handle = 0, end_handle = 0;
   tBTA_GATTC_CB_DATA* cb_data = (tBTA_GATTC_CB_DATA*)user_data;
   tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(cb_data->sdp_conn_id);
 
-  if (((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) &&
-      p_srvc_cb != NULL) {
-    do {
-      /* find a service record, report it */
-      p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
-      if (p_sdp_rec) {
-        if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
-          if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT,
-                                            &pe)) {
-            start_handle = (uint16_t)pe.params[0];
-            end_handle = (uint16_t)pe.params[1];
+  if (p_srvc_cb == nullptr) {
+    LOG(ERROR) << "GATT service discovery is done on unknown connection";
+  } else {
+    bool no_pending_disc = p_srvc_cb->pending_discovery.empty();
+
+    if ((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) {
+      tSDP_DISC_REC* p_sdp_rec = NULL;
+      do {
+        /* find a service record, report it */
+        p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
+        if (p_sdp_rec) {
+          Uuid service_uuid;
+          if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
+            tSDP_PROTOCOL_ELEM pe;
+            if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT,
+                                              &pe)) {
+              uint16_t start_handle = (uint16_t)pe.params[0];
+              uint16_t end_handle = (uint16_t)pe.params[1];
 
 #if (BTA_GATT_DEBUG == TRUE)
-            APPL_TRACE_EVENT(
-                "Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]",
-                service_uuid.uu.uuid16, start_handle, end_handle);
+              VLOG(1) << "Found ATT service uuid=" << service_uuid
+                      << ", s_handle=" << loghex(start_handle)
+                      << ", e_handle=" << loghex(end_handle);
 #endif
 
-            if (GATT_HANDLE_IS_VALID(start_handle) &&
-                GATT_HANDLE_IS_VALID(end_handle) && p_srvc_cb != NULL) {
-              /* discover services result, add services into a service list */
-              bta_gattc_add_srvc_to_list(p_srvc_cb, start_handle, end_handle,
-                                         service_uuid, true);
-            } else {
-              APPL_TRACE_ERROR("invalid start_handle = %d end_handle = %d",
-                               start_handle, end_handle);
+              if (GATT_HANDLE_IS_VALID(start_handle) &&
+                  GATT_HANDLE_IS_VALID(end_handle) && p_srvc_cb != NULL) {
+                /* discover services result, add services into a service list */
+                add_service_to_gatt_db(p_srvc_cb->pending_discovery,
+                                       start_handle, end_handle, service_uuid,
+                                       true);
+              } else {
+                LOG(ERROR) << "invalid start_handle=" << loghex(start_handle)
+                           << ", end_handle=" << loghex(end_handle);
+              }
             }
           }
         }
-      }
-    } while (p_sdp_rec);
-  }
+      } while (p_sdp_rec);
+    }
 
-  if (p_srvc_cb != NULL) {
+    if (no_pending_disc) {
+      p_srvc_cb->pending_service = p_srvc_cb->pending_discovery.begin();
+    }
+
     /* start discover primary service */
     bta_gattc_explore_srvc(cb_data->sdp_conn_id, p_srvc_cb);
-  } else {
-    APPL_TRACE_ERROR("GATT service discovery is done on unknown connection");
   }
 
   /* both were allocated in bta_gattc_sdp_service_disc */
@@ -770,17 +462,11 @@
  * Returns          void
  *
  ******************************************************************************/
-static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(
-    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb) {
-  tSDP_UUID uuid;
+static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
+                                               tBTA_GATTC_SERV* p_server_cb) {
   uint16_t num_attrs = 2;
   uint16_t attr_list[2];
 
-  memset(&uuid, 0, sizeof(tSDP_UUID));
-
-  uuid.len = LEN_UUID_16;
-  uuid.uu.uuid16 = UUID_PROTOCOL_ATT;
-
   /*
    * On success, cb_data will be freed inside bta_gattc_sdp_callback,
    * otherwise it will be freed within this function.
@@ -792,6 +478,7 @@
   attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
   attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
 
+  Uuid uuid = Uuid::From16Bit(UUID_PROTOCOL_ATT);
   SDP_InitDiscoveryDb(cb_data->p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid,
                       num_attrs, attr_list);
 
@@ -800,86 +487,67 @@
                                           &bta_gattc_sdp_callback, cb_data)) {
     osi_free(cb_data->p_sdp_db);
     osi_free(cb_data);
-    return BTA_GATT_ERROR;
+    return GATT_ERROR;
   }
 
   cb_data->sdp_conn_id = conn_id;
-  return BTA_GATT_OK;
+  return GATT_SUCCESS;
 }
-/*******************************************************************************
- *
- * Function         bta_gattc_disc_res_cback
- *                  bta_gattc_disc_cmpl_cback
- *
- * Description      callback functions to GATT client stack.
- *
- * Returns          void
- *
- ******************************************************************************/
+
+/** callback function to GATT client stack */
 void bta_gattc_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                               tGATT_DISC_RES* p_data) {
-  tBTA_GATTC_SERV* p_srvc_cb = NULL;
-  bool pri_srvc;
   tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
 
-  p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+  if (!p_srvc_cb || !p_clcb || p_clcb->state != BTA_GATTC_DISCOVER_ST) return;
 
-  if (p_srvc_cb != NULL && p_clcb != NULL &&
-      p_clcb->state == BTA_GATTC_DISCOVER_ST) {
-    switch (disc_type) {
-      case GATT_DISC_SRVC_ALL:
-        /* discover services result, add services into a service list */
-        bta_gattc_add_srvc_to_list(
-            p_srvc_cb, p_data->handle, p_data->value.group_value.e_handle,
-            p_data->value.group_value.service_type, true);
+  switch (disc_type) {
+    case GATT_DISC_SRVC_ALL:
+    case GATT_DISC_SRVC_BY_UUID:
+      /* discover services result, add services into a service list */
+      add_service_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
+                             p_data->value.group_value.e_handle,
+                             p_data->value.group_value.service_type, true);
+      break;
 
-        break;
-      case GATT_DISC_SRVC_BY_UUID:
-        bta_gattc_add_srvc_to_list(
-            p_srvc_cb, p_data->handle, p_data->value.group_value.e_handle,
-            p_data->value.group_value.service_type, true);
-        break;
+    case GATT_DISC_INC_SRVC:
+      /* add included service into service list if it's secondary or it never
+         showed up in the primary service search */
+      if (!bta_gattc_srvc_in_list(p_srvc_cb->pending_discovery,
+                                  p_data->value.incl_service.s_handle,
+                                  p_data->value.incl_service.e_handle,
+                                  p_data->value.incl_service.service_type)) {
+        add_service_to_gatt_db(p_srvc_cb->pending_discovery,
+                               p_data->value.incl_service.s_handle,
+                               p_data->value.incl_service.e_handle,
+                               p_data->value.incl_service.service_type, false);
+      }
 
-      case GATT_DISC_INC_SRVC:
-        /* add included service into service list if it's secondary or it never
-           showed up
-           in the primary service search */
-        pri_srvc = bta_gattc_srvc_in_list(
-            p_srvc_cb, p_data->value.incl_service.s_handle,
-            p_data->value.incl_service.e_handle,
-            p_data->value.incl_service.service_type);
+      /* add into database */
+      add_incl_srvc_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
+                               p_data->value.incl_service.service_type,
+                               p_data->value.incl_service.s_handle);
+      break;
 
-        if (!pri_srvc)
-          bta_gattc_add_srvc_to_list(
-              p_srvc_cb, p_data->value.incl_service.s_handle,
-              p_data->value.incl_service.e_handle,
-              p_data->value.incl_service.service_type, false);
-        /* add into database */
-        bta_gattc_add_attr_to_cache(
-            p_srvc_cb, p_data->handle, &p_data->value.incl_service.service_type,
-            pri_srvc, p_data->value.incl_service.s_handle,
-            BTA_GATTC_ATTR_TYPE_INCL_SRVC);
-        break;
+    case GATT_DISC_CHAR:
+      /* add char value into database */
+      add_characteristic_to_gatt_db(p_srvc_cb->pending_discovery,
+                                    p_data->handle,
+                                    p_data->value.dclr_value.val_handle,
+                                    p_data->value.dclr_value.char_uuid,
+                                    p_data->value.dclr_value.char_prop);
+      break;
 
-      case GATT_DISC_CHAR:
-        /* add char value into database */
-        bta_gattc_add_char_to_list(p_srvc_cb, p_data->handle,
-                                   p_data->value.dclr_value.val_handle,
-                                   p_data->value.dclr_value.char_uuid,
-                                   p_data->value.dclr_value.char_prop);
-        break;
-
-      case GATT_DISC_CHAR_DSCPT:
-        bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0,
-                                    0 /* incl_srvc_handle */,
-                                    BTA_GATTC_ATTR_TYPE_CHAR_DESCR);
-        break;
-    }
+    case GATT_DISC_CHAR_DSCPT:
+      add_descriptor_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
+                                p_data->type);
+      break;
   }
 }
+
 void bta_gattc_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                                tGATT_STATUS status) {
-  tBTA_GATTC_SERV* p_srvc_cb;
   tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
 
   if (p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS)) {
@@ -887,87 +555,85 @@
     bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL);
     return;
   }
-  p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
 
-  if (p_srvc_cb != NULL) {
-    switch (disc_type) {
-      case GATT_DISC_SRVC_ALL:
-      case GATT_DISC_SRVC_BY_UUID:
+  tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+  if (!p_srvc_cb) return;
+
+  switch (disc_type) {
+    case GATT_DISC_SRVC_ALL:
+    case GATT_DISC_SRVC_BY_UUID:
+// definition of all services are discovered, now it's time to discover
+// their content
 #if (BTA_GATT_DEBUG == TRUE)
-        bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list,
-                                         p_srvc_cb->next_avail_idx);
+      bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
 #endif
-        bta_gattc_explore_srvc(conn_id, p_srvc_cb);
-        break;
+      p_srvc_cb->pending_service = p_srvc_cb->pending_discovery.begin();
+      bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+      break;
 
-      case GATT_DISC_INC_SRVC:
-        bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb);
+    case GATT_DISC_INC_SRVC: {
+      auto& service = *p_srvc_cb->pending_service;
 
-        break;
+      /* start discoverying characteristic */
 
-      case GATT_DISC_CHAR:
-#if (BTA_GATT_DEBUG == TRUE)
-        bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list,
-                                         p_srvc_cb->next_avail_idx);
-#endif
-        bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb);
-        break;
-
-      case GATT_DISC_CHAR_DSCPT:
-        bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
-        break;
+      tGATT_DISC_PARAM param = {.s_handle = service.s_handle,
+                                .e_handle = service.e_handle};
+      GATTC_Discover(conn_id, GATT_DISC_CHAR, &param);
+      break;
     }
+
+    case GATT_DISC_CHAR: {
+#if (BTA_GATT_DEBUG == TRUE)
+      bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
+#endif
+      auto& service = *p_srvc_cb->pending_service;
+      if (!service.characteristics.empty()) {
+        /* discover descriptors */
+        p_srvc_cb->pending_char = service.characteristics.begin();
+        bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+        return;
+      }
+      /* start next service */
+      ++p_srvc_cb->pending_service;
+      bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+      break;
+    }
+
+    case GATT_DISC_CHAR_DSCPT:
+      bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+      break;
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_search_service
- *
- * Description      search local cache for matching service record.
- *
- * Returns          false if map can not be found.
- *
- ******************************************************************************/
-void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, tBT_UUID* p_uuid) {
-  tBTA_GATTC cb_data;
-
-  if (!p_clcb->p_srcb->p_srvc_cache ||
-      list_is_empty(p_clcb->p_srcb->p_srvc_cache))
-    return;
-
-  for (list_node_t* sn = list_begin(p_clcb->p_srcb->p_srvc_cache);
-       sn != list_end(p_clcb->p_srcb->p_srvc_cache); sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* p_cache = (tBTA_GATTC_SERVICE*)list_node(sn);
-
-    if (!bta_gattc_uuid_compare(p_uuid, &p_cache->uuid, false)) continue;
+/** search local cache for matching service record */
+void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, Uuid* p_uuid) {
+  for (const tBTA_GATTC_SERVICE& service : p_clcb->p_srcb->srvc_cache) {
+    if (p_uuid && *p_uuid != service.uuid) continue;
 
 #if (BTA_GATT_DEBUG == TRUE)
-    APPL_TRACE_DEBUG("found service [0x%04x], inst[%d] handle [%d]",
-                     p_cache->uuid.uu.uuid16, p_cache->handle,
-                     p_cache->s_handle);
+    VLOG(1) << __func__ << "found service " << service.uuid
+            << ", inst:" << +service.handle << " handle:" << +service.s_handle;
 #endif
     if (!p_clcb->p_rcb->p_cback) continue;
 
+    tBTA_GATTC cb_data;
     memset(&cb_data, 0, sizeof(tBTA_GATTC));
-
     cb_data.srvc_res.conn_id = p_clcb->bta_conn_id;
-    cb_data.srvc_res.service_uuid.inst_id = p_cache->handle;
-    memcpy(&cb_data.srvc_res.service_uuid.uuid, &p_cache->uuid,
-           sizeof(tBTA_GATT_ID));
+    cb_data.srvc_res.service_uuid.inst_id = service.handle;
+    cb_data.srvc_res.service_uuid.uuid = service.uuid;
 
     (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data);
   }
 }
 
-list_t* bta_gattc_get_services_srcb(tBTA_GATTC_SERV* p_srcb) {
-  if (!p_srcb || !p_srcb->p_srvc_cache || list_is_empty(p_srcb->p_srvc_cache))
-    return NULL;
+std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services_srcb(
+    tBTA_GATTC_SERV* p_srcb) {
+  if (!p_srcb || p_srcb->srvc_cache.empty()) return NULL;
 
-  return p_srcb->p_srvc_cache;
+  return &p_srcb->srvc_cache;
 }
 
-const list_t* bta_gattc_get_services(uint16_t conn_id) {
+std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services(uint16_t conn_id) {
   tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
 
   if (p_clcb == NULL) return NULL;
@@ -977,47 +643,31 @@
   return bta_gattc_get_services_srcb(p_srcb);
 }
 
-tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(const list_t* services,
-                                                    uint16_t handle) {
-  if (!services || list_is_empty(services)) return NULL;
-
-  for (list_node_t* sn = list_begin(services); sn != list_end(services);
-       sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* service = (tBTA_GATTC_SERVICE*)list_node(sn);
-
-    if (handle >= service->s_handle && handle <= service->e_handle)
-      return service;
-  }
-
-  return NULL;
-}
-
-const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
+tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
     tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
-  const list_t* services = bta_gattc_get_services_srcb(p_srcb);
-
-  return bta_gattc_find_matching_service(services, handle);
+  std::vector<tBTA_GATTC_SERVICE>* services =
+      bta_gattc_get_services_srcb(p_srcb);
+  if (services == NULL) return NULL;
+  return bta_gattc_find_matching_service(*services, handle);
 }
 
 const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(uint16_t conn_id,
                                                            uint16_t handle) {
-  const list_t* services = bta_gattc_get_services(conn_id);
+  std::vector<tBTA_GATTC_SERVICE>* services = bta_gattc_get_services(conn_id);
+  if (services == NULL) return NULL;
 
-  return bta_gattc_find_matching_service(services, handle);
+  return bta_gattc_find_matching_service(*services, handle);
 }
 
 tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
     tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
-  const tBTA_GATTC_SERVICE* service =
+  tBTA_GATTC_SERVICE* service =
       bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
 
   if (!service) return NULL;
 
-  for (list_node_t* cn = list_begin(service->characteristics);
-       cn != list_end(service->characteristics); cn = list_next(cn)) {
-    tBTA_GATTC_CHARACTERISTIC* p_char =
-        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-    if (handle == p_char->handle) return p_char;
+  for (tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+    if (handle == charac.value_handle) return &charac;
   }
 
   return NULL;
@@ -1033,8 +683,8 @@
   return bta_gattc_get_characteristic_srcb(p_srcb, handle);
 }
 
-tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
-                                                     uint16_t handle) {
+const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
   const tBTA_GATTC_SERVICE* service =
       bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
 
@@ -1042,22 +692,17 @@
     return NULL;
   }
 
-  for (list_node_t* cn = list_begin(service->characteristics);
-       cn != list_end(service->characteristics); cn = list_next(cn)) {
-    tBTA_GATTC_CHARACTERISTIC* p_char =
-        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-    for (list_node_t* dn = list_begin(p_char->descriptors);
-         dn != list_end(p_char->descriptors); dn = list_next(dn)) {
-      tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
-      if (handle == p_desc->handle) return p_desc;
+  for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+    for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+      if (handle == desc.handle) return &desc;
     }
   }
 
   return NULL;
 }
 
-tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
-                                                uint16_t handle) {
+const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+                                                      uint16_t handle) {
   tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
 
   if (p_clcb == NULL) return NULL;
@@ -1066,6 +711,30 @@
   return bta_gattc_get_descriptor_srcb(p_srcb, handle);
 }
 
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
+  tBTA_GATTC_SERVICE* service =
+      bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
+
+  if (!service) return NULL;
+
+  for (tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+    for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+      if (handle == desc.handle) return &charac;
+    }
+  }
+
+  return NULL;
+}
+
+const tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic(
+    uint16_t conn_id, uint16_t handle) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  if (!p_clcb) return NULL;
+
+  return bta_gattc_get_owning_characteristic_srcb(p_clcb->p_srcb, handle);
+}
+
 /*******************************************************************************
  *
  * Function         bta_gattc_fill_gatt_db_el
@@ -1078,7 +747,7 @@
 void bta_gattc_fill_gatt_db_el(btgatt_db_element_t* p_attr,
                                bt_gatt_db_attribute_type_t type,
                                uint16_t att_handle, uint16_t s_handle,
-                               uint16_t e_handle, uint16_t id, tBT_UUID uuid,
+                               uint16_t e_handle, uint16_t id, const Uuid& uuid,
                                uint8_t prop) {
   p_attr->type = type;
   p_attr->attribute_handle = att_handle;
@@ -1090,43 +759,33 @@
   // Permissions are not discoverable using the attribute protocol.
   // Core 5.0, Part F, 3.2.5 Attribute Permissions
   p_attr->permissions = 0;
-  bta_to_btif_uuid(&p_attr->uuid, &uuid);
+  p_attr->uuid = uuid;
 }
 
 /*******************************************************************************
  * Returns          number of elements inside db from start_handle to end_handle
  ******************************************************************************/
-static size_t bta_gattc_get_db_size(list_t* services, uint16_t start_handle,
-                                    uint16_t end_handle) {
-  if (!services || list_is_empty(services)) return 0;
+static size_t bta_gattc_get_db_size(
+    const std::vector<tBTA_GATTC_SERVICE>& services, uint16_t start_handle,
+    uint16_t end_handle) {
+  if (services.empty()) return 0;
 
   size_t db_size = 0;
 
-  for (list_node_t* sn = list_begin(services); sn != list_end(services);
-       sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+  for (const tBTA_GATTC_SERVICE& service : services) {
+    if (service.s_handle < start_handle) continue;
 
-    if (p_cur_srvc->s_handle < start_handle) continue;
-
-    if (p_cur_srvc->e_handle > end_handle) break;
+    if (service.e_handle > end_handle) break;
 
     db_size++;
-    if (!p_cur_srvc->characteristics ||
-        list_is_empty(p_cur_srvc->characteristics))
-      continue;
 
-    for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
-         cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
-      tBTA_GATTC_CHARACTERISTIC* p_char =
-          (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+    for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
       db_size++;
 
-      if (p_char->descriptors) db_size += list_length(p_char->descriptors);
+      db_size += charac.descriptors.size();
     }
 
-    if (p_cur_srvc->included_svc) {
-      db_size += list_length(p_cur_srvc->included_svc);
-    }
+    db_size += service.included_svc.size();
   }
 
   return db_size;
@@ -1151,77 +810,55 @@
                                        uint16_t start_handle,
                                        uint16_t end_handle,
                                        btgatt_db_element_t** db, int* count) {
-  APPL_TRACE_DEBUG("%s: start_handle 0x%04x, end_handle 0x%04x", __func__,
-                   start_handle, end_handle);
+  VLOG(1) << __func__
+          << StringPrintf(": start_handle 0x%04x, end_handle 0x%04x",
+                          start_handle, end_handle);
 
-  if (!p_srvc_cb->p_srvc_cache || list_is_empty(p_srvc_cb->p_srvc_cache)) {
+  if (p_srvc_cb->srvc_cache.empty()) {
     *count = 0;
     *db = NULL;
     return;
   }
 
   size_t db_size =
-      bta_gattc_get_db_size(p_srvc_cb->p_srvc_cache, start_handle, end_handle);
+      bta_gattc_get_db_size(p_srvc_cb->srvc_cache, start_handle, end_handle);
 
   void* buffer = osi_malloc(db_size * sizeof(btgatt_db_element_t));
   btgatt_db_element_t* curr_db_attr = (btgatt_db_element_t*)buffer;
 
-  for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
-       sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+  for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
+    if (service.s_handle < start_handle) continue;
 
-    if (p_cur_srvc->s_handle < start_handle) continue;
+    if (service.e_handle > end_handle) break;
 
-    if (p_cur_srvc->e_handle > end_handle) break;
-
-    bta_gattc_fill_gatt_db_el(
-        curr_db_attr, p_cur_srvc->is_primary ? BTGATT_DB_PRIMARY_SERVICE
-                                             : BTGATT_DB_SECONDARY_SERVICE,
-        0 /* att_handle */, p_cur_srvc->s_handle, p_cur_srvc->e_handle,
-        p_cur_srvc->s_handle, p_cur_srvc->uuid, 0 /* prop */);
+    bta_gattc_fill_gatt_db_el(curr_db_attr,
+                              service.is_primary ? BTGATT_DB_PRIMARY_SERVICE
+                                                 : BTGATT_DB_SECONDARY_SERVICE,
+                              0 /* att_handle */, service.s_handle,
+                              service.e_handle, service.s_handle, service.uuid,
+                              0 /* prop */);
     curr_db_attr++;
 
-    if (!p_cur_srvc->characteristics ||
-        list_is_empty(p_cur_srvc->characteristics))
-      continue;
-
-    for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
-         cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
-      tBTA_GATTC_CHARACTERISTIC* p_char =
-          (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-
+    for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
       bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_CHARACTERISTIC,
-                                p_char->handle, 0 /* s_handle */,
-                                0 /* e_handle */, p_char->handle, p_char->uuid,
-                                p_char->properties);
+                                charac.value_handle, 0 /* s_handle */,
+                                0 /* e_handle */, charac.value_handle,
+                                charac.uuid, charac.properties);
       curr_db_attr++;
 
-      if (!p_char->descriptors || list_is_empty(p_char->descriptors)) continue;
-
-      for (list_node_t* dn = list_begin(p_char->descriptors);
-           dn != list_end(p_char->descriptors); dn = list_next(dn)) {
-        tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
-
-        bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_DESCRIPTOR,
-                                  p_desc->handle, 0 /* s_handle */,
-                                  0 /* e_handle */, p_desc->handle,
-                                  p_desc->uuid, 0 /* property */);
+      for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+        bta_gattc_fill_gatt_db_el(
+            curr_db_attr, BTGATT_DB_DESCRIPTOR, desc.handle, 0 /* s_handle */,
+            0 /* e_handle */, desc.handle, desc.uuid, 0 /* property */);
         curr_db_attr++;
       }
     }
 
-    if (!p_cur_srvc->included_svc || list_is_empty(p_cur_srvc->included_svc))
-      continue;
-
-    for (list_node_t* isn = list_begin(p_cur_srvc->included_svc);
-         isn != list_end(p_cur_srvc->included_svc); isn = list_next(isn)) {
-      tBTA_GATTC_INCLUDED_SVC* p_isvc =
-          (tBTA_GATTC_INCLUDED_SVC*)list_node(isn);
-
-      bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_INCLUDED_SERVICE,
-                                p_isvc->handle, 0 /* s_handle */,
-                                0 /* e_handle */, p_isvc->handle, p_isvc->uuid,
-                                0 /* property */);
+    for (const tBTA_GATTC_INCLUDED_SVC& p_isvc : service.included_svc) {
+      bta_gattc_fill_gatt_db_el(
+          curr_db_attr, BTGATT_DB_INCLUDED_SERVICE, p_isvc.handle,
+          p_isvc.included_service ? p_isvc.included_service->s_handle : 0,
+          0 /* e_handle */, p_isvc.handle, p_isvc.uuid, 0 /* property */);
       curr_db_attr++;
     }
   }
@@ -1251,20 +888,19 @@
 
   LOG_DEBUG(LOG_TAG, "%s", __func__);
   if (p_clcb == NULL) {
-    APPL_TRACE_ERROR("Unknown conn ID: %d", conn_id);
+    LOG(ERROR) << "Unknown conn_id=" << loghex(conn_id);
     return;
   }
 
   if (p_clcb->state != BTA_GATTC_CONN_ST) {
-    APPL_TRACE_ERROR("server cache not available, CLCB state = %d",
-                     p_clcb->state);
+    LOG(ERROR) << "server cache not available, CLCB state=" << +p_clcb->state;
     return;
   }
 
   if (!p_clcb->p_srcb ||
-      p_clcb->p_srcb->p_srvc_list || /* no active discovery */
-      !p_clcb->p_srcb->p_srvc_cache) {
-    APPL_TRACE_ERROR("No server cache available");
+      !p_clcb->p_srcb->pending_discovery.empty() || /* no active discovery */
+      p_clcb->p_srcb->srvc_cache.empty()) {
+    LOG(ERROR) << "No server cache available";
     return;
   }
 
@@ -1272,45 +908,36 @@
                              count);
 }
 
-/*******************************************************************************
- *
- * Function         bta_gattc_rebuild_cache
- *
- * Description      rebuild server cache from NV cache.
- *
- * Parameters
- *
- * Returns          None.
- *
- ******************************************************************************/
+/* rebuild server cache from NV cache */
 void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srvc_cb, uint16_t num_attr,
                              tBTA_GATTC_NV_ATTR* p_attr) {
   /* first attribute loading, initialize buffer */
-  APPL_TRACE_ERROR("%s: bta_gattc_rebuild_cache", __func__);
+  LOG(INFO) << __func__ << " " << num_attr;
 
-  list_free(p_srvc_cb->p_srvc_cache);
-  p_srvc_cb->p_srvc_cache = NULL;
+  // clear reallocating
+  std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
 
   while (num_attr > 0 && p_attr != NULL) {
     switch (p_attr->attr_type) {
       case BTA_GATTC_ATTR_TYPE_SRVC:
-        bta_gattc_add_srvc_to_cache(p_srvc_cb, p_attr->s_handle,
-                                    p_attr->e_handle, &p_attr->uuid,
-                                    p_attr->is_primary);
+        add_service_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
+                               p_attr->e_handle, p_attr->uuid,
+                               p_attr->is_primary);
         break;
 
       case BTA_GATTC_ATTR_TYPE_CHAR:
-        // TODO(jpawlowski): store decl_handle properly.
-        bta_gattc_add_char_to_cache(p_srvc_cb, p_attr->s_handle,
-                                    p_attr->s_handle, &p_attr->uuid,
-                                    p_attr->prop);
+        add_characteristic_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
+                                      p_attr->s_handle, p_attr->uuid,
+                                      p_attr->prop);
         break;
 
       case BTA_GATTC_ATTR_TYPE_CHAR_DESCR:
+        add_descriptor_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
+                                  p_attr->uuid);
+        break;
       case BTA_GATTC_ATTR_TYPE_INCL_SRVC:
-        bta_gattc_add_attr_to_cache(p_srvc_cb, p_attr->s_handle, &p_attr->uuid,
-                                    p_attr->prop, p_attr->incl_srvc_handle,
-                                    p_attr->attr_type);
+        add_incl_srvc_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
+                                 p_attr->uuid, p_attr->incl_srvc_handle);
         break;
     }
     p_attr++;
@@ -1328,7 +955,7 @@
  *
  ******************************************************************************/
 void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR* p_attr, uint8_t type,
-                            uint16_t s_handle, uint16_t e_handle, tBT_UUID uuid,
+                            uint16_t s_handle, uint16_t e_handle, Uuid uuid,
                             uint8_t prop, uint16_t incl_srvc_handle,
                             bool is_primary) {
   p_attr->s_handle = s_handle;
@@ -1338,8 +965,7 @@
   p_attr->id = 0;
   p_attr->prop = prop;
   p_attr->incl_srvc_handle = incl_srvc_handle;
-
-  memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID));
+  p_attr->uuid = uuid;
 }
 
 /*******************************************************************************
@@ -1352,65 +978,37 @@
  *
  ******************************************************************************/
 void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id) {
-  if (!p_srvc_cb->p_srvc_cache || list_is_empty(p_srvc_cb->p_srvc_cache))
-    return;
+  if (p_srvc_cb->srvc_cache.empty()) return;
 
   int i = 0;
-  size_t db_size =
-      bta_gattc_get_db_size(p_srvc_cb->p_srvc_cache, 0x0000, 0xFFFF);
+  size_t db_size = bta_gattc_get_db_size(p_srvc_cb->srvc_cache, 0x0000, 0xFFFF);
   tBTA_GATTC_NV_ATTR* nv_attr =
       (tBTA_GATTC_NV_ATTR*)osi_malloc(db_size * sizeof(tBTA_GATTC_NV_ATTR));
 
-  for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
-       sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
-
+  for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
     bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_SRVC,
-                           p_cur_srvc->s_handle, p_cur_srvc->e_handle,
-                           p_cur_srvc->uuid, 0 /* properties */,
-                           0 /* incl_srvc_handle */, p_cur_srvc->is_primary);
+                           service.s_handle, service.e_handle, service.uuid,
+                           0 /* properties */, 0 /* incl_srvc_handle */,
+                           service.is_primary);
   }
 
-  for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
-       sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
-
-    if (!p_cur_srvc->characteristics ||
-        list_is_empty(p_cur_srvc->characteristics))
-      continue;
-
-    for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
-         cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
-      tBTA_GATTC_CHARACTERISTIC* p_char =
-          (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-
+  for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
+    for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
       bta_gattc_fill_nv_attr(
-          &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR, p_char->handle, 0,
-          p_char->uuid, p_char->properties, 0 /* incl_srvc_handle */, false);
+          &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR, charac.value_handle, 0,
+          charac.uuid, charac.properties, 0 /* incl_srvc_handle */, false);
 
-      if (!p_char->descriptors || list_is_empty(p_char->descriptors)) continue;
-
-      for (list_node_t* dn = list_begin(p_char->descriptors);
-           dn != list_end(p_char->descriptors); dn = list_next(dn)) {
-        tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
-
-        bta_gattc_fill_nv_attr(
-            &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR_DESCR, p_desc->handle, 0,
-            p_desc->uuid, 0 /* properties */, 0 /* incl_srvc_handle */, false);
+      for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+        bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
+                               desc.handle, 0, desc.uuid, 0 /* properties */,
+                               0 /* incl_srvc_handle */, false);
       }
     }
 
-    if (!p_cur_srvc->included_svc || list_is_empty(p_cur_srvc->included_svc))
-      continue;
-
-    for (list_node_t* an = list_begin(p_cur_srvc->included_svc);
-         an != list_end(p_cur_srvc->included_svc); an = list_next(an)) {
-      tBTA_GATTC_INCLUDED_SVC* p_isvc = (tBTA_GATTC_INCLUDED_SVC*)list_node(an);
-
+    for (const tBTA_GATTC_INCLUDED_SVC& p_isvc : service.included_svc) {
       bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_INCL_SRVC,
-                             p_isvc->handle, 0, p_isvc->uuid,
-                             0 /* properties */,
-                             p_isvc->included_service->s_handle, false);
+                             p_isvc.handle, 0, p_isvc.uuid, 0 /* properties */,
+                             p_isvc.included_service->s_handle, false);
     }
   }
 
@@ -1436,8 +1034,8 @@
 
   FILE* fd = fopen(fname, "rb");
   if (!fd) {
-    APPL_TRACE_ERROR("%s: can't open GATT cache file %s for reading, error: %s",
-                     __func__, fname, strerror(errno));
+    LOG(ERROR) << __func__ << ": can't open GATT cache file " << fname
+               << " for reading, error: " << strerror(errno);
     return false;
   }
 
@@ -1447,31 +1045,25 @@
   uint16_t num_attr = 0;
 
   if (fread(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
-    APPL_TRACE_ERROR("%s: can't read GATT cache version from: %s", __func__,
-                     fname);
+    LOG(ERROR) << __func__ << ": can't read GATT cache version from: " << fname;
     goto done;
   }
 
   if (cache_ver != GATT_CACHE_VERSION) {
-    APPL_TRACE_ERROR("%s: wrong GATT cache version: %s", __func__, fname);
+    LOG(ERROR) << __func__ << ": wrong GATT cache version: " << fname;
     goto done;
   }
 
   if (fread(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
-    APPL_TRACE_ERROR("%s: can't read number of GATT attributes: %s", __func__,
-                     fname);
-    goto done;
-  }
-
-  if (num_attr > 0xFFFF) {
-    APPL_TRACE_ERROR("%s: more than 0xFFFF GATT attributes: %s", __func__, fname);
+    LOG(ERROR) << __func__
+               << ": can't read number of GATT attributes: " << fname;
     goto done;
   }
 
   attr = (tBTA_GATTC_NV_ATTR*)osi_malloc(sizeof(tBTA_GATTC_NV_ATTR) * num_attr);
 
   if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
-    APPL_TRACE_ERROR("%s: can't read GATT attributes: %s", __func__, fname);
+    LOG(ERROR) << __func__ << "s: can't read GATT attributes: " << fname;
     goto done;
   }
 
@@ -1505,28 +1097,27 @@
 
   FILE* fd = fopen(fname, "wb");
   if (!fd) {
-    APPL_TRACE_ERROR("%s: can't open GATT cache file for writing: %s", __func__,
-                     fname);
+    LOG(ERROR) << __func__
+               << ": can't open GATT cache file for writing: " << fname;
     return;
   }
 
   uint16_t cache_ver = GATT_CACHE_VERSION;
   if (fwrite(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
-    APPL_TRACE_ERROR("%s: can't write GATT cache version: %s", __func__, fname);
+    LOG(ERROR) << __func__ << ": can't write GATT cache version: " << fname;
     fclose(fd);
     return;
   }
 
   if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
-    APPL_TRACE_ERROR("%s: can't write GATT cache attribute count: %s", __func__,
-                     fname);
+    LOG(ERROR) << __func__
+               << ": can't write GATT cache attribute count: " << fname;
     fclose(fd);
     return;
   }
 
   if (fwrite(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
-    APPL_TRACE_ERROR("%s: can't write GATT cache attributes: %s", __func__,
-                     fname);
+    LOG(ERROR) << __func__ << ": can't write GATT cache attributes: " << fname;
     fclose(fd);
     return;
   }
@@ -1547,7 +1138,7 @@
  *
  ******************************************************************************/
 void bta_gattc_cache_reset(const RawAddress& server_bda) {
-  BTIF_TRACE_DEBUG("%s", __func__);
+  VLOG(1) << __func__;
   char fname[255] = {0};
   bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
   unlink(fname);
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index 8055090..5b33eae 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,6 +32,9 @@
 
 #include "bt_common.h"
 
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+
 /*****************************************************************************
  *  Constants and data types
  ****************************************************************************/
@@ -84,7 +87,7 @@
 typedef struct {
   BT_HDR hdr;
   RawAddress remote_bda;
-  tBTA_GATTC_IF client_if;
+  tGATT_IF client_if;
   bool is_direct;
   tBTA_TRANSPORT transport;
   uint8_t initiating_phys;
@@ -95,13 +98,13 @@
 
 typedef struct {
   BT_HDR hdr;
-  tBTA_GATT_AUTH_REQ auth_req;
+  tGATT_AUTH_REQ auth_req;
 
   // read by handle data
   uint16_t handle;
 
   // read by UUID data
-  tBT_UUID uuid;
+  bluetooth::Uuid uuid;
   uint16_t s_handle;
   uint16_t e_handle;
 
@@ -112,9 +115,9 @@
 
 typedef struct {
   BT_HDR hdr;
-  tBTA_GATT_AUTH_REQ auth_req;
+  tGATT_AUTH_REQ auth_req;
   uint16_t handle;
-  tBTA_GATTC_WRITE_TYPE write_type;
+  tGATT_WRITE_TYPE write_type;
   uint16_t offset;
   uint16_t len;
   uint8_t* p_value;
@@ -143,12 +146,12 @@
 
 typedef struct {
   BT_HDR hdr;
-  tBT_UUID* p_srvc_uuid;
+  bluetooth::Uuid* p_srvc_uuid;
 } tBTA_GATTC_API_SEARCH;
 
 typedef struct {
   BT_HDR hdr;
-  tBTA_GATT_AUTH_REQ auth_req;
+  tGATT_AUTH_REQ auth_req;
   uint8_t num_attr;
   uint16_t handles[GATT_MAX_READ_MULTI_HANDLES];
 } tBTA_GATTC_API_READ_MULTI;
@@ -161,7 +164,7 @@
 typedef struct {
   BT_HDR hdr;
   RawAddress remote_bda;
-  tBTA_GATTC_IF client_if;
+  tGATT_IF client_if;
   uint8_t role;
   tBT_TRANSPORT transport;
   tGATT_DISCONN_REASON reason;
@@ -182,26 +185,6 @@
   tBTA_GATTC_INT_CONN int_conn;
 } tBTA_GATTC_DATA;
 
-/* GATT server cache on the client */
-
-typedef struct {
-  tBT_UUID uuid;
-  uint16_t s_handle;
-  uint16_t e_handle;
-  // this field is set only for characteristic
-  uint16_t char_decl_handle;
-  bool is_primary;
-  tBTA_GATT_CHAR_PROP property;
-} tBTA_GATTC_ATTR_REC;
-
-#define BTA_GATTC_MAX_CACHE_CHAR 40
-#define BTA_GATTC_ATTR_LIST_SIZE \
-  (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC))
-
-#ifndef BTA_GATTC_CACHE_SRVR_SIZE
-#define BTA_GATTC_CACHE_SRVR_SIZE 600
-#endif
-
 enum {
   BTA_GATTC_IDLE_ST = 0, /* Idle  */
   BTA_GATTC_W4_CONN_ST,  /* Wait for connection -  (optional) */
@@ -223,16 +206,13 @@
 
   uint8_t state;
 
-  list_t* p_srvc_cache; /* list of tBTA_GATTC_SERVICE */
+  std::vector<tBTA_GATTC_SERVICE> srvc_cache;
   uint8_t update_count; /* indication received */
   uint8_t num_clcb;     /* number of associated CLCB */
 
-  tBTA_GATTC_ATTR_REC* p_srvc_list;
-  uint8_t cur_srvc_idx;
-  uint8_t cur_char_idx;
-  uint8_t next_avail_idx;
-  uint8_t total_srvc;
-  uint8_t total_char;
+  std::vector<tBTA_GATTC_SERVICE> pending_discovery;
+  std::vector<tBTA_GATTC_SERVICE>::iterator pending_service;
+  std::vector<tBTA_GATTC_CHARACTERISTIC>::iterator pending_char;
 
   uint8_t srvc_hdl_chg; /* service handle change indication pending */
   uint16_t attr_index;  /* cahce NV saving/loading attribute index */
@@ -253,11 +233,10 @@
 typedef struct {
   tBTA_GATTC_CBACK* p_cback;
   bool in_use;
-  tBTA_GATTC_IF
-      client_if;    /* client interface with BTE stack for this application */
+  tGATT_IF client_if; /* client interface with BTE stack for this application */
   uint8_t num_clcb; /* number of associated CLCB */
   bool dereg_pending;
-  tBT_UUID app_uuid;
+  bluetooth::Uuid app_uuid;
   tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX];
 } tBTA_GATTC_RCB;
 
@@ -279,7 +258,7 @@
   bool disc_active;
   bool in_use;
   tBTA_GATTC_STATE state;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   uint16_t reason;
 } tBTA_GATTC_CLCB;
 
@@ -338,7 +317,8 @@
 
 /* function processed outside SM */
 extern void bta_gattc_disable();
-extern void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_data,
+extern void bta_gattc_register(const bluetooth::Uuid& app_uuid,
+                               tBTA_GATTC_CBACK* p_data,
                                BtaAppRegisterCallback cb);
 extern void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg);
 extern void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg);
@@ -391,7 +371,7 @@
                                    tBTA_GATTC_RCB* p_clreg);
 extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data);
 extern void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg,
-                                      tBTA_GATT_STATUS status,
+                                      tGATT_STATUS status,
                                       const RawAddress& remote_bda,
                                       uint16_t conn_id,
                                       tBTA_TRANSPORT transport, uint16_t mtu);
@@ -405,11 +385,11 @@
                                                    const RawAddress& remote_bda,
                                                    tBTA_TRANSPORT transport);
 extern tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(uint16_t conn_id);
-extern tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if,
+extern tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tGATT_IF client_if,
                                              const RawAddress& remote_bda,
                                              tBTA_TRANSPORT transport);
 extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb);
-extern tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if,
+extern tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tGATT_IF client_if,
                                                   const RawAddress& remote_bda,
                                                   tBTA_TRANSPORT transport);
 extern tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if);
@@ -421,14 +401,12 @@
 
 extern bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
 
-extern bool bta_gattc_uuid_compare(const tBT_UUID* p_src, const tBT_UUID* p_tar,
-                                   bool is_precise);
 extern bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg,
                                            tBTA_GATTC_SERV* p_srcb,
                                            tBTA_GATTC_NOTIFY* p_notify);
-extern bool bta_gattc_mark_bg_conn(tBTA_GATTC_IF client_if,
+extern bool bta_gattc_mark_bg_conn(tGATT_IF client_if,
                                    const RawAddress& remote_bda, bool add);
-extern bool bta_gattc_check_bg_conn(tBTA_GATTC_IF client_if,
+extern bool bta_gattc_check_bg_conn(tGATT_IF client_if,
                                     const RawAddress& remote_bda, uint8_t role);
 extern uint8_t bta_gattc_num_reg_app(void);
 extern void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV* p_srcb,
@@ -444,29 +422,34 @@
 extern void bta_gattc_disc_cmpl_cback(uint16_t conn_id,
                                       tGATT_DISC_TYPE disc_type,
                                       tGATT_STATUS status);
-extern tBTA_GATT_STATUS bta_gattc_discover_procedure(
-    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb, uint8_t disc_type);
-extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(
-    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb, uint8_t disc_type);
-extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, tBT_UUID* p_uuid);
-extern const list_t* bta_gattc_get_services(uint16_t conn_id);
+extern tGATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
+                                                   tBTA_GATTC_SERV* p_server_cb,
+                                                   uint8_t disc_type);
+extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb,
+                                     bluetooth::Uuid* p_uuid);
+extern std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services(
+    uint16_t conn_id);
 extern const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(
     uint16_t conn_id, uint16_t handle);
 tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
     tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle);
 extern tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
                                                                uint16_t handle);
-extern tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
-                                                       uint16_t handle);
+extern const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+                                                             uint16_t handle);
+extern const tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic(
+    uint16_t conn_id, uint16_t handle);
 extern void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
                                   uint16_t end_handle, btgatt_db_element_t** db,
                                   int* count);
-extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
+extern tGATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
 extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srcv, uint16_t num_attr,
                                     tBTA_GATTC_NV_ATTR* attr);
 extern void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id);
 extern void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
-                                        tBTA_GATT_STATUS status);
+                                        tGATT_STATUS status);
 
 extern tBTA_GATTC_CONN* bta_gattc_conn_alloc(const RawAddress& remote_bda);
 extern tBTA_GATTC_CONN* bta_gattc_conn_find(const RawAddress& remote_bda);
diff --git a/bta/gatt/bta_gattc_main.cc b/bta/gatt/bta_gattc_main.cc
index 9a2deb6..afc3e51 100644
--- a/bta/gatt/bta_gattc_main.cc
+++ b/bta/gatt/bta_gattc_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,6 +29,8 @@
 #include "bt_common.h"
 #include "bta_gattc_int.h"
 
+using base::StringPrintf;
+
 /*****************************************************************************
  * Constants and types
  ****************************************************************************/
@@ -44,13 +46,11 @@
   BTA_GATTC_CONN,
   BTA_GATTC_START_DISCOVER,
   BTA_GATTC_DISC_CMPL,
-
   BTA_GATTC_Q_CMD,
   BTA_GATTC_CLOSE,
   BTA_GATTC_CLOSE_FAIL,
   BTA_GATTC_READ,
   BTA_GATTC_WRITE,
-
   BTA_GATTC_OP_CMPL,
   BTA_GATTC_SEARCH,
   BTA_GATTC_FAIL,
@@ -69,32 +69,32 @@
                                   tBTA_GATTC_DATA* p_data);
 
 /* action function list */
-const tBTA_GATTC_ACTION bta_gattc_action[] = {bta_gattc_open,
-                                              bta_gattc_open_fail,
-                                              bta_gattc_open_error,
-                                              bta_gattc_cancel_open,
-                                              bta_gattc_cancel_open_ok,
-                                              bta_gattc_cancel_open_error,
-                                              bta_gattc_conn,
-                                              bta_gattc_start_discover,
-                                              bta_gattc_disc_cmpl,
-
-                                              bta_gattc_q_cmd,
-                                              bta_gattc_close,
-                                              bta_gattc_close_fail,
-                                              bta_gattc_read,
-                                              bta_gattc_write,
-
-                                              bta_gattc_op_cmpl,
-                                              bta_gattc_search,
-                                              bta_gattc_fail,
-                                              bta_gattc_confirm,
-                                              bta_gattc_execute,
-                                              bta_gattc_read_multi,
-                                              bta_gattc_ignore_op_cmpl,
-                                              bta_gattc_disc_close,
-                                              bta_gattc_restart_discover,
-                                              bta_gattc_cfg_mtu};
+const tBTA_GATTC_ACTION bta_gattc_action[] = {
+    bta_gattc_open,              /* BTA_GATTC_OPEN */
+    bta_gattc_open_fail,         /* BTA_GATTC_OPEN_FAIL */
+    bta_gattc_open_error,        /* BTA_GATTC_OPEN_ERROR */
+    bta_gattc_cancel_open,       /* BTA_GATTC_CANCEL_OPEN */
+    bta_gattc_cancel_open_ok,    /* BTA_GATTC_CANCEL_OPEN_OK */
+    bta_gattc_cancel_open_error, /* BTA_GATTC_CANCEL_OPEN_ERROR */
+    bta_gattc_conn,              /* BTA_GATTC_CONN */
+    bta_gattc_start_discover,    /* BTA_GATTC_START_DISCOVER */
+    bta_gattc_disc_cmpl,         /* BTA_GATTC_DISC_CMPL */
+    bta_gattc_q_cmd,             /* BTA_GATTC_Q_CMD */
+    bta_gattc_close,             /* BTA_GATTC_CLOSE */
+    bta_gattc_close_fail,        /* BTA_GATTC_CLOSE_FAIL */
+    bta_gattc_read,              /* BTA_GATTC_READ */
+    bta_gattc_write,             /* BTA_GATTC_WRITE */
+    bta_gattc_op_cmpl,           /* BTA_GATTC_OP_CMPL */
+    bta_gattc_search,            /* BTA_GATTC_SEARCH */
+    bta_gattc_fail,              /* BTA_GATTC_FAIL */
+    bta_gattc_confirm,           /* BTA_GATTC_CONFIRM */
+    bta_gattc_execute,           /* BTA_GATTC_EXEC */
+    bta_gattc_read_multi,        /* BTA_GATTC_READ_MULTI */
+    bta_gattc_ignore_op_cmpl,    /* BTA_GATTC_IGNORE_OP_CMPL */
+    bta_gattc_disc_close,        /* BTA_GATTC_DISC_CLOSE */
+    bta_gattc_restart_discover,  /* BTA_GATTC_RESTART_DISCOVER */
+    bta_gattc_cfg_mtu            /* BTA_GATTC_CFG_MTU */
+};
 
 /* state table information */
 #define BTA_GATTC_ACTIONS 1    /* number of actions */
@@ -267,8 +267,11 @@
 
 /* state table */
 const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = {
-    bta_gattc_st_idle, bta_gattc_st_w4_conn, bta_gattc_st_connected,
-    bta_gattc_st_discover};
+    bta_gattc_st_idle,      /* BTA_GATTC_IDLE_ST */
+    bta_gattc_st_w4_conn,   /* BTA_GATTC_W4_CONN_ST */
+    bta_gattc_st_connected, /* BTA_GATTC_CONN_ST */
+    bta_gattc_st_discover   /* BTA_GATTC_DISCOVER_ST */
+};
 
 /*****************************************************************************
  * Global data
@@ -278,8 +281,8 @@
 tBTA_GATTC_CB bta_gattc_cb;
 
 #if (BTA_GATT_DEBUG == TRUE)
-static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code);
-static char* gattc_state_code(tBTA_GATTC_STATE state_code);
+static const char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code);
+static const char* gattc_state_code(tBTA_GATTC_STATE state_code);
 #endif
 
 /*******************************************************************************
@@ -299,12 +302,15 @@
   uint8_t action;
   int i;
   bool rt = true;
-#if (BTA_GATT_DEBUG == TRUE)
   tBTA_GATTC_STATE in_state = p_clcb->state;
   uint16_t in_event = event;
-  APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]",
-                   in_state, gattc_state_code(in_state), in_event,
-                   gattc_evt_code(in_event));
+#if (BTA_GATT_DEBUG == TRUE)
+  VLOG(1) << StringPrintf("%s: State 0x%02x [%s], Event 0x%x[%s]", __func__,
+                          in_state, gattc_state_code(in_state), in_event,
+                          gattc_evt_code(in_event));
+#else
+  VLOG(1) << StringPrintf("%s: State 0x%02x, Event 0x%x", __func__, in_state,
+                          in_event);
 #endif
 
   /* look up the state table for the current state */
@@ -333,10 +339,15 @@
 
 #if (BTA_GATT_DEBUG == TRUE)
   if (in_state != p_clcb->state) {
-    APPL_TRACE_DEBUG("GATTC State Change: [%s] -> [%s] after Event [%s]",
-                     gattc_state_code(in_state),
-                     gattc_state_code(p_clcb->state), gattc_evt_code(in_event));
+    VLOG(1) << StringPrintf("GATTC State Change: [%s] -> [%s] after Event [%s]",
+                            gattc_state_code(in_state),
+                            gattc_state_code(p_clcb->state),
+                            gattc_evt_code(in_event));
   }
+#else
+  VLOG(1) << StringPrintf(
+      "%s: GATTC State Change: 0x%02x -> 0x%02x after Event 0x%x", __func__,
+      in_state, p_clcb->state, in_event);
 #endif
   return rt;
 }
@@ -355,8 +366,7 @@
   tBTA_GATTC_CLCB* p_clcb = NULL;
   bool rt = true;
 #if (BTA_GATT_DEBUG == TRUE)
-  APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]",
-                   gattc_evt_code(p_msg->event));
+  VLOG(1) << __func__ << ": Event:" << gattc_evt_code(p_msg->event);
 #endif
   switch (p_msg->event) {
 
@@ -380,7 +390,7 @@
         rt =
             bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA*)p_msg);
       } else {
-        APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
+        VLOG(1) << "Ignore unknown conn ID: " << +p_msg->layer_specific;
       }
 
       break;
@@ -403,7 +413,7 @@
  * Returns          void
  *
  ******************************************************************************/
-static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) {
+static const char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) {
   switch (evt_code) {
     case BTA_GATTC_API_OPEN_EVT:
       return "BTA_GATTC_API_OPEN_EVT";
@@ -453,7 +463,7 @@
  * Returns          void
  *
  ******************************************************************************/
-static char* gattc_state_code(tBTA_GATTC_STATE state_code) {
+static const char* gattc_state_code(tBTA_GATTC_STATE state_code) {
   switch (state_code) {
     case BTA_GATTC_IDLE_ST:
       return "GATTC_IDLE_ST";
diff --git a/bta/gatt/bta_gattc_queue.cc b/bta/gatt/bta_gattc_queue.cc
new file mode 100644
index 0000000..c00a885
--- /dev/null
+++ b/bta/gatt/bta_gattc_queue.cc
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2017 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 "bta_gatt_queue.h"
+
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+
+using gatt_operation = BtaGattQueue::gatt_operation;
+
+constexpr uint8_t GATT_READ_CHAR = 1;
+constexpr uint8_t GATT_READ_DESC = 2;
+constexpr uint8_t GATT_WRITE_CHAR = 3;
+constexpr uint8_t GATT_WRITE_DESC = 4;
+
+struct gatt_read_op_data {
+  GATT_READ_OP_CB cb;
+  void* cb_data;
+};
+
+std::unordered_map<uint16_t, std::list<gatt_operation>>
+    BtaGattQueue::gatt_op_queue;
+std::unordered_set<uint16_t> BtaGattQueue::gatt_op_queue_executing;
+
+void BtaGattQueue::mark_as_not_executing(uint16_t conn_id) {
+  gatt_op_queue_executing.erase(conn_id);
+}
+
+void BtaGattQueue::gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
+                                         uint16_t handle, uint16_t len,
+                                         uint8_t* value, void* data) {
+  gatt_read_op_data* tmp = (gatt_read_op_data*)data;
+  GATT_READ_OP_CB tmp_cb = tmp->cb;
+  void* tmp_cb_data = tmp->cb_data;
+
+  osi_free(data);
+
+  mark_as_not_executing(conn_id);
+  gatt_execute_next_op(conn_id);
+
+  if (tmp_cb) {
+    tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
+    return;
+  }
+}
+
+struct gatt_write_op_data {
+  GATT_WRITE_OP_CB cb;
+  void* cb_data;
+};
+
+void BtaGattQueue::gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
+                                          uint16_t handle, void* data) {
+  gatt_write_op_data* tmp = (gatt_write_op_data*)data;
+  GATT_WRITE_OP_CB tmp_cb = tmp->cb;
+  void* tmp_cb_data = tmp->cb_data;
+
+  osi_free(data);
+
+  mark_as_not_executing(conn_id);
+  gatt_execute_next_op(conn_id);
+
+  if (tmp_cb) {
+    tmp_cb(conn_id, status, handle, tmp_cb_data);
+    return;
+  }
+}
+
+void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) {
+  APPL_TRACE_DEBUG("%s:", __func__, conn_id);
+  if (gatt_op_queue.empty()) {
+    APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
+    return;
+  }
+
+  auto map_ptr = gatt_op_queue.find(conn_id);
+  if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
+    APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
+                     conn_id);
+    return;
+  }
+
+  if (gatt_op_queue_executing.count(conn_id)) {
+    APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
+    return;
+  }
+
+  gatt_op_queue_executing.insert(conn_id);
+
+  std::list<gatt_operation>& gatt_ops = map_ptr->second;
+
+  gatt_operation& op = gatt_ops.front();
+
+  if (op.type == GATT_READ_CHAR) {
+    gatt_read_op_data* data =
+        (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
+    data->cb = op.read_cb;
+    data->cb_data = op.read_cb_data;
+    BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE,
+                                 gatt_read_op_finished, data);
+
+  } else if (op.type == GATT_READ_DESC) {
+    gatt_read_op_data* data =
+        (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
+    data->cb = op.read_cb;
+    data->cb_data = op.read_cb_data;
+    BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE,
+                            gatt_read_op_finished, data);
+
+  } else if (op.type == GATT_WRITE_CHAR) {
+    gatt_write_op_data* data =
+        (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
+    data->cb = op.write_cb;
+    data->cb_data = op.write_cb_data;
+    BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
+                             std::move(op.value), GATT_AUTH_REQ_NONE,
+                             gatt_write_op_finished, data);
+
+  } else if (op.type == GATT_WRITE_DESC) {
+    gatt_write_op_data* data =
+        (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
+    data->cb = op.write_cb;
+    data->cb_data = op.write_cb_data;
+    BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
+                             GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
+  }
+
+  gatt_ops.pop_front();
+}
+
+void BtaGattQueue::Clean(uint16_t conn_id) {
+  gatt_op_queue.erase(conn_id);
+  gatt_op_queue_executing.erase(conn_id);
+}
+
+void BtaGattQueue::ReadCharacteristic(uint16_t conn_id, uint16_t handle,
+                                      GATT_READ_OP_CB cb, void* cb_data) {
+  gatt_op_queue[conn_id].push_back({.type = GATT_READ_CHAR,
+                                    .handle = handle,
+                                    .read_cb = cb,
+                                    .read_cb_data = cb_data});
+  gatt_execute_next_op(conn_id);
+}
+
+void BtaGattQueue::ReadDescriptor(uint16_t conn_id, uint16_t handle,
+                                  GATT_READ_OP_CB cb, void* cb_data) {
+  gatt_op_queue[conn_id].push_back({.type = GATT_READ_DESC,
+                                    .handle = handle,
+                                    .read_cb = cb,
+                                    .read_cb_data = cb_data});
+  gatt_execute_next_op(conn_id);
+}
+
+void BtaGattQueue::WriteCharacteristic(uint16_t conn_id, uint16_t handle,
+                                       std::vector<uint8_t> value,
+                                       tGATT_WRITE_TYPE write_type,
+                                       GATT_WRITE_OP_CB cb, void* cb_data) {
+  gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
+                                    .handle = handle,
+                                    .write_type = write_type,
+                                    .write_cb = cb,
+                                    .write_cb_data = cb_data,
+                                    .value = std::move(value)});
+  gatt_execute_next_op(conn_id);
+}
+
+void BtaGattQueue::WriteDescriptor(uint16_t conn_id, uint16_t handle,
+                                   std::vector<uint8_t> value,
+                                   tGATT_WRITE_TYPE write_type,
+                                   GATT_WRITE_OP_CB cb, void* cb_data) {
+  gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
+                                    .handle = handle,
+                                    .write_type = write_type,
+                                    .write_cb = cb,
+                                    .write_cb_data = cb_data,
+                                    .value = std::move(value)});
+  gatt_execute_next_op(conn_id);
+}
diff --git a/bta/gatt/bta_gattc_utils.cc b/bta/gatt/bta_gattc_utils.cc
index f14f469..21b63c0 100644
--- a/bta/gatt/bta_gattc_utils.cc
+++ b/bta/gatt/bta_gattc_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,76 +35,6 @@
 #include "l2c_api.h"
 #include "utl.h"
 
-/*****************************************************************************
- *  Constants
- ****************************************************************************/
-
-static const uint8_t base_uuid[LEN_UUID_128] = {
-    0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
-    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-/*******************************************************************************
- *
- * Function         bta_gatt_convert_uuid16_to_uuid128
- *
- * Description      Convert a 16 bits UUID to be an standard 128 bits one.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
-                                        uint16_t uuid_16) {
-  uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
-
-  memcpy(uuid_128, base_uuid, LEN_UUID_128);
-
-  UINT16_TO_STREAM(p, uuid_16);
-}
-/*******************************************************************************
- *
- * Function         bta_gattc_uuid_compare
- *
- * Description      Compare two UUID to see if they are the same.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-bool bta_gattc_uuid_compare(const tBT_UUID* p_src, const tBT_UUID* p_tar,
-                            bool is_precise) {
-  uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
-  const uint8_t *ps, *pt;
-
-  /* any of the UUID is unspecified */
-  if (p_src == 0 || p_tar == 0) {
-    if (is_precise)
-      return false;
-    else
-      return true;
-  }
-
-  /* If both are 16-bit, we can do a simple compare */
-  if (p_src->len == 2 && p_tar->len == 2) {
-    return p_src->uu.uuid16 == p_tar->uu.uuid16;
-  }
-
-  /* One or both of the UUIDs is 128-bit */
-  if (p_src->len == LEN_UUID_16) {
-    /* convert a 16 bits UUID to 128 bits value */
-    bta_gatt_convert_uuid16_to_uuid128(su, p_src->uu.uuid16);
-    ps = su;
-  } else
-    ps = p_src->uu.uuid128;
-
-  if (p_tar->len == LEN_UUID_16) {
-    /* convert a 16 bits UUID to 128 bits value */
-    bta_gatt_convert_uuid16_to_uuid128(tu, p_tar->uu.uuid16);
-    pt = tu;
-  } else
-    pt = p_tar->uu.uuid128;
-
-  return (memcmp(ps, pt, LEN_UUID_128) == 0);
-}
-
 /*******************************************************************************
  *
  * Function         bta_gattc_cl_get_regcb
@@ -190,7 +120,7 @@
  * Returns          pointer to the clcb
  *
  ******************************************************************************/
-tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if,
+tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tGATT_IF client_if,
                                       const RawAddress& remote_bda,
                                       tBTA_TRANSPORT transport) {
   uint8_t i_clcb = 0;
@@ -199,12 +129,11 @@
   for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) {
     if (!bta_gattc_cb.clcb[i_clcb].in_use) {
 #if (BTA_GATT_DEBUG == TRUE)
-      APPL_TRACE_DEBUG("bta_gattc_clcb_alloc: found clcb[%d] available",
-                       i_clcb);
+      VLOG(1) << __func__ << ": found clcb:" << +i_clcb << " available";
 #endif
       p_clcb = &bta_gattc_cb.clcb[i_clcb];
       p_clcb->in_use = true;
-      p_clcb->status = BTA_GATT_OK;
+      p_clcb->status = GATT_SUCCESS;
       p_clcb->transport = transport;
       p_clcb->bda = remote_bda;
 
@@ -236,7 +165,7 @@
  * Returns          pointer to the clcb
  *
  ******************************************************************************/
-tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if,
+tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tGATT_IF client_if,
                                            const RawAddress& remote_bda,
                                            tBTA_TRANSPORT transport) {
   tBTA_GATTC_CLCB* p_clcb;
@@ -258,32 +187,28 @@
  *
  ******************************************************************************/
 void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb) {
-  tBTA_GATTC_SERV* p_srcb = NULL;
-
-  if (p_clcb) {
-    p_srcb = p_clcb->p_srcb;
-    if (p_srcb->num_clcb) p_srcb->num_clcb--;
-
-    if (p_clcb->p_rcb->num_clcb) p_clcb->p_rcb->num_clcb--;
-
-    /* if the srcb is no longer needed, reset the state */
-    if (p_srcb->num_clcb == 0) {
-      p_srcb->connected = false;
-      p_srcb->state = BTA_GATTC_SERV_IDLE;
-      p_srcb->mtu = 0;
-
-      /* clean up cache */
-      if (p_srcb->p_srvc_cache) {
-        list_free(p_srcb->p_srvc_cache);
-        p_srcb->p_srvc_cache = NULL;
-      }
-    }
-
-    osi_free_and_reset((void**)&p_clcb->p_q_cmd);
-    memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB));
-  } else {
-    APPL_TRACE_ERROR("bta_gattc_clcb_dealloc p_clcb=NULL");
+  if (!p_clcb) {
+    LOG(ERROR) << __func__ << " p_clcb=NULL";
+    return;
   }
+
+  tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+  if (p_srcb->num_clcb) p_srcb->num_clcb--;
+
+  if (p_clcb->p_rcb->num_clcb) p_clcb->p_rcb->num_clcb--;
+
+  /* if the srcb is no longer needed, reset the state */
+  if (p_srcb->num_clcb == 0) {
+    p_srcb->connected = false;
+    p_srcb->state = BTA_GATTC_SERV_IDLE;
+    p_srcb->mtu = 0;
+
+    // clear reallocating
+    std::vector<tBTA_GATTC_SERVICE>().swap(p_srcb->srvc_cache);
+  }
+
+  osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+  memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB));
 }
 
 /*******************************************************************************
@@ -370,10 +295,10 @@
     p_tcb = p_recycle;
 
   if (p_tcb != NULL) {
-    if (p_tcb->p_srvc_cache != NULL) list_free(p_tcb->p_srvc_cache);
-
-    osi_free_and_reset((void**)&p_tcb->p_srvc_list);
-    memset(p_tcb, 0, sizeof(tBTA_GATTC_SERV));
+    // clear reallocating
+    std::vector<tBTA_GATTC_SERVICE>().swap(p_tcb->srvc_cache);
+    std::vector<tBTA_GATTC_SERVICE>().swap(p_tcb->pending_discovery);
+    *p_tcb = tBTA_GATTC_SERV();
 
     p_tcb->in_use = true;
     p_tcb->server_bda = bda;
@@ -395,7 +320,7 @@
     return true;
   }
 
-  APPL_TRACE_ERROR("%s: already has a pending command!!", __func__);
+  LOG(ERROR) << __func__ << ": already has a pending command";
   /* skip the callback now. ----- need to send callback ? */
   return false;
 }
@@ -418,7 +343,7 @@
     if (p_clreg->notif_reg[i].in_use &&
         p_clreg->notif_reg[i].remote_bda == p_srcb->server_bda &&
         p_clreg->notif_reg[i].handle == p_notify->handle) {
-      APPL_TRACE_DEBUG("Notification registered!");
+      VLOG(1) << "Notification registered!";
       return true;
     }
   }
@@ -441,7 +366,7 @@
                                         uint16_t conn_id, uint16_t start_handle,
                                         uint16_t end_handle) {
   RawAddress remote_bda;
-  tBTA_GATTC_IF gatt_if;
+  tGATT_IF gatt_if;
   tBTA_GATTC_RCB* p_clrcb;
   uint8_t i;
   tGATT_TRANSPORT transport;
@@ -463,8 +388,7 @@
       }
     }
   } else {
-    APPL_TRACE_ERROR(
-        "can not clear indication/notif registration for unknown app");
+    LOG(ERROR) << "can not clear indication/notif registration for unknown app";
   }
   return;
 }
@@ -479,7 +403,7 @@
  * Returns          true if success; false otherwise.
  *
  ******************************************************************************/
-bool bta_gattc_mark_bg_conn(tBTA_GATTC_IF client_if,
+bool bta_gattc_mark_bg_conn(tGATT_IF client_if,
                             const RawAddress& remote_bda_ptr, bool add) {
   tBTA_GATTC_BG_TCK* p_bg_tck = &bta_gattc_cb.bg_track[0];
   uint8_t i = 0;
@@ -506,7 +430,8 @@
     }
   }
   if (!add) {
-    LOG(ERROR) << __func__ << " unable to find the bg connection mask for: "
+    LOG(ERROR) << __func__
+               << " unable to find the bg connection mask for bd_addr="
                << remote_bda_ptr;
     return false;
   } else /* adding a new device mask */
@@ -523,7 +448,7 @@
         return true;
       }
     }
-    APPL_TRACE_ERROR("no available space to mark the bg connection status");
+    LOG(ERROR) << "no available space to mark the bg connection status";
     return false;
   }
 }
@@ -537,8 +462,8 @@
  * Returns          true if success; false otherwise.
  *
  ******************************************************************************/
-bool bta_gattc_check_bg_conn(tBTA_GATTC_IF client_if,
-                             const RawAddress& remote_bda, uint8_t role) {
+bool bta_gattc_check_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda,
+                             uint8_t role) {
   tBTA_GATTC_BG_TCK* p_bg_tck = &bta_gattc_cb.bg_track[0];
   uint8_t i = 0;
   bool is_bg_conn = false;
@@ -562,7 +487,7 @@
  * Returns
  *
  ******************************************************************************/
-void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg, tBTA_GATT_STATUS status,
+void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg, tGATT_STATUS status,
                                const RawAddress& remote_bda, uint16_t conn_id,
                                tBTA_TRANSPORT transport, uint16_t mtu) {
   tBTA_GATTC cb_data;
@@ -596,8 +521,7 @@
   for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
     if (!p_conn->in_use) {
 #if (BTA_GATT_DEBUG == TRUE)
-      APPL_TRACE_DEBUG("bta_gattc_conn_alloc: found conn_track[%d] available",
-                       i_conn);
+      VLOG(1) << __func__ << ": found conn_track:" << +i_conn << " available";
 #endif
       p_conn->in_use = true;
       p_conn->remote_bda = remote_bda;
@@ -623,8 +547,7 @@
   for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
     if (p_conn->in_use && remote_bda == p_conn->remote_bda) {
 #if (BTA_GATT_DEBUG == TRUE)
-      APPL_TRACE_DEBUG("bta_gattc_conn_find: found conn_track[%d] matched",
-                       i_conn);
+      VLOG(1) << __func__ << ": found conn_track:" << +i_conn << " matched";
 #endif
       return p_conn;
     }
@@ -727,8 +650,8 @@
                                         p_msg->int_conn.transport);
   }
   if (p_clcb == NULL) {
-    APPL_TRACE_DEBUG(" disconnection ID: [%d] not used by BTA",
-                     p_msg->int_conn.hdr.layer_specific);
+    VLOG(1) << " disconnection ID:" << +p_msg->int_conn.hdr.layer_specific
+            << " not used by BTA";
   }
   return p_clcb;
 }
diff --git a/bta/gatt/bta_gatts_act.cc b/bta/gatt/bta_gatts_act.cc
index b328093..8e3d589 100644
--- a/bta/gatt/bta_gatts_act.cc
+++ b/bta/gatt/bta_gatts_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@
 #include "osi/include/osi.h"
 #include "utl.h"
 
+using base::StringPrintf;
+
 static void bta_gatts_nv_save_cback(bool is_saved,
                                     tGATTS_HNDL_RANGE* p_hndl_range);
 static bool bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd,
@@ -101,9 +103,9 @@
 static bool bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd,
                                        tGATTS_SRV_CHG_REQ* p_req,
                                        tGATTS_SRV_CHG_RSP* p_rsp) {
-  return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD)cmd,
-                              (tBTA_GATTS_SRV_CHG_REQ*)p_req,
-                              (tBTA_GATTS_SRV_CHG_RSP*)p_rsp);
+  return bta_gatts_co_srv_chg((tGATTS_SRV_CHG_CMD)cmd,
+                              (tGATTS_SRV_CHG_REQ*)p_req,
+                              (tGATTS_SRV_CHG_RSP*)p_rsp);
 }
 
 /*******************************************************************************
@@ -120,7 +122,7 @@
   tBTA_GATTS_HNDL_RANGE handle_range;
 
   if (p_cb->enabled) {
-    APPL_TRACE_DEBUG("GATTS already enabled.");
+    VLOG(1) << "GATTS already enabled.";
   } else {
     memset(p_cb, 0, sizeof(tBTA_GATTS_CB));
 
@@ -132,10 +134,10 @@
       index++;
     }
 
-    APPL_TRACE_DEBUG("bta_gatts_enable: num of handle range added=%d", index);
+    VLOG(1) << __func__ << ": num of handle range added:" << +index;
 
     if (!GATTS_NVRegister(&bta_gatts_nv_cback)) {
-      APPL_TRACE_ERROR("BTA GATTS NV register failed.");
+      LOG(ERROR) << "BTA GATTS NV register failed.";
     }
   }
 }
@@ -160,7 +162,7 @@
     }
     memset(p_cb, 0, sizeof(tBTA_GATTS_CB));
   } else {
-    APPL_TRACE_ERROR("GATTS not enabled");
+    LOG(ERROR) << "GATTS not enabled";
   }
 }
 
@@ -175,25 +177,24 @@
  ******************************************************************************/
 void bta_gatts_register(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
   tBTA_GATTS cb_data;
-  tBTA_GATT_STATUS status = BTA_GATT_OK;
+  tGATT_STATUS status = GATT_SUCCESS;
   uint8_t i, first_unuse = 0xff;
 
-  if (p_cb->enabled == false) {
+  if (!p_cb->enabled) {
     bta_gatts_enable(p_cb);
   }
 
   for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
     if (p_cb->rcb[i].in_use) {
-      if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid,
-                                 p_msg->api_reg.app_uuid)) {
-        APPL_TRACE_ERROR("application already registered.");
-        status = BTA_GATT_DUP_REG;
+      if (p_cb->rcb[i].app_uuid == p_msg->api_reg.app_uuid) {
+        LOG(ERROR) << "application already registered.";
+        status = GATT_DUP_REG;
         break;
       }
     }
   }
 
-  if (status == BTA_GATT_OK) {
+  if (status == GATT_SUCCESS) {
     for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
       if (first_unuse == 0xff && !p_cb->rcb[i].in_use) {
         first_unuse = i;
@@ -202,19 +203,17 @@
     }
 
     cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF;
-    memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
+    cb_data.reg_oper.uuid = p_msg->api_reg.app_uuid;
     if (first_unuse != 0xff) {
-      APPL_TRACE_ERROR("register application first_unuse rcb_idx = %d",
-                       first_unuse);
+      LOG(INFO) << "register application first_unuse rcb_idx=" << +first_unuse;
 
       p_cb->rcb[first_unuse].in_use = true;
       p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback;
-      memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid,
-             sizeof(tBT_UUID));
+      p_cb->rcb[first_unuse].app_uuid = p_msg->api_reg.app_uuid;
       cb_data.reg_oper.server_if = p_cb->rcb[first_unuse].gatt_if =
-          GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback);
+          GATT_Register(p_msg->api_reg.app_uuid, &bta_gatts_cback);
       if (!p_cb->rcb[first_unuse].gatt_if) {
-        status = BTA_GATT_NO_RESOURCES;
+        status = GATT_NO_RESOURCES;
       } else {
         tBTA_GATTS_INT_START_IF* p_buf = (tBTA_GATTS_INT_START_IF*)osi_malloc(
             sizeof(tBTA_GATTS_INT_START_IF));
@@ -224,7 +223,7 @@
         bta_sys_sendmsg(p_buf);
       }
     } else {
-      status = BTA_GATT_NO_RESOURCES;
+      status = GATT_NO_RESOURCES;
     }
   }
   cb_data.reg_oper.status = status;
@@ -246,8 +245,8 @@
   if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if)) {
     GATT_StartIf(p_msg->int_start_if.server_if);
   } else {
-    APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",
-                     p_msg->int_start_if.server_if);
+    LOG(ERROR) << "Unable to start app.: Unknown interface="
+               << +p_msg->int_start_if.server_if;
   }
 }
 /*******************************************************************************
@@ -260,7 +259,7 @@
  *
  ******************************************************************************/
 void bta_gatts_deregister(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
-  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  tGATT_STATUS status = GATT_ERROR;
   tBTA_GATTS_CBACK* p_cback = NULL;
   uint8_t i;
   tBTA_GATTS cb_data;
@@ -272,7 +271,7 @@
     if (p_cb->rcb[i].in_use &&
         p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if) {
       p_cback = p_cb->rcb[i].p_cback;
-      status = BTA_GATT_OK;
+      status = GATT_SUCCESS;
 
       /* deregister the app */
       GATT_Deregister(p_cb->rcb[i].gatt_if);
@@ -287,7 +286,7 @@
   if (p_cback) {
     (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data);
   } else {
-    APPL_TRACE_ERROR("application not registered.");
+    LOG(ERROR) << "application not registered.";
   }
 }
 
@@ -310,10 +309,10 @@
 
   if (GATTS_DeleteService(p_rcb->gatt_if, &p_srvc_cb->service_uuid,
                           p_srvc_cb->service_id)) {
-    cb_data.srvc_oper.status = BTA_GATT_OK;
+    cb_data.srvc_oper.status = GATT_SUCCESS;
     memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB));
   } else {
-    cb_data.srvc_oper.status = BTA_GATT_ERROR;
+    cb_data.srvc_oper.status = GATT_ERROR;
   }
 
   if (p_rcb->p_cback) (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data);
@@ -336,9 +335,8 @@
   GATTS_StopService(p_srvc_cb->service_id);
   cb_data.srvc_oper.server_if = p_rcb->gatt_if;
   cb_data.srvc_oper.service_id = p_srvc_cb->service_id;
-  cb_data.srvc_oper.status = BTA_GATT_OK;
-  APPL_TRACE_ERROR("bta_gatts_stop_service service_id= %d",
-                   p_srvc_cb->service_id);
+  cb_data.srvc_oper.status = GATT_SUCCESS;
+  LOG(ERROR) << __func__ << " service_id=" << +p_srvc_cb->service_id;
 
   if (p_rcb->p_cback) (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data);
 }
@@ -356,7 +354,7 @@
   if (GATTS_SendRsp(p_msg->api_rsp.hdr.layer_specific, p_msg->api_rsp.trans_id,
                     p_msg->api_rsp.status,
                     (tGATTS_RSP*)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) {
-    APPL_TRACE_ERROR("Sending response failed");
+    LOG(ERROR) << "Sending response failed";
   }
 }
 /*******************************************************************************
@@ -371,7 +369,7 @@
 void bta_gatts_indicate_handle(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
   tBTA_GATTS_SRVC_CB* p_srvc_cb;
   tBTA_GATTS_RCB* p_rcb = NULL;
-  tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+  tGATT_STATUS status = GATT_ILLEGAL_PARAMETER;
   tGATT_IF gatt_if;
   RawAddress remote_bda;
   tBTA_TRANSPORT transport;
@@ -401,8 +399,9 @@
         bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
       }
     } else {
-      APPL_TRACE_ERROR("Unknown connection ID: %d fail sending notification",
-                       p_msg->api_indicate.hdr.layer_specific);
+      LOG(ERROR) << "Unknown connection_id="
+                 << loghex(p_msg->api_indicate.hdr.layer_specific)
+                 << " fail sending notification";
     }
 
     if ((status != GATT_SUCCESS || !p_msg->api_indicate.need_confirm) &&
@@ -413,8 +412,8 @@
       (*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
     }
   } else {
-    APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x",
-                     p_msg->api_indicate.attr_id);
+    LOG(ERROR) << "Not an registered servce attribute ID: "
+               << loghex(p_msg->api_indicate.attr_id);
   }
 }
 
@@ -429,7 +428,7 @@
  ******************************************************************************/
 void bta_gatts_open(UNUSED_ATTR tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
   tBTA_GATTS_RCB* p_rcb = NULL;
-  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  tGATT_STATUS status = GATT_ERROR;
   uint16_t conn_id;
 
   p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if);
@@ -438,19 +437,22 @@
     if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda,
                      p_msg->api_open.is_direct, p_msg->api_open.transport,
                      false)) {
-      status = BTA_GATT_OK;
+      status = GATT_SUCCESS;
 
       if (GATT_GetConnIdIfConnected(p_rcb->gatt_if, p_msg->api_open.remote_bda,
                                     &conn_id, p_msg->api_open.transport)) {
-        status = BTA_GATT_ALREADY_OPEN;
+        status = GATT_ALREADY_OPEN;
       }
     }
   } else {
-    APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_open.server_if);
+    LOG(ERROR) << "Inavlid server_if=" << p_msg->api_open.server_if;
   }
 
-  if (p_rcb && p_rcb->p_cback)
-    (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS*)&status);
+  if (p_rcb && p_rcb->p_cback) {
+    tBTA_GATTS bta_gatts;
+    bta_gatts.status = status;
+    (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, &bta_gatts);
+  }
 }
 /*******************************************************************************
  *
@@ -464,22 +466,25 @@
 void bta_gatts_cancel_open(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
                            tBTA_GATTS_DATA* p_msg) {
   tBTA_GATTS_RCB* p_rcb;
-  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  tGATT_STATUS status = GATT_ERROR;
 
   p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_cancel_open.server_if);
   if (p_rcb != NULL) {
     if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda,
                             p_msg->api_cancel_open.is_direct)) {
-      APPL_TRACE_ERROR("bta_gatts_cancel_open failed for open request");
+      LOG(ERROR) << __func__ << ": failed for open request";
     } else {
-      status = BTA_GATT_OK;
+      status = GATT_SUCCESS;
     }
   } else {
-    APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_cancel_open.server_if);
+    LOG(ERROR) << "Inavlid server_if=" << +p_msg->api_cancel_open.server_if;
   }
 
-  if (p_rcb && p_rcb->p_cback)
-    (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS*)&status);
+  if (p_rcb && p_rcb->p_cback) {
+    tBTA_GATTS bta_gatts;
+    bta_gatts.status = status;
+    (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, &bta_gatts);
+  }
 }
 /*******************************************************************************
  *
@@ -492,18 +497,18 @@
  ******************************************************************************/
 void bta_gatts_close(UNUSED_ATTR tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
   tBTA_GATTS_RCB* p_rcb;
-  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  tGATT_STATUS status = GATT_ERROR;
   tGATT_IF gatt_if;
   RawAddress remote_bda;
-  tBTA_GATT_TRANSPORT transport;
+  tGATT_TRANSPORT transport;
 
   if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda,
                               &transport)) {
     if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS) {
-      APPL_TRACE_ERROR("bta_gatts_close fail conn_id=%d",
-                       p_msg->hdr.layer_specific);
+      LOG(ERROR) << __func__
+                 << ": fail conn_id=" << loghex(p_msg->hdr.layer_specific);
     } else {
-      status = BTA_GATT_OK;
+      status = GATT_SUCCESS;
     }
 
     p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
@@ -512,10 +517,12 @@
       if (transport == BTA_TRANSPORT_BR_EDR)
         bta_sys_conn_close(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
 
-      (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS*)&status);
+      tBTA_GATTS bta_gatts;
+      bta_gatts.status = status;
+      (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, &bta_gatts);
     }
   } else {
-    APPL_TRACE_ERROR("Unknown connection ID: %d", p_msg->hdr.layer_specific);
+    LOG(ERROR) << "Unknown connection_id=" << loghex(p_msg->hdr.layer_specific);
   }
 }
 
@@ -534,7 +541,7 @@
   tBTA_GATTS cb_data;
   tBTA_GATTS_RCB* p_rcb;
   tGATT_IF gatt_if;
-  tBTA_GATT_TRANSPORT transport;
+  tGATT_TRANSPORT transport;
 
   memset(&cb_data, 0, sizeof(tBTA_GATTS));
 
@@ -542,8 +549,8 @@
                               &transport)) {
     p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
 
-    APPL_TRACE_DEBUG("%s: conn_id=%d trans_id=%d req_type=%d", __func__,
-                     conn_id, trans_id, req_type);
+    VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
+            << ", trans_id=" << +trans_id << ", req_type=" << +req_type;
 
     if (p_rcb && p_rcb->p_cback) {
       /* if over BR_EDR, inform PM for mode change */
@@ -554,15 +561,15 @@
 
       cb_data.req_data.conn_id = conn_id;
       cb_data.req_data.trans_id = trans_id;
-      cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA*)p_data;
+      cb_data.req_data.p_data = (tGATTS_DATA*)p_data;
 
       (*p_rcb->p_cback)(req_type, &cb_data);
     } else {
-      APPL_TRACE_ERROR("connection request on gatt_if[%d] is not interested",
-                       gatt_if);
+      LOG(ERROR) << "connection request on gatt_if=" << +gatt_if
+                 << " is not interested";
     }
   } else {
-    APPL_TRACE_ERROR("request received on unknown connectino ID: %d", conn_id);
+    LOG(ERROR) << "request received on unknown conn_id=" << loghex(conn_id);
   }
 }
 
@@ -583,10 +590,9 @@
   uint8_t evt = connected ? BTA_GATTS_CONNECT_EVT : BTA_GATTS_DISCONNECT_EVT;
   tBTA_GATTS_RCB* p_reg;
 
-  APPL_TRACE_DEBUG(
-      "bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d",
-      gatt_if, conn_id, connected, reason);
-  VLOG(1) << __func__ << "  bda :" << bdaddr;
+  VLOG(1) << __func__ << "  bda=" << bdaddr << " gatt_if= " << gatt_if
+          << ", conn_id=" << loghex(conn_id) << " connected=" << connected
+          << ", reason=" << loghex(reason);
 
   if (connected)
     btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
@@ -611,7 +617,7 @@
     cb_data.conn.remote_bda = bdaddr;
     (*p_reg->p_cback)(evt, &cb_data);
   } else {
-    APPL_TRACE_ERROR("bta_gatts_conn_cback server_if=%d not found", gatt_if);
+    LOG(ERROR) << __func__ << " server_if=" << +gatt_if << " not found";
   }
 }
 
@@ -620,7 +626,7 @@
                                        uint8_t status) {
   tBTA_GATTS_RCB* p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
   if (!p_reg || !p_reg->p_cback) {
-    APPL_TRACE_ERROR("%s: server_if=%d not found", __func__, gatt_if);
+    LOG(ERROR) << __func__ << ": server_if=" << +gatt_if << " not found";
     return;
   }
 
@@ -638,7 +644,7 @@
                                         uint16_t timeout, uint8_t status) {
   tBTA_GATTS_RCB* p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
   if (!p_reg || !p_reg->p_cback) {
-    APPL_TRACE_ERROR("%s: server_if=%d not found", __func__, gatt_if);
+    LOG(ERROR) << __func__ << ": server_if=" << +gatt_if << " not found";
     return;
   }
 
@@ -664,7 +670,7 @@
 static void bta_gatts_cong_cback(uint16_t conn_id, bool congested) {
   tBTA_GATTS_RCB* p_rcb;
   tGATT_IF gatt_if;
-  tBTA_GATT_TRANSPORT transport;
+  tGATT_TRANSPORT transport;
   tBTA_GATTS cb_data;
 
   if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda,
diff --git a/bta/gatt/bta_gatts_api.cc b/bta/gatt/bta_gatts_api.cc
index 7d45043..9d7cda0 100644
--- a/bta/gatt/bta_gatts_api.cc
+++ b/bta/gatt/bta_gatts_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2010-2012 Broadcom Corporation
+ *  Copyright 2010-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,15 +24,15 @@
 
 #include "bt_target.h"
 
+#include <base/bind.h>
 #include <string.h>
 
 #include "bt_common.h"
+#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "bta_gatts_int.h"
 #include "bta_sys.h"
 
-void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src);
-
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
@@ -52,8 +52,8 @@
  *
  ******************************************************************************/
 void BTA_GATTS_Disable(void) {
-  if (bta_sys_is_register(BTA_ID_GATTS) == false) {
-    APPL_TRACE_WARNING("GATTS Module not enabled/already disabled");
+  if (!bta_sys_is_register(BTA_ID_GATTS)) {
+    LOG(WARNING) << "GATTS Module not enabled/already disabled";
     return;
   }
 
@@ -76,17 +76,17 @@
  * Returns          None
  *
  ******************************************************************************/
-void BTA_GATTS_AppRegister(tBT_UUID* p_app_uuid, tBTA_GATTS_CBACK* p_cback) {
+void BTA_GATTS_AppRegister(const bluetooth::Uuid& app_uuid,
+                           tBTA_GATTS_CBACK* p_cback) {
   tBTA_GATTS_API_REG* p_buf =
       (tBTA_GATTS_API_REG*)osi_malloc(sizeof(tBTA_GATTS_API_REG));
 
   /* register with BTA system manager */
-  if (bta_sys_is_register(BTA_ID_GATTS) == false)
+  if (!bta_sys_is_register(BTA_ID_GATTS))
     bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg);
 
   p_buf->hdr.event = BTA_GATTS_API_REG_EVT;
-  if (p_app_uuid != NULL)
-    memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
+  p_buf->app_uuid = app_uuid;
   p_buf->p_cback = p_cback;
 
   bta_sys_sendmsg(p_buf);
@@ -103,7 +103,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) {
+void BTA_GATTS_AppDeregister(tGATT_IF server_if) {
   tBTA_GATTS_API_DEREG* p_buf =
       (tBTA_GATTS_API_DEREG*)osi_malloc(sizeof(tBTA_GATTS_API_DEREG));
 
@@ -113,6 +113,43 @@
   bta_sys_sendmsg(p_buf);
 }
 
+void bta_gatts_add_service_impl(tGATT_IF server_if,
+                                std::vector<btgatt_db_element_t> service,
+                                BTA_GATTS_AddServiceCb cb) {
+  uint8_t rcb_idx =
+      bta_gatts_find_app_rcb_idx_by_app_if(&bta_gatts_cb, server_if);
+
+  LOG(INFO) << __func__ << ": rcb_idx=" << +rcb_idx;
+
+  if (rcb_idx == BTA_GATTS_INVALID_APP) {
+    cb.Run(GATT_ERROR, server_if, std::move(service));
+    return;
+  }
+
+  uint8_t srvc_idx = bta_gatts_alloc_srvc_cb(&bta_gatts_cb, rcb_idx);
+  if (srvc_idx == BTA_GATTS_INVALID_APP) {
+    cb.Run(GATT_ERROR, server_if, std::move(service));
+    return;
+  }
+
+  uint16_t status = GATTS_AddService(server_if, service.data(), service.size());
+  if (status != GATT_SERVICE_STARTED) {
+    memset(&bta_gatts_cb.srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB));
+    LOG(ERROR) << __func__ << ": service creation failed.";
+    cb.Run(GATT_ERROR, server_if, std::move(service));
+    return;
+  }
+
+  bta_gatts_cb.srvc_cb[srvc_idx].service_uuid = service[0].uuid;
+
+  // service_id is equal to service start handle
+  bta_gatts_cb.srvc_cb[srvc_idx].service_id = service[0].attribute_handle;
+  bta_gatts_cb.srvc_cb[srvc_idx].idx = srvc_idx;
+
+  cb.Run(GATT_SUCCESS, server_if, std::move(service));
+  return;
+}
+
 /*******************************************************************************
  *
  * Function         BTA_GATTS_AddService
@@ -124,38 +161,15 @@
  * Parameters       server_if: server interface.
  *                  service: pointer vector describing service.
  *
- * Returns          Returns |BTA_GATT_OK| on success or |BTA_GATT_ERROR| if the
+ * Returns          Returns |GATT_SUCCESS| on success or |GATT_ERROR| if the
  *                  service cannot be added.
  *
  ******************************************************************************/
-extern uint16_t BTA_GATTS_AddService(tBTA_GATTS_IF server_if,
-                                     vector<btgatt_db_element_t>& service) {
-  uint8_t rcb_idx =
-      bta_gatts_find_app_rcb_idx_by_app_if(&bta_gatts_cb, server_if);
-
-  APPL_TRACE_ERROR("%s: rcb_idx = %d", __func__, rcb_idx);
-
-  if (rcb_idx == BTA_GATTS_INVALID_APP) return BTA_GATT_ERROR;
-
-  uint8_t srvc_idx = bta_gatts_alloc_srvc_cb(&bta_gatts_cb, rcb_idx);
-  if (srvc_idx == BTA_GATTS_INVALID_APP) return BTA_GATT_ERROR;
-
-  uint16_t status = GATTS_AddService(server_if, service.data(), service.size());
-
-  if (status == GATT_SERVICE_STARTED) {
-    btif_to_bta_uuid(&bta_gatts_cb.srvc_cb[srvc_idx].service_uuid,
-                     &service[0].uuid);
-
-    // service_id is equal to service start handle
-    bta_gatts_cb.srvc_cb[srvc_idx].service_id = service[0].attribute_handle;
-    bta_gatts_cb.srvc_cb[srvc_idx].idx = srvc_idx;
-
-    return BTA_GATT_OK;
-  } else {
-    memset(&bta_gatts_cb.srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB));
-    APPL_TRACE_ERROR("%s: service creation failed.", __func__);
-    return BTA_GATT_ERROR;
-  }
+extern void BTA_GATTS_AddService(tGATT_IF server_if,
+                                 std::vector<btgatt_db_element_t> service,
+                                 BTA_GATTS_AddServiceCb cb) {
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_gatts_add_service_impl, server_if,
+                                         std::move(service), std::move(cb)));
 }
 
 /*******************************************************************************
@@ -248,9 +262,9 @@
  * Returns          None
  *
  ******************************************************************************/
-void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
-                       tBTA_GATT_STATUS status, tBTA_GATTS_RSP* p_msg) {
-  const size_t len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP);
+void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id, tGATT_STATUS status,
+                       tGATTS_RSP* p_msg) {
+  const size_t len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tGATTS_RSP);
   tBTA_GATTS_API_RSP* p_buf = (tBTA_GATTS_API_RSP*)osi_calloc(len);
 
   p_buf->hdr.event = BTA_GATTS_API_RSP_EVT;
@@ -258,8 +272,8 @@
   p_buf->trans_id = trans_id;
   p_buf->status = status;
   if (p_msg != NULL) {
-    p_buf->p_rsp = (tBTA_GATTS_RSP*)(p_buf + 1);
-    memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP));
+    p_buf->p_rsp = (tGATTS_RSP*)(p_buf + 1);
+    memcpy(p_buf->p_rsp, p_msg, sizeof(tGATTS_RSP));
   }
 
   bta_sys_sendmsg(p_buf);
@@ -281,8 +295,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_GATTS_Open(tBTA_GATTS_IF server_if, const RawAddress& remote_bda,
-                    bool is_direct, tBTA_GATT_TRANSPORT transport) {
+void BTA_GATTS_Open(tGATT_IF server_if, const RawAddress& remote_bda,
+                    bool is_direct, tGATT_TRANSPORT transport) {
   tBTA_GATTS_API_OPEN* p_buf =
       (tBTA_GATTS_API_OPEN*)osi_malloc(sizeof(tBTA_GATTS_API_OPEN));
 
@@ -309,7 +323,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, const RawAddress& remote_bda,
+void BTA_GATTS_CancelOpen(tGATT_IF server_if, const RawAddress& remote_bda,
                           bool is_direct) {
   tBTA_GATTS_API_CANCEL_OPEN* p_buf = (tBTA_GATTS_API_CANCEL_OPEN*)osi_malloc(
       sizeof(tBTA_GATTS_API_CANCEL_OPEN));
diff --git a/bta/gatt/bta_gatts_int.h b/bta/gatt/bta_gatts_int.h
index df5d706..adecf30 100644
--- a/bta/gatt/bta_gatts_int.h
+++ b/bta/gatt/bta_gatts_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
 #include "bta_sys.h"
 #include "gatt_api.h"
 
+#include <base/strings/stringprintf.h>
 #include "bt_common.h"
 
 /*****************************************************************************
@@ -59,20 +60,20 @@
 /* internal strucutre for GATTC register API  */
 typedef struct {
   BT_HDR hdr;
-  tBT_UUID app_uuid;
+  bluetooth::Uuid app_uuid;
   tBTA_GATTS_CBACK* p_cback;
 } tBTA_GATTS_API_REG;
 
 typedef struct {
   BT_HDR hdr;
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
 } tBTA_GATTS_INT_START_IF;
 
 typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG;
 
 typedef struct {
   BT_HDR hdr;
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   btgatt_db_element_t* service;
   uint16_t count;
 } tBTA_GATTS_API_ADD_SERVICE;
@@ -82,27 +83,27 @@
   uint16_t attr_id;
   uint16_t len;
   bool need_confirm;
-  uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+  uint8_t value[GATT_MAX_ATTR_LEN];
 } tBTA_GATTS_API_INDICATION;
 
 typedef struct {
   BT_HDR hdr;
   uint32_t trans_id;
-  tBTA_GATT_STATUS status;
-  tBTA_GATTS_RSP* p_rsp;
+  tGATT_STATUS status;
+  tGATTS_RSP* p_rsp;
 } tBTA_GATTS_API_RSP;
 
 typedef struct {
   BT_HDR hdr;
-  tBTA_GATT_TRANSPORT transport;
+  tGATT_TRANSPORT transport;
 } tBTA_GATTS_API_START;
 
 typedef struct {
   BT_HDR hdr;
   RawAddress remote_bda;
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   bool is_direct;
-  tBTA_GATT_TRANSPORT transport;
+  tGATT_TRANSPORT transport;
 
 } tBTA_GATTS_API_OPEN;
 
@@ -124,14 +125,14 @@
 /* application registration control block */
 typedef struct {
   bool in_use;
-  tBT_UUID app_uuid;
+  bluetooth::Uuid app_uuid;
   tBTA_GATTS_CBACK* p_cback;
-  tBTA_GATTS_IF gatt_if;
+  tGATT_IF gatt_if;
 } tBTA_GATTS_RCB;
 
 /* service registration control block */
 typedef struct {
-  tBT_UUID service_uuid; /* service UUID */
+  bluetooth::Uuid service_uuid; /* service UUID */
   uint16_t service_id;   /* service start handle */
   uint8_t rcb_idx;
   uint8_t idx; /* self index of serviec CB */
@@ -175,11 +176,9 @@
 extern void bta_gatts_cancel_open(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
 extern void bta_gatts_close(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
 
-extern bool bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src);
-extern tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(
-    tBTA_GATTS_IF server_if);
+extern tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(tGATT_IF server_if);
 extern uint8_t bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB* p_cb,
-                                                    tBTA_GATTS_IF server_if);
+                                                    tGATT_IF server_if);
 extern uint8_t bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB* p_cb, uint8_t rcb_idx);
 extern tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_srvc_id(
     tBTA_GATTS_CB* p_cb, uint16_t service_id);
diff --git a/bta/gatt/bta_gatts_main.cc b/bta/gatt/bta_gatts_main.cc
index ac82878..1dc0aa2 100644
--- a/bta/gatt/bta_gatts_main.cc
+++ b/bta/gatt/bta_gatts_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -89,8 +89,7 @@
       if (p_srvc_cb != NULL)
         bta_gatts_delete_service(p_srvc_cb, (tBTA_GATTS_DATA*)p_msg);
       else
-        APPL_TRACE_ERROR("%s: can't delete service - no srvc_cb found",
-                         __func__);
+        LOG(ERROR) << __func__ << ": can't delete service - no srvc_cb found";
 
       break;
     }
@@ -102,7 +101,7 @@
       if (p_srvc_cb != NULL)
         bta_gatts_stop_service(p_srvc_cb, (tBTA_GATTS_DATA*)p_msg);
       else
-        APPL_TRACE_ERROR("%s: can't stop service - no srvc_cb found", __func__);
+        LOG(ERROR) << __func__ << ": can't stop service - no srvc_cb found";
 
       break;
     }
diff --git a/bta/gatt/bta_gatts_utils.cc b/bta/gatt/bta_gatts_utils.cc
index 23cc7c7..173d4f3 100644
--- a/bta/gatt/bta_gatts_utils.cc
+++ b/bta/gatt/bta_gatts_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,27 +31,6 @@
 #include "bta_sys.h"
 #include "utl.h"
 
-static const uint8_t base_uuid[LEN_UUID_128] = {
-    0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
-    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-/*******************************************************************************
- *
- * Function         bta_gatt_convert_uuid16_to_uuid128
- *
- * Description      Convert a 16 bits UUID to be an standard 128 bits one.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-static void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
-                                               uint16_t uuid_16) {
-  uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
-
-  memcpy(uuid_128, base_uuid, LEN_UUID_128);
-
-  UINT16_TO_STREAM(p, uuid_16);
-}
 /*******************************************************************************
  *
  * Function         bta_gatts_alloc_srvc_cb
@@ -83,7 +62,7 @@
  * Returns          pointer to the control block if success, otherwise NULL
  *
  ******************************************************************************/
-tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if) {
+tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(tGATT_IF server_if) {
   uint8_t i;
   tBTA_GATTS_RCB* p_reg;
 
@@ -106,7 +85,7 @@
  ******************************************************************************/
 
 uint8_t bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB* p_cb,
-                                             tBTA_GATTS_IF server_if) {
+                                             tGATT_IF server_if) {
   uint8_t i;
 
   for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
@@ -126,12 +105,10 @@
 tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB* p_cb,
                                                       uint16_t service_id) {
   uint8_t i;
-  APPL_TRACE_DEBUG("bta_gatts_find_srvc_cb_by_srvc_id  service_id=%d",
-                   service_id);
+  VLOG(1) << __func__ << ": service_id=" << +service_id;
   for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i++) {
     if (p_cb->srvc_cb[i].in_use && p_cb->srvc_cb[i].service_id == service_id) {
-      APPL_TRACE_DEBUG(
-          "bta_gatts_find_srvc_cb_by_srvc_id  found service cb index =%d", i);
+      VLOG(1) << __func__ << ": found service cb index=" << +i;
       return &p_cb->srvc_cb[i];
     }
   }
@@ -168,43 +145,3 @@
   }
   return NULL;
 }
-/*******************************************************************************
- *
- * Function         bta_gatts_uuid_compare
- *
- * Description      Compare two UUID to see if they are the same.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-bool bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src) {
-  uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
-  uint8_t *ps, *pt;
-
-  /* any of the UUID is unspecified */
-  if (src.len == 0 || tar.len == 0) {
-    return true;
-  }
-
-  /* If both are 16-bit, we can do a simple compare */
-  if (src.len == 2 && tar.len == 2) {
-    return src.uu.uuid16 == tar.uu.uuid16;
-  }
-
-  /* One or both of the UUIDs is 128-bit */
-  if (src.len == LEN_UUID_16) {
-    /* convert a 16 bits UUID to 128 bits value */
-    bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
-    ps = su;
-  } else
-    ps = src.uu.uuid128;
-
-  if (tar.len == LEN_UUID_16) {
-    /* convert a 16 bits UUID to 128 bits value */
-    bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
-    pt = tu;
-  } else
-    pt = tar.uu.uuid128;
-
-  return (memcmp(ps, pt, LEN_UUID_128) == 0);
-}
diff --git a/bta/hd/bta_hd_act.cc b/bta/hd/bta_hd_act.cc
index b8cdb7d..0d677ee 100644
--- a/bta/hd/bta_hd_act.cc
+++ b/bta/hd/bta_hd_act.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -104,7 +104,9 @@
   }
 
   /* signal BTA call back event */
-  (*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD*)&status);
+  tBTA_HD bta_hd;
+  bta_hd.status = status;
+  (*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, &bta_hd);
 }
 
 /*******************************************************************************
@@ -139,7 +141,9 @@
     APPL_TRACE_ERROR("%s: Failed to deregister HID device (%s)", __func__, ret);
   }
 
-  (*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, (tBTA_HD*)&status);
+  tBTA_HD bta_hd;
+  bta_hd.status = status;
+  (*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, &bta_hd);
 
   memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
 }
@@ -232,7 +236,9 @@
   bta_hd_cb.sdp_handle = 0;
   bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
 
-  (*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, (tBTA_HD*)&status);
+  tBTA_HD bta_hd;
+  bta_hd.status = status;
+  (*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, &bta_hd);
 }
 
 /*******************************************************************************
@@ -520,7 +526,9 @@
   ret.len = len;
   ret.p_data = p_buf;
 
-  (*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, (tBTA_HD*)&ret);
+  tBTA_HD bta_hd;
+  bta_hd.intr_data = ret;
+  (*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, &bta_hd);
 }
 
 /*******************************************************************************
@@ -569,7 +577,9 @@
     ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
   }
 
-  (*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD*)&ret);
+  tBTA_HD bta_hd;
+  bta_hd.get_report = ret;
+  (*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, &bta_hd);
 }
 
 /*******************************************************************************
@@ -614,7 +624,9 @@
   ret.len = len;
   ret.p_data = p_buf;
 
-  (*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, (tBTA_HD*)&ret);
+  tBTA_HD bta_hd;
+  bta_hd.set_report = ret;
+  (*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, &bta_hd);
 }
 
 /*******************************************************************************
diff --git a/bta/hd/bta_hd_api.cc b/bta/hd/bta_hd_api.cc
index 199bc7b..5459747 100644
--- a/bta/hd/bta_hd_api.cc
+++ b/bta/hd/bta_hd_api.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -104,23 +104,20 @@
   p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
 
   if (p_app_info->p_name) {
-    strncpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
-    p_buf->name[BTA_HD_APP_NAME_LEN] = '\0';
+    strlcpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
   } else {
     p_buf->name[0] = '\0';
   }
 
   if (p_app_info->p_description) {
-    strncpy(p_buf->description, p_app_info->p_description,
+    strlcpy(p_buf->description, p_app_info->p_description,
             BTA_HD_APP_DESCRIPTION_LEN);
-    p_buf->description[BTA_HD_APP_DESCRIPTION_LEN] = '\0';
   } else {
     p_buf->description[0] = '\0';
   }
 
   if (p_app_info->p_provider) {
-    strncpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
-    p_buf->provider[BTA_HD_APP_PROVIDER_LEN] = '\0';
+    strlcpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
   } else {
     p_buf->provider[0] = '\0';
   }
diff --git a/bta/hd/bta_hd_int.h b/bta/hd/bta_hd_int.h
index 318e350..4a48254 100644
--- a/bta/hd/bta_hd_int.h
+++ b/bta/hd/bta_hd_int.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -77,9 +77,9 @@
 
 typedef struct {
   BT_HDR hdr;
-  char name[BTA_HD_APP_NAME_LEN + 1];
-  char description[BTA_HD_APP_DESCRIPTION_LEN + 1];
-  char provider[BTA_HD_APP_PROVIDER_LEN + 1];
+  char name[BTA_HD_APP_NAME_LEN];
+  char description[BTA_HD_APP_DESCRIPTION_LEN];
+  char provider[BTA_HD_APP_PROVIDER_LEN];
   uint8_t subclass;
   uint16_t d_len;
   uint8_t d_data[BTA_HD_APP_DESCRIPTOR_LEN];
@@ -141,12 +141,7 @@
   bool disable_w4_close;
 } tBTA_HD_CB;
 
-#if BTA_DYNAMIC_MEMORY == FALSE
 extern tBTA_HD_CB bta_hd_cb;
-#else
-extern tBTA_HD_CB* bta_hd_cb_ptr;
-#define bta_hd_cb (*bta_hd_cb_ptr)
-#endif
 
 /*****************************************************************************
  *  Function prototypes
diff --git a/bta/hd/bta_hd_main.cc b/bta/hd/bta_hd_main.cc
index dff5d9c..84784b1 100644
--- a/bta/hd/bta_hd_main.cc
+++ b/bta/hd/bta_hd_main.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -219,9 +219,7 @@
 /*****************************************************************************
  * Global data
  ****************************************************************************/
-#if BTA_DYNAMIC_MEMORY == FALSE
 tBTA_HD_CB bta_hd_cb;
-#endif
 
 static const char* bta_hd_evt_code(tBTA_HD_INT_EVT evt_code);
 static const char* bta_hd_state_code(tBTA_HD_STATE state_code);
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
new file mode 100644
index 0000000..8779542
--- /dev/null
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -0,0 +1,1221 @@
+/******************************************************************************
+ *
+ *  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 "bta_hearing_aid_api.h"
+
+#include "bta_gatt_api.h"
+#include "bta_gatt_queue.h"
+#include "btm_int.h"
+#include "device/include/controller.h"
+#include "embdrv/g722/g722_enc_dec.h"
+#include "gap_api.h"
+#include "gatt_api.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <hardware/bt_hearing_aid.h>
+#include <vector>
+
+using base::Closure;
+using bluetooth::Uuid;
+using bluetooth::hearing_aid::ConnectionState;
+
+void btif_storage_add_hearing_aid(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,
+                                  uint16_t render_delay,
+                                  uint16_t preparation_delay);
+
+constexpr uint8_t CODEC_G722_16KHZ = 0x01;
+constexpr uint8_t CODEC_G722_24KHZ = 0x02;
+
+// Masks for checking capability support
+constexpr uint8_t CAPABILITY_SIDE = 0x01;
+constexpr uint8_t CAPABILITY_BINAURAL = 0x02;
+constexpr uint8_t CAPABILITY_RESERVED = 0xFC;
+
+// audio control point opcodes
+constexpr uint8_t CONTROL_POINT_OP_START = 0x01;
+constexpr uint8_t CONTROL_POINT_OP_STOP = 0x02;
+
+// used to mark current_volume as not yet known, or possibly old
+constexpr int8_t VOLUME_UNKNOWN = 127;
+constexpr int8_t VOLUME_MIN = -127;
+
+namespace {
+
+// clang-format off
+Uuid HEARING_AID_UUID          = Uuid::FromString("FDF0");
+Uuid READ_ONLY_PROPERTIES_UUID = Uuid::FromString("6333651e-c481-4a3e-9169-7c902aad37bb");
+Uuid AUDIO_CONTROL_POINT_UUID  = Uuid::FromString("f0d4de7e-4a88-476c-9d9f-1937b0996cc0");
+Uuid AUDIO_STATUS_UUID         = Uuid::FromString("38663f1a-e711-4cac-b641-326b56404837");
+Uuid VOLUME_UUID               = Uuid::FromString("00e4ca9e-ab14-41e4-8823-f9e70c7e91df");
+Uuid LE_PSM_UUID               = Uuid::FromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
+// clang-format on
+
+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*,
+                         tBTM_STATUS);
+
+inline BT_HDR* malloc_l2cap_buf(uint16_t len) {
+  BT_HDR* msg = (BT_HDR*)osi_malloc(BT_HDR_SIZE + L2CAP_MIN_OFFSET +
+                                    len /* LE-only, no need for FCS here */);
+  msg->offset = L2CAP_MIN_OFFSET;
+  msg->len = len;
+  return msg;
+}
+
+inline uint8_t* get_l2cap_sdu_start_ptr(BT_HDR* msg) {
+  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;
+
+struct HearingDevice {
+  RawAddress address;
+  /* This is true only during first connection to profile, until we store the
+   * device */
+  bool first_connection;
+
+  /* we are making active attempt to connect to this device, 'direct connect'.
+   * This is true only during initial phase of first connection. */
+  bool connecting_actively;
+
+  /* For two hearing aids, you must update their parameters one after another,
+   * not simulteanously, to ensure start of connection events for both devices
+   * are far from each other. This flag means that this device is waiting for
+   * update of parameters, that should happen after "LE Connection Update
+   * Complete" event
+   */
+  bool connection_update_pending;
+
+  /* if true, we are connected, L2CAP socket is open, we can stream audio*/
+  bool accepting_audio;
+
+  uint16_t conn_id;
+  uint16_t gap_handle;
+  uint16_t audio_control_point_handle;
+  uint16_t volume_handle;
+  uint16_t psm;
+
+  uint8_t capabilities;
+  uint64_t hi_sync_id;
+  uint16_t render_delay;
+  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,
+                uint16_t render_delay, uint16_t preparation_delay)
+      : address(address),
+        first_connection(false),
+        connecting_actively(false),
+        connection_update_pending(false),
+        accepting_audio(false),
+        conn_id(0),
+        gap_handle(0),
+        audio_control_point_handle(audio_control_point_handle),
+        volume_handle(volume_handle),
+        psm(psm),
+        capabilities(capabilities),
+        hi_sync_id(hiSyncId),
+        render_delay(render_delay),
+        preparation_delay(preparation_delay),
+        codecs(codecs) {}
+
+  HearingDevice(const RawAddress& address, bool first_connection)
+      : address(address),
+        first_connection(first_connection),
+        connecting_actively(first_connection),
+        connection_update_pending(false),
+        accepting_audio(false),
+        conn_id(0),
+        gap_handle(0),
+        psm(0) {}
+
+  HearingDevice() { HearingDevice(RawAddress::kEmpty, false); }
+
+  /* return true if this device represents left Hearing Aid. Returned value is
+   * valid only after capabilities are discovered */
+  bool isLeft() const { return !(capabilities & CAPABILITY_SIDE); }
+};
+
+class HearingDevices {
+ public:
+  void Add(HearingDevice device) {
+    if (FindByAddress(device.address) != nullptr) return;
+
+    devices.push_back(device);
+  }
+
+  void Remove(const RawAddress& address) {
+    for (auto it = devices.begin(); it != devices.end();) {
+      if (it->address != address) {
+        ++it;
+        continue;
+      }
+
+      it = devices.erase(it);
+      return;
+    }
+  }
+
+  HearingDevice* FindByAddress(const RawAddress& address) {
+    auto iter = std::find_if(devices.begin(), devices.end(),
+                             [&address](const HearingDevice& device) {
+                               return device.address == address;
+                             });
+
+    return (iter == devices.end()) ? nullptr : &(*iter);
+  }
+
+  HearingDevice* FindByConnId(uint16_t conn_id) {
+    auto iter = std::find_if(devices.begin(), devices.end(),
+                             [&conn_id](const HearingDevice& device) {
+                               return device.conn_id == conn_id;
+                             });
+
+    return (iter == devices.end()) ? nullptr : &(*iter);
+  }
+
+  HearingDevice* FindByGapHandle(uint16_t gap_handle) {
+    auto iter = std::find_if(devices.begin(), devices.end(),
+                             [&gap_handle](const HearingDevice& device) {
+                               return device.gap_handle == gap_handle;
+                             });
+
+    return (iter == devices.end()) ? nullptr : &(*iter);
+  }
+
+  bool IsAnyConnectionUpdatePending() {
+    for (const auto& d : devices) {
+      if (d.connection_update_pending) return true;
+    }
+
+    return false;
+  }
+
+  size_t size() { return (devices.size()); }
+
+  std::vector<HearingDevice> devices;
+};
+
+g722_encode_state_t* encoder_state_left = nullptr;
+g722_encode_state_t* encoder_state_right = nullptr;
+
+class HearingAidImpl : public HearingAid {
+ public:
+  virtual ~HearingAidImpl() = default;
+
+  HearingAidImpl(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
+                 Closure initCb)
+      : gatt_if(0),
+        seq_counter(0),
+        current_volume(VOLUME_UNKNOWN),
+        callbacks(callbacks) {
+    DVLOG(2) << __func__;
+    BTA_GATTC_AppRegister(
+        hearingaid_gattc_callback,
+        base::Bind(
+            [](Closure initCb, uint8_t client_id, uint8_t status) {
+              if (status != GATT_SUCCESS) {
+                LOG(ERROR) << "Can't start Hearing Aid profile - no gatt "
+                              "clients left!";
+                return;
+              }
+              instance->gatt_if = client_id;
+              initCb.Run();
+            },
+            initCb));
+  }
+
+  void Connect(const RawAddress& address) override {
+    DVLOG(2) << __func__ << " " << address;
+    hearingDevices.Add(HearingDevice(address, true));
+    BTA_GATTC_Open(gatt_if, address, true, GATT_TRANSPORT_LE, false);
+  }
+
+  void AddFromStorage(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,
+                      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);
+
+      /* 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);
+  }
+
+  int GetDeviceCount() { return (hearingDevices.size()); }
+
+  void OnGattConnected(tGATT_STATUS status, uint16_t conn_id,
+                       tGATT_IF client_if, RawAddress address,
+                       tBTA_TRANSPORT transport, uint16_t mtu) {
+    VLOG(2) << __func__ << " " << address;
+
+    HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown device, address=" << address;
+      return;
+    }
+
+    if (status != GATT_SUCCESS) {
+      if (!hearingDevice->connecting_actively) {
+        // whitelist connection failed, that's ok.
+        return;
+      }
+
+      LOG(INFO) << "Failed to connect to Hearing Aid device";
+      hearingDevices.Remove(address);
+      callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+      return;
+    }
+
+    hearingDevice->connecting_actively = false;
+    hearingDevice->conn_id = conn_id;
+
+    /* We must update connection parameters one at a time, otherwise anchor
+     * point (start of connection event) for two devices can be too close to
+     * each other. Here, by setting min_ce_len=max_ce_len=X, we force controller
+     * to move anchor point of both connections away from each other, to make
+     * sure we'll be able to fit all the data we want in one connection event.
+     */
+    bool any_update_pending = hearingDevices.IsAnyConnectionUpdatePending();
+    // mark the device as pending connection update. If we don't start the
+    // update now, it'll be started once current device finishes.
+    hearingDevice->connection_update_pending = true;
+    if (!any_update_pending) {
+      L2CA_UpdateBleConnParams(address, 0x0008, 0x0008, 0x000A, 0x0064 /*1s*/,
+                               MIN_CE_LEN_1M, MIN_CE_LEN_1M);
+    }
+
+    // Set data length
+    // TODO(jpawlowski: for 16khz only 87 is required, optimize
+    BTM_SetBleDataLength(address, 147);
+
+    tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address);
+    if (p_dev_rec) {
+      if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+          p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+        /* if security collision happened, wait for encryption done
+         * (BTA_GATTC_ENC_CMPL_CB_EVT) */
+        return;
+      }
+    }
+
+    /* verify bond */
+    uint8_t sec_flag = 0;
+    BTM_GetSecurityFlagsByTransport(address, &sec_flag, BT_TRANSPORT_LE);
+
+    if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
+      /* if link has been encrypted */
+      OnEncryptionComplete(address, true);
+      return;
+    }
+
+    if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) {
+      /* if bonded and link not encrypted */
+      sec_flag = BTM_BLE_SEC_ENCRYPT;
+      BTM_SetEncryption(address, BTA_TRANSPORT_LE, encryption_callback, nullptr,
+                        sec_flag);
+      return;
+    }
+
+    /* otherwise let it go through */
+    OnEncryptionComplete(address, true);
+  }
+
+  void OnConnectionUpdateComplete(uint16_t conn_id) {
+    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      return;
+    }
+
+    hearingDevice->connection_update_pending = false;
+
+    for (auto& device : hearingDevices.devices) {
+      if (device.conn_id && device.connection_update_pending) {
+        L2CA_UpdateBleConnParams(device.address, 0x0008, 0x0008, 0x000A,
+                                 0x0064 /*1s*/, MIN_CE_LEN_1M, MIN_CE_LEN_1M);
+        return;
+      }
+    }
+  }
+
+  void OnEncryptionComplete(const RawAddress& address, bool success) {
+    HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown device" << address;
+      return;
+    }
+
+    if (!success) {
+      LOG(ERROR) << "encryption failed";
+      BTA_GATTC_Close(hearingDevice->conn_id);
+      if (hearingDevice->first_connection) {
+        callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+      }
+      return;
+    }
+
+    DVLOG(2) << __func__ << " " << address;
+
+    if (!hearingDevice->first_connection) {
+      // Use cached data, jump to connecting socket
+      ConnectSocket(hearingDevice);
+      return;
+    }
+
+    BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
+  }
+
+  void OnServiceSearchComplete(uint16_t conn_id, tGATT_STATUS status) {
+    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      return;
+    }
+
+    // Known device, nothing to do.
+    if (!hearingDevice->first_connection) return;
+
+    if (status != GATT_SUCCESS) {
+      /* close connection and report service discovery complete with error */
+      LOG(ERROR) << "Service discovery failed";
+      if (hearingDevice->first_connection) {
+        callbacks->OnConnectionState(ConnectionState::DISCONNECTED,
+                                     hearingDevice->address);
+      }
+      return;
+    }
+
+    const std::vector<tBTA_GATTC_SERVICE>* services =
+        BTA_GATTC_GetServices(conn_id);
+
+    const tBTA_GATTC_SERVICE* service = nullptr;
+    for (const tBTA_GATTC_SERVICE& tmp : *services) {
+      if (tmp.uuid != HEARING_AID_UUID) continue;
+      LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
+      service = &tmp;
+      break;
+    }
+
+    if (!service) {
+      LOG(ERROR) << "No Hearing Aid service found";
+      callbacks->OnConnectionState(ConnectionState::DISCONNECTED,
+                                   hearingDevice->address);
+      return;
+    }
+
+    uint16_t psm_handle = 0x0000;
+    for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+      if (charac.uuid == READ_ONLY_PROPERTIES_UUID) {
+        DVLOG(2) << "Reading read only properties "
+                 << loghex(charac.value_handle);
+        BtaGattQueue::ReadCharacteristic(
+            conn_id, charac.value_handle,
+            HearingAidImpl::OnReadOnlyPropertiesReadStatic, nullptr);
+      } else if (charac.uuid == AUDIO_CONTROL_POINT_UUID) {
+        hearingDevice->audio_control_point_handle = charac.value_handle;
+        // store audio control point!
+      } else if (charac.uuid == AUDIO_STATUS_UUID) {
+        DVLOG(2) << "Reading Audio status " << loghex(charac.value_handle);
+        BtaGattQueue::ReadCharacteristic(conn_id, charac.value_handle,
+                                         HearingAidImpl::OnAudioStatusStatic,
+                                         nullptr);
+      } else if (charac.uuid == VOLUME_UUID) {
+        hearingDevice->volume_handle = charac.value_handle;
+      } else if (charac.uuid == LE_PSM_UUID) {
+        psm_handle = charac.value_handle;
+      } else {
+        LOG(WARNING) << "Unknown characteristic found:" << charac.uuid;
+      }
+    }
+
+    if (psm_handle) {
+      DVLOG(2) << "Reading PSM " << loghex(psm_handle);
+      BtaGattQueue::ReadCharacteristic(
+          conn_id, psm_handle, HearingAidImpl::OnPsmReadStatic, nullptr);
+    }
+  }
+
+  void OnReadOnlyPropertiesRead(uint16_t conn_id, tGATT_STATUS status,
+                                uint16_t handle, uint16_t len, uint8_t* value,
+                                void* data) {
+    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+    if (!hearingDevice) {
+      DVLOG(2) << __func__ << "unknown conn_id=" << loghex(conn_id);
+      return;
+    }
+
+    VLOG(2) << __func__ << " " << base::HexEncode(value, len);
+
+    uint8_t* p = value;
+
+    uint8_t version;
+    STREAM_TO_UINT8(version, p);
+
+    if (version != 0x01) {
+      LOG(WARNING) << "Unknown version: " << loghex(version);
+      return;
+    }
+
+    // version 0x01 of read only properties:
+    if (len < 17) {
+      LOG(WARNING) << "Read only properties too short: " << loghex(len);
+      return;
+    }
+    uint8_t capabilities;
+    STREAM_TO_UINT8(capabilities, p);
+    hearingDevice->capabilities = capabilities;
+    bool side = capabilities & CAPABILITY_SIDE;
+    bool standalone = capabilities & CAPABILITY_BINAURAL;
+    VLOG(2) << __func__ << " capabilities: " << (side ? "right" : "left")
+            << ", " << (standalone ? "binaural" : "monaural");
+
+    if (capabilities & CAPABILITY_RESERVED) {
+      LOG(WARNING) << __func__ << " reserved capabilities are set";
+    }
+
+    STREAM_TO_UINT64(hearingDevice->hi_sync_id, p);
+    VLOG(2) << __func__ << " hiSyncId: " << loghex(hearingDevice->hi_sync_id);
+    uint8_t feature_map;
+    STREAM_TO_UINT8(feature_map, p);
+
+    STREAM_TO_UINT16(hearingDevice->render_delay, p);
+    VLOG(2) << __func__
+            << " render delay: " << loghex(hearingDevice->render_delay);
+
+    STREAM_TO_UINT16(hearingDevice->preparation_delay, p);
+    VLOG(2) << __func__ << " preparation delay: "
+            << loghex(hearingDevice->preparation_delay);
+
+    uint16_t codecs;
+    STREAM_TO_UINT16(codecs, p);
+    hearingDevice->codecs = codecs;
+    VLOG(2) << __func__ << " supported codecs: " << loghex(codecs);
+    if (codecs & (1 << CODEC_G722_16KHZ)) VLOG(2) << "\tG722@16kHz";
+    if (codecs & (1 << CODEC_G722_24KHZ)) VLOG(2) << "\tG722@24kHz";
+
+    if (!(codecs & (1 << CODEC_G722_16KHZ))) {
+      LOG(WARNING) << __func__ << " Mandatory codec, G722@16kHz not supported";
+    }
+  }
+
+  void OnAudioStatus(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+                     uint16_t len, uint8_t* value, void* data) {
+    DVLOG(2) << __func__ << " " << base::HexEncode(value, len);
+  }
+
+  void OnPsmRead(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+                 uint16_t len, uint8_t* value, void* data) {
+    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown read event, conn_id=" << loghex(conn_id);
+      return;
+    }
+
+    if (status != GATT_SUCCESS) {
+      LOG(ERROR) << "Error reading PSM for device" << hearingDevice->address;
+      return;
+    }
+
+    if (len > 2) {
+      LOG(ERROR) << "Bad PSM length";
+      return;
+    }
+
+    uint16_t psm_val = *((uint16_t*)value);
+    hearingDevice->psm = psm_val;
+    VLOG(2) << "read psm:" << loghex(hearingDevice->psm);
+
+    ConnectSocket(hearingDevice);
+  }
+
+  void ConnectSocket(HearingDevice* hearingDevice) {
+    tL2CAP_CFG_INFO cfg_info = tL2CAP_CFG_INFO{.mtu = 512};
+
+    uint16_t gap_handle = GAP_ConnOpen(
+        "", 0, false, &hearingDevice->address, hearingDevice->psm,
+        514 /* MPS */, &cfg_info, nullptr,
+        BTM_SEC_NONE /* TODO: request security ? */, L2CAP_FCR_LE_COC_MODE,
+        HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
+    if (gap_handle == GAP_INVALID_HANDLE) {
+      LOG(ERROR) << "UNABLE TO GET gap_handle";
+      return;
+    }
+
+    hearingDevice->gap_handle = gap_handle;
+    LOG(INFO) << "Successfully sent GAP connect request";
+  }
+
+  static void OnReadOnlyPropertiesReadStatic(uint16_t conn_id,
+                                             tGATT_STATUS status,
+                                             uint16_t handle, uint16_t len,
+                                             uint8_t* value, void* data) {
+    if (instance)
+      instance->OnReadOnlyPropertiesRead(conn_id, status, handle, len, value,
+                                         data);
+  }
+  static void OnAudioStatusStatic(uint16_t conn_id, tGATT_STATUS status,
+                                  uint16_t handle, uint16_t len, uint8_t* value,
+                                  void* data) {
+    if (instance)
+      instance->OnAudioStatus(conn_id, status, handle, len, value, data);
+  }
+
+  static void OnPsmReadStatic(uint16_t conn_id, tGATT_STATUS status,
+                              uint16_t handle, uint16_t len, uint8_t* value,
+                              void* data) {
+    if (instance)
+      instance->OnPsmRead(conn_id, status, handle, len, value, data);
+  }
+
+  /* CoC Socket is ready */
+  void OnGapConnection(const RawAddress& address) {
+    HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+    if (!hearingDevice) {
+      LOG(INFO) << "Device not connected to profile" << address;
+      return;
+    }
+
+    if (hearingDevice->first_connection) {
+      /* add device into BG connection to accept remote initiated connection */
+      BTA_GATTC_Open(gatt_if, address, false, GATT_TRANSPORT_LE, false);
+      BTA_DmBleStartAutoConn();
+
+      btif_storage_add_hearing_aid(
+          address, hearingDevice->psm, hearingDevice->capabilities,
+          hearingDevice->codecs, hearingDevice->audio_control_point_handle,
+          hearingDevice->volume_handle, hearingDevice->hi_sync_id,
+          hearingDevice->render_delay, hearingDevice->preparation_delay);
+
+      hearingDevice->first_connection = false;
+    }
+
+    SendStart(*hearingDevice);
+
+    hearingDevice->accepting_audio = true;
+    LOG(INFO) << __func__ << ": address=" << address
+              << ", hi_sync_id=" << loghex(hearingDevice->hi_sync_id);
+    callbacks->OnDeviceAvailable(hearingDevice->capabilities,
+                                 hearingDevice->hi_sync_id, address);
+    callbacks->OnConnectionState(ConnectionState::CONNECTED, address);
+
+    StartSendingAudio(*hearingDevice);
+  }
+
+  void StartSendingAudio(const HearingDevice& hearingDevice) {
+    VLOG(0) << __func__ << hearingDevice.address;
+
+    if (encoder_state_left == nullptr) {
+      encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
+      encoder_state_right = g722_encode_init(nullptr, 64000, G722_PACKED);
+      seq_counter = 0;
+
+      // use the best codec avaliable for this pair of devices.
+      uint16_t codecs = hearingDevice.codecs;
+      if (hearingDevice.hi_sync_id != 0) {
+        for (const auto& device : hearingDevices.devices) {
+          if (device.hi_sync_id != hearingDevice.hi_sync_id) continue;
+
+          codecs &= device.codecs;
+        }
+      }
+
+      if ((codecs & (1 << CODEC_G722_24KHZ)) &&
+          controller_get_interface()->supports_ble_2m_phy()) {
+        codec_in_use = CODEC_G722_24KHZ;
+        codec.sample_rate = 24000;
+        codec.bit_rate = 16;
+        codec.data_interval_ms = 10;
+      } else if (codecs & (1 << CODEC_G722_16KHZ)) {
+        codec_in_use = CODEC_G722_16KHZ;
+        codec.sample_rate = 16000;
+        codec.bit_rate = 16;
+        codec.data_interval_ms = 10;
+      }
+
+      // TODO: remove once we implement support for other codecs
+      codec_in_use = CODEC_G722_16KHZ;
+      HearingAidAudioSource::Start(codec, audioReceiver);
+    }
+  }
+
+  void OnAudioSuspend() {
+    DVLOG(2) << __func__;
+
+    std::vector<uint8_t> stop({CONTROL_POINT_OP_STOP});
+    for (const auto& device : hearingDevices.devices) {
+      if (!device.accepting_audio) continue;
+
+      BtaGattQueue::WriteCharacteristic(device.conn_id,
+                                        device.audio_control_point_handle, stop,
+                                        GATT_WRITE, nullptr, nullptr);
+    }
+  }
+
+  void OnAudioResume() {
+    DVLOG(2) << __func__;
+
+    // TODO: shall we also reset the encoder ?
+    if (encoder_state_left != nullptr) {
+      g722_encode_release(encoder_state_left);
+      g722_encode_release(encoder_state_right);
+      encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
+      encoder_state_right = g722_encode_init(nullptr, 64000, G722_PACKED);
+    }
+    seq_counter = 0;
+
+    for (const auto& device : hearingDevices.devices) {
+      if (!device.accepting_audio) continue;
+      SendStart(device);
+    }
+  }
+
+  void SendStart(const HearingDevice& device) {
+    std::vector<uint8_t> start({CONTROL_POINT_OP_START, codec_in_use,
+                                0x02 /* media */, (uint8_t)current_volume});
+
+    if (current_volume == VOLUME_UNKNOWN) start[3] = (uint8_t)VOLUME_MIN;
+
+    BtaGattQueue::WriteCharacteristic(device.conn_id,
+                                      device.audio_control_point_handle, start,
+                                      GATT_WRITE, nullptr, nullptr);
+
+    // TODO(jpawlowski): this will be removed, once test devices get volume
+    // from start reqest
+    if (current_volume != VOLUME_UNKNOWN) {
+      std::vector<uint8_t> volume_value(
+          {static_cast<unsigned char>(current_volume)});
+      BtaGattQueue::WriteCharacteristic(device.conn_id, device.volume_handle,
+                                        volume_value, GATT_WRITE_NO_RSP,
+                                        nullptr, nullptr);
+    }
+  }
+
+  void OnAudioDataReady(const std::vector<uint8_t>& data) {
+    /* For now we assume data comes in as 16bit per sample 16kHz PCM stereo */
+    DVLOG(2) << __func__;
+
+    int num_samples =
+        data.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/);
+
+    // The G.722 codec accept only even number of samples for encoding
+    if (num_samples % 2 != 0)
+      LOG(FATAL) << "num_samples is not even: " << num_samples;
+
+    std::vector<uint16_t> chan_left;
+    std::vector<uint16_t> chan_right;
+    // TODO: encode data into G.722 left/right or mono.
+    for (int i = 0; i < num_samples; i++) {
+      const uint8_t* sample = data.data() + i * 4;
+
+      uint16_t left = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
+      chan_left.push_back(left);
+
+      sample += 2;
+      uint16_t right = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
+      chan_right.push_back(right);
+    }
+
+    // TODO: we should cache left/right and current state, instad of recomputing
+    // it for each packet, 100 times a second.
+    HearingDevice* left = nullptr;
+    HearingDevice* right = nullptr;
+    for (auto& device : hearingDevices.devices) {
+      if (!device.accepting_audio) continue;
+
+      if (device.isLeft())
+        left = &device;
+      else
+        right = &device;
+    }
+
+    if (left == nullptr && right == nullptr) {
+      HearingAidAudioSource::Stop();
+      current_volume = VOLUME_UNKNOWN;
+      return;
+    }
+
+    // TODO: monural, binarual check
+
+    // divide encoded data into packets, add header, send.
+
+    // TODO: make those buffers static and global to prevent constant
+    // reallocations
+    // TODO: this should basically fit the encoded data, tune the size later
+    std::vector<uint8_t> encoded_data_left;
+    if (left) {
+      encoded_data_left.resize(2000);
+      int encoded_size =
+          g722_encode(encoder_state_left, encoded_data_left.data(),
+                      (const int16_t*)chan_left.data(), chan_left.size());
+      encoded_data_left.resize(encoded_size);
+
+      uint16_t cid = GAP_ConnGetL2CAPCid(left->gap_handle);
+      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);
+    }
+
+    std::vector<uint8_t> encoded_data_right;
+    if (right) {
+      encoded_data_right.resize(2000);
+      int encoded_size =
+          g722_encode(encoder_state_right, encoded_data_right.data(),
+                      (const int16_t*)chan_right.data(), chan_right.size());
+      encoded_data_right.resize(encoded_size);
+
+      uint16_t cid = GAP_ConnGetL2CAPCid(right->gap_handle);
+      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);
+    }
+
+    size_t encoded_data_size =
+        std::max(encoded_data_left.size(), encoded_data_right.size());
+
+    // TODO: make it also dependent on the interval, when we support intervals
+    // different than 10ms
+    uint16_t packet_size;
+
+    if (codec_in_use == CODEC_G722_24KHZ) {
+      packet_size = 120;
+    } else /* if (codec_in_use == CODEC_G722_16KHZ) */ {
+      packet_size = 80;
+    }
+
+    for (size_t i = 0; i < encoded_data_size; i += packet_size) {
+      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,
+                 HearingDevice* hearingAid) {
+    BT_HDR* audio_packet = malloc_l2cap_buf(packet_size + 1);
+    uint8_t* p = get_l2cap_sdu_start_ptr(audio_packet);
+    *p = seq_counter;
+    p++;
+    memcpy(p, encoded_data, packet_size);
+
+    DVLOG(2) << hearingAid->address << " : " << base::HexEncode(p, packet_size);
+
+    uint16_t result = GAP_ConnWriteData(hearingAid->gap_handle, audio_packet);
+
+    if (result != BT_PASS) {
+      LOG(ERROR) << " Error sending data: " << loghex(result);
+    }
+  }
+
+  void GapCallback(uint16_t gap_handle, uint16_t event, tGAP_CB_DATA* data) {
+    HearingDevice* hearingDevice = hearingDevices.FindByGapHandle(gap_handle);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown device, gap_handle=" << gap_handle;
+      return;
+    }
+
+    switch (event) {
+      case GAP_EVT_CONN_OPENED: {
+        RawAddress address = *GAP_ConnGetRemoteAddr(gap_handle);
+        uint16_t tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+
+        LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu;
+        OnGapConnection(address);
+        break;
+      }
+
+      // TODO: handle properly!
+      case GAP_EVT_CONN_CLOSED:
+        DVLOG(2) << "GAP_EVT_CONN_CLOSED";
+        hearingDevice->accepting_audio = false;
+        hearingDevice->gap_handle = 0;
+        break;
+      case GAP_EVT_CONN_DATA_AVAIL: {
+        DVLOG(2) << "GAP_EVT_CONN_DATA_AVAIL";
+
+        // only data we receive back from hearing aids are some stats, not
+        // really important, but useful now for debugging.
+        uint32_t bytes_to_read = 0;
+        GAP_GetRxQueueCnt(gap_handle, &bytes_to_read);
+        std::vector<uint8_t> buffer(bytes_to_read);
+
+        uint16_t bytes_read = 0;
+        // TODO:GAP_ConnReadData should accpet uint32_t for length!
+        GAP_ConnReadData(gap_handle, buffer.data(), buffer.size(), &bytes_read);
+
+        if (bytes_read < 4) {
+          LOG(WARNING) << " Wrong data length";
+          return;
+        }
+
+        uint8_t* p = buffer.data();
+
+        DVLOG(1) << "stats from the hearing aid:";
+        for (size_t i = 0; i + 4 <= buffer.size(); i += 4) {
+          uint16_t event_counter, frame_index;
+          STREAM_TO_UINT16(event_counter, p);
+          STREAM_TO_UINT16(frame_index, p);
+          DVLOG(1) << "event_counter=" << event_counter
+                   << " frame_index: " << frame_index;
+        }
+        break;
+      }
+
+      case GAP_EVT_TX_EMPTY:
+        DVLOG(2) << "GAP_EVT_TX_EMPTY";
+        break;
+      case GAP_EVT_CONN_CONGESTED:
+        DVLOG(2) << "GAP_EVT_CONN_CONGESTED";
+
+        // TODO: make it into function
+        HearingAidAudioSource::Stop();
+        // TODO: kill the encoder only if all hearing aids are down.
+        // g722_encode_release(encoder_state);
+        // encoder_state_left = nulllptr;
+        // encoder_state_right = nulllptr;
+        break;
+      case GAP_EVT_CONN_UNCONGESTED:
+        DVLOG(2) << "GAP_EVT_CONN_UNCONGESTED";
+        break;
+
+      case GAP_EVT_LE_COC_CREDITS: {
+        auto& tmp = data->coc_credits;
+        DVLOG(2) << "GAP_EVT_LE_COC_CREDITS, for device: "
+                 << hearingDevice->address << " added" << tmp.credits_received
+                 << " credit_count: " << tmp.credit_count;
+        break;
+      }
+    }
+  }
+
+  static void GapCallbackStatic(uint16_t gap_handle, uint16_t event,
+                                tGAP_CB_DATA* data) {
+    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);
+    if (!hearingDevice) {
+      LOG(INFO) << "Device not connected to profile" << address;
+      return;
+    }
+
+    VLOG(2) << __func__ << ": " << address;
+
+    bool connected = hearingDevice->accepting_audio;
+    hearingDevice->accepting_audio = false;
+
+    if (hearingDevice->connecting_actively) {
+      // cancel pending direct connect
+      BTA_GATTC_CancelOpen(gatt_if, address, true);
+    }
+
+    if (hearingDevice->conn_id) {
+      BTA_GATTC_Close(hearingDevice->conn_id);
+    }
+
+    if (hearingDevice->gap_handle) {
+      GAP_ConnClose(hearingDevice->gap_handle);
+      hearingDevice->gap_handle = 0;
+    }
+
+    // cancel autoconnect
+    BTA_GATTC_CancelOpen(gatt_if, address, false);
+
+    hearingDevices.Remove(address);
+
+    if (connected)
+      callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+  }
+
+  void OnGattDisconnected(tGATT_STATUS status, uint16_t conn_id,
+                          tGATT_IF client_if, RawAddress remote_bda,
+                          tBTA_GATT_REASON reason) {
+    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+    if (!hearingDevice) {
+      VLOG(2) << "Skipping unknown device disconnect, conn_id=" << conn_id;
+      return;
+    }
+
+    hearingDevice->accepting_audio = false;
+    hearingDevice->conn_id = 0;
+
+    BtaGattQueue::Clean(conn_id);
+
+    callbacks->OnConnectionState(ConnectionState::DISCONNECTED, remote_bda);
+  }
+
+  void SetVolume(int8_t volume) override {
+    VLOG(2) << __func__ << ": " << +volume;
+    current_volume = volume;
+    for (HearingDevice& device : hearingDevices.devices) {
+      if (!device.accepting_audio) continue;
+
+      std::vector<uint8_t> volume_value({static_cast<unsigned char>(volume)});
+      BtaGattQueue::WriteCharacteristic(device.conn_id, device.volume_handle,
+                                        volume_value, GATT_WRITE_NO_RSP,
+                                        nullptr, nullptr);
+    }
+  }
+
+  void CleanUp() {
+    BTA_GATTC_AppDeregister(gatt_if);
+    for (HearingDevice& device : hearingDevices.devices) {
+      if (!device.gap_handle) continue;
+
+      GAP_ConnClose(device.gap_handle);
+      device.gap_handle = 0;
+    }
+
+    hearingDevices.devices.clear();
+    HearingAidAudioSource::Stop();
+  }
+
+ private:
+  uint8_t gatt_if;
+  uint8_t seq_counter;
+  /* current volume gain for the hearing aids*/
+  int8_t current_volume;
+  bluetooth::hearing_aid::HearingAidCallbacks* callbacks;
+
+  /* currently used codec */
+  uint8_t codec_in_use;
+  CodecConfiguration codec;
+
+  HearingDevices hearingDevices;
+};
+
+void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+  VLOG(2) << __func__ << " event = " << +event;
+
+  if (p_data == nullptr) return;
+
+  switch (event) {
+    case BTA_GATTC_DEREG_EVT:
+      break;
+
+    case BTA_GATTC_OPEN_EVT: {
+      if (!instance) return;
+      tBTA_GATTC_OPEN& o = p_data->open;
+      instance->OnGattConnected(o.status, o.conn_id, o.client_if, o.remote_bda,
+                                o.transport, o.mtu);
+      break;
+    }
+
+    case BTA_GATTC_CLOSE_EVT: {
+      if (!instance) return;
+      tBTA_GATTC_CLOSE& c = p_data->close;
+      instance->OnGattDisconnected(c.status, c.conn_id, c.client_if,
+                                   c.remote_bda, c.reason);
+    } break;
+
+    case BTA_GATTC_SEARCH_CMPL_EVT:
+      if (!instance) return;
+      instance->OnServiceSearchComplete(p_data->search_cmpl.conn_id,
+                                        p_data->search_cmpl.status);
+      break;
+
+    case BTA_GATTC_NOTIF_EVT:
+      break;
+
+    case BTA_GATTC_ENC_CMPL_CB_EVT:
+      if (!instance) return;
+      instance->OnEncryptionComplete(p_data->enc_cmpl.remote_bda, true);
+      break;
+
+    case BTA_GATTC_CONN_UPDATE_EVT:
+      if (!instance) return;
+      instance->OnConnectionUpdateComplete(p_data->conn_update.conn_id);
+      break;
+
+    default:
+      break;
+  }
+}
+
+void encryption_callback(const RawAddress* address, tGATT_TRANSPORT, void*,
+                         tBTM_STATUS status) {
+  if (instance) {
+    instance->OnEncryptionComplete(*address,
+                                   status == BTM_SUCCESS ? true : false);
+  }
+}
+
+class HearingAidAudioReceiverImpl : public HearingAidAudioReceiver {
+ public:
+  void OnAudioDataReady(const std::vector<uint8_t>& data) override {
+    if (instance) instance->OnAudioDataReady(data);
+  }
+  void OnAudioSuspend() override {
+    if (instance) instance->OnAudioSuspend();
+  }
+
+  void OnAudioResume() override {
+    if (instance) instance->OnAudioResume();
+  }
+};
+
+HearingAidAudioReceiverImpl audioReceiverImpl;
+
+}  // namespace
+
+void HearingAid::Initialize(
+    bluetooth::hearing_aid::HearingAidCallbacks* callbacks, Closure initCb) {
+  if (instance) {
+    LOG(ERROR) << "Already initialized!";
+  }
+
+  audioReceiver = &audioReceiverImpl;
+  instance = new HearingAidImpl(callbacks, initCb);
+  HearingAidAudioSource::Initialize();
+}
+
+bool HearingAid::IsInitialized() { return instance; }
+
+HearingAid* HearingAid::Get() {
+  CHECK(instance);
+  return instance;
+};
+
+void HearingAid::AddFromStorage(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,
+                                uint16_t render_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, is_white_listed);
+};
+
+int HearingAid::GetDeviceCount() {
+  if (!instance) {
+    LOG(INFO) << __func__ << ": Not initialized yet";
+    return 0;
+  }
+
+  return (instance->GetDeviceCount());
+}
+
+void HearingAid::CleanUp() {
+  // Must stop audio source to make sure it doesn't call any of callbacks on our
+  // soon to be  null instance
+  HearingAidAudioSource::Stop();
+  HearingAidAudioSource::CleanUp();
+
+  instance->CleanUp();
+  HearingAidImpl* ptr = instance;
+  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
new file mode 100644
index 0000000..947caaf
--- /dev/null
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -0,0 +1,304 @@
+/******************************************************************************
+ *
+ *  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 "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h"
+#include "bta_hearing_aid_api.h"
+#include "osi/include/alarm.h"
+#include "uipc.h"
+
+#include <base/files/file_util.h>
+#include <include/hardware/bt_av.h>
+
+using base::FilePath;
+extern const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event);
+
+namespace {
+int bit_rate = 16;
+int sample_rate = 16000;
+int data_interval_ms = 10 /* msec */;
+int num_channels = 2;
+alarm_t* audio_timer = nullptr;
+
+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*) {
+  uint32_t bytes_per_tick =
+      (num_channels * sample_rate * data_interval_ms * (bit_rate / 8)) / 1000;
+
+  uint16_t event;
+  uint8_t p_buf[bytes_per_tick];
+
+  uint32_t bytes_read = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO,
+                                  &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);
+
+  localAudioReceiver->OnAudioDataReady(data);
+}
+
+void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) {
+  uint8_t ack = status;
+  DVLOG(2) << "Hearing Aid audio ctrl ack: " << status;
+  UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+}
+
+void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
+  DVLOG(2) << "Hearing Aid audio data event: " << event;
+  switch (event) {
+    case UIPC_OPEN_EVT:
+      /*
+       * Read directly from media task from here on (keep callback for
+       * connection events.
+       */
+      UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO,
+                 UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
+      UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
+                 reinterpret_cast<void*>(0));
+
+      audio_timer = alarm_new_periodic("hearing_aid_data_timer");
+      alarm_set_on_mloop(audio_timer, data_interval_ms, send_audio_data,
+                         nullptr);
+      break;
+    case UIPC_CLOSE_EVT:
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      if (audio_timer) {
+        alarm_cancel(audio_timer);
+      }
+      break;
+    default:
+      LOG(ERROR) << "Hearing Aid audio data event not recognized:" << event;
+  }
+}
+
+void hearing_aid_recv_ctrl_data() {
+  tHEARING_AID_CTRL_CMD cmd = HEARING_AID_CTRL_CMD_NONE;
+  int n;
+
+  uint8_t read_cmd = 0; /* The read command size is one octet */
+  n = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, NULL, &read_cmd, 1);
+  cmd = static_cast<tHEARING_AID_CTRL_CMD>(read_cmd);
+
+  /* detach on ctrl channel means audioflinger process was terminated */
+  if (n == 0) {
+    LOG(WARNING) << __func__ << "CTRL CH DETACHED";
+    UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL);
+    return;
+  }
+
+  VLOG(2) << __func__ << " " << audio_ha_hw_dump_ctrl_event(cmd);
+  //  a2dp_cmd_pending = cmd;
+
+  switch (cmd) {
+    case HEARING_AID_CTRL_CMD_CHECK_READY:
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      break;
+
+    case HEARING_AID_CTRL_CMD_START:
+      if (localAudioReceiver) localAudioReceiver->OnAudioResume();
+      // timer is restarted in UIPC_Open
+      UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, hearing_aid_data_cb,
+                HEARING_AID_DATA_PATH);
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      break;
+
+    case HEARING_AID_CTRL_CMD_STOP:
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      break;
+
+    case HEARING_AID_CTRL_CMD_SUSPEND:
+      if (audio_timer) alarm_cancel(audio_timer);
+      if (localAudioReceiver) localAudioReceiver->OnAudioSuspend();
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      break;
+
+    case HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG: {
+      btav_a2dp_codec_config_t codec_config;
+      btav_a2dp_codec_config_t codec_capability;
+      if (sample_rate == 16000) {
+        codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_16000;
+        codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_16000;
+      } else if (sample_rate == 24000) {
+        codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
+        codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
+      } else {
+        LOG(FATAL) << "unsupported sample rate: " << sample_rate;
+      }
+
+      codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+      codec_capability.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+
+      codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+      codec_capability.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      // Send the current codec config
+      UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                reinterpret_cast<const uint8_t*>(&codec_config.sample_rate),
+                sizeof(btav_a2dp_codec_sample_rate_t));
+      UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                reinterpret_cast<const uint8_t*>(&codec_config.bits_per_sample),
+                sizeof(btav_a2dp_codec_bits_per_sample_t));
+      UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                reinterpret_cast<const uint8_t*>(&codec_config.channel_mode),
+                sizeof(btav_a2dp_codec_channel_mode_t));
+      // Send the current codec capability
+      UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                reinterpret_cast<const uint8_t*>(&codec_capability.sample_rate),
+                sizeof(btav_a2dp_codec_sample_rate_t));
+      UIPC_Send(
+          *uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+          reinterpret_cast<const uint8_t*>(&codec_capability.bits_per_sample),
+          sizeof(btav_a2dp_codec_bits_per_sample_t));
+      UIPC_Send(
+          *uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+          reinterpret_cast<const uint8_t*>(&codec_capability.channel_mode),
+          sizeof(btav_a2dp_codec_channel_mode_t));
+      break;
+    }
+
+    case HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: {
+      // TODO: we only support one config for now!
+      btav_a2dp_codec_config_t codec_config;
+      codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+      codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+      codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+      // Send the current codec config
+      if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                    reinterpret_cast<uint8_t*>(&codec_config.sample_rate),
+                    sizeof(btav_a2dp_codec_sample_rate_t)) !=
+          sizeof(btav_a2dp_codec_sample_rate_t)) {
+        LOG(ERROR) << __func__ << "Error reading sample rate from audio HAL";
+        break;
+      }
+      if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                    reinterpret_cast<uint8_t*>(&codec_config.bits_per_sample),
+                    sizeof(btav_a2dp_codec_bits_per_sample_t)) !=
+          sizeof(btav_a2dp_codec_bits_per_sample_t)) {
+        LOG(ERROR) << __func__
+                   << "Error reading bits per sample from audio HAL";
+
+        break;
+      }
+      if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+                    reinterpret_cast<uint8_t*>(&codec_config.channel_mode),
+                    sizeof(btav_a2dp_codec_channel_mode_t)) !=
+          sizeof(btav_a2dp_codec_channel_mode_t)) {
+        LOG(ERROR) << __func__ << "Error reading channel mode from audio HAL";
+
+        break;
+      }
+      LOG(INFO) << __func__ << " HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: "
+                << "sample_rate=" << codec_config.sample_rate
+                << "bits_per_sample=" << codec_config.bits_per_sample
+                << "channel_mode=" << codec_config.channel_mode;
+      break;
+    }
+
+    default:
+      LOG(ERROR) << __func__ << "UNSUPPORTED CMD: " << cmd;
+      hearing_aid_send_ack(HEARING_AID_CTRL_ACK_FAILURE);
+      break;
+  }
+  VLOG(2) << __func__ << " a2dp-ctrl-cmd : " << audio_ha_hw_dump_ctrl_event(cmd)
+          << " DONE";
+}
+
+void hearing_aid_ctrl_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
+  VLOG(2) << "Hearing Aid audio ctrl event: " << event;
+  switch (event) {
+    case UIPC_OPEN_EVT:
+      break;
+    case UIPC_CLOSE_EVT:
+      UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb,
+                HEARING_AID_CTRL_PATH);
+      break;
+    case UIPC_RX_DATA_READY_EVT:
+      hearing_aid_recv_ctrl_data();
+      break;
+    default:
+      LOG(ERROR) << "Hearing Aid audio ctrl unrecognized event: " << event;
+  }
+}
+}  // namespace
+
+void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration,
+                                  HearingAidAudioReceiver* audioReceiver) {
+  localAudioReceiver = audioReceiver;
+  VLOG(2) << "Hearing Aid UIPC Open";
+  stats.Reset();
+}
+
+void HearingAidAudioSource::Stop() {
+  if (audio_timer) {
+    alarm_cancel(audio_timer);
+  }
+}
+
+void HearingAidAudioSource::Initialize() {
+  uipc_hearing_aid = UIPC_Init();
+  UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb,
+            HEARING_AID_CTRL_PATH);
+}
+
+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 b633bd0..3e6c22d 100644
--- a/bta/hf_client/bta_hf_client_act.cc
+++ b/bta/hf_client/bta_hf_client_act.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -108,7 +108,7 @@
     /* Let the incoming connection goes through.                        */
     /* Issue collision for now.                                         */
     /* We will decide what to do when we find incoming connection later.*/
-    bta_hf_client_collision_cback(0, BTA_ID_HS, 0, &client_cb->peer_addr);
+    bta_hf_client_collision_cback(0, BTA_ID_HS, 0, client_cb->peer_addr);
     return;
   }
 
@@ -303,7 +303,7 @@
   evt.conn.bd_addr = client_cb->peer_addr;
 
   /* if not deregistering reopen server */
-  if (bta_hf_client_cb_arr.deregister == false) {
+  if (!bta_hf_client_cb_arr.deregister) {
     /* Make sure SCO is shutdown */
     bta_hf_client_sco_shutdown(client_cb);
 
diff --git a/bta/hf_client/bta_hf_client_api.cc b/bta/hf_client/bta_hf_client_api.cc
index d1ec0b7..38c5594 100644
--- a/bta/hf_client/bta_hf_client_api.cc
+++ b/bta/hf_client/bta_hf_client_api.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hf_client/bta_hf_client_at.cc b/bta/hf_client/bta_hf_client_at.cc
index 5d8493b..5bcc68e 100644
--- a/bta/hf_client/bta_hf_client_at.cc
+++ b/bta/hf_client/bta_hf_client_at.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -170,7 +170,7 @@
                                   uint16_t buf_len) {
   APPL_TRACE_DEBUG("%s", __func__);
   if ((client_cb->at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE ||
-       client_cb->svc_conn == false) &&
+       !client_cb->svc_conn) &&
       !alarm_is_scheduled(client_cb->at_cb.hold_timer)) {
     uint16_t len;
 
@@ -257,7 +257,7 @@
       client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
       return;
     case BTA_HF_CLIENT_AT_CLIP:  // last cmd is post slc seq
-      if (client_cb->send_at_reply == false) {
+      if (!client_cb->send_at_reply) {
         client_cb->send_at_reply = true;
       }
       break;
@@ -296,7 +296,7 @@
       bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
       break;
     case BTA_HF_CLIENT_AT_CLIP:  // last cmd is post slc seq
-      if (client_cb->send_at_reply == false) {
+      if (!client_cb->send_at_reply) {
         client_cb->send_at_reply = true;
       }
       break;
@@ -1587,7 +1587,7 @@
     client_cb->at_cb.offset += space_left;
 
     /* find end of last complete command before proceeding */
-    while (bta_hf_client_check_at_complete(client_cb) == false) {
+    while (!bta_hf_client_check_at_complete(client_cb)) {
       if (client_cb->at_cb.offset == 0) {
         APPL_TRACE_ERROR("HFPClient: AT parser buffer overrun, disconnecting");
 
@@ -1620,7 +1620,7 @@
   client_cb->at_cb.offset += len;
 
   /* If last event is complete, parsing can be started */
-  if (bta_hf_client_check_at_complete(client_cb) == true) {
+  if (bta_hf_client_check_at_complete(client_cb)) {
     bta_hf_client_at_parse_start(client_cb);
     bta_hf_client_at_clear_buf(client_cb);
   }
@@ -1886,7 +1886,7 @@
 
   APPL_TRACE_DEBUG("%s", __func__);
 
-  if (query == true) {
+  if (query) {
     at_len = snprintf(buf, sizeof(buf), "AT+BTRH?\r");
   } else {
     at_len = snprintf(buf, sizeof(buf), "AT+BTRH=%u\r", val);
diff --git a/bta/hf_client/bta_hf_client_at.h b/bta/hf_client/bta_hf_client_at.h
index 7b52336..1328175 100644
--- a/bta/hf_client/bta_hf_client_at.h
+++ b/bta/hf_client/bta_hf_client_at.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hf_client/bta_hf_client_int.h b/bta/hf_client/bta_hf_client_int.h
index 9ff7fa1..15ceec2 100644
--- a/bta/hf_client/bta_hf_client_int.h
+++ b/bta/hf_client/bta_hf_client_int.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -218,7 +218,7 @@
 extern void bta_hf_client_app_callback(uint16_t event, tBTA_HF_CLIENT* data);
 extern void bta_hf_client_collision_cback(tBTA_SYS_CONN_STATUS status,
                                           uint8_t id, uint8_t app_id,
-                                          const RawAddress* peer_addr);
+                                          const RawAddress& peer_addr);
 extern void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb);
 extern tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback,
                                             tBTA_SEC sec_mask,
diff --git a/bta/hf_client/bta_hf_client_main.cc b/bta/hf_client/bta_hf_client_main.cc
index e52994c..4f717ae 100644
--- a/bta/hf_client/bta_hf_client_main.cc
+++ b/bta/hf_client/bta_hf_client_main.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2016 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -363,8 +363,8 @@
  ******************************************************************************/
 void bta_hf_client_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
                                    uint8_t id, UNUSED_ATTR uint8_t app_id,
-                                   const RawAddress* peer_addr) {
-  tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_bda(*peer_addr);
+                                   const RawAddress& peer_addr) {
+  tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_bda(peer_addr);
   if (client_cb != NULL && client_cb->state == BTA_HF_CLIENT_OPENING_ST) {
     if (id == BTA_ID_SYS) /* ACL collision */
     {
@@ -381,7 +381,7 @@
     /* Cancel SDP if it had been started. */
     if (client_cb->p_disc_db) {
       (void)SDP_CancelServiceSearch(client_cb->p_disc_db);
-      bta_hf_client_free_db(NULL);
+      osi_free_and_reset((void**)&client_cb->p_disc_db);
     }
 
     /* reopen registered server */
diff --git a/bta/hf_client/bta_hf_client_rfc.cc b/bta/hf_client/bta_hf_client_rfc.cc
index 3e2aa59..e261c16 100644
--- a/bta/hf_client/bta_hf_client_rfc.cc
+++ b/bta/hf_client/bta_hf_client_rfc.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -284,7 +284,7 @@
     /* Cancel SDP if it had been started. */
     if (client_cb->p_disc_db) {
       (void)SDP_CancelServiceSearch(client_cb->p_disc_db);
-      bta_hf_client_free_db(NULL);
+      osi_free_and_reset((void**)&client_cb->p_disc_db);
     }
   }
 }
diff --git a/bta/hf_client/bta_hf_client_sco.cc b/bta/hf_client/bta_hf_client_sco.cc
index 6181ba1..e03de4f 100644
--- a/bta/hf_client/bta_hf_client_sco.cc
+++ b/bta/hf_client/bta_hf_client_sco.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@
   evt.bd_addr = client_cb->peer_addr;
 
   /* call app cback */
-  bta_hf_client_app_callback(event, (tBTA_HF_CLIENT*)&evt);
+  bta_hf_client_app_callback(event, &evt);
 }
 
 /*******************************************************************************
@@ -233,7 +233,7 @@
     return;
   }
 
-  enh_esco_params_t params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1);
+  enh_esco_params_t params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
 
   /* if initiating set current scb and peer bd addr */
   if (is_orig) {
@@ -602,7 +602,7 @@
   /* call app callback */
   bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
 
-  if (client_cb->sco_close_rfc == true) {
+  if (client_cb->sco_close_rfc) {
     client_cb->sco_close_rfc = false;
     bta_hf_client_rfc_do_close(p_data);
   }
diff --git a/bta/hf_client/bta_hf_client_sdp.cc b/bta/hf_client/bta_hf_client_sdp.cc
index 475ce16..d68adcc 100644
--- a/bta/hf_client/bta_hf_client_sdp.cc
+++ b/bta/hf_client/bta_hf_client_sdp.cc
@@ -1,21 +1,21 @@
 /******************************************************************************
-*
-*  Copyright (c) 2014 The Android Open Source Project
-*  Copyright (C) 2003-2012 Broadcom Corporation
-*
-*  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.
-*
-******************************************************************************/
+ *
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
 
 /******************************************************************************
  *
@@ -25,6 +25,7 @@
  ******************************************************************************/
 
 #include <string.h>
+#include <base/logging.h>
 
 #include "bt_utils.h"
 #include "bta_api.h"
@@ -33,6 +34,8 @@
 #include "bta_sys.h"
 #include "osi/include/osi.h"
 
+using bluetooth::Uuid;
+
 /* Number of protocol elements in protocol element list. */
 #define BTA_HF_CLIENT_NUM_PROTO_ELEMS 2
 
@@ -289,7 +292,7 @@
  *
  ******************************************************************************/
 void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) {
-  tSDP_UUID uuid_list[2];
+  Uuid uuid_list[1];
   uint16_t num_uuid = 1;
   uint16_t attr_list[4];
   uint8_t num_attr;
@@ -302,7 +305,7 @@
     attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
     attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
     num_attr = 4;
-    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+    uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
   }
   /* acceptor; get features */
   else {
@@ -310,15 +313,13 @@
     attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
     attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
     num_attr = 3;
-    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+    uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
   }
 
   /* allocate buffer for sdp database */
   client_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
 
   /* set up service discovery database; attr happens to be attr_list len */
-  uuid_list[0].len = LEN_UUID_16;
-  uuid_list[1].len = LEN_UUID_16;
   db_inited = SDP_InitDiscoveryDb(client_cb->p_disc_db, BT_DEFAULT_BUFFER_SIZE,
                                   num_uuid, uuid_list, num_attr, attr_list);
 
@@ -331,7 +332,7 @@
 
   if (!db_inited) {
     /*free discover db */
-    bta_hf_client_free_db(NULL);
+    osi_free_and_reset((void**)&client_cb->p_disc_db);
     /* sent failed event */
     tBTA_HF_CLIENT_DATA msg;
     msg.hdr.layer_specific = client_cb->handle;
@@ -350,6 +351,7 @@
  *
  ******************************************************************************/
 void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA* p_data) {
+  CHECK(p_data != NULL);
   tBTA_HF_CLIENT_CB* client_cb =
       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
   if (client_cb == NULL) {
diff --git a/bta/hh/bta_hh_act.cc b/bta/hh/bta_hh_act.cc
index 4b11a09..4d85437 100644
--- a/bta/hh/bta_hh_act.cc
+++ b/bta/hh/bta_hh_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -99,8 +99,12 @@
     bta_hh_le_enable();
   } else
 #endif
+  {
     /* signal BTA call back event */
-    (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH*)&status);
+    tBTA_HH bta_hh;
+    bta_hh.status = status;
+    (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, &bta_hh);
+  }
 }
 /*******************************************************************************
  *
@@ -224,7 +228,9 @@
   osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
 
   /* send SDP_CMPL_EVT into state machine */
-  bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+  tBTA_HH_DATA bta_hh_data;
+  bta_hh_data.status = status;
+  bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
 
   return;
 }
@@ -282,7 +288,9 @@
   if (status != BTA_HH_OK) {
     osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
     /* send SDP_CMPL_EVT into state machine */
-    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+    tBTA_HH_DATA bta_hh_data;
+    bta_hh_data.status = status;
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
   }
   return;
 }
@@ -332,7 +340,9 @@
       } else
         status = BTA_HH_ERR_NO_RES;
     }
-    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+    tBTA_HH_DATA bta_hh_data;
+    bta_hh_data.status = status;
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
 
     return;
   }
@@ -366,8 +376,11 @@
     return;
   }
 
-  if (status != BTA_HH_OK)
-    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+  if (status != BTA_HH_OK) {
+    tBTA_HH_DATA bta_hh_data;
+    bta_hh_data.status = status;
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
+  }
 
   return;
 }
@@ -486,7 +499,11 @@
 
     status = HID_HostCloseDev(disc_dat.handle);
 
-    if (status) (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH*)&disc_dat);
+    if (status) {
+      tBTA_HH bta_hh;
+      bta_hh.dev_status = disc_dat;
+      (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, &bta_hh);
+    }
   }
 
   return;
@@ -622,31 +639,28 @@
  *
  ******************************************************************************/
 void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
-  tBTA_HH_CBDATA cback_data;
-  tBTA_HH_HSDATA hs_data;
-  tBTA_HH_CONN conn;
-
 #if (BTA_HH_DEBUG == TRUE)
   APPL_TRACE_DEBUG("HANDSHAKE received for: event = %s data= %d",
                    bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data);
 #endif
 
-  memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA));
-  memset(&cback_data, 0, sizeof(tBTA_HH_CBDATA));
+  tBTA_HH bta_hh;
+  memset(&bta_hh, 0, sizeof(tBTA_HH));
 
   switch (p_cb->w4_evt) {
     /* GET_ transsaction, handshake indicate unsupported request */
     case BTA_HH_GET_PROTO_EVT:
-      hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
+      bta_hh.hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
     /* fall through */
     case BTA_HH_GET_RPT_EVT:
     case BTA_HH_GET_IDLE_EVT:
-      hs_data.handle = p_cb->hid_handle;
+      bta_hh.hs_data.handle = p_cb->hid_handle;
       /* if handshake gives an OK code for these transaction, fill in UNSUPT */
-      hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
-      if (hs_data.status == BTA_HH_OK) hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
+      bta_hh.hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+      if (bta_hh.hs_data.status == BTA_HH_OK)
+        bta_hh.hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
 
-      (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&hs_data);
+      (*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
       p_cb->w4_evt = 0;
       break;
 
@@ -654,18 +668,20 @@
     case BTA_HH_SET_RPT_EVT:
     case BTA_HH_SET_PROTO_EVT:
     case BTA_HH_SET_IDLE_EVT:
-      cback_data.handle = p_cb->hid_handle;
-      cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
-      (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&cback_data);
+      bta_hh.dev_status.handle = p_cb->hid_handle;
+      bta_hh.dev_status.status =
+          bta_hh_get_trans_status(p_data->hid_cback.data);
+      (*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
       p_cb->w4_evt = 0;
       break;
 
     /* SET_PROTOCOL when open connection */
     case BTA_HH_OPEN_EVT:
-      conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
-      conn.handle = p_cb->hid_handle;
-      conn.bda = p_cb->addr;
-      (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&conn);
+      bta_hh.conn.status =
+          p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
+      bta_hh.conn.handle = p_cb->hid_handle;
+      bta_hh.conn.bda = p_cb->addr;
+      (*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
 #if (BTA_HH_DEBUG == TRUE)
       bta_hh_trace_dev_db();
 #endif
@@ -916,7 +932,8 @@
 #if (BTA_HH_LE_INCLUDED == TRUE)
         if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
           dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info);
-          dev_info.status = BTA_HH_OK;
+          if (dev_info.handle != BTA_HH_INVALID_HANDLE)
+            dev_info.status = BTA_HH_OK;
         } else
 #endif
 
diff --git a/bta/hh/bta_hh_api.cc b/bta/hh/bta_hh_api.cc
index 164633c..e9b3f64 100644
--- a/bta/hh/bta_hh_api.cc
+++ b/bta/hh/bta_hh_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hh/bta_hh_cfg.cc b/bta/hh/bta_hh_cfg.cc
index 9479e8b..debe3e5 100644
--- a/bta/hh/bta_hh_cfg.cc
+++ b/bta/hh/bta_hh_cfg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -52,4 +52,4 @@
     BTA_HH_DISC_BUF_SIZE /* HH SDP discovery database size */
 };
 
-tBTA_HH_CFG* p_bta_hh_cfg = (tBTA_HH_CFG*)&bta_hh_cfg;
+const tBTA_HH_CFG* p_bta_hh_cfg = &bta_hh_cfg;
diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h
index 128a078..74bcffc 100644
--- a/bta/hh/bta_hh_int.h
+++ b/bta/hh/bta_hh_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -284,9 +284,9 @@
   uint8_t cb_index[BTA_HH_MAX_KNOWN];     /* maintain a CB index
                                         map to dev handle */
 #if (BTA_HH_LE_INCLUDED == TRUE)
-  uint8_t le_cb_index[BTA_HH_MAX_DEVICE]; /* maintain a CB index map to LE dev
+  uint8_t le_cb_index[BTA_HH_LE_MAX_KNOWN]; /* maintain a CB index map to LE dev
                                              handle */
-  tBTA_GATTC_IF gatt_if;
+  tGATT_IF gatt_if;
 #endif
   tBTA_HH_CBACK* p_cback; /* Application callbacks */
   tSDP_DISCOVERY_DB* p_disc_db;
@@ -354,7 +354,7 @@
 
 /* functions for LE HID */
 extern void bta_hh_le_enable(void);
-extern bool bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if);
+extern bool bta_hh_le_is_hh_gatt_if(tGATT_IF client_if);
 extern void bta_hh_le_deregister(void);
 extern bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb,
                                 const RawAddress& remote_bda);
diff --git a/bta/hh/bta_hh_le.cc b/bta/hh/bta_hh_le.cc
index b4827a2..adeb957 100644
--- a/bta/hh/bta_hh_le.cc
+++ b/bta/hh/bta_hh_le.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,12 +28,9 @@
 
 #include <base/bind.h>
 #include <base/callback.h>
-#include <list>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
 
 #include "bta_gatt_api.h"
+#include "bta_gatt_queue.h"
 #include "bta_hh_co.h"
 #include "btm_api.h"
 #include "btm_ble_api.h"
@@ -44,6 +41,7 @@
 #include "stack/include/l2c_api.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
 using std::vector;
 
 #ifndef BTA_HH_LE_RECONN
@@ -73,161 +71,6 @@
 //                                       tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache,
 //                                       uint8_t num_rpt);
 
-#define GATT_READ_CHAR 0
-#define GATT_READ_DESC 1
-#define GATT_WRITE_CHAR 2
-#define GATT_WRITE_DESC 3
-
-/* Holds pending GATT operations */
-struct gatt_operation {
-  uint8_t type;
-  uint16_t handle;
-  GATT_READ_OP_CB read_cb;
-  void* read_cb_data;
-  GATT_WRITE_OP_CB write_cb;
-  void* write_cb_data;
-
-  /* write-specific fields */
-  tBTA_GATTC_WRITE_TYPE write_type;
-  vector<uint8_t> value;
-};
-
-// maps connection id to operations waiting for execution
-static std::unordered_map<uint16_t, std::list<gatt_operation>> gatt_op_queue;
-// contain connection ids that currently execute operations
-static std::unordered_set<uint16_t> gatt_op_queue_executing;
-
-static void mark_as_not_executing(uint16_t conn_id) {
-  gatt_op_queue_executing.erase(conn_id);
-}
-
-static void gatt_op_queue_clean(uint16_t conn_id) {
-  gatt_op_queue.erase(conn_id);
-  gatt_op_queue_executing.erase(conn_id);
-}
-
-static void gatt_execute_next_op(uint16_t conn_id);
-GATT_READ_OP_CB act_read_cb = NULL;
-void* act_read_cb_data = NULL;
-static void gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
-                                  uint16_t handle, uint16_t len, uint8_t* value,
-                                  void* data) {
-  GATT_READ_OP_CB tmp_cb = act_read_cb;
-  void* tmp_cb_data = act_read_cb_data;
-
-  act_read_cb = NULL;
-  act_read_cb_data = NULL;
-
-  mark_as_not_executing(conn_id);
-  gatt_execute_next_op(conn_id);
-
-  if (tmp_cb) {
-    tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
-    return;
-  }
-}
-
-GATT_WRITE_OP_CB act_write_cb = NULL;
-void* act_write_cb_data = NULL;
-static void gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
-                                   uint16_t handle, void* data) {
-  GATT_WRITE_OP_CB tmp_cb = act_write_cb;
-  void* tmp_cb_data = act_write_cb_data;
-  act_write_cb = NULL;
-  act_write_cb_data = NULL;
-
-  mark_as_not_executing(conn_id);
-  gatt_execute_next_op(conn_id);
-
-  if (tmp_cb) {
-    tmp_cb(conn_id, status, handle, tmp_cb_data);
-    return;
-  }
-}
-
-static void gatt_execute_next_op(uint16_t conn_id) {
-  APPL_TRACE_DEBUG("%s:", __func__, conn_id);
-  if (gatt_op_queue.empty()) {
-    APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
-    return;
-  }
-
-  auto map_ptr = gatt_op_queue.find(conn_id);
-  if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
-    APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
-                     conn_id);
-    return;
-  }
-
-  if (gatt_op_queue_executing.count(conn_id)) {
-    APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
-    return;
-  }
-
-  gatt_op_queue_executing.insert(conn_id);
-
-  std::list<gatt_operation>& gatt_ops = map_ptr->second;
-
-  gatt_operation& op = gatt_ops.front();
-
-  if (op.type == GATT_READ_CHAR) {
-    act_read_cb = op.read_cb;
-    act_read_cb_data = op.read_cb_data;
-    BTA_GATTC_ReadCharacteristic(conn_id, op.handle, BTA_GATT_AUTH_REQ_NONE,
-                                 gatt_read_op_finished, NULL);
-
-  } else if (op.type == GATT_READ_DESC) {
-    act_read_cb = op.read_cb;
-    act_read_cb_data = op.read_cb_data;
-    BTA_GATTC_ReadCharDescr(conn_id, op.handle, BTA_GATT_AUTH_REQ_NONE,
-                            gatt_read_op_finished, NULL);
-
-  } else if (op.type == GATT_WRITE_CHAR) {
-    act_write_cb = op.write_cb;
-    act_write_cb_data = op.write_cb_data;
-    BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
-                             std::move(op.value), BTA_GATT_AUTH_REQ_NONE,
-                             gatt_write_op_finished, NULL);
-
-  } else if (op.type == GATT_WRITE_DESC) {
-    act_write_cb = op.write_cb;
-    act_write_cb_data = op.write_cb_data;
-    BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
-                             BTA_GATT_AUTH_REQ_NONE, gatt_write_op_finished,
-                             NULL);
-  }
-
-  gatt_ops.pop_front();
-}
-
-static void gatt_queue_read_op(uint8_t op_type, uint16_t conn_id,
-                               uint16_t handle, GATT_READ_OP_CB cb,
-                               void* cb_data) {
-  gatt_operation op;
-  op.type = op_type;
-  op.handle = handle;
-  op.read_cb = cb;
-  op.read_cb_data = cb_data;
-  gatt_op_queue[conn_id].push_back(op);
-  gatt_execute_next_op(conn_id);
-}
-
-static void gatt_queue_write_op(uint8_t op_type, uint16_t conn_id,
-                                uint16_t handle, vector<uint8_t> value,
-                                tBTA_GATTC_WRITE_TYPE write_type,
-                                GATT_WRITE_OP_CB cb, void* cb_data) {
-  gatt_operation op;
-  op.type = op_type;
-  op.handle = handle;
-  op.write_type = write_type;
-  op.write_cb = cb;
-  op.write_cb_data = cb_data;
-  op.value = std::move(value);
-
-  gatt_op_queue[conn_id].push_back(op);
-  gatt_execute_next_op(conn_id);
-}
-
 #if (BTA_HH_DEBUG == TRUE)
 static const char* bta_hh_le_rpt_name[4] = {"UNKNOWN", "INPUT", "OUTPUT",
                                             "FEATURE"};
@@ -324,22 +167,27 @@
 
   bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
 
-  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++)
+  for (xx = 0; xx < ARRAY_SIZE(bta_hh_cb.le_cb_index); xx++)
     bta_hh_cb.le_cb_index[xx] = BTA_HH_IDX_INVALID;
 
   BTA_GATTC_AppRegister(bta_hh_gattc_callback,
                         base::Bind([](uint8_t client_id, uint8_t r_status) {
-                          tBTA_HH_STATUS status = BTA_HH_ERR;
+                          tBTA_HH bta_hh;
+                          bta_hh.status = BTA_HH_ERR;
 
-                          if (r_status == BTA_GATT_OK) {
+                          if (r_status == GATT_SUCCESS) {
                             bta_hh_cb.gatt_if = client_id;
-                            status = BTA_HH_OK;
-                          } else
+                            bta_hh.status = BTA_HH_OK;
+                          } else {
                             bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+                          }
 
-                          /* signal BTA call back event */
-                          (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT,
-                                               (tBTA_HH*)&status);
+                          /* null check is needed in case HID profile is shut
+                           * down before BTA_GATTC_AppRegister is done */
+                          if (bta_hh_cb.p_cback) {
+                            /* signal BTA call back event */
+                            (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, &bta_hh);
+                          }
                         }));
 }
 
@@ -353,7 +201,7 @@
  * Returns          whether it is HH GATT IF
  *
  ******************************************************************************/
-bool bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if) {
+bool bta_hh_le_is_hh_gatt_if(tGATT_IF client_if) {
   return (bta_hh_cb.gatt_if == client_if);
 }
 
@@ -384,6 +232,28 @@
   return p_cb->is_le_device;
 }
 
+/******************************************************************************
+ *
+ * Function         bta_hh_le_get_le_cb
+ *
+ * Description      Allocate bta_hh_cb.le_cb_index
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+uint8_t bta_hh_le_get_le_dev_hdl(uint8_t cb_index) {
+  uint8_t i;
+  for (i = 0; i < ARRAY_SIZE(bta_hh_cb.le_cb_index); i++) {
+    if (bta_hh_cb.le_cb_index[i] == cb_index) return BTA_HH_GET_LE_DEV_HDL(i);
+  }
+
+  for (i = 0; i < ARRAY_SIZE(bta_hh_cb.le_cb_index); i++) {
+    if (bta_hh_cb.le_cb_index[i] == BTA_HH_IDX_INVALID)
+      return BTA_HH_GET_LE_DEV_HDL(i);
+  }
+  return BTA_HH_IDX_INVALID;
+}
+
 /*******************************************************************************
  *
  * Function         bta_hh_le_open_conn
@@ -394,14 +264,20 @@
  *
  ******************************************************************************/
 void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, const RawAddress& remote_bda) {
+  tBTA_HH_STATUS status = BTA_HH_ERR_NO_RES;
+
   /* update cb_index[] map */
-  p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+  p_cb->hid_handle = bta_hh_le_get_le_dev_hdl(p_cb->index);
+  if (p_cb->hid_handle == BTA_HH_IDX_INVALID) {
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+    return;
+  }
+
   p_cb->addr = remote_bda;
   bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
   p_cb->in_use = true;
 
-  BTA_GATTC_Open(bta_hh_cb.gatt_if, remote_bda, true, BTA_GATT_TRANSPORT_LE,
-                 false);
+  BTA_GATTC_Open(bta_hh_cb.gatt_if, remote_bda, true, GATT_TRANSPORT_LE, false);
 }
 
 /*******************************************************************************
@@ -581,7 +457,7 @@
   return NULL;
 }
 
-static tBTA_GATTC_DESCRIPTOR* find_descriptor_by_short_uuid(
+static const tBTA_GATTC_DESCRIPTOR* find_descriptor_by_short_uuid(
     uint16_t conn_id, uint16_t char_handle, uint16_t short_uuid) {
   const tBTA_GATTC_CHARACTERISTIC* p_char =
       BTA_GATTC_GetCharacteristic(conn_id, char_handle);
@@ -591,14 +467,8 @@
     return NULL;
   }
 
-  if (!p_char->descriptors || list_is_empty(p_char->descriptors)) return NULL;
-
-  for (list_node_t* dn = list_begin(p_char->descriptors);
-       dn != list_end(p_char->descriptors); dn = list_next(dn)) {
-    tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
-
-    if (p_char->uuid.len == LEN_UUID_16 && p_desc->uuid.uu.uuid16 == short_uuid)
-      return p_desc;
+  for (const tBTA_GATTC_DESCRIPTOR& desc : p_char->descriptors) {
+    if (desc.uuid == Uuid::From16Bit(short_uuid)) return &desc;
   }
 
   return NULL;
@@ -620,8 +490,7 @@
       find_descriptor_by_short_uuid(p_cb->conn_id, char_handle, short_uuid);
   if (!p_desc) return BTA_HH_ERR;
 
-  gatt_queue_read_op(GATT_READ_DESC, p_cb->conn_id, p_desc->handle, cb,
-                     cb_data);
+  BtaGattQueue::ReadDescriptor(p_cb->conn_id, p_desc->handle, cb, cb_data);
   return BTA_HH_OK;
 }
 
@@ -637,7 +506,7 @@
 void bta_hh_le_save_report_ref(tBTA_HH_DEV_CB* p_dev_cb, tBTA_HH_LE_RPT* p_rpt,
                                tGATT_STATUS status, uint8_t* value,
                                uint16_t len) {
-  if (status == BTA_GATT_INSUF_AUTHENTICATION) {
+  if (status == GATT_INSUF_AUTHENTICATION) {
     /* close connection right away */
     p_dev_cb->status = BTA_HH_ERR_AUTH_FAILED;
     /* close the connection and report service discovery complete with error */
@@ -646,7 +515,7 @@
   }
 
   /* if the length of the descriptor value is right, parse it */
-  if (status == BTA_GATT_OK && len == 2) {
+  if (status == GATT_SUCCESS && len == 2) {
     uint8_t* pp = value;
 
     STREAM_TO_UINT8(p_rpt->rpt_id, pp);
@@ -702,7 +571,7 @@
       /* boot mode, deregister report input notification */
       else if (proto_mode == BTA_HH_PROTO_BOOT_MODE) {
         if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
-            p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+            p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) {
           APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__,
                            p_rpt->rpt_id);
           BTA_GATTC_DeregisterForNotifications(
@@ -719,14 +588,13 @@
       } else if (proto_mode == BTA_HH_PROTO_RPT_MODE) {
         if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
              p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
-            p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+            p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) {
           APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__,
                            p_rpt->rpt_id);
           BTA_GATTC_DeregisterForNotifications(
               bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id);
         } else if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
-                   p_rpt->client_cfg_value ==
-                       BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+                   p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) {
           APPL_TRACE_DEBUG("%s <--- Register Report ID: %d", __func__,
                            p_rpt->rpt_id);
           BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
@@ -752,14 +620,14 @@
   for (uint8_t i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
     if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
       if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
-          p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+          p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) {
         APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__,
                          p_rpt->rpt_id);
         BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
                                              p_rpt->char_inst_id);
       } else if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
                   p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
-                 p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+                 p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) {
         APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__,
                          p_rpt->rpt_id);
         BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
@@ -803,7 +671,7 @@
 bool bta_hh_le_write_ccc(tBTA_HH_DEV_CB* p_cb, uint8_t char_handle,
                          uint16_t clt_cfg_value, GATT_WRITE_OP_CB cb,
                          void* cb_data) {
-  tBTA_GATTC_DESCRIPTOR* p_desc = find_descriptor_by_short_uuid(
+  const tBTA_GATTC_DESCRIPTOR* p_desc = find_descriptor_by_short_uuid(
       p_cb->conn_id, char_handle, GATT_UUID_CHAR_CLIENT_CONFIG);
   if (!p_desc) return false;
 
@@ -811,8 +679,8 @@
   uint8_t* ptr = value.data();
   UINT16_TO_STREAM(ptr, clt_cfg_value);
 
-  gatt_queue_write_op(GATT_WRITE_DESC, p_cb->conn_id, p_desc->handle,
-                      std::move(value), BTA_GATTC_TYPE_WRITE, cb, cb_data);
+  BtaGattQueue::WriteDescriptor(p_cb->conn_id, p_desc->handle, std::move(value),
+                                GATT_WRITE, cb, cb_data);
   return true;
 }
 
@@ -823,12 +691,11 @@
   uint8_t srvc_inst_id, hid_inst_id;
 
   tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
-  const tBTA_GATTC_DESCRIPTOR* p_desc =
-      BTA_GATTC_GetDescriptor(conn_id, handle);
+  const tBTA_GATTC_CHARACTERISTIC* characteristic =
+      BTA_GATTC_GetOwningCharacteristic(conn_id, handle);
+  uint16_t char_uuid = characteristic->uuid.As16Bit();
 
-  uint16_t char_uuid = p_desc->characteristic->uuid.uu.uuid16;
-
-  srvc_inst_id = p_desc->characteristic->service->handle;
+  srvc_inst_id = BTA_GATTC_GetOwningService(conn_id, handle)->handle;
   hid_inst_id = srvc_inst_id;
   switch (char_uuid) {
     case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */
@@ -838,9 +705,9 @@
     case GATT_UUID_HID_BT_KB_INPUT:
     case GATT_UUID_HID_BT_MOUSE_INPUT:
     case GATT_UUID_HID_REPORT:
-      if (status == BTA_GATT_OK)
+      if (status == GATT_SUCCESS)
         p_dev_cb->hid_srvc.report[p_dev_cb->clt_cfg_idx].client_cfg_value =
-            BTA_GATT_CLT_CONFIG_NOTIFICATION;
+            GATT_CLT_CONFIG_NOTIFICATION;
       p_dev_cb->clt_cfg_idx++;
       bta_hh_le_write_rpt_clt_cfg(p_dev_cb);
       break;
@@ -866,7 +733,7 @@
     /* enable notification for all input report, regardless mode */
     if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
       if (bta_hh_le_write_ccc(p_cb, p_rpt->char_inst_id,
-                              BTA_GATT_CLT_CONFIG_NOTIFICATION,
+                              GATT_CLT_CONFIG_NOTIFICATION,
                               write_rpt_ctl_cfg_cb, p_cb)) {
         p_cb->clt_cfg_idx = i;
         return true;
@@ -897,15 +764,15 @@
     tBTA_HH_CBDATA cback_data;
 
     cback_data.handle = p_dev_cb->hid_handle;
-    cback_data.status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR;
+    cback_data.status = (status == GATT_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR;
 
-    if (status == BTA_GATT_OK)
+    if (status == GATT_SUCCESS)
       bta_hh_le_register_input_notif(p_dev_cb, p_dev_cb->mode, false);
 
     p_dev_cb->w4_evt = 0;
     (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
   } else if (p_dev_cb->state == BTA_HH_W4_CONN_ST) {
-    p_dev_cb->status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
+    p_dev_cb->status = (status == GATT_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
 
     if ((p_dev_cb->disc_active & BTA_HH_LE_DISC_HIDS) == 0)
       bta_hh_le_open_cmpl(p_dev_cb);
@@ -950,9 +817,9 @@
     mode = (mode == BTA_HH_PROTO_BOOT_MODE) ? BTA_HH_LE_PROTO_BOOT_MODE
                                             : BTA_HH_LE_PROTO_REPORT_MODE;
 
-    gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id,
-                        p_cb->hid_srvc.proto_mode_handle, {mode},
-                        BTA_GATTC_TYPE_WRITE_NO_RSP, write_proto_mode_cb, p_cb);
+    BtaGattQueue::WriteCharacteristic(
+        p_cb->conn_id, p_cb->hid_srvc.proto_mode_handle, {mode},
+        GATT_WRITE_NO_RSP, write_proto_mode_cb, p_cb);
     return true;
   }
 
@@ -976,7 +843,7 @@
   hs_data.handle = p_dev_cb->hid_handle;
   hs_data.rsp_data.proto_mode = p_dev_cb->mode;
 
-  if (status == BTA_GATT_OK && len) {
+  if (status == GATT_SUCCESS && len) {
     hs_data.status = BTA_HH_OK;
     /* match up BTE/BTA report/boot mode def*/
     hs_data.rsp_data.proto_mode = *(value);
@@ -1013,9 +880,9 @@
   p_cb->w4_evt = BTA_HH_GET_PROTO_EVT;
 
   if (p_cb->hid_srvc.in_use && p_cb->hid_srvc.proto_mode_handle != 0) {
-    gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id,
-                       p_cb->hid_srvc.proto_mode_handle, get_protocol_mode_cb,
-                       p_cb);
+    BtaGattQueue::ReadCharacteristic(p_cb->conn_id,
+                                     p_cb->hid_srvc.proto_mode_handle,
+                                     get_protocol_mode_cb, p_cb);
     return;
   }
 
@@ -1071,8 +938,6 @@
  *
  ******************************************************************************/
 void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB* p_cb) {
-  tBT_UUID pri_srvc;
-
   bta_hh_le_co_reset_rpt_cache(p_cb->addr, p_cb->app_id);
 
   p_cb->disc_active |= (BTA_HH_LE_DISC_HIDS | BTA_HH_LE_DISC_DIS);
@@ -1085,8 +950,7 @@
 
   /* in parallel */
   /* start primary service discovery for HID service */
-  pri_srvc.len = LEN_UUID_16;
-  pri_srvc.uu.uuid16 = UUID_SERVCLASS_LE_HID;
+  Uuid pri_srvc = Uuid::From16Bit(UUID_SERVCLASS_LE_HID);
   BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc);
   return;
 }
@@ -1101,7 +965,7 @@
  *
  ******************************************************************************/
 void bta_hh_le_encrypt_cback(const RawAddress* bd_addr,
-                             UNUSED_ATTR tBTA_GATT_TRANSPORT transport,
+                             UNUSED_ATTR tGATT_TRANSPORT transport,
                              UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
   uint8_t idx = bta_hh_find_cb(*bd_addr);
   tBTA_HH_DEV_CB* p_dev_cb;
@@ -1150,7 +1014,7 @@
     if (p_cb->app_id != 0 && p_cb->hid_srvc.in_use) {
       APPL_TRACE_DEBUG("%s: discovery has been done for HID service", __func__);
       /* configure protocol mode */
-      if (bta_hh_le_set_protocol_mode(p_cb, p_cb->mode) == false) {
+      if (!bta_hh_le_set_protocol_mode(p_cb, p_cb->mode)) {
         bta_hh_le_open_cmpl(p_cb);
       }
     }
@@ -1177,7 +1041,7 @@
  *
  ******************************************************************************/
 void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
-  if (p_cb == NULL || p_cb->security_pending == false || p_buf == NULL ||
+  if (p_cb == NULL || !p_cb->security_pending || p_buf == NULL ||
       p_buf->le_enc_cmpl.client_if != bta_hh_cb.gatt_if) {
     return;
   }
@@ -1234,6 +1098,7 @@
 
   /* if link has been encrypted */
   if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
+    p_cb->status = BTA_HH_OK;
     bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
   }
   /* if bonded and link not encrypted */
@@ -1269,7 +1134,6 @@
 void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
   tBTA_GATTC_OPEN* p_data = &p_buf->le_open;
   uint8_t* p2;
-  tHID_STATUS status = BTA_HH_ERR;
 
   /* if received invalid callback data , ignore it */
   if (p_cb == NULL || p_data == NULL) return;
@@ -1281,15 +1145,20 @@
       ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]),
       ((p2[4]) << 8) + p2[5], p_data->status);
 
-  if (p_data->status == BTA_GATT_OK) {
+  if (p_data->status == GATT_SUCCESS) {
+    p_cb->hid_handle = bta_hh_le_get_le_dev_hdl(p_cb->index);
+    if (p_cb->hid_handle == BTA_HH_IDX_INVALID) {
+      p_cb->conn_id = p_data->conn_id;
+      bta_hh_le_api_disc_act(p_cb);
+      return;
+    }
     p_cb->is_le_device = true;
     p_cb->in_use = true;
     p_cb->conn_id = p_data->conn_id;
-    p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
 
     bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
 
-    gatt_op_queue_clean(p_cb->conn_id);
+    BtaGattQueue::Clean(p_cb->conn_id);
 
 #if (BTA_HH_DEBUG == TRUE)
     APPL_TRACE_DEBUG("hid_handle = %2x conn_id = %04x cb_index = %d",
@@ -1298,9 +1167,11 @@
 
     bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL);
 
-  } else /* open failure */
-  {
-    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+  } else {
+    /* open failure */
+    tBTA_HH_DATA bta_hh_data;
+    bta_hh_data.status = BTA_HH_ERR;
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
   }
 }
 
@@ -1326,7 +1197,7 @@
     p_buf->conn_id = p_data->conn_id;
     p_buf->reason = p_data->reason;
 
-    p_dev_cb->conn_id = BTA_GATT_INVALID_CONN_ID;
+    p_dev_cb->conn_id = GATT_INVALID_CONN_ID;
     p_dev_cb->security_pending = false;
     bta_sys_sendmsg(p_buf);
   }
@@ -1363,7 +1234,7 @@
 static void read_hid_info_cb(uint16_t conn_id, tGATT_STATUS status,
                              uint16_t handle, uint16_t len, uint8_t* value,
                              void* data) {
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     APPL_TRACE_ERROR("%s: error: %d", __func__, status);
     return;
   }
@@ -1384,7 +1255,7 @@
 static void read_hid_report_map_cb(uint16_t conn_id, tGATT_STATUS status,
                                    uint16_t handle, uint16_t len,
                                    uint8_t* value, void* data) {
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     APPL_TRACE_ERROR("%s: error reading characteristic: %d", __func__, status);
     return;
   }
@@ -1407,14 +1278,14 @@
 static void read_ext_rpt_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
                                      uint16_t handle, uint16_t len,
                                      uint8_t* value, void* data) {
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     APPL_TRACE_ERROR("%s: error: %d", __func__, status);
     return;
   }
 
   /* if the length of the descriptor value is right, parse it assume it's a 16
    * bits UUID */
-  if (len != LEN_UUID_16) {
+  if (len != Uuid::kNumBytes16) {
     APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len);
     return;
   }
@@ -1433,7 +1304,7 @@
 static void read_report_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
                                     uint16_t handle, uint16_t len,
                                     uint8_t* value, void* data) {
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     APPL_TRACE_ERROR("%s: error: %d", __func__, status);
     return;
   }
@@ -1447,17 +1318,22 @@
     return;
   }
 
+  const tBTA_GATTC_CHARACTERISTIC* characteristic =
+      BTA_GATTC_GetOwningCharacteristic(conn_id, handle);
+  const tBTA_GATTC_SERVICE* service =
+      BTA_GATTC_GetOwningService(conn_id, characteristic->value_handle);
+
   tBTA_HH_LE_RPT* p_rpt;
-  p_rpt = bta_hh_le_find_report_entry(
-      p_dev_cb, p_desc->characteristic->service->handle, GATT_UUID_HID_REPORT,
-      p_desc->characteristic->handle);
+  p_rpt = bta_hh_le_find_report_entry(p_dev_cb, service->handle,
+                                      GATT_UUID_HID_REPORT,
+                                      characteristic->value_handle);
   if (p_rpt) bta_hh_le_save_report_ref(p_dev_cb, p_rpt, status, value, len);
 }
 
 void read_pref_conn_params_cb(uint16_t conn_id, tGATT_STATUS status,
                               uint16_t handle, uint16_t len, uint8_t* value,
                               void* data) {
-  if (status != BTA_GATT_OK) {
+  if (status != GATT_SUCCESS) {
     APPL_TRACE_ERROR("%s: error: %d", __func__, status);
     return;
   }
@@ -1470,30 +1346,45 @@
   // TODO(jpawlowski): this should be done by GAP profile, remove when GAP is
   // fixed.
   uint8_t* pp = value;
-  uint16_t min, max, latency, tout;
-  STREAM_TO_UINT16(min, pp);
-  STREAM_TO_UINT16(max, pp);
+  uint16_t min_interval, max_interval, latency, timeout;
+  STREAM_TO_UINT16(min_interval, pp);
+  STREAM_TO_UINT16(max_interval, pp);
   STREAM_TO_UINT16(latency, pp);
-  STREAM_TO_UINT16(tout, pp);
+  STREAM_TO_UINT16(timeout, pp);
 
   // Make sure both min, and max are bigger than 11.25ms, lower values can
-  // introduce
-  // audio issues if A2DP is also active.
-  if (min < BTM_BLE_CONN_INT_MIN_LIMIT) min = BTM_BLE_CONN_INT_MIN_LIMIT;
-  if (max < BTM_BLE_CONN_INT_MIN_LIMIT) max = BTM_BLE_CONN_INT_MIN_LIMIT;
+  // introduce audio issues if A2DP is also active.
+  L2CA_AdjustConnectionIntervals(&min_interval, &max_interval,
+                                 BTM_BLE_CONN_INT_MIN_LIMIT);
 
   // If the device has no preferred connection timeout, use the default.
-  if (tout == BTM_BLE_CONN_PARAM_UNDEF) tout = BTM_BLE_CONN_TIMEOUT_DEF;
+  if (timeout == BTM_BLE_CONN_PARAM_UNDEF) timeout = BTM_BLE_CONN_TIMEOUT_DEF;
+
+  if (min_interval < BTM_BLE_CONN_INT_MIN ||
+      min_interval > BTM_BLE_CONN_INT_MAX ||
+      max_interval < BTM_BLE_CONN_INT_MIN ||
+      max_interval > BTM_BLE_CONN_INT_MAX ||
+      latency > BTM_BLE_CONN_LATENCY_MAX ||
+      timeout < BTM_BLE_CONN_SUP_TOUT_MIN ||
+      timeout > BTM_BLE_CONN_SUP_TOUT_MAX || max_interval < min_interval) {
+    APPL_TRACE_ERROR(
+        "%s: Invalid connection parameters. min=%d, max=%d, latency=%d, "
+        "timeout=%d",
+        __func__, min_interval, max_interval, latency, timeout);
+    return;
+  }
 
   tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
 
   if (interop_match_addr(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S,
-                         (RawAddress*)&p_dev_cb->addr) == true) {
-    if (tout < 300) tout = 300;
+                         (RawAddress*)&p_dev_cb->addr)) {
+    if (timeout < 300) timeout = 300;
   }
 
-  BTM_BleSetPrefConnParams(p_dev_cb->addr, min, max, latency, tout);
-  L2CA_UpdateBleConnParams(p_dev_cb->addr, min, max, latency, tout);
+  BTM_BleSetPrefConnParams(p_dev_cb->addr, min_interval, max_interval, latency,
+                           timeout);
+  L2CA_UpdateBleConnParams(p_dev_cb->addr, min_interval, max_interval, latency,
+                           timeout);
 }
 
 /*******************************************************************************
@@ -1507,35 +1398,31 @@
  *
  ******************************************************************************/
 static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb,
-                                       tBTA_GATTC_SERVICE* service) {
+                                       const tBTA_GATTC_SERVICE* service) {
   tBTA_HH_LE_RPT* p_rpt;
 
-  for (list_node_t* cn = list_begin(service->characteristics);
-       cn != list_end(service->characteristics); cn = list_next(cn)) {
-    tBTA_GATTC_CHARACTERISTIC* p_char =
-        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+  for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+    if (!charac.uuid.Is16Bit()) continue;
 
-    if (p_char->uuid.len != LEN_UUID_16) continue;
+    uint16_t uuid16 = charac.uuid.As16Bit();
+    LOG_DEBUG(LOG_TAG, "%s: %s %s", __func__, bta_hh_uuid_to_str(uuid16),
+              charac.uuid.ToString().c_str());
 
-    LOG_DEBUG(LOG_TAG, "%s: %s 0x%04d", __func__,
-              bta_hh_uuid_to_str(p_char->uuid.uu.uuid16),
-              p_char->uuid.uu.uuid16);
-
-    switch (p_char->uuid.uu.uuid16) {
+    switch (uuid16) {
       case GATT_UUID_HID_CONTROL_POINT:
-        p_dev_cb->hid_srvc.control_point_handle = p_char->handle;
+        p_dev_cb->hid_srvc.control_point_handle = charac.value_handle;
         break;
       case GATT_UUID_HID_INFORMATION:
         /* only one instance per HID service */
-        gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
-                           read_hid_info_cb, p_dev_cb);
+        BtaGattQueue::ReadCharacteristic(p_dev_cb->conn_id, charac.value_handle,
+                                         read_hid_info_cb, p_dev_cb);
         break;
       case GATT_UUID_HID_REPORT_MAP:
         /* only one instance per HID service */
-        gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
-                           read_hid_report_map_cb, p_dev_cb);
+        BtaGattQueue::ReadCharacteristic(p_dev_cb->conn_id, charac.value_handle,
+                                         read_hid_report_map_cb, p_dev_cb);
         /* descriptor is optional */
-        bta_hh_le_read_char_descriptor(p_dev_cb, p_char->handle,
+        bta_hh_le_read_char_descriptor(p_dev_cb, charac.value_handle,
                                        GATT_UUID_EXT_RPT_REF_DESCR,
                                        read_ext_rpt_ref_desc_cb, p_dev_cb);
         break;
@@ -1543,7 +1430,7 @@
       case GATT_UUID_HID_REPORT:
         p_rpt = bta_hh_le_find_alloc_report_entry(
             p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id, GATT_UUID_HID_REPORT,
-            p_char->handle);
+            charac.value_handle);
         if (p_rpt == NULL) {
           APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__);
           break;
@@ -1551,7 +1438,7 @@
 
         if (p_rpt->rpt_type != BTA_HH_RPTT_INPUT) break;
 
-        bta_hh_le_read_char_descriptor(p_dev_cb, p_char->handle,
+        bta_hh_le_read_char_descriptor(p_dev_cb, charac.value_handle,
                                        GATT_UUID_RPT_REF_DESCR,
                                        read_report_ref_desc_cb, p_dev_cb);
         break;
@@ -1560,29 +1447,22 @@
       case GATT_UUID_HID_BT_KB_OUTPUT:
       case GATT_UUID_HID_BT_MOUSE_INPUT:
       case GATT_UUID_HID_BT_KB_INPUT:
-        if (bta_hh_le_find_alloc_report_entry(p_dev_cb, service->handle,
-                                              p_char->uuid.uu.uuid16,
-                                              p_char->handle) == NULL)
+        if (bta_hh_le_find_alloc_report_entry(p_dev_cb, service->handle, uuid16,
+                                              charac.value_handle) == NULL)
           APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__);
 
         break;
 
       default:
         APPL_TRACE_DEBUG("%s: not processing %s 0x%04d", __func__,
-                         bta_hh_uuid_to_str(p_char->uuid.uu.uuid16),
-                         p_char->uuid.uu.uuid16);
+                         bta_hh_uuid_to_str(uuid16), uuid16);
     }
   }
 
   /* Make sure PROTO_MODE is processed as last */
-  for (list_node_t* cn = list_begin(service->characteristics);
-       cn != list_end(service->characteristics); cn = list_next(cn)) {
-    tBTA_GATTC_CHARACTERISTIC* p_char =
-        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-
-    if (p_char->uuid.len == LEN_UUID_16 &&
-        p_char->uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE) {
-      p_dev_cb->hid_srvc.proto_mode_handle = p_char->handle;
+  for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+    if (charac.uuid == Uuid::From16Bit(GATT_UUID_HID_PROTO_MODE)) {
+      p_dev_cb->hid_srvc.proto_mode_handle = charac.value_handle;
       bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
       break;
     }
@@ -1604,46 +1484,40 @@
   /* service search exception or no HID service is supported on remote */
   if (p_dev_cb == NULL) return;
 
-  if (p_data->status != BTA_GATT_OK) {
+  if (p_data->status != GATT_SUCCESS) {
     p_dev_cb->status = BTA_HH_ERR_SDP;
     /* close the connection and report service discovery complete with error */
     bta_hh_le_api_disc_act(p_dev_cb);
     return;
   }
 
-  const list_t* services = BTA_GATTC_GetServices(p_data->conn_id);
+  const std::vector<tBTA_GATTC_SERVICE>* services =
+      BTA_GATTC_GetServices(p_data->conn_id);
 
   bool have_hid = false;
-  for (list_node_t* sn = list_begin(services); sn != list_end(services);
-       sn = list_next(sn)) {
-    tBTA_GATTC_SERVICE* service = (tBTA_GATTC_SERVICE*)list_node(sn);
-
-    if (service->uuid.uu.uuid16 == UUID_SERVCLASS_LE_HID &&
-        service->is_primary && !have_hid) {
+  for (const tBTA_GATTC_SERVICE& service : *services) {
+    if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_LE_HID) &&
+        service.is_primary && !have_hid) {
       have_hid = true;
 
       /* found HID primamry service */
       p_dev_cb->hid_srvc.in_use = true;
-      p_dev_cb->hid_srvc.srvc_inst_id = service->handle;
+      p_dev_cb->hid_srvc.srvc_inst_id = service.handle;
       p_dev_cb->hid_srvc.proto_mode_handle = 0;
       p_dev_cb->hid_srvc.control_point_handle = 0;
 
-      bta_hh_le_search_hid_chars(p_dev_cb, service);
+      bta_hh_le_search_hid_chars(p_dev_cb, &service);
 
       APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__,
                        p_dev_cb->hid_srvc.srvc_inst_id);
-    } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_SCAN_PARAM) {
+    } else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_SCAN_PARAM)) {
       p_dev_cb->scan_refresh_char_handle = 0;
 
-      for (list_node_t* cn = list_begin(service->characteristics);
-           cn != list_end(service->characteristics); cn = list_next(cn)) {
-        tBTA_GATTC_CHARACTERISTIC* p_char =
-            (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-        if (p_char->uuid.len == LEN_UUID_16 &&
-            p_char->uuid.uu.uuid16 == GATT_UUID_SCAN_REFRESH) {
-          p_dev_cb->scan_refresh_char_handle = p_char->handle;
+      for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+        if (charac.uuid == Uuid::From16Bit(GATT_UUID_SCAN_REFRESH)) {
+          p_dev_cb->scan_refresh_char_handle = charac.value_handle;
 
-          if (p_char->properties & BTA_GATT_CHAR_PROP_BIT_NOTIFY)
+          if (charac.properties & GATT_CHAR_PROP_BIT_NOTIFY)
             p_dev_cb->scps_notify |= BTA_HH_LE_SCPS_NOTIFY_SPT;
           else
             p_dev_cb->scps_notify = BTA_HH_LE_SCPS_NOTIFY_NONE;
@@ -1651,19 +1525,15 @@
           break;
         }
       }
-    } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER) {
+    } else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) {
       // TODO(jpawlowski): this should be done by GAP profile, remove when GAP
       // is fixed.
-      for (list_node_t* cn = list_begin(service->characteristics);
-           cn != list_end(service->characteristics); cn = list_next(cn)) {
-        tBTA_GATTC_CHARACTERISTIC* p_char =
-            (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
-        if (p_char->uuid.len == LEN_UUID_16 &&
-            p_char->uuid.uu.uuid16 == GATT_UUID_GAP_PREF_CONN_PARAM) {
+      for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+        if (charac.uuid == Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM)) {
           /* read the char value */
-          gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
-                             read_pref_conn_params_cb, p_dev_cb);
-
+          BtaGattQueue::ReadCharacteristic(p_dev_cb->conn_id,
+                                           charac.value_handle,
+                                           read_pref_conn_params_cb, p_dev_cb);
           break;
         }
       }
@@ -1707,19 +1577,20 @@
 
   app_id = p_dev_cb->app_id;
 
-  p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id,
-                                      p_char->uuid.uu.uuid16, p_char->handle);
+  p_rpt =
+      bta_hh_le_find_report_entry(p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id,
+                                  p_char->uuid.As16Bit(), p_char->value_handle);
   if (p_rpt == NULL) {
     APPL_TRACE_ERROR(
-        "%s: notification received for Unknown Report, uuid: 0x%04x, handle: "
+        "%s: notification received for Unknown Report, uuid: %s, handle: "
         "0x%04x",
-        __func__, p_char->uuid.uu.uuid16, p_char->handle);
+        __func__, p_char->uuid.ToString().c_str(), p_char->value_handle);
     return;
   }
 
-  if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_BT_MOUSE_INPUT)
+  if (p_char->uuid == Uuid::From16Bit(GATT_UUID_HID_BT_MOUSE_INPUT))
     app_id = BTA_HH_APP_ID_MI;
-  else if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_BT_KB_INPUT)
+  else if (p_char->uuid == Uuid::From16Bit(GATT_UUID_HID_BT_KB_INPUT))
     app_id = BTA_HH_APP_ID_KB;
 
   APPL_TRACE_DEBUG("Notification received on report ID: %d", p_rpt->rpt_id);
@@ -1767,7 +1638,7 @@
   conn_dat.scps_supported = p_cb->scps_supported;
 
   if (p_cb->status == BTA_HH_OK)
-    conn_dat.status = (p_data->le_close.reason == BTA_GATT_CONN_UNKNOWN)
+    conn_dat.status = (p_data->le_close.reason == GATT_CONN_UNKNOWN)
                           ? p_cb->status
                           : BTA_HH_ERR;
   else
@@ -1807,7 +1678,7 @@
     bta_hh_disc_cmpl();
   } else {
 #if (BTA_HH_LE_RECONN == TRUE)
-    if (p_data->le_close.reason == BTA_GATT_CONN_TIMEOUT) {
+    if (p_data->le_close.reason == GATT_CONN_TIMEOUT) {
       bta_hh_le_add_dev_bg_conn(p_cb, false);
     }
 #endif
@@ -1826,8 +1697,8 @@
  *
  ******************************************************************************/
 void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb) {
-  if (p_cb->conn_id != BTA_GATT_INVALID_CONN_ID) {
-    gatt_op_queue_clean(p_cb->conn_id);
+  if (p_cb->conn_id != GATT_INVALID_CONN_ID) {
+    BtaGattQueue::Clean(p_cb->conn_id);
     BTA_GATTC_Close(p_cb->conn_id);
     /* remove device from background connection if intended to disconnect,
        do not allow reconnection */
@@ -1853,7 +1724,7 @@
 
   if (p_char == NULL) return;
 
-  uint16_t char_uuid = p_char->uuid.uu.uuid16;
+  uint16_t char_uuid = p_char->uuid.As16Bit();
 
   if (char_uuid != GATT_UUID_HID_REPORT &&
       char_uuid != GATT_UUID_HID_BT_KB_INPUT &&
@@ -1880,9 +1751,12 @@
   hs_data.status = BTA_HH_ERR;
   hs_data.handle = p_dev_cb->hid_handle;
 
-  if (status == BTA_GATT_OK) {
-    p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_char->service->handle,
-                                        p_char->uuid.uu.uuid16, p_char->handle);
+  if (status == GATT_SUCCESS) {
+    const tBTA_GATTC_SERVICE* p_svc =
+        BTA_GATTC_GetOwningService(conn_id, p_char->value_handle);
+
+    p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_svc->handle, char_uuid,
+                                        p_char->value_handle);
 
     if (p_rpt != NULL && len) {
       p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + len + 1);
@@ -1928,8 +1802,8 @@
   }
 
   p_cb->w4_evt = BTA_HH_GET_RPT_EVT;
-  gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
-                     read_report_cb, p_cb);
+  BtaGattQueue::ReadCharacteristic(p_cb->conn_id, p_rpt->char_inst_id,
+                                   read_report_cb, p_cb);
 }
 
 static void write_report_cb(uint16_t conn_id, tGATT_STATUS status,
@@ -1946,7 +1820,7 @@
 
   const tBTA_GATTC_CHARACTERISTIC* p_char =
       BTA_GATTC_GetCharacteristic(conn_id, handle);
-  uint16_t uuid = p_char->uuid.uu.uuid16;
+  uint16_t uuid = p_char->uuid.As16Bit();
   if (uuid != GATT_UUID_HID_REPORT && uuid != GATT_UUID_HID_BT_KB_INPUT &&
       uuid != GATT_UUID_HID_BT_MOUSE_INPUT &&
       uuid != GATT_UUID_HID_BT_KB_OUTPUT) {
@@ -1955,7 +1829,7 @@
 
   /* Set Report finished */
   cback_data.handle = p_dev_cb->hid_handle;
-  cback_data.status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR;
+  cback_data.status = (status == GATT_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR;
   p_dev_cb->w4_evt = 0;
   (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
 }
@@ -1996,12 +1870,13 @@
   const tBTA_GATTC_CHARACTERISTIC* p_char =
       BTA_GATTC_GetCharacteristic(p_cb->conn_id, p_rpt->char_inst_id);
 
-  tBTA_GATTC_WRITE_TYPE write_type = BTA_GATTC_TYPE_WRITE;
-  if (p_char && (p_char->properties & BTA_GATT_CHAR_PROP_BIT_WRITE_NR))
-    write_type = BTA_GATTC_TYPE_WRITE_NO_RSP;
+  tGATT_WRITE_TYPE write_type = GATT_WRITE;
+  if (p_char && (p_char->properties & GATT_CHAR_PROP_BIT_WRITE_NR))
+    write_type = GATT_WRITE_NO_RSP;
 
-  gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
-                      std::move(value), write_type, write_report_cb, p_cb);
+  BtaGattQueue::WriteCharacteristic(p_cb->conn_id, p_rpt->char_inst_id,
+                                    std::move(value), write_type,
+                                    write_report_cb, p_cb);
 }
 
 /*******************************************************************************
@@ -2018,9 +1893,9 @@
   ctrl_type -= BTA_HH_CTRL_SUSPEND;
 
   // We don't care about response
-  gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id,
-                      p_cb->hid_srvc.control_point_handle, {(uint8_t)ctrl_type},
-                      BTA_GATTC_TYPE_WRITE_NO_RSP, NULL, NULL);
+  BtaGattQueue::WriteCharacteristic(
+      p_cb->conn_id, p_cb->hid_srvc.control_point_handle, {(uint8_t)ctrl_type},
+      GATT_WRITE_NO_RSP, NULL, NULL);
 }
 
 /*******************************************************************************
@@ -2118,7 +1993,7 @@
   if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/
       !p_cb->in_bg_conn && to_add) {
     /* add device into BG connection to accept remote initiated connection */
-    BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, BTA_GATT_TRANSPORT_LE,
+    BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, GATT_TRANSPORT_LE,
                    false);
     p_cb->in_bg_conn = true;
 
@@ -2140,7 +2015,8 @@
  ******************************************************************************/
 uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
                              tBTA_HH_MAINT_DEV* p_dev_info) {
-  p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+  p_cb->hid_handle = bta_hh_le_get_le_dev_hdl(p_cb->index);
+  if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) return BTA_HH_INVALID_HANDLE;
   bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
 
   /* update DI information */
@@ -2333,7 +2209,7 @@
 //                     == BTA_HH_RPTT_INPUT))
 //                 {
 //                     p_rpt->client_cfg_value =
-//                     BTA_GATT_CLT_CONFIG_NOTIFICATION;
+//                     GATT_CLT_CONFIG_NOTIFICATION;
 //                 }
 //             }
 //         }
diff --git a/bta/hh/bta_hh_main.cc b/bta/hh/bta_hh_main.cc
index e747773..2528391 100644
--- a/bta/hh/bta_hh_main.cc
+++ b/bta/hh/bta_hh_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -400,7 +400,7 @@
             * force the index to be IDX_INVALID
             */
           if ((index != BTA_HH_IDX_INVALID) &&
-              (bta_hh_cb.kdev[index].in_use == false)) {
+              (!bta_hh_cb.kdev[index].in_use)) {
             index = BTA_HH_IDX_INVALID;
           }
         }
diff --git a/bta/hh/bta_hh_utils.cc b/bta/hh/bta_hh_utils.cc
index c687a2a..c4c6061 100644
--- a/bta/hh/bta_hh_utils.cc
+++ b/bta/hh/bta_hh_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -437,7 +437,9 @@
   }
 
   if (bta_hh_cb.p_cback) {
-    (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
+    tBTA_HH bta_hh;
+    bta_hh.status = status;
+    (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, &bta_hh);
     /* all connections are down, no waiting for diconnect */
     memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
   }
diff --git a/bta/hl/bta_hl_act.cc b/bta/hl/bta_hl_act.cc
index 6c896f1..6d37bdf 100644
--- a/bta/hl/bta_hl_act.cc
+++ b/bta/hl/bta_hl_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,6 +39,8 @@
 #include "sdp_api.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Local Function prototypes
  ****************************************************************************/
@@ -1817,7 +1819,6 @@
 tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, uint8_t app_idx,
                                uint8_t mcl_idx, uint8_t mdl_idx) {
   tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
-  tSDP_UUID uuid_list;
   uint16_t attr_list[BTA_HL_NUM_SRCH_ATTR];
   uint16_t num_attrs = BTA_HL_NUM_SRCH_ATTR;
   tBTA_HL_STATUS status;
@@ -1843,8 +1844,7 @@
     attr_list[8] = ATTR_ID_HDP_DATA_EXCH_SPEC;
     attr_list[9] = ATTR_ID_HDP_MCAP_SUP_PROC;
 
-    uuid_list.len = LEN_UUID_16;
-    uuid_list.uu.uuid16 = UUID_SERVCLASS_HDP_PROFILE;
+    Uuid uuid_list = Uuid::From16Bit(UUID_SERVCLASS_HDP_PROFILE);
     SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs,
                         attr_list);
 
diff --git a/bta/hl/bta_hl_api.cc b/bta/hl/bta_hl_api.cc
index 145c4f2..fa82245 100644
--- a/bta/hl/bta_hl_api.cc
+++ b/bta/hl/bta_hl_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hl/bta_hl_ci.cc b/bta/hl/bta_hl_ci.cc
index b7bc2fd..e48c74b 100644
--- a/bta/hl/bta_hl_ci.cc
+++ b/bta/hl/bta_hl_ci.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hl/bta_hl_int.h b/bta/hl/bta_hl_int.h
index c0ba647..c6dce11 100644
--- a/bta/hl/bta_hl_int.h
+++ b/bta/hl/bta_hl_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1998-2012 Broadcom Corporation
+ *  Copyright 1998-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hl/bta_hl_main.cc b/bta/hl/bta_hl_main.cc
index 69c0909..dcd0815 100644
--- a/bta/hl/bta_hl_main.cc
+++ b/bta/hl/bta_hl_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1998-2012 Broadcom Corporation
+ *  Copyright 1998-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/hl/bta_hl_sdp.cc b/bta/hl/bta_hl_sdp.cc
index fe3da58..0a357f0 100644
--- a/bta/hl/bta_hl_sdp.cc
+++ b/bta/hl/bta_hl_sdp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1998-2012 Broadcom Corporation
+ *  Copyright 1998-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -220,9 +220,8 @@
     add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
     add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
     add_proto_list.list_elem[1].num_params = 0;
-    result &=
-        SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
-                                  (tSDP_PROTO_LIST_ELEM*)&add_proto_list);
+    result &= SDP_AddAdditionProtoLists(
+        p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, &add_proto_list);
   }
 
   if (result) {
@@ -410,9 +409,8 @@
     add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
     add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
     add_proto_list.list_elem[1].num_params = 0;
-    result &=
-        SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
-                                  (tSDP_PROTO_LIST_ELEM*)&add_proto_list);
+    result &= SDP_AddAdditionProtoLists(
+        p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, &add_proto_list);
   }
 
   if (result) {
diff --git a/bta/hl/bta_hl_utils.cc b/bta/hl/bta_hl_utils.cc
index 8cdacc9..0aa93b3 100644
--- a/bta/hl/bta_hl_utils.cc
+++ b/bta/hl/bta_hl_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
index 1322368..b968ae6 100644
--- a/bta/include/bta_ag_api.h
+++ b/bta/include/bta_ag_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,9 +27,16 @@
 
 #include "bta_api.h"
 
+#include <string>
+#include <vector>
+
 /*****************************************************************************
  *  Constants and data types
  ****************************************************************************/
+/* Number of SCBs (AG service instances that can be registered) */
+#define BTA_AG_MAX_NUM_CLIENTS 6
+
+#define HFP_HSP_VERSION_UNKNOWN 0x0000
 #define HFP_VERSION_1_1 0x0101
 #define HFP_VERSION_1_5 0x0105
 #define HFP_VERSION_1_6 0x0106
@@ -38,6 +45,9 @@
 #define HSP_VERSION_1_0 0x0100
 #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.
  */
@@ -57,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
 
@@ -73,14 +89,6 @@
 
 typedef uint32_t tBTA_AG_FEAT;
 
-/* AG parse mode */
-#define BTA_AG_PARSE 0 /* Perform AT command parsing in AG */
-
-/* Pass data directly to phone's AT command interpreter */
-#define BTA_AG_PASS_THROUGH 1
-
-typedef uint8_t tBTA_AG_PARSE_MODE;
-
 /* AG open status */
 #define BTA_AG_SUCCESS 0        /* Connection successfully opened */
 #define BTA_AG_FAIL_SDP 1       /* Open failed due to SDP */
@@ -140,6 +148,7 @@
 #define BTA_AG_UNAT_RES 20         /* Response to unknown AT command event */
 #define BTA_AG_MULTI_CALL_RES 21   /* SLC at three way call */
 #define BTA_AG_BIND_RES 22         /* Activate/Deactivate HF indicator */
+#define BTA_AG_IND_RES_ON_DEMAND 33 /* Update an indicator value forcible */
 
 typedef uint8_t tBTA_AG_RES;
 
@@ -268,7 +277,7 @@
 } tBTA_AG_IND;
 
 /* data type for BTA_AgResult() */
-typedef struct {
+struct tBTA_AG_RES_DATA {
   char str[BTA_AG_AT_MAX_LEN + 1];
   tBTA_AG_IND ind;
   uint16_t num;
@@ -277,7 +286,8 @@
   uint8_t
       ok_flag; /* Indicates if response is finished, and if error occurred */
   bool state;
-} tBTA_AG_RES_DATA;
+  static const tBTA_AG_RES_DATA kEmpty;
+};
 
 /* AG callback events */
 #define BTA_AG_ENABLE_EVT 0      /* AG enabled */
@@ -313,6 +323,7 @@
 #define BTA_AG_AT_BCS_EVT 27  /* Codec select */
 #define BTA_AG_AT_BIND_EVT 28 /* HF indicator */
 #define BTA_AG_AT_BIEV_EVT 29 /* HF indicator updates from peer */
+#define BTA_AG_AT_BIA_EVT 32  /* AG indicator activation event from peer */
 
 typedef uint8_t tBTA_AG_EVT;
 
@@ -356,7 +367,7 @@
   tBTA_AG_HDR hdr;
   RawAddress bd_addr;
   char str[BTA_AG_AT_MAX_LEN + 1];
-  uint16_t num;
+  uint32_t num;
   uint8_t idx;   /* call number used by CLCC and CHLD */
   uint16_t lidx; /* long index, ex, HF indicator */
 } tBTA_AG_VAL;
@@ -459,7 +470,7 @@
  * Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
  *
  ******************************************************************************/
-tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK* p_cback);
+tBTA_STATUS BTA_AgEnable(tBTA_AG_CBACK* p_cback);
 
 /*******************************************************************************
  *
@@ -471,7 +482,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AgDisable(void);
+void BTA_AgDisable();
 
 /*******************************************************************************
  *
@@ -484,7 +495,8 @@
  *
  ******************************************************************************/
 void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
-                    tBTA_AG_FEAT features, const char* p_service_names[],
+                    tBTA_AG_FEAT features,
+                    const std::vector<std::string>& service_names,
                     uint8_t app_id);
 
 /*******************************************************************************
@@ -512,8 +524,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AgOpen(uint16_t handle, const RawAddress& bd_addr, tBTA_SEC sec_mask,
-                tBTA_SERVICE_MASK services);
+void BTA_AgOpen(uint16_t handle, const RawAddress& bd_addr, tBTA_SEC sec_mask);
 
 /*******************************************************************************
  *
@@ -559,15 +570,13 @@
  * Function         BTA_AgResult
  *
  * Description      Send an AT result code to a headset or hands-free device.
- *                  This function is only used when the AG parse mode is set
- *                  to BTA_AG_PARSE.
  *
  *
  * Returns          void
  *
  ******************************************************************************/
 void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
-                  tBTA_AG_RES_DATA* p_data);
+                  const tBTA_AG_RES_DATA& data);
 
 /*******************************************************************************
  *
@@ -585,4 +594,6 @@
 
 void BTA_AgSetScoAllowed(bool value);
 
+void BTA_AgSetActiveDevice(const RawAddress& active_device_addr);
+
 #endif /* BTA_AG_API_H */
diff --git a/bta/include/bta_ag_ci.h b/bta/include/bta_ag_ci.h
deleted file mode 100644
index 01e3870..0000000
--- a/bta/include/bta_ag_ci.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2003-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- *  This is the interface file for audio gateway call-in functions.
- *
- ******************************************************************************/
-#ifndef BTA_AG_CI_H
-#define BTA_AG_CI_H
-
-#include "bta_ag_api.h"
-
-/*****************************************************************************
- *  Function Declarations
- ****************************************************************************/
-/*******************************************************************************
- *
- * Function         bta_ag_ci_rx_write
- *
- * Description      This function is called to send data to the AG when the AG
- *                  is configured for AT command pass-through.  The function
- *                  copies data to an event buffer and sends it.
- *
- * Returns          void
- *
- ******************************************************************************/
-extern void bta_ag_ci_rx_write(uint16_t handle, char* p_data, uint16_t len);
-
-/******************************************************************************
- *
- * Function         bta_ag_ci_slc_ready
- *
- * Description      This function is called to notify AG that SLC is up at
- *                  the application. This funcion is only used when the app
- *                  is running in pass-through mode.
- *
- * Returns          void
- *
- *****************************************************************************/
-extern void bta_ag_ci_slc_ready(uint16_t handle);
-
-/******************************************************************************
- *
- * Function         bta_ag_ci_wbs_command
- *
- * Description      This function is called to notify AG that a WBS command is
- *                  received
- *
- * Returns          void
- *
- *****************************************************************************/
-extern void bta_ag_ci_wbs_command(uint16_t handle, char* p_data, uint16_t len);
-
-#endif /* BTA_AG_CI_H */
diff --git a/bta/include/bta_ag_co.h b/bta/include/bta_ag_co.h
deleted file mode 100644
index aed7def..0000000
--- a/bta/include/bta_ag_co.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2003-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- *  This is the interface file for audio gateway call-out functions.
- *
- ******************************************************************************/
-#ifndef BTA_AG_CO_H
-#define BTA_AG_CO_H
-
-#include "bta_ag_api.h"
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_init
- *
- * Description      This callout function is executed by AG when it is
- *                  started by calling BTA_AgEnable().  This function can be
- *                  used by the phone to initialize audio paths or for other
- *                  initialization purposes.
- *
- *
- * Returns          Void.
- *
- ******************************************************************************/
-extern void bta_ag_co_init(void);
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_data_open
- *
- * Description      This function is executed by AG when a service level
- *                  connection
- *                  is opened.  The phone can use this function to set
- *                  up data paths or perform any required initialization or
- *                  set up particular to the connected service.
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-extern void bta_ag_co_data_open(uint16_t handle, tBTA_SERVICE_ID service);
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_data_close
- *
- * Description      This function is called by AG when a service level
- *                  connection is closed
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-extern void bta_ag_co_data_close(uint16_t handle);
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_tx_write
- *
- * Description      This function is called by the AG to send data to the
- *                  phone when the AG is configured for AT command pass-through.
- *                  The implementation of this function must copy the data to
- *                  the phone's memory.
- *
- * Returns          void
- *
- ******************************************************************************/
-extern void bta_ag_co_tx_write(uint16_t handle, uint8_t* p_data, uint16_t len);
-
-#endif /* BTA_AG_CO_H */
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 814038c..9d4693e 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2014 Broadcom Corporation
+ *  Copyright 2003-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -143,7 +143,7 @@
 typedef struct {
   tBTA_SERVICE_MASK srvc_mask;
   uint8_t num_uuid;
-  tBT_UUID* p_uuid;
+  bluetooth::Uuid* p_uuid;
 } tBTA_SERVICE_MASK_EXT;
 
 /* Security Setting Mask */
@@ -291,10 +291,6 @@
                       */
   tBTA_DM_INQ_FILT filter_type; /* Filter condition type. */
   tBTA_DM_INQ_COND filter_cond; /* Filter condition data. */
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  uint8_t intl_duration
-      [4]; /*duration array storing the interleave scan's time portions*/
-#endif
 } tBTA_DM_INQ;
 
 typedef struct {
@@ -762,7 +758,7 @@
   uint32_t raw_data_size;      /* size of raw data */
   tBT_DEVICE_TYPE device_type; /* device type in case it is BLE device */
   uint32_t num_uuids;
-  uint8_t* p_uuid_list;
+  bluetooth::Uuid* p_uuid_list;
   tBTA_STATUS result;
 } tBTA_DM_DISC_RES;
 
@@ -770,7 +766,7 @@
 typedef struct {
   RawAddress bd_addr; /* BD address peer device. */
   BD_NAME bd_name;  /* Name of peer device. */
-  tBT_UUID service; /* GATT based Services UUID found on peer device. */
+  bluetooth::Uuid service; /* GATT based Services UUID found on peer device. */
 } tBTA_DM_DISC_BLE_RES;
 
 /* Union of all search callback structures */
@@ -1073,7 +1069,7 @@
  * Returns          tBTA_STATUS
  *
  ******************************************************************************/
-extern tBTA_STATUS BTA_EnableTestMode(void);
+extern void BTA_EnableTestMode(void);
 
 /*******************************************************************************
  *
@@ -1172,7 +1168,8 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void BTA_DmDiscoverUUID(const RawAddress& bd_addr, tSDP_UUID* uuid,
+extern void BTA_DmDiscoverUUID(const RawAddress& bd_addr,
+                               const bluetooth::Uuid& uuid,
                                tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
 
 /*******************************************************************************
@@ -1363,59 +1360,6 @@
 extern void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev,
                            tBTA_TRANSPORT transport);
 
-/*******************************************************************************
- *
- * Function         bta_dmexecutecallback
- *
- * Description      This function will request BTA to execute a call back in the
- *                  context of BTU task.
- *                  This API was named in lower case because it is only intended
- *                  for the internal customers(like BTIF).
- *
- * Returns          void
- *
- ******************************************************************************/
-extern void bta_dmexecutecallback(tBTA_DM_EXEC_CBACK* p_callback,
-                                  void* p_param);
-
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-/*******************************************************************************
- *
- * Function         BTA_DmPcmInitSamples
- *
- * Description      initialize the down sample converter.
- *
- *                  src_sps: original samples per second (source audio data)
- *                            (ex. 44100, 48000)
- *                  bits: number of bits per pcm sample (16)
- *                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
- *
- * Returns          none
- *
- ******************************************************************************/
-extern void BTA_DmPcmInitSamples(uint32_t src_sps, uint32_t bits,
-                                 uint32_t n_channels);
-
-/*******************************************************************************
- * Function         BTA_DmPcmResample
- *
- * Description      Down sampling utility to convert higher sampling rate into
- *                  8K/16bits
- *                  PCM samples.
- *
- * Parameters       p_src: pointer to the buffer where the original sampling PCM
- *                              are stored.
- *                  in_bytes:  Length of the input PCM sample buffer in byte.
- *                  p_dst: pointer to the buffer which is to be used to store
- *                         the converted PCM samples.
- *
- *
- * Returns          int32_t: number of samples converted.
- *
- ******************************************************************************/
-extern int32_t BTA_DmPcmResample(void* p_src, uint32_t in_bytes, void* p_dst);
-#endif
-
 /* BLE related API functions */
 /*******************************************************************************
  *
@@ -1704,7 +1648,9 @@
  ******************************************************************************/
 extern void BTA_DmBleUpdateConnectionParams(const RawAddress& bd_addr,
                                             uint16_t min_int, uint16_t max_int,
-                                            uint16_t latency, uint16_t timeout);
+                                            uint16_t latency, uint16_t timeout,
+                                            uint16_t min_ce_len,
+                                            uint16_t max_ce_len);
 
 /*******************************************************************************
  *
diff --git a/bta/include/bta_ar_api.h b/bta/include/bta_ar_api.h
index ffa9c19..b2a8753 100644
--- a/bta/include/bta_ar_api.h
+++ b/bta/include/bta_ar_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -60,7 +60,7 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void bta_ar_reg_avdt(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback,
+extern void bta_ar_reg_avdt(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback,
                             tBTA_SYS_ID sys_id);
 
 /*******************************************************************************
@@ -86,7 +86,8 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, const RawAddress& bd_addr);
+extern void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, const RawAddress& bd_addr,
+                             uint8_t scb_index);
 
 /*******************************************************************************
  *
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
index 9add76b..4c0539e 100644
--- a/bta/include/bta_av_api.h
+++ b/bta/include/bta_av_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -91,9 +91,9 @@
 /* handle index to mask */
 #define BTA_AV_HNDL_TO_MSK(h) ((uint8_t)(1 << (h)))
 
-/* maximum number of streams created: 1 for audio, 1 for video */
+/* maximum number of streams created */
 #ifndef BTA_AV_NUM_STRS
-#define BTA_AV_NUM_STRS 2
+#define BTA_AV_NUM_STRS 6
 #endif
 
 #ifndef BTA_AV_MAX_A2DP_MTU
@@ -101,109 +101,19 @@
 #define BTA_AV_MAX_A2DP_MTU 1008
 #endif
 
-#ifndef BTA_AV_MAX_VDP_MTU
-#define BTA_AV_MAX_VDP_MTU 1008
-#endif
-
 /* operation id list for BTA_AvRemoteCmd */
-#define BTA_AV_RC_SELECT AVRC_ID_SELECT         /* select */
-#define BTA_AV_RC_UP AVRC_ID_UP                 /* up */
-#define BTA_AV_RC_DOWN AVRC_ID_DOWN             /* down */
-#define BTA_AV_RC_LEFT AVRC_ID_LEFT             /* left */
-#define BTA_AV_RC_RIGHT AVRC_ID_RIGHT           /* right */
-#define BTA_AV_RC_RIGHT_UP AVRC_ID_RIGHT_UP     /* right-up */
-#define BTA_AV_RC_RIGHT_DOWN AVRC_ID_RIGHT_DOWN /* right-down */
-#define BTA_AV_RC_LEFT_UP AVRC_ID_LEFT_UP       /* left-up */
-#define BTA_AV_RC_LEFT_DOWN AVRC_ID_LEFT_DOWN   /* left-down */
-#define BTA_AV_RC_ROOT_MENU AVRC_ID_ROOT_MENU   /* root menu */
-#define BTA_AV_RC_SETUP_MENU AVRC_ID_SETUP_MENU /* setup menu */
-#define BTA_AV_RC_CONT_MENU AVRC_ID_CONT_MENU   /* contents menu */
-#define BTA_AV_RC_FAV_MENU AVRC_ID_FAV_MENU     /* favorite menu */
-#define BTA_AV_RC_EXIT AVRC_ID_EXIT             /* exit */
-#define BTA_AV_RC_0 AVRC_ID_0                   /* 0 */
-#define BTA_AV_RC_1 AVRC_ID_1                   /* 1 */
-#define BTA_AV_RC_2 AVRC_ID_2                   /* 2 */
-#define BTA_AV_RC_3 AVRC_ID_3                   /* 3 */
-#define BTA_AV_RC_4 AVRC_ID_4                   /* 4 */
-#define BTA_AV_RC_5 AVRC_ID_5                   /* 5 */
-#define BTA_AV_RC_6 AVRC_ID_6                   /* 6 */
-#define BTA_AV_RC_7 AVRC_ID_7                   /* 7 */
-#define BTA_AV_RC_8 AVRC_ID_8                   /* 8 */
-#define BTA_AV_RC_9 AVRC_ID_9                   /* 9 */
-#define BTA_AV_RC_DOT AVRC_ID_DOT               /* dot */
-#define BTA_AV_RC_ENTER AVRC_ID_ENTER           /* enter */
-#define BTA_AV_RC_CLEAR AVRC_ID_CLEAR           /* clear */
-#define BTA_AV_RC_CHAN_UP AVRC_ID_CHAN_UP       /* channel up */
-#define BTA_AV_RC_CHAN_DOWN AVRC_ID_CHAN_DOWN   /* channel down */
-#define BTA_AV_RC_PREV_CHAN AVRC_ID_PREV_CHAN   /* previous channel */
-#define BTA_AV_RC_SOUND_SEL AVRC_ID_SOUND_SEL   /* sound select */
-#define BTA_AV_RC_INPUT_SEL AVRC_ID_INPUT_SEL   /* input select */
-#define BTA_AV_RC_DISP_INFO AVRC_ID_DISP_INFO   /* display information */
-#define BTA_AV_RC_HELP AVRC_ID_HELP             /* help */
-#define BTA_AV_RC_PAGE_UP AVRC_ID_PAGE_UP       /* page up */
-#define BTA_AV_RC_PAGE_DOWN AVRC_ID_PAGE_DOWN   /* page down */
-#define BTA_AV_RC_POWER AVRC_ID_POWER           /* power */
-#define BTA_AV_RC_VOL_UP AVRC_ID_VOL_UP         /* volume up */
-#define BTA_AV_RC_VOL_DOWN AVRC_ID_VOL_DOWN     /* volume down */
-#define BTA_AV_RC_MUTE AVRC_ID_MUTE             /* mute */
-#define BTA_AV_RC_PLAY AVRC_ID_PLAY             /* play */
-#define BTA_AV_RC_STOP AVRC_ID_STOP             /* stop */
-#define BTA_AV_RC_PAUSE AVRC_ID_PAUSE           /* pause */
-#define BTA_AV_RC_RECORD AVRC_ID_RECORD         /* record */
-#define BTA_AV_RC_REWIND AVRC_ID_REWIND         /* rewind */
-#define BTA_AV_RC_FAST_FOR AVRC_ID_FAST_FOR     /* fast forward */
-#define BTA_AV_RC_EJECT AVRC_ID_EJECT           /* eject */
-#define BTA_AV_RC_FORWARD AVRC_ID_FORWARD       /* forward */
-#define BTA_AV_RC_BACKWARD AVRC_ID_BACKWARD     /* backward */
-#define BTA_AV_RC_ANGLE AVRC_ID_ANGLE           /* angle */
-#define BTA_AV_RC_SUBPICT AVRC_ID_SUBPICT       /* subpicture */
-#define BTA_AV_RC_F1 AVRC_ID_F1                 /* F1 */
-#define BTA_AV_RC_F2 AVRC_ID_F2                 /* F2 */
-#define BTA_AV_RC_F3 AVRC_ID_F3                 /* F3 */
-#define BTA_AV_RC_F4 AVRC_ID_F4                 /* F4 */
-#define BTA_AV_RC_F5 AVRC_ID_F5                 /* F5 */
-#define BTA_AV_VENDOR AVRC_ID_VENDOR            /* vendor unique */
-
 typedef uint8_t tBTA_AV_RC;
 
 /* state flag for pass through command */
-#define BTA_AV_STATE_PRESS AVRC_STATE_PRESS     /* key pressed */
-#define BTA_AV_STATE_RELEASE AVRC_STATE_RELEASE /* key released */
-
 typedef uint8_t tBTA_AV_STATE;
 
 /* command codes for BTA_AvVendorCmd */
-#define BTA_AV_CMD_CTRL AVRC_CMD_CTRL
-#define BTA_AV_CMD_STATUS AVRC_CMD_STATUS
-#define BTA_AV_CMD_SPEC_INQ AVRC_CMD_SPEC_INQ
-#define BTA_AV_CMD_NOTIF AVRC_CMD_NOTIF
-#define BTA_AV_CMD_GEN_INQ AVRC_CMD_GEN_INQ
-
 typedef uint8_t tBTA_AV_CMD;
 
 /* response codes for BTA_AvVendorRsp */
-#define BTA_AV_RSP_NOT_IMPL AVRC_RSP_NOT_IMPL
-#define BTA_AV_RSP_ACCEPT AVRC_RSP_ACCEPT
-#define BTA_AV_RSP_REJ AVRC_RSP_REJ
-#define BTA_AV_RSP_IN_TRANS AVRC_RSP_IN_TRANS
-#define BTA_AV_RSP_IMPL_STBL AVRC_RSP_IMPL_STBL
-#define BTA_AV_RSP_CHANGED AVRC_RSP_CHANGED
-#define BTA_AV_RSP_INTERIM AVRC_RSP_INTERIM
-
 typedef uint8_t tBTA_AV_CODE;
 
 /* error codes for BTA_AvProtectRsp */
-#define BTA_AV_ERR_NONE A2DP_SUCCESS /* Success, no error */
-#define BTA_AV_ERR_BAD_STATE \
-  AVDT_ERR_BAD_STATE /* Message cannot be processed in this state */
-#define BTA_AV_ERR_RESOURCE AVDT_ERR_RESOURCE /* Insufficient resources */
-#define BTA_AV_ERR_BAD_CP_TYPE                                               \
-  A2DP_BAD_CP_TYPE /* The requested Content Protection Type is not supported \
-                      */
-#define BTA_AV_ERR_BAD_CP_FORMAT                                             \
-  A2DP_BAD_CP_FORMAT /* The format of Content Protection Data is not correct \
-                        */
-
 typedef uint8_t tBTA_AV_ERR;
 
 /* AV callback events */
@@ -244,6 +154,15 @@
 
 typedef uint8_t tBTA_AV_EVT;
 
+typedef enum {
+  BTA_AV_CODEC_TYPE_UNKNOWN = 0x00,
+  BTA_AV_CODEC_TYPE_SBC = 0x01,
+  BTA_AV_CODEC_TYPE_AAC = 0x02,
+  BTA_AV_CODEC_TYPE_APTX = 0x04,
+  BTA_AV_CODEC_TYPE_APTXHD = 0x08,
+  BTA_AV_CODEC_TYPE_LDAC = 0x10
+} tBTA_AV_CODEC_TYPE;
+
 /* Event associated with BTA_AV_ENABLE_EVT */
 typedef struct { tBTA_AV_FEAT features; } tBTA_AV_ENABLE;
 
@@ -285,7 +204,7 @@
   bool suspending;
 } tBTA_AV_START;
 
-/* data associated with BTA_AV_SUSPEND_EVT */
+/* data associated with BTA_AV_SUSPEND_EVT, BTA_AV_STOP_EVT */
 typedef struct {
   tBTA_AV_CHNL chnl;
   tBTA_AV_HNDL hndl;
@@ -449,10 +368,9 @@
 typedef void(tBTA_AV_SINK_DATA_CBACK)(tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data);
 
 /* type for stream state machine action functions */
-typedef void (*tBTA_AV_ACT)(void* p_cb, void* p_data);
-
-/* type for registering VDP */
-typedef void(tBTA_AV_REG)(tAVDT_CS* p_cs, char* p_service_name, void* p_data);
+struct tBTA_AV_SCB;
+union tBTA_AV_DATA;
+typedef void (*tBTA_AV_ACT)(tBTA_AV_SCB* p_cb, tBTA_AV_DATA* p_data);
 
 /* AV configuration structure */
 typedef struct {
@@ -466,8 +384,6 @@
   const uint16_t*
       p_audio_flush_to;    /* AVDTP audio transport channel flush timeout */
   uint16_t audio_mqs;      /* AVDTP audio channel max data queue size */
-  uint16_t video_mtu;      /* AVDTP video transport channel MTU at L2CAP */
-  uint16_t video_flush_to; /* AVDTP video transport channel flush timeout */
   bool avrc_group;     /* true, to accept AVRC 1.3 group nevigation command */
   uint8_t num_co_ids;  /* company id count in p_meta_co_ids */
   uint8_t num_evt_ids; /* event id count in p_meta_evt_ids */
@@ -477,8 +393,7 @@
       p_meta_co_ids; /* the metadata Get Capabilities response for company id */
   const uint8_t* p_meta_evt_ids; /* the the metadata Get Capabilities response
                                     for event id */
-  const tBTA_AV_ACT* p_act_tbl;  /* the action function table for VDP stream */
-  tBTA_AV_REG* p_reg;            /* action function to register VDP */
+  const tBTA_AV_ACT* p_act_tbl;  /* action function table for audio stream */
   char avrc_controller_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP controller
                                                       name */
   char avrc_target_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP target name*/
@@ -589,7 +504,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AvStart(void);
+void BTA_AvStart(tBTA_AV_HNDL handle);
 
 /*******************************************************************************
  *
@@ -602,7 +517,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AvStop(bool suspend);
+void BTA_AvStop(tBTA_AV_HNDL handle, bool suspend);
 
 /*******************************************************************************
  *
@@ -788,4 +703,23 @@
  ******************************************************************************/
 void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status);
 
+/**
+ * Obtain the Channel Index for a peer.
+ * If the peer already has associated internal state, the corresponding
+ * Channel Index for that state is returned. Otherwise, the Channel Index
+ * for unused internal state is returned instead.
+ *
+ * @param peer_address the peer address
+ * @return the peer Channel Index index if obtained, otherwise -1
+ */
+int BTA_AvObtainPeerChannelIndex(const RawAddress& peer_address);
+
+/**
+ * Dump debug-related information for the BTA AV module.
+ *
+ * @param fd the file descriptor to use for writing the ASCII formatted
+ * information
+ */
+void bta_debug_av_dump(int fd);
+
 #endif /* BTA_AV_API_H */
diff --git a/bta/include/bta_av_ci.h b/bta/include/bta_av_ci.h
index 3b68f05..07b59e6 100644
--- a/bta/include/bta_av_ci.h
+++ b/bta/include/bta_av_ci.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
  *
  * Description      This function sends an event to the AV indicating that
  *                  the phone has audio stream data ready to send and AV
- *                  should call bta_av_co_audio_src_data_path().
+ *                  should call bta_av_co_audio_source_data_path().
  *
  * Returns          void
  *
@@ -55,7 +55,7 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, uint8_t err_code,
+extern void bta_av_ci_setconfig(tBTA_AV_HNDL bta_av_handle, uint8_t err_code,
                                 uint8_t category, uint8_t num_seid,
                                 uint8_t* p_seid, bool recfg_needed,
                                 uint8_t avdt_handle);
diff --git a/bta/include/bta_av_co.h b/bta/include/bta_av_co.h
index 0e71ac2..f83ff23 100644
--- a/bta/include/bta_av_co.h
+++ b/bta/include/bta_av_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@
  *
  ******************************************************************************/
 bool bta_av_co_audio_init(btav_a2dp_codec_index_t codec_index,
-                          tAVDT_CFG* p_cfg);
+                          AvdtpSepConfig* p_cfg);
 
 /*******************************************************************************
  *
@@ -59,9 +59,10 @@
  * Returns          void.
  *
  ******************************************************************************/
-void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, uint8_t num_seps,
-                              uint8_t num_snk, uint8_t num_src,
-                              const RawAddress& addr, uint16_t uuid_local);
+void bta_av_co_audio_disc_res(tBTA_AV_HNDL bta_av_handle,
+                              const RawAddress& peer_address, uint8_t num_seps,
+                              uint8_t num_sinks, uint8_t num_sources,
+                              uint16_t uuid_local);
 
 /*******************************************************************************
  *
@@ -75,7 +76,9 @@
  * Returns          Stream codec and content protection configuration info.
  *
  ******************************************************************************/
-tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL bta_av_handle,
+                                       const RawAddress& peer_address,
+                                       uint8_t* p_codec_info,
                                        uint8_t* p_sep_info_idx, uint8_t seid,
                                        uint8_t* p_num_protect,
                                        uint8_t* p_protect_info);
@@ -92,8 +95,9 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
-                               uint8_t seid, const RawAddress& addr,
+void bta_av_co_audio_setconfig(tBTA_AV_HNDL bta_av_handle,
+                               const RawAddress& peer_address,
+                               const uint8_t* p_codec_info, uint8_t seid,
                                uint8_t num_protect,
                                const uint8_t* p_protect_info,
                                uint8_t t_local_sep, uint8_t avdt_handle);
@@ -111,7 +115,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_open(tBTA_AV_HNDL hndl, uint16_t mtu);
+void bta_av_co_audio_open(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address, uint16_t mtu);
 
 /*******************************************************************************
  *
@@ -127,7 +132,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_close(tBTA_AV_HNDL hndl);
+void bta_av_co_audio_close(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address);
 
 /*******************************************************************************
  *
@@ -140,8 +146,9 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_start(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
-                           bool* p_no_rtp_hdr);
+void bta_av_co_audio_start(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address,
+                           const uint8_t* p_codec_info, bool* p_no_rtp_header);
 
 /*******************************************************************************
  *
@@ -154,11 +161,12 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_stop(tBTA_AV_HNDL hndl);
+void bta_av_co_audio_stop(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address);
 
 /*******************************************************************************
  *
- * Function         bta_av_co_audio_src_data_path
+ * Function         bta_av_co_audio_source_data_path
  *
  * Description      This function is called to get the next data buffer from
  *                  the audio codec
@@ -167,14 +175,14 @@
  *                  Otherwise, a buffer (BT_HDR*) containing the audio data.
  *
  ******************************************************************************/
-void* bta_av_co_audio_src_data_path(const uint8_t* p_codec_info,
-                                    uint32_t* p_timestamp);
+BT_HDR* bta_av_co_audio_source_data_path(const uint8_t* p_codec_info,
+                                         uint32_t* p_timestamp);
 
 /*******************************************************************************
  *
  * Function         bta_av_co_audio_drop
  *
- * Description      An Audio packet is dropped. .
+ * Description      An Audio packet is dropped.
  *                  It's very likely that the connected headset with this handle
  *                  is moved far away. The implementation may want to reduce
  *                  the encoder bit rate setting to reduce the packet size.
@@ -182,7 +190,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_drop(tBTA_AV_HNDL hndl);
+void bta_av_co_audio_drop(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address);
 
 /*******************************************************************************
  *
@@ -196,7 +205,8 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, uint16_t delay);
+void bta_av_co_audio_delay(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address, uint16_t delay);
 
 /*******************************************************************************
  *
@@ -211,6 +221,18 @@
  * Returns          void
  *
  ******************************************************************************/
-void bta_av_co_audio_update_mtu(tBTA_AV_HNDL hndl, uint16_t mtu);
+void bta_av_co_audio_update_mtu(tBTA_AV_HNDL bta_av_handle,
+                                const RawAddress& peer_address, uint16_t mtu);
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_content_protect_is_active
+ **
+ ** Description     Get the current configuration of content protection
+ **
+ ** Returns          TRUE if the current streaming has CP, FALSE otherwise
+ **
+ ******************************************************************************/
+bool bta_av_co_content_protect_is_active(const RawAddress& peer_address);
 
 #endif /* BTA_AV_CO_H */
diff --git a/bta/include/bta_closure_api.h b/bta/include/bta_closure_api.h
index 8c4e11a..a4c0188 100644
--- a/bta/include/bta_closure_api.h
+++ b/bta/include/bta_closure_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -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_dm_api.h b/bta/include/bta_dm_api.h
index 76cb618..8fdff76 100644
--- a/bta/include/bta_dm_api.h
+++ b/bta/include/bta_dm_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_dm_ci.h b/bta/include/bta_dm_ci.h
index a517da5..dbbace6 100644
--- a/bta/include/bta_dm_ci.h
+++ b/bta/include/bta_dm_ci.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_dm_co.h b/bta/include/bta_dm_co.h
index 80e99c4..ddb9d22 100644
--- a/bta/include/bta_dm_co.h
+++ b/bta/include/bta_dm_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 8034dc7..4dcc76a 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2013 Broadcom Corporation
+ *  Copyright 2003-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,13 +27,10 @@
 
 #include "bta_api.h"
 #include "gatt_api.h"
-#include "osi/include/list.h"
 
 #include <base/callback_forward.h>
 #include <vector>
 
-using std::vector;
-
 #ifndef BTA_GATT_DEBUG
 #define BTA_GATT_DEBUG false
 #endif
@@ -46,65 +43,10 @@
  **************************/
 /* GATT ID */
 typedef struct {
-  tBT_UUID uuid;   /* uuid of the attribute */
-  uint8_t inst_id; /* instance ID */
+  bluetooth::Uuid uuid; /* uuid of the attribute */
+  uint8_t inst_id;      /* instance ID */
 } __attribute__((packed)) tBTA_GATT_ID;
 
-/* Success code and error codes */
-#define BTA_GATT_OK GATT_SUCCESS
-#define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE             /* 0x0001 */
-#define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT           /* 0x0002 */
-#define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT         /* 0x0003 */
-#define BTA_GATT_INVALID_PDU GATT_INVALID_PDU                   /* 0x0004 */
-#define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION /* 0x0005 */
-#define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED       /* 0x0006 */
-#define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET             /* 0x0007 */
-#define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION   /* 0x0008 */
-#define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL             /* 0x0009 */
-#define BTA_GATT_NOT_FOUND GATT_NOT_FOUND                       /* 0x000a */
-#define BTA_GATT_NOT_LONG GATT_NOT_LONG                         /* 0x000b */
-#define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE             /* 0x000c */
-#define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN         /* 0x000d */
-#define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY                 /* 0x000e */
-#define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION         /* 0x000f */
-#define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE     /* 0x0010 */
-#define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE             /* 0x0011 */
-
-#define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES           /* 0x80 */
-#define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR       /* 0x81 */
-#define BTA_GATT_WRONG_STATE GATT_WRONG_STATE             /* 0x82 */
-#define BTA_GATT_DB_FULL GATT_DB_FULL                     /* 0x83 */
-#define BTA_GATT_BUSY GATT_BUSY                           /* 0x84 */
-#define BTA_GATT_ERROR GATT_ERROR                         /* 0x85 */
-#define BTA_GATT_CMD_STARTED GATT_CMD_STARTED             /* 0x86 */
-#define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER /* 0x87 */
-#define BTA_GATT_PENDING GATT_PENDING                     /* 0x88 */
-#define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL                 /* 0x89 */
-#define BTA_GATT_MORE GATT_MORE                           /* 0x8a */
-#define BTA_GATT_INVALID_CFG GATT_INVALID_CFG             /* 0x8b */
-#define BTA_GATT_SERVICE_STARTED GATT_SERVICE_STARTED     /* 0x8c */
-#define BTA_GATT_ENCRYPED_MITM GATT_ENCRYPED_MITM         /* GATT_SUCCESS */
-#define BTA_GATT_ENCRYPED_NO_MITM GATT_ENCRYPED_NO_MITM   /* 0x8d */
-#define BTA_GATT_NOT_ENCRYPTED GATT_NOT_ENCRYPTED         /* 0x8e */
-#define BTA_GATT_CONGESTED GATT_CONGESTED                 /* 0x8f */
-
-#define BTA_GATT_DUP_REG 0x90      /* 0x90 */
-#define BTA_GATT_ALREADY_OPEN 0x91 /* 0x91 */
-#define BTA_GATT_CANCEL 0x92       /* 0x92 */
-
-/* 0xE0 ~ 0xFC reserved for future use */
-#define BTA_GATT_CCC_CFG_ERR                                              \
-  GATT_CCC_CFG_ERR /* 0xFD Client Characteristic Configuration Descriptor \
-                      Improperly Configured */
-#define BTA_GATT_PRC_IN_PROGRESS \
-  GATT_PRC_IN_PROGRESS /* 0xFE Procedure Already in progress */
-#define BTA_GATT_OUT_OF_RANGE \
-  GATT_OUT_OF_RANGE /* 0xFFAttribute value out of range */
-
-typedef uint8_t tBTA_GATT_STATUS;
-
-#define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID
-
 /* Client callback function events */
 #define BTA_GATTC_DEREG_EVT 1        /* GATT client deregistered event */
 #define BTA_GATTC_OPEN_EVT 2         /* GATTC open request status  event */
@@ -124,8 +66,6 @@
 
 typedef uint8_t tBTA_GATTC_EVT;
 
-typedef tGATT_IF tBTA_GATTC_IF;
-
 typedef struct {
   uint16_t unit;  /* as UUIUD defined by SIG */
   uint16_t descr; /* as UUID as defined by SIG */
@@ -134,52 +74,19 @@
   uint8_t name_spc; /* The name space of the description */
 } tBTA_GATT_CHAR_PRES;
 
-#define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000    */
-#define BTA_GATT_CLT_CONFIG_NOTIFICATION \
-  GATT_CLT_CONFIG_NOTIFICATION                                    /* 0x0001 */
-#define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */
-typedef uint16_t tBTA_GATT_CLT_CHAR_CONFIG;
-
-/* characteristic descriptor: server configuration value
-*/
-#define BTA_GATT_SVR_CONFIG_NONE GATT_SVR_CONFIG_NONE           /* 0x0000 */
-#define BTA_GATT_SVR_CONFIG_BROADCAST GATT_SVR_CONFIG_BROADCAST /*  0x0001 */
-typedef uint16_t tBTA_GATT_SVR_CHAR_CONFIG;
-
 /* Characteristic Aggregate Format attribute value
-*/
+ */
 #define BTA_GATT_AGGR_HANDLE_NUM_MAX 10
 typedef struct {
   uint8_t num_handle;
   uint16_t handle_list[BTA_GATT_AGGR_HANDLE_NUM_MAX];
 } tBTA_GATT_CHAR_AGGRE;
-typedef tGATT_VALID_RANGE tBTA_GATT_VALID_RANGE;
 
 typedef struct {
   uint16_t len;
   uint8_t* p_value;
 } tBTA_GATT_UNFMT;
 
-#define BTA_GATT_MAX_ATTR_LEN GATT_MAX_ATTR_LEN
-
-#define BTA_GATTC_TYPE_WRITE GATT_WRITE
-#define BTA_GATTC_TYPE_WRITE_NO_RSP GATT_WRITE_NO_RSP
-typedef uint8_t tBTA_GATTC_WRITE_TYPE;
-
-#define BTA_GATT_CONN_UNKNOWN 0
-#define BTA_GATT_CONN_L2C_FAILURE \
-  GATT_CONN_L2C_FAILURE /* general l2cap resource failure */
-#define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT /* 0x08 connection timeout  */
-#define BTA_GATT_CONN_TERMINATE_PEER_USER \
-  GATT_CONN_TERMINATE_PEER_USER /* 0x13 connection terminate by peer user  */
-#define BTA_GATT_CONN_TERMINATE_LOCAL_HOST \
-  GATT_CONN_TERMINATE_LOCAL_HOST /* 0x16 connectionterminated by local host */
-#define BTA_GATT_CONN_FAIL_ESTABLISH \
-  GATT_CONN_FAIL_ESTABLISH /* 0x03E connection fail to establish  */
-#define BTA_GATT_CONN_LMP_TIMEOUT \
-  GATT_CONN_LMP_TIMEOUT /* 0x22 connection fail for LMP response tout */
-#define BTA_GATT_CONN_CANCEL \
-  GATT_CONN_CANCEL                /* 0x0100 L2CAP connection cancelled  */
 #define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel  */
 typedef uint16_t tBTA_GATT_REASON;
 
@@ -190,17 +97,6 @@
   uint16_t handles[BTA_GATTC_MULTI_MAX];
 } tBTA_GATTC_MULTI;
 
-#define BTA_GATT_AUTH_REQ_NONE GATT_AUTH_REQ_NONE
-#define BTA_GATT_AUTH_REQ_NO_MITM \
-  GATT_AUTH_REQ_NO_MITM /* unauthenticated encryption */
-#define BTA_GATT_AUTH_REQ_MITM                   \
-  GATT_AUTH_REQ_MITM /* authenticated encryption \
-                        */
-#define BTA_GATT_AUTH_REQ_SIGNED_NO_MITM GATT_AUTH_REQ_SIGNED_NO_MITM
-#define BTA_GATT_AUTH_REQ_SIGNED_MITM GATT_AUTH_REQ_SIGNED_MITM
-
-typedef tGATT_AUTH_REQ tBTA_GATT_AUTH_REQ;
-
 enum {
   BTA_GATTC_ATTR_TYPE_INCL_SRVC,
   BTA_GATTC_ATTR_TYPE_CHAR,
@@ -210,7 +106,7 @@
 typedef uint8_t tBTA_GATTC_ATTR_TYPE;
 
 typedef struct {
-  tBT_UUID uuid;
+  bluetooth::Uuid uuid;
   uint16_t s_handle;
   uint16_t e_handle; /* used for service only */
   uint8_t attr_type;
@@ -222,33 +118,32 @@
 
 /* callback data structure */
 typedef struct {
-  tBTA_GATT_STATUS status;
-  tBTA_GATTC_IF client_if;
-  tBT_UUID app_uuid;
+  tGATT_STATUS status;
+  tGATT_IF client_if;
 } tBTA_GATTC_REG;
 
 typedef struct {
   uint16_t conn_id;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   uint16_t handle;
   uint16_t len;
-  uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+  uint8_t value[GATT_MAX_ATTR_LEN];
 } tBTA_GATTC_READ;
 
 typedef struct {
   uint16_t conn_id;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   uint16_t handle;
 } tBTA_GATTC_WRITE;
 
 typedef struct {
   uint16_t conn_id;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTC_EXEC_CMPL;
 
 typedef struct {
   uint16_t conn_id;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTC_SEARCH_CMPL;
 
 typedef struct {
@@ -258,23 +153,23 @@
 
 typedef struct {
   uint16_t conn_id;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   uint16_t mtu;
 } tBTA_GATTC_CFG_MTU;
 
 typedef struct {
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   uint16_t conn_id;
-  tBTA_GATTC_IF client_if;
+  tGATT_IF client_if;
   RawAddress remote_bda;
   tBTA_TRANSPORT transport;
   uint16_t mtu;
 } tBTA_GATTC_OPEN;
 
 typedef struct {
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   uint16_t conn_id;
-  tBTA_GATTC_IF client_if;
+  tGATT_IF client_if;
   RawAddress remote_bda;
   tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
                               event is reported */
@@ -285,7 +180,7 @@
   RawAddress bda;
   uint16_t handle;
   uint16_t len;
-  uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+  uint8_t value[GATT_MAX_ATTR_LEN];
   bool is_notify;
 } tBTA_GATTC_NOTIFY;
 
@@ -295,36 +190,36 @@
 } tBTA_GATTC_CONGEST;
 
 typedef struct {
-  tBTA_GATT_STATUS status;
-  tBTA_GATTC_IF client_if;
+  tGATT_STATUS status;
+  tGATT_IF client_if;
   uint16_t conn_id;
   RawAddress remote_bda;
 } tBTA_GATTC_OPEN_CLOSE;
 
 typedef struct {
-  tBTA_GATTC_IF client_if;
+  tGATT_IF client_if;
   RawAddress remote_bda;
 } tBTA_GATTC_ENC_CMPL_CB;
 
 typedef struct {
-  tBTA_GATTC_IF server_if;
+  tGATT_IF server_if;
   uint16_t conn_id;
   uint8_t tx_phy;
   uint8_t rx_phy;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTC_PHY_UPDATE;
 
 typedef struct {
-  tBTA_GATTC_IF server_if;
+  tGATT_IF server_if;
   uint16_t conn_id;
   uint16_t interval;
   uint16_t latency;
   uint16_t timeout;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTC_CONN_UPDATE;
 
 typedef union {
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 
   tBTA_GATTC_SEARCH_CMPL search_cmpl; /* discovery complete */
   tBTA_GATTC_SRVC_RES srvc_res;       /* discovery result */
@@ -344,7 +239,7 @@
 } tBTA_GATTC;
 
 /* GATTC enable callback function */
-typedef void(tBTA_GATTC_ENB_CBACK)(tBTA_GATT_STATUS status);
+typedef void(tBTA_GATTC_ENB_CBACK)(tGATT_STATUS status);
 
 /* Client callback function */
 typedef void(tBTA_GATTC_CBACK)(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
@@ -374,130 +269,61 @@
 #define BTA_GATTS_CONN_UPDATE_EVT 22
 
 typedef uint8_t tBTA_GATTS_EVT;
-typedef tGATT_IF tBTA_GATTS_IF;
-
-/* Attribute permissions
-*/
-#define BTA_GATT_PERM_READ GATT_PERM_READ /* bit 0 -  0x0001 */
-#define BTA_GATT_PERM_READ_ENCRYPTED \
-  GATT_PERM_READ_ENCRYPTED /* bit 1 -  0x0002 */
-#define BTA_GATT_PERM_READ_ENC_MITM \
-  GATT_PERM_READ_ENC_MITM                   /* bit 2 -  0x0004 */
-#define BTA_GATT_PERM_WRITE GATT_PERM_WRITE /* bit 4 -  0x0010 */
-#define BTA_GATT_PERM_WRITE_ENCRYPTED \
-  GATT_PERM_WRITE_ENCRYPTED /* bit 5 -  0x0020 */
-#define BTA_GATT_PERM_WRITE_ENC_MITM \
-  GATT_PERM_WRITE_ENC_MITM /* bit 6 -  0x0040 */
-#define BTA_GATT_PERM_WRITE_SIGNED          \
-  GATT_PERM_WRITE_SIGNED /* bit 7 -  0x0080 \
-                            */
-#define BTA_GATT_PERM_WRITE_SIGNED_MITM \
-  GATT_PERM_WRITE_SIGNED_MITM /* bit 8 -  0x0100 */
-typedef uint16_t tBTA_GATT_PERM;
 
 #define BTA_GATTS_INVALID_APP 0xff
 
 #define BTA_GATTS_INVALID_IF 0
 
-/* definition of characteristic properties */
-#define BTA_GATT_CHAR_PROP_BIT_BROADCAST                                    \
-  GATT_CHAR_PROP_BIT_BROADCAST                                      /* 0x01 \
-                                                                       */
-#define BTA_GATT_CHAR_PROP_BIT_READ GATT_CHAR_PROP_BIT_READ         /* 0x02 */
-#define BTA_GATT_CHAR_PROP_BIT_WRITE_NR GATT_CHAR_PROP_BIT_WRITE_NR /* 0x04 */
-#define BTA_GATT_CHAR_PROP_BIT_WRITE GATT_CHAR_PROP_BIT_WRITE       /* 0x08 */
-#define BTA_GATT_CHAR_PROP_BIT_NOTIFY GATT_CHAR_PROP_BIT_NOTIFY     /* 0x10 */
-#define BTA_GATT_CHAR_PROP_BIT_INDICATE GATT_CHAR_PROP_BIT_INDICATE /* 0x20 */
-#define BTA_GATT_CHAR_PROP_BIT_AUTH GATT_CHAR_PROP_BIT_AUTH         /* 0x40 */
-#define BTA_GATT_CHAR_PROP_BIT_EXT_PROP GATT_CHAR_PROP_BIT_EXT_PROP /* 0x80 */
-typedef uint8_t tBTA_GATT_CHAR_PROP;
-
 #ifndef BTA_GATTC_CHAR_DESCR_MAX
 #define BTA_GATTC_CHAR_DESCR_MAX 7
 #endif
 
 /***********************  NV callback Data Definitions   **********************
-*/
+ */
 typedef struct {
-  tBT_UUID app_uuid128;
-  tBT_UUID svc_uuid;
+  bluetooth::Uuid app_uuid128;
+  bluetooth::Uuid svc_uuid;
   uint16_t svc_inst;
   uint16_t s_handle;
   uint16_t e_handle;
   bool is_primary; /* primary service or secondary */
 } tBTA_GATTS_HNDL_RANGE;
 
-#define BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT GATTS_SRV_CHG_CMD_ADD_CLIENT
-#define BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT GATTS_SRV_CHG_CMD_UPDATE_CLIENT
-#define BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT GATTS_SRV_CHG_CMD_REMOVE_CLIENT
-#define BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS GATTS_SRV_CHG_CMD_READ_NUM_CLENTS
-#define BTA_GATTS_SRV_CHG_CMD_READ_CLENT GATTS_SRV_CHG_CMD_READ_CLENT
-typedef tGATTS_SRV_CHG_CMD tBTA_GATTS_SRV_CHG_CMD;
-
-typedef tGATTS_SRV_CHG tBTA_GATTS_SRV_CHG;
-typedef tGATTS_SRV_CHG_REQ tBTA_GATTS_SRV_CHG_REQ;
-typedef tGATTS_SRV_CHG_RSP tBTA_GATTS_SRV_CHG_RSP;
-
-#define BTA_GATT_TRANSPORT_LE GATT_TRANSPORT_LE
-#define BTA_GATT_TRANSPORT_BR_EDR GATT_TRANSPORT_BR_EDR
-#define BTA_GATT_TRANSPORT_LE_BR_EDR GATT_TRANSPORT_LE_BR_EDR
-typedef uint8_t tBTA_GATT_TRANSPORT;
-
-/* attribute value */
-typedef tGATT_VALUE tBTA_GATT_VALUE;
-
-/* attribute response data */
-typedef tGATTS_RSP tBTA_GATTS_RSP;
-
-/* attribute request data from the client */
-#define BTA_GATT_PREP_WRITE_CANCEL 0x00
-#define BTA_GATT_PREP_WRITE_EXEC 0x01
-typedef tGATT_EXEC_FLAG tBTA_GATT_EXEC_FLAG;
-
-/* read request always based on UUID */
-typedef tGATT_READ_REQ tTA_GBATT_READ_REQ;
-
-/* write request data */
-typedef tGATT_WRITE_REQ tBTA_GATT_WRITE_REQ;
-
-/* callback data for server access request from client */
-typedef tGATTS_DATA tBTA_GATTS_REQ_DATA;
-
 typedef struct {
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
   RawAddress remote_bda;
   uint32_t trans_id;
   uint16_t conn_id;
-  tBTA_GATTS_REQ_DATA* p_data;
+  tGATTS_DATA* p_data;
 } tBTA_GATTS_REQ;
 
 typedef struct {
-  tBTA_GATTS_IF server_if;
-  tBTA_GATT_STATUS status;
-  tBT_UUID uuid;
+  tGATT_IF server_if;
+  tGATT_STATUS status;
+  bluetooth::Uuid uuid;
 } tBTA_GATTS_REG_OPER;
 
 typedef struct {
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   uint16_t service_id;
   uint16_t svc_instance;
   bool is_primary;
-  tBTA_GATT_STATUS status;
-  tBT_UUID uuid;
+  tGATT_STATUS status;
+  bluetooth::Uuid uuid;
 } tBTA_GATTS_CREATE;
 
 typedef struct {
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   uint16_t service_id;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTS_SRVC_OPER;
 
 typedef struct {
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   RawAddress remote_bda;
   uint16_t conn_id;
   tBTA_GATT_REASON reason; /* report disconnect reason */
-  tBTA_GATT_TRANSPORT transport;
+  tGATT_TRANSPORT transport;
 } tBTA_GATTS_CONN;
 
 typedef struct {
@@ -507,24 +333,24 @@
 
 typedef struct {
   uint16_t conn_id;        /* connection ID */
-  tBTA_GATT_STATUS status; /* notification/indication status */
+  tGATT_STATUS status;     /* notification/indication status */
 } tBTA_GATTS_CONF;
 
 typedef struct {
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   uint16_t conn_id;
   uint8_t tx_phy;
   uint8_t rx_phy;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTS_PHY_UPDATE;
 
 typedef struct {
-  tBTA_GATTS_IF server_if;
+  tGATT_IF server_if;
   uint16_t conn_id;
   uint16_t interval;
   uint16_t latency;
   uint16_t timeout;
-  tBTA_GATT_STATUS status;
+  tGATT_STATUS status;
 } tBTA_GATTS_CONN_UPDATE;
 
 /* GATTS callback data */
@@ -532,52 +358,56 @@
   tBTA_GATTS_REG_OPER reg_oper;
   tBTA_GATTS_CREATE create;
   tBTA_GATTS_SRVC_OPER srvc_oper;
-  tBTA_GATT_STATUS status; /* BTA_GATTS_LISTEN_EVT */
+  tGATT_STATUS status; /* BTA_GATTS_LISTEN_EVT */
   tBTA_GATTS_REQ req_data;
-  tBTA_GATTS_CONN conn;       /* BTA_GATTS_CONN_EVT */
-  tBTA_GATTS_CONGEST congest; /* BTA_GATTS_CONGEST_EVT callback data */
-  tBTA_GATTS_CONF confirm;    /* BTA_GATTS_CONF_EVT callback data */
+  tBTA_GATTS_CONN conn;             /* BTA_GATTS_CONN_EVT */
+  tBTA_GATTS_CONGEST congest;       /* BTA_GATTS_CONGEST_EVT callback data */
+  tBTA_GATTS_CONF confirm;          /* BTA_GATTS_CONF_EVT callback data */
   tBTA_GATTS_PHY_UPDATE phy_update; /* BTA_GATTS_PHY_UPDATE_EVT callback data */
   tBTA_GATTS_CONN_UPDATE
       conn_update; /* BTA_GATTS_CONN_UPDATE_EVT callback data */
 } tBTA_GATTS;
 
 /* GATTS enable callback function */
-typedef void(tBTA_GATTS_ENB_CBACK)(tBTA_GATT_STATUS status);
+typedef void(tBTA_GATTS_ENB_CBACK)(tGATT_STATUS status);
 
 /* Server callback function */
 typedef void(tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS* p_data);
 
-typedef struct {
-  tBT_UUID uuid;
+struct tBTA_GATTC_CHARACTERISTIC;
+struct tBTA_GATTC_DESCRIPTOR;
+struct tBTA_GATTC_INCLUDED_SVC;
+
+struct tBTA_GATTC_SERVICE {
+  bluetooth::Uuid uuid;
   bool is_primary;
   uint16_t handle;
   uint16_t s_handle;
   uint16_t e_handle;
-  list_t* characteristics; /* list of tBTA_GATTC_CHARACTERISTIC */
-  list_t* included_svc;    /* list of tBTA_GATTC_INCLUDED_SVC */
-} __attribute__((packed, aligned(alignof(tBT_UUID)))) tBTA_GATTC_SERVICE;
+  std::vector<tBTA_GATTC_CHARACTERISTIC> characteristics;
+  std::vector<tBTA_GATTC_INCLUDED_SVC> included_svc;
+};
 
-typedef struct {
-  tBT_UUID uuid;
+struct tBTA_GATTC_CHARACTERISTIC {
+  bluetooth::Uuid uuid;
+  // this is used only during discovery, and not persisted in cache
+  uint16_t declaration_handle;
+  uint16_t value_handle;
+  tGATT_CHAR_PROP properties;
+  std::vector<tBTA_GATTC_DESCRIPTOR> descriptors;
+};
+
+struct tBTA_GATTC_DESCRIPTOR {
+  bluetooth::Uuid uuid;
   uint16_t handle;
-  tBTA_GATT_CHAR_PROP properties;
-  tBTA_GATTC_SERVICE* service; /* owning service*/
-  list_t* descriptors;         /* list of tBTA_GATTC_DESCRIPTOR */
-} __attribute__((packed, aligned(alignof(tBT_UUID)))) tBTA_GATTC_CHARACTERISTIC;
+};
 
-typedef struct {
-  tBT_UUID uuid;
-  uint16_t handle;
-  tBTA_GATTC_CHARACTERISTIC* characteristic; /* owning characteristic */
-} __attribute__((packed)) tBTA_GATTC_DESCRIPTOR;
-
-typedef struct {
-  tBT_UUID uuid;
+struct tBTA_GATTC_INCLUDED_SVC {
+  bluetooth::Uuid uuid;
   uint16_t handle;
   tBTA_GATTC_SERVICE* owning_service; /* owning service*/
   tBTA_GATTC_SERVICE* included_service;
-} __attribute__((packed)) tBTA_GATTC_INCLUDED_SVC;
+};
 
 /*****************************************************************************
  *  External Function Declarations
@@ -623,7 +453,7 @@
  * Returns          None
  *
  ******************************************************************************/
-extern void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if);
+extern void BTA_GATTC_AppDeregister(tGATT_IF client_if);
 
 /*******************************************************************************
  *
@@ -638,13 +468,12 @@
  *                  initiating_phys: LE PHY to use, optional
  *
  ******************************************************************************/
-extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if,
-                           const RawAddress& remote_bda, bool is_direct,
-                           tBTA_GATT_TRANSPORT transport, bool opportunistic);
-extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if,
-                           const RawAddress& remote_bda, bool is_direct,
-                           tBTA_GATT_TRANSPORT transport, bool opportunistic,
-                           uint8_t initiating_phys);
+extern void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda,
+                           bool is_direct, tGATT_TRANSPORT transport,
+                           bool opportunistic);
+extern void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda,
+                           bool is_direct, tGATT_TRANSPORT transport,
+                           bool opportunistic, uint8_t initiating_phys);
 
 /*******************************************************************************
  *
@@ -660,7 +489,7 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if,
+extern void BTA_GATTC_CancelOpen(tGATT_IF client_if,
                                  const RawAddress& remote_bda, bool is_direct);
 
 /*******************************************************************************
@@ -693,14 +522,14 @@
  *
  ******************************************************************************/
 extern void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id,
-                                           tBT_UUID* p_srvc_uuid);
+                                           bluetooth::Uuid* p_srvc_uuid);
 
 /**
  * This function is called to send "Find service by UUID" request. Used only for
  * PTS tests.
  */
 extern void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
-                                            tBT_UUID* p_srvc_uuid);
+                                            const bluetooth::Uuid& p_srvc_uuid);
 
 /*******************************************************************************
  *
@@ -711,10 +540,11 @@
  *
  * Parameters       conn_id: connection ID which identify the server.
  *
- * Returns          returns list_t of tBTA_GATTC_SERVICE or NULL.
+ * Returns          returns list of tBTA_GATTC_SERVICE or NULL.
  *
  ******************************************************************************/
-extern const list_t* BTA_GATTC_GetServices(uint16_t conn_id);
+extern const std::vector<tBTA_GATTC_SERVICE>* BTA_GATTC_GetServices(
+    uint16_t conn_id);
 
 /*******************************************************************************
  *
@@ -748,6 +578,16 @@
 extern const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
                                                             uint16_t handle);
 
+/* Return characteristic that owns descriptor with handle equal to |handle|, or
+ * NULL */
+extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetOwningCharacteristic(
+    uint16_t conn_id, uint16_t handle);
+
+/* Return service that owns descriptor or characteristic with handle equal to
+ * |handle|, or NULL */
+extern const tBTA_GATTC_SERVICE* BTA_GATTC_GetOwningService(uint16_t conn_id,
+                                                            uint16_t handle);
+
 /*******************************************************************************
  *
  * Function         BTA_GATTC_GetGattDb
@@ -783,16 +623,16 @@
  *
  ******************************************************************************/
 void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle,
-                                  tBTA_GATT_AUTH_REQ auth_req,
+                                  tGATT_AUTH_REQ auth_req,
                                   GATT_READ_OP_CB callback, void* cb_data);
 
 /**
  * This function is called to read a value of characteristic with uuid equal to
  * |uuid|
  */
-void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, tBT_UUID uuid,
+void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, const bluetooth::Uuid& uuid,
                                  uint16_t s_handle, uint16_t e_handle,
-                                 tBTA_GATT_AUTH_REQ auth_req,
+                                 tGATT_AUTH_REQ auth_req,
                                  GATT_READ_OP_CB callback, void* cb_data);
 
 /*******************************************************************************
@@ -808,8 +648,8 @@
  *
  ******************************************************************************/
 void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle,
-                             tBTA_GATT_AUTH_REQ auth_req,
-                             GATT_READ_OP_CB callback, void* cb_data);
+                             tGATT_AUTH_REQ auth_req, GATT_READ_OP_CB callback,
+                             void* cb_data);
 
 /*******************************************************************************
  *
@@ -826,9 +666,9 @@
  *
  ******************************************************************************/
 void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle,
-                              tBTA_GATTC_WRITE_TYPE write_type,
-                              vector<uint8_t> value,
-                              tBTA_GATT_AUTH_REQ auth_req,
+                              tGATT_WRITE_TYPE write_type,
+                              std::vector<uint8_t> value,
+                              tGATT_AUTH_REQ auth_req,
                               GATT_WRITE_OP_CB callback, void* cb_data);
 
 /*******************************************************************************
@@ -845,8 +685,8 @@
  *
  ******************************************************************************/
 void BTA_GATTC_WriteCharDescr(uint16_t conn_id, uint16_t handle,
-                              vector<uint8_t> value,
-                              tBTA_GATT_AUTH_REQ auth_req,
+                              std::vector<uint8_t> value,
+                              tGATT_AUTH_REQ auth_req,
                               GATT_WRITE_OP_CB callback, void* cb_data);
 
 /*******************************************************************************
@@ -877,8 +717,8 @@
  * Returns          OK if registration succeed, otherwise failed.
  *
  ******************************************************************************/
-extern tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications(
-    tBTA_GATTC_IF client_if, const RawAddress& remote_bda, uint16_t handle);
+extern tGATT_STATUS BTA_GATTC_RegisterForNotifications(
+    tGATT_IF client_if, const RawAddress& remote_bda, uint16_t handle);
 
 /*******************************************************************************
  *
@@ -894,8 +734,8 @@
  * Returns          OK if deregistration succeed, otherwise failed.
  *
  ******************************************************************************/
-extern tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(
-    tBTA_GATTC_IF client_if, const RawAddress& remote_bda, uint16_t handle);
+extern tGATT_STATUS BTA_GATTC_DeregisterForNotifications(
+    tGATT_IF client_if, const RawAddress& remote_bda, uint16_t handle);
 
 /*******************************************************************************
  *
@@ -913,8 +753,8 @@
  *
  ******************************************************************************/
 extern void BTA_GATTC_PrepareWrite(uint16_t conn_id, uint16_t handle,
-                                   uint16_t offset, vector<uint8_t> value,
-                                   tBTA_GATT_AUTH_REQ auth_req,
+                                   uint16_t offset, std::vector<uint8_t> value,
+                                   tGATT_AUTH_REQ auth_req,
                                    GATT_WRITE_OP_CB callback, void* cb_data);
 
 /*******************************************************************************
@@ -947,7 +787,7 @@
  ******************************************************************************/
 extern void BTA_GATTC_ReadMultiple(uint16_t conn_id,
                                    tBTA_GATTC_MULTI* p_read_multi,
-                                   tBTA_GATT_AUTH_REQ auth_req);
+                                   tGATT_AUTH_REQ auth_req);
 
 /*******************************************************************************
  *
@@ -1020,7 +860,7 @@
  * Returns          None
  *
  ******************************************************************************/
-extern void BTA_GATTS_AppRegister(tBT_UUID* p_app_uuid,
+extern void BTA_GATTS_AppRegister(const bluetooth::Uuid& app_uuid,
                                   tBTA_GATTS_CBACK* p_cback);
 
 /*******************************************************************************
@@ -1034,7 +874,7 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if);
+extern void BTA_GATTS_AppDeregister(tGATT_IF server_if);
 
 /*******************************************************************************
  *
@@ -1047,12 +887,17 @@
  * Parameters       server_if: server interface.
  *                  service: pointer to vector describing service.
  *
- * Returns          Returns |BTA_GATT_OK| on success or |BTA_GATT_ERROR| if the
+ * Returns          Returns |GATT_SUCCESS| on success or |GATT_ERROR| if the
  *                  service cannot be added.
  *
  ******************************************************************************/
-extern uint16_t BTA_GATTS_AddService(tBTA_GATTS_IF server_if,
-                                     vector<btgatt_db_element_t>& service);
+typedef base::Callback<void(uint8_t status, int server_if,
+                            std::vector<btgatt_db_element_t> service)>
+    BTA_GATTS_AddServiceCb;
+
+extern void BTA_GATTS_AddService(tGATT_IF server_if,
+                                 std::vector<btgatt_db_element_t> service,
+                                 BTA_GATTS_AddServiceCb cb);
 
 /*******************************************************************************
  *
@@ -1099,7 +944,7 @@
  *
  ******************************************************************************/
 extern void BTA_GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_id,
-                                            vector<uint8_t> value,
+                                            std::vector<uint8_t> value,
                                             bool need_confirm);
 
 /*******************************************************************************
@@ -1117,7 +962,7 @@
  *
  ******************************************************************************/
 extern void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
-                              tBTA_GATT_STATUS status, tBTA_GATTS_RSP* p_msg);
+                              tGATT_STATUS status, tGATTS_RSP* p_msg);
 
 /*******************************************************************************
  *
@@ -1133,9 +978,8 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void BTA_GATTS_Open(tBTA_GATTS_IF server_if,
-                           const RawAddress& remote_bda, bool is_direct,
-                           tBTA_GATT_TRANSPORT transport);
+extern void BTA_GATTS_Open(tGATT_IF server_if, const RawAddress& remote_bda,
+                           bool is_direct, tGATT_TRANSPORT transport);
 
 /*******************************************************************************
  *
@@ -1151,7 +995,7 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if,
+extern void BTA_GATTS_CancelOpen(tGATT_IF server_if,
                                  const RawAddress& remote_bda, bool is_direct);
 
 /*******************************************************************************
diff --git a/bta/include/bta_gatt_queue.h b/bta/include/bta_gatt_queue.h
new file mode 100644
index 0000000..963fc13
--- /dev/null
+++ b/bta/include/bta_gatt_queue.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 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 <vector>
+
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+#include "bta_gatt_api.h"
+
+/* BTA GATTC implementation does not allow for multiple commands queuing. So one
+ * client making calls to BTA_GATTC_ReadCharacteristic, BTA_GATTC_ReadCharDescr,
+ * BTA_GATTC_WriteCharValue, BTA_GATTC_WriteCharDescr must wait for the callacks
+ * before scheduling next operation.
+ *
+ * Methods below can be used as replacement to BTA_GATTC_* in BTA app. They do
+ * queue the commands if another command is currently being executed.
+ *
+ * If you decide to use those methods in your app, make sure to not mix it with
+ * existing BTA_GATTC_* API.
+ */
+class BtaGattQueue {
+ public:
+  static void Clean(uint16_t conn_id);
+  static void ReadCharacteristic(uint16_t conn_id, uint16_t handle,
+                                 GATT_READ_OP_CB cb, void* cb_data);
+  static void ReadDescriptor(uint16_t conn_id, uint16_t handle,
+                             GATT_READ_OP_CB cb, void* cb_data);
+  static void WriteCharacteristic(uint16_t conn_id, uint16_t handle,
+                                  std::vector<uint8_t> value,
+                                  tGATT_WRITE_TYPE write_type,
+                                  GATT_WRITE_OP_CB cb, void* cb_data);
+  static void WriteDescriptor(uint16_t conn_id, uint16_t handle,
+                              std::vector<uint8_t> value,
+                              tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb,
+                              void* cb_data);
+
+  /* Holds pending GATT operations */
+  struct gatt_operation {
+    uint8_t type;
+    uint16_t handle;
+    GATT_READ_OP_CB read_cb;
+    void* read_cb_data;
+    GATT_WRITE_OP_CB write_cb;
+    void* write_cb_data;
+
+    /* write-specific fields */
+    tGATT_WRITE_TYPE write_type;
+    std::vector<uint8_t> value;
+  };
+
+ private:
+  static void mark_as_not_executing(uint16_t conn_id);
+  static void gatt_execute_next_op(uint16_t conn_id);
+  static void gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
+                                    uint16_t handle, uint16_t len,
+                                    uint8_t* value, void* data);
+  static void gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
+                                     uint16_t handle, void* data);
+
+  // maps connection id to operations waiting for execution
+  static std::unordered_map<uint16_t, std::list<gatt_operation>> gatt_op_queue;
+  // contain connection ids that currently execute operations
+  static std::unordered_set<uint16_t> gatt_op_queue_executing;
+};
\ No newline at end of file
diff --git a/bta/include/bta_gatts_co.h b/bta/include/bta_gatts_co.h
index bf8277f..eb820f7 100644
--- a/bta/include/bta_gatts_co.h
+++ b/bta/include/bta_gatts_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2010-2012 Broadcom Corporation
+ *  Copyright 2010-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -60,9 +60,9 @@
  *                  false - if the request can not be processed
  *
  ******************************************************************************/
-extern bool bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd,
-                                 tBTA_GATTS_SRV_CHG_REQ* p_req,
-                                 tBTA_GATTS_SRV_CHG_RSP* p_rsp);
+extern bool bta_gatts_co_srv_chg(tGATTS_SRV_CHG_CMD cmd,
+                                 tGATTS_SRV_CHG_REQ* p_req,
+                                 tGATTS_SRV_CHG_RSP* p_rsp);
 
 /*******************************************************************************
  *
diff --git a/bta/include/bta_hd_api.h b/bta/include/bta_hd_api.h
index 31cb7a0..2bb78f1 100644
--- a/bta/include/bta_hd_api.h
+++ b/bta/include/bta_hd_api.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h
new file mode 100644
index 0000000..96ad7e6
--- /dev/null
+++ b/bta/include/bta_hearing_aid_api.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+ *
+ *  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 <base/callback_forward.h>
+#include <hardware/bt_hearing_aid.h>
+
+
+/** Implementations of HearingAid will also implement this interface */
+class HearingAidAudioReceiver {
+ public:
+  virtual ~HearingAidAudioReceiver() = default;
+  virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
+  virtual void OnAudioSuspend();
+  virtual void OnAudioResume();
+};
+
+class HearingAid {
+ public:
+  virtual ~HearingAid() = default;
+
+  static void Initialize(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
+                         base::Closure initCb);
+  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 is_white_listed);
+
+  static int GetDeviceCount();
+
+  virtual void Connect(const RawAddress& address) = 0;
+  virtual void Disconnect(const RawAddress& address) = 0;
+  virtual void SetVolume(int8_t volume) = 0;
+};
+
+/* Represents configuration of audio codec, as exchanged between hearing aid and
+ * phone.
+ * It can also be passed to the audio source to configure its parameters.
+ */
+struct CodecConfiguration {
+  /** sampling rate that the codec expects to receive from audio framework */
+  uint32_t sample_rate;
+
+  /** bitrate that codec expects to receive from audio framework in bits per
+   * channel */
+  uint32_t bit_rate;
+
+  /** Data interval determines how often we send samples to the remote. This
+   * should match how often we grab data from audio source, optionally we can
+   * grab data every 2 or 3 intervals, but this would increase latency.
+   *
+   * Value is provided in ms, must be divisable by 1.25 to make sure the
+   * connection interval is integer.
+   */
+  uint16_t data_interval_ms;
+};
+
+/** Represents source of audio for hearing aids */
+class HearingAidAudioSource {
+ public:
+  static void Start(const CodecConfiguration& codecConfiguration,
+                    HearingAidAudioReceiver* audioReceiver);
+  static void Stop();
+  static void Initialize();
+  static void CleanUp();
+  static void DebugDump(int fd);
+};
diff --git a/bta/include/bta_hf_client_api.h b/bta/include/bta_hf_client_api.h
index 5d725e7..69dc109 100644
--- a/bta/include/bta_hf_client_api.h
+++ b/bta/include/bta_hf_client_api.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_hh_api.h b/bta/include/bta_hh_api.h
index 6960d6f..9198b46 100644
--- a/bta/include/bta_hh_api.h
+++ b/bta/include/bta_hh_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -79,8 +79,13 @@
 
 #if (BTA_HH_LE_INCLUDED == TRUE)
 /* GATT_MAX_PHY_CHANNEL can not exceed 14 for the design of BTA HH */
+#if GATT_MAX_PHY_CHANNEL > 14
+#define BTA_HH_LE_MAX_KNOWN 14
+#else
 #define BTA_HH_LE_MAX_KNOWN GATT_MAX_PHY_CHANNEL
-#define BTA_HH_MAX_DEVICE (HID_HOST_MAX_DEVICES + GATT_MAX_PHY_CHANNEL)
+#endif
+
+#define BTA_HH_MAX_DEVICE (HID_HOST_MAX_DEVICES + BTA_HH_LE_MAX_KNOWN)
 #else
 #define BTA_HH_MAX_DEVICE HID_HOST_MAX_DEVICES
 #endif
diff --git a/bta/include/bta_hh_co.h b/bta/include/bta_hh_co.h
index 7781d00..da884bc 100644
--- a/bta/include/bta_hh_co.h
+++ b/bta/include/bta_hh_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2005-2012 Broadcom Corporation
+ *  Copyright 2005-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_hl_api.h b/bta/include/bta_hl_api.h
index 414d42d..12532d7 100644
--- a/bta/include/bta_hl_api.h
+++ b/bta/include/bta_hl_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_hl_ci.h b/bta/include/bta_hl_ci.h
index ad1499f..73a7cd4 100644
--- a/bta/include/bta_hl_ci.h
+++ b/bta/include/bta_hl_ci.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_hl_co.h b/bta/include/bta_hl_co.h
index 82b6243..9a36911 100644
--- a/bta/include/bta_hl_co.h
+++ b/bta/include/bta_hl_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_jv_api.h b/bta/include/bta_jv_api.h
index 54824c4..39f72fd 100644
--- a/bta/include/bta_jv_api.h
+++ b/bta/include/bta_jv_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -246,7 +246,6 @@
   uint32_t handle;       /* The connection handle */
   uint32_t req_id;       /* The req_id in the associated BTA_JvL2capWrite() */
   uint16_t len;          /* The length of the data written. */
-  uint8_t* p_data;       /* The buffer where data is held */
   bool cong;             /* congestion status */
 } tBTA_JV_L2CAP_WRITE;
 
@@ -256,7 +255,6 @@
   uint16_t channel;      /* The connection channel */
   RawAddress addr;       /* The peer address */
   uint32_t req_id;       /* The req_id in the associated BTA_JvL2capWrite() */
-  uint8_t* p_data;       /* The buffer where data is held */
   uint16_t len;          /* The length of the data written. */
   bool cong;             /* congestion status */
 } tBTA_JV_L2CAP_WRITE_FIXED;
@@ -442,11 +440,10 @@
  *                  request a new channel will be made. set channel to <= 0 to
  *                  automatically assign an channel ID.
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ * Returns          void
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel);
+void BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel);
 
 /*******************************************************************************
  *
@@ -475,7 +472,8 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvStartDiscovery(const RawAddress& bd_addr,
-                                    uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+                                    uint16_t num_uuid,
+                                    const bluetooth::Uuid* p_uuid_list,
                                     uint32_t rfcomm_slot_id);
 
 /*******************************************************************************
@@ -514,17 +512,10 @@
  *                  When the connection is established or failed,
  *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
- *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
-                                    const tL2CAP_ERTM_INFO* ertm_info,
-                                    uint16_t remote_chan, uint16_t rx_mtu,
-                                    tL2CAP_CFG_INFO* cfg,
-                                    const RawAddress& peer_bd_addr,
-                                    tBTA_JV_L2CAP_CBACK* p_cback,
-                                    uint32_t l2cap_socket_id);
+void BTA_JvL2capConnectLE(uint16_t remote_chan, const RawAddress& peer_bd_addr,
+                          tBTA_JV_L2CAP_CBACK* p_cback,
+                          uint32_t l2cap_socket_id);
 
 /*******************************************************************************
  *
@@ -537,15 +528,13 @@
  *                  When the connection is established or failed,
  *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
- *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capConnect(
-    int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
-    const tL2CAP_ERTM_INFO* ertm_info, uint16_t remote_psm, uint16_t rx_mtu,
-    tL2CAP_CFG_INFO* cfg, const RawAddress& peer_bd_addr,
-    tBTA_JV_L2CAP_CBACK* p_cback, uint32_t l2cap_socket_id);
+void BTA_JvL2capConnect(int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                        std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                        uint16_t remote_psm, uint16_t rx_mtu,
+                        std::unique_ptr<tL2CAP_CFG_INFO> cfg,
+                        const RawAddress& peer_bd_addr,
+                        tBTA_JV_L2CAP_CBACK* p_cback, uint32_t l2cap_socket_id);
 
 /*******************************************************************************
  *
@@ -583,17 +572,15 @@
  *                  established, tBTA_JV_L2CAP_CBACK is called with
  *                  BTA_JV_L2CAP_OPEN_EVT.
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ * Returns          void
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capStartServer(int conn_type, tBTA_SEC sec_mask,
-                                      tBTA_JV_ROLE role,
-                                      const tL2CAP_ERTM_INFO* ertm_info,
-                                      uint16_t local_psm, uint16_t rx_mtu,
-                                      tL2CAP_CFG_INFO* cfg,
-                                      tBTA_JV_L2CAP_CBACK* p_cback,
-                                      uint32_t l2cap_socket_id);
+void BTA_JvL2capStartServer(int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                            std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                            uint16_t local_psm, uint16_t rx_mtu,
+                            std::unique_ptr<tL2CAP_CFG_INFO> cfg,
+                            tBTA_JV_L2CAP_CBACK* p_cback,
+                            uint32_t l2cap_socket_id);
 
 /*******************************************************************************
  *
@@ -606,16 +593,11 @@
  *                  BTA_JV_L2CAP_START_EVT.  When the connection is established,
  *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ * Returns          void
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
-                                        const tL2CAP_ERTM_INFO* ertm_info,
-                                        uint16_t local_chan, uint16_t rx_mtu,
-                                        tL2CAP_CFG_INFO* cfg,
-                                        tBTA_JV_L2CAP_CBACK* p_cback,
-                                        uint32_t l2cap_socket_id);
+void BTA_JvL2capStartServerLE(uint16_t local_chan, tBTA_JV_L2CAP_CBACK* p_cback,
+                              uint32_t l2cap_socket_id);
 
 /*******************************************************************************
  *
@@ -686,8 +668,7 @@
  *                  BTA_JV_FAILURE, otherwise.
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
-                                uint8_t* p_data, uint16_t len,
+tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id, BT_HDR* msg,
                                 uint32_t user_id);
 
 /*******************************************************************************
@@ -699,15 +680,10 @@
  *                  called with BTA_JV_L2CAP_WRITE_FIXED_EVT. Works for
  *                  fixed-channel connections
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
- *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capWriteFixed(uint16_t channel, const RawAddress& addr,
-                                     uint32_t req_id,
-                                     tBTA_JV_L2CAP_CBACK* p_cback,
-                                     uint8_t* p_data, uint16_t len,
-                                     uint32_t user_id);
+void BTA_JvL2capWriteFixed(uint16_t channel, const RawAddress& addr,
+                           uint32_t req_id, tBTA_JV_L2CAP_CBACK* p_cback,
+                           BT_HDR* msg, uint32_t user_id);
 
 /*******************************************************************************
  *
diff --git a/bta/include/bta_jv_co.h b/bta/include/bta_jv_co.h
index e3a4130..fdee4ef 100644
--- a/bta/include/bta_jv_co.h
+++ b/bta/include/bta_jv_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2007-2012 Broadcom Corporation
+ *  Copyright 2007-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_mce_api.h b/bta/include/bta_mce_api.h
index 27d6236..182e5da 100644
--- a/bta/include/bta_mce_api.h
+++ b/bta/include/bta_mce_api.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_op_api.h b/bta/include/bta_op_api.h
index 3918568..bab96ff 100644
--- a/bta/include/bta_op_api.h
+++ b/bta/include/bta_op_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_pan_api.h b/bta/include/bta_pan_api.h
index 1eaaa2d..ce8a3c8 100644
--- a/bta/include/bta_pan_api.h
+++ b/bta/include/bta_pan_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_pan_ci.h b/bta/include/bta_pan_ci.h
index 889d77b..3711700 100644
--- a/bta/include/bta_pan_ci.h
+++ b/bta/include/bta_pan_ci.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_pan_co.h b/bta/include/bta_pan_co.h
index 1ce512d..acd212e 100644
--- a/bta/include/bta_pan_co.h
+++ b/bta/include/bta_pan_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/include/bta_sdp_api.h b/bta/include/bta_sdp_api.h
index 4dc5885..078167a 100644
--- a/bta/include/bta_sdp_api.h
+++ b/bta/include/bta_sdp_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 The Android Open Source Project
+ *  Copyright 2015 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.
@@ -31,6 +31,8 @@
 #include "bta_api.h"
 #include "btm_api.h"
 
+using bluetooth::Uuid;
+
 /* status values */
 #define BTA_SDP_SUCCESS 0 /* Successful operation. */
 #define BTA_SDP_FAILURE 1 /* Generic failure. */
@@ -55,7 +57,7 @@
 typedef struct {
   tBTA_SDP_STATUS status;
   RawAddress remote_addr;
-  tBT_UUID uuid;
+  bluetooth::Uuid uuid;
   int record_count;
   bluetooth_sdp_record records[BTA_SDP_MAX_RECORDS];
 } tBTA_SDP_SEARCH_COMP;
@@ -104,7 +106,7 @@
  *
  ******************************************************************************/
 extern tBTA_SDP_STATUS BTA_SdpSearch(const RawAddress& bd_addr,
-                                     tSDP_UUID* uuid);
+                                     const bluetooth::Uuid& uuid);
 
 /*******************************************************************************
  *
diff --git a/bta/include/utl.h b/bta/include/utl.h
index 88ec332..10afd25 100644
--- a/bta/include/utl.h
+++ b/bta/include/utl.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index d1d66aa..69fa3f2 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
  *
  ******************************************************************************/
 #include <arpa/inet.h>
+#include <bluetooth/uuid.h>
 #include <hardware/bluetooth.h>
 #include <pthread.h>
 #include <stdlib.h>
@@ -38,16 +39,22 @@
 #include "bta_sys.h"
 #include "btm_api.h"
 #include "btm_int.h"
+#include "device/include/controller.h"
 #include "gap_api.h"
 #include "l2c_api.h"
 #include "osi/include/allocator.h"
 #include "port_api.h"
 #include "rfcdefs.h"
 #include "sdp_api.h"
+#include "stack/l2cap/l2c_int.h"
 #include "utl.h"
 
 #include "osi/include/osi.h"
 
+using bluetooth::Uuid;
+
+tBTA_JV_CB bta_jv_cb;
+
 /* one of these exists for each client */
 struct fc_client {
   struct fc_client* next_all_list;
@@ -81,13 +88,6 @@
 static void fcchan_data_cbk(uint16_t chan, const RawAddress& bd_addr,
                             BT_HDR* p_buf);
 
-extern void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len);
-static inline void logu(const char* title, const uint8_t* p_uuid) {
-  char uuids[128];
-  uuid_to_string_legacy((bt_uuid_t*)p_uuid, uuids, sizeof(uuids));
-  APPL_TRACE_DEBUG("%s: %s", title, uuids);
-}
-
 static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb,
                                         tBTA_JV_PCB* p_pcb_open);
 static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(uint32_t jv_handle);
@@ -95,8 +95,6 @@
 static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB* p_cb);
 static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb,
                                    const tBTA_JV_CONN_STATE state);
-tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB* p_cb,
-                                        const tBTA_JV_CONN_STATE new_st);
 
 /*******************************************************************************
  *
@@ -126,8 +124,8 @@
     if (bta_jv_cb.sec_id[i]) used++;
   }
   if (used == BTA_JV_NUM_SERVICE_ID)
-    APPL_TRACE_ERROR("get_sec_id_used, sec id exceeds the limit:%d",
-                     BTA_JV_NUM_SERVICE_ID);
+    LOG(ERROR) << __func__
+               << ": sec id exceeds the limit=" << BTA_JV_NUM_SERVICE_ID;
   return used;
 }
 static int get_rfc_cb_used(void) {
@@ -137,8 +135,8 @@
     if (bta_jv_cb.rfc_cb[i].handle) used++;
   }
   if (used == BTA_JV_MAX_RFC_CONN)
-    APPL_TRACE_ERROR("get_sec_id_used, rfc ctrl block exceeds the limit:%d",
-                     BTA_JV_MAX_RFC_CONN);
+    LOG(ERROR) << __func__
+               << ": rfc ctrl block exceeds the limit=" << BTA_JV_MAX_RFC_CONN;
   return used;
 }
 
@@ -184,8 +182,8 @@
       p_cb->curr_sess = 1;
       for (j = 0; j < BTA_JV_MAX_RFC_SR_SESSION; j++) p_cb->rfc_hdl[j] = 0;
       p_cb->rfc_hdl[0] = port_handle;
-      APPL_TRACE_DEBUG("bta_jv_alloc_rfc_cb port_handle:%d handle:0x%2x",
-                       port_handle, p_cb->handle);
+      VLOG(2) << __func__ << "port_handle=" << +port_handle
+              << ", handle=" << loghex(p_cb->handle);
 
       p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
       p_pcb->handle = p_cb->handle;
@@ -196,10 +194,9 @@
     }
   }
   if (p_cb == NULL) {
-    APPL_TRACE_ERROR(
-        "bta_jv_alloc_rfc_cb: port_handle:%d, ctrl block exceeds "
-        "limit:%d",
-        port_handle, BTA_JV_MAX_RFC_CONN);
+    LOG(ERROR) << __func__ << "port_handle=" << port_handle
+               << " ctrl block exceeds limit:" << port_handle,
+        BTA_JV_MAX_RFC_CONN;
   }
   return p_cb;
 }
@@ -246,10 +243,8 @@
     handle &= ~BTA_JV_RFCOMM_MASK;
     if (handle) p_cb = &bta_jv_cb.rfc_cb[handle - 1];
   } else {
-    APPL_TRACE_WARNING(
-        "bta_jv_rfc_port_to_cb(port_handle:0x%x):jv handle:0x%x not"
-        " FOUND",
-        port_handle, bta_jv_cb.port_cb[port_handle - 1].handle);
+    LOG(WARNING) << __func__
+                 << ": jv handle not found port_handle:" << port_handle;
   }
   return p_cb;
 }
@@ -261,55 +256,48 @@
   int close_pending = 0;
 
   if (!p_cb || !p_pcb) {
-    APPL_TRACE_ERROR("bta_jv_free_sr_rfc_cb, p_cb or p_pcb cannot be null");
+    LOG(ERROR) << __func__ << " p_cb or p_pcb cannot be null";
     return BTA_JV_FAILURE;
   }
-  APPL_TRACE_DEBUG(
-      "bta_jv_free_sr_rfc_cb: max_sess:%d, curr_sess:%d, p_pcb:%p, user:"
-      "%p, state:%d, jv handle: 0x%x",
-      p_cb->max_sess, p_cb->curr_sess, p_pcb, p_pcb->rfcomm_slot_id,
-      p_pcb->state, p_pcb->handle);
+  VLOG(2) << __func__ << ": max_sess=" << p_cb->max_sess
+          << ", curr_sess=" << p_cb->curr_sess << ", p_pcb=" << p_pcb
+          << ", user=" << p_pcb->rfcomm_slot_id << ", state=" << p_pcb->state
+          << ", jv handle=" << loghex(p_pcb->handle);
 
   if (p_cb->curr_sess <= 0) return BTA_JV_SUCCESS;
 
   switch (p_pcb->state) {
     case BTA_JV_ST_CL_CLOSING:
     case BTA_JV_ST_SR_CLOSING:
-      APPL_TRACE_WARNING(
-          "bta_jv_free_sr_rfc_cb: return on closing, port state:%d, "
-          "scn:%d, p_pcb:%p, user_data:%p",
-          p_pcb->state, p_cb->scn, p_pcb, p_pcb->rfcomm_slot_id);
+      LOG(WARNING) << __func__
+                   << ": return on closing, port state=" << p_pcb->state
+                   << ", scn=" << p_cb->scn << ", p_pcb=" << p_pcb
+                   << ", user_data=" << p_pcb->rfcomm_slot_id;
       status = BTA_JV_FAILURE;
       return status;
     case BTA_JV_ST_CL_OPEN:
     case BTA_JV_ST_CL_OPENING:
-      APPL_TRACE_DEBUG(
-          "bta_jv_free_sr_rfc_cb: state: %d, scn:%d,"
-          " user_data:%p",
-          p_pcb->state, p_cb->scn, p_pcb->rfcomm_slot_id);
+      VLOG(2) << __func__ << ": state=" << p_pcb->state << ", scn=" << p_cb->scn
+              << ", user_data=" << p_pcb->rfcomm_slot_id;
       p_pcb->state = BTA_JV_ST_CL_CLOSING;
       break;
     case BTA_JV_ST_SR_LISTEN:
       p_pcb->state = BTA_JV_ST_SR_CLOSING;
       remove_server = true;
-      APPL_TRACE_DEBUG(
-          "bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_LISTEN, scn:%d,"
-          " user_data:%p",
-          p_cb->scn, p_pcb->rfcomm_slot_id);
+      VLOG(2) << __func__ << ": state: BTA_JV_ST_SR_LISTEN, scn=" << p_cb->scn
+              << ", user_data=" << p_pcb->rfcomm_slot_id;
       break;
     case BTA_JV_ST_SR_OPEN:
       p_pcb->state = BTA_JV_ST_SR_CLOSING;
-      APPL_TRACE_DEBUG(
-          "bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_OPEN, scn:%d,"
-          " user_data:%p",
-          p_cb->scn, p_pcb->rfcomm_slot_id);
+      VLOG(2) << ": state: BTA_JV_ST_SR_OPEN, scn=" << p_cb->scn
+              << " user_data=" << p_pcb->rfcomm_slot_id;
       break;
     default:
-      APPL_TRACE_WARNING(
-          "bta_jv_free_sr_rfc_cb():failed, ignore port state:%d, scn:"
-          "%d, p_pcb:%p, jv handle: 0x%x, port_handle: %d, user_data:%p",
-          p_pcb->state, p_cb->scn, p_pcb, p_pcb->handle, p_pcb->port_handle,
-          p_pcb->rfcomm_slot_id);
+      LOG(WARNING) << __func__ << ":failed, ignore port state= " << p_pcb->state
+                   << ", scn=" << p_cb->scn << ", p_pcb= " << p_pcb
+                   << ", jv handle=" << loghex(p_pcb->handle)
+                   << ", port_handle=" << p_pcb->port_handle
+                   << ", user_data=" << p_pcb->rfcomm_slot_id;
       status = BTA_JV_FAILURE;
       break;
   }
@@ -322,11 +310,11 @@
       port_status = RFCOMM_RemoveServer(p_pcb->port_handle);
     if (port_status != PORT_SUCCESS) {
       status = BTA_JV_FAILURE;
-      APPL_TRACE_WARNING(
-          "bta_jv_free_rfc_cb(jv handle: 0x%x, state %d)::"
-          "port_status: %d, port_handle: %d, close_pending: %d:Remove",
-          p_pcb->handle, p_pcb->state, port_status, p_pcb->port_handle,
-          close_pending);
+      LOG(WARNING) << __func__ << ": Remove jv handle=" << loghex(p_pcb->handle)
+                   << ", state=" << p_pcb->state
+                   << ", port_status=" << port_status
+                   << ", port_handle=" << p_pcb->port_handle
+                   << ", close_pending=" << close_pending;
     }
   }
   if (!close_pending) {
@@ -431,14 +419,10 @@
           appid_counter++;
       }
 
-      APPL_TRACE_API(
-          "%s(jv_handle: 0x%2x), idx: %d, "
-          "app_id: 0x%x",
-          __func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
-      APPL_TRACE_API(
-          "%s, bd_counter = %d, "
-          "appid_counter = %d",
-          __func__, bd_counter, appid_counter);
+      VLOG(2) << __func__ << ": jv_handle=" << loghex(jv_handle)
+              << ", idx=" << i << "app_id=" << bta_jv_cb.pm_cb[i].app_id
+              << ", bd_counter=" << bd_counter
+              << ", appid_counter=" << appid_counter;
       if (bd_counter > 1) {
         bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
       }
@@ -460,11 +444,9 @@
               bta_jv_rfc_port_to_pcb(bta_jv_cb.rfc_cb[hi].rfc_hdl[si]);
           if (p_pcb) {
             if (NULL == p_pcb->p_pm_cb)
-              APPL_TRACE_WARNING(
-                  "%s(jv_handle:"
-                  " 0x%x):port_handle: 0x%x, p_pm_cb: %d: no link to "
-                  "pm_cb?",
-                  __func__, jv_handle, p_pcb->port_handle, i);
+              LOG(WARNING) << __func__ << ": jv_handle=" << loghex(jv_handle)
+                           << ", port_handle=" << p_pcb->port_handle
+                           << ", i=" << i << ", no link to pm_cb?";
             p_cb = &p_pcb->p_pm_cb;
           }
         }
@@ -472,10 +454,8 @@
         if (jv_handle < BTA_JV_MAX_L2C_CONN) {
           tBTA_JV_L2C_CB* p_l2c_cb = &bta_jv_cb.l2c_cb[jv_handle];
           if (NULL == p_l2c_cb->p_pm_cb)
-            APPL_TRACE_WARNING(
-                "%s(jv_handle: "
-                "0x%x): p_pm_cb: %d: no link to pm_cb?",
-                __func__, jv_handle, i);
+            LOG(WARNING) << __func__ << ": jv_handle=" << loghex(jv_handle)
+                         << ", i=" << i << " no link to pm_cb?";
           p_cb = &p_l2c_cb->p_pm_cb;
         }
       }
@@ -534,10 +514,10 @@
           }
         }
       }
-      APPL_TRACE_API(
-          "bta_jv_alloc_set_pm_profile_cb(handle 0x%2x, app_id %d): "
-          "idx: %d, (BTA_JV_PM_MAX_NUM: %d), pp_cb: 0x%x",
-          jv_handle, app_id, i, BTA_JV_PM_MAX_NUM, pp_cb);
+      VLOG(2) << __func__ << ": handle=" << loghex(jv_handle)
+              << ", app_id=" << app_id << ", idx=" << i
+              << ", BTA_JV_PM_MAX_NUM=" << BTA_JV_PM_MAX_NUM
+              << ", pp_cb=" << pp_cb;
       break;
     }
   }
@@ -550,11 +530,9 @@
     bta_jv_cb.pm_cb[i].state = BTA_JV_PM_IDLE_ST;
     return &bta_jv_cb.pm_cb[i];
   }
-  APPL_TRACE_WARNING(
-      "bta_jv_alloc_set_pm_profile_cb(jv_handle: 0x%x, app_id: %d) "
-      "return NULL",
-      jv_handle, app_id);
-  return (tBTA_JV_PM_CB*)NULL;
+  LOG(WARNING) << __func__ << ": handle=" << loghex(jv_handle)
+               << ", app_id=" << app_id << ", return NULL";
+  return NULL;
 }
 
 /*******************************************************************************
@@ -580,27 +558,27 @@
 
         case TCS_PSM_INTERCOM: /* 5 */
         case TCS_PSM_CORDLESS: /* 7 */
-          if (false == bta_sys_is_register(BTA_ID_CT) &&
-              false == bta_sys_is_register(BTA_ID_CG))
+          if (!bta_sys_is_register(BTA_ID_CT) &&
+              !bta_sys_is_register(BTA_ID_CG))
             ret = true;
           break;
 
         case BT_PSM_BNEP: /* F */
-          if (false == bta_sys_is_register(BTA_ID_PAN)) ret = true;
+          if (!bta_sys_is_register(BTA_ID_PAN)) ret = true;
           break;
 
         case HID_PSM_CONTROL:   /* 0x11 */
         case HID_PSM_INTERRUPT: /* 0x13 */
           // FIX: allow HID Device and HID Host to coexist
-          if (false == bta_sys_is_register(BTA_ID_HD) ||
-              false == bta_sys_is_register(BTA_ID_HH))
+          if (!bta_sys_is_register(BTA_ID_HD) ||
+              !bta_sys_is_register(BTA_ID_HH))
             ret = true;
           break;
 
         case AVCT_PSM: /* 0x17 */
         case AVDT_PSM: /* 0x19 */
-          if ((false == bta_sys_is_register(BTA_ID_AV)) &&
-              (false == bta_sys_is_register(BTA_ID_AVK)))
+          if ((!bta_sys_is_register(BTA_ID_AV)) &&
+              (!bta_sys_is_register(BTA_ID_AVK)))
             ret = true;
           break;
 
@@ -615,37 +593,18 @@
   return ret;
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_enable
- *
- * Description  Initialises the JAVA I/F
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_enable(tBTA_JV_MSG* p_data) {
+/* Initialises the JAVA I/F */
+void bta_jv_enable(tBTA_JV_DM_CBACK* p_cback) {
   tBTA_JV_STATUS status = BTA_JV_SUCCESS;
-  bta_jv_cb.p_dm_cback = p_data->enable.p_cback;
+  bta_jv_cb.p_dm_cback = p_cback;
   tBTA_JV bta_jv;
   bta_jv.status = status;
   bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, &bta_jv, 0);
   memset(bta_jv_cb.free_psm_list, 0, sizeof(bta_jv_cb.free_psm_list));
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_disable
- *
- * Description  Disables the BT device manager
- *              free the resources used by java
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_disable(UNUSED_ATTR tBTA_JV_MSG* p_data) {
-  APPL_TRACE_ERROR("%s", __func__);
-}
+/** Disables the BT device manager free the resources used by java */
+void bta_jv_disable() { LOG(ERROR) << __func__; }
 
 /**
  * We keep a list of PSM's that have been freed from JAVA, for reuse.
@@ -659,7 +618,7 @@
   for (int i = 0; i < cnt; i++) {
     uint16_t psm = bta_jv_cb.free_psm_list[i];
     if (psm != 0) {
-      APPL_TRACE_DEBUG("%s(): Reusing PSM: 0x%04d", __func__, psm)
+      VLOG(2) << __func__ << ": Reusing PSM=" << loghex(psm);
       bta_jv_cb.free_psm_list[i] = 0;
       return psm;
     }
@@ -680,39 +639,33 @@
   }
   if (free_index != -1) {
     bta_jv_cb.free_psm_list[free_index] = psm;
-    APPL_TRACE_DEBUG("%s(): Recycling PSM: 0x%04d", __func__, psm)
+    VLOG(2) << __func__ << ": Recycling PSM=" << loghex(psm);
   } else {
-    APPL_TRACE_ERROR("%s unable to free psm 0x%x no more free slots", __func__,
-                     psm);
+    LOG(ERROR) << __func__ << ": unable to free psm=" << loghex(psm)
+               << " no more free slots";
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_get_channel_id
- *
- * Description  Obtain a free SCN (Server Channel Number)
- *              (RFCOMM channel or L2CAP PSM)
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_get_channel_id(tBTA_JV_MSG* p_data) {
+/** Obtain a free SCN (Server Channel Number) (RFCOMM channel or L2CAP PSM) */
+void bta_jv_get_channel_id(
+    int32_t type /* One of BTA_JV_CONN_TYPE_ */,
+    int32_t channel /* optionally request a specific channel */,
+    uint32_t l2cap_socket_id, uint32_t rfcomm_slot_id) {
   uint16_t psm = 0;
 
-  switch (p_data->alloc_channel.type) {
+  switch (type) {
     case BTA_JV_CONN_TYPE_RFCOMM: {
-      int32_t channel = p_data->alloc_channel.channel;
       uint8_t scn = 0;
       if (channel > 0) {
-        if (BTM_TryAllocateSCN(channel) == false) {
-          APPL_TRACE_ERROR("rfc channel:%d already in use or invalid", channel);
+        if (!BTM_TryAllocateSCN(channel)) {
+          LOG(ERROR) << "rfc channel=" << channel
+                     << " already in use or invalid";
           channel = 0;
         }
       } else {
         channel = BTM_AllocateSCN();
         if (channel == 0) {
-          APPL_TRACE_ERROR("run out of rfc channels");
+          LOG(ERROR) << "run out of rfc channels";
           channel = 0;
         }
       }
@@ -723,8 +676,7 @@
       if (bta_jv_cb.p_dm_cback) {
         tBTA_JV bta_jv;
         bta_jv.scn = scn;
-        bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, &bta_jv,
-                             p_data->alloc_channel.rfcomm_slot_id);
+        bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, &bta_jv, rfcomm_slot_id);
       }
       return;
     }
@@ -732,10 +684,14 @@
       psm = bta_jv_get_free_psm();
       if (psm == 0) {
         psm = L2CA_AllocatePSM();
-        APPL_TRACE_DEBUG("%s() returned PSM: 0x%04x", __func__, psm);
+        VLOG(2) << __func__ << ": returned PSM=" << loghex(psm);
       }
       break;
     case BTA_JV_CONN_TYPE_L2CAP_LE:
+      psm = L2CA_AllocateLePSM();
+      if (psm == 0) {
+        LOG(ERROR) << __func__ << ": Error: No free LE PSM available";
+      }
       break;
     default:
       break;
@@ -744,24 +700,14 @@
   if (bta_jv_cb.p_dm_cback) {
     tBTA_JV bta_jv;
     bta_jv.psm = psm;
-    bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, &bta_jv,
-                         p_data->alloc_channel.l2cap_socket_id);
+    bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, &bta_jv, l2cap_socket_id);
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_free_scn
- *
- * Description  free a SCN
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_free_scn(tBTA_JV_MSG* p_data) {
-  uint16_t scn = p_data->free_channel.scn;
-
-  switch (p_data->free_channel.type) {
+/** free a SCN */
+void bta_jv_free_scn(int32_t type /* One of BTA_JV_CONN_TYPE_ */,
+                     uint16_t scn) {
+  switch (type) {
     case BTA_JV_CONN_TYPE_RFCOMM: {
       if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn - 1]) {
         /* this scn is used by JV */
@@ -774,42 +720,13 @@
       bta_jv_set_free_psm(scn);
       break;
     case BTA_JV_CONN_TYPE_L2CAP_LE:
-      // TODO: Not yet implemented...
+      VLOG(2) << __func__ << ": type=BTA_JV_CONN_TYPE_L2CAP_LE. psm=" << scn;
+      L2CA_FreeLePSM(scn);
       break;
     default:
       break;
   }
 }
-static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) {
-  static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                   0x5F, 0x9B, 0x34, 0xFB};
-
-  logu("in, uuid:", u->uu.uuid128);
-  APPL_TRACE_DEBUG("uuid len:%d", u->len);
-  if (u->len == 16) {
-    if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) == 0) {
-      tBT_UUID su;
-      memset(&su, 0, sizeof(su));
-      if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
-        su.len = 2;
-        uint16_t u16;
-        memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
-        su.uu.uuid16 = ntohs(u16);
-        APPL_TRACE_DEBUG("shorten to 16 bits uuid: %x", su.uu.uuid16);
-      } else {
-        su.len = 4;
-        uint32_t u32;
-        memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
-        su.uu.uuid32 = ntohl(u32);
-        APPL_TRACE_DEBUG("shorten to 32 bits uuid: %x", su.uu.uuid32);
-      }
-      return su;
-    }
-  }
-  APPL_TRACE_DEBUG("cannot shorten none-reserved 128 bits uuid");
-  return *u;
-}
 
 /*******************************************************************************
  *
@@ -824,7 +741,7 @@
   tBTA_JV_STATUS status;
   uint32_t* p_rfcomm_slot_id = static_cast<uint32_t*>(user_data);
 
-  APPL_TRACE_DEBUG("bta_jv_start_discovery_cback res: 0x%x", result);
+  VLOG(2) << __func__ << ": res=" << loghex(result);
 
   bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
   if (bta_jv_cb.p_dm_cback) {
@@ -834,12 +751,10 @@
     if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
       tSDP_DISC_REC* p_sdp_rec = NULL;
       tSDP_PROTOCOL_ELEM pe;
-      logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
-      tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
-      logu("shorten uuid:", su.uu.uuid128);
-      p_sdp_rec =
-          SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
-      APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
+      VLOG(2) << __func__ << ": bta_jv_cb.uuid=" << bta_jv_cb.uuid;
+      p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db,
+                                          bta_jv_cb.uuid, p_sdp_rec);
+      VLOG(2) << __func__ << ": p_sdp_rec=" << p_sdp_rec;
       if (p_sdp_rec &&
           SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
         dcomp.scn = (uint8_t)pe.params[0];
@@ -855,61 +770,49 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_start_discovery
- *
- * Description  Discovers services on a remote device
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_start_discovery(tBTA_JV_MSG* p_data) {
+/* Discovers services on a remote device */
+void bta_jv_start_discovery(const RawAddress& bd_addr, uint16_t num_uuid,
+                            bluetooth::Uuid* uuid_list,
+                            uint32_t rfcomm_slot_id) {
   tBTA_JV_STATUS status = BTA_JV_FAILURE;
-  APPL_TRACE_DEBUG("bta_jv_start_discovery in, sdp_active:%d",
-                   bta_jv_cb.sdp_active);
+  VLOG(2) << __func__ << ": in, sdp_active=" << bta_jv_cb.sdp_active;
   if (bta_jv_cb.sdp_active != BTA_JV_SDP_ACT_NONE) {
     /* SDP is still in progress */
     status = BTA_JV_BUSY;
     if (bta_jv_cb.p_dm_cback) {
       tBTA_JV bta_jv;
       bta_jv.status = status;
-      bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, &bta_jv,
-                           p_data->start_discovery.rfcomm_slot_id);
+      bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, &bta_jv, rfcomm_slot_id);
     }
     return;
   }
 
   /* init the database/set up the filter */
-  APPL_TRACE_DEBUG(
-      "call SDP_InitDiscoveryDb, p_data->start_discovery.num_uuid:%d",
-      p_data->start_discovery.num_uuid);
+  VLOG(2) << __func__ << ": call SDP_InitDiscoveryDb, num_uuid=", num_uuid;
   SDP_InitDiscoveryDb(p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size,
-                      p_data->start_discovery.num_uuid,
-                      p_data->start_discovery.uuid_list, 0, NULL);
+                      num_uuid, uuid_list, 0, NULL);
 
   /* tell SDP to keep the raw data */
   p_bta_jv_cfg->p_sdp_db->raw_data = p_bta_jv_cfg->p_sdp_raw_data;
   p_bta_jv_cfg->p_sdp_db->raw_size = p_bta_jv_cfg->sdp_raw_size;
 
   bta_jv_cb.p_sel_raw_data = 0;
-  bta_jv_cb.uuid = p_data->start_discovery.uuid_list[0];
+  bta_jv_cb.uuid = uuid_list[0];
 
   bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_YES;
 
-  uint32_t* rfcomm_slot_id = (uint32_t*)osi_malloc(sizeof(uint32_t));
-  *rfcomm_slot_id = p_data->start_discovery.rfcomm_slot_id;
+  uint32_t* rfcomm_slot_id_copy = (uint32_t*)osi_malloc(sizeof(uint32_t));
+  *rfcomm_slot_id_copy = rfcomm_slot_id;
 
-  if (!SDP_ServiceSearchAttributeRequest2(
-          p_data->start_discovery.bd_addr, p_bta_jv_cfg->p_sdp_db,
-          bta_jv_start_discovery_cback, (void*)rfcomm_slot_id)) {
+  if (!SDP_ServiceSearchAttributeRequest2(bd_addr, p_bta_jv_cfg->p_sdp_db,
+                                          bta_jv_start_discovery_cback,
+                                          (void*)rfcomm_slot_id_copy)) {
     bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
     /* failed to start SDP. report the failure right away */
     if (bta_jv_cb.p_dm_cback) {
       tBTA_JV bta_jv;
       bta_jv.status = status;
-      bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, &bta_jv,
-                           p_data->start_discovery.rfcomm_slot_id);
+      bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, &bta_jv, rfcomm_slot_id);
     }
   }
   /*
@@ -917,42 +820,23 @@
   */
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_create_record
- *
- * Description  Create an SDP record with the given attributes
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_create_record(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_CREATE_RECORD* cr = &(p_data->create_record);
+/* Create an SDP record with the given attributes */
+void bta_jv_create_record(uint32_t rfcomm_slot_id) {
   tBTA_JV_CREATE_RECORD evt_data;
   evt_data.status = BTA_JV_SUCCESS;
   if (bta_jv_cb.p_dm_cback) {
     // callback immediately to create the sdp record in stack thread context
     tBTA_JV bta_jv;
     bta_jv.create_rec = evt_data;
-    bta_jv_cb.p_dm_cback(BTA_JV_CREATE_RECORD_EVT, &bta_jv, cr->rfcomm_slot_id);
+    bta_jv_cb.p_dm_cback(BTA_JV_CREATE_RECORD_EVT, &bta_jv, rfcomm_slot_id);
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_delete_record
- *
- * Description  Delete an SDP record
- *
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_delete_record(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_ADD_ATTRIBUTE* dr = &(p_data->add_attr);
-  if (dr->handle) {
+/* Delete an SDP record */
+void bta_jv_delete_record(uint32_t handle) {
+  if (handle) {
     /* this is a record created by btif layer*/
-    SDP_DeleteRecord(dr->handle);
+    SDP_DeleteRecord(handle);
   }
 }
 
@@ -965,13 +849,15 @@
  * Returns      void
  *
  ******************************************************************************/
-static void bta_jv_l2cap_client_cback(uint16_t gap_handle, uint16_t event) {
+static void bta_jv_l2cap_client_cback(uint16_t gap_handle, uint16_t event,
+                                      tGAP_CB_DATA* data) {
   tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[gap_handle];
   tBTA_JV evt_data;
 
   if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) return;
 
-  APPL_TRACE_DEBUG("%s: %d evt:x%x", __func__, gap_handle, event);
+  VLOG(2) << __func__ << ": gap_handle=" << gap_handle
+          << ", evt=" << loghex(event);
   evt_data.l2c_open.status = BTA_JV_SUCCESS;
   evt_data.l2c_open.handle = gap_handle;
 
@@ -1016,59 +902,49 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_connect
- *
- * Description  makes an l2cap client connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_connect(tBTA_JV_MSG* p_data) {
-  tBTA_JV_L2C_CB* p_cb;
-  tBTA_JV_L2CAP_CL_INIT evt_data;
+/* makes an l2cap client connection */
+void bta_jv_l2cap_connect(int32_t type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                          uint16_t remote_psm, uint16_t rx_mtu,
+                          const RawAddress& peer_bd_addr,
+                          std::unique_ptr<tL2CAP_CFG_INFO> cfg_param,
+                          std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                          tBTA_JV_L2CAP_CBACK* p_cback,
+                          uint32_t l2cap_socket_id) {
   uint16_t handle = GAP_INVALID_HANDLE;
-  uint8_t sec_id;
-  tL2CAP_CFG_INFO cfg;
-  tBTA_JV_API_L2CAP_CONNECT* cc = &(p_data->l2cap_connect);
   uint8_t chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
-  tL2CAP_ERTM_INFO* ertm_info = NULL;
 
+  tL2CAP_CFG_INFO cfg;
   memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
-  if (cc->has_cfg == true) {
-    cfg = cc->cfg;
+  if (cfg_param) {
+    cfg = *cfg_param;
     if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
       chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
     }
   }
 
-  if (cc->has_ertm_info == true) {
-    ertm_info = &(cc->ertm_info);
-  }
-
   /* We need to use this value for MTU to be able to handle cases where cfg is
    * not set in req. */
   cfg.mtu_present = true;
-  cfg.mtu = cc->rx_mtu;
+  cfg.mtu = rx_mtu;
 
   /* TODO: DM role manager
-  L2CA_SetDesireRole(cc->role);
+  L2CA_SetDesireRole(role);
   */
 
-  sec_id = bta_jv_alloc_sec_id();
+  uint8_t sec_id = bta_jv_alloc_sec_id();
+  tBTA_JV_L2CAP_CL_INIT evt_data;
   evt_data.sec_id = sec_id;
   evt_data.status = BTA_JV_FAILURE;
 
   if (sec_id) {
     /* PSM checking is not required for LE COC */
-    if ((cc->type != BTA_JV_CONN_TYPE_L2CAP) ||
-        (bta_jv_check_psm(cc->remote_psm))) /* allowed */
+    if ((type != BTA_JV_CONN_TYPE_L2CAP) ||
+        (bta_jv_check_psm(remote_psm))) /* allowed */
     {
-      handle = GAP_ConnOpen("", sec_id, 0, &cc->peer_bd_addr, cc->remote_psm,
-                            &cfg, ertm_info, cc->sec_mask, chan_mode_mask,
-                            bta_jv_l2cap_client_cback, cc->type);
+      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);
       if (handle != GAP_INVALID_HANDLE) {
         evt_data.status = BTA_JV_SUCCESS;
       }
@@ -1076,10 +952,11 @@
   }
 
   if (evt_data.status == BTA_JV_SUCCESS) {
+    tBTA_JV_L2C_CB* p_cb;
     p_cb = &bta_jv_cb.l2c_cb[handle];
     p_cb->handle = handle;
-    p_cb->p_cback = cc->p_cback;
-    p_cb->l2cap_socket_id = cc->l2cap_socket_id;
+    p_cb->p_cback = p_cback;
+    p_cb->l2cap_socket_id = l2cap_socket_id;
     p_cb->psm = 0; /* not a server */
     p_cb->sec_id = sec_id;
     p_cb->state = BTA_JV_ST_CL_OPENING;
@@ -1088,30 +965,21 @@
   }
 
   evt_data.handle = handle;
-  if (cc->p_cback) {
+  if (p_cback) {
     tBTA_JV bta_jv;
     bta_jv.l2c_cl_init = evt_data;
-    cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &bta_jv, cc->l2cap_socket_id);
+    p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &bta_jv, l2cap_socket_id);
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_close
- *
- * Description  Close an L2CAP client connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_close(tBTA_JV_MSG* p_data) {
+/** Close an L2CAP client connection */
+void bta_jv_l2cap_close(uint32_t handle, tBTA_JV_L2C_CB* p_cb) {
   tBTA_JV_L2CAP_CLOSE evt_data;
-  tBTA_JV_API_L2CAP_CLOSE* cc = &(p_data->l2cap_close);
-  tBTA_JV_L2CAP_CBACK* p_cback = cc->p_cb->p_cback;
-  uint32_t l2cap_socket_id = cc->p_cb->l2cap_socket_id;
+  tBTA_JV_L2CAP_CBACK* p_cback = p_cb->p_cback;
+  uint32_t l2cap_socket_id = p_cb->l2cap_socket_id;
 
-  evt_data.handle = cc->handle;
-  evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
+  evt_data.handle = handle;
+  evt_data.status = bta_jv_free_l2c_cb(p_cb);
   evt_data.async = false;
 
   if (p_cback) {
@@ -1130,7 +998,8 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_jv_l2cap_server_cback(uint16_t gap_handle, uint16_t event) {
+static void bta_jv_l2cap_server_cback(uint16_t gap_handle, uint16_t event,
+                                      tGAP_CB_DATA* data) {
   tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[gap_handle];
   tBTA_JV evt_data;
   tBTA_JV_L2CAP_CBACK* p_cback;
@@ -1138,7 +1007,8 @@
 
   if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) return;
 
-  APPL_TRACE_DEBUG("%s: %d evt:x%x", __func__, gap_handle, event);
+  VLOG(2) << __func__ << ": gap_handle=" << gap_handle
+          << ", evt=" << loghex(event);
   evt_data.l2c_open.status = BTA_JV_SUCCESS;
   evt_data.l2c_open.handle = gap_handle;
 
@@ -1184,100 +1054,78 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_start_server
- *
- * Description  starts an L2CAP server
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_start_server(tBTA_JV_MSG* p_data) {
-  tBTA_JV_L2C_CB* p_cb;
-  uint8_t sec_id;
+/** starts an L2CAP server */
+void bta_jv_l2cap_start_server(int32_t type, tBTA_SEC sec_mask,
+                               tBTA_JV_ROLE role, uint16_t local_psm,
+                               uint16_t rx_mtu,
+                               std::unique_ptr<tL2CAP_CFG_INFO> cfg_param,
+                               std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                               tBTA_JV_L2CAP_CBACK* p_cback,
+                               uint32_t l2cap_socket_id) {
   uint16_t handle;
-  tL2CAP_CFG_INFO cfg;
   tBTA_JV_L2CAP_START evt_data;
-  tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
   uint8_t chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
-  tL2CAP_ERTM_INFO* ertm_info = NULL;
 
+  tL2CAP_CFG_INFO cfg;
   memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
-  if (ls->has_cfg == true) {
-    cfg = ls->cfg;
+  if (cfg_param) {
+    cfg = *cfg_param;
     if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
       chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
     }
   }
 
-  if (ls->has_ertm_info == true) {
-    ertm_info = &(ls->ertm_info);
-  }
-
   // FIX: MTU=0 means not present
-  if (ls->rx_mtu > 0) {
+  if (rx_mtu > 0) {
     cfg.mtu_present = true;
-    cfg.mtu = ls->rx_mtu;
+    cfg.mtu = rx_mtu;
   } else {
     cfg.mtu_present = false;
     cfg.mtu = 0;
   }
 
   /* TODO DM role manager
-  L2CA_SetDesireRole(ls->role);
+  L2CA_SetDesireRole(role);
   */
 
-  sec_id = bta_jv_alloc_sec_id();
+  uint8_t sec_id = bta_jv_alloc_sec_id();
+  uint16_t max_mps = 0xffff;  // Let GAP_ConnOpen set the max_mps.
   /* PSM checking is not required for LE COC */
-  if (0 == sec_id || ((ls->type == BTA_JV_CONN_TYPE_L2CAP) &&
-                      (false == bta_jv_check_psm(ls->local_psm))) ||
-      (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, nullptr, ls->local_psm,
-                             &cfg, ertm_info, ls->sec_mask, chan_mode_mask,
-                             bta_jv_l2cap_server_cback, ls->type)) ==
+  if (0 == sec_id ||
+      ((type == BTA_JV_CONN_TYPE_L2CAP) && (!bta_jv_check_psm(local_psm))) ||
+      (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, nullptr, local_psm, max_mps,
+                             &cfg, ertm_info.get(), sec_mask, chan_mode_mask,
+                             bta_jv_l2cap_server_cback, type)) ==
           GAP_INVALID_HANDLE) {
     bta_jv_free_sec_id(&sec_id);
     evt_data.status = BTA_JV_FAILURE;
   } else {
-    p_cb = &bta_jv_cb.l2c_cb[handle];
+    tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[handle];
     evt_data.status = BTA_JV_SUCCESS;
     evt_data.handle = handle;
     evt_data.sec_id = sec_id;
-    p_cb->p_cback = ls->p_cback;
-    p_cb->l2cap_socket_id = ls->l2cap_socket_id;
+    p_cb->p_cback = p_cback;
+    p_cb->l2cap_socket_id = l2cap_socket_id;
     p_cb->handle = handle;
     p_cb->sec_id = sec_id;
     p_cb->state = BTA_JV_ST_SR_LISTEN;
-    p_cb->psm = ls->local_psm;
+    p_cb->psm = local_psm;
   }
 
-  if (ls->p_cback) {
+  if (p_cback) {
     tBTA_JV bta_jv;
     bta_jv.l2c_start = evt_data;
-    ls->p_cback(BTA_JV_L2CAP_START_EVT, &bta_jv, ls->l2cap_socket_id);
+    p_cback(BTA_JV_L2CAP_START_EVT, &bta_jv, l2cap_socket_id);
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_stop_server
- *
- * Description  stops an L2CAP server
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_stop_server(tBTA_JV_MSG* p_data) {
-  tBTA_JV_L2C_CB* p_cb;
-  tBTA_JV_L2CAP_CLOSE evt_data;
-  tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
-  tBTA_JV_L2CAP_CBACK* p_cback;
+/* stops an L2CAP server */
+void bta_jv_l2cap_stop_server(uint16_t local_psm, uint32_t l2cap_socket_id) {
   for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++) {
-    if (bta_jv_cb.l2c_cb[i].psm == ls->local_psm) {
-      p_cb = &bta_jv_cb.l2c_cb[i];
-      p_cback = p_cb->p_cback;
-      uint32_t l2cap_socket_id = p_cb->l2cap_socket_id;
+    if (bta_jv_cb.l2c_cb[i].psm == local_psm) {
+      tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[i];
+      tBTA_JV_L2CAP_CBACK* p_cback = p_cb->p_cback;
+      tBTA_JV_L2CAP_CLOSE evt_data;
       evt_data.handle = p_cb->handle;
       evt_data.status = bta_jv_free_l2c_cb(p_cb);
       evt_data.async = false;
@@ -1291,127 +1139,73 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_read
- *
- * Description  Read data from an L2CAP connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_read(tBTA_JV_MSG* p_data) {
-  tBTA_JV_L2CAP_READ evt_data;
-  tBTA_JV_API_L2CAP_READ* rc = &(p_data->l2cap_read);
+/* Write data to an L2CAP connection */
+void bta_jv_l2cap_write(uint32_t handle, uint32_t req_id, BT_HDR* msg,
+                        uint32_t user_id, tBTA_JV_L2C_CB* p_cb) {
+  /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be
+   * send through the API this check should not be needed. But the API is not
+   * designed to be used (safely at least) in a multi-threaded scheduler, hence
+   * if the peer device disconnects the l2cap link after the API is called, but
+   * before this message is handled, the ->p_cback will be cleared at this
+   * point. At first glanch this seems highly unlikely, but for all
+   * obex-profiles with two channels connected - e.g. MAP, this happens around 1
+   * of 4 disconnects, as a disconnect on the server channel causes a disconnect
+   * to be send on the client (notification) channel, but at the peer typically
+   * disconnects both the OBEX disconnect request crosses the incoming l2cap
+   * disconnect. If p_cback is cleared, we simply discard the data. RISK: The
+   * caller must handle any cleanup based on another signal than
+   * BTA_JV_L2CAP_WRITE_EVT, which is typically not possible, as the pointer to
+   * the allocated buffer is stored in this message, and can therefore not be
+   * freed, hence we have a mem-leak-by-design.*/
+  if (!p_cb->p_cback) {
+    /* As this pointer is checked in the API function, this occurs only when the
+     * channel is disconnected after the API function is called, but before the
+     * message is handled. */
+    LOG(ERROR) << __func__ << ": p_cb->p_cback == NULL";
+    osi_free(msg);
+    return;
+  }
 
+  tBTA_JV_L2CAP_WRITE evt_data;
   evt_data.status = BTA_JV_FAILURE;
-  evt_data.handle = rc->handle;
-  evt_data.req_id = rc->req_id;
-  evt_data.p_data = rc->p_data;
-  evt_data.len = 0;
+  evt_data.handle = handle;
+  evt_data.req_id = req_id;
+  evt_data.cong = p_cb->cong;
+  evt_data.len = msg->len;
 
-  if (BT_PASS ==
-      GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len)) {
-    evt_data.status = BTA_JV_SUCCESS;
+  bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+
+  // TODO: this was set only for non-fixed channel packets. Is that needed ?
+  msg->event = BT_EVT_TO_BTU_SP_DATA;
+
+  if (evt_data.cong) {
+    osi_free(msg);
+  } else {
+    if (GAP_ConnWriteData(handle, msg) == BT_PASS)
+      evt_data.status = BTA_JV_SUCCESS;
   }
 
   tBTA_JV bta_jv;
-  bta_jv.l2c_read = evt_data;
-  rc->p_cback(BTA_JV_L2CAP_READ_EVT, &bta_jv, rc->l2cap_socket_id);
+  bta_jv.l2c_write = evt_data;
+  p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, &bta_jv, user_id);
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_write
- *
- * Description  Write data to an L2CAP connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_write(tBTA_JV_MSG* p_data) {
-  tBTA_JV_L2CAP_WRITE evt_data;
-  tBTA_JV_API_L2CAP_WRITE* ls = &(p_data->l2cap_write);
-
-  /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be
-   * send through the
-   * API this check should not be needed.
-   * But the API is not designed to be used (safely at least) in a
-   * multi-threaded scheduler, hence
-   * if the peer device disconnects the l2cap link after the API is called, but
-   * before this
-   * message is handled, the ->p_cback will be cleared at this point. At first
-   * glanch this seems
-   * highly unlikely, but for all obex-profiles with two channels connected -
-   * e.g. MAP, this
-   * happens around 1 of 4 disconnects, as a disconnect on the server channel
-   * causes a disconnect
-   * to be send on the client (notification) channel, but at the peer typically
-   * disconnects both
-   * the OBEX disconnect request crosses the incoming l2cap disconnect.
-   * If p_cback is cleared, we simply discard the data.
-   * RISK: The caller must handle any cleanup based on another signal than
-   * BTA_JV_L2CAP_WRITE_EVT,
-   *       which is typically not possible, as the pointer to the allocated
-   * buffer is stored
-   *       in this message, and can therefore not be freed, hence we have a
-   * mem-leak-by-design.*/
-  if (ls->p_cb->p_cback != NULL) {
-    evt_data.status = BTA_JV_FAILURE;
-    evt_data.handle = ls->handle;
-    evt_data.req_id = ls->req_id;
-    evt_data.p_data = ls->p_data;
-    evt_data.cong = ls->p_cb->cong;
-    evt_data.len = 0;
-    bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
-    if (!evt_data.cong &&
-        BT_PASS ==
-            GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len)) {
-      evt_data.status = BTA_JV_SUCCESS;
-    }
-    tBTA_JV bta_jv;
-    bta_jv.l2c_write = evt_data;
-    ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, &bta_jv, ls->user_id);
-  } else {
-    /* As this pointer is checked in the API function, this occurs only when the
-     * channel is
-     * disconnected after the API function is called, but before the message is
-     * handled. */
-    APPL_TRACE_ERROR("%s() ls->p_cb->p_cback == NULL", __func__);
-  }
-}
-
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_write_fixed
- *
- * Description  Write data to an L2CAP connection using Fixed channels
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_write_fixed(tBTA_JV_MSG* p_data) {
+/* Write data to an L2CAP connection using Fixed channels */
+void bta_jv_l2cap_write_fixed(uint16_t channel, const RawAddress& addr,
+                              uint32_t req_id, BT_HDR* msg, uint32_t user_id,
+                              tBTA_JV_L2CAP_CBACK* p_cback) {
   tBTA_JV_L2CAP_WRITE_FIXED evt_data;
-  tBTA_JV_API_L2CAP_WRITE_FIXED* ls = &(p_data->l2cap_write_fixed);
-  BT_HDR* msg =
-      (BT_HDR*)osi_malloc(sizeof(BT_HDR) + ls->len + L2CAP_MIN_OFFSET);
-
   evt_data.status = BTA_JV_FAILURE;
-  evt_data.channel = ls->channel;
-  evt_data.addr = ls->addr;
-  evt_data.req_id = ls->req_id;
-  evt_data.p_data = ls->p_data;
+  evt_data.channel = channel;
+  evt_data.addr = addr;
+  evt_data.req_id = req_id;
   evt_data.len = 0;
 
-  memcpy(((uint8_t*)(msg + 1)) + L2CAP_MIN_OFFSET, ls->p_data, ls->len);
-  msg->len = ls->len;
-  msg->offset = L2CAP_MIN_OFFSET;
-
-  L2CA_SendFixedChnlData(ls->channel, ls->addr, msg);
+  L2CA_SendFixedChnlData(channel, addr, msg);
 
   tBTA_JV bta_jv;
   bta_jv.l2c_write_fixed = evt_data;
-  ls->p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, &bta_jv, ls->user_id);
+  p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, &bta_jv, user_id);
 }
 
 /*******************************************************************************
@@ -1428,8 +1222,8 @@
                                      uint16_t len, int type) {
   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);
-  APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb,
-                   p_pcb, len, type);
+  VLOG(2) << __func__ << ": p_cb=" << p_cb << ", p_pcb=" << p_pcb
+          << ", len=" << len << ", type=" << type;
   if (p_pcb != NULL) {
     switch (type) {
       case DATA_CO_CALLBACK_TYPE_INCOMING:
@@ -1439,7 +1233,7 @@
       case DATA_CO_CALLBACK_TYPE_OUTGOING:
         return bta_co_rfc_data_outgoing(p_pcb->rfcomm_slot_id, buf, len);
       default:
-        APPL_TRACE_ERROR("unknown callout type:%d", type);
+        LOG(ERROR) << __func__ << ": unknown callout type=" << type;
         break;
     }
   }
@@ -1464,12 +1258,11 @@
   uint16_t lcid;
   tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
 
-  APPL_TRACE_DEBUG("bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code,
-                   port_handle);
+  VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle;
   if (NULL == p_cb || NULL == p_cb->p_cback) return;
 
-  APPL_TRACE_DEBUG("bta_jv_port_mgmt_cl_cback code=%d port_handle:%d handle:%d",
-                   code, port_handle, p_cb->handle);
+  VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle
+          << ", handle=" << p_cb->handle;
 
   PORT_CheckConnection(port_handle, rem_bda, &lcid);
 
@@ -1509,12 +1302,11 @@
   tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
   tBTA_JV evt_data;
 
-  APPL_TRACE_DEBUG("bta_jv_port_event_cl_cback:%d", port_handle);
+  VLOG(2) << __func__ << ": port_handle=" << port_handle;
   if (NULL == p_cb || NULL == p_cb->p_cback) return;
 
-  APPL_TRACE_DEBUG(
-      "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d", code,
-      port_handle, p_cb->handle);
+  VLOG(2) << __func__ << ": code=" << loghex(code)
+          << ", port_handle=" << port_handle << ", handle=" << p_cb->handle;
   if (code & PORT_EV_RXCHAR) {
     evt_data.data_ind.handle = p_cb->handle;
     p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, p_pcb->rfcomm_slot_id);
@@ -1533,57 +1325,50 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_rfcomm_connect
- *
- * Description  Client initiates an RFCOMM connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_rfcomm_connect(tBTA_JV_MSG* p_data) {
+/* Client initiates an RFCOMM connection */
+void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                           uint8_t remote_scn, const RawAddress& peer_bd_addr,
+                           tBTA_JV_RFCOMM_CBACK* p_cback,
+                           uint32_t rfcomm_slot_id) {
   uint16_t handle = 0;
   uint32_t event_mask = BTA_JV_RFC_EV_MASK;
   tPORT_STATE port_state;
-  uint8_t sec_id = 0;
-  tBTA_JV_RFC_CB* p_cb = NULL;
-  tBTA_JV_PCB* p_pcb;
-  tBTA_JV_API_RFCOMM_CONNECT* cc = &(p_data->rfcomm_connect);
-  tBTA_JV_RFCOMM_CL_INIT evt_data;
 
   /* TODO DM role manager
-  L2CA_SetDesireRole(cc->role);
+  L2CA_SetDesireRole(role);
   */
 
-  sec_id = bta_jv_alloc_sec_id();
+  uint8_t sec_id = bta_jv_alloc_sec_id();
+
+  tBTA_JV_RFCOMM_CL_INIT evt_data;
   memset(&evt_data, 0, sizeof(evt_data));
   evt_data.sec_id = sec_id;
   evt_data.status = BTA_JV_SUCCESS;
   if (0 == sec_id ||
-      BTM_SetSecurityLevel(true, "", sec_id, cc->sec_mask, BT_PSM_RFCOMM,
-                           BTM_SEC_PROTO_RFCOMM, cc->remote_scn) == false) {
+      !BTM_SetSecurityLevel(true, "", sec_id, sec_mask, BT_PSM_RFCOMM,
+                            BTM_SEC_PROTO_RFCOMM, remote_scn)) {
     evt_data.status = BTA_JV_FAILURE;
-    APPL_TRACE_ERROR(
-        "sec_id:%d is zero or BTM_SetSecurityLevel failed, remote_scn:%d",
-        sec_id, cc->remote_scn);
+    LOG(ERROR) << __func__ << ": sec_id=" << +sec_id
+               << " is zero or BTM_SetSecurityLevel failed, remote_scn:"
+               << +remote_scn;
   }
 
   if (evt_data.status == BTA_JV_SUCCESS &&
-      RFCOMM_CreateConnection(UUID_SERVCLASS_SERIAL_PORT, cc->remote_scn, false,
-                              BTA_JV_DEF_RFC_MTU, cc->peer_bd_addr, &handle,
+      RFCOMM_CreateConnection(UUID_SERVCLASS_SERIAL_PORT, remote_scn, false,
+                              BTA_JV_DEF_RFC_MTU, peer_bd_addr, &handle,
                               bta_jv_port_mgmt_cl_cback) != PORT_SUCCESS) {
-    APPL_TRACE_ERROR("bta_jv_rfcomm_connect, RFCOMM_CreateConnection failed");
+    LOG(ERROR) << __func__ << ": RFCOMM_CreateConnection failed";
     evt_data.status = BTA_JV_FAILURE;
   }
   if (evt_data.status == BTA_JV_SUCCESS) {
-    p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+    tBTA_JV_PCB* p_pcb;
+    tBTA_JV_RFC_CB* p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
     if (p_cb) {
-      p_cb->p_cback = cc->p_cback;
+      p_cb->p_cback = p_cback;
       p_cb->sec_id = sec_id;
       p_cb->scn = 0;
       p_pcb->state = BTA_JV_ST_CL_OPENING;
-      p_pcb->rfcomm_slot_id = cc->rfcomm_slot_id;
+      p_pcb->rfcomm_slot_id = rfcomm_slot_id;
       evt_data.use_co = true;
 
       PORT_SetEventCallback(handle, bta_jv_port_event_cl_cback);
@@ -1599,12 +1384,12 @@
       evt_data.handle = p_cb->handle;
     } else {
       evt_data.status = BTA_JV_FAILURE;
-      APPL_TRACE_ERROR("run out of rfc control block");
+      LOG(ERROR) << __func__ << ": run out of rfc control block";
     }
   }
   tBTA_JV bta_jv;
   bta_jv.rfc_cl_init = evt_data;
-  cc->p_cback(BTA_JV_RFCOMM_CL_INIT_EVT, &bta_jv, cc->rfcomm_slot_id);
+  p_cback(BTA_JV_RFCOMM_CL_INIT_EVT, &bta_jv, rfcomm_slot_id);
   if (bta_jv.rfc_cl_init.status == BTA_JV_FAILURE) {
     if (sec_id) bta_jv_free_sec_id(&sec_id);
     if (handle) RFCOMM_RemoveConnection(handle);
@@ -1622,41 +1407,34 @@
     if (rfc_handle && bta_jv_cb.port_cb[i].rfcomm_slot_id == rfcomm_slot_id) {
       *pcb = &bta_jv_cb.port_cb[i];
       *cb = &bta_jv_cb.rfc_cb[rfc_handle - 1];
-      APPL_TRACE_DEBUG(
-          "find_rfc_pcb(): FOUND rfc_cb_handle 0x%x, port.jv_handle:"
-          " 0x%x, state: %d, rfc_cb->handle: 0x%x",
-          rfc_handle, (*pcb)->handle, (*pcb)->state, (*cb)->handle);
+      VLOG(2) << __func__ << ": FOUND rfc_cb_handle=" << loghex(rfc_handle)
+              << ", port.jv_handle=" << loghex((*pcb)->handle)
+              << ", state=" << (*pcb)->state
+              << ", rfc_cb->handle=" << loghex((*cb)->handle);
       return 1;
     }
   }
-  APPL_TRACE_DEBUG("find_rfc_pcb: cannot find rfc_cb from user data: %u",
-                   rfcomm_slot_id);
+  VLOG(2) << __func__
+          << ": cannot find rfc_cb from user data:" << rfcomm_slot_id;
   return 0;
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_rfcomm_close
- *
- * Description  Close an RFCOMM connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_rfcomm_close(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_RFCOMM_CLOSE* cc = &(p_data->rfcomm_close);
-  tBTA_JV_RFC_CB* p_cb = NULL;
-  tBTA_JV_PCB* p_pcb = NULL;
-  APPL_TRACE_DEBUG("bta_jv_rfcomm_close, rfc handle:%d", cc->handle);
-  if (!cc->handle) {
-    APPL_TRACE_ERROR("bta_jv_rfcomm_close, rfc handle is null");
+/* Close an RFCOMM connection */
+void bta_jv_rfcomm_close(uint32_t handle, uint32_t rfcomm_slot_id) {
+  if (!handle) {
+    LOG(ERROR) << __func__ << ": rfc handle is null";
     return;
   }
 
-  if (!find_rfc_pcb(cc->rfcomm_slot_id, &p_cb, &p_pcb)) return;
+  VLOG(2) << __func__ << ": rfc handle=" << handle;
+
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb = NULL;
+
+  if (!find_rfc_pcb(rfcomm_slot_id, &p_cb, &p_pcb)) return;
   bta_jv_free_rfc_cb(p_cb, p_pcb);
-  APPL_TRACE_DEBUG("bta_jv_rfcomm_close: sec id in use:%d, rfc_cb in use:%d",
-                   get_sec_id_used(), get_rfc_cb_used());
+  VLOG(2) << __func__ << ": sec id in use=" << get_sec_id_used()
+          << ", rfc_cb in use=" << get_rfc_cb_used();
 }
 
 /*******************************************************************************
@@ -1675,18 +1453,17 @@
   tBTA_JV evt_data;
   RawAddress rem_bda;
   uint16_t lcid;
-  APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:%d, port_handle:%d", code,
-                   port_handle);
+  VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle;
   if (NULL == p_cb || NULL == p_cb->p_cback) {
-    APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
-                     p_cb, p_cb ? p_cb->p_cback : NULL);
+    LOG(ERROR) << __func__ << ": p_cb=" << p_cb
+               << ", p_cb->p_cback=" << (p_cb ? p_cb->p_cback : 0);
     return;
   }
   uint32_t rfcomm_slot_id = p_pcb->rfcomm_slot_id;
-  APPL_TRACE_DEBUG(
-      "bta_jv_port_mgmt_sr_cback code=%d port_handle:0x%x handle:0x%x, "
-      "p_pcb:%p, user:%d",
-      code, port_handle, p_cb->handle, p_pcb, p_pcb->rfcomm_slot_id);
+  VLOG(2) << __func__ << ": code=" << code
+          << ", port_handle=" << loghex(port_handle)
+          << ", handle=" << loghex(p_cb->handle) << ", p_pcb" << p_pcb
+          << ", user=" << p_pcb->rfcomm_slot_id;
 
   PORT_CheckConnection(port_handle, rem_bda, &lcid);
   int failed = true;
@@ -1699,11 +1476,11 @@
       evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle;
       p_pcb_new_listen->rfcomm_slot_id =
           p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, rfcomm_slot_id);
-      APPL_TRACE_DEBUG("PORT_SUCCESS: curr_sess:%d, max_sess:%d",
-                       p_cb->curr_sess, p_cb->max_sess);
+      VLOG(2) << __func__ << ": curr_sess=" << p_cb->curr_sess
+              << ", max_sess=" << p_cb->max_sess;
       failed = false;
     } else
-      APPL_TRACE_ERROR("bta_jv_add_rfc_port failed to create new listen port");
+      LOG(ERROR) << __func__ << ": failed to create new listen port";
   }
   if (failed) {
     evt_data.rfc_close.handle = p_cb->handle;
@@ -1713,9 +1490,9 @@
     p_pcb->cong = false;
 
     tBTA_JV_RFCOMM_CBACK* p_cback = p_cb->p_cback;
-    APPL_TRACE_DEBUG(
-        "PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
-        p_cb->curr_sess, p_cb->max_sess);
+    VLOG(2) << __func__
+            << ": PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess="
+            << p_cb->curr_sess << ", max_sess=" << p_cb->max_sess;
     if (BTA_JV_ST_SR_CLOSING == p_pcb->state) {
       evt_data.rfc_close.async = false;
       evt_data.rfc_close.status = BTA_JV_SUCCESS;
@@ -1724,9 +1501,9 @@
     p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, rfcomm_slot_id);
     // bta_jv_free_rfc_cb(p_cb, p_pcb);
 
-    APPL_TRACE_DEBUG(
-        "PORT_CLOSED after BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
-        p_cb->curr_sess, p_cb->max_sess);
+    VLOG(2) << __func__
+            << ": PORT_CLOSED after BTA_JV_RFCOMM_CLOSE_EVT: curr_sess="
+            << p_cb->curr_sess << ", max_sess=" << p_cb->max_sess;
   }
 }
 
@@ -1746,9 +1523,8 @@
 
   if (NULL == p_cb || NULL == p_cb->p_cback) return;
 
-  APPL_TRACE_DEBUG(
-      "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d", code,
-      port_handle, p_cb->handle);
+  VLOG(2) << __func__ << ": code=" << loghex(code)
+          << ", port_handle=" << port_handle << ", handle=" << p_cb->handle;
 
   uint32_t user_data = p_pcb->rfcomm_slot_id;
   if (code & PORT_EV_RXCHAR) {
@@ -1792,17 +1568,15 @@
         if (p_pcb->state == BTA_JV_ST_SR_LISTEN) {
           listen++;
           if (p_pcb_open == p_pcb) {
-            APPL_TRACE_DEBUG(
-                "bta_jv_add_rfc_port, port_handle:%d, change the listen port "
-                "to open state",
-                p_pcb->port_handle);
+            VLOG(2) << __func__ << ": port_handle=" << p_pcb->port_handle
+                    << ", change the listen port to open state";
             p_pcb->state = BTA_JV_ST_SR_OPEN;
 
           } else {
-            APPL_TRACE_ERROR(
-                "bta_jv_add_rfc_port, open pcb not matching listen one,"
-                "listen count:%d, listen pcb handle:%d, open pcb:%d",
-                listen, p_pcb->port_handle, p_pcb_open->handle);
+            LOG(ERROR) << __func__
+                       << ": open pcb not matching listen one, count=" << listen
+                       << ", listen pcb handle=" << p_pcb->port_handle
+                       << ", open pcb=" << p_pcb_open->handle;
             return NULL;
           }
         }
@@ -1812,9 +1586,9 @@
       }
     }
 
-    APPL_TRACE_DEBUG(
-        "bta_jv_add_rfc_port max_sess=%d used:%d curr_sess:%d, listen:%d si:%d",
-        p_cb->max_sess, used, p_cb->curr_sess, listen, si);
+    VLOG(2) << __func__ << ": max_sess=" << p_cb->max_sess << ", used=" << used
+            << ", curr_sess=" << p_cb->curr_sess << ", listen=" << listen
+            << ", si=" << si;
     if (used < p_cb->max_sess && listen == 1 && si) {
       si--;
       if (RFCOMM_CreateConnection(p_cb->sec_id, p_cb->scn, true,
@@ -1837,80 +1611,69 @@
 
         PORT_SetState(p_pcb->port_handle, &port_state);
         p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si);
-        APPL_TRACE_DEBUG(
-            "bta_jv_add_rfc_port: p_pcb->handle:0x%x, curr_sess:%d",
-            p_pcb->handle, p_cb->curr_sess);
+        VLOG(2) << __func__ << ": p_pcb->handle=" << loghex(p_pcb->handle)
+                << ", curr_sess=" << p_cb->curr_sess;
       }
-    } else
-      APPL_TRACE_ERROR(
-          "bta_jv_add_rfc_port, cannot create new rfc listen port");
+    } else {
+      LOG(ERROR) << __func__ << ": cannot create new rfc listen port";
+      return NULL;
+    }
   }
-  APPL_TRACE_DEBUG("bta_jv_add_rfc_port: sec id in use:%d, rfc_cb in use:%d",
-                   get_sec_id_used(), get_rfc_cb_used());
+  VLOG(2) << __func__ << ": sec id in use=" << get_sec_id_used()
+          << ", rfc_cb in use=" << get_rfc_cb_used();
   return p_pcb;
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_rfcomm_start_server
- *
- * Description  waits for an RFCOMM client to connect
- *
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_rfcomm_start_server(tBTA_JV_MSG* p_data) {
+/* waits for an RFCOMM client to connect */
+void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                uint8_t local_scn, uint8_t max_session,
+                                tBTA_JV_RFCOMM_CBACK* p_cback,
+                                uint32_t rfcomm_slot_id) {
   uint16_t handle = 0;
   uint32_t event_mask = BTA_JV_RFC_EV_MASK;
   tPORT_STATE port_state;
   uint8_t sec_id = 0;
   tBTA_JV_RFC_CB* p_cb = NULL;
   tBTA_JV_PCB* p_pcb;
-  tBTA_JV_API_RFCOMM_SERVER* rs = &(p_data->rfcomm_server);
   tBTA_JV_RFCOMM_START evt_data;
 
   /* TODO DM role manager
-  L2CA_SetDesireRole(rs->role);
+  L2CA_SetDesireRole(role);
   */
   memset(&evt_data, 0, sizeof(evt_data));
   evt_data.status = BTA_JV_FAILURE;
-  APPL_TRACE_DEBUG(
-      "bta_jv_rfcomm_start_server: sec id in use:%d, rfc_cb in use:%d",
-      get_sec_id_used(), get_rfc_cb_used());
+  VLOG(2) << __func__ << ": sec id in use=" << get_sec_id_used()
+          << ", rfc_cb in use=" << get_rfc_cb_used();
 
   do {
     sec_id = bta_jv_alloc_sec_id();
 
     if (0 == sec_id ||
-        BTM_SetSecurityLevel(false, "JV PORT", sec_id, rs->sec_mask,
-                             BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
-                             rs->local_scn) == false) {
-      APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of sec_id");
+        !BTM_SetSecurityLevel(false, "JV PORT", sec_id, sec_mask, BT_PSM_RFCOMM,
+                              BTM_SEC_PROTO_RFCOMM, local_scn)) {
+      LOG(ERROR) << __func__ << ": run out of sec_id";
       break;
     }
 
-    if (RFCOMM_CreateConnection(sec_id, rs->local_scn, true, BTA_JV_DEF_RFC_MTU,
+    if (RFCOMM_CreateConnection(sec_id, local_scn, true, BTA_JV_DEF_RFC_MTU,
                                 RawAddress::kAny, &handle,
                                 bta_jv_port_mgmt_sr_cback) != PORT_SUCCESS) {
-      APPL_TRACE_ERROR(
-          "bta_jv_rfcomm_start_server, RFCOMM_CreateConnection failed");
+      LOG(ERROR) << __func__ << ": RFCOMM_CreateConnection failed";
       break;
     }
 
     p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
     if (!p_cb) {
-      APPL_TRACE_ERROR(
-          "bta_jv_rfcomm_start_server, run out of rfc control block");
+      LOG(ERROR) << __func__ << ": run out of rfc control block";
       break;
     }
 
-    p_cb->max_sess = rs->max_session;
-    p_cb->p_cback = rs->p_cback;
+    p_cb->max_sess = max_session;
+    p_cb->p_cback = p_cback;
     p_cb->sec_id = sec_id;
-    p_cb->scn = rs->local_scn;
+    p_cb->scn = local_scn;
     p_pcb->state = BTA_JV_ST_SR_LISTEN;
-    p_pcb->rfcomm_slot_id = rs->rfcomm_slot_id;
+    p_pcb->rfcomm_slot_id = rfcomm_slot_id;
     evt_data.status = BTA_JV_SUCCESS;
     evt_data.handle = p_cb->handle;
     evt_data.sec_id = sec_id;
@@ -1928,7 +1691,7 @@
 
   tBTA_JV bta_jv;
   bta_jv.rfc_start = evt_data;
-  rs->p_cback(BTA_JV_RFCOMM_START_EVT, &bta_jv, rs->rfcomm_slot_id);
+  p_cback(BTA_JV_RFCOMM_START_EVT, &bta_jv, rfcomm_slot_id);
   if (bta_jv.rfc_start.status == BTA_JV_SUCCESS) {
     PORT_SetDataCOCallback(handle, bta_jv_port_data_co_cback);
   } else {
@@ -1937,58 +1700,37 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_rfcomm_stop_server
- *
- * Description  stops an RFCOMM server
- *
- * Returns      void
- *
- ******************************************************************************/
-
-void bta_jv_rfcomm_stop_server(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_RFCOMM_SERVER* ls = &(p_data->rfcomm_server);
-  tBTA_JV_RFC_CB* p_cb = NULL;
-  tBTA_JV_PCB* p_pcb = NULL;
-  APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server");
-  if (!ls->handle) {
-    APPL_TRACE_ERROR("bta_jv_rfcomm_stop_server, jv handle is null");
+/* stops an RFCOMM server */
+void bta_jv_rfcomm_stop_server(uint32_t handle, uint32_t rfcomm_slot_id) {
+  if (!handle) {
+    LOG(ERROR) << __func__ << ": jv handle is null";
     return;
   }
 
-  if (!find_rfc_pcb(ls->rfcomm_slot_id, &p_cb, &p_pcb)) return;
-  APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: p_pcb:%p, p_pcb->port_handle:%d",
-                   p_pcb, p_pcb->port_handle);
+  VLOG(2) << __func__;
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb = NULL;
+
+  if (!find_rfc_pcb(rfcomm_slot_id, &p_cb, &p_pcb)) return;
+  VLOG(2) << __func__ << ": p_pcb=" << p_pcb
+          << ", p_pcb->port_handle=" << p_pcb->port_handle;
   bta_jv_free_rfc_cb(p_cb, p_pcb);
-  APPL_TRACE_DEBUG(
-      "bta_jv_rfcomm_stop_server: sec id in use:%d, rfc_cb in use:%d",
-      get_sec_id_used(), get_rfc_cb_used());
+  VLOG(2) << __func__ << ": sec id in use=" << get_sec_id_used()
+          << ", rfc_cb in use=" << get_rfc_cb_used();
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_rfcomm_write
- *
- * Description  write data to an RFCOMM connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_rfcomm_write(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_RFCOMM_WRITE* wc = &(p_data->rfcomm_write);
-  tBTA_JV_RFC_CB* p_cb = wc->p_cb;
-  tBTA_JV_PCB* p_pcb = wc->p_pcb;
-
+/* write data to an RFCOMM connection */
+void bta_jv_rfcomm_write(uint32_t handle, uint32_t req_id, tBTA_JV_RFC_CB* p_cb,
+                         tBTA_JV_PCB* p_pcb) {
   if (p_pcb->state == BTA_JV_ST_NONE) {
-    APPL_TRACE_ERROR("%s in state BTA_JV_ST_NONE - cannot write", __func__);
+    LOG(ERROR) << __func__ << ": in state BTA_JV_ST_NONE - cannot write";
     return;
   }
 
   tBTA_JV_RFCOMM_WRITE evt_data;
   evt_data.status = BTA_JV_FAILURE;
-  evt_data.handle = p_cb->handle;
-  evt_data.req_id = wc->req_id;
+  evt_data.handle = handle;
+  evt_data.req_id = req_id;
   evt_data.cong = p_pcb->cong;
   evt_data.len = 0;
 
@@ -2002,101 +1744,45 @@
   // Update congestion flag
   evt_data.cong = p_pcb->cong;
 
-  if (p_cb->p_cback) {
-    tBTA_JV bta_jv;
-    bta_jv.rfc_write = evt_data;
-    p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, &bta_jv, p_pcb->rfcomm_slot_id);
-  } else {
-    APPL_TRACE_ERROR("%s No JV callback set", __func__);
+  if (!p_cb->p_cback) {
+    LOG(ERROR) << __func__ << ": No JV callback set";
+    return;
   }
+
+  tBTA_JV bta_jv;
+  bta_jv.rfc_write = evt_data;
+  p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, &bta_jv, p_pcb->rfcomm_slot_id);
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_set_pm_profile
- *
- * Description  Set or free power mode profile for a JV application
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_set_pm_profile(tBTA_JV_MSG* p_data) {
+/* Set or free power mode profile for a JV application */
+void bta_jv_set_pm_profile(uint32_t handle, tBTA_JV_PM_ID app_id,
+                           tBTA_JV_CONN_STATE init_st) {
   tBTA_JV_STATUS status;
   tBTA_JV_PM_CB* p_cb;
 
-  APPL_TRACE_API("bta_jv_set_pm_profile(handle: 0x%x, app_id: %d, init_st: %d)",
-                 p_data->set_pm.handle, p_data->set_pm.app_id,
-                 p_data->set_pm.init_st);
+  VLOG(2) << __func__ << " handle=" << loghex(handle) << ", app_id=" << app_id
+          << ", init_st=" << +init_st;
 
   /* clear PM control block */
-  if (p_data->set_pm.app_id == BTA_JV_PM_ID_CLEAR) {
-    status = bta_jv_free_set_pm_profile_cb(p_data->set_pm.handle);
+  if (app_id == BTA_JV_PM_ID_CLEAR) {
+    status = bta_jv_free_set_pm_profile_cb(handle);
 
     if (status != BTA_JV_SUCCESS) {
-      APPL_TRACE_WARNING("bta_jv_set_pm_profile() free pm cb failed: reason %d",
-                         status);
+      LOG(WARNING) << __func__ << ": free pm cb failed: reason=" << +status;
     }
   } else /* set PM control block */
   {
-    p_cb = bta_jv_alloc_set_pm_profile_cb(p_data->set_pm.handle,
-                                          p_data->set_pm.app_id);
+    p_cb = bta_jv_alloc_set_pm_profile_cb(handle, app_id);
 
     if (NULL != p_cb)
-      bta_jv_pm_state_change(p_cb, p_data->set_pm.init_st);
+      bta_jv_pm_state_change(p_cb, init_st);
     else
-      APPL_TRACE_WARNING("bta_jv_alloc_set_pm_profile_cb() failed");
+      LOG(WARNING) << __func__ << ": failed";
   }
 }
 
 /*******************************************************************************
  *
- * Function     bta_jv_change_pm_state
- *
- * Description  change jv pm connect state, used internally
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_change_pm_state(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_PM_STATE_CHANGE* p_msg = (tBTA_JV_API_PM_STATE_CHANGE*)p_data;
-
-  if (p_msg->p_cb) bta_jv_pm_state_change(p_msg->p_cb, p_msg->state);
-}
-
-/*******************************************************************************
- *
- * Function    bta_jv_set_pm_conn_state
- *
- * Description Send pm event state change to jv state machine to serialize jv pm
- *             changes in relation to other jv messages. internal API use
- *             mainly.
- *
- * Params:     p_cb: jv pm control block, NULL pointer returns failure
- *             new_state: new PM connections state, setting is forced by action
- *                        function
- *
- * Returns     BTA_JV_SUCCESS, BTA_JV_FAILURE (buffer allocation, or NULL ptr!)
- *
- ******************************************************************************/
-tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB* p_cb,
-                                        const tBTA_JV_CONN_STATE new_st) {
-  if (p_cb == NULL) return BTA_JV_FAILURE;
-
-  APPL_TRACE_API("%s: handle:0x%x, state: %d", __func__, p_cb->handle, new_st);
-
-  tBTA_JV_API_PM_STATE_CHANGE* p_msg = (tBTA_JV_API_PM_STATE_CHANGE*)osi_malloc(
-      sizeof(tBTA_JV_API_PM_STATE_CHANGE));
-  p_msg->hdr.event = BTA_JV_API_PM_STATE_CHANGE_EVT;
-  p_msg->p_cb = p_cb;
-  p_msg->state = new_st;
-
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
-}
-
-/*******************************************************************************
- *
  * Function    bta_jv_pm_conn_busy
  *
  * Description set pm connection busy state (input param safe)
@@ -2140,10 +1826,10 @@
  ******************************************************************************/
 static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb,
                                    const tBTA_JV_CONN_STATE state) {
-  APPL_TRACE_API(
-      "bta_jv_pm_state_change(p_cb: 0x%x, handle: 0x%x, busy/idle_state: %d"
-      ", app_id: %d, conn_state: %d)",
-      p_cb, p_cb->handle, p_cb->state, p_cb->app_id, state);
+  VLOG(2) << __func__ << ": p_cb=" << p_cb
+          << ", handle=" << loghex(p_cb->handle)
+          << ", busy/idle_state=" << p_cb->state << ", app_id=" << p_cb->app_id
+          << ", conn_state=" << state;
 
   switch (state) {
     case BTA_JV_CONN_OPEN:
@@ -2181,8 +1867,7 @@
       break;
 
     default:
-      APPL_TRACE_WARNING("bta_jv_pm_state_change(state: %d): Invalid state",
-                         state);
+      LOG(WARNING) << __func__ << ": Invalid state=" << +state;
       break;
   }
 }
@@ -2439,17 +2124,11 @@
   if (sock_cback) sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_id);
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_connect_le
- *
- * Description  makes an le l2cap client connection
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_connect_le(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_L2CAP_CONNECT* cc = &(p_data->l2cap_connect);
+/** makes an le l2cap client connection */
+void bta_jv_l2cap_connect_le(uint16_t remote_chan,
+                             const RawAddress& peer_bd_addr,
+                             tBTA_JV_L2CAP_CBACK* p_cback,
+                             uint32_t l2cap_socket_id) {
   tBTA_JV evt;
   uint32_t id;
   char call_init_f = true;
@@ -2458,15 +2137,15 @@
   evt.l2c_cl_init.handle = GAP_INVALID_HANDLE;
   evt.l2c_cl_init.status = BTA_JV_FAILURE;
 
-  t = fcclient_alloc(cc->remote_chan, false, NULL);
+  t = fcclient_alloc(remote_chan, false, NULL);
   if (!t) {
-    cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->l2cap_socket_id);
+    p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, l2cap_socket_id);
     return;
   }
 
-  t->p_cback = cc->p_cback;
-  t->l2cap_socket_id = cc->l2cap_socket_id;
-  t->remote_addr = cc->peer_bd_addr;
+  t->p_cback = p_cback;
+  t->l2cap_socket_id = l2cap_socket_id;
+  t->remote_addr = peer_bd_addr;
   id = t->id;
   t->init_called = false;
 
@@ -2483,37 +2162,24 @@
     else
       fcclient_free(t);
   }
-  if (call_init_f)
-    cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->l2cap_socket_id);
+  if (call_init_f) p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, l2cap_socket_id);
   t->init_called = true;
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_stop_server_le
- *
- * Description  stops an LE L2CAP server
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG* p_data) {
-  tBTA_JV evt;
-  tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
-  tBTA_JV_L2CAP_CBACK* p_cback = NULL;
-  struct fc_channel* fcchan;
+/* stops an LE L2CAP server */
+void bta_jv_l2cap_stop_server_le(uint16_t local_chan) {
   struct fc_client* fcclient;
-  uint32_t l2cap_socket_id;
 
+  tBTA_JV evt;
   evt.l2c_close.status = BTA_JV_FAILURE;
   evt.l2c_close.async = false;
   evt.l2c_close.handle = GAP_INVALID_HANDLE;
 
-  fcchan = fcchan_get(ls->local_chan, false);
+  struct fc_channel* fcchan = fcchan_get(local_chan, false);
   if (fcchan) {
     while ((fcclient = fcchan->clients)) {
-      p_cback = fcclient->p_cback;
-      l2cap_socket_id = fcclient->l2cap_socket_id;
+      tBTA_JV_L2CAP_CBACK* p_cback = fcclient->p_cback;
+      uint32_t l2cap_socket_id = fcclient->l2cap_socket_id;
 
       evt.l2c_close.handle = fcclient->id;
       evt.l2c_close.status = BTA_JV_SUCCESS;
@@ -2526,28 +2192,19 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_start_server_le
- *
- * Description  starts an LE L2CAP server
- *
- * Returns      void
- *
- ******************************************************************************/
-void bta_jv_l2cap_start_server_le(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_L2CAP_SERVER* ss = &(p_data->l2cap_server);
+/** starts an LE L2CAP server */
+void bta_jv_l2cap_start_server_le(uint16_t local_chan,
+                                  tBTA_JV_L2CAP_CBACK* p_cback,
+                                  uint32_t l2cap_socket_id) {
   tBTA_JV_L2CAP_START evt_data;
-  struct fc_client* t;
-
   evt_data.handle = GAP_INVALID_HANDLE;
   evt_data.status = BTA_JV_FAILURE;
 
-  t = fcclient_alloc(ss->local_chan, true, NULL);
+  struct fc_client* t = fcclient_alloc(local_chan, true, NULL);
   if (!t) goto out;
 
-  t->p_cback = ss->p_cback;
-  t->l2cap_socket_id = ss->l2cap_socket_id;
+  t->p_cback = p_cback;
+  t->l2cap_socket_id = l2cap_socket_id;
 
   // if we got here, we're registered...
   evt_data.status = BTA_JV_SUCCESS;
@@ -2557,22 +2214,11 @@
 out:
   tBTA_JV bta_jv;
   bta_jv.l2c_start = evt_data;
-  ss->p_cback(BTA_JV_L2CAP_START_EVT, &bta_jv, ss->l2cap_socket_id);
+  p_cback(BTA_JV_L2CAP_START_EVT, &bta_jv, l2cap_socket_id);
 }
 
-/*******************************************************************************
- *
- * Function     bta_jv_l2cap_close_fixed
- *
- * Description  close a fixed channel connection. calls no callbacks. idempotent
- *
- * Returns      void
- *
- ******************************************************************************/
-extern void bta_jv_l2cap_close_fixed(tBTA_JV_MSG* p_data) {
-  tBTA_JV_API_L2CAP_CLOSE* cc = &(p_data->l2cap_close);
-  struct fc_client* t;
-
-  t = fcclient_find_by_id(cc->handle);
+/* close a fixed channel connection. calls no callbacks. idempotent */
+extern void bta_jv_l2cap_close_fixed(uint32_t handle) {
+  struct fc_client* t = fcclient_find_by_id(handle);
   if (t) fcclient_free(t);
 }
diff --git a/bta/jv/bta_jv_api.cc b/bta/jv/bta_jv_api.cc
index 0478a3b..74818b6 100644
--- a/bta/jv/bta_jv_api.cc
+++ b/bta/jv/bta_jv_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,10 +22,14 @@
  *  Technology (JABWT) as specified by the JSR82 specificiation
  *
  ******************************************************************************/
+#include <base/bind.h>
+#include <base/bind_helpers.h>
+#include <base/logging.h>
 #include <string.h>
 
 #include "bt_common.h"
 #include "bta_api.h"
+#include "bta_closure_api.h"
 #include "bta_jv_api.h"
 #include "bta_jv_int.h"
 #include "bta_sys.h"
@@ -34,11 +38,12 @@
 #include "sdp_api.h"
 #include "utl.h"
 
-/*****************************************************************************
- *  Constants
- ****************************************************************************/
+using base::Bind;
+using bluetooth::Uuid;
 
-static const tBTA_SYS_REG bta_jv_reg = {bta_jv_sm_execute, NULL};
+namespace {
+bool bta_jv_enabled = false;
+}
 
 /*******************************************************************************
  *
@@ -55,52 +60,32 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK* p_cback) {
-  tBTA_JV_STATUS status = BTA_JV_FAILURE;
-  int i;
-
-  APPL_TRACE_API("BTA_JvEnable");
-  if (p_cback && false == bta_sys_is_register(BTA_ID_JV)) {
-    memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB));
-    /* set handle to invalid value by default */
-    for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
-      bta_jv_cb.pm_cb[i].handle = BTA_JV_PM_HANDLE_CLEAR;
-    }
-
-    /* register with BTA system manager */
-    bta_sys_register(BTA_ID_JV, &bta_jv_reg);
-
-    if (p_cback) {
-      tBTA_JV_API_ENABLE* p_buf =
-          (tBTA_JV_API_ENABLE*)osi_malloc(sizeof(tBTA_JV_API_ENABLE));
-      p_buf->hdr.event = BTA_JV_API_ENABLE_EVT;
-      p_buf->p_cback = p_cback;
-      bta_sys_sendmsg(p_buf);
-      status = BTA_JV_SUCCESS;
-    }
-  } else {
-    APPL_TRACE_ERROR("JVenable fails");
+  if (!p_cback || bta_jv_enabled) {
+    LOG(ERROR) << __func__ << ": failure";
+    return BTA_JV_FAILURE;
   }
-  return (status);
+
+  VLOG(2) << __func__;
+
+  memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB));
+  /* set handle to invalid value by default */
+  for (int i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+    bta_jv_cb.pm_cb[i].handle = BTA_JV_PM_HANDLE_CLEAR;
+  }
+
+  bta_jv_enabled = true;
+
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_enable, p_cback));
+  return BTA_JV_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         BTA_JvDisable
- *
- * Description      Disable the Java I/F
- *
- * Returns          void
- *
- ******************************************************************************/
+/** Disable the Java I/F */
 void BTA_JvDisable(void) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
+  bta_jv_enabled = false;
 
-  bta_sys_deregister(BTA_ID_JV);
-  p_buf->event = BTA_JV_API_DISABLE_EVT;
-
-  bta_sys_sendmsg(p_buf);
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_disable));
 }
 
 /*******************************************************************************
@@ -143,32 +128,20 @@
  *   channel        Only used for RFCOMM - to try to allocate a specific RFCOMM
  *                  channel.
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ * Returns          void
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel) {
-  tBTA_JV_API_ALLOC_CHANNEL* p_msg =
-      (tBTA_JV_API_ALLOC_CHANNEL*)osi_malloc(sizeof(tBTA_JV_API_ALLOC_CHANNEL));
+void BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel) {
+  VLOG(2) << __func__ << ": conn_type=" << conn_type;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_GET_CHANNEL_EVT;
-  p_msg->type = conn_type;
-  p_msg->channel = channel;
-  if (conn_type == BTA_JV_CONN_TYPE_RFCOMM) {
-    p_msg->rfcomm_slot_id = id;
-  } else if (conn_type == BTA_JV_CONN_TYPE_L2CAP ||
-             conn_type == BTA_JV_CONN_TYPE_L2CAP_LE) {
-    p_msg->l2cap_socket_id = id;
-  } else {
-    APPL_TRACE_ERROR("%s: Invalid connection type");
-    return BTA_JV_FAILURE;
+  if (conn_type != BTA_JV_CONN_TYPE_RFCOMM &&
+      conn_type != BTA_JV_CONN_TYPE_L2CAP &&
+      conn_type != BTA_JV_CONN_TYPE_L2CAP_LE) {
+    CHECK(false) << "Invalid conn_type=" << conn_type;
   }
 
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_get_channel_id, conn_type, channel, id, id));
 }
 
 /*******************************************************************************
@@ -186,17 +159,9 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvFreeChannel(uint16_t channel, int conn_type) {
-  tBTA_JV_API_FREE_CHANNEL* p_msg =
-      (tBTA_JV_API_FREE_CHANNEL*)osi_malloc(sizeof(tBTA_JV_API_FREE_CHANNEL));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
-  p_msg->scn = channel;
-  p_msg->type = conn_type;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_free_scn, conn_type, channel));
   return BTA_JV_SUCCESS;
 }
 
@@ -214,22 +179,16 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvStartDiscovery(const RawAddress& bd_addr,
-                                    uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+                                    uint16_t num_uuid, const Uuid* p_uuid_list,
                                     uint32_t rfcomm_slot_id) {
-  tBTA_JV_API_START_DISCOVERY* p_msg = (tBTA_JV_API_START_DISCOVERY*)osi_malloc(
-      sizeof(tBTA_JV_API_START_DISCOVERY));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
+  Uuid* uuid_list_copy = new Uuid[num_uuid];
+  memcpy(uuid_list_copy, p_uuid_list, num_uuid * sizeof(Uuid));
 
-  p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT;
-  p_msg->bd_addr = bd_addr;
-  p_msg->num_uuid = num_uuid;
-  memcpy(p_msg->uuid_list, p_uuid_list, num_uuid * sizeof(tSDP_UUID));
-  p_msg->num_attr = 0;
-  p_msg->rfcomm_slot_id = rfcomm_slot_id;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_start_discovery, bd_addr, num_uuid,
+                        base::Owned(uuid_list_copy), rfcomm_slot_id));
   return BTA_JV_SUCCESS;
 }
 
@@ -246,16 +205,9 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvCreateRecordByUser(uint32_t rfcomm_slot_id) {
-  tBTA_JV_API_CREATE_RECORD* p_msg =
-      (tBTA_JV_API_CREATE_RECORD*)osi_malloc(sizeof(tBTA_JV_API_CREATE_RECORD));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_CREATE_RECORD_EVT;
-  p_msg->rfcomm_slot_id = rfcomm_slot_id;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_create_record, rfcomm_slot_id));
   return BTA_JV_SUCCESS;
 }
 
@@ -270,16 +222,9 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvDeleteRecord(uint32_t handle) {
-  tBTA_JV_API_ADD_ATTRIBUTE* p_msg =
-      (tBTA_JV_API_ADD_ATTRIBUTE*)osi_malloc(sizeof(tBTA_JV_API_ADD_ATTRIBUTE));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_DELETE_RECORD_EVT;
-  p_msg->handle = handle;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_delete_record, handle));
   return BTA_JV_SUCCESS;
 }
 
@@ -294,47 +239,14 @@
  *                  When the connection is established or failed,
  *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
- *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
-                                    const tL2CAP_ERTM_INFO* ertm_info,
-                                    uint16_t remote_chan, uint16_t rx_mtu,
-                                    tL2CAP_CFG_INFO* cfg,
-                                    const RawAddress& peer_bd_addr,
-                                    tBTA_JV_L2CAP_CBACK* p_cback,
-                                    uint32_t l2cap_socket_id) {
-  APPL_TRACE_API("%s", __func__);
-
-  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
-
-  tBTA_JV_API_L2CAP_CONNECT* p_msg =
-      (tBTA_JV_API_L2CAP_CONNECT*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT));
-  p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_LE_EVT;
-  p_msg->sec_mask = sec_mask;
-  p_msg->role = role;
-  p_msg->remote_chan = remote_chan;
-  p_msg->rx_mtu = rx_mtu;
-  if (cfg != NULL) {
-    p_msg->has_cfg = true;
-    p_msg->cfg = *cfg;
-  } else {
-    p_msg->has_cfg = false;
-  }
-  if (ertm_info != NULL) {
-    p_msg->has_ertm_info = true;
-    p_msg->ertm_info = *ertm_info;
-  } else {
-    p_msg->has_ertm_info = false;
-  }
-  p_msg->peer_bd_addr = peer_bd_addr;
-  p_msg->p_cback = p_cback;
-  p_msg->l2cap_socket_id = l2cap_socket_id;
-
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
+void BTA_JvL2capConnectLE(uint16_t remote_chan, const RawAddress& peer_bd_addr,
+                          tBTA_JV_L2CAP_CBACK* p_cback,
+                          uint32_t l2cap_socket_id) {
+  VLOG(2) << __func__;
+  CHECK(p_cback);
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_connect_le, remote_chan,
+                                   peer_bd_addr, p_cback, l2cap_socket_id));
 }
 
 /*******************************************************************************
@@ -348,46 +260,21 @@
  *                  When the connection is established or failed,
  *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
- *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capConnect(
-    int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
-    const tL2CAP_ERTM_INFO* ertm_info, uint16_t remote_psm, uint16_t rx_mtu,
-    tL2CAP_CFG_INFO* cfg, const RawAddress& peer_bd_addr,
-    tBTA_JV_L2CAP_CBACK* p_cback, uint32_t l2cap_socket_id) {
-  APPL_TRACE_API("%s", __func__);
+void BTA_JvL2capConnect(int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                        std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                        uint16_t remote_psm, uint16_t rx_mtu,
+                        std::unique_ptr<tL2CAP_CFG_INFO> cfg,
+                        const RawAddress& peer_bd_addr,
+                        tBTA_JV_L2CAP_CBACK* p_cback,
+                        uint32_t l2cap_socket_id) {
+  VLOG(2) << __func__;
+  CHECK(p_cback);
 
-  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
-
-  tBTA_JV_API_L2CAP_CONNECT* p_msg =
-      (tBTA_JV_API_L2CAP_CONNECT*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT));
-  p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_EVT;
-  p_msg->type = conn_type;
-  p_msg->sec_mask = sec_mask;
-  p_msg->role = role;
-  p_msg->remote_psm = remote_psm;
-  p_msg->rx_mtu = rx_mtu;
-  if (cfg != NULL) {
-    p_msg->has_cfg = true;
-    p_msg->cfg = *cfg;
-  } else {
-    p_msg->has_cfg = false;
-  }
-  if (ertm_info != NULL) {
-    p_msg->has_ertm_info = true;
-    p_msg->ertm_info = *ertm_info;
-  } else {
-    p_msg->has_ertm_info = false;
-  }
-  p_msg->peer_bd_addr = peer_bd_addr;
-  p_msg->p_cback = p_cback;
-  p_msg->l2cap_socket_id = l2cap_socket_id;
-
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_l2cap_connect, conn_type, sec_mask, role,
+                        remote_psm, rx_mtu, peer_bd_addr, base::Passed(&cfg),
+                        base::Passed(&ertm_info), p_cback, l2cap_socket_id));
 }
 
 /*******************************************************************************
@@ -401,22 +288,14 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvL2capClose(uint32_t handle) {
-  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
+  if (handle >= BTA_JV_MAX_L2C_CONN || !bta_jv_cb.l2c_cb[handle].p_cback)
+    return BTA_JV_FAILURE;
 
-  if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
-    tBTA_JV_API_L2CAP_CLOSE* p_msg =
-        (tBTA_JV_API_L2CAP_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE));
-    p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
-    p_msg->handle = handle;
-    p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
-
-    bta_sys_sendmsg(p_msg);
-    status = BTA_JV_SUCCESS;
-  }
-
-  return status;
+  do_in_bta_thread(
+      FROM_HERE, Bind(&bta_jv_l2cap_close, handle, &bta_jv_cb.l2c_cb[handle]));
+  return BTA_JV_SUCCESS;
 }
 
 /*******************************************************************************
@@ -431,16 +310,9 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvL2capCloseLE(uint32_t handle) {
-  tBTA_JV_API_L2CAP_CLOSE* p_msg =
-      (tBTA_JV_API_L2CAP_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_FIXED_EVT;
-  p_msg->handle = handle;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_close_fixed, handle));
   return BTA_JV_SUCCESS;
 }
 
@@ -455,47 +327,22 @@
  *                  established tBTA_JV_L2CAP_CBACK is called with
  *                  BTA_JV_L2CAP_OPEN_EVT.
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ * Returns          void
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capStartServer(int conn_type, tBTA_SEC sec_mask,
-                                      tBTA_JV_ROLE role,
-                                      const tL2CAP_ERTM_INFO* ertm_info,
-                                      uint16_t local_psm, uint16_t rx_mtu,
-                                      tL2CAP_CFG_INFO* cfg,
-                                      tBTA_JV_L2CAP_CBACK* p_cback,
-                                      uint32_t l2cap_socket_id) {
-  APPL_TRACE_API("%s", __func__);
+void BTA_JvL2capStartServer(int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                            std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                            uint16_t local_psm, uint16_t rx_mtu,
+                            std::unique_ptr<tL2CAP_CFG_INFO> cfg,
+                            tBTA_JV_L2CAP_CBACK* p_cback,
+                            uint32_t l2cap_socket_id) {
+  VLOG(2) << __func__;
+  CHECK(p_cback);
 
-  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
-
-  tBTA_JV_API_L2CAP_SERVER* p_msg =
-      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
-  p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT;
-  p_msg->type = conn_type;
-  p_msg->sec_mask = sec_mask;
-  p_msg->role = role;
-  p_msg->local_psm = local_psm;
-  p_msg->rx_mtu = rx_mtu;
-  if (cfg != NULL) {
-    p_msg->has_cfg = true;
-    p_msg->cfg = *cfg;
-  } else {
-    p_msg->has_cfg = false;
-  }
-  if (ertm_info != NULL) {
-    p_msg->has_ertm_info = true;
-    p_msg->ertm_info = *ertm_info;
-  } else {
-    p_msg->has_ertm_info = false;
-  }
-  p_msg->p_cback = p_cback;
-  p_msg->l2cap_socket_id = l2cap_socket_id;
-
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_l2cap_start_server, conn_type, sec_mask, role,
+                        local_psm, rx_mtu, base::Passed(&cfg),
+                        base::Passed(&ertm_info), p_cback, l2cap_socket_id));
 }
 
 /*******************************************************************************
@@ -509,45 +356,15 @@
  *                  established, tBTA_JV_L2CAP_CBACK is called with
  *                  BTA_JV_L2CAP_OPEN_EVT.
  *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ * Returns          void
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
-                                        const tL2CAP_ERTM_INFO* ertm_info,
-                                        uint16_t local_chan, uint16_t rx_mtu,
-                                        tL2CAP_CFG_INFO* cfg,
-                                        tBTA_JV_L2CAP_CBACK* p_cback,
-                                        uint32_t l2cap_socket_id) {
-  APPL_TRACE_API("%s", __func__);
-
-  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
-
-  tBTA_JV_API_L2CAP_SERVER* p_msg =
-      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
-  p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_LE_EVT;
-  p_msg->sec_mask = sec_mask;
-  p_msg->role = role;
-  p_msg->local_chan = local_chan;
-  p_msg->rx_mtu = rx_mtu;
-  if (cfg != NULL) {
-    p_msg->has_cfg = true;
-    p_msg->cfg = *cfg;
-  } else {
-    p_msg->has_cfg = false;
-  }
-  if (ertm_info != NULL) {
-    p_msg->has_ertm_info = true;
-    p_msg->ertm_info = *ertm_info;
-  } else {
-    p_msg->has_ertm_info = false;
-  }
-  p_msg->p_cback = p_cback;
-  p_msg->l2cap_socket_id = l2cap_socket_id;
-
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
+void BTA_JvL2capStartServerLE(uint16_t local_chan, tBTA_JV_L2CAP_CBACK* p_cback,
+                              uint32_t l2cap_socket_id) {
+  VLOG(2) << __func__;
+  CHECK(p_cback);
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_start_server_le, local_chan,
+                                   p_cback, l2cap_socket_id));
 }
 
 /*******************************************************************************
@@ -563,16 +380,10 @@
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvL2capStopServer(uint16_t local_psm,
                                      uint32_t l2cap_socket_id) {
-  APPL_TRACE_API("%s", __func__);
+  VLOG(2) << __func__;
 
-  tBTA_JV_API_L2CAP_SERVER* p_msg =
-      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
-  p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT;
-  p_msg->local_psm = local_psm;
-  p_msg->l2cap_socket_id = l2cap_socket_id;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_l2cap_stop_server, local_psm, l2cap_socket_id));
   return BTA_JV_SUCCESS;
 }
 
@@ -589,16 +400,9 @@
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvL2capStopServerLE(uint16_t local_chan,
                                        uint32_t l2cap_socket_id) {
-  APPL_TRACE_API("%s", __func__);
+  VLOG(2) << __func__;
 
-  tBTA_JV_API_L2CAP_SERVER* p_msg =
-      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
-  p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT;
-  p_msg->local_chan = local_chan;
-  p_msg->l2cap_socket_id = l2cap_socket_id;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_stop_server_le, local_chan));
   return BTA_JV_SUCCESS;
 }
 
@@ -606,9 +410,7 @@
  *
  * Function         BTA_JvL2capRead
  *
- * Description      This function reads data from an L2CAP connecti;
-    tBTA_JV_RFC_CB  *p_cb = rc->p_cb;
-on
+ * Description      This function reads data from an L2CAP connection
  *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
  *                  called with BTA_JV_L2CAP_READ_EVT.
  *
@@ -618,28 +420,25 @@
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvL2capRead(uint32_t handle, uint32_t req_id,
                                uint8_t* p_data, uint16_t len) {
-  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  VLOG(2) << __func__;
+
+  if (handle >= BTA_JV_MAX_L2C_CONN || !bta_jv_cb.l2c_cb[handle].p_cback)
+    return BTA_JV_FAILURE;
+
   tBTA_JV_L2CAP_READ evt_data;
+  evt_data.status = BTA_JV_FAILURE;
+  evt_data.handle = handle;
+  evt_data.req_id = req_id;
+  evt_data.p_data = p_data;
+  evt_data.len = 0;
 
-  APPL_TRACE_API("%s", __func__);
-
-  if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
-    status = BTA_JV_SUCCESS;
-    evt_data.status = BTA_JV_FAILURE;
-    evt_data.handle = handle;
-    evt_data.req_id = req_id;
-    evt_data.p_data = p_data;
-    evt_data.len = 0;
-
-    if (BT_PASS ==
-        GAP_ConnReadData((uint16_t)handle, p_data, len, &evt_data.len)) {
-      evt_data.status = BTA_JV_SUCCESS;
-    }
-    bta_jv_cb.l2c_cb[handle].p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV*)&evt_data,
-                                     bta_jv_cb.l2c_cb[handle].l2cap_socket_id);
+  if (BT_PASS ==
+      GAP_ConnReadData((uint16_t)handle, p_data, len, &evt_data.len)) {
+    evt_data.status = BTA_JV_SUCCESS;
   }
-
-  return (status);
+  bta_jv_cb.l2c_cb[handle].p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV*)&evt_data,
+                                   bta_jv_cb.l2c_cb[handle].l2cap_socket_id);
+  return BTA_JV_SUCCESS;
 }
 
 /*******************************************************************************
@@ -656,7 +455,7 @@
 tBTA_JV_STATUS BTA_JvL2capReady(uint32_t handle, uint32_t* p_data_size) {
   tBTA_JV_STATUS status = BTA_JV_FAILURE;
 
-  APPL_TRACE_API("%s: %d", __func__, handle);
+  VLOG(2) << __func__ << ": handle=" << handle;
   if (p_data_size && handle < BTA_JV_MAX_L2C_CONN &&
       bta_jv_cb.l2c_cb[handle].p_cback) {
     *p_data_size = 0;
@@ -675,36 +474,26 @@
  * Description      This function writes data to an L2CAP connection
  *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
  *                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
- *                  PSM-based connections
+ *                  PSM-based connections. This function takes ownership of
+ *                  p_data, and will osi_free it. Data length must be smaller
+ *                  than remote maximum SDU size.
  *
  * Returns          BTA_JV_SUCCESS, if the request is being processed.
  *                  BTA_JV_FAILURE, otherwise.
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
-                                uint8_t* p_data, uint16_t len,
+tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id, BT_HDR* msg,
                                 uint32_t user_id) {
-  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
-    tBTA_JV_API_L2CAP_WRITE* p_msg =
-        (tBTA_JV_API_L2CAP_WRITE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_WRITE));
-    p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
-    p_msg->handle = handle;
-    p_msg->req_id = req_id;
-    p_msg->p_data = p_data;
-    p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
-    p_msg->len = len;
-    p_msg->user_id = user_id;
-
-    bta_sys_sendmsg(p_msg);
-
-    status = BTA_JV_SUCCESS;
+  if (handle >= BTA_JV_MAX_L2C_CONN || !bta_jv_cb.l2c_cb[handle].p_cback) {
+    osi_free(msg);
+    return BTA_JV_FAILURE;
   }
 
-  return status;
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_write, handle, req_id, msg,
+                                   user_id, &bta_jv_cb.l2c_cb[handle]));
+  return BTA_JV_SUCCESS;
 }
 
 /*******************************************************************************
@@ -714,35 +503,17 @@
  * Description      This function writes data to an L2CAP connection
  *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
  *                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
- *                  fixed-channel connections
- *
- * Returns          BTA_JV_SUCCESS, if the request is being processed.
- *                  BTA_JV_FAILURE, otherwise.
+ *                  fixed-channel connections. This function takes ownership of
+ *                  p_data, and will osi_free it.
  *
  ******************************************************************************/
-tBTA_JV_STATUS BTA_JvL2capWriteFixed(uint16_t channel, const RawAddress& addr,
-                                     uint32_t req_id,
-                                     tBTA_JV_L2CAP_CBACK* p_cback,
-                                     uint8_t* p_data, uint16_t len,
-                                     uint32_t user_id) {
-  tBTA_JV_API_L2CAP_WRITE_FIXED* p_msg =
-      (tBTA_JV_API_L2CAP_WRITE_FIXED*)osi_malloc(
-          sizeof(tBTA_JV_API_L2CAP_WRITE_FIXED));
+void BTA_JvL2capWriteFixed(uint16_t channel, const RawAddress& addr,
+                           uint32_t req_id, tBTA_JV_L2CAP_CBACK* p_cback,
+                           BT_HDR* msg, uint32_t user_id) {
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_FIXED_EVT;
-  p_msg->channel = channel;
-  p_msg->addr = addr;
-  p_msg->req_id = req_id;
-  p_msg->p_data = p_data;
-  p_msg->p_cback = p_cback;
-  p_msg->len = len;
-  p_msg->user_id = user_id;
-
-  bta_sys_sendmsg(p_msg);
-
-  return BTA_JV_SUCCESS;
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_write_fixed, channel, addr,
+                                   req_id, msg, user_id, p_cback));
 }
 
 /*******************************************************************************
@@ -766,22 +537,13 @@
                                    const RawAddress& peer_bd_addr,
                                    tBTA_JV_RFCOMM_CBACK* p_cback,
                                    uint32_t rfcomm_slot_id) {
-  APPL_TRACE_API("%s", __func__);
+  VLOG(2) << __func__;
 
-  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+  if (!p_cback) return BTA_JV_FAILURE; /* Nothing to do */
 
-  tBTA_JV_API_RFCOMM_CONNECT* p_msg = (tBTA_JV_API_RFCOMM_CONNECT*)osi_malloc(
-      sizeof(tBTA_JV_API_RFCOMM_CONNECT));
-  p_msg->hdr.event = BTA_JV_API_RFCOMM_CONNECT_EVT;
-  p_msg->sec_mask = sec_mask;
-  p_msg->role = role;
-  p_msg->remote_scn = remote_scn;
-  p_msg->peer_bd_addr = peer_bd_addr;
-  p_msg->p_cback = p_cback;
-  p_msg->rfcomm_slot_id = rfcomm_slot_id;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_rfcomm_connect, sec_mask, role, remote_scn,
+                        peer_bd_addr, p_cback, rfcomm_slot_id));
   return BTA_JV_SUCCESS;
 }
 
@@ -796,28 +558,18 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, uint32_t rfcomm_slot_id) {
-  tBTA_JV_STATUS status = BTA_JV_FAILURE;
   uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
   uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
 
-  APPL_TRACE_API("%s", __func__);
+  VLOG(2) << __func__;
 
-  if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
-      si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
-    tBTA_JV_API_RFCOMM_CLOSE* p_msg =
-        (tBTA_JV_API_RFCOMM_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_CLOSE));
-    p_msg->hdr.event = BTA_JV_API_RFCOMM_CLOSE_EVT;
-    p_msg->handle = handle;
-    p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
-    p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
-    p_msg->rfcomm_slot_id = rfcomm_slot_id;
+  if (hi >= BTA_JV_MAX_RFC_CONN || !bta_jv_cb.rfc_cb[hi].p_cback ||
+      si >= BTA_JV_MAX_RFC_SR_SESSION || !bta_jv_cb.rfc_cb[hi].rfc_hdl[si])
+    return BTA_JV_FAILURE;
 
-    bta_sys_sendmsg(p_msg);
-
-    status = BTA_JV_SUCCESS;
-  }
-
-  return status;
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_rfcomm_close, handle, rfcomm_slot_id));
+  return BTA_JV_SUCCESS;
 }
 
 /*******************************************************************************
@@ -839,28 +591,20 @@
                                        uint8_t local_scn, uint8_t max_session,
                                        tBTA_JV_RFCOMM_CBACK* p_cback,
                                        uint32_t rfcomm_slot_id) {
-  APPL_TRACE_API("%s", __func__);
+  VLOG(2) << __func__;
 
   if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
 
-  tBTA_JV_API_RFCOMM_SERVER* p_msg =
-      (tBTA_JV_API_RFCOMM_SERVER*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER));
   if (max_session == 0) max_session = 1;
   if (max_session > BTA_JV_MAX_RFC_SR_SESSION) {
-    APPL_TRACE_DEBUG("max_session is too big. use max (%d)", max_session,
-                     BTA_JV_MAX_RFC_SR_SESSION);
+    LOG(INFO) << __func__ << "max_session is too big. use max "
+              << BTA_JV_MAX_RFC_SR_SESSION;
     max_session = BTA_JV_MAX_RFC_SR_SESSION;
   }
-  p_msg->hdr.event = BTA_JV_API_RFCOMM_START_SERVER_EVT;
-  p_msg->sec_mask = sec_mask;
-  p_msg->role = role;
-  p_msg->local_scn = local_scn;
-  p_msg->max_session = max_session;
-  p_msg->p_cback = p_cback;
-  p_msg->rfcomm_slot_id = rfcomm_slot_id;  // caller's private data
 
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_rfcomm_start_server, sec_mask, role, local_scn,
+                        max_session, p_cback, rfcomm_slot_id));
   return BTA_JV_SUCCESS;
 }
 
@@ -877,17 +621,10 @@
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvRfcommStopServer(uint32_t handle,
                                       uint32_t rfcomm_slot_id) {
-  tBTA_JV_API_RFCOMM_SERVER* p_msg =
-      (tBTA_JV_API_RFCOMM_SERVER*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER));
+  VLOG(2) << __func__;
 
-  APPL_TRACE_API("%s", __func__);
-
-  p_msg->hdr.event = BTA_JV_API_RFCOMM_STOP_SERVER_EVT;
-  p_msg->handle = handle;
-  p_msg->rfcomm_slot_id = rfcomm_slot_id;  // caller's private data
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_rfcomm_stop_server, handle, rfcomm_slot_id));
   return BTA_JV_SUCCESS;
 }
 
@@ -923,29 +660,24 @@
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvRfcommWrite(uint32_t handle, uint32_t req_id) {
-  tBTA_JV_STATUS status = BTA_JV_FAILURE;
   uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
   uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
 
-  APPL_TRACE_API("%s", __func__);
+  VLOG(2) << __func__;
 
-  APPL_TRACE_DEBUG("handle:0x%x, hi:%d, si:%d", handle, hi, si);
-  if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
-      si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
-    tBTA_JV_API_RFCOMM_WRITE* p_msg =
-        (tBTA_JV_API_RFCOMM_WRITE*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_WRITE));
-    p_msg->hdr.event = BTA_JV_API_RFCOMM_WRITE_EVT;
-    p_msg->handle = handle;
-    p_msg->req_id = req_id;
-    p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
-    p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
-    APPL_TRACE_API("write ok");
-
-    bta_sys_sendmsg(p_msg);
-    status = BTA_JV_SUCCESS;
+  VLOG(2) << __func__ << "handle=" << loghex(handle) << ", hi=" << hi
+          << ", si=" << si;
+  if (hi >= BTA_JV_MAX_RFC_CONN || !bta_jv_cb.rfc_cb[hi].p_cback ||
+      si >= BTA_JV_MAX_RFC_SR_SESSION || !bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+    return BTA_JV_FAILURE;
   }
 
-  return status;
+  VLOG(2) << "write ok";
+
+  tBTA_JV_RFC_CB* p_cb = &bta_jv_cb.rfc_cb[hi];
+  do_in_bta_thread(FROM_HERE, Bind(&bta_jv_rfcomm_write, handle, req_id, p_cb,
+                                   &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1]));
+  return BTA_JV_SUCCESS;
 }
 
 /*******************************************************************************
@@ -973,17 +705,9 @@
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvSetPmProfile(uint32_t handle, tBTA_JV_PM_ID app_id,
                                   tBTA_JV_CONN_STATE init_st) {
-  tBTA_JV_API_SET_PM_PROFILE* p_msg = (tBTA_JV_API_SET_PM_PROFILE*)osi_malloc(
-      sizeof(tBTA_JV_API_SET_PM_PROFILE));
+  VLOG(2) << __func__ << " handle=" << loghex(handle) << ", app_id:" << app_id;
 
-  APPL_TRACE_API("%s handle:0x%x, app_id:%d", __func__, handle, app_id);
-
-  p_msg->hdr.event = BTA_JV_API_SET_PM_PROFILE_EVT;
-  p_msg->handle = handle;
-  p_msg->app_id = app_id;
-  p_msg->init_st = init_st;
-
-  bta_sys_sendmsg(p_msg);
-
+  do_in_bta_thread(FROM_HERE,
+                   Bind(&bta_jv_set_pm_profile, handle, app_id, init_st));
   return BTA_JV_SUCCESS;
 }
diff --git a/bta/jv/bta_jv_cfg.cc b/bta/jv/bta_jv_cfg.cc
index b43b035..c01445e 100644
--- a/bta/jv/bta_jv_cfg.cc
+++ b/bta/jv/bta_jv_cfg.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -43,16 +43,16 @@
  * BTA_JvStartDiscovery
  * it can be de-allocated after the last call to access the database */
 static uint8_t bta_jv_sdp_raw_data[BTA_JV_SDP_RAW_DATA_SIZE];
-static uint8_t __attribute__((aligned(4)))
-bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE];
+static tSDP_DISCOVERY_DB
+    bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE / sizeof(tSDP_DISCOVERY_DB)];
 
 /* JV configuration structure */
 const tBTA_JV_CFG bta_jv_cfg = {
     BTA_JV_SDP_RAW_DATA_SIZE, /* The size of p_sdp_raw_data */
-    BTA_JV_SDP_DB_SIZE,       /* The size of p_sdp_db_data */
-    bta_jv_sdp_raw_data,      /* The data buffer to keep raw data */
-    (tSDP_DISCOVERY_DB*)
-        bta_jv_sdp_db_data /* The data buffer to keep SDP database */
+    (BTA_JV_SDP_DB_SIZE / sizeof(tSDP_DISCOVERY_DB)) *
+        sizeof(tSDP_DISCOVERY_DB), /* The size of p_sdp_db_data */
+    bta_jv_sdp_raw_data,           /* The data buffer to keep raw data */
+    bta_jv_sdp_db_data             /* The data buffer to keep SDP database */
 };
 
-tBTA_JV_CFG* p_bta_jv_cfg = (tBTA_JV_CFG*)&bta_jv_cfg;
+const tBTA_JV_CFG* p_bta_jv_cfg = &bta_jv_cfg;
diff --git a/bta/jv/bta_jv_int.h b/bta/jv/bta_jv_int.h
index 94ee085..fa71580 100644
--- a/bta/jv/bta_jv_int.h
+++ b/bta/jv/bta_jv_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -30,62 +30,17 @@
 #include "port_api.h"
 #include "rfcdefs.h"
 
+#include <memory>
+
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
 
-enum {
-  /* these events are handled by the state machine */
-  BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV),
-  BTA_JV_API_DISABLE_EVT,
-  BTA_JV_API_GET_CHANNEL_EVT,
-  BTA_JV_API_FREE_SCN_EVT,
-  BTA_JV_API_START_DISCOVERY_EVT,
-  BTA_JV_API_CREATE_RECORD_EVT,
-  BTA_JV_API_DELETE_RECORD_EVT,
-  BTA_JV_API_L2CAP_CONNECT_EVT,
-  BTA_JV_API_L2CAP_CLOSE_EVT,
-  BTA_JV_API_L2CAP_START_SERVER_EVT,
-  BTA_JV_API_L2CAP_STOP_SERVER_EVT,
-  BTA_JV_API_L2CAP_READ_EVT,
-  BTA_JV_API_L2CAP_WRITE_EVT,
-  BTA_JV_API_RFCOMM_CONNECT_EVT,
-  BTA_JV_API_RFCOMM_CLOSE_EVT,
-  BTA_JV_API_RFCOMM_START_SERVER_EVT,
-  BTA_JV_API_RFCOMM_STOP_SERVER_EVT,
-  BTA_JV_API_RFCOMM_WRITE_EVT,
-  BTA_JV_API_SET_PM_PROFILE_EVT,
-  BTA_JV_API_PM_STATE_CHANGE_EVT,
-  BTA_JV_API_L2CAP_CONNECT_LE_EVT,
-  BTA_JV_API_L2CAP_START_SERVER_LE_EVT,
-  BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT,
-  BTA_JV_API_L2CAP_WRITE_FIXED_EVT,
-  BTA_JV_API_L2CAP_CLOSE_FIXED_EVT,
-  BTA_JV_MAX_INT_EVT
-};
-
 #ifndef BTA_JV_RFC_EV_MASK
 #define BTA_JV_RFC_EV_MASK \
   (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_FC | PORT_EV_FCS)
 #endif
 
-/* data type for BTA_JV_API_ENABLE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_JV_DM_CBACK* p_cback;
-} tBTA_JV_API_ENABLE;
-
-/* data type for BTA_JV_API_START_DISCOVERY_EVT */
-typedef struct {
-  BT_HDR hdr;
-  RawAddress bd_addr;
-  uint16_t num_uuid;
-  tSDP_UUID uuid_list[BTA_JV_MAX_UUIDS];
-  uint16_t num_attr;
-  uint16_t attr_list[BTA_JV_MAX_ATTRS];
-  uint32_t rfcomm_slot_id;
-} tBTA_JV_API_START_DISCOVERY;
-
 enum {
   BTA_JV_PM_FREE_ST = 0, /* empty PM slot */
   BTA_JV_PM_IDLE_ST,
@@ -151,199 +106,6 @@
   int curr_sess;          /* current sessions count*/
 } tBTA_JV_RFC_CB;
 
-/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT
- */
-typedef struct {
-  BT_HDR hdr;
-  int32_t type; /* One of BTA_JV_CONN_TYPE_ */
-  tBTA_SEC sec_mask;
-  tBTA_JV_ROLE role;
-  union {
-    uint16_t remote_psm;
-    uint16_t remote_chan;
-  };
-  uint16_t rx_mtu;
-  RawAddress peer_bd_addr;
-  int32_t has_cfg;
-  tL2CAP_CFG_INFO cfg;
-  int32_t has_ertm_info;
-  tL2CAP_ERTM_INFO ertm_info;
-  tBTA_JV_L2CAP_CBACK* p_cback;
-  uint32_t l2cap_socket_id;
-} tBTA_JV_API_L2CAP_CONNECT;
-
-/* data type for BTA_JV_API_L2CAP_SERVER_EVT */
-typedef struct {
-  BT_HDR hdr;
-  int32_t type; /* One of BTA_JV_CONN_TYPE_ */
-  tBTA_SEC sec_mask;
-  tBTA_JV_ROLE role;
-  union {
-    uint16_t local_psm;
-    uint16_t local_chan;
-  };
-  uint16_t rx_mtu;
-  int32_t has_cfg;
-  tL2CAP_CFG_INFO cfg;
-  int32_t has_ertm_info;
-  tL2CAP_ERTM_INFO ertm_info;
-  tBTA_JV_L2CAP_CBACK* p_cback;
-  uint32_t l2cap_socket_id;
-} tBTA_JV_API_L2CAP_SERVER;
-
-/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  tBTA_JV_L2C_CB* p_cb;
-} tBTA_JV_API_L2CAP_CLOSE;
-
-/* data type for BTA_JV_API_L2CAP_READ_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  uint32_t req_id;
-  tBTA_JV_L2CAP_CBACK* p_cback;
-  uint8_t* p_data;
-  uint16_t len;
-  uint32_t l2cap_socket_id;
-} tBTA_JV_API_L2CAP_READ;
-
-/* data type for BTA_JV_API_L2CAP_WRITE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  uint32_t req_id;
-  tBTA_JV_L2C_CB* p_cb;
-  uint8_t* p_data;
-  uint16_t len;
-  uint32_t user_id;
-} tBTA_JV_API_L2CAP_WRITE;
-
-/* data type for BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint16_t channel;
-  RawAddress addr;
-  uint32_t req_id;
-  tBTA_JV_L2CAP_CBACK* p_cback;
-  uint8_t* p_data;
-  uint16_t len;
-  uint32_t user_id;
-} tBTA_JV_API_L2CAP_WRITE_FIXED;
-
-/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_SEC sec_mask;
-  tBTA_JV_ROLE role;
-  uint8_t remote_scn;
-  RawAddress peer_bd_addr;
-  tBTA_JV_RFCOMM_CBACK* p_cback;
-  uint32_t rfcomm_slot_id;
-} tBTA_JV_API_RFCOMM_CONNECT;
-
-/* data type for BTA_JV_API_RFCOMM_SERVER_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_SEC sec_mask;
-  tBTA_JV_ROLE role;
-  uint8_t local_scn;
-  uint8_t max_session;
-  uint32_t handle;
-  tBTA_JV_RFCOMM_CBACK* p_cback;
-  uint32_t rfcomm_slot_id;
-} tBTA_JV_API_RFCOMM_SERVER;
-
-/* data type for BTA_JV_API_SET_PM_PROFILE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  tBTA_JV_PM_ID app_id;
-  tBTA_JV_CONN_STATE init_st;
-} tBTA_JV_API_SET_PM_PROFILE;
-
-/* data type for BTA_JV_API_PM_STATE_CHANGE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  tBTA_JV_PM_CB* p_cb;
-  tBTA_JV_CONN_STATE state;
-} tBTA_JV_API_PM_STATE_CHANGE;
-
-/* data type for BTA_JV_API_RFCOMM_WRITE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  uint32_t req_id;
-  uint8_t* p_data;
-  int len;
-  tBTA_JV_RFC_CB* p_cb;
-  tBTA_JV_PCB* p_pcb;
-} tBTA_JV_API_RFCOMM_WRITE;
-
-/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  tBTA_JV_RFC_CB* p_cb;
-  tBTA_JV_PCB* p_pcb;
-  uint32_t rfcomm_slot_id;
-} tBTA_JV_API_RFCOMM_CLOSE;
-
-/* data type for BTA_JV_API_CREATE_RECORD_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t rfcomm_slot_id;
-} tBTA_JV_API_CREATE_RECORD;
-
-/* data type for BTA_JV_API_ADD_ATTRIBUTE_EVT */
-typedef struct {
-  BT_HDR hdr;
-  uint32_t handle;
-  uint16_t attr_id;
-  uint8_t* p_value;
-  int32_t value_size;
-} tBTA_JV_API_ADD_ATTRIBUTE;
-
-/* data type for BTA_JV_API_FREE_SCN_EVT */
-typedef struct {
-  BT_HDR hdr;
-  int32_t type; /* One of BTA_JV_CONN_TYPE_ */
-  uint16_t scn;
-} tBTA_JV_API_FREE_CHANNEL;
-
-/* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
-typedef struct {
-  BT_HDR hdr;
-  int32_t type;    /* One of BTA_JV_CONN_TYPE_ */
-  int32_t channel; /* optionally request a specific channel */
-  uint32_t l2cap_socket_id;
-  uint32_t rfcomm_slot_id;
-} tBTA_JV_API_ALLOC_CHANNEL;
-/* union of all data types */
-typedef union {
-  /* GKI event buffer header */
-  BT_HDR hdr;
-  tBTA_JV_API_ENABLE enable;
-  tBTA_JV_API_START_DISCOVERY start_discovery;
-  tBTA_JV_API_ALLOC_CHANNEL alloc_channel;
-  tBTA_JV_API_FREE_CHANNEL free_channel;
-  tBTA_JV_API_CREATE_RECORD create_record;
-  tBTA_JV_API_ADD_ATTRIBUTE add_attr;
-  tBTA_JV_API_L2CAP_CONNECT l2cap_connect;
-  tBTA_JV_API_L2CAP_READ l2cap_read;
-  tBTA_JV_API_L2CAP_WRITE l2cap_write;
-  tBTA_JV_API_L2CAP_CLOSE l2cap_close;
-  tBTA_JV_API_L2CAP_SERVER l2cap_server;
-  tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
-  tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
-  tBTA_JV_API_SET_PM_PROFILE set_pm;
-  tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
-  tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
-  tBTA_JV_API_RFCOMM_SERVER rfcomm_server;
-  tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
-} tBTA_JV_MSG;
-
 /* JV control block */
 typedef struct {
   /* the SDP handle reported to JV user is the (index + 1) to sdp_handle[].
@@ -361,7 +123,7 @@
   uint16_t free_psm_list[BTA_JV_MAX_L2C_CONN]; /* PSMs freed by java
                                                 (can be reused) */
   uint8_t sdp_active;                          /* see BTA_JV_SDP_ACT_* */
-  tSDP_UUID uuid;                         /* current uuid of sdp discovery*/
+  bluetooth::Uuid uuid;                   /* current uuid of sdp discovery*/
   tBTA_JV_PM_CB pm_cb[BTA_JV_PM_MAX_NUM]; /* PM on a per JV handle bases */
 } tBTA_JV_CB;
 
@@ -377,33 +139,62 @@
 /* config struct */
 extern tBTA_JV_CFG* p_bta_jv_cfg;
 
-extern bool bta_jv_sm_execute(BT_HDR* p_msg);
-
-extern void bta_jv_enable(tBTA_JV_MSG* p_data);
-extern void bta_jv_disable(tBTA_JV_MSG* p_data);
-extern void bta_jv_get_channel_id(tBTA_JV_MSG* p_data);
-extern void bta_jv_free_scn(tBTA_JV_MSG* p_data);
-extern void bta_jv_start_discovery(tBTA_JV_MSG* p_data);
-extern void bta_jv_create_record(tBTA_JV_MSG* p_data);
-extern void bta_jv_delete_record(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_connect(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_close(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_start_server(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_stop_server(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_read(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_write(tBTA_JV_MSG* p_data);
-extern void bta_jv_rfcomm_connect(tBTA_JV_MSG* p_data);
-extern void bta_jv_rfcomm_close(tBTA_JV_MSG* p_data);
-extern void bta_jv_rfcomm_start_server(tBTA_JV_MSG* p_data);
-extern void bta_jv_rfcomm_stop_server(tBTA_JV_MSG* p_data);
-extern void bta_jv_rfcomm_read(tBTA_JV_MSG* p_data);
-extern void bta_jv_rfcomm_write(tBTA_JV_MSG* p_data);
-extern void bta_jv_set_pm_profile(tBTA_JV_MSG* p_data);
-extern void bta_jv_change_pm_state(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_connect_le(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_start_server_le(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_write_fixed(tBTA_JV_MSG* p_data);
-extern void bta_jv_l2cap_close_fixed(tBTA_JV_MSG* p_data);
+extern void bta_jv_enable(tBTA_JV_DM_CBACK* p_cback);
+extern void bta_jv_disable();
+extern void bta_jv_get_channel_id(int32_t type, int32_t channel,
+                                  uint32_t l2cap_socket_id,
+                                  uint32_t rfcomm_slot_id);
+extern void bta_jv_free_scn(int32_t type, uint16_t scn);
+extern void bta_jv_start_discovery(const RawAddress& bd_addr, uint16_t num_uuid,
+                                   bluetooth::Uuid* uuid_list,
+                                   uint32_t rfcomm_slot_id);
+extern void bta_jv_create_record(uint32_t rfcomm_slot_id);
+extern void bta_jv_delete_record(uint32_t handle);
+extern void bta_jv_l2cap_connect(int32_t type, tBTA_SEC sec_mask,
+                                 tBTA_JV_ROLE role, uint16_t remote_psm,
+                                 uint16_t rx_mtu,
+                                 const RawAddress& peer_bd_addr,
+                                 std::unique_ptr<tL2CAP_CFG_INFO> cfg,
+                                 std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info,
+                                 tBTA_JV_L2CAP_CBACK* p_cback,
+                                 uint32_t l2cap_socket_id);
+extern void bta_jv_l2cap_close(uint32_t handle, tBTA_JV_L2C_CB* p_cb);
+extern void bta_jv_l2cap_start_server(
+    int32_t type, tBTA_SEC sec_mask, tBTA_JV_ROLE role, uint16_t local_psm,
+    uint16_t rx_mtu, std::unique_ptr<tL2CAP_CFG_INFO> cfg_param,
+    std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info, tBTA_JV_L2CAP_CBACK* p_cback,
+    uint32_t l2cap_socket_id);
+extern void bta_jv_l2cap_stop_server(uint16_t local_psm,
+                                     uint32_t l2cap_socket_id);
+extern void bta_jv_l2cap_write(uint32_t handle, uint32_t req_id, BT_HDR* msg,
+                               uint32_t user_id, tBTA_JV_L2C_CB* p_cb);
+extern void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                  uint8_t remote_scn,
+                                  const RawAddress& peer_bd_addr,
+                                  tBTA_JV_RFCOMM_CBACK* p_cback,
+                                  uint32_t rfcomm_slot_id);
+extern void bta_jv_rfcomm_close(uint32_t handle, uint32_t rfcomm_slot_id);
+extern void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                       uint8_t local_scn, uint8_t max_session,
+                                       tBTA_JV_RFCOMM_CBACK* p_cback,
+                                       uint32_t rfcomm_slot_id);
+extern void bta_jv_rfcomm_stop_server(uint32_t handle, uint32_t rfcomm_slot_id);
+extern void bta_jv_rfcomm_write(uint32_t handle, uint32_t req_id,
+                                tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb);
+extern void bta_jv_set_pm_profile(uint32_t handle, tBTA_JV_PM_ID app_id,
+                                  tBTA_JV_CONN_STATE init_st);
+extern void bta_jv_l2cap_connect_le(uint16_t remote_chan,
+                                    const RawAddress& peer_bd_addr,
+                                    tBTA_JV_L2CAP_CBACK* p_cback,
+                                    uint32_t l2cap_socket_id);
+extern void bta_jv_l2cap_start_server_le(uint16_t local_chan,
+                                         tBTA_JV_L2CAP_CBACK* p_cback,
+                                         uint32_t l2cap_socket_id);
+extern void bta_jv_l2cap_stop_server_le(uint16_t local_chan);
+extern void bta_jv_l2cap_write_fixed(uint16_t channel, const RawAddress& addr,
+                                     uint32_t req_id, BT_HDR* msg,
+                                     uint32_t user_id,
+                                     tBTA_JV_L2CAP_CBACK* p_cback);
+extern void bta_jv_l2cap_close_fixed(uint32_t handle);
 
 #endif /* BTA_JV_INT_H */
diff --git a/bta/jv/bta_jv_main.cc b/bta/jv/bta_jv_main.cc
deleted file mode 100644
index fd5ce3a..0000000
--- a/bta/jv/bta_jv_main.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- *  This is the main implementation file for the BTA Java I/F
- *
- ******************************************************************************/
-
-#include "bta_api.h"
-#include "bta_jv_api.h"
-#include "bta_jv_int.h"
-#include "bta_sys.h"
-
-/*****************************************************************************
- * Constants and types
- ****************************************************************************/
-
-tBTA_JV_CB bta_jv_cb;
-
-/* state machine action enumeration list */
-#define BTA_JV_NUM_ACTIONS (BTA_JV_MAX_INT_EVT & 0x00ff)
-
-/* type for action functions */
-typedef void (*tBTA_JV_ACTION)(tBTA_JV_MSG* p_data);
-
-/* action function list */
-const tBTA_JV_ACTION bta_jv_action[] = {
-    bta_jv_enable,                /* BTA_JV_API_ENABLE_EVT */
-    bta_jv_disable,               /* BTA_JV_API_DISABLE_EVT */
-    bta_jv_get_channel_id,        /* BTA_JV_API_GET_CHANNEL_EVT */
-    bta_jv_free_scn,              /* BTA_JV_API_FREE_SCN_EVT */
-    bta_jv_start_discovery,       /* BTA_JV_API_START_DISCOVERY_EVT */
-    bta_jv_create_record,         /* BTA_JV_API_CREATE_RECORD_EVT */
-    bta_jv_delete_record,         /* BTA_JV_API_DELETE_RECORD_EVT */
-    bta_jv_l2cap_connect,         /* BTA_JV_API_L2CAP_CONNECT_EVT */
-    bta_jv_l2cap_close,           /* BTA_JV_API_L2CAP_CLOSE_EVT */
-    bta_jv_l2cap_start_server,    /* BTA_JV_API_L2CAP_START_SERVER_EVT */
-    bta_jv_l2cap_stop_server,     /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */
-    bta_jv_l2cap_read,            /* BTA_JV_API_L2CAP_READ_EVT */
-    bta_jv_l2cap_write,           /* BTA_JV_API_L2CAP_WRITE_EVT */
-    bta_jv_rfcomm_connect,        /* BTA_JV_API_RFCOMM_CONNECT_EVT */
-    bta_jv_rfcomm_close,          /* BTA_JV_API_RFCOMM_CLOSE_EVT */
-    bta_jv_rfcomm_start_server,   /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
-    bta_jv_rfcomm_stop_server,    /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */
-    bta_jv_rfcomm_write,          /* BTA_JV_API_RFCOMM_WRITE_EVT */
-    bta_jv_set_pm_profile,        /* BTA_JV_API_SET_PM_PROFILE_EVT */
-    bta_jv_change_pm_state,       /* BTA_JV_API_PM_STATE_CHANGE_EVT */
-    bta_jv_l2cap_connect_le,      /* BTA_JV_API_L2CAP_CONNECT_LE_EVT */
-    bta_jv_l2cap_start_server_le, /* BTA_JV_API_L2CAP_START_SERVER_LE_EVT */
-    bta_jv_l2cap_stop_server_le,  /* BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT */
-    bta_jv_l2cap_write_fixed,     /* BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
-    bta_jv_l2cap_close_fixed,     /*  BTA_JV_API_L2CAP_CLOSE_FIXED_EVT */
-};
-
-/*******************************************************************************
- *
- * Function         bta_jv_sm_execute
- *
- * Description      State machine event handling function for JV
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-bool bta_jv_sm_execute(BT_HDR* p_msg) {
-  bool ret = false;
-  uint16_t action = (p_msg->event & 0x00ff);
-  /* execute action functions */
-
-  if (action < BTA_JV_NUM_ACTIONS) {
-    (*bta_jv_action[action])((tBTA_JV_MSG*)p_msg);
-    ret = true;
-  }
-
-  return (ret);
-}
diff --git a/bta/mce/bta_mce_act.cc b/bta/mce/bta_mce_act.cc
index f188b01..0d9bbf3 100644
--- a/bta/mce/bta_mce_act.cc
+++ b/bta/mce/bta_mce_act.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -38,12 +38,14 @@
 #include "sdp_api.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
 
-static const tBT_UUID bta_mce_mas_uuid = {
-    .len = 2, .uu.uuid16 = UUID_SERVCLASS_MESSAGE_ACCESS};
+static const Uuid bta_mce_mas_uuid =
+    Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_ACCESS);
 
 /*******************************************************************************
  *
@@ -75,8 +77,8 @@
       tSDP_DISC_ATTR* p_attr;
       tSDP_PROTOCOL_ELEM pe;
 
-      p_rec = SDP_FindServiceUUIDInDb(p_bta_mce_cfg->p_sdp_db,
-                                      (tBT_UUID*)&bta_mce_mas_uuid, p_rec);
+      p_rec = SDP_FindServiceUUIDInDb(p_bta_mce_cfg->p_sdp_db, bta_mce_mas_uuid,
+                                      p_rec);
 
       APPL_TRACE_DEBUG("p_rec:%p", p_rec);
 
@@ -167,7 +169,7 @@
   bta_mce_cb.remote_addr = p_data->get_rmt_mas.bd_addr;
 
   SDP_InitDiscoveryDb(p_bta_mce_cfg->p_sdp_db, p_bta_mce_cfg->sdp_db_size, 1,
-                      (tBT_UUID*)&bta_mce_mas_uuid, 0, NULL);
+                      &bta_mce_mas_uuid, 0, NULL);
 
   if (!SDP_ServiceSearchAttributeRequest2(p_data->get_rmt_mas.bd_addr,
                                           p_bta_mce_cfg->p_sdp_db,
diff --git a/bta/mce/bta_mce_api.cc b/bta/mce/bta_mce_api.cc
index b44c210..7ab10da 100644
--- a/bta/mce/bta_mce_api.cc
+++ b/bta/mce/bta_mce_api.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@
 
   APPL_TRACE_API("%", __func__);
 
-  if (p_cback && false == bta_sys_is_register(BTA_ID_MCE)) {
+  if (p_cback && !bta_sys_is_register(BTA_ID_MCE)) {
     memset(&bta_mce_cb, 0, sizeof(tBTA_MCE_CB));
 
     /* register with BTA system manager */
diff --git a/bta/mce/bta_mce_cfg.cc b/bta/mce/bta_mce_cfg.cc
index 3beb265..ede80ba 100644
--- a/bta/mce/bta_mce_cfg.cc
+++ b/bta/mce/bta_mce_cfg.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,14 +32,14 @@
 #define BTA_MCE_SDP_DB_SIZE 4500
 #endif
 
-static uint8_t __attribute__((aligned(4)))
-bta_mce_sdp_db_data[BTA_MCE_SDP_DB_SIZE];
+static tSDP_DISCOVERY_DB
+    bta_mce_sdp_db_data[BTA_MCE_SDP_DB_SIZE / sizeof(tSDP_DISCOVERY_DB)];
 
 /* MCE configuration structure */
 const tBTA_MCE_CFG bta_mce_cfg = {
-    BTA_MCE_SDP_DB_SIZE,
-    (tSDP_DISCOVERY_DB*)
-        bta_mce_sdp_db_data /* The data buffer to keep SDP database */
+    (BTA_MCE_SDP_DB_SIZE / sizeof(tSDP_DISCOVERY_DB)) *
+        sizeof(tSDP_DISCOVERY_DB),
+    bta_mce_sdp_db_data /* The data buffer to keep SDP database */
 };
 
-tBTA_MCE_CFG* p_bta_mce_cfg = (tBTA_MCE_CFG*)&bta_mce_cfg;
+const tBTA_MCE_CFG* p_bta_mce_cfg = &bta_mce_cfg;
diff --git a/bta/mce/bta_mce_int.h b/bta/mce/bta_mce_int.h
index cff5875..4e1058f 100644
--- a/bta/mce/bta_mce_int.h
+++ b/bta/mce/bta_mce_int.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/mce/bta_mce_main.cc b/bta/mce/bta_mce_main.cc
index abd3e5c..d2a2ca1 100644
--- a/bta/mce/bta_mce_main.cc
+++ b/bta/mce/bta_mce_main.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/pan/bta_pan_act.cc b/bta/pan/bta_pan_act.cc
index 41e0bf6..04c06d0 100644
--- a/bta/pan/bta_pan_act.cc
+++ b/bta/pan/bta_pan_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -171,31 +171,25 @@
 static void bta_pan_data_buf_ind_cback(uint16_t handle, const RawAddress& src,
                                        const RawAddress& dst, uint16_t protocol,
                                        BT_HDR* p_buf, bool ext, bool forward) {
-  tBTA_PAN_SCB* p_scb;
-  BT_HDR* p_new_buf;
-
-  p_scb = bta_pan_scb_by_handle(handle);
+  tBTA_PAN_SCB* p_scb = bta_pan_scb_by_handle(handle);
   if (p_scb == NULL) {
     return;
   }
 
-  if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
-    /* offset smaller than data structure in front of actual data */
-    if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
-        PAN_BUF_SIZE) {
-      android_errorWriteLog(0x534e4554, "63146237");
-      APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
-                       p_buf->len);
-      return;
-    }
-    p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
-    memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
-           (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
-    p_new_buf->len = p_buf->len;
-    p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
-  } else {
-    p_new_buf = p_buf;
+  if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
+      PAN_BUF_SIZE) {
+    android_errorWriteLog(0x534e4554, "63146237");
+    APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
+                     p_buf->len);
+    return;
   }
+
+  BT_HDR* p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+  memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
+         (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+  p_new_buf->len = p_buf->len;
+  p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
+
   /* copy params into the space before the data */
   ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->src = src;
   ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->dst = dst;
@@ -268,7 +262,7 @@
 
   for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
     p_scb = &bta_pan_cb.scb[index];
-    if (p_scb->in_use == true && app_id == p_scb->app_id) {
+    if (p_scb->in_use && app_id == p_scb->app_id) {
       /* save temp bd_addr */
       bd_addr = p_scb->bd_addr;
       found = true;
@@ -277,14 +271,14 @@
   }
 
   /* If cannot find a match then there is no connection at all */
-  if (found == false) return false;
+  if (!found) return false;
 
   /* Find whether there is another connection with different device other than
      PANU.
       Could be same service or different service */
   for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
     p_scb = &bta_pan_cb.scb[index];
-    if (p_scb->in_use == true && p_scb->app_id != bta_pan_cb.app_id[0] &&
+    if (p_scb->in_use && p_scb->app_id != bta_pan_cb.app_id[0] &&
         bd_addr != p_scb->bd_addr) {
       return true;
     }
@@ -583,7 +577,7 @@
   /* if data path configured for rx pull */
   if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PULL) {
     /* if we can accept data */
-    if (p_scb->pan_flow_enable == true) {
+    if (p_scb->pan_flow_enable) {
       /* call application callout function for rx path */
       bta_pan_co_rx_path(p_scb->handle, p_scb->app_id);
     }
@@ -618,7 +612,7 @@
   /* if configured for zero copy push */
   else if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PUSH_BUF) {
     /* if app can accept data */
-    if (p_scb->app_flow_enable == true) {
+    if (p_scb->app_flow_enable) {
       BT_HDR* p_buf;
 
       /* read data from the queue */
diff --git a/bta/pan/bta_pan_api.cc b/bta/pan/bta_pan_api.cc
index 0011522..9f25735 100644
--- a/bta/pan/bta_pan_api.cc
+++ b/bta/pan/bta_pan_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/pan/bta_pan_ci.cc b/bta/pan/bta_pan_ci.cc
index 9863e78..d2fda39 100644
--- a/bta/pan/bta_pan_ci.cc
+++ b/bta/pan/bta_pan_ci.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -183,10 +183,10 @@
  ******************************************************************************/
 BT_HDR* bta_pan_ci_readbuf(uint16_t handle, RawAddress& src, RawAddress& dst,
                            uint16_t* p_protocol, bool* p_ext, bool* p_forward) {
-  tBTA_PAN_SCB* p_scb;
+  tBTA_PAN_SCB* p_scb = bta_pan_scb_by_handle(handle);
   BT_HDR* p_buf;
 
-  p_scb = bta_pan_scb_by_handle(handle);
+  if (p_scb == NULL) return NULL;
 
   p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue);
   if (p_buf != NULL) {
diff --git a/bta/pan/bta_pan_int.h b/bta/pan/bta_pan_int.h
index 089fd1d..df79fcb 100644
--- a/bta/pan/bta_pan_int.h
+++ b/bta/pan/bta_pan_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/pan/bta_pan_main.cc b/bta/pan/bta_pan_main.cc
index 9ee5e0a..09df88f 100644
--- a/bta/pan/bta_pan_main.cc
+++ b/bta/pan/bta_pan_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -51,7 +51,8 @@
   BTA_PAN_CONN_OPEN,
   BTA_PAN_CONN_CLOSE,
   BTA_PAN_FREE_BUF,
-  BTA_PAN_IGNORE
+  BTA_PAN_IGNORE,
+  BTA_PAN_MAX_ACTIONS
 };
 
 /* type for action functions */
@@ -184,11 +185,9 @@
   /* execute action functions */
   for (i = 0; i < BTA_PAN_ACTIONS; i++) {
     action = state_table[event][i];
-    if (action != BTA_PAN_IGNORE) {
-      (*bta_pan_action[action])(p_scb, p_data);
-    } else {
-      break;
-    }
+    CHECK(action < BTA_PAN_MAX_ACTIONS);
+    if (action == BTA_PAN_IGNORE) continue;
+    (*bta_pan_action[action])(p_scb, p_data);
   }
 }
 
diff --git a/bta/pb/bta_pbs_int.h b/bta/pb/bta_pbs_int.h
index ae21ce4..cf597f8 100644
--- a/bta/pb/bta_pbs_int.h
+++ b/bta/pb/bta_pbs_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/sdp/bta_sdp.cc b/bta/sdp/bta_sdp.cc
index 735d0b7..1729db8 100644
--- a/bta/sdp/bta_sdp.cc
+++ b/bta/sdp/bta_sdp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 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.
diff --git a/bta/sdp/bta_sdp_act.cc b/bta/sdp/bta_sdp_act.cc
index 172875f..80baed7 100644
--- a/bta/sdp/bta_sdp_act.cc
+++ b/bta/sdp/bta_sdp_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 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.
@@ -42,55 +42,11 @@
  *  Constants
  ****************************************************************************/
 
-static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
-    0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
-    0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00,
-                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                        0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00,
-                                       0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                       0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_MAP_MNS[] = {0x00, 0x00, 0x11, 0x33, 0x00, 0x00,
-                                       0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                       0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00,
-                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                   0x5F, 0x9B, 0x34, 0xFB};
-// TODO:
-// Both the fact that the UUIDs are declared in multiple places, plus the fact
-// that there is a mess of UUID comparison and shortening methods will have to
-// be fixed.
-// The btcore->uuid module should be used for all instances.
-
-#define UUID_MAX_LENGTH 16
-#define IS_UUID(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
-
-static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) {
-  static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                   0x5F, 0x9B, 0x34, 0xFB};
-
-  APPL_TRACE_DEBUG("%s() - uuid len:%d", __func__, u->len);
-  if (u->len != 16) return *u;
-
-  if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) != 0) return *u;
-
-  tBT_UUID su;
-  memset(&su, 0, sizeof(su));
-  if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
-    su.len = 2;
-    uint16_t u16;
-    memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
-    su.uu.uuid16 = ntohs(u16);
-  } else {
-    su.len = 4;
-    uint32_t u32;
-    memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
-    su.uu.uuid32 = ntohl(u32);
-  }
-  return su;
-}
+static const Uuid UUID_OBEX_OBJECT_PUSH = Uuid::From16Bit(0x1105);
+static const Uuid UUID_PBAP_PSE = Uuid::From16Bit(0x112F);
+static const Uuid UUID_MAP_MAS = Uuid::From16Bit(0x1132);
+static const Uuid UUID_MAP_MNS = Uuid::From16Bit(0x1133);
+static const Uuid UUID_SAP = Uuid::From16Bit(0x112D);
 
 static void bta_create_mns_sdp_record(bluetooth_sdp_record* record,
                                       tSDP_DISC_REC* p_rec) {
@@ -373,74 +329,63 @@
   record->hdr.user1_ptr = p_bta_sdp_cfg->p_sdp_db->raw_data;
 }
 
-/*******************************************************************************
- *
- * Function     bta_sdp_search_cback
- *
- * Description  Callback from btm after search is completed
- *
- * Returns      void
- *
- ******************************************************************************/
+/** Callback from btm after search is completed */
 static void bta_sdp_search_cback(uint16_t result, void* user_data) {
-  tSDP_DISC_REC* p_rec = NULL;
-  tBTA_SDP_SEARCH_COMP evt_data;
   tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
   int count = 0;
-  tBT_UUID su;
   APPL_TRACE_DEBUG("%s() -  res: 0x%x", __func__, result);
 
-  memset(&evt_data, 0, sizeof(evt_data));
   bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
 
   if (bta_sdp_cb.p_dm_cback == NULL) return;
 
+  Uuid& uuid = *(reinterpret_cast<Uuid*>(user_data));
+
+  tBTA_SDP_SEARCH_COMP evt_data;
+  memset(&evt_data, 0, sizeof(evt_data));
   evt_data.remote_addr = bta_sdp_cb.remote_addr;
-  tBT_UUID* uuid = (tBT_UUID*)user_data;
-  memcpy(&evt_data.uuid, uuid, sizeof(tBT_UUID));
-  su = shorten_sdp_uuid(uuid);
+  evt_data.uuid = uuid;
 
   if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+    tSDP_DISC_REC* p_rec = NULL;
     do {
-      p_rec = SDP_FindServiceUUIDInDb(p_bta_sdp_cfg->p_sdp_db, &su, p_rec);
+      p_rec = SDP_FindServiceUUIDInDb(p_bta_sdp_cfg->p_sdp_db, uuid, p_rec);
       /* generate the matching record data pointer */
-      if (p_rec != NULL) {
-        status = BTA_SDP_SUCCESS;
-        if (IS_UUID(UUID_MAP_MAS, uuid->uu.uuid128)) {
-          APPL_TRACE_DEBUG("%s() - found MAP (MAS) uuid", __func__);
-          bta_create_mas_sdp_record(&evt_data.records[count], p_rec);
-        } else if (IS_UUID(UUID_MAP_MNS, uuid->uu.uuid128)) {
-          APPL_TRACE_DEBUG("%s() - found MAP (MNS) uuid", __func__);
-          bta_create_mns_sdp_record(&evt_data.records[count], p_rec);
-        } else if (IS_UUID(UUID_PBAP_PSE, uuid->uu.uuid128)) {
-          APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid", __func__);
-          bta_create_pse_sdp_record(&evt_data.records[count], p_rec);
-        } else if (IS_UUID(UUID_OBEX_OBJECT_PUSH, uuid->uu.uuid128)) {
-          APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid",
-                           __func__);
-          bta_create_ops_sdp_record(&evt_data.records[count], p_rec);
-        } else if (IS_UUID(UUID_SAP, uuid->uu.uuid128)) {
-          APPL_TRACE_DEBUG("%s() - found SAP uuid", __func__);
-          bta_create_sap_sdp_record(&evt_data.records[count], p_rec);
-        } else {
-          /* we do not have specific structure for this */
-          APPL_TRACE_DEBUG("%s() - profile not identified. using raw data",
-                           __func__);
-          bta_create_raw_sdp_record(&evt_data.records[count], p_rec);
-          p_rec = NULL;  // Terminate loop
-          /* For raw, we only extract the first entry, and then return the
-             entire
-             raw data chunk.
-             TODO: Find a way to split the raw data into record chunks, and
-             iterate
-                   to extract generic data for each chunk - e.g. rfcomm channel
-             and
-                   service name. */
-        }
-        count++;
-      } else {
+      if (!p_rec) {
         APPL_TRACE_DEBUG("%s() - UUID not found", __func__);
+        continue;
       }
+
+      status = BTA_SDP_SUCCESS;
+      if (uuid == UUID_MAP_MAS) {
+        APPL_TRACE_DEBUG("%s() - found MAP (MAS) uuid", __func__);
+        bta_create_mas_sdp_record(&evt_data.records[count], p_rec);
+      } else if (uuid == UUID_MAP_MNS) {
+        APPL_TRACE_DEBUG("%s() - found MAP (MNS) uuid", __func__);
+        bta_create_mns_sdp_record(&evt_data.records[count], p_rec);
+      } else if (uuid == UUID_PBAP_PSE) {
+        APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid", __func__);
+        bta_create_pse_sdp_record(&evt_data.records[count], p_rec);
+      } else if (uuid == UUID_OBEX_OBJECT_PUSH) {
+        APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid",
+                         __func__);
+        bta_create_ops_sdp_record(&evt_data.records[count], p_rec);
+      } else if (uuid == UUID_SAP) {
+        APPL_TRACE_DEBUG("%s() - found SAP uuid", __func__);
+        bta_create_sap_sdp_record(&evt_data.records[count], p_rec);
+      } else {
+        /* we do not have specific structure for this */
+        APPL_TRACE_DEBUG("%s() - profile not identified. using raw data",
+                         __func__);
+        bta_create_raw_sdp_record(&evt_data.records[count], p_rec);
+        p_rec = NULL;  // Terminate loop
+        /* For raw, we only extract the first entry, and then return the
+           entire raw data chunk.
+           TODO: Find a way to split the raw data into record chunks, and
+           iterate to extract generic data for each chunk - e.g. rfcomm
+           channel and service name. */
+      }
+      count++;
     } while (p_rec != NULL && count < BTA_SDP_MAX_RECORDS);
 
     evt_data.record_count = count;
@@ -449,8 +394,7 @@
 
   tBTA_SDP bta_sdp;
   bta_sdp.sdp_search_comp = evt_data;
-  bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, &bta_sdp,
-                        (void*)&uuid->uu.uuid128);
+  bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, &bta_sdp, (void*)&uuid);
   osi_free(user_data);  // We no longer need the user data to track the search
 }
 
@@ -490,13 +434,14 @@
 
   APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
 
+  const Uuid& uuid = p_data->get_search.uuid;
   if (bta_sdp_cb.sdp_active != BTA_SDP_ACTIVE_NONE) {
     /* SDP is still in progress */
     status = BTA_SDP_BUSY;
     if (bta_sdp_cb.p_dm_cback) {
       tBTA_SDP_SEARCH_COMP result;
       memset(&result, 0, sizeof(result));
-      result.uuid = p_data->get_search.uuid;
+      result.uuid = uuid;
       result.remote_addr = p_data->get_search.bd_addr;
       result.status = status;
       tBTA_SDP bta_sdp;
@@ -508,20 +453,15 @@
 
   bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_YES;
   bta_sdp_cb.remote_addr = p_data->get_search.bd_addr;
-  /* set the uuid used in the search */
-  tBT_UUID* bta_sdp_search_uuid =
-      static_cast<tBT_UUID*>(osi_malloc(sizeof(tBT_UUID)));
-  memcpy(bta_sdp_search_uuid, &(p_data->get_search.uuid), sizeof(tBT_UUID));
 
   /* initialize the search for the uuid */
-  APPL_TRACE_DEBUG("%s init discovery with UUID(len: %d):", __func__,
-                   bta_sdp_search_uuid->len);
-  for (int x = 0; x < bta_sdp_search_uuid->len; x++) {
-    APPL_TRACE_DEBUG("%X", bta_sdp_search_uuid->uu.uuid128[x]);
-  }
+  APPL_TRACE_DEBUG("%s init discovery with UUID: %s", __func__,
+                   uuid.ToString().c_str());
   SDP_InitDiscoveryDb(p_bta_sdp_cfg->p_sdp_db, p_bta_sdp_cfg->sdp_db_size, 1,
-                      bta_sdp_search_uuid, 0, NULL);
+                      &uuid, 0, NULL);
 
+  Uuid* bta_sdp_search_uuid = (Uuid*)osi_malloc(sizeof(Uuid));
+  *bta_sdp_search_uuid = uuid;
   if (!SDP_ServiceSearchAttributeRequest2(
           p_data->get_search.bd_addr, p_bta_sdp_cfg->p_sdp_db,
           bta_sdp_search_cback, (void*)bta_sdp_search_uuid)) {
@@ -531,7 +471,7 @@
     if (bta_sdp_cb.p_dm_cback) {
       tBTA_SDP_SEARCH_COMP result;
       memset(&result, 0, sizeof(result));
-      result.uuid = p_data->get_search.uuid;
+      result.uuid = uuid;
       result.remote_addr = p_data->get_search.bd_addr;
       result.status = status;
       tBTA_SDP bta_sdp;
diff --git a/bta/sdp/bta_sdp_api.cc b/bta/sdp/bta_sdp_api.cc
index bc6a9b9..17e449c 100644
--- a/bta/sdp/bta_sdp_api.cc
+++ b/bta/sdp/bta_sdp_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 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.
@@ -56,7 +56,7 @@
   tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
 
   APPL_TRACE_API(__func__);
-  if (p_cback && false == bta_sys_is_register(BTA_ID_SDP)) {
+  if (p_cback && !bta_sys_is_register(BTA_ID_SDP)) {
     memset(&bta_sdp_cb, 0, sizeof(tBTA_SDP_CB));
 
     /* register with BTA system manager */
@@ -87,7 +87,8 @@
  *                  BTA_SDP_FAILURE, otherwise.
  *
  ******************************************************************************/
-tBTA_SDP_STATUS BTA_SdpSearch(const RawAddress& bd_addr, tSDP_UUID* uuid) {
+tBTA_SDP_STATUS BTA_SdpSearch(const RawAddress& bd_addr,
+                              const bluetooth::Uuid& uuid) {
   tBTA_SDP_API_SEARCH* p_msg =
       (tBTA_SDP_API_SEARCH*)osi_malloc(sizeof(tBTA_SDP_API_SEARCH));
 
@@ -95,8 +96,7 @@
 
   p_msg->hdr.event = BTA_SDP_API_SEARCH_EVT;
   p_msg->bd_addr = bd_addr;
-  // p_msg->uuid = uuid;
-  memcpy(&(p_msg->uuid), uuid, sizeof(tSDP_UUID));
+  p_msg->uuid = uuid;
 
   bta_sys_sendmsg(p_msg);
 
diff --git a/bta/sdp/bta_sdp_cfg.cc b/bta/sdp/bta_sdp_cfg.cc
index 5be6755..beec3b5 100644
--- a/bta/sdp/bta_sdp_cfg.cc
+++ b/bta/sdp/bta_sdp_cfg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 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.
@@ -28,13 +28,13 @@
 #define BTA_SDP_DB_SIZE 4500
 #endif
 
-static uint8_t __attribute__((aligned(4))) bta_sdp_db_data[BTA_SDP_DB_SIZE];
+static tSDP_DISCOVERY_DB
+    bta_sdp_db_data[BTA_SDP_DB_SIZE / sizeof(tSDP_DISCOVERY_DB)];
 
 /* SDP configuration structure */
 const tBTA_SDP_CFG bta_sdp_cfg = {
-    BTA_SDP_DB_SIZE,
-    (tSDP_DISCOVERY_DB*)
-        bta_sdp_db_data /* The data buffer to keep SDP database */
+    (BTA_SDP_DB_SIZE / sizeof(tSDP_DISCOVERY_DB)) * sizeof(tSDP_DISCOVERY_DB),
+    bta_sdp_db_data /* The data buffer to keep SDP database */
 };
 
-tBTA_SDP_CFG* p_bta_sdp_cfg = (tBTA_SDP_CFG*)&bta_sdp_cfg;
+const tBTA_SDP_CFG* p_bta_sdp_cfg = &bta_sdp_cfg;
diff --git a/bta/sdp/bta_sdp_int.h b/bta/sdp/bta_sdp_int.h
index 0cb5b93..b6b68fa 100644
--- a/bta/sdp/bta_sdp_int.h
+++ b/bta/sdp/bta_sdp_int.h
@@ -2,8 +2,8 @@
 
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@
 typedef struct {
   BT_HDR hdr;
   RawAddress bd_addr;
-  tSDP_UUID uuid;
+  bluetooth::Uuid uuid;
 } tBTA_SDP_API_SEARCH;
 
 /* data type for BTA_SDP_API_SEARCH_EVT */
diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h
index 4edcfb3..a72f34b 100644
--- a/bta/sys/bta_sys.h
+++ b/bta/sys/bta_sys.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,6 +31,8 @@
 #include <base/logging.h>
 #include <base/threading/thread.h>
 
+#include "bta/include/bta_closure_api.h"
+
 /*****************************************************************************
  *  Constants and data types
  ****************************************************************************/
@@ -61,7 +63,6 @@
 /* SW sub-systems */
 #define BTA_ID_SYS 0 /* system manager */
 /* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */
-#define BTA_ID_DM 1             /* device manager */
 #define BTA_ID_DM_SEARCH 2      /* device manager search */
 #define BTA_ID_DM_SEC 3         /* device manager security */
 #define BTA_ID_DG 4             /* data gateway */
@@ -139,7 +140,7 @@
 
 /* conn callback for role / low power manager*/
 typedef void(tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status, uint8_t id,
-                                  uint8_t app_id, const RawAddress* peer_addr);
+                                  uint8_t app_id, const RawAddress& peer_addr);
 
 /* conn callback for role / low power manager*/
 typedef void(tBTA_SYS_SSR_CFG_CBACK)(uint8_t id, uint8_t app_id,
@@ -223,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);
@@ -267,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 6d9fc17..ef9649b 100644
--- a/bta/sys/bta_sys_conn.cc
+++ b/bta/sys/bta_sys_conn.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -97,10 +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__,
+                   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);
   }
 }
 
@@ -137,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);
     }
   }
 }
@@ -190,11 +192,11 @@
 void bta_sys_conn_open(uint8_t id, uint8_t app_id,
                        const RawAddress& peer_addr) {
   if (bta_sys_cb.prm_cb) {
-    bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, &peer_addr);
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
   }
 
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
   }
 }
 
@@ -212,11 +214,11 @@
 void bta_sys_conn_close(uint8_t id, uint8_t app_id,
                         const RawAddress& peer_addr) {
   if (bta_sys_cb.prm_cb) {
-    bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, &peer_addr);
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
   }
 
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
   }
 }
 
@@ -233,7 +235,7 @@
  ******************************************************************************/
 void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) {
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr);
   }
 }
 
@@ -250,7 +252,7 @@
 void bta_sys_app_close(uint8_t id, uint8_t app_id,
                        const RawAddress& peer_addr) {
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr);
   }
 }
 
@@ -268,11 +270,11 @@
   /* AG triggers p_sco_cb by bta_sys_sco_use. */
   if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) {
     /* without querying BTM_GetNumScoLinks() */
-    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, &peer_addr);
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
   }
 
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr);
   }
 }
 
@@ -292,11 +294,11 @@
 
   if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) {
     num_sco_links = BTM_GetNumScoLinks();
-    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, &peer_addr);
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
   }
 
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, peer_addr);
   }
 }
 
@@ -315,7 +317,7 @@
   /* AV streaming need to be suspended before SCO is connected. */
   if (bta_sys_cb.p_sco_cb) {
     /* without querying BTM_GetNumScoLinks() */
-    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, &peer_addr);
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
   }
 }
 
@@ -333,7 +335,7 @@
                        const RawAddress& peer_addr) {
   if ((bta_sys_cb.p_sco_cb)) {
     uint8_t num_sco_links = BTM_GetNumScoLinks();
-    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, &peer_addr);
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
   }
 }
 /*******************************************************************************
@@ -366,8 +368,10 @@
  ******************************************************************************/
 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);
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr);
   }
 }
 
@@ -383,8 +387,10 @@
  ******************************************************************************/
 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);
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr);
   }
 }
 
@@ -399,8 +405,10 @@
  *
  ******************************************************************************/
 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, NULL);
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy,
+                           RawAddress::kEmpty);
   }
 }
 
@@ -415,8 +423,10 @@
  *
  ******************************************************************************/
 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, NULL);
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy,
+                           RawAddress::kEmpty);
   }
 }
 
@@ -432,11 +442,11 @@
  ******************************************************************************/
 void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) {
   if (bta_sys_cb.prm_cb) {
-    bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, &peer_addr);
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
   }
 
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
   }
 }
 
@@ -452,11 +462,11 @@
  ******************************************************************************/
 void bta_sys_busy(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) {
   if (bta_sys_cb.prm_cb) {
-    bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, &peer_addr);
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
   }
 
   if (bta_sys_cb.ppm_cb) {
-    bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, &peer_addr);
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
   }
 }
 
diff --git a/bta/sys/bta_sys_int.h b/bta/sys/bta_sys_int.h
index dc88e45..fcf2199 100644
--- a/bta/sys/bta_sys_int.h
+++ b/bta/sys/bta_sys_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/sys/bta_sys_main.cc b/bta/sys/bta_sys_main.cc
index 777f23a..bdedcde 100644
--- a/bta/sys/bta_sys_main.cc
+++ b/bta/sys/bta_sys_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
 #include "osi/include/thread.h"
 #include "utl.h"
 
-#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == true)
+#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == TRUE)
 #include "bta_ar_api.h"
 #endif
 
@@ -159,8 +159,12 @@
 typedef const uint8_t (*tBTA_SYS_ST_TBL)[BTA_SYS_NUM_COLS];
 
 /* state table */
-const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = {bta_sys_hw_off, bta_sys_hw_starting,
-                                          bta_sys_hw_on, bta_sys_hw_stopping};
+const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = {
+    bta_sys_hw_off,      /* BTA_SYS_HW_OFF */
+    bta_sys_hw_starting, /* BTA_SYS_HW_STARTING */
+    bta_sys_hw_on,       /* BTA_SYS_HW_ON */
+    bta_sys_hw_stopping  /* BTA_SYS_HW_STOPPING */
+};
 
 /*******************************************************************************
  *
@@ -181,9 +185,9 @@
   bta_sys_register(BTA_ID_SYS, &bta_sys_hw_reg);
 
   /* register for BTM notifications */
-  BTM_RegisterForDeviceStatusNotif((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback);
+  BTM_RegisterForDeviceStatusNotif(&bta_sys_hw_btm_cback);
 
-#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == true)
+#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == TRUE)
   bta_ar_init();
 #endif
 }
@@ -543,19 +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 || !bta_message_loop->task_runner().get()) {
+  if (!bta_message_loop) {
     APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
-    return;
+    return BT_STATUS_FAIL;
   }
 
-  bta_message_loop->task_runner()->PostTask(from_here, task);
+  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 BT_STATUS_FAIL;
+  }
+
+  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;
 }
 
 /*******************************************************************************
@@ -595,7 +609,7 @@
 
   switch (module) {
     case BTA_SYS_HW_BLUETOOTH:
-      bta_id = BTA_ID_DM;
+      bta_id = BTA_ID_DM_SEARCH;
       bta_id_max = BTA_ID_BLUETOOTH_MAX;
       break;
     default:
@@ -605,7 +619,7 @@
 
   for (; bta_id <= bta_id_max; bta_id++) {
     if (bta_sys_cb.reg[bta_id] != NULL) {
-      if (bta_sys_cb.is_reg[bta_id] == true &&
+      if (bta_sys_cb.is_reg[bta_id] &&
           bta_sys_cb.reg[bta_id]->disable != NULL) {
         (*bta_sys_cb.reg[bta_id]->disable)();
       }
diff --git a/bta/sys/utl.cc b/bta/sys/utl.cc
index 7feda33..92318d4 100644
--- a/bta/sys/utl.cc
+++ b/bta/sys/utl.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/bta/test/bta_hf_client_test.cc b/bta/test/bta_hf_client_test.cc
index 01d9f5f..107a2e5 100644
--- a/bta/test/bta_hf_client_test.cc
+++ b/bta/test/bta_hf_client_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
diff --git a/bta/test/gatt_cache_file_test.cc b/bta/test/gatt_cache_file_test.cc
new file mode 100644
index 0000000..3ea8902
--- /dev/null
+++ b/bta/test/gatt_cache_file_test.cc
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ *  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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include "bta/include/bta_gatt_api.h"
+
+using bluetooth::Uuid;
+
+/* This test makes sure that v3 cache element is properly encoded into file*/
+TEST(GattCacheTest, nv_attr_to_binary_test) {
+  tBTA_GATTC_NV_ATTR attr{
+      .uuid = Uuid::FromString("1800"),
+      .s_handle = 0x0001,
+      .e_handle = 0xFFFF,
+      .attr_type = 0x01,
+      .id = 0x02,
+      .prop = 0x03,
+      .is_primary = false,
+      .incl_srvc_handle = 0x4543,
+  };
+
+  constexpr size_t len = sizeof(tBTA_GATTC_NV_ATTR);
+  uint8_t binary_form[len] = {0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10,
+                              0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B,
+                              0x34, 0xFB, 0x01, 0x00, 0xFF, 0xFF, 0x01,
+                              0x02, 0x03, 0x00, 0x43, 0x45};
+
+  // USEFUL for debugging:
+  // LOG(ERROR) << " " << base::HexEncode(binary_form, len);
+  EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
diff --git a/btcore/Android.bp b/btcore/Android.bp
index 3984098..6f5b0ad 100644
--- a/btcore/Android.bp
+++ b/btcore/Android.bp
@@ -11,17 +11,14 @@
         "src/module.cc",
         "src/osi_module.cc",
         "src/property.cc",
-        "src/uuid.cc",
     ],
     shared_libs: [
         "liblog",
     ],
+    header_libs: ["libbluetooth_headers"],
     host_supported: true,
     target: {
-        darwin: {
-            enabled: false,
-        },
-        linux: {
+        linux_glibc: {
             cflags: ["-D_GNU_SOURCE"],
         },
     },
@@ -40,7 +37,6 @@
     srcs: [
         "test/device_class_test.cc",
         "test/property_test.cc",
-        "test/uuid_test.cc",
     ],
     shared_libs: [
         "liblog",
@@ -51,9 +47,4 @@
         "libosi",
     ],
     host_supported: true,
-    target: {
-        darwin: {
-            enabled: false,
-        }
-    }
 }
diff --git a/btcore/AndroidTest.xml b/btcore/AndroidTest.xml
index be321c5..27cd569 100644
--- a/btcore/AndroidTest.xml
+++ b/btcore/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright 2017 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.
diff --git a/btcore/BUILD.gn b/btcore/BUILD.gn
index 01d5ec1..01b9cf7 100644
--- a/btcore/BUILD.gn
+++ b/btcore/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
     "src/hal_util.cc",
     "src/module.cc",
     "src/property.cc",
-    "src/uuid.cc",
     "src/osi_module.cc",
   ]
 
@@ -39,7 +38,6 @@
   sources = [
     "test/device_class_test.cc",
     "test/property_test.cc",
-    "test/uuid_test.cc",
     "//osi/test/AllocationTestHarness.cc",
   ]
 
diff --git a/btcore/include/device_class.h b/btcore/include/device_class.h
index 2a11400..0bfbf3f 100644
--- a/btcore/include/device_class.h
+++ b/btcore/include/device_class.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/include/device_features.h b/btcore/include/device_features.h
index bf62949..6cb2df6 100644
--- a/btcore/include/device_features.h
+++ b/btcore/include/device_features.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/include/event_mask.h b/btcore/include/event_mask.h
index cabac9e..c3efe64 100644
--- a/btcore/include/event_mask.h
+++ b/btcore/include/event_mask.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/include/hal_util.h b/btcore/include/hal_util.h
index 46e4906..5de668f 100644
--- a/btcore/include/hal_util.h
+++ b/btcore/include/hal_util.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -16,9 +16,8 @@
 
 #pragma once
 
-struct hw_module_t;
+#include <hardware/bluetooth.h>
 
-// Loads the Bluetooth library. If OS_GENERIC is defined, this function looks
-// explicitly for libbluetooth.default.so and loads it. On Android, this calls
-// the hw_get_module routine with the Bluetooth stack module id.
-int hal_util_load_bt_library(const struct hw_module_t** module);
+// Loads the Bluetooth library. This function looks explicitly for
+// libbluetooth.so and loads it.
+int hal_util_load_bt_library(const bt_interface_t** interface);
diff --git a/btcore/include/iac.h b/btcore/include/iac.h
index 6272b0a..39c830e 100644
--- a/btcore/include/iac.h
+++ b/btcore/include/iac.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/include/module.h b/btcore/include/module.h
index 1b29fbb..949d147 100644
--- a/btcore/include/module.h
+++ b/btcore/include/module.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/include/osi_module.h b/btcore/include/osi_module.h
index 964a3fa..d0a8039 100644
--- a/btcore/include/osi_module.h
+++ b/btcore/include/osi_module.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/include/property.h b/btcore/include/property.h
index 40e2f2a..b11cf7f 100644
--- a/btcore/include/property.h
+++ b/btcore/include/property.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <bluetooth/uuid.h>
 #include <hardware/bluetooth.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -48,7 +49,7 @@
 bt_property_t* property_new_name(const char* name);
 bt_property_t* property_new_rssi(const int8_t rssi);
 bt_property_t* property_new_scan_mode(bt_scan_mode_t scan_mode);
-bt_property_t* property_new_uuids(const bt_uuid_t* uuid, size_t count);
+bt_property_t* property_new_uuids(const bluetooth::Uuid* uuid, size_t count);
 
 // Property resource frees both property and value.
 void property_free(bt_property_t* property);
@@ -76,5 +77,5 @@
 const bt_bdname_t* property_as_name(const bt_property_t* property);
 int8_t property_as_rssi(const bt_property_t* property);
 bt_scan_mode_t property_as_scan_mode(const bt_property_t* property);
-const bt_uuid_t* property_as_uuids(const bt_property_t* property,
-                                   size_t* count);
+const bluetooth::Uuid* property_as_uuids(const bt_property_t* property,
+                                         size_t* count);
diff --git a/btcore/include/uuid.h b/btcore/include/uuid.h
deleted file mode 100644
index 6114ab3..0000000
--- a/btcore/include/uuid.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2014 Google, Inc.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at:
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- ******************************************************************************/
-
-#pragma once
-
-#include <hardware/bluetooth.h>
-#include <stdbool.h>
-
-typedef struct uuid_string_t uuid_string_t;
-
-// Creates uuid string structure to hold a well formed UUID
-// string.  Must release resources with |uuid_string_free|.
-// Returns NULL if no memory.
-uuid_string_t* uuid_string_new(void);
-
-// Frees a uuid string structure created from |uuid_string_new|.
-// |uuid_string| may be NULL.
-void uuid_string_free(uuid_string_t* uuid_string);
-
-// Returns a string pointer to the well formed UUID string
-// entry.  |uuid_string| must not be NULL.
-const char* uuid_string_data(const uuid_string_t* uuid_string);
-
-// Creates uuid structure from a well formed UUID string
-// |uuid_string|.  The caller takes ownership of the uuid
-// structure and must release resources with |uuid_free|.
-// |uuid_string| must not be NULL.
-//
-// Returns NULL if |uuid_string| is malformed or no memory.
-//
-// A well formed UUID string is structured like this:
-//   "00112233-4455-6677-8899-aabbccddeeff"
-bt_uuid_t* uuid_new(const char* uuid_string);
-
-// Frees a uuid structure created from |uuid_new| and friends.
-// |uuid| may be NULL.
-void uuid_free(bt_uuid_t* uuid);
-
-// Returns true if the UUID is all zeros, false otherwise.
-// |uuid| may not be NULL.
-bool uuid_is_empty(const bt_uuid_t* uuid);
-
-// Returns true if the two UUIDs are equal, false otherwise.
-// |first| and |second| may not be NULL.
-bool uuid_is_equal(const bt_uuid_t* first, const bt_uuid_t* second);
-
-// Copies uuid |src| into |dest| and returns a pointer to |dest|.
-// |src| and |dest| must not be NULL.
-bt_uuid_t* uuid_copy(bt_uuid_t* dest, const bt_uuid_t* src);
-
-// Converts contents of |uuid| to a well formed UUID string
-// |uuid_string| using numbers and lower case letter.  |uuid|
-// and |uuid_string| must not be NULL.
-void uuid_to_string(const bt_uuid_t* uuid, uuid_string_t* uuid_string);
-
-// Converts contents of |uuid| to a short uuid if possible.  Returns
-// true if conversion is possible, false otherwise.
-// |uuid|, |uuid16| and |uuid32| must not be NULL.
-bool uuid_128_to_16(const bt_uuid_t* uuid, uint16_t* uuid16);
-bool uuid_128_to_32(const bt_uuid_t* uuid, uint32_t* uuid32);
diff --git a/btcore/include/version.h b/btcore/include/version.h
index a0696ad..d7787c7 100644
--- a/btcore/include/version.h
+++ b/btcore/include/version.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/src/device_class.cc b/btcore/src/device_class.cc
index d421b6d..911eeee 100644
--- a/btcore/src/device_class.cc
+++ b/btcore/src/device_class.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
 #include <string.h>
 
 #include "btcore/include/device_class.h"
-#include "osi/include/osi.h"
 
 typedef struct _bt_device_class_t {
   uint32_t unused : 2;  // LSBs
@@ -35,7 +34,9 @@
 
 // Ensure the internal device class implementation and public one
 // have equal size.
-COMPILE_ASSERT(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t));
+static_assert(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t),
+              "Internal and external device class implementation should have "
+              "the same size");
 
 // [Major Service Classes]
 // (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
diff --git a/btcore/src/hal_util.cc b/btcore/src/hal_util.cc
index 21be613..d043348 100644
--- a/btcore/src/hal_util.cc
+++ b/btcore/src/hal_util.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -16,8 +16,9 @@
 
 #define LOG_TAG "hal_util"
 
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
 #include <hardware/bluetooth.h>
-#include <hardware/hardware.h>
 
 #include <dlfcn.h>
 #include <errno.h>
@@ -26,66 +27,41 @@
 #include "btcore/include/hal_util.h"
 #include "osi/include/log.h"
 
-#if defined(OS_GENERIC)
+using base::StringPrintf;
 
-// TODO(armansito): All logging macros should include __func__ by default (see
-// Bug: 22671731)
-#define HULOGERR(fmt, args...)                                          \
-  LOG_ERROR(LOG_TAG, "[%s] failed to load the Bluetooth library: " fmt, \
-            __func__, ##args)
+#define BLUETOOTH_LIBRARY_NAME "libbluetooth.so"
 
-// TODO(armansito): It might be better to pass the library name in a more
-// generic manner as opposed to hard-coding it here.
-static const char kBluetoothLibraryName[] = "libbluetooth.default.so";
-
-static int load_bt_library(const struct hw_module_t** module) {
-  const char* id = BT_STACK_MODULE_ID;
-  const char* sym = HAL_MODULE_INFO_SYM_AS_STR;
-  struct hw_module_t* hmi = nullptr;
+int hal_util_load_bt_library(const bt_interface_t** interface) {
+  const char* sym = BLUETOOTH_INTERFACE_STRING;
+  bt_interface_t* itf = nullptr;
 
   // Always try to load the default Bluetooth stack on GN builds.
-  void* handle = dlopen(kBluetoothLibraryName, RTLD_NOW);
+  void* handle = dlopen(BLUETOOTH_LIBRARY_NAME, RTLD_NOW);
   if (!handle) {
-    char const* err_str = dlerror();
-    HULOGERR("%s", err_str ? err_str : "error unknown");
+    const char* err_str = dlerror();
+    LOG(ERROR) << __func__ << ": failed to load bluetooth library, error="
+               << (err_str ? err_str : "error unknown");
     goto error;
   }
 
-  // Get the address of the struct hal_module_info.
-  hmi = (struct hw_module_t*)dlsym(handle, sym);
-  if (!hmi) {
-    HULOGERR("%s", sym);
+  // Get the address of the bt_interface_t.
+  itf = (bt_interface_t*)dlsym(handle, sym);
+  if (!itf) {
+    LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library "
+               << sym;
     goto error;
   }
 
-  // Check that the id matches.
-  if (strcmp(id, hmi->id) != 0) {
-    HULOGERR("id=%s does not match HAL module ID: %s", id, hmi->id);
-    goto error;
-  }
-
-  hmi->dso = handle;
-
   // Success.
-  LOG_INFO(LOG_TAG, "[%s] loaded HAL id=%s path=%s hmi=%p handle=%p", __func__,
-           id, kBluetoothLibraryName, hmi, handle);
+  LOG(INFO) << __func__ << " loaded HAL path=" << BLUETOOTH_LIBRARY_NAME
+            << " btinterface=" << itf << " handle=" << handle;
 
-  *module = hmi;
+  *interface = itf;
   return 0;
 
 error:
-  *module = NULL;
+  *interface = NULL;
   if (handle) dlclose(handle);
 
   return -EINVAL;
 }
-
-#endif  // defined(OS_GENERIC)
-
-int hal_util_load_bt_library(const struct hw_module_t** module) {
-#if defined(OS_GENERIC)
-  return load_bt_library(module);
-#else  // !defined(OS_GENERIC)
-  return hw_get_module(BT_STACK_MODULE_ID, module);
-#endif  // defined(OS_GENERIC)
-}
diff --git a/btcore/src/module.cc b/btcore/src/module.cc
index 1a0674a..88d4f80 100644
--- a/btcore/src/module.cc
+++ b/btcore/src/module.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/src/osi_module.cc b/btcore/src/osi_module.cc
index 1938d3f..9481c87 100644
--- a/btcore/src/osi_module.cc
+++ b/btcore/src/osi_module.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/src/property.cc b/btcore/src/property.cc
index 1e314f0..a3ce6f7 100644
--- a/btcore/src/property.cc
+++ b/btcore/src/property.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,8 +20,10 @@
 #include <base/logging.h>
 #include <string.h>
 #include "btcore/include/device_class.h"
-#include "btcore/include/uuid.h"
 #include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+
+using bluetooth::Uuid;
 
 static bt_property_t* property_new_(void* val, size_t len,
                                     bt_property_type_t type);
@@ -110,10 +112,9 @@
                        BT_PROPERTY_ADAPTER_SCAN_MODE);
 }
 
-bt_property_t* property_new_uuids(const bt_uuid_t* uuid, size_t count) {
+bt_property_t* property_new_uuids(const Uuid* uuid, size_t count) {
   CHECK(uuid != NULL);
-  return property_new_((void*)uuid, sizeof(bt_uuid_t) * count,
-                       BT_PROPERTY_UUIDS);
+  return property_new_((void*)uuid, sizeof(Uuid) * count, BT_PROPERTY_UUIDS);
 }
 
 void property_free(bt_property_t* property) {
@@ -207,11 +208,10 @@
   return *(const bt_scan_mode_t*)property->val;
 }
 
-const bt_uuid_t* property_as_uuids(const bt_property_t* property,
-                                   size_t* count) {
+const Uuid* property_as_uuids(const bt_property_t* property, size_t* count) {
   CHECK(property_is_uuids(property));
-  *count = sizeof(bt_uuid_t) / property->len;
-  return (const bt_uuid_t*)property->val;
+  *count = sizeof(Uuid) / property->len;
+  return (const Uuid*)property->val;
 }
 
 static bt_property_t* property_new_(void* val, size_t len,
@@ -219,8 +219,12 @@
   bt_property_t* property =
       static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t)));
 
-  property->val = osi_malloc(len);
-  memcpy(property->val, val, len);
+  property->val = osi_calloc(len + 1);
+  if (type == BT_PROPERTY_BDNAME) {
+    strlcpy((char*)property->val, (const char*)val, len);
+  } else {
+    memcpy(property->val, val, len);
+  }
 
   property->type = type;
   property->len = len;
diff --git a/btcore/src/uuid.cc b/btcore/src/uuid.cc
deleted file mode 100644
index 9985fe6..0000000
--- a/btcore/src/uuid.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2014 Google, Inc.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at:
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- ******************************************************************************/
-
-#include <base/logging.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "btcore/include/uuid.h"
-#include "osi/include/allocator.h"
-
-static const size_t UUID_WELL_FORMED_STRING_LEN = 36;
-static const size_t UUID_WELL_FORMED_STRING_LEN_WITH_NULL = 36 + 1;
-
-typedef struct uuid_string_t { char string[0]; } uuid_string_t;
-
-static const bt_uuid_t empty_uuid = {{0}};
-
-// The base UUID is used for calculating 128-bit UUIDs from 16 and
-// 32 bit UUIDs as described in the SDP specification.
-static const bt_uuid_t base_uuid = {{
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-    0x5f, 0x9b, 0x34, 0xfb,
-}};
-
-static bool uuid_is_base(const bt_uuid_t* uuid);
-
-uuid_string_t* uuid_string_new(void) {
-  return static_cast<uuid_string_t*>(
-      osi_calloc(UUID_WELL_FORMED_STRING_LEN_WITH_NULL));
-}
-
-void uuid_string_free(uuid_string_t* uuid_string) { osi_free(uuid_string); }
-
-const char* uuid_string_data(const uuid_string_t* uuid_string) {
-  CHECK(uuid_string != NULL);
-  return (const char*)uuid_string->string;
-}
-
-bt_uuid_t* uuid_new(const char* uuid_string) {
-  CHECK(uuid_string != NULL);
-
-  if (strlen(uuid_string) < UUID_WELL_FORMED_STRING_LEN) return NULL;
-  if (uuid_string[8] != '-' || uuid_string[13] != '-' ||
-      uuid_string[18] != '-' || uuid_string[23] != '-')
-    return NULL;
-
-  bt_uuid_t* uuid = static_cast<bt_uuid_t*>(osi_calloc(sizeof(bt_uuid_t)));
-
-  const char* s = uuid_string;
-  for (size_t i = 0; i < sizeof(bt_uuid_t); ++i, s += 2) {
-    char buf[3] = {0};
-    buf[0] = s[0];
-    buf[1] = s[1];
-    uuid->uu[i] = strtoul(buf, NULL, 16);
-    // Adjust by skipping the dashes
-    switch (i) {
-      case 3:
-      case 5:
-      case 7:
-      case 9:
-        s++;
-        break;
-    }
-  }
-  return uuid;
-}
-
-void uuid_free(bt_uuid_t* uuid) { osi_free(uuid); }
-
-bool uuid_is_empty(const bt_uuid_t* uuid) {
-  return !uuid || !memcmp(uuid, &empty_uuid, sizeof(bt_uuid_t));
-}
-
-bool uuid_is_equal(const bt_uuid_t* first, const bt_uuid_t* second) {
-  CHECK(first != NULL);
-  CHECK(second != NULL);
-  return !memcmp(first, second, sizeof(bt_uuid_t));
-}
-
-bt_uuid_t* uuid_copy(bt_uuid_t* dest, const bt_uuid_t* src) {
-  CHECK(dest != NULL);
-  CHECK(src != NULL);
-  return (bt_uuid_t*)memcpy(dest, src, sizeof(bt_uuid_t));
-}
-
-bool uuid_128_to_16(const bt_uuid_t* uuid, uint16_t* uuid16) {
-  CHECK(uuid != NULL);
-  CHECK(uuid16 != NULL);
-
-  if (!uuid_is_base(uuid)) return false;
-
-  *uuid16 = (uuid->uu[2] << 8) + uuid->uu[3];
-  return true;
-}
-
-bool uuid_128_to_32(const bt_uuid_t* uuid, uint32_t* uuid32) {
-  CHECK(uuid != NULL);
-  CHECK(uuid32 != NULL);
-
-  if (!uuid_is_base(uuid)) return false;
-
-  *uuid32 = (uuid->uu[0] << 24) + (uuid->uu[1] << 16) + (uuid->uu[2] << 8) +
-            uuid->uu[3];
-  return true;
-}
-
-void uuid_to_string(const bt_uuid_t* uuid, uuid_string_t* uuid_string) {
-  CHECK(uuid != NULL);
-  CHECK(uuid_string != NULL);
-
-  char* string = uuid_string->string;
-  char* end = string + UUID_WELL_FORMED_STRING_LEN_WITH_NULL;
-
-  // XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
-  for (int i = 0; i < 4; i++) {
-    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
-  }
-  *string = '-';
-  ++string;
-  for (int i = 4; i < 6; i++) {
-    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
-  }
-  *string = '-';
-  ++string;
-  for (int i = 6; i < 8; i++) {
-    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
-  }
-  *string = '-';
-  ++string;
-  for (int i = 8; i < 10; i++) {
-    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
-  }
-  *string = '-';
-  ++string;
-  for (int i = 10; i < 16; i++) {
-    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
-  }
-}
-
-static bool uuid_is_base(const bt_uuid_t* uuid) {
-  if (!uuid) return false;
-
-  for (int i = 4; i < 16; i++) {
-    if (uuid->uu[i] != base_uuid.uu[i]) return false;
-  }
-  return true;
-}
diff --git a/btcore/test/device_class_test.cc b/btcore/test/device_class_test.cc
index 434f9ca..5ce1523 100644
--- a/btcore/test/device_class_test.cc
+++ b/btcore/test/device_class_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btcore/test/property_test.cc b/btcore/test/property_test.cc
index e87c186..72eac76 100644
--- a/btcore/test/property_test.cc
+++ b/btcore/test/property_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@
 
 #include "btcore/include/property.h"
 
+using bluetooth::Uuid;
+
 class PropertyTest : public AllocationTestHarness {};
 
 TEST_F(PropertyTest, addr) {
@@ -131,38 +133,38 @@
 }
 
 TEST_F(PropertyTest, uuids) {
-  bt_uuid_t uuid0 = {{
+  Uuid uuid0 = Uuid::From128BitBE({{
       0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
       0xcc, 0xdd, 0xee, 0xff,
-  }};
+  }});
   bt_property_t* property = property_new_uuids(&uuid0, 1);
 
-  EXPECT_EQ(0, strcmp((const char*)uuid0.uu, (char*)property->val));
+  EXPECT_EQ(0, memcmp(uuid0.To128BitBE().data(), property->val, sizeof(Uuid)));
   EXPECT_EQ(BT_PROPERTY_UUIDS, property->type);
-  EXPECT_EQ((int)sizeof(bt_uuid_t), property->len);
+  EXPECT_EQ((int)sizeof(Uuid), property->len);
 
   size_t uuid_cnt1;
-  const bt_uuid_t* uuid1 = property_as_uuids(property, &uuid_cnt1);
-  EXPECT_EQ(0, memcmp(uuid1->uu, uuid1->uu, sizeof(bt_uuid_t)));
+  const Uuid* uuid1 = property_as_uuids(property, &uuid_cnt1);
+  EXPECT_EQ(uuid0, *uuid1);
 
   property_free(property);
 }
 
 TEST_F(PropertyTest, copy) {
   {
-    bt_uuid_t uuids[] = {
-        {{
+    Uuid uuids[] = {
+        Uuid::From128BitBE({{
             0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
             0xbb, 0xcc, 0xdd, 0xee, 0xff,
-        }},
-        {{
+        }}),
+        Uuid::From128BitBE({{
             0xf0, 0xe1, 0xd2, 0xc3, 0xf4, 0xe5, 0xd6, 0xc7, 0xf8, 0xe9, 0xda,
             0xcb, 0xfc, 0xed, 0xde, 0xcf,
-        }},
+        }}),
     };
 
     bt_property_t* property0 =
-        property_new_uuids(uuids, sizeof(bt_uuid_t) / sizeof(uuids));
+        property_new_uuids(uuids, sizeof(uuids) / sizeof(Uuid));
 
     bt_property_t property1;
     property_copy(&property1, property0);
diff --git a/btcore/test/uuid_test.cc b/btcore/test/uuid_test.cc
deleted file mode 100644
index e9a40ed..0000000
--- a/btcore/test/uuid_test.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2014 Google, Inc.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at:
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- ******************************************************************************/
-
-#include <gtest/gtest.h>
-#include "osi/test/AllocationTestHarness.h"
-
-#include "btcore/include/uuid.h"
-
-static const char* UUID_EMPTY = "00000000-0000-0000-0000-000000000000";
-static const char* UUID_ONES = "11111111-1111-1111-1111-111111111111";
-static const char* UUID_SEQUENTIAL = "01234567-89ab-cdef-ABCD-EF0123456789";
-static const char* UUID_BASE = "00000000-0000-1000-8000-00805f9b34fb";
-
-class UuidTest : public AllocationTestHarness {
- protected:
-  virtual void SetUp() {}
-
-  virtual void TearDown() {}
-};
-
-TEST_F(UuidTest, new_from_string) {
-  bt_uuid_t* uuid;
-
-  uuid = uuid_new("incorrect length");
-  EXPECT_EQ(NULL, uuid);
-
-  uuid = uuid_new("correct length but missing dashes --");
-  EXPECT_EQ(NULL, uuid);
-
-  uuid = uuid_new(UUID_ONES);
-  ASSERT_TRUE(uuid != NULL);
-  for (int i = 0; i < 16; i++) {
-    EXPECT_EQ(0x11, uuid->uu[i]);
-  }
-  uuid_free(uuid);
-
-  uuid = uuid_new(UUID_SEQUENTIAL);
-  EXPECT_EQ(0x01, uuid->uu[0]);
-  EXPECT_EQ(0x23, uuid->uu[1]);
-  EXPECT_EQ(0x45, uuid->uu[2]);
-  EXPECT_EQ(0x67, uuid->uu[3]);
-  EXPECT_EQ(0x89, uuid->uu[4]);
-  EXPECT_EQ(0xAB, uuid->uu[5]);
-  EXPECT_EQ(0xCD, uuid->uu[6]);
-  EXPECT_EQ(0xEF, uuid->uu[7]);
-  EXPECT_EQ(0xab, uuid->uu[8]);
-  EXPECT_EQ(0xcd, uuid->uu[9]);
-  EXPECT_EQ(0xef, uuid->uu[10]);
-  EXPECT_EQ(0x01, uuid->uu[11]);
-  EXPECT_EQ(0x23, uuid->uu[12]);
-  EXPECT_EQ(0x45, uuid->uu[13]);
-  EXPECT_EQ(0x67, uuid->uu[14]);
-  EXPECT_EQ(0x89, uuid->uu[15]);
-  uuid_free(uuid);
-
-  uuid = uuid_new(UUID_BASE);
-  EXPECT_EQ(0x00, uuid->uu[0]);
-  EXPECT_EQ(0x00, uuid->uu[1]);
-  EXPECT_EQ(0x00, uuid->uu[2]);
-  EXPECT_EQ(0x00, uuid->uu[3]);
-  EXPECT_EQ(0x00, uuid->uu[4]);
-  EXPECT_EQ(0x00, uuid->uu[5]);
-  EXPECT_EQ(0x10, uuid->uu[6]);
-  EXPECT_EQ(0x00, uuid->uu[7]);
-  EXPECT_EQ(0x80, uuid->uu[8]);
-  EXPECT_EQ(0x00, uuid->uu[9]);
-  EXPECT_EQ(0x00, uuid->uu[10]);
-  EXPECT_EQ(0x80, uuid->uu[11]);
-  EXPECT_EQ(0x5f, uuid->uu[12]);
-  EXPECT_EQ(0x9b, uuid->uu[13]);
-  EXPECT_EQ(0x34, uuid->uu[14]);
-  EXPECT_EQ(0xfb, uuid->uu[15]);
-  uuid_free(uuid);
-}
-
-TEST_F(UuidTest, uuid_is_empty) {
-  bt_uuid_t* uuid = NULL;
-
-  uuid = uuid_new(UUID_EMPTY);
-  ASSERT_TRUE(uuid != NULL);
-  EXPECT_TRUE(uuid_is_empty(uuid));
-  uuid_free(uuid);
-
-  uuid = uuid_new(UUID_BASE);
-  ASSERT_TRUE(uuid != NULL);
-  EXPECT_FALSE(uuid_is_empty(uuid));
-  uuid_free(uuid);
-}
-
-TEST_F(UuidTest, uuid_128_to_16) {
-  bt_uuid_t* uuid = NULL;
-  uint16_t uuid16 = 0xffff;
-
-  uuid = uuid_new(UUID_ONES);
-  EXPECT_FALSE(uuid_128_to_16(uuid, &uuid16));
-  uuid_free(uuid);
-  EXPECT_EQ((uint16_t)0xffff, uuid16);
-
-  uuid = uuid_new(UUID_BASE);
-  EXPECT_TRUE(uuid_128_to_16(uuid, &uuid16));
-  uuid_free(uuid);
-  EXPECT_NE((uint16_t)0xffff, uuid16);
-  EXPECT_EQ((uint16_t)0, uuid16);
-}
-
-TEST_F(UuidTest, uuid_128_to_32) {
-  bt_uuid_t* uuid = NULL;
-  uint32_t uuid32 = 0xffffffff;
-
-  uuid = uuid_new(UUID_ONES);
-  EXPECT_FALSE(uuid_128_to_32(uuid, &uuid32));
-  uuid_free(uuid);
-  EXPECT_EQ((uint32_t)0xffffffff, uuid32);
-
-  uuid = uuid_new(UUID_BASE);
-  EXPECT_TRUE(uuid_128_to_32(uuid, &uuid32));
-  uuid_free(uuid);
-  EXPECT_NE((uint32_t)0xffffffff, uuid32);
-  EXPECT_EQ((uint32_t)0, uuid32);
-}
-
-TEST_F(UuidTest, uuid_to_string) {
-  bt_uuid_t* uuid = NULL;
-
-  uuid_string_t* uuid_string = uuid_string_new();
-  EXPECT_TRUE(uuid_string != NULL);
-
-  uuid = uuid_new(UUID_BASE);
-  EXPECT_TRUE(uuid != NULL);
-  uuid_to_string(uuid, uuid_string);
-  uuid_free(uuid);
-
-  EXPECT_TRUE(!strcmp(UUID_BASE, uuid_string_data(uuid_string)));
-
-  uuid = uuid_new(UUID_SEQUENTIAL);
-  EXPECT_TRUE(uuid != NULL);
-
-  uuid_to_string(uuid, uuid_string);
-  uuid_free(uuid);
-
-  char lower_case_buf[36 + 1];
-  for (int i = 0; i < 36 + 1; i++) {
-    lower_case_buf[i] = tolower(UUID_SEQUENTIAL[i]);
-  }
-  EXPECT_TRUE(!strcmp(lower_case_buf, uuid_string_data(uuid_string)));
-  uuid_string_free(uuid_string);
-}
diff --git a/btif/Android.bp b/btif/Android.bp
index c5ff0765..4b2dc30 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -7,13 +7,14 @@
     "system/bt/bta/dm",
     "system/bt/btcore/include",
     "system/bt/device/include",
-    "system/bt/include",
+    "system/bt/internal_include",
     "system/bt/stack/include",
     "system/bt/stack/l2cap",
     "system/bt/stack/a2dp",
     "system/bt/stack/btm",
     "system/bt/stack/avdt",
     "system/bt/udrv/include",
+    "system/bt/btif/avrcp",
     "system/bt/btif/include",
     "system/bt/btif/co",
     "system/bt/hci/include",
@@ -21,6 +22,8 @@
     "system/bt/embdrv/sbc/encoder/include",
     "system/bt/embdrv/sbc/decoder/include",
     "system/bt/utils/include",
+    "system/bt/include",
+    "system/libhwbinder/include",
 ]
 
 // libbtif static library for target
@@ -30,10 +33,20 @@
     defaults: ["fluoride_defaults"],
     include_dirs: btifCommonIncludes,
     srcs: [
+        // AVRCP Target Service
+        "avrcp/avrcp_service.cc",
+        // Callouts
+        "co/bta_dm_co.cc",
+        "co/bta_av_co.cc",
+        "co/bta_hh_co.cc",
+        "co/bta_hl_co.cc",
+        "co/bta_pan_co.cc",
+        "co/bta_gatts_co.cc",
         // HAL layer
         "src/bluetooth.cc",
         // BTIF implementation
         "src/btif_a2dp.cc",
+        "src/btif_a2dp_audio_interface.cc",
         "src/btif_a2dp_control.cc",
         "src/btif_a2dp_sink.cc",
         "src/btif_a2dp_source.cc",
@@ -53,6 +66,7 @@
         "src/btif_gatt_server.cc",
         "src/btif_gatt_test.cc",
         "src/btif_gatt_util.cc",
+        "src/btif_hearing_aid.cc",
         "src/btif_hf.cc",
         "src/btif_hf_client.cc",
         "src/btif_hh.cc",
@@ -64,7 +78,6 @@
         "src/btif_rc.cc",
         "src/btif_sdp.cc",
         "src/btif_sdp_server.cc",
-        "src/btif_sm.cc",
         "src/btif_sock.cc",
         "src/btif_sock_rfc.cc",
         "src/btif_sock_l2cap.cc",
@@ -76,14 +89,6 @@
         "src/btif_uid.cc",
         "src/btif_util.cc",
         "src/stack_manager.cc",
-        // Callouts
-        "co/bta_ag_co.cc",
-        "co/bta_dm_co.cc",
-        "co/bta_av_co.cc",
-        "co/bta_hh_co.cc",
-        "co/bta_hl_co.cc",
-        "co/bta_pan_co.cc",
-        "co/bta_gatts_co.cc",
     ],
     shared_libs: [
         "libaudioclient",
@@ -91,9 +96,16 @@
         "liblog",
         "libz",
         "libtinyxml2",
+        "android.hardware.bluetooth.a2dp@1.0",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
     ],
     whole_static_libs: [
+        "avrcp-target-service",
         "libaudio-a2dp-hw-utils",
+        "lib-bt-packets",
     ],
     cflags: ["-DBUILDCFG"],
 
@@ -106,17 +118,34 @@
     defaults: ["fluoride_defaults"],
     include_dirs: btifCommonIncludes,
     srcs: ["test/btif_storage_test.cc"],
+    header_libs: ["libbluetooth_headers"],
     shared_libs: [
+        "libaudioclient",
+        "android.hardware.bluetooth.a2dp@1.0",
+        "libhidlbase",
         "liblog",
-        "libhardware",
+        "libprotobuf-cpp-lite",
         "libcutils",
+        "libutils",
     ],
     static_libs: [
+        "libbt-bta",
         "libbtcore",
-        "libbtif",
         "libbt-stack",
+        "libbt-sbc-encoder",
+        "libbt-utils",
+        "libFraunhoferAAC",
+        "libg722codec",
+        "libbtdevice",
+        "libbt-hci",
+        "libudrv-uipc",
         "libbluetooth-types",
         "libosi",
+        "libbt-protos-lite",
+    ],
+    whole_static_libs: [
+        "libbtif",
+        "libbluetooth-for-tests",
     ],
     cflags: ["-DBUILDCFG"],
 }
@@ -131,9 +160,31 @@
       "src/btif_profile_queue.cc",
       "test/btif_profile_queue_test.cc"
     ],
+    header_libs: ["libbluetooth_headers"],
     shared_libs: [
         "liblog",
-        "libhardware",
+        "libcutils",
+    ],
+    static_libs: [
+        "libbluetooth-types",
+        "libosi",
+    ],
+    cflags: ["-DBUILDCFG"],
+}
+
+// btif state machine unit tests for target
+// ========================================================
+cc_test {
+    name: "net_test_btif_state_machine",
+    defaults: ["fluoride_defaults"],
+    include_dirs: btifCommonIncludes,
+    host_supported: true,
+    srcs: [
+      "test/btif_state_machine_test.cc"
+    ],
+    header_libs: ["libbluetooth_headers"],
+    shared_libs: [
+        "liblog",
         "libcutils",
     ],
     static_libs: [
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index 6f29584..de50a97 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
     "src/btif_gatt_server.cc",
     "src/btif_gatt_test.cc",
     "src/btif_gatt_util.cc",
+    "src/btif_hearing_aid.cc",
     "src/btif_hf.cc",
     "src/btif_hf_client.cc",
     "src/btif_hh.cc",
@@ -50,7 +51,6 @@
     "src/btif_rc.cc",
     "src/btif_sdp.cc",
     "src/btif_sdp_server.cc",
-    "src/btif_sm.cc",
     "src/btif_sock.cc",
     "src/btif_sock_l2cap.cc",
     "src/btif_sock_rfc.cc",
@@ -90,7 +90,7 @@
     "//stack/btm",
     "//stack/include",
     "//third_party/tinyxml2",
-    "//include",
+    "//internal_include",
     "//udrv/include",
     "//utils/include",
     "//vnd/include",
diff --git a/btif/avrcp/avrcp_service.cc b/btif/avrcp/avrcp_service.cc
new file mode 100644
index 0000000..8c22365
--- /dev/null
+++ b/btif/avrcp/avrcp_service.cc
@@ -0,0 +1,465 @@
+/*
+ * 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 "avrcp_service.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/task/cancelable_task_tracker.h>
+#include <base/threading/thread.h>
+#include <mutex>
+#include <sstream>
+
+#include "bta_closure_api.h"
+#include "btif_av.h"
+#include "btif_common.h"
+#include "device.h"
+
+namespace bluetooth {
+namespace avrcp {
+// Static variables and interface definitions
+AvrcpService* AvrcpService::instance_ = nullptr;
+AvrcpService::ServiceInterfaceImpl* AvrcpService::service_interface_ = nullptr;
+
+std::mutex jni_mutex_;
+base::MessageLoop* jni_message_loop_ = nullptr;
+base::CancelableTaskTracker task_tracker_;
+
+void do_in_avrcp_jni(const base::Closure& task) {
+  std::lock_guard<std::mutex> lock(jni_mutex_);
+
+  if (jni_message_loop_ == nullptr) {
+    LOG(WARNING) << __func__ << ": jni_message_loop_ is null";
+    return;
+  }
+
+  task_tracker_.PostTask(jni_message_loop_->task_runner().get(), FROM_HERE,
+                         task);
+}
+
+class A2dpInterfaceImpl : public A2dpInterface {
+  RawAddress active_peer() override { return btif_av_source_active_peer(); }
+} a2dp_interface_;
+
+class AvrcpInterfaceImpl : public AvrcpInterface {
+ public:
+  uint16_t AddRecord(uint16_t service_uuid, const char* p_service_name,
+                     const char* p_provider_name, uint16_t categories,
+                     uint32_t sdp_handle, bool browse_supported,
+                     uint16_t profile_version) override {
+    return AVRC_AddRecord(service_uuid, p_service_name, p_provider_name,
+                          categories, sdp_handle, browse_supported,
+                          profile_version);
+  }
+
+  uint16_t FindService(uint16_t service_uuid, const RawAddress& bd_addr,
+                       tAVRC_SDP_DB_PARAMS* p_db,
+                       tAVRC_FIND_CBACK p_cback) override {
+    return AVRC_FindService(service_uuid, bd_addr, p_db, p_cback);
+  }
+
+  uint16_t Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb,
+                const RawAddress& bd_addr) override {
+    return AVRC_Open(p_handle, p_ccb, bd_addr);
+  }
+
+  uint16_t OpenBrowse(uint8_t handle, uint8_t conn_role) override {
+    return AVRC_OpenBrowse(handle, conn_role);
+  }
+
+  uint16_t GetPeerMtu(uint8_t handle) override {
+    return AVCT_GetPeerMtu(handle);
+  }
+
+  uint16_t GetBrowseMtu(uint8_t handle) override {
+    return AVCT_GetBrowseMtu(handle);
+  }
+
+  uint16_t Close(uint8_t handle) override { return AVRC_Close(handle); }
+
+  uint16_t CloseBrowse(uint8_t handle) override {
+    return AVRC_CloseBrowse(handle);
+  }
+
+  uint16_t MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
+                  BT_HDR* p_pkt) override {
+    return AVRC_MsgReq(handle, label, ctype, p_pkt);
+  }
+} avrcp_interface_;
+
+class SdpInterfaceImpl : public SdpInterface {
+ public:
+  bool InitDiscoveryDb(tSDP_DISCOVERY_DB* a, uint32_t b, uint16_t c,
+                       const bluetooth::Uuid* d, uint16_t e,
+                       uint16_t* f) override {
+    return SDP_InitDiscoveryDb(a, b, c, d, e, f);
+  }
+
+  bool ServiceSearchAttributeRequest(const RawAddress& a, tSDP_DISCOVERY_DB* b,
+                                     tSDP_DISC_CMPL_CB* c) override {
+    return SDP_ServiceSearchAttributeRequest(a, b, c);
+  }
+
+  tSDP_DISC_REC* FindServiceInDb(tSDP_DISCOVERY_DB* a, uint16_t b,
+                                 t_sdp_disc_rec* c) override {
+    return SDP_FindServiceInDb(a, b, c);
+  }
+
+  tSDP_DISC_ATTR* FindAttributeInRec(t_sdp_disc_rec* a, uint16_t b) override {
+    return SDP_FindAttributeInRec(a, b);
+  }
+
+  bool FindProfileVersionInRec(t_sdp_disc_rec* a, uint16_t b,
+                               uint16_t* c) override {
+    return SDP_FindProfileVersionInRec(a, b, c);
+  }
+} sdp_interface_;
+
+// A wrapper class for the media callbacks that handles thread
+// switching/synchronization so the devices don't have to worry about it.
+class MediaInterfaceWrapper : public MediaInterface {
+ public:
+  MediaInterfaceWrapper(MediaInterface* cb) : wrapped_(cb){};
+
+  void SendKeyEvent(uint8_t key, KeyState state) override {
+    do_in_avrcp_jni(base::Bind(&MediaInterface::SendKeyEvent,
+                               base::Unretained(wrapped_), key, state));
+  }
+
+  void GetSongInfo(SongInfoCallback info_cb) override {
+    auto cb_lambda = [](SongInfoCallback cb, SongInfo data) {
+      do_in_bta_thread(FROM_HERE, base::Bind(cb, data));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, info_cb);
+
+    do_in_avrcp_jni(base::Bind(&MediaInterface::GetSongInfo,
+                               base::Unretained(wrapped_), bound_cb));
+  }
+
+  void GetPlayStatus(PlayStatusCallback status_cb) override {
+    auto cb_lambda = [](PlayStatusCallback cb, PlayStatus status) {
+      do_in_bta_thread(FROM_HERE, base::Bind(cb, status));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, status_cb);
+
+    do_in_avrcp_jni(base::Bind(&MediaInterface::GetPlayStatus,
+                               base::Unretained(wrapped_), bound_cb));
+  }
+
+  void GetNowPlayingList(NowPlayingCallback now_playing_cb) override {
+    auto cb_lambda = [](NowPlayingCallback cb, std::string curr_media_id,
+                        std::vector<SongInfo> song_list) {
+      do_in_bta_thread(FROM_HERE,
+                       base::Bind(cb, curr_media_id, std::move(song_list)));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, now_playing_cb);
+
+    do_in_avrcp_jni(base::Bind(&MediaInterface::GetNowPlayingList,
+                               base::Unretained(wrapped_), bound_cb));
+  }
+
+  void GetMediaPlayerList(MediaListCallback list_cb) override {
+    auto cb_lambda = [](MediaListCallback cb, uint16_t curr_player,
+                        std::vector<MediaPlayerInfo> player_list) {
+      do_in_bta_thread(FROM_HERE,
+                       base::Bind(cb, curr_player, std::move(player_list)));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, list_cb);
+
+    do_in_avrcp_jni(base::Bind(&MediaInterface::GetMediaPlayerList,
+                               base::Unretained(wrapped_), bound_cb));
+  }
+
+  void GetFolderItems(uint16_t player_id, std::string media_id,
+                      FolderItemsCallback folder_cb) override {
+    auto cb_lambda = [](FolderItemsCallback cb,
+                        std::vector<ListItem> item_list) {
+      do_in_bta_thread(FROM_HERE, base::Bind(cb, std::move(item_list)));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, folder_cb);
+
+    do_in_avrcp_jni(base::Bind(&MediaInterface::GetFolderItems,
+                               base::Unretained(wrapped_), player_id, media_id,
+                               bound_cb));
+  }
+
+  void SetBrowsedPlayer(uint16_t player_id,
+                        SetBrowsedPlayerCallback browse_cb) override {
+    auto cb_lambda = [](SetBrowsedPlayerCallback cb, bool success,
+                        std::string root_id, uint32_t num_items) {
+      do_in_bta_thread(FROM_HERE, base::Bind(cb, success, root_id, num_items));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, browse_cb);
+
+    do_in_avrcp_jni(base::Bind(&MediaInterface::SetBrowsedPlayer,
+                               base::Unretained(wrapped_), player_id,
+                               bound_cb));
+  }
+
+  void PlayItem(uint16_t player_id, bool now_playing,
+                std::string media_id) override {
+    do_in_avrcp_jni(base::Bind(&MediaInterface::PlayItem,
+                               base::Unretained(wrapped_), player_id,
+                               now_playing, media_id));
+  }
+
+  void SetActiveDevice(const RawAddress& address) override {
+    do_in_avrcp_jni(base::Bind(&MediaInterface::SetActiveDevice,
+                               base::Unretained(wrapped_), address));
+  }
+
+  void RegisterUpdateCallback(MediaCallbacks* callback) override {
+    wrapped_->RegisterUpdateCallback(callback);
+  }
+
+  void UnregisterUpdateCallback(MediaCallbacks* callback) override {
+    wrapped_->UnregisterUpdateCallback(callback);
+  }
+
+ private:
+  MediaInterface* wrapped_;
+};
+
+// A wrapper class for the media callbacks that handles thread
+// switching/synchronization so the devices don't have to worry about it.
+class VolumeInterfaceWrapper : public VolumeInterface {
+ public:
+  VolumeInterfaceWrapper(VolumeInterface* interface) : wrapped_(interface){};
+
+  void DeviceConnected(const RawAddress& bdaddr) override {
+    do_in_avrcp_jni(
+        base::Bind(static_cast<void (VolumeInterface::*)(const RawAddress&)>(
+                       &VolumeInterface::DeviceConnected),
+                   base::Unretained(wrapped_), bdaddr));
+  }
+
+  void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override {
+    auto cb_lambda = [](VolumeChangedCb cb, int8_t volume) {
+      do_in_bta_thread(FROM_HERE, base::Bind(cb, volume));
+    };
+
+    auto bound_cb = base::Bind(cb_lambda, cb);
+
+    do_in_avrcp_jni(base::Bind(static_cast<void (VolumeInterface::*)(
+                                   const RawAddress&, VolumeChangedCb)>(
+                                   &VolumeInterface::DeviceConnected),
+                               base::Unretained(wrapped_), bdaddr, bound_cb));
+  }
+
+  void DeviceDisconnected(const RawAddress& bdaddr) override {
+    do_in_avrcp_jni(base::Bind(&VolumeInterface::DeviceDisconnected,
+                               base::Unretained(wrapped_), bdaddr));
+  }
+
+  void SetVolume(int8_t volume) override {
+    do_in_avrcp_jni(base::Bind(&VolumeInterface::SetVolume,
+                               base::Unretained(wrapped_), volume));
+  }
+
+ private:
+  VolumeInterface* wrapped_;
+};
+
+void AvrcpService::Init(MediaInterface* media_interface,
+                        VolumeInterface* volume_interface) {
+  LOG(INFO) << "AVRCP Target Service started";
+
+  // TODO (apanicke): Add a function that sets up the SDP records once we
+  // remove the AVRCP SDP setup in AVDTP (bta_av_main.cc)
+
+  media_interface_ = new MediaInterfaceWrapper(media_interface);
+  media_interface->RegisterUpdateCallback(instance_);
+
+  VolumeInterfaceWrapper* wrapped_volume_interface = nullptr;
+  if (volume_interface != nullptr) {
+    wrapped_volume_interface = new VolumeInterfaceWrapper(volume_interface);
+  }
+
+  volume_interface_ = wrapped_volume_interface;
+
+  ConnectionHandler::Initialize(
+      base::Bind(&AvrcpService::DeviceCallback, base::Unretained(instance_)),
+      &avrcp_interface_, &sdp_interface_, wrapped_volume_interface);
+  connection_handler_ = ConnectionHandler::Get();
+}
+
+void AvrcpService::Cleanup() {
+  LOG(INFO) << "AVRCP Target Service stopped";
+
+  connection_handler_->CleanUp();
+  connection_handler_ = nullptr;
+  if (volume_interface_ != nullptr) {
+    delete volume_interface_;
+  }
+  delete media_interface_;
+}
+
+AvrcpService* AvrcpService::Get() {
+  CHECK(instance_);
+  return instance_;
+}
+
+ServiceInterface* AvrcpService::GetServiceInterface() {
+  if (service_interface_ == nullptr) {
+    service_interface_ = new ServiceInterfaceImpl();
+  }
+
+  return service_interface_;
+}
+
+void AvrcpService::ConnectDevice(const RawAddress& bdaddr) {
+  LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
+
+  connection_handler_->ConnectDevice(bdaddr);
+}
+
+void AvrcpService::DisconnectDevice(const RawAddress& bdaddr) {
+  LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
+  connection_handler_->DisconnectDevice(bdaddr);
+}
+
+void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state,
+                                   bool queue) {
+  LOG(INFO) << __PRETTY_FUNCTION__ << " track_changed=" << track_changed
+            << " : "
+            << " play_state=" << play_state << " : "
+            << " queue=" << queue;
+
+  // This function may be called on any thread, we need to make sure that the
+  // device update happens on the main thread.
+  for (auto device : instance_->connection_handler_->GetListOfDevices()) {
+    do_in_bta_thread(FROM_HERE, base::Bind(&Device::SendMediaUpdate,
+                                           base::Unretained(device.get()),
+                                           track_changed, play_state, queue));
+  }
+}
+
+void AvrcpService::SendFolderUpdate(bool available_players,
+                                    bool addressed_players, bool uids) {
+  LOG(INFO) << __PRETTY_FUNCTION__ << " available_players=" << available_players
+            << " : "
+            << " addressed_players=" << addressed_players << " : "
+            << " uids=" << uids;
+
+  // Ensure that the update is posted to the correct thread
+  for (auto device : instance_->connection_handler_->GetListOfDevices()) {
+    do_in_bta_thread(
+        FROM_HERE,
+        base::Bind(&Device::SendFolderUpdate, base::Unretained(device.get()),
+                   available_players, addressed_players, uids));
+  }
+}
+
+// Send out the track changed info to update the playback state for each device
+void AvrcpService::SendActiveDeviceChanged(const RawAddress& address) {
+  SendMediaUpdate(false, true, false);
+}
+
+void AvrcpService::DeviceCallback(std::shared_ptr<Device> new_device) {
+  if (new_device == nullptr) return;
+
+  // TODO (apanicke): Pass the interfaces into the connection handler
+  // so that the devices can be created with any interfaces they need.
+  new_device->RegisterInterfaces(media_interface_, &a2dp_interface_,
+                                 volume_interface_);
+}
+
+// Service Interface
+void AvrcpService::ServiceInterfaceImpl::Init(
+    MediaInterface* media_interface, VolumeInterface* volume_interface) {
+  std::lock_guard<std::mutex> lock(service_interface_lock_);
+
+  // TODO: This function should block until the service is completely up so
+  // that its possible to call Get() on the service immediately after calling
+  // init without issues.
+
+  CHECK(instance_ == nullptr);
+  instance_ = new AvrcpService();
+
+  {
+    std::lock_guard<std::mutex> jni_lock(jni_mutex_);
+    jni_message_loop_ = get_jni_message_loop();
+  }
+
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&AvrcpService::Init, base::Unretained(instance_),
+                              media_interface, volume_interface));
+}
+
+bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(
+    const RawAddress& bdaddr) {
+  std::lock_guard<std::mutex> lock(service_interface_lock_);
+  CHECK(instance_ != nullptr);
+  do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice,
+                                         base::Unretained(instance_), bdaddr));
+  return true;
+}
+
+bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice(
+    const RawAddress& bdaddr) {
+  std::lock_guard<std::mutex> lock(service_interface_lock_);
+  CHECK(instance_ != nullptr);
+  do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice,
+                                         base::Unretained(instance_), bdaddr));
+  return true;
+}
+
+bool AvrcpService::ServiceInterfaceImpl::Cleanup() {
+  std::lock_guard<std::mutex> lock(service_interface_lock_);
+
+  if (instance_ == nullptr) return false;
+
+  {
+    std::lock_guard<std::mutex> jni_lock(jni_mutex_);
+    task_tracker_.TryCancelAll();
+    jni_message_loop_ = nullptr;
+  }
+
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&AvrcpService::Cleanup, base::Owned(instance_)));
+
+  // Setting instance to nullptr here is fine since it will be deleted on the
+  // other thread.
+  instance_ = nullptr;
+
+  return true;
+}
+
+void AvrcpService::DebugDump(int fd) {
+  if (instance_ == nullptr) {
+    dprintf(fd, "\nAVRCP Target Service not started\n");
+    return;
+  }
+
+  auto device_list = instance_->connection_handler_->GetListOfDevices();
+  dprintf(fd, "\nAVRCP Target Native Service: %zu devices\n",
+          device_list.size());
+
+  std::stringstream stream;
+  for (auto device : device_list) {
+    stream << *device << std::endl;
+  }
+  dprintf(fd, "%s", stream.str().c_str());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/btif/avrcp/avrcp_service.h b/btif/avrcp/avrcp_service.h
new file mode 100644
index 0000000..d26b200
--- /dev/null
+++ b/btif/avrcp/avrcp_service.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <map>
+#include <memory>
+
+#include "avrcp.h"
+#include "connection_handler.h"
+#include "osi/include/properties.h"
+#include "raw_address.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+/**
+ * AvrcpService is the management interface for AVRCP Target. It handles any
+ * required thread switching, interface registration, and provides an API
+ * for connecting and disconnecting devices.
+ * TODO (apanicke): Instead of providing a service interface implementation,
+ * have the AvrcpService itself be its interface so we don't have to access
+ * it indirectly.
+ */
+class AvrcpService : public MediaCallbacks {
+ public:
+  /**
+   * Gets a handle to the AvrcpService
+   *
+   * Currently used by A2DP to tell AVRCP to initiate a connection to the
+   * remote device.
+   */
+  static AvrcpService* Get();
+
+  /**
+   * Returns an interface to control this service. The Avrcp::ServiceInterface
+   * handles all thread switching between the caller thread and the thread the
+   * service runs on, that way whoever uses the interface doesn't need to be
+   * aware which thread the service runs on.
+   */
+  static ServiceInterface* GetServiceInterface();
+
+  void Init(MediaInterface* media_interface, VolumeInterface* volume_interface);
+  void Cleanup();
+
+  void ConnectDevice(const RawAddress& bdaddr);
+  void DisconnectDevice(const RawAddress& bdaddr);
+
+  // Functions inherited from MediaCallbacks in order to receive updates
+  void SendMediaUpdate(bool track_changed, bool play_state,
+                       bool queue) override;
+  void SendFolderUpdate(bool available_players, bool addressed_player,
+                        bool queue) override;
+  void SendActiveDeviceChanged(const RawAddress& address) override;
+
+  class ServiceInterfaceImpl : public ServiceInterface {
+   public:
+    void Init(MediaInterface* media_interface,
+              VolumeInterface* volume_interface) override;
+    bool ConnectDevice(const RawAddress& bdaddr) override;
+    bool DisconnectDevice(const RawAddress& bdaddr) override;
+    bool Cleanup() override;
+
+   private:
+    std::mutex service_interface_lock_;
+  };
+
+  static void DebugDump(int fd);
+
+ protected:
+  void DeviceCallback(std::shared_ptr<Device> device);
+
+ private:
+  static AvrcpService* instance_;
+  static ServiceInterfaceImpl* service_interface_;
+
+  MediaInterface* media_interface_ = nullptr;
+  VolumeInterface* volume_interface_ = nullptr;
+
+  ConnectionHandler* connection_handler_;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
+
+inline bool is_new_avrcp_enabled() {
+  return osi_property_get_bool("persist.bluetooth.enablenewavrcp", true);
+}
\ No newline at end of file
diff --git a/btif/co/bta_ag_co.cc b/btif/co/bta_ag_co.cc
deleted file mode 100644
index b27e57e..0000000
--- a/btif/co/bta_ag_co.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2009-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-#define LOG_TAG "bt_btif_bta_ag"
-
-#include "bta/include/bta_ag_co.h"
-#include "bta/ag/bta_ag_int.h"
-#include "bta/include/bta_ag_api.h"
-#include "bta/include/bta_ag_ci.h"
-#include "osi/include/osi.h"
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_init
- *
- * Description      This callout function is executed by AG when it is
- *                  started by calling BTA_AgEnable().  This function can be
- *                  used by the phone to initialize audio paths or for other
- *                  initialization purposes.
- *
- *
- * Returns          Void.
- *
- ******************************************************************************/
-void bta_ag_co_init(void) { BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); }
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_data_open
- *
- * Description      This function is executed by AG when a service level
- *                  connection is opened.  The phone can use this function to
- *                  set up data paths or perform any required initialization or
- *                  set up particular to the connected service.
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_ag_co_data_open(uint16_t handle, tBTA_SERVICE_ID service) {
-  BTIF_TRACE_DEBUG("bta_ag_co_data_open handle:%d service:%d", handle, service);
-}
-
-/*******************************************************************************
- *
- * Function         bta_ag_co_data_close
- *
- * Description      This function is called by AG when a service level
- *                  connection is closed
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_ag_co_data_close(uint16_t handle) {
-  BTIF_TRACE_DEBUG("bta_ag_co_data_close handle:%d", handle);
-}
-
-/*******************************************************************************
- **
- ** Function         bta_ag_co_tx_write
- **
- ** Description      This function is called by the AG to send data to the
- **                  phone when the AG is configured for AT command
- **                  pass-through. The implementation of this function must copy
- **                  the data to the phones memory.
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_ag_co_tx_write(uint16_t handle, UNUSED_ATTR uint8_t* p_data,
-                        uint16_t len) {
-  BTIF_TRACE_DEBUG("bta_ag_co_tx_write: handle: %d, len: %d", handle, len);
-}
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index e931714..6147744 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,407 +23,899 @@
  *
  ******************************************************************************/
 
-#include "bta_av_co.h"
+#include <mutex>
+
+#include <base/bind.h>
 #include <base/logging.h>
 #include <string.h>
+
+#include "bt_target.h"
+
 #include "a2dp_api.h"
 #include "a2dp_sbc.h"
-#include "bt_target.h"
 #include "bta_av_api.h"
 #include "bta_av_ci.h"
+#include "bta_av_co.h"
 #include "bta_sys.h"
 
 #include "btif_av.h"
 #include "btif_av_co.h"
 #include "btif_util.h"
-#include "osi/include/mutex.h"
 #include "osi/include/osi.h"
+#include "osi/include/properties.h"
 
-/*****************************************************************************
- **  Constants
- *****************************************************************************/
-
-/* Macro to retrieve the number of elements in a statically allocated array */
+// Macro to retrieve the number of elements in a statically allocated array
 #define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a) / sizeof((__a)[0]))
 
-/* Macro to convert audio handle to index and vice versa */
-#define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1)
-#define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO)
+// Macro to convert BTA AV audio handle to index and vice versa
+#define BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle) \
+  (((bta_av_handle) & (~BTA_AV_CHNL_MSK)) - 1)
+#define BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(index) \
+  (((index) + 1) | BTA_AV_CHNL_AUDIO)
 
-/* SCMS-T protect info */
-const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00};
-
-/*****************************************************************************
- *  Local data
- ****************************************************************************/
-typedef struct {
-  uint8_t sep_info_idx;                   /* local SEP index (in BTA tables) */
-  uint8_t seid;                           /* peer SEP index (in peer tables) */
-  uint8_t codec_caps[AVDT_CODEC_SIZE];    /* peer SEP codec capabilities */
-  uint8_t num_protect;                    /* peer SEP number of CP elements */
-  uint8_t protect_info[AVDT_CP_INFO_LEN]; /* peer SEP content protection info */
-} tBTA_AV_CO_SINK;
-
-typedef struct {
-  RawAddress addr; /* address of audio/video peer */
-  tBTA_AV_CO_SINK
-      sinks[BTAV_A2DP_CODEC_INDEX_MAX]; /* array of supported sinks */
-  tBTA_AV_CO_SINK srcs[BTAV_A2DP_CODEC_INDEX_MAX]; /* array of supported srcs */
-  uint8_t num_sinks;     /* total number of sinks at peer */
-  uint8_t num_srcs;      /* total number of srcs at peer */
-  uint8_t num_seps;      /* total number of seids at peer */
-  uint8_t num_rx_sinks;  /* number of received sinks */
-  uint8_t num_rx_srcs;   /* number of received srcs */
-  uint8_t num_sup_sinks; /* number of supported sinks in the sinks array */
-  uint8_t num_sup_srcs;  /* number of supported srcs in the srcs array */
-  const tBTA_AV_CO_SINK* p_sink;         /* currently selected sink */
-  const tBTA_AV_CO_SINK* p_src;          /* currently selected src */
-  uint8_t codec_config[AVDT_CODEC_SIZE]; /* current codec configuration */
-  bool cp_active;                        /* current CP configuration */
-  bool acp;                              /* acceptor */
-  bool reconfig_needed;                  /* reconfiguration is needed */
-  bool opened;                           /* opened */
-  uint16_t mtu;                          /* maximum transmit unit size */
-  uint16_t uuid_to_connect;              /* uuid of peer device */
-  tBTA_AV_HNDL handle;                   /* handle to use */
-} tBTA_AV_CO_PEER;
-
-typedef struct {
-  bool active;
-  uint8_t flag;
-} tBTA_AV_CO_CP;
-
-class BtaAvCoCb {
+class BtaAvCoSep {
  public:
-  BtaAvCoCb() : codecs(nullptr) { reset(); }
-
-  /* Connected peer information */
-  tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
-  /* Current codec configuration - access to this variable must be protected */
-  uint8_t codec_config[AVDT_CODEC_SIZE];
-  A2dpCodecs* codecs; /* Locally supported codecs */
-  tBTA_AV_CO_CP cp;
-
-  void reset() {
-    delete codecs;
-    codecs = nullptr;
-    // TODO: Ugly leftover reset from the original C code. Should go away once
-    // the rest of the code in this file migrates to C++.
-    memset(peers, 0, sizeof(peers));
-    memset(codec_config, 0, sizeof(codec_config));
-    memset(&cp, 0, sizeof(cp));
-
-    // Initialize the handles
-    for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers); i++) {
-      tBTA_AV_CO_PEER* p_peer = &peers[i];
-      p_peer->handle = BTA_AV_CO_AUDIO_INDX_TO_HNDL(i);
-    }
+  BtaAvCoSep()
+      : sep_info_idx(0), seid(0), codec_caps{}, num_protect(0), protect_info{} {
+    Reset();
   }
+
+  /**
+   * Reset the state.
+   */
+  void Reset() {
+    sep_info_idx = 0;
+    seid = 0;
+    memset(codec_caps, 0, sizeof(codec_caps));
+    num_protect = 0;
+    memset(protect_info, 0, sizeof(protect_info));
+  }
+
+  uint8_t sep_info_idx;                    // Local SEP index (in BTA tables)
+  uint8_t seid;                            // Peer SEP index (in peer tables)
+  uint8_t codec_caps[AVDT_CODEC_SIZE];     // Peer SEP codec capabilities
+  uint8_t num_protect;                     // Peer SEP number of CP elements
+  uint8_t protect_info[AVDT_CP_INFO_LEN];  // Peer SEP content protection info
 };
 
-/* Control block instance */
-static BtaAvCoCb bta_av_co_cb;
-
-static bool bta_av_co_cp_is_scmst(const uint8_t* p_protect_info);
-static bool bta_av_co_audio_protect_has_scmst(uint8_t num_protect,
-                                              const uint8_t* p_protect_info);
-static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
-    const tBTA_AV_CO_PEER* p_peer);
-static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer);
-static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(
-    A2dpCodecConfig& codec_config, tBTA_AV_CO_PEER* p_peer);
-static bool bta_av_co_audio_update_selectable_codec(
-    A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer);
-static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
-                                            const uint8_t* new_codec_config,
-                                            uint8_t num_protect,
-                                            const uint8_t* p_protect_info);
-static bool bta_av_co_set_codec_ota_config(tBTA_AV_CO_PEER* p_peer,
-                                           const uint8_t* p_ota_codec_config,
-                                           uint8_t num_protect,
-                                           const uint8_t* p_protect_info,
-                                           bool* p_restart_output);
-
-/*******************************************************************************
- **
- ** Function         bta_av_co_cp_get_flag
- **
- ** Description      Get content protection flag
- **                  AVDT_CP_SCMS_COPY_NEVER
- **                  AVDT_CP_SCMS_COPY_ONCE
- **                  AVDT_CP_SCMS_COPY_FREE
- **
- ** Returns          The current flag value
- **
- ******************************************************************************/
-static uint8_t bta_av_co_cp_get_flag(void) { return bta_av_co_cb.cp.flag; }
-
-/*******************************************************************************
- **
- ** Function         bta_av_co_cp_set_flag
- **
- ** Description      Set content protection flag
- **                  AVDT_CP_SCMS_COPY_NEVER
- **                  AVDT_CP_SCMS_COPY_ONCE
- **                  AVDT_CP_SCMS_COPY_FREE
- **
- ** Returns          true if setting the SCMS flag is supported else false
- **
- ******************************************************************************/
-static bool bta_av_co_cp_set_flag(uint8_t cp_flag) {
-  APPL_TRACE_DEBUG("%s: cp_flag = %d", __func__, cp_flag);
-
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-#else
-  if (cp_flag != AVDT_CP_SCMS_COPY_FREE) {
-    return false;
+class BtaAvCoPeer {
+ public:
+  BtaAvCoPeer()
+      : addr(RawAddress::kEmpty),
+        num_sinks(0),
+        num_sources(0),
+        num_seps(0),
+        num_rx_sinks(0),
+        num_rx_sources(0),
+        num_sup_sinks(0),
+        num_sup_sources(0),
+        p_sink(nullptr),
+        p_source(nullptr),
+        codec_config{},
+        acceptor(false),
+        reconfig_needed(false),
+        opened(false),
+        mtu(0),
+        uuid_to_connect(0),
+        bta_av_handle_(0),
+        codecs_(nullptr),
+        content_protect_active_(false) {
+    Reset(0);
   }
+
+  /**
+   * Initialize the state.
+   *
+   * @param codec_priorities the codec priorities to use for the initialization
+   */
+  void Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
+
+  /**
+   * Reset the state.
+   *
+   * @param bta_av_handle the BTA AV handle to use
+   */
+  void Reset(tBTA_AV_HNDL bta_av_handle);
+
+  /**
+   * Get the BTA AV handle.
+   *
+   * @return the BTA AV handle
+   */
+  tBTA_AV_HNDL BtaAvHandle() const { return bta_av_handle_; }
+
+  /**
+   * Get the A2DP codecs.
+   *
+   * @return the A2DP codecs
+   */
+  A2dpCodecs* GetCodecs() { return codecs_; }
+
+  bool ContentProtectActive() const { return content_protect_active_; }
+  void SetContentProtectActive(bool cp_active) {
+    content_protect_active_ = cp_active;
+  }
+
+  RawAddress addr;                                // Peer address
+  BtaAvCoSep sinks[BTAV_A2DP_CODEC_INDEX_MAX];    // Supported sinks
+  BtaAvCoSep sources[BTAV_A2DP_CODEC_INDEX_MAX];  // Supported sources
+  uint8_t num_sinks;                      // Total number of sinks at peer
+  uint8_t num_sources;                    // Total number of sources at peer
+  uint8_t num_seps;                       // Total number of SEPs at peer
+  uint8_t num_rx_sinks;                   // Number of received sinks
+  uint8_t num_rx_sources;                 // Number of received sources
+  uint8_t num_sup_sinks;                  // Number of supported sinks
+  uint8_t num_sup_sources;                // Number of supported sources
+  const BtaAvCoSep* p_sink;               // Currently selected sink
+  const BtaAvCoSep* p_source;             // Currently selected source
+  uint8_t codec_config[AVDT_CODEC_SIZE];  // Current codec configuration
+  bool acceptor;                          // True if acceptor
+  bool reconfig_needed;                   // True if reconfiguration is needed
+  bool opened;                            // True if opened
+  uint16_t mtu;                           // Maximum Transmit Unit size
+  uint16_t uuid_to_connect;               // UUID of peer device
+
+ private:
+  tBTA_AV_HNDL bta_av_handle_;   // BTA AV handle to use
+  A2dpCodecs* codecs_;           // Locally supported codecs
+  bool content_protect_active_;  // True if Content Protect is active
+};
+
+class BtaAvCo {
+ public:
+  BtaAvCo(bool content_protect_enabled)
+      : active_peer_(nullptr),
+        codec_config_{},
+        content_protect_enabled_(content_protect_enabled),
+        content_protect_flag_(0) {
+    Reset();
+  }
+
+  /**
+   * Initialize the state.
+   *
+   * @param codec_priorities the codec priorities to use for the initialization
+   */
+  void Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
+
+  /**
+   * Get the current codec configuration for the active peer.
+   *
+   * @return the current codec configuration if found, otherwise nullptr
+   */
+  A2dpCodecConfig* GetActivePeerCurrentCodec();
+
+  /**
+   * Get the current codec configuration for a peer.
+   *
+   * @param peer_address the peer address
+   * @return the current codec configuration if found, otherwise nullptr
+   */
+  A2dpCodecConfig* GetPeerCurrentCodec(const RawAddress& peer_address);
+
+  /**
+   * Find the peer UUID for a given BTA AV handle.
+   *
+   * @param bta_av_handle the BTA AV handle to use
+   * @return the peer UUID if found, otherwise 0
+   */
+  uint16_t FindPeerUuid(tBTA_AV_HNDL bta_av_handle);
+
+  /**
+   * Process the AVDTP discovery result: number of Stream End Points (SEP)
+   * found during the AVDTP stream discovery process.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param num_seps the number of discovered SEPs
+   * @param num_sinks number of discovered Sink SEPs
+   * @param num_sources number of discovered Source SEPs
+   * @param uuid_local local UUID
+   */
+  void ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle,
+                              const RawAddress& peer_address, uint8_t num_seps,
+                              uint8_t num_sinks, uint8_t num_sources,
+                              uint16_t uuid_local);
+
+  /**
+   * Process retrieved codec configuration and content protection from
+   * Peer Sink SEP.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param p_codec_info the peer sink capability filled-in by the caller.
+   * On success, it will contain the current codec configuration for the peer.
+   * @param p_sep_info_idx the peer SEP index for the corresponding peer
+   * sink capability filled-in by the caller. On success, it will contain
+   * the SEP index for the current codec configuration for the peer.
+   * @param seid the peer SEP index in peer tables
+   * @param p_num_protect the peer SEP number of content protection elements
+   * filled-in by the caller. On success, it will contain the SEP number of
+   * content protection elements for the current codec configuration for the
+   * peer.
+   * @param p_protect_info the peer SEP content protection info filled-in by
+   * the caller. On success, it will contain the SEP content protection info
+   * for the current codec configuration for the peer.
+   * @return A2DP_SUCCESS on success, otherwise A2DP_FAIL
+   */
+  tA2DP_STATUS ProcessSourceGetConfig(tBTA_AV_HNDL bta_av_handle,
+                                      const RawAddress& peer_address,
+                                      uint8_t* p_codec_info,
+                                      uint8_t* p_sep_info_idx, uint8_t seid,
+                                      uint8_t* p_num_protect,
+                                      uint8_t* p_protect_info);
+
+  /**
+   * Process retrieved codec configuration and content protection from
+   * Peer Source SEP.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param p_codec_info the peer source capability filled-in by the caller.
+   * On success, it will contain the current codec configuration for the peer.
+   * @param p_sep_info_idx the peer SEP index for the corresponding peer
+   * source capability filled-in by the caller. On success, it will contain
+   * the SEP index for the current codec configuration for the peer.
+   * @param seid the peer SEP index in peer tables
+   * @param p_num_protect the peer SEP number of content protection elements
+   * filled-in by the caller. On success, it will contain the SEP number of
+   * content protection elements for the current codec configuration for the
+   * peer.
+   * @param p_protect_info the peer SEP content protection info filled-in by
+   * the caller. On success, it will contain the SEP content protection info
+   * for the current codec configuration for the peer.
+   * @return A2DP_SUCCESS on success, otherwise A2DP_FAIL
+   */
+  tA2DP_STATUS ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle,
+                                    const RawAddress& peer_address,
+                                    uint8_t* p_codec_info,
+                                    uint8_t* p_sep_info_idx, uint8_t seid,
+                                    uint8_t* p_num_protect,
+                                    uint8_t* p_protect_info);
+
+  /**
+   * Process AVDTP Set Config to set the codec and content protection
+   * configuration of the audio stream.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param p_codec_info the codec configuration to set
+   * @param seid stream endpoint ID of stream initiating the operation
+   * @param peer_address the peer address
+   * @param num_protect the peer SEP number of content protection elements
+   * @param p_protect_info the peer SEP conntent protection info
+   * @param t_local_sep the local SEP: AVDT_TSEP_SRC or AVDT_TSEP_SNK
+   * @param avdt_handle the AVDTP handle
+   */
+  void ProcessSetConfig(tBTA_AV_HNDL bta_av_handle,
+                        const RawAddress& peer_address,
+                        const uint8_t* p_codec_info, uint8_t seid,
+                        uint8_t num_protect, const uint8_t* p_protect_info,
+                        uint8_t t_local_sep, uint8_t avdt_handle);
+
+  /**
+   * Process AVDTP Open when the stream connection is opened.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param mtu the MTU of the connection
+   */
+  void ProcessOpen(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address,
+                   uint16_t mtu);
+
+  /**
+   * Process AVDTP Close when the stream connection is closed.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   */
+  void ProcessClose(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address);
+
+  /**
+   * Process AVDTP Start when the audio data streaming is started.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param p_codec_info the codec configuration
+   * @param p_no_rtp_header on return, set to true if the audio data packets
+   * should not contain RTP header
+   */
+  void ProcessStart(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address,
+                    const uint8_t* p_codec_info, bool* p_no_rtp_header);
+
+  /**
+   * Process AVDTP Stop when the audio data streaming is stopped.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   */
+  void ProcessStop(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address);
+
+  /**
+   * Get the next encoded audio data packet to send.
+   *
+   * @param p_codec_info the codec configuration
+   * @param p_timestamp on return, set to the timestamp of the data packet
+   * @return the next encoded data packet or nullptr if no encoded data to send
+   */
+  BT_HDR* GetNextSourceDataPacket(const uint8_t* p_codec_info,
+                                  uint32_t* p_timestamp);
+
+  /**
+   * An audio packet has been dropped.
+   * This signal can be used by the encoder to reduce the encoder bit rate
+   * setting.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   */
+  void DataPacketWasDropped(tBTA_AV_HNDL bta_av_handle,
+                            const RawAddress& peer_address);
+
+  /**
+   * Process AVDTP Audio Delay when the initial delay report is received by
+   * the Source.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param delay the reported delay in 1/10th of a millisecond
+   */
+  void ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle,
+                         const RawAddress& peer_address, uint16_t delay);
+
+  /**
+   * Update the MTU of the audio data connection.
+   *
+   * @param bta_av_handle the BTA AV handle to identify the peer
+   * @param peer_address the peer address
+   * @param mtu the new MTU of the audio data connection
+   */
+  void UpdateMtu(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address,
+                 uint16_t mtu);
+
+  /**
+   * Set the active peer.
+   *
+   * @param peer_address the peer address
+   * @return true on success, otherwise false
+   */
+  bool SetActivePeer(const RawAddress& peer_address);
+
+  /**
+   * Get the encoder parameters for a peer.
+   *
+   * @param peer_address the peer address
+   * @param p_peer_params on return, set to the peer's encoder parameters
+   */
+  void GetPeerEncoderParameters(const RawAddress& peer_address,
+                                tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params);
+
+  /**
+   * Get the Source encoder interface for the current codec.
+   *
+   * @return the Source encoder interface for the current codec
+   */
+  const tA2DP_ENCODER_INTERFACE* GetSourceEncoderInterface();
+
+  /**
+   * Get the Sink decoder interface for the current codec.
+   *
+   * @return the Sink decoder interface for the current codec
+   */
+  const tA2DP_DECODER_INTERFACE* GetSinkDecoderInterface();
+
+  /**
+   * Set the codec user configuration.
+   *
+   * @param peer_address the peer address
+   * @param codec_user_config the codec user configuration to set
+   * @return true on success, otherwise false
+   */
+  bool SetCodecUserConfig(const RawAddress& peer_address,
+                          const btav_a2dp_codec_config_t& codec_user_config);
+
+  /**
+   * Set the codec audio configuration.
+   *
+   * @param codec_audio_config the codec audio configuration to set
+   * @return true on success, otherwise false
+   */
+  bool SetCodecAudioConfig(const btav_a2dp_codec_config_t& codec_audio_config);
+
+  /**
+   * Report the source codec state for a peer
+   *
+   * @param p_peer the peer to report
+   * @return true on success, otherwise false
+   */
+  bool ReportSourceCodecState(BtaAvCoPeer* p_peer);
+
+  /**
+   * Report the sink codec state for a peer
+   *
+   * @param p_peer the peer to report
+   * @return true on success, otherwise false
+   */
+  bool ReportSinkCodecState(BtaAvCoPeer* p_peer);
+
+  /**
+   * Get the content protection flag.
+   *
+   * @return the content protection flag. It should be one of the following:
+   * AVDT_CP_SCMS_COPY_NEVER, AVDT_CP_SCMS_COPY_ONCE, AVDT_CP_SCMS_COPY_FREE
+   */
+  uint8_t ContentProtectFlag() const { return content_protect_flag_; }
+
+  /**
+   * Set the content protection flag.
+   *
+   * @param cp_flag the content protection flag. It should be one of the
+   * following:
+   * AVDT_CP_SCMS_COPY_NEVER, AVDT_CP_SCMS_COPY_ONCE, AVDT_CP_SCMS_COPY_FREE
+   * NOTE: If Content Protection is not enabled on the system, then
+   * the only acceptable vailue is AVDT_CP_SCMS_COPY_FREE.
+   */
+  void SetContentProtectFlag(uint8_t cp_flag) {
+    if (!ContentProtectEnabled() && (cp_flag != AVDT_CP_SCMS_COPY_FREE)) {
+      return;
+    }
+    content_protect_flag_ = cp_flag;
+  }
+
+  /**
+   * Dump debug-related information.
+   *
+   * @param fd the file descritor to use for writing the ASCII formatted
+   * information
+   */
+  void DebugDump(int fd);
+
+  /**
+   * Find the peer entry for a given peer address.
+   *
+   * @param peer_address the peer address to use
+   * @return the peer entry if found, otherwise nullptr
+   */
+  BtaAvCoPeer* FindPeer(const RawAddress& peer_address);
+
+  /**
+   * Find the peer Sink SEP entry for a given codec index.
+   *
+   * @param p_peer the peer to use
+   * @param codec_index the codec index to use
+   * @return the peer Sink SEP for the codec index if found, otherwise nullptr
+   */
+  BtaAvCoSep* FindPeerSink(BtaAvCoPeer* p_peer,
+                           btav_a2dp_codec_index_t codec_index);
+
+  /**
+   * Find the peer Source SEP entry for a given codec index.
+   *
+   * @param p_peer the peer to use
+   * @param codec_config the codec index to use
+   * @return the peer Source SEP for the codec index if found, otherwise nullptr
+   */
+  BtaAvCoSep* FindPeerSource(BtaAvCoPeer* p_peer,
+                             btav_a2dp_codec_index_t codec_index);
+
+ private:
+  /**
+   * Reset the state.
+   */
+  void Reset();
+
+  /**
+   * Find the peer entry for a given BTA AV handle.
+   *
+   * @param bta_av_handle the BTA AV handle to use
+   * @return the peer entry if found, otherwise nullptr
+   */
+  BtaAvCoPeer* FindPeer(tBTA_AV_HNDL bta_av_handle);
+
+  /**
+   * Find the peer entry for a given BTA AV handle and update it with the
+   * peer address.
+   *
+   * @param bta_av_handle the BTA AV handle to use
+   * @param peer_address the peer address
+   * @return the peer entry if found, otherwise nullptr
+   */
+  BtaAvCoPeer* FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle,
+                                 const RawAddress& peer_address);
+
+  /**
+   * Select the Source codec configuration based on peer codec support.
+   *
+   * Furthermore, the local state for the remaining non-selected codecs is
+   * updated to reflect whether the codec is selectable.
+   *
+   * @param p_peer the peer to use
+   * @return a pointer to the corresponding SEP Sink entry on success,
+   * otherwise nullptr
+   */
+  const BtaAvCoSep* SelectSourceCodec(BtaAvCoPeer* p_peer);
+
+  /**
+   * Select the Sink codec configuration based on peer codec support.
+   *
+   * Furthermore, the local state for the remaining non-selected codecs is
+   * updated to reflect whether the codec is selectable.
+   *
+   * @param p_peer the peer to use
+   * @return a pointer to the corresponding SEP Source entry on success,
+   * otherwise nullptr
+   */
+  const BtaAvCoSep* SelectSinkCodec(BtaAvCoPeer* p_peer);
+
+  /**
+   * Save new codec configuration.
+   *
+   * @param p_peer the peer to use
+   * @param new_codec_config the new codec configuration to use
+   * @param num_protect the number of content protection elements
+   * @param p_protect_info the content protection info to use
+   */
+  void SaveNewCodecConfig(BtaAvCoPeer* p_peer, const uint8_t* new_codec_config,
+                          uint8_t num_protect, const uint8_t* p_protect_info);
+
+  /**
+   * Set the Over-The-Air preferred codec configuration.
+   *
+   * The OTA prefered codec configuration is ignored if the current
+   * codec configuration contains explicit user configuration, or if the
+   * codec configuration for the same codec contains explicit user
+   * configuration.
+   *
+   * @param p_peer is the peer device that sent the OTA codec configuration
+   * @param p_ota_codec_config contains the received OTA A2DP codec
+   * configuration from the remote peer. Note: this is not the peer codec
+   * capability, but the codec configuration that the peer would like to use.
+   * @param num_protect is the number of content protection methods to use
+   * @param p_protect_info contains the content protection information to use.
+   * @param p_restart_output if there is a change in the encoder configuration
+   * that requires restarting of the A2DP connection, flag |p_restart_output|
+   * is set to true.
+   * @return true on success, otherwise false
+   */
+  bool SetCodecOtaConfig(BtaAvCoPeer* p_peer, const uint8_t* p_ota_codec_config,
+                         uint8_t num_protect, const uint8_t* p_protect_info,
+                         bool* p_restart_output);
+
+  /**
+   * Update all selectable Source codecs with the corresponding codec
+   * information from a Sink peer.
+   *
+   * @param p_peer the peer Sink SEP to use
+   * @return the number of codecs that have been updated
+   */
+  size_t UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer);
+
+  /**
+   * Update a selectable Source codec with the corresponding codec information
+   * from a Sink peer.
+   *
+   * @param codec_config the codec config info to identify the codec to update
+   * @param p_peer the peer Sink SEP to use
+   * @return true if the codec is updated, otherwise false
+   */
+  bool UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config,
+                                   BtaAvCoPeer* p_peer);
+
+  /**
+   * Update all selectable Sink codecs with the corresponding codec
+   * information from a Source peer.
+   *
+   * @param p_peer the peer Source SEP to use
+   * @return the number of codecs that have been updated
+   */
+  size_t UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer);
+
+  /**
+   * Update a selectable Sink codec with the corresponding codec information
+   * from a Source peer.
+   *
+   * @param codec_config the codec config info to identify the codec to update
+   * @param p_peer the peer Source SEP to use
+   * @return true if the codec is updated, otherwise false
+   */
+  bool UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config,
+                                 BtaAvCoPeer* p_peer);
+
+  /**
+   * Attempt to select Source codec configuration for a Sink peer.
+   *
+   * @param codec_config the codec configuration to use
+   * @param p_peer the Sink peer to use
+   * @return a pointer to the corresponding SEP Sink entry on success,
+   * otnerwise nullptr
+   */
+  const BtaAvCoSep* AttemptSourceCodecSelection(
+      const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer);
+
+  /**
+   * Attempt to select Sink codec configuration for a Source peer.
+   *
+   * @param codec_config the codec configuration to use
+   * @param p_peer the Source peer to use
+   * @return a pointer to the corresponding SEP Source entry on success,
+   * otnerwise nullptr
+   */
+  const BtaAvCoSep* AttemptSinkCodecSelection(
+      const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer);
+
+  /**
+   * Check if a peer SEP has content protection enabled.
+   *
+   * @param p_sep the peer SEP to check
+   * @return true if the peer SEP has content protection enabled,
+   * otherwise false
+   */
+  bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep);
+
+  /**
+   * Check if a content protection service is SCMS-T.
+   *
+   * @param p_orotect_info the content protection info to check
+   * @return true if the Contention Protection in @param p_protect_info
+   * is SCMS-T, otherwise false
+   */
+  static bool ContentProtectIsScmst(const uint8_t* p_protect_info);
+
+  /**
+   * Check if audio protect info contains SCMS-T Content Protection.
+   *
+   * @param num_protect number of protect schemes
+   * @param p_protect_info the protect info to check
+   * @return true if @param p_protect_info contains SCMS-T, otherwise false
+   */
+  static bool AudioProtectHasScmst(uint8_t num_protect,
+                                   const uint8_t* p_protect_info);
+
+  bool ContentProtectEnabled() const { return content_protect_enabled_; }
+
+  std::recursive_mutex codec_lock_;  // Protect access to the codec state
+  std::vector<btav_a2dp_codec_config_t> codec_priorities_;  // Configured
+  BtaAvCoPeer peers_[BTA_AV_NUM_STRS];     // Connected peer information
+  BtaAvCoPeer* active_peer_;               // The current active peer
+  uint8_t codec_config_[AVDT_CODEC_SIZE];  // Current codec configuration
+  const bool content_protect_enabled_;     // True if Content Protect is enabled
+  uint8_t content_protect_flag_;           // Content Protect flag
+};
+
+// SCMS-T protect info
+const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00};
+
+// Control block instance
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+static const bool kContentProtectEnabled = true;
+#else
+static const bool kContentProtectEnabled = false;
 #endif
-  bta_av_co_cb.cp.flag = cp_flag;
-  return true;
+static BtaAvCo bta_av_co_cb(kContentProtectEnabled);
+
+void BtaAvCoPeer::Init(
+    const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
+  Reset(bta_av_handle_);
+  // Reset the current config
+  codecs_ = new A2dpCodecs(codec_priorities);
+  codecs_->init();
+  A2DP_InitDefaultCodec(codec_config);
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_get_peer
- **
- ** Description      find the peer entry for a given handle
- **
- ** Returns          the control block
- **
- ******************************************************************************/
-static tBTA_AV_CO_PEER* bta_av_co_get_peer(tBTA_AV_HNDL hndl) {
+void BtaAvCoPeer::Reset(tBTA_AV_HNDL bta_av_handle) {
+  addr = RawAddress::kEmpty;
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sinks); i++) {
+    BtaAvCoSep& sink = sinks[i];
+    sink.Reset();
+  }
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sources); i++) {
+    BtaAvCoSep& source = sources[i];
+    source.Reset();
+  }
+  num_sinks = 0;
+  num_sources = 0;
+  num_seps = 0;
+  num_rx_sinks = 0;
+  num_rx_sources = 0;
+  num_sup_sinks = 0;
+  num_sup_sources = 0;
+  p_sink = nullptr;
+  p_source = nullptr;
+  memset(codec_config, 0, sizeof(codec_config));
+  acceptor = false;
+  reconfig_needed = false;
+  opened = false;
+  mtu = 0;
+  uuid_to_connect = 0;
+
+  bta_av_handle_ = bta_av_handle;
+  delete codecs_;
+  codecs_ = nullptr;
+  content_protect_active_ = false;
+}
+
+void BtaAvCo::Init(
+    const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  // Reset the control block
+  Reset();
+  codec_priorities_ = codec_priorities;
+
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
+    BtaAvCoPeer* p_peer = &peers_[i];
+    p_peer->Init(codec_priorities);
+  }
+}
+
+void BtaAvCo::Reset() {
+  codec_priorities_.clear();
+  active_peer_ = nullptr;
+  content_protect_flag_ = 0;
+  memset(codec_config_, 0, sizeof(codec_config_));
+
+  if (ContentProtectEnabled()) {
+    SetContentProtectFlag(AVDT_CP_SCMS_COPY_NEVER);
+  } else {
+    SetContentProtectFlag(AVDT_CP_SCMS_COPY_FREE);
+  }
+
+  // Reset the peers and initialize the handles
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
+    BtaAvCoPeer* p_peer = &peers_[i];
+    p_peer->Reset(BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(i));
+  }
+}
+
+A2dpCodecConfig* BtaAvCo::GetActivePeerCurrentCodec() {
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  if (active_peer_ == nullptr || active_peer_->GetCodecs() == nullptr) {
+    return nullptr;
+  }
+  return active_peer_->GetCodecs()->getCurrentCodecConfig();
+}
+
+A2dpCodecConfig* BtaAvCo::GetPeerCurrentCodec(const RawAddress& peer_address) {
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  BtaAvCoPeer* peer = FindPeer(peer_address);
+  if (peer == nullptr || peer->GetCodecs() == nullptr) {
+    return nullptr;
+  }
+  return peer->GetCodecs()->getCurrentCodecConfig();
+}
+
+BtaAvCoPeer* BtaAvCo::FindPeer(const RawAddress& peer_address) {
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
+    BtaAvCoPeer* p_peer = &peers_[i];
+    if (p_peer->addr == peer_address) {
+      return p_peer;
+    }
+  }
+  return nullptr;
+}
+
+BtaAvCoPeer* BtaAvCo::FindPeer(tBTA_AV_HNDL bta_av_handle) {
   uint8_t index;
 
-  index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl);
+  index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle);
 
-  APPL_TRACE_DEBUG("%s: handle = %d index = %d", __func__, hndl, index);
+  APPL_TRACE_DEBUG("%s: bta_av_handle = 0x%x index = %d", __func__,
+                   bta_av_handle, index);
 
-  /* Sanity check */
-  if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) {
-    APPL_TRACE_ERROR("%s: peer index out of bounds: %d", __func__, index);
-    return NULL;
+  // Sanity check
+  if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) {
+    APPL_TRACE_ERROR(
+        "%s: peer index %d for BTA AV handle 0x%x is out of bounds", __func__,
+        index, bta_av_handle);
+    return nullptr;
   }
 
-  return &bta_av_co_cb.peers[index];
+  return &peers_[index];
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_init
- **
- ** Description      This callout function is executed by AV when it is
- **                  started by calling BTA_AvRegister().  This function can be
- **                  used by the phone to initialize audio paths or for other
- **                  initialization purposes.
- **
- **
- ** Returns          Stream codec and content protection capabilities info.
- **
- ******************************************************************************/
-bool bta_av_co_audio_init(btav_a2dp_codec_index_t codec_index,
-                          tAVDT_CFG* p_cfg) {
-  return A2DP_InitCodecConfig(codec_index, p_cfg);
+BtaAvCoPeer* BtaAvCo::FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle,
+                                        const RawAddress& peer_address) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle = 0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle);
+
+  BtaAvCoPeer* p_peer = FindPeer(bta_av_handle);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR("%s: peer entry for BTA AV handle 0x%x peer %s not found",
+                     __func__, bta_av_handle, peer_address.ToString().c_str());
+    return nullptr;
+  }
+
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle = 0x%x previous address %s",
+                   __func__, peer_address.ToString().c_str(), bta_av_handle,
+                   p_peer->addr.ToString().c_str());
+  p_peer->addr = peer_address;
+  return p_peer;
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_disc_res
- **
- ** Description      This callout function is executed by AV to report the
- **                  number of stream end points (SEP) were found during the
- **                  AVDT stream discovery process.
- **
- **
- ** Returns          void.
- **
- ******************************************************************************/
-void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, uint8_t num_seps,
-                              uint8_t num_sink, uint8_t num_src,
-                              const RawAddress& addr, uint16_t uuid_local) {
-  tBTA_AV_CO_PEER* p_peer;
+uint16_t BtaAvCo::FindPeerUuid(tBTA_AV_HNDL bta_av_handle) {
+  BtaAvCoPeer* p_peer = FindPeer(bta_av_handle);
+  if (p_peer == nullptr) {
+    return 0;
+  }
+  return p_peer->uuid_to_connect;
+}
 
-  APPL_TRACE_DEBUG("%s: h:x%x num_seps:%d num_sink:%d num_src:%d", __func__,
-                   hndl, num_seps, num_sink, num_src);
+void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle,
+                                     const RawAddress& peer_address,
+                                     uint8_t num_seps, uint8_t num_sinks,
+                                     uint8_t num_sources, uint16_t uuid_local) {
+  APPL_TRACE_DEBUG(
+      "%s: peer %s bta_av_handle:0x%x num_seps:%d num_sinks:%d num_sources:%d",
+      __func__, peer_address.ToString().c_str(), bta_av_handle, num_seps,
+      num_sinks, num_sources);
 
-  /* Find the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer == NULL) {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
     return;
   }
 
   /* Sanity check : this should never happen */
   if (p_peer->opened) {
-    APPL_TRACE_ERROR("%s: peer already opened", __func__);
+    APPL_TRACE_ERROR("%s: peer %s already opened", __func__,
+                     peer_address.ToString().c_str());
   }
 
   /* Copy the discovery results */
-  p_peer->addr = addr;
-  p_peer->num_sinks = num_sink;
-  p_peer->num_srcs = num_src;
+  p_peer->addr = peer_address;
+  p_peer->num_sinks = num_sinks;
+  p_peer->num_sources = num_sources;
   p_peer->num_seps = num_seps;
   p_peer->num_rx_sinks = 0;
-  p_peer->num_rx_srcs = 0;
+  p_peer->num_rx_sources = 0;
   p_peer->num_sup_sinks = 0;
-  if (uuid_local == UUID_SERVCLASS_AUDIO_SINK)
+  p_peer->num_sup_sources = 0;
+  if (uuid_local == UUID_SERVCLASS_AUDIO_SINK) {
     p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE;
-  else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE)
+  } else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE) {
     p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK;
+  }
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_audio_sink_getconfig
- **
- ** Description      This callout function is executed by AV to retrieve the
- **                  desired codec and content protection configuration for the
- **                  A2DP Sink audio stream in Initiator.
- **
- **
- ** Returns          Pass or Fail for current getconfig.
- **
- ******************************************************************************/
-static tA2DP_STATUS bta_av_audio_sink_getconfig(
-    tBTA_AV_HNDL hndl, uint8_t* p_codec_info, uint8_t* p_sep_info_idx,
-    uint8_t seid, uint8_t* p_num_protect, uint8_t* p_protect_info) {
-  tA2DP_STATUS result = A2DP_FAIL;
-  tBTA_AV_CO_PEER* p_peer;
-
-  APPL_TRACE_DEBUG("%s: handle:0x%x codec:%s seid:%d", __func__, hndl,
+tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig(
+    tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address,
+    uint8_t* p_codec_info, uint8_t* p_sep_info_idx, uint8_t seid,
+    uint8_t* p_num_protect, uint8_t* p_protect_info) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle,
                    A2DP_CodecName(p_codec_info), seid);
   APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
                    __func__, *p_num_protect, p_protect_info[0],
                    p_protect_info[1], p_protect_info[2]);
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_codec_info).c_str());
 
-  /* Retrieve the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer == NULL) {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
     return A2DP_FAIL;
   }
-
-  APPL_TRACE_DEBUG("%s: peer(o=%d,n_sinks=%d,n_rx_sinks=%d,n_sup_sinks=%d)",
-                   __func__, p_peer->opened, p_peer->num_srcs,
-                   p_peer->num_rx_srcs, p_peer->num_sup_srcs);
-
-  p_peer->num_rx_srcs++;
-
-  /* Check the peer's SOURCE codec */
-  if (A2DP_IsPeerSourceCodecValid(p_codec_info)) {
-    /* If there is room for a new one */
-    if (p_peer->num_sup_srcs < BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs)) {
-      tBTA_AV_CO_SINK* p_src = &p_peer->srcs[p_peer->num_sup_srcs++];
-
-      APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
-                       p_codec_info[1], p_codec_info[2], p_codec_info[3],
-                       p_codec_info[4], p_codec_info[5], p_codec_info[6]);
-
-      memcpy(p_src->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
-      p_src->sep_info_idx = *p_sep_info_idx;
-      p_src->seid = seid;
-      p_src->num_protect = *p_num_protect;
-      memcpy(p_src->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
-    } else {
-      APPL_TRACE_ERROR("%s: no more room for SRC info", __func__);
-    }
-  }
-
-  /* If last SINK get capabilities or all supported codec caps retrieved */
-  if ((p_peer->num_rx_srcs == p_peer->num_srcs) ||
-      (p_peer->num_sup_srcs == BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs))) {
-    APPL_TRACE_DEBUG("%s: last SRC reached", __func__);
-
-    /* Protect access to bta_av_co_cb.codec_config */
-    mutex_global_lock();
-
-    /* Find a src that matches the codec config */
-    const tBTA_AV_CO_SINK* p_src =
-        bta_av_co_find_peer_src_supports_codec(p_peer);
-    if (p_src != NULL) {
-      uint8_t pref_config[AVDT_CODEC_SIZE];
-      APPL_TRACE_DEBUG("%s: codec supported", __func__);
-
-      /* Build the codec configuration for this sink */
-      /* Save the new configuration */
-      p_peer->p_src = p_src;
-      /* get preferred config from src_caps */
-      if (A2DP_BuildSrc2SinkConfig(p_src->codec_caps, pref_config) !=
-          A2DP_SUCCESS) {
-        mutex_global_unlock();
-        return A2DP_FAIL;
-      }
-      memcpy(p_peer->codec_config, pref_config, AVDT_CODEC_SIZE);
-
-      APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
-                       p_peer->codec_config[1], p_peer->codec_config[2],
-                       p_peer->codec_config[3], p_peer->codec_config[4],
-                       p_peer->codec_config[5], p_peer->codec_config[6]);
-      /* By default, no content protection */
-      *p_num_protect = 0;
-
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-      p_peer->cp_active = false;
-      bta_av_co_cb.cp.active = false;
-#endif
-
-      *p_sep_info_idx = p_src->sep_info_idx;
-      memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
-      result = A2DP_SUCCESS;
-    }
-    /* Protect access to bta_av_co_cb.codec_config */
-    mutex_global_unlock();
-  }
-  return result;
-}
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_getconfig
- **
- ** Description      This callout function is executed by AV to retrieve the
- **                  desired codec and content protection configuration for the
- **                  audio stream.
- **
- **
- ** Returns          Stream codec and content protection configuration info.
- **
- ******************************************************************************/
-tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
-                                       uint8_t* p_sep_info_idx, uint8_t seid,
-                                       uint8_t* p_num_protect,
-                                       uint8_t* p_protect_info) {
-  tBTA_AV_CO_PEER* p_peer;
-
-  APPL_TRACE_DEBUG("%s", __func__);
-  A2DP_DumpCodecInfo(p_codec_info);
-
-  /* Retrieve the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer == NULL) {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
-    return A2DP_FAIL;
-  }
-
-  if (p_peer->uuid_to_connect == UUID_SERVCLASS_AUDIO_SOURCE) {
-    return bta_av_audio_sink_getconfig(hndl, p_codec_info, p_sep_info_idx, seid,
-                                       p_num_protect, p_protect_info);
-  }
-  APPL_TRACE_DEBUG("%s: handle:0x%x codec:%s seid:%d", __func__, hndl,
-                   A2DP_CodecName(p_codec_info), seid);
-  APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
-                   __func__, *p_num_protect, p_protect_info[0],
-                   p_protect_info[1], p_protect_info[2]);
   APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)",
                    __func__, p_peer->opened, p_peer->num_sinks,
                    p_peer->num_rx_sinks, p_peer->num_sup_sinks);
 
   p_peer->num_rx_sinks++;
 
-  /* Check the peer's SINK codec */
+  // Check the peer's Sink codec
   if (A2DP_IsPeerSinkCodecValid(p_codec_info)) {
-    /* If there is room for a new one */
+    // If there is room for a new one
     if (p_peer->num_sup_sinks < BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks)) {
-      tBTA_AV_CO_SINK* p_sink = &p_peer->sinks[p_peer->num_sup_sinks++];
+      BtaAvCoSep* p_sink = &p_peer->sinks[p_peer->num_sup_sinks++];
 
       APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
                        p_codec_info[1], p_codec_info[2], p_codec_info[3],
@@ -435,149 +927,286 @@
       p_sink->num_protect = *p_num_protect;
       memcpy(p_sink->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
     } else {
-      APPL_TRACE_ERROR("%s: no more room for SINK info", __func__);
+      APPL_TRACE_ERROR("%s: peer %s : no more room for Sink info", __func__,
+                       p_peer->addr.ToString().c_str());
     }
   }
 
-  // Check if this is the last SINK get capabilities or all supported codec
+  // Check if this is the last Sink get capabilities or all supported codec
   // capabilities are retrieved.
   if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
       (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
     return A2DP_FAIL;
   }
-  APPL_TRACE_DEBUG("%s: last sink reached", __func__);
+  APPL_TRACE_DEBUG("%s: last Sink codec reached for peer %s", __func__,
+                   p_peer->addr.ToString().c_str());
 
-  const tBTA_AV_CO_SINK* p_sink = bta_av_co_audio_set_codec(p_peer);
-  if (p_sink == NULL) {
-    APPL_TRACE_ERROR("%s: cannot set up codec for the peer SINK", __func__);
-    return A2DP_FAIL;
+  // Select the Source codec
+  const BtaAvCoSep* p_sink = nullptr;
+  if (p_peer->acceptor) {
+    UpdateAllSelectableSourceCodecs(p_peer);
+    if (p_peer->p_sink == nullptr) {
+      // Update the selected codec
+      p_peer->p_sink =
+          FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_peer->codec_config));
+    }
+    p_sink = p_peer->p_sink;
+    if (p_sink == nullptr) {
+      APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s",
+                       __func__, p_peer->addr.ToString().c_str());
+      return A2DP_FAIL;
+    }
+  } else {
+    p_sink = SelectSourceCodec(p_peer);
+    if (p_sink == nullptr) {
+      APPL_TRACE_ERROR("%s: cannot set up codec for peer %s", __func__,
+                       p_peer->addr.ToString().c_str());
+      return A2DP_FAIL;
+    }
   }
 
   // By default, no content protection
   *p_num_protect = 0;
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-  if (p_peer->cp_active) {
+  if (ContentProtectEnabled() && p_peer->ContentProtectActive()) {
     *p_num_protect = AVDT_CP_INFO_LEN;
     memcpy(p_protect_info, bta_av_co_cp_scmst, AVDT_CP_INFO_LEN);
   }
-#endif
 
-  // If acceptor -> reconfig otherwise reply for configuration.
-  if (p_peer->acp) {
-    // Stop fetching caps once we retrieved a supported codec.
-    APPL_TRACE_EVENT("%s: no need to fetch more SEPs", __func__);
-    *p_sep_info_idx = p_peer->num_seps;
+  // If acceptor -> reconfig otherwise reply for configuration
+  *p_sep_info_idx = p_sink->sep_info_idx;
+  APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__,
+                   p_peer->addr.ToString().c_str(),
+                   (p_peer->acceptor) ? "true" : "false",
+                   (p_peer->reconfig_needed) ? "true" : "false");
+  if (p_peer->acceptor) {
     if (p_peer->reconfig_needed) {
-      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, hndl);
-      BTA_AvReconfig(hndl, true, p_sink->sep_info_idx, p_peer->codec_config,
-                     *p_num_protect, bta_av_co_cp_scmst);
+      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__,
+                       bta_av_handle, p_peer->addr.ToString().c_str());
+      BTA_AvReconfig(bta_av_handle, true, p_sink->sep_info_idx,
+                     p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst);
     }
   } else {
-    *p_sep_info_idx = p_sink->sep_info_idx;
     memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
   }
 
   return A2DP_SUCCESS;
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_setconfig
- **
- ** Description      This callout function is executed by AV to set the codec
- **                  and content protection configuration of the audio stream.
- **
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
-                               UNUSED_ATTR uint8_t seid,
-                               UNUSED_ATTR const RawAddress& addr,
-                               uint8_t num_protect,
+tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle,
+                                           const RawAddress& peer_address,
+                                           uint8_t* p_codec_info,
+                                           uint8_t* p_sep_info_idx,
+                                           uint8_t seid, uint8_t* p_num_protect,
+                                           uint8_t* p_protect_info) {
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle,
+                   A2DP_CodecName(p_codec_info), seid);
+  APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
+                   __func__, *p_num_protect, p_protect_info[0],
+                   p_protect_info[1], p_protect_info[2]);
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_codec_info).c_str());
+
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
+    return A2DP_FAIL;
+  }
+  APPL_TRACE_DEBUG(
+      "%s: peer %s found (o=%d, n_sources=%d, n_rx_sources=%d, "
+      "n_sup_sources=%d)",
+      __func__, p_peer->addr.ToString().c_str(), p_peer->opened,
+      p_peer->num_sources, p_peer->num_rx_sources, p_peer->num_sup_sources);
+
+  p_peer->num_rx_sources++;
+
+  // Check the peer's Source codec
+  if (A2DP_IsPeerSourceCodecValid(p_codec_info)) {
+    // If there is room for a new one
+    if (p_peer->num_sup_sources < BTA_AV_CO_NUM_ELEMENTS(p_peer->sources)) {
+      BtaAvCoSep* p_source = &p_peer->sources[p_peer->num_sup_sources++];
+
+      APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
+                       p_codec_info[1], p_codec_info[2], p_codec_info[3],
+                       p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+      memcpy(p_source->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+      p_source->sep_info_idx = *p_sep_info_idx;
+      p_source->seid = seid;
+      p_source->num_protect = *p_num_protect;
+      memcpy(p_source->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
+    } else {
+      APPL_TRACE_ERROR("%s: peer %s : no more room for Source info", __func__,
+                       p_peer->addr.ToString().c_str());
+    }
+  }
+
+  // Check if this is the last Source get capabilities or all supported codec
+  // capabilities are retrieved.
+  if ((p_peer->num_rx_sources != p_peer->num_sources) &&
+      (p_peer->num_sup_sources != BTA_AV_CO_NUM_ELEMENTS(p_peer->sources))) {
+    return A2DP_FAIL;
+  }
+  APPL_TRACE_DEBUG("%s: last Source codec reached for peer %s", __func__,
+                   p_peer->addr.ToString().c_str());
+
+  // Select the Sink codec
+  const BtaAvCoSep* p_source = nullptr;
+  if (p_peer->acceptor) {
+    UpdateAllSelectableSinkCodecs(p_peer);
+    if (p_peer->p_source == nullptr) {
+      // Update the selected codec
+      p_peer->p_source =
+          FindPeerSource(p_peer, A2DP_SinkCodecIndex(p_peer->codec_config));
+    }
+    p_source = p_peer->p_source;
+    if (p_source == nullptr) {
+      APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s",
+                       __func__, p_peer->addr.ToString().c_str());
+      return A2DP_FAIL;
+    }
+  } else {
+    p_source = SelectSinkCodec(p_peer);
+    if (p_source == nullptr) {
+      APPL_TRACE_ERROR("%s: cannot set up codec for the peer %s", __func__,
+                       p_peer->addr.ToString().c_str());
+      return A2DP_FAIL;
+    }
+  }
+
+  // By default, no content protection
+  *p_num_protect = 0;
+  if (ContentProtectEnabled() && p_peer->ContentProtectActive()) {
+    *p_num_protect = AVDT_CP_INFO_LEN;
+    memcpy(p_protect_info, bta_av_co_cp_scmst, AVDT_CP_INFO_LEN);
+  }
+
+  // If acceptor -> reconfig otherwise reply for configuration
+  *p_sep_info_idx = p_source->sep_info_idx;
+  APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__,
+                   p_peer->addr.ToString().c_str(),
+                   (p_peer->acceptor) ? "true" : "false",
+                   (p_peer->reconfig_needed) ? "true" : "false");
+  if (p_peer->acceptor) {
+    if (p_peer->reconfig_needed) {
+      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__,
+                       bta_av_handle, p_peer->addr.ToString().c_str());
+      BTA_AvReconfig(bta_av_handle, true, p_source->sep_info_idx,
+                     p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst);
+    }
+  } else {
+    memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
+  }
+
+  return A2DP_SUCCESS;
+}
+
+void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle,
+                               UNUSED_ATTR const RawAddress& peer_address,
+                               const uint8_t* p_codec_info,
+                               UNUSED_ATTR uint8_t seid, uint8_t num_protect,
                                const uint8_t* p_protect_info,
                                uint8_t t_local_sep, uint8_t avdt_handle) {
-  tBTA_AV_CO_PEER* p_peer;
   tA2DP_STATUS status = A2DP_SUCCESS;
   uint8_t category = A2DP_SUCCESS;
   bool reconfig_needed = false;
 
+  APPL_TRACE_DEBUG(
+      "%s: bta_av_handle=0x%x peer_address=%s seid=%d "
+      "num_protect=%d t_local_sep=%d avdt_handle=%d",
+      __func__, bta_av_handle, peer_address.ToString().c_str(), seid,
+      num_protect, t_local_sep, avdt_handle);
   APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
                    p_codec_info[1], p_codec_info[2], p_codec_info[3],
                    p_codec_info[4], p_codec_info[5], p_codec_info[6]);
-  APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x",
-                   num_protect, p_protect_info[0], p_protect_info[1],
+  APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
+                   __func__, num_protect, p_protect_info[0], p_protect_info[1],
                    p_protect_info[2]);
-  A2DP_DumpCodecInfo(p_codec_info);
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_codec_info).c_str());
 
-  /* Retrieve the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer == NULL) {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
-    /* Call call-in rejecting the configuration */
-    bta_av_ci_setconfig(hndl, A2DP_BUSY, AVDT_ASC_CODEC, 0, NULL, false,
-                        avdt_handle);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
+    // Call call-in rejecting the configuration
+    bta_av_ci_setconfig(bta_av_handle, A2DP_BUSY, AVDT_ASC_CODEC, 0, nullptr,
+                        false, avdt_handle);
     return;
   }
 
-  APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)",
-                   __func__, p_peer->opened, p_peer->num_sinks,
-                   p_peer->num_rx_sinks, p_peer->num_sup_sinks);
+  APPL_TRACE_DEBUG(
+      "%s: peer %s found (o=%d, n_sinks=%d, n_rx_sinks=%d, "
+      "n_sup_sinks=%d)",
+      __func__, p_peer->addr.ToString().c_str(), p_peer->opened,
+      p_peer->num_sinks, p_peer->num_rx_sinks, p_peer->num_sup_sinks);
 
-  /* Sanity check: should not be opened at this point */
+  // Sanity check: should not be opened at this point
   if (p_peer->opened) {
-    APPL_TRACE_ERROR("%s: peer already in use", __func__);
+    APPL_TRACE_ERROR("%s: peer %s already in use", __func__,
+                     p_peer->addr.ToString().c_str());
   }
 
   if (num_protect != 0) {
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-    /* If CP is supported */
-    if ((num_protect != 1) ||
-        (bta_av_co_cp_is_scmst(p_protect_info) == false)) {
-      APPL_TRACE_ERROR("%s: wrong CP configuration", __func__);
+    if (ContentProtectEnabled()) {
+      if ((num_protect != 1) ||
+          !BtaAvCo::ContentProtectIsScmst(p_protect_info)) {
+        APPL_TRACE_ERROR("%s: wrong CP configuration for peer %s", __func__,
+                         p_peer->addr.ToString().c_str());
+        status = A2DP_BAD_CP_TYPE;
+        category = AVDT_ASC_PROTECT;
+      }
+    } else {
+      // Do not support content protection for the time being
+      APPL_TRACE_ERROR("%s: wrong CP configuration for peer %s", __func__,
+                       p_peer->addr.ToString().c_str());
       status = A2DP_BAD_CP_TYPE;
       category = AVDT_ASC_PROTECT;
     }
-#else
-    /* Do not support content protection for the time being */
-    APPL_TRACE_ERROR("%s: wrong CP configuration", __func__);
-    status = A2DP_BAD_CP_TYPE;
-    category = AVDT_ASC_PROTECT;
-#endif
   }
 
   if (status == A2DP_SUCCESS) {
     bool codec_config_supported = false;
 
     if (t_local_sep == AVDT_TSEP_SNK) {
-      APPL_TRACE_DEBUG("%s: peer is A2DP SRC", __func__);
+      APPL_TRACE_DEBUG("%s: peer %s is A2DP Source", __func__,
+                       p_peer->addr.ToString().c_str());
       codec_config_supported = A2DP_IsSinkCodecSupported(p_codec_info);
       if (codec_config_supported) {
-        // If Peer is SRC, and our config subset matches with what is
+        // If Peer is Source, and our config subset matches with what is
         // requested by peer, then just accept what peer wants.
-        bta_av_co_save_new_codec_config(p_peer, p_codec_info, num_protect,
-                                        p_protect_info);
+        SaveNewCodecConfig(p_peer, p_codec_info, num_protect, p_protect_info);
       }
     }
     if (t_local_sep == AVDT_TSEP_SRC) {
-      APPL_TRACE_DEBUG("%s: peer is A2DP SINK", __func__);
-      bool restart_output = false;
-      if ((bta_av_co_cb.codecs == nullptr) ||
-          !bta_av_co_set_codec_ota_config(p_peer, p_codec_info, num_protect,
-                                          p_protect_info, &restart_output)) {
-        APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__,
-                         A2DP_CodecName(p_codec_info));
+      APPL_TRACE_DEBUG("%s: peer %s is A2DP SINK", __func__,
+                       p_peer->addr.ToString().c_str());
+      // Ignore the restart_output flag: accepting the remote device's
+      // codec selection should not trigger codec reconfiguration.
+      bool dummy_restart_output = false;
+      if ((p_peer->GetCodecs() == nullptr) ||
+          !SetCodecOtaConfig(p_peer, p_codec_info, num_protect, p_protect_info,
+                             &dummy_restart_output)) {
+        APPL_TRACE_ERROR("%s: cannot set source codec %s for peer %s", __func__,
+                         A2DP_CodecName(p_codec_info),
+                         p_peer->addr.ToString().c_str());
       } else {
         codec_config_supported = true;
         // Check if reconfiguration is needed
-        if (restart_output ||
-            ((num_protect == 1) && (!bta_av_co_cb.cp.active))) {
+        if (((num_protect == 1) && !p_peer->ContentProtectActive())) {
           reconfig_needed = true;
         }
       }
     }
 
-    /* Check if codec configuration is supported */
+    // Check if codec configuration is supported
     if (!codec_config_supported) {
       category = AVDT_ASC_CODEC;
       status = A2DP_WRONG_CODEC;
@@ -585,124 +1214,106 @@
   }
 
   if (status != A2DP_SUCCESS) {
-    APPL_TRACE_DEBUG("%s: reject s=%d c=%d", __func__, status, category);
-    /* Call call-in rejecting the configuration */
-    bta_av_ci_setconfig(hndl, status, category, 0, NULL, false, avdt_handle);
+    APPL_TRACE_DEBUG("%s: peer %s reject s=%d c=%d", __func__,
+                     p_peer->addr.ToString().c_str(), status, category);
+    // Call call-in rejecting the configuration
+    bta_av_ci_setconfig(bta_av_handle, status, category, 0, nullptr, false,
+                        avdt_handle);
     return;
   }
 
-  /* Mark that this is an acceptor peer */
-  p_peer->acp = true;
+  // Mark that this is an acceptor peer
+  p_peer->acceptor = true;
   p_peer->reconfig_needed = reconfig_needed;
-  APPL_TRACE_DEBUG("%s: accept reconf=%d", __func__, reconfig_needed);
-  /* Call call-in accepting the configuration */
-  bta_av_ci_setconfig(hndl, A2DP_SUCCESS, A2DP_SUCCESS, 0, NULL,
+  APPL_TRACE_DEBUG("%s: peer %s accept reconf=%d", __func__,
+                   p_peer->addr.ToString().c_str(), reconfig_needed);
+  // Call call-in accepting the configuration
+  bta_av_ci_setconfig(bta_av_handle, A2DP_SUCCESS, A2DP_SUCCESS, 0, nullptr,
                       reconfig_needed, avdt_handle);
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_open
- **
- ** Description      This function is called by AV when the audio stream
- **                  connection is opened.
- **
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_open(tBTA_AV_HNDL hndl, uint16_t mtu) {
-  tBTA_AV_CO_PEER* p_peer;
+void BtaAvCo::ProcessOpen(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address, uint16_t mtu) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x mtu:%d", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle, mtu);
 
-  APPL_TRACE_DEBUG("%s: handle: %d mtu:%d", __func__, hndl, mtu);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
+    return;
+  }
+  p_peer->opened = true;
+  p_peer->mtu = mtu;
 
-  /* Retrieve the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer == NULL) {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
-  } else {
-    p_peer->opened = true;
-    p_peer->mtu = mtu;
+  // The first connected peer becomes the active peer
+  if (active_peer_ == nullptr) {
+    active_peer_ = p_peer;
   }
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_close
- **
- ** Description      This function is called by AV when the audio stream
- **                  connection is closed.
- **
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_close(tBTA_AV_HNDL hndl) {
-  tBTA_AV_CO_PEER* p_peer;
+void BtaAvCo::ProcessClose(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle);
+  btif_av_reset_audio_delay();
 
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  /* Retrieve the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer) {
-    /* Mark the peer closed and clean the peer info */
-    memset(p_peer, 0, sizeof(*p_peer));
-  } else {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
+    return;
   }
+  // Reset the active peer
+  if (active_peer_ == p_peer) {
+    active_peer_ = nullptr;
+  }
+  // Mark the peer closed and clean the peer info
+  p_peer->Init(codec_priorities_);
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_start
- **
- ** Description      This function is called by AV when the audio streaming data
- **                  transfer is started.
- **
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_start(UNUSED_ATTR tBTA_AV_HNDL hndl,
-                           UNUSED_ATTR uint8_t* p_codec_info,
-                           UNUSED_ATTR bool* p_no_rtp_hdr) {
-  APPL_TRACE_DEBUG("%s", __func__);
+void BtaAvCo::ProcessStart(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address,
+                           const uint8_t* p_codec_info, bool* p_no_rtp_header) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle);
+
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
+    return;
+  }
+
+  bool add_rtp_header =
+      A2DP_UsesRtpHeader(p_peer->ContentProtectActive(), p_codec_info);
+
+  APPL_TRACE_DEBUG("%s: bta_av_handle: 0x%x add_rtp_header: %s", __func__,
+                   bta_av_handle, add_rtp_header ? "true" : "false");
+  *p_no_rtp_header = !add_rtp_header;
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_stop
- **
- ** Description      This function is called by AV when the audio streaming data
- **                  transfer is stopped.
- **
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_stop(UNUSED_ATTR tBTA_AV_HNDL hndl) {
-  APPL_TRACE_DEBUG("%s", __func__);
+void BtaAvCo::ProcessStop(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle);
+  // Nothing to do
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_src_data_path
- **
- ** Description      This function is called to manage data transfer from
- **                  the audio codec to AVDTP.
- **
- ** Returns          Pointer to the GKI buffer to send, NULL if no buffer to
- **                  send
- **
- ******************************************************************************/
-void* bta_av_co_audio_src_data_path(const uint8_t* p_codec_info,
-                                    uint32_t* p_timestamp) {
+BT_HDR* BtaAvCo::GetNextSourceDataPacket(const uint8_t* p_codec_info,
+                                         uint32_t* p_timestamp) {
   BT_HDR* p_buf;
 
   APPL_TRACE_DEBUG("%s: codec: %s", __func__, A2DP_CodecName(p_codec_info));
 
   p_buf = btif_a2dp_source_audio_readbuf();
-  if (p_buf == NULL) return NULL;
+  if (p_buf == nullptr) return nullptr;
 
   /*
    * Retrieve the timestamp information from the media packet,
@@ -719,387 +1330,154 @@
                      A2DP_GetCodecType(p_codec_info));
   }
 
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-  if (bta_av_co_cb.cp.active) {
+  if (ContentProtectEnabled() && (active_peer_ != nullptr) &&
+      active_peer_->ContentProtectActive()) {
     p_buf->len++;
     p_buf->offset--;
     uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
-    *p = bta_av_co_cp_get_flag();
+    *p = ContentProtectFlag();
   }
-#endif
 
   return p_buf;
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_drop
- **
- ** Description      An Audio packet is dropped. .
- **                  It's very likely that the connected headset with this
- **                  handle is moved far away. The implementation may want to
- **                  reduce the encoder bit rate setting to reduce the packet
- **                  size.
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_drop(tBTA_AV_HNDL hndl) {
-  APPL_TRACE_ERROR("%s: dropped audio packet on handle 0x%x", __func__, hndl);
+void BtaAvCo::DataPacketWasDropped(tBTA_AV_HNDL bta_av_handle,
+                                   const RawAddress& peer_address) {
+  APPL_TRACE_ERROR("%s: peer %s dropped audio packet on handle 0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle);
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_delay
- **
- ** Description      This function is called by AV when the audio stream
- **                  connection needs to send the initial delay report to the
- **                  connected SRC.
- **
- **
- ** Returns          void
- **
- ******************************************************************************/
-void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, uint16_t delay) {
-  APPL_TRACE_ERROR("%s: handle: x%x, delay:0x%x", __func__, hndl, delay);
+void BtaAvCo::ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle,
+                                const RawAddress& peer_address,
+                                uint16_t delay) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x delay:0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle, delay);
+
+  btif_av_set_audio_delay(delay);
 }
 
-void bta_av_co_audio_update_mtu(tBTA_AV_HNDL hndl, uint16_t mtu) {
-  tBTA_AV_CO_PEER* p_peer;
+void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle,
+                        const RawAddress& peer_address, uint16_t mtu) {
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x mtu: %d", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle, mtu);
 
-  APPL_TRACE_DEBUG("%s: handle: %d mtu: %d", __func__, hndl, mtu);
-
-  /* Retrieve the peer info */
-  p_peer = bta_av_co_get_peer(hndl);
-  if (p_peer == NULL) {
-    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
+  if (p_peer == nullptr) {
+    APPL_TRACE_ERROR(
+        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
+        __func__, bta_av_handle, peer_address.ToString().c_str());
     return;
   }
   p_peer->mtu = mtu;
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_cp_is_scmst
- **
- ** Description      Check if a content protection service is SCMS-T
- **
- ** Returns          true if this CP is SCMS-T, false otherwise
- **
- ******************************************************************************/
-static bool bta_av_co_cp_is_scmst(const uint8_t* p_protect_info) {
-  APPL_TRACE_DEBUG("%s", __func__);
+bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) {
+  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
+                   peer_address.ToString().c_str());
 
-  if (*p_protect_info >= AVDT_CP_LOSC) {
-    uint16_t cp_id;
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
 
-    p_protect_info++;
-    STREAM_TO_UINT16(cp_id, p_protect_info);
-    if (cp_id == AVDT_CP_SCMS_T_ID) {
-      APPL_TRACE_DEBUG("%s: SCMS-T found", __func__);
-      return true;
-    }
+  if (peer_address.IsEmpty()) {
+    // Reset the active peer;
+    active_peer_ = nullptr;
+    memset(codec_config_, 0, sizeof(codec_config_));
+    return true;
   }
 
-  return false;
-}
-
-// Check if audio protect info contains SCMS-T Copy Protection
-// Returns true if |p_protect_info| contains SCMS-T, otherwise false.
-static bool bta_av_co_audio_protect_has_scmst(uint8_t num_protect,
-                                              const uint8_t* p_protect_info) {
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  while (num_protect--) {
-    if (bta_av_co_cp_is_scmst(p_protect_info)) return true;
-    /* Move to the next SC */
-    p_protect_info += *p_protect_info + 1;
-  }
-  APPL_TRACE_DEBUG("%s: SCMS-T not found", __func__);
-  return false;
-}
-
-/*******************************************************************************
- **
- ** Function         bta_av_co_audio_sink_supports_cp
- **
- ** Description      Check if a sink supports the current content protection
- **
- ** Returns          true if the sink supports this CP, false otherwise
- **
- ******************************************************************************/
-static bool bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK* p_sink) {
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  /* Check if content protection is enabled for this stream */
-  if (bta_av_co_cp_get_flag() != AVDT_CP_SCMS_COPY_FREE) {
-    return bta_av_co_audio_protect_has_scmst(p_sink->num_protect,
-                                             p_sink->protect_info);
+  // Find the peer
+  BtaAvCoPeer* p_peer = FindPeer(peer_address);
+  if (p_peer == nullptr) {
+    return false;
   }
 
-  APPL_TRACE_DEBUG("%s: not required", __func__);
+  active_peer_ = p_peer;
+  memcpy(codec_config_, active_peer_->codec_config, AVDT_CODEC_SIZE);
+  APPL_TRACE_DEBUG("%s: codec = %s", __func__,
+                   A2DP_CodecInfoString(codec_config_).c_str());
+  ReportSourceCodecState(active_peer_);
   return true;
 }
 
-/*******************************************************************************
- **
- ** Function         bta_av_co_find_peer_src_supports_codec
- **
- ** Description      Find a peer acting as src that supports codec config
- **
- ** Returns          The peer source that supports the codec, otherwise NULL.
- **
- ******************************************************************************/
-static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
-    const tBTA_AV_CO_PEER* p_peer) {
-  APPL_TRACE_DEBUG("%s: peer num_sup_srcs = %d", __func__,
-                   p_peer->num_sup_srcs);
-
-  for (size_t index = 0; index < p_peer->num_sup_srcs; index++) {
-    const uint8_t* p_codec_caps = p_peer->srcs[index].codec_caps;
-    if (A2DP_CodecTypeEquals(bta_av_co_cb.codec_config, p_codec_caps) &&
-        A2DP_IsPeerSourceCodecSupported(p_codec_caps)) {
-      return &p_peer->srcs[index];
-    }
-  }
-  return NULL;
-}
-
-//
-// Select the current codec configuration based on peer codec support.
-// Furthermore, the local state for the remaining non-selected codecs is
-// updated to reflect whether the codec is selectable.
-// Return a pointer to the corresponding |tBTA_AV_CO_SINK| sink entry
-// on success, otherwise NULL.
-//
-static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer) {
-  tBTA_AV_CO_SINK* p_sink = NULL;
-
-  // Update all selectable codecs.
-  // This is needed to update the selectable parameters for each codec.
-  // NOTE: The selectable codec info is used only for informational purpose.
-  for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {
-    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
-                     iter->name().c_str());
-    bta_av_co_audio_update_selectable_codec(*iter, p_peer);
-  }
-
-  // Select the codec
-  for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {
-    APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
-    p_sink = bta_av_co_audio_codec_selected(*iter, p_peer);
-    if (p_sink != NULL) {
-      APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
-      break;
-    }
-    APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
-  }
-
-  // NOTE: Unconditionally dispatch the event to make sure a callback with
-  // the most recent codec info is generated.
-  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
-
-  return p_sink;
-}
-
-// Select an open device for the preferred codec specified by |codec_config|.
-// Return the corresponding peer that supports the codec, otherwise NULL.
-static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(
-    A2dpCodecConfig& codec_config, tBTA_AV_CO_PEER* p_peer) {
-  uint8_t new_codec_config[AVDT_CODEC_SIZE];
-
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  // Find the peer sink for the codec
-  tBTA_AV_CO_SINK* p_sink = NULL;
-  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
-    btav_a2dp_codec_index_t peer_codec_index =
-        A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
-    if (peer_codec_index != codec_config.codecIndex()) {
-      continue;
-    }
-    if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) {
-      APPL_TRACE_DEBUG(
-          "%s: peer sink for codec %s does not support "
-          "Copy Protection",
-          __func__, codec_config.name().c_str());
-      continue;
-    }
-    p_sink = &p_peer->sinks[index];
-    break;
-  }
-  if (p_sink == NULL) {
-    APPL_TRACE_DEBUG("%s: peer sink for codec %s not found", __func__,
-                     codec_config.name().c_str());
-    return NULL;
-  }
-  if (!bta_av_co_cb.codecs->setCodecConfig(
-          p_sink->codec_caps, true /* is_capability */, new_codec_config,
-          true /* select_current_codec */)) {
-    APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__,
-                     codec_config.name().c_str());
-    return NULL;
-  }
-  p_peer->p_sink = p_sink;
-
-  bta_av_co_save_new_codec_config(p_peer, new_codec_config, p_sink->num_protect,
-                                  p_sink->protect_info);
-  // NOTE: Event BTIF_AV_SOURCE_CONFIG_UPDATED_EVT is dispatched by the caller
-
-  return p_sink;
-}
-
-// Update a selectable codec |codec_config| with the corresponding codec
-// information from a peer device |p_peer|.
-// Returns true if the codec is updated, otherwise false.
-static bool bta_av_co_audio_update_selectable_codec(
-    A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer) {
-  uint8_t new_codec_config[AVDT_CODEC_SIZE];
-
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  // Find the peer sink for the codec
-  const tBTA_AV_CO_SINK* p_sink = NULL;
-  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
-    btav_a2dp_codec_index_t peer_codec_index =
-        A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
-    if (peer_codec_index != codec_config.codecIndex()) {
-      continue;
-    }
-    if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) {
-      APPL_TRACE_DEBUG(
-          "%s: peer sink for codec %s does not support "
-          "Copy Protection",
-          __func__, codec_config.name().c_str());
-      continue;
-    }
-    p_sink = &p_peer->sinks[index];
-    break;
-  }
-  if (p_sink == NULL) {
-    // The peer sink device does not support this codec
-    return false;
-  }
-  if (!bta_av_co_cb.codecs->setCodecConfig(
-          p_sink->codec_caps, true /* is_capability */, new_codec_config,
-          false /* select_current_codec */)) {
-    APPL_TRACE_DEBUG("%s: cannot update source codec %s", __func__,
-                     codec_config.name().c_str());
-    return false;
-  }
-  return true;
-}
-
-static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
-                                            const uint8_t* new_codec_config,
-                                            uint8_t num_protect,
-                                            const uint8_t* p_protect_info) {
-  APPL_TRACE_DEBUG("%s", __func__);
-  A2DP_DumpCodecInfo(new_codec_config);
-
-  // Protect access to bta_av_co_cb.codec_config
-  mutex_global_lock();
-
-  memcpy(bta_av_co_cb.codec_config, new_codec_config,
-         sizeof(bta_av_co_cb.codec_config));
-  memcpy(p_peer->codec_config, new_codec_config, AVDT_CODEC_SIZE);
-
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-  /* Check if this sink supports SCMS */
-  bool cp_active =
-      bta_av_co_audio_protect_has_scmst(num_protect, p_protect_info);
-  bta_av_co_cb.cp.active = cp_active;
-  p_peer->cp_active = cp_active;
-#endif
-
-  // Protect access to bta_av_co_cb.codec_config
-  mutex_global_unlock();
-}
-
-void bta_av_co_get_peer_params(tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) {
+void BtaAvCo::GetPeerEncoderParameters(
+    const RawAddress& peer_address,
+    tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) {
   uint16_t min_mtu = 0xFFFF;
+  CHECK(p_peer_params != nullptr) << "Peer address " << peer_address;
 
-  APPL_TRACE_DEBUG("%s", __func__);
-  CHECK(p_peer_params != nullptr);
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
 
-  /* Protect access to bta_av_co_cb.codec_config */
-  mutex_global_lock();
-
-  /* Compute the MTU */
-  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
-    const tBTA_AV_CO_PEER* p_peer = &bta_av_co_cb.peers[i];
+  // Compute the MTU
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
+    const BtaAvCoPeer* p_peer = &peers_[i];
     if (!p_peer->opened) continue;
+    if (p_peer->addr != peer_address) continue;
     if (p_peer->mtu < min_mtu) min_mtu = p_peer->mtu;
   }
   p_peer_params->peer_mtu = min_mtu;
-  p_peer_params->is_peer_edr = btif_av_is_peer_edr();
-  p_peer_params->peer_supports_3mbps = btif_av_peer_supports_3mbps();
-
-  /* Protect access to bta_av_co_cb.codec_config */
-  mutex_global_unlock();
+  p_peer_params->is_peer_edr = btif_av_is_peer_edr(peer_address);
+  p_peer_params->peer_supports_3mbps =
+      btif_av_peer_supports_3mbps(peer_address);
+  APPL_TRACE_DEBUG(
+      "%s: peer_address=%s peer_mtu=%d is_peer_edr=%s peer_supports_3mbps=%s",
+      __func__, peer_address.ToString().c_str(), p_peer_params->peer_mtu,
+      logbool(p_peer_params->is_peer_edr).c_str(),
+      logbool(p_peer_params->peer_supports_3mbps).c_str());
 }
 
-const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
-  /* Protect access to bta_av_co_cb.codec_config */
-  mutex_global_lock();
+const tA2DP_ENCODER_INTERFACE* BtaAvCo::GetSourceEncoderInterface() {
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
 
-  const tA2DP_ENCODER_INTERFACE* encoder_interface =
-      A2DP_GetEncoderInterface(bta_av_co_cb.codec_config);
-
-  /* Protect access to bta_av_co_cb.codec_config */
-  mutex_global_unlock();
-
-  return encoder_interface;
+  return A2DP_GetEncoderInterface(codec_config_);
 }
 
-bool bta_av_co_set_codec_user_config(
+const tA2DP_DECODER_INTERFACE* BtaAvCo::GetSinkDecoderInterface() {
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  return A2DP_GetDecoderInterface(codec_config_);
+}
+
+bool BtaAvCo::SetCodecUserConfig(
+    const RawAddress& peer_address,
     const btav_a2dp_codec_config_t& codec_user_config) {
   uint8_t result_codec_config[AVDT_CODEC_SIZE];
-  const tBTA_AV_CO_SINK* p_sink = nullptr;
+  const BtaAvCoSep* p_sink = nullptr;
   bool restart_input = false;
   bool restart_output = false;
   bool config_updated = false;
   bool success = true;
 
-  // Find the peer that is currently open
-  tBTA_AV_CO_PEER* p_peer = nullptr;
-  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
-    tBTA_AV_CO_PEER* p_peer_tmp = &bta_av_co_cb.peers[i];
-    if (p_peer_tmp->opened) {
-      p_peer = p_peer_tmp;
-      break;
-    }
-  }
+  APPL_TRACE_DEBUG("%s: peer_address=%s codec_user_config=%s", __func__,
+                   peer_address.ToString().c_str(),
+                   codec_user_config.ToString().c_str());
+
+  BtaAvCoPeer* p_peer = FindPeer(peer_address);
   if (p_peer == nullptr) {
-    APPL_TRACE_ERROR("%s: no open peer to configure", __func__);
+    APPL_TRACE_ERROR("%s: cannot find peer %s to configure", __func__,
+                     peer_address.ToString().c_str());
     success = false;
     goto done;
   }
 
   // Find the peer SEP codec to use
   if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) {
-    for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
-      btav_a2dp_codec_index_t peer_codec_index =
-          A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
-      if (peer_codec_index != codec_user_config.codec_type) continue;
-      if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) continue;
-      p_sink = &p_peer->sinks[index];
-      break;
-    }
+    p_sink = FindPeerSink(p_peer, codec_user_config.codec_type);
   } else {
     // Use the current sink codec
     p_sink = p_peer->p_sink;
   }
   if (p_sink == nullptr) {
-    APPL_TRACE_ERROR("%s: cannot find peer SEP to configure for codec type %d",
-                     __func__, codec_user_config.codec_type);
+    APPL_TRACE_ERROR(
+        "%s: peer %s : cannot find peer SEP to configure for codec type %d",
+        __func__, p_peer->addr.ToString().c_str(),
+        codec_user_config.codec_type);
     success = false;
     goto done;
   }
 
   tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
-  bta_av_co_get_peer_params(&peer_params);
-  if (!bta_av_co_cb.codecs->setCodecUserConfig(
+  GetPeerEncoderParameters(p_peer->addr, &peer_params);
+  if (!p_peer->GetCodecs()->setCodecUserConfig(
           codec_user_config, &peer_params, p_sink->codec_caps,
           result_codec_config, &restart_input, &restart_output,
           &config_updated)) {
@@ -1109,152 +1487,74 @@
 
   if (restart_output) {
     uint8_t num_protect = 0;
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-    if (p_peer->cp_active) num_protect = AVDT_CP_INFO_LEN;
-#endif
+    if (ContentProtectEnabled() && p_peer->ContentProtectActive()) {
+      num_protect = AVDT_CP_INFO_LEN;
+    }
 
-    p_sink = bta_av_co_audio_set_codec(p_peer);
-    if (p_sink == NULL) {
-      APPL_TRACE_ERROR("%s: cannot set up codec for the peer SINK", __func__);
+    p_sink = SelectSourceCodec(p_peer);
+    if (p_sink == nullptr) {
+      APPL_TRACE_ERROR("%s: peer %s : cannot set up codec for the peer SINK",
+                       __func__, p_peer->addr.ToString().c_str());
       success = false;
       goto done;
     }
     // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
     if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
         (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
-      APPL_TRACE_WARNING("%s: not all peer's capabilities have been retrieved",
-                         __func__);
+      APPL_TRACE_WARNING(
+          "%s: peer %s : not all peer's capabilities have been retrieved",
+          __func__, p_peer->addr.ToString().c_str());
       success = false;
       goto done;
     }
 
-    APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, p_peer->handle);
-    BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
+    p_peer->acceptor = false;
+    APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
+                     p_peer->BtaAvHandle());
+    BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
                    p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
   }
 
 done:
-  // NOTE: We uncoditionally send the upcall even if there is no change
+  // NOTE: We unconditionally send the upcall even if there is no change
   // or the user config failed. Thus, the caller would always know whether the
   // request succeeded or failed.
   // NOTE: Currently, the input is restarted by sending an upcall
   // and informing the Media Framework about the change.
-  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+  if (p_peer != nullptr) {
+    return ReportSourceCodecState(p_peer);
+  }
 
   return success;
 }
 
-// Sets the Over-The-Air preferred codec configuration.
-// The OTA prefered codec configuration is ignored if the current
-// codec configuration contains explicit user configuration, or if the
-// codec configuration for the same codec contains explicit user
-// configuration.
-// |p_peer| is the peer device that sent the OTA codec configuration.
-// |p_ota_codec_config| contains the received OTA A2DP codec configuration
-// from the remote peer. Note: this is not the peer codec capability,
-// but the codec configuration that the peer would like to use.
-// |num_protect| is the number of content protection methods to use.
-// |p_protect_info| contains the content protection information to use.
-// If there is a change in the encoder configuration tht requires restarting
-// of the A2DP connection, flag |p_restart_output| is set to true.
-// Returns true on success, otherwise false.
-static bool bta_av_co_set_codec_ota_config(tBTA_AV_CO_PEER* p_peer,
-                                           const uint8_t* p_ota_codec_config,
-                                           uint8_t num_protect,
-                                           const uint8_t* p_protect_info,
-                                           bool* p_restart_output) {
-  uint8_t result_codec_config[AVDT_CODEC_SIZE];
-  bool restart_input = false;
-  bool restart_output = false;
-  bool config_updated = false;
-
-  APPL_TRACE_DEBUG("%s", __func__);
-  A2DP_DumpCodecInfo(p_ota_codec_config);
-
-  *p_restart_output = false;
-
-  // Find the peer SEP codec to use
-  btav_a2dp_codec_index_t ota_codec_index =
-      A2DP_SourceCodecIndex(p_ota_codec_config);
-  if (ota_codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
-    APPL_TRACE_WARNING("%s: invalid peer codec config", __func__);
-    return false;
-  }
-  const tBTA_AV_CO_SINK* p_sink = nullptr;
-  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
-    btav_a2dp_codec_index_t peer_codec_index =
-        A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
-    if (peer_codec_index != ota_codec_index) continue;
-    if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) continue;
-    p_sink = &p_peer->sinks[index];
-    break;
-  }
-  if ((p_peer->num_sup_sinks > 0) && (p_sink == nullptr)) {
-    // There are no peer SEPs if we didn't do the discovery procedure yet.
-    // We have all the information we need from the peer, so we can
-    // proceed with the OTA codec configuration.
-    APPL_TRACE_ERROR("%s: cannot find peer SEP to configure", __func__);
-    return false;
-  }
-
-  tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
-  bta_av_co_get_peer_params(&peer_params);
-  if (!bta_av_co_cb.codecs->setCodecOtaConfig(
-          p_ota_codec_config, &peer_params, result_codec_config, &restart_input,
-          &restart_output, &config_updated)) {
-    APPL_TRACE_ERROR("%s: cannot set OTA config", __func__);
-    return false;
-  }
-
-  if (restart_output) {
-    APPL_TRACE_DEBUG("%s: restart output", __func__);
-    A2DP_DumpCodecInfo(result_codec_config);
-
-    *p_restart_output = true;
-    p_peer->p_sink = p_sink;
-    bta_av_co_save_new_codec_config(p_peer, result_codec_config, num_protect,
-                                    p_protect_info);
-  }
-
-  if (restart_input || config_updated) {
-    // NOTE: Currently, the input is restarted by sending an upcall
-    // and informing the Media Framework about the change.
-    btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
-  }
-
-  return true;
-}
-
-bool bta_av_co_set_codec_audio_config(
+bool BtaAvCo::SetCodecAudioConfig(
     const btav_a2dp_codec_config_t& codec_audio_config) {
   uint8_t result_codec_config[AVDT_CODEC_SIZE];
   bool restart_output = false;
   bool config_updated = false;
 
+  APPL_TRACE_DEBUG("%s: codec_audio_config: %s", __func__,
+                   codec_audio_config.ToString().c_str());
+
   // Find the peer that is currently open
-  tBTA_AV_CO_PEER* p_peer = nullptr;
-  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
-    tBTA_AV_CO_PEER* p_peer_tmp = &bta_av_co_cb.peers[i];
-    if (p_peer_tmp->opened) {
-      p_peer = p_peer_tmp;
-      break;
-    }
-  }
+  BtaAvCoPeer* p_peer = active_peer_;
   if (p_peer == nullptr) {
-    APPL_TRACE_ERROR("%s: no open peer to configure", __func__);
+    APPL_TRACE_ERROR("%s: no active peer to configure", __func__);
     return false;
   }
 
   // Use the current sink codec
-  const tBTA_AV_CO_SINK* p_sink = p_peer->p_sink;
+  const BtaAvCoSep* p_sink = p_peer->p_sink;
   if (p_sink == nullptr) {
-    APPL_TRACE_ERROR("%s: cannot find peer SEP to configure", __func__);
+    APPL_TRACE_ERROR("%s: peer %s : cannot find peer SEP to configure",
+                     __func__, p_peer->addr.ToString().c_str());
     return false;
   }
 
   tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
-  bta_av_co_get_peer_params(&peer_params);
-  if (!bta_av_co_cb.codecs->setCodecAudioConfig(
+  GetPeerEncoderParameters(p_peer->addr, &peer_params);
+  if (!p_peer->GetCodecs()->setCodecAudioConfig(
           codec_audio_config, &peer_params, p_sink->codec_caps,
           result_codec_config, &restart_output, &config_updated)) {
     return false;
@@ -1262,22 +1562,24 @@
 
   if (restart_output) {
     uint8_t num_protect = 0;
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-    if (p_peer->cp_active) num_protect = AVDT_CP_INFO_LEN;
-#endif
+    if (ContentProtectEnabled() && p_peer->ContentProtectActive()) {
+      num_protect = AVDT_CP_INFO_LEN;
+    }
 
-    bta_av_co_save_new_codec_config(p_peer, result_codec_config,
-                                    p_sink->num_protect, p_sink->protect_info);
+    SaveNewCodecConfig(p_peer, result_codec_config, p_sink->num_protect,
+                       p_sink->protect_info);
 
     // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
     if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
         (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
-      APPL_TRACE_WARNING("%s: not all peer's capabilities have been retrieved",
-                         __func__);
+      APPL_TRACE_WARNING(
+          "%s: peer %s : not all peer's capabilities have been retrieved",
+          __func__, p_peer->addr.ToString().c_str());
     } else {
-      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__,
-                       p_peer->handle);
-      BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
+      p_peer->acceptor = false;
+      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
+                       p_peer->BtaAvHandle());
+      BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
                      p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
     }
   }
@@ -1285,50 +1587,575 @@
   if (config_updated) {
     // NOTE: Currently, the input is restarted by sending an upcall
     // and informing the Media Framework about the change.
-    btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+    return ReportSourceCodecState(p_peer);
   }
 
   return true;
 }
 
-A2dpCodecs* bta_av_get_a2dp_codecs(void) { return bta_av_co_cb.codecs; }
+bool BtaAvCo::ReportSourceCodecState(BtaAvCoPeer* p_peer) {
+  btav_a2dp_codec_config_t codec_config;
+  std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
+  std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;
 
-A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) {
-  A2dpCodecConfig* current_codec;
+  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
+                   p_peer->addr.ToString().c_str());
+  A2dpCodecs* codecs = p_peer->GetCodecs();
+  CHECK(codecs != nullptr);
+  if (!codecs->getCodecConfigAndCapabilities(&codec_config,
+                                             &codecs_local_capabilities,
+                                             &codecs_selectable_capabilities)) {
+    APPL_TRACE_WARNING(
+        "%s: Peer %s : error reporting audio source codec state: "
+        "cannot get codec config and capabilities",
+        __func__, p_peer->addr.ToString().c_str());
+    return false;
+  }
+  APPL_TRACE_DEBUG("%s: peer %s codec_config=%s", __func__,
+                   p_peer->addr.ToString().c_str(),
+                   codec_config.ToString().c_str());
+  btif_av_report_source_codec_state(p_peer->addr, codec_config,
+                                    codecs_local_capabilities,
+                                    codecs_selectable_capabilities);
+  return true;
+}
 
-  mutex_global_lock();
-  if (bta_av_co_cb.codecs == nullptr) {
-    mutex_global_unlock();
+bool BtaAvCo::ReportSinkCodecState(BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
+                   p_peer->addr.ToString().c_str());
+  // Nothing to do (for now)
+  return true;
+}
+void BtaAvCo::DebugDump(int fd) {
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  dprintf(fd, "\nA2DP Codecs and Peers State:\n");
+  dprintf(fd, "  Active peer: %s\n",
+          (active_peer_ != nullptr) ? active_peer_->addr.ToString().c_str()
+                                    : "null");
+
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
+    const BtaAvCoPeer& peer = peers_[i];
+    dprintf(fd, "  Peer: %s\n", peer.addr.ToString().c_str());
+    dprintf(fd, "    Number of sinks: %u\n", peer.num_sinks);
+    dprintf(fd, "    Number of sources: %u\n", peer.num_sources);
+    dprintf(fd, "    Number of SEPs: %u\n", peer.num_seps);
+    dprintf(fd, "    Number of received sinks: %u\n", peer.num_rx_sinks);
+    dprintf(fd, "    Number of received sources: %u\n", peer.num_rx_sources);
+    dprintf(fd, "    Number of supported sinks: %u\n", peer.num_sup_sinks);
+    dprintf(fd, "    Number of supported sources: %u\n", peer.num_sup_sources);
+    dprintf(fd, "    Acceptor: %s\n", (peer.acceptor) ? "true" : "false");
+    dprintf(fd, "    Reconfig needed: %s\n",
+            (peer.reconfig_needed) ? "true" : "false");
+    dprintf(fd, "    Opened: %s\n", (peer.opened) ? "true" : "false");
+    dprintf(fd, "    MTU: %u\n", peer.mtu);
+    dprintf(fd, "    UUID to connect: 0x%x\n", peer.uuid_to_connect);
+    dprintf(fd, "    BTA AV handle: %u\n", peer.BtaAvHandle());
+  }
+
+  //
+  // Active peer codec-specific stats
+  //
+  if (active_peer_ != nullptr) {
+    A2dpCodecs* a2dp_codecs = active_peer_->GetCodecs();
+    if (a2dp_codecs != nullptr) {
+      a2dp_codecs->debug_codec_dump(fd);
+    }
+  }
+}
+
+bool BtaAvCo::ContentProtectIsScmst(const uint8_t* p_protect_info) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (*p_protect_info >= AVDT_CP_LOSC) {
+    uint16_t cp_id;
+    p_protect_info++;
+    STREAM_TO_UINT16(cp_id, p_protect_info);
+    if (cp_id == AVDT_CP_SCMS_T_ID) {
+      APPL_TRACE_DEBUG("%s: SCMS-T found", __func__);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool BtaAvCo::AudioProtectHasScmst(uint8_t num_protect,
+                                   const uint8_t* p_protect_info) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  while (num_protect--) {
+    if (BtaAvCo::ContentProtectIsScmst(p_protect_info)) return true;
+    // Move to the next Content Protect schema
+    p_protect_info += *p_protect_info + 1;
+  }
+  APPL_TRACE_DEBUG("%s: SCMS-T not found", __func__);
+  return false;
+}
+
+bool BtaAvCo::AudioSepHasContentProtection(const BtaAvCoSep* p_sep) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  // Check if content protection is enabled for this stream
+  if (ContentProtectFlag() != AVDT_CP_SCMS_COPY_FREE) {
+    return BtaAvCo::AudioProtectHasScmst(p_sep->num_protect,
+                                         p_sep->protect_info);
+  }
+
+  APPL_TRACE_DEBUG("%s: not required", __func__);
+  return true;
+}
+
+const BtaAvCoSep* BtaAvCo::SelectSourceCodec(BtaAvCoPeer* p_peer) {
+  const BtaAvCoSep* p_sink = nullptr;
+
+  // Update all selectable codecs.
+  // This is needed to update the selectable parameters for each codec.
+  // NOTE: The selectable codec info is used only for informational purpose.
+  UpdateAllSelectableSourceCodecs(p_peer);
+
+  // Select the codec
+  for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) {
+    APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
+    p_sink = AttemptSourceCodecSelection(*iter, p_peer);
+    if (p_sink != nullptr) {
+      APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
+      break;
+    }
+    APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
+  }
+
+  // NOTE: Unconditionally dispatch the event to make sure a callback with
+  // the most recent codec info is generated.
+  ReportSourceCodecState(p_peer);
+
+  return p_sink;
+}
+
+const BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) {
+  const BtaAvCoSep* p_source = nullptr;
+
+  // Update all selectable codecs.
+  // This is needed to update the selectable parameters for each codec.
+  // NOTE: The selectable codec info is used only for informational purpose.
+  UpdateAllSelectableSinkCodecs(p_peer);
+
+  // Select the codec
+  for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) {
+    APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
+    p_source = AttemptSinkCodecSelection(*iter, p_peer);
+    if (p_source != nullptr) {
+      APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
+      break;
+    }
+    APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
+  }
+
+  // NOTE: Unconditionally dispatch the event to make sure a callback with
+  // the most recent codec info is generated.
+  ReportSinkCodecState(p_peer);
+
+  return p_source;
+}
+
+BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer,
+                                  btav_a2dp_codec_index_t codec_index) {
+  if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
+    APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__,
+                       p_peer->addr.ToString().c_str());
     return nullptr;
   }
-  current_codec = bta_av_co_cb.codecs->getCurrentCodecConfig();
-  mutex_global_unlock();
 
-  return current_codec;
+  // Find the peer Sink for the codec
+  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
+    BtaAvCoSep* p_sink = &p_peer->sinks[index];
+    btav_a2dp_codec_index_t peer_codec_index =
+        A2DP_SourceCodecIndex(p_sink->codec_caps);
+    if (peer_codec_index != codec_index) {
+      continue;
+    }
+    if (!AudioSepHasContentProtection(p_sink)) {
+      APPL_TRACE_DEBUG(
+          "%s: peer Sink for codec %s does not support "
+          "Content Protection",
+          __func__, A2DP_CodecIndexStr(codec_index));
+      continue;
+    }
+    return p_sink;
+  }
+  return nullptr;
+}
+
+BtaAvCoSep* BtaAvCo::FindPeerSource(BtaAvCoPeer* p_peer,
+                                    btav_a2dp_codec_index_t codec_index) {
+  if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
+    APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__,
+                       p_peer->addr.ToString().c_str());
+    return nullptr;
+  }
+
+  // Find the peer Source for the codec
+  for (size_t index = 0; index < p_peer->num_sup_sources; index++) {
+    BtaAvCoSep* p_source = &p_peer->sources[index];
+    btav_a2dp_codec_index_t peer_codec_index =
+        A2DP_SinkCodecIndex(p_source->codec_caps);
+    if (peer_codec_index != codec_index) {
+      continue;
+    }
+    if (!AudioSepHasContentProtection(p_source)) {
+      APPL_TRACE_DEBUG(
+          "%s: peer Source for codec %s does not support "
+          "Content Protection",
+          __func__, A2DP_CodecIndexStr(codec_index));
+      continue;
+    }
+    return p_source;
+  }
+  return nullptr;
+}
+
+const BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection(
+    const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) {
+  uint8_t new_codec_config[AVDT_CODEC_SIZE];
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  // Find the peer Sink for the codec
+  BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex());
+  if (p_sink == nullptr) {
+    APPL_TRACE_DEBUG("%s: peer Sink for codec %s not found", __func__,
+                     codec_config.name().c_str());
+    return nullptr;
+  }
+  if (!p_peer->GetCodecs()->setCodecConfig(
+          p_sink->codec_caps, true /* is_capability */, new_codec_config,
+          true /* select_current_codec */)) {
+    APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__,
+                     codec_config.name().c_str());
+    return nullptr;
+  }
+  p_peer->p_sink = p_sink;
+
+  SaveNewCodecConfig(p_peer, new_codec_config, p_sink->num_protect,
+                     p_sink->protect_info);
+
+  return p_sink;
+}
+
+const BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection(
+    const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) {
+  uint8_t new_codec_config[AVDT_CODEC_SIZE];
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  // Find the peer Source for the codec
+  BtaAvCoSep* p_source = FindPeerSource(p_peer, codec_config.codecIndex());
+  if (p_source == nullptr) {
+    APPL_TRACE_DEBUG("%s: peer Source for codec %s not found", __func__,
+                     codec_config.name().c_str());
+    return nullptr;
+  }
+  if (!p_peer->GetCodecs()->setSinkCodecConfig(
+          p_source->codec_caps, true /* is_capability */, new_codec_config,
+          true /* select_current_codec */)) {
+    APPL_TRACE_DEBUG("%s: cannot set sink codec %s", __func__,
+                     codec_config.name().c_str());
+    return nullptr;
+  }
+  p_peer->p_source = p_source;
+
+  SaveNewCodecConfig(p_peer, new_codec_config, p_source->num_protect,
+                     p_source->protect_info);
+
+  return p_source;
+}
+
+size_t BtaAvCo::UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+
+  size_t updated_codecs = 0;
+  for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) {
+    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
+                     iter->name().c_str());
+    if (UpdateSelectableSourceCodec(*iter, p_peer)) {
+      updated_codecs++;
+    }
+  }
+  return updated_codecs;
+}
+
+bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config,
+                                          BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+
+  // Find the peer Sink for the codec
+  const BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex());
+  if (p_sink == nullptr) {
+    // The peer Sink device does not support this codec
+    return false;
+  }
+  if (!p_peer->GetCodecs()->setPeerSinkCodecCapabilities(p_sink->codec_caps)) {
+    APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s",
+                       __func__, p_peer->addr.ToString().c_str(),
+                       A2DP_CodecName(p_sink->codec_caps));
+    return false;
+  }
+  return true;
+}
+
+size_t BtaAvCo::UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+
+  size_t updated_codecs = 0;
+  for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) {
+    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
+                     iter->name().c_str());
+    if (UpdateSelectableSinkCodec(*iter, p_peer)) {
+      updated_codecs++;
+    }
+  }
+  return updated_codecs;
+}
+
+bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config,
+                                        BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+
+  // Find the peer Source for the codec
+  const BtaAvCoSep* p_source =
+      FindPeerSource(p_peer, codec_config.codecIndex());
+  if (p_source == nullptr) {
+    // The peer Source device does not support this codec
+    return false;
+  }
+  if (!p_peer->GetCodecs()->setPeerSourceCodecCapabilities(
+          p_source->codec_caps)) {
+    APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s",
+                       __func__, p_peer->addr.ToString().c_str(),
+                       A2DP_CodecName(p_source->codec_caps));
+    return false;
+  }
+  return true;
+}
+
+void BtaAvCo::SaveNewCodecConfig(BtaAvCoPeer* p_peer,
+                                 const uint8_t* new_codec_config,
+                                 uint8_t num_protect,
+                                 const uint8_t* p_protect_info) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(new_codec_config).c_str());
+
+  std::lock_guard<std::recursive_mutex> lock(codec_lock_);
+
+  memcpy(codec_config_, new_codec_config, sizeof(codec_config_));
+  memcpy(p_peer->codec_config, new_codec_config, AVDT_CODEC_SIZE);
+
+  if (ContentProtectEnabled()) {
+    // Check if this Sink supports SCMS
+    bool cp_active = BtaAvCo::AudioProtectHasScmst(num_protect, p_protect_info);
+    p_peer->SetContentProtectActive(cp_active);
+  }
+}
+
+bool BtaAvCo::SetCodecOtaConfig(BtaAvCoPeer* p_peer,
+                                const uint8_t* p_ota_codec_config,
+                                uint8_t num_protect,
+                                const uint8_t* p_protect_info,
+                                bool* p_restart_output) {
+  uint8_t result_codec_config[AVDT_CODEC_SIZE];
+  bool restart_input = false;
+  bool restart_output = false;
+  bool config_updated = false;
+
+  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
+                   p_peer->addr.ToString().c_str());
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecInfoString(p_ota_codec_config).c_str());
+
+  *p_restart_output = false;
+
+  // Find the peer SEP codec to use
+  const BtaAvCoSep* p_sink =
+      FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_ota_codec_config));
+  if ((p_peer->num_sup_sinks > 0) && (p_sink == nullptr)) {
+    // There are no peer SEPs if we didn't do the discovery procedure yet.
+    // We have all the information we need from the peer, so we can
+    // proceed with the OTA codec configuration.
+    APPL_TRACE_ERROR("%s: peer %s : cannot find peer SEP to configure",
+                     __func__, p_peer->addr.ToString().c_str());
+    return false;
+  }
+
+  tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
+  GetPeerEncoderParameters(p_peer->addr, &peer_params);
+  if (!p_peer->GetCodecs()->setCodecOtaConfig(
+          p_ota_codec_config, &peer_params, result_codec_config, &restart_input,
+          &restart_output, &config_updated)) {
+    APPL_TRACE_ERROR("%s: peer %s : cannot set OTA config", __func__,
+                     p_peer->addr.ToString().c_str());
+    return false;
+  }
+
+  if (restart_output) {
+    APPL_TRACE_DEBUG("%s: restart output", __func__);
+    APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                     A2DP_CodecInfoString(result_codec_config).c_str());
+
+    *p_restart_output = true;
+    p_peer->p_sink = p_sink;
+    SaveNewCodecConfig(p_peer, result_codec_config, num_protect,
+                       p_protect_info);
+  }
+
+  if (restart_input || config_updated) {
+    // NOTE: Currently, the input is restarted by sending an upcall
+    // and informing the Media Framework about the change.
+    ReportSourceCodecState(p_peer);
+  }
+
+  return true;
 }
 
 void bta_av_co_init(
     const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  /* Reset the control block */
-  bta_av_co_cb.reset();
-
-#if (BTA_AV_CO_CP_SCMS_T == TRUE)
-  bta_av_co_cp_set_flag(AVDT_CP_SCMS_COPY_NEVER);
-#else
-  bta_av_co_cp_set_flag(AVDT_CP_SCMS_COPY_FREE);
-#endif
-
-  /* Reset the current config */
-  /* Protect access to bta_av_co_cb.codec_config */
-  mutex_global_lock();
-  bta_av_co_cb.codecs = new A2dpCodecs(codec_priorities);
-  bta_av_co_cb.codecs->init();
-  A2DP_InitDefaultCodec(bta_av_co_cb.codec_config);
-  mutex_global_unlock();
-
-  // NOTE: Unconditionally dispatch the event to make sure a callback with
-  // the most recent codec info is generated.
-  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+  bta_av_co_cb.Init(codec_priorities);
 }
+
+A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) {
+  return bta_av_co_cb.GetActivePeerCurrentCodec();
+}
+
+A2dpCodecConfig* bta_av_get_a2dp_peer_current_codec(
+    const RawAddress& peer_address) {
+  return bta_av_co_cb.GetPeerCurrentCodec(peer_address);
+}
+
+bool bta_av_co_audio_init(btav_a2dp_codec_index_t codec_index,
+                          AvdtpSepConfig* p_cfg) {
+  return A2DP_InitCodecConfig(codec_index, p_cfg);
+}
+
+void bta_av_co_audio_disc_res(tBTA_AV_HNDL bta_av_handle,
+                              const RawAddress& peer_address, uint8_t num_seps,
+                              uint8_t num_sinks, uint8_t num_sources,
+                              uint16_t uuid_local) {
+  bta_av_co_cb.ProcessDiscoveryResult(bta_av_handle, peer_address, num_seps,
+                                      num_sinks, num_sources, uuid_local);
+}
+
+tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL bta_av_handle,
+                                       const RawAddress& peer_address,
+                                       uint8_t* p_codec_info,
+                                       uint8_t* p_sep_info_idx, uint8_t seid,
+                                       uint8_t* p_num_protect,
+                                       uint8_t* p_protect_info) {
+  uint16_t peer_uuid = bta_av_co_cb.FindPeerUuid(bta_av_handle);
+
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle=0x%x peer_uuid=0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_av_handle, peer_uuid);
+
+  switch (peer_uuid) {
+    case UUID_SERVCLASS_AUDIO_SOURCE:
+      return bta_av_co_cb.ProcessSinkGetConfig(
+          bta_av_handle, peer_address, p_codec_info, p_sep_info_idx, seid,
+          p_num_protect, p_protect_info);
+    case UUID_SERVCLASS_AUDIO_SINK:
+      return bta_av_co_cb.ProcessSourceGetConfig(
+          bta_av_handle, peer_address, p_codec_info, p_sep_info_idx, seid,
+          p_num_protect, p_protect_info);
+    default:
+      break;
+  }
+  APPL_TRACE_ERROR(
+      "%s: peer %s : Invalid peer UUID: 0x%x for bta_av_handle 0x%x",
+      peer_address.ToString().c_str(), peer_uuid, bta_av_handle);
+  return A2DP_FAIL;
+}
+
+void bta_av_co_audio_setconfig(tBTA_AV_HNDL bta_av_handle,
+                               const RawAddress& peer_address,
+                               const uint8_t* p_codec_info, uint8_t seid,
+                               uint8_t num_protect,
+                               const uint8_t* p_protect_info,
+                               uint8_t t_local_sep, uint8_t avdt_handle) {
+  bta_av_co_cb.ProcessSetConfig(bta_av_handle, peer_address, p_codec_info, seid,
+                                num_protect, p_protect_info, t_local_sep,
+                                avdt_handle);
+}
+
+void bta_av_co_audio_open(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address, uint16_t mtu) {
+  bta_av_co_cb.ProcessOpen(bta_av_handle, peer_address, mtu);
+}
+
+void bta_av_co_audio_close(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address) {
+  bta_av_co_cb.ProcessClose(bta_av_handle, peer_address);
+}
+
+void bta_av_co_audio_start(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address,
+                           const uint8_t* p_codec_info, bool* p_no_rtp_header) {
+  bta_av_co_cb.ProcessStart(bta_av_handle, peer_address, p_codec_info,
+                            p_no_rtp_header);
+}
+
+void bta_av_co_audio_stop(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address) {
+  bta_av_co_cb.ProcessStop(bta_av_handle, peer_address);
+}
+
+BT_HDR* bta_av_co_audio_source_data_path(const uint8_t* p_codec_info,
+                                         uint32_t* p_timestamp) {
+  return bta_av_co_cb.GetNextSourceDataPacket(p_codec_info, p_timestamp);
+}
+
+void bta_av_co_audio_drop(tBTA_AV_HNDL bta_av_handle,
+                          const RawAddress& peer_address) {
+  bta_av_co_cb.DataPacketWasDropped(bta_av_handle, peer_address);
+}
+
+void bta_av_co_audio_delay(tBTA_AV_HNDL bta_av_handle,
+                           const RawAddress& peer_address, uint16_t delay) {
+  bta_av_co_cb.ProcessAudioDelay(bta_av_handle, peer_address, delay);
+}
+
+void bta_av_co_audio_update_mtu(tBTA_AV_HNDL bta_av_handle,
+                                const RawAddress& peer_address, uint16_t mtu) {
+  bta_av_co_cb.UpdateMtu(bta_av_handle, peer_address, mtu);
+}
+
+bool bta_av_co_set_active_peer(const RawAddress& peer_address) {
+  return bta_av_co_cb.SetActivePeer(peer_address);
+}
+
+void bta_av_co_get_peer_params(const RawAddress& peer_address,
+                               tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) {
+  bta_av_co_cb.GetPeerEncoderParameters(peer_address, p_peer_params);
+}
+
+const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
+  return bta_av_co_cb.GetSourceEncoderInterface();
+}
+
+const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) {
+  return bta_av_co_cb.GetSinkDecoderInterface();
+}
+
+bool bta_av_co_set_codec_user_config(
+    const RawAddress& peer_address,
+    const btav_a2dp_codec_config_t& codec_user_config) {
+  return bta_av_co_cb.SetCodecUserConfig(peer_address, codec_user_config);
+}
+
+bool bta_av_co_set_codec_audio_config(
+    const btav_a2dp_codec_config_t& codec_audio_config) {
+  return bta_av_co_cb.SetCodecAudioConfig(codec_audio_config);
+}
+
+bool bta_av_co_content_protect_is_active(const RawAddress& peer_address) {
+  BtaAvCoPeer* p_peer = bta_av_co_cb.FindPeer(peer_address);
+  CHECK(p_peer != nullptr);
+  return p_peer->ContentProtectActive();
+}
+
+void btif_a2dp_codec_debug_dump(int fd) { bta_av_co_cb.DebugDump(fd); }
diff --git a/btif/co/bta_dm_co.cc b/btif/co/bta_dm_co.cc
index f6c7c1c..dfd512b 100644
--- a/btif/co/bta_dm_co.cc
+++ b/btif/co/bta_dm_co.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -165,99 +165,6 @@
   bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r);
 }
 
-// REMOVE FOR BLUEDROID ?
-
-#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)
-
-/*******************************************************************************
- *
- * Function         btui_sco_codec_callback
- *
- * Description      Callback for btui codec.
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-static void btui_sco_codec_callback(uint16_t event, uint16_t sco_handle) {
-  bta_dm_sco_ci_data_ready(event, sco_handle);
-}
-
-/*******************************************************************************
- *
- * Function         bta_dm_sco_co_open
- *
- * Description      This function is executed when a SCO connection is open.
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_sco_co_open(uint16_t handle, uint8_t pkt_size, uint16_t event) {
-  tBTUI_SCO_CODEC_CFG cfg;
-
-  if (btui_cb.sco_hci) {
-    BTIF_TRACE_DEBUG("bta_dm_sco_co_open handle:%d pkt_size:%d", handle,
-                     pkt_size);
-    cfg.p_cback = btui_sco_codec_callback;
-    cfg.pkt_size = pkt_size;
-    cfg.cb_event = event;
-    /* open and start the codec */
-    btui_sco_codec_open(&cfg);
-    btui_sco_codec_start(handle);
-  }
-}
-
-/*******************************************************************************
- *
- * Function         bta_dm_sco_co_close
- *
- * Description      This function is called when a SCO connection is closed
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_sco_co_close(void) {
-  if (btui_cb.sco_hci) {
-    BTIF_TRACE_DEBUG("bta_dm_sco_co_close close codec");
-    /* close sco codec */
-    btui_sco_codec_close();
-
-    btui_cb.sco_hci = false;
-  }
-}
-
-/*******************************************************************************
- *
- * Function         bta_dm_sco_co_in_data
- *
- * Description      This function is called to send incoming SCO data to
- *                  application.
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_sco_co_in_data(BT_HDR* p_buf) {
-  if (btui_cfg.sco_use_mic)
-    btui_sco_codec_inqdata(p_buf);
-  else
-    osi_free(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function         bta_dm_sco_co_out_data
- *
- * Description      This function is called to send SCO data over HCI.
- *
- * Returns          void
- *
- ******************************************************************************/
-void bta_dm_sco_co_out_data(BT_HDR** p_buf) { btui_sco_codec_readbuf(p_buf); }
-
-#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)*/
-
 /*******************************************************************************
  *
  * Function         bta_dm_co_le_io_key_req
diff --git a/btif/co/bta_gatts_co.cc b/btif/co/bta_gatts_co.cc
index 0466291..4fc308e 100644
--- a/btif/co/bta_gatts_co.cc
+++ b/btif/co/bta_gatts_co.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
 typedef struct {
   bool enable;
   uint8_t num_clients;
-  tBTA_GATTS_SRV_CHG srv_chg[BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE];
+  tGATTS_SRV_CHG srv_chg[BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE];
 } __attribute__((packed)) btif_gatts_srv_chg_cb_t;
 
 /*****************************************************************************
@@ -121,9 +121,9 @@
  *                  false - if the request can not be processed
  *
  ******************************************************************************/
-bool bta_gatts_co_srv_chg(UNUSED_ATTR tBTA_GATTS_SRV_CHG_CMD cmd,
-                          UNUSED_ATTR tBTA_GATTS_SRV_CHG_REQ* p_req,
-                          UNUSED_ATTR tBTA_GATTS_SRV_CHG_RSP* p_rsp) {
+bool bta_gatts_co_srv_chg(UNUSED_ATTR tGATTS_SRV_CHG_CMD cmd,
+                          UNUSED_ATTR tGATTS_SRV_CHG_REQ* p_req,
+                          UNUSED_ATTR tGATTS_SRV_CHG_RSP* p_rsp) {
   return false;
 }
 
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index f6bc7cf..2f507f9 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -473,12 +473,9 @@
   // Create and send hid descriptor to kernel
   memset(&ev, 0, sizeof(ev));
   ev.type = UHID_CREATE;
-  strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
-  snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq),
-           "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", p_dev->bd_addr.address[5],
-           p_dev->bd_addr.address[4], p_dev->bd_addr.address[3],
-           p_dev->bd_addr.address[2], p_dev->bd_addr.address[1],
-           p_dev->bd_addr.address[0]);
+  strlcpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name));
+  snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq), "%s",
+           p_dev->bd_addr.ToString().c_str());
   ev.u.create.rd_size = dscp_len;
   ev.u.create.rd_data = p_dscp;
   ev.u.create.bus = BUS_BLUETOOTH;
@@ -565,7 +562,7 @@
   const char* bdstr = addrstr.c_str();
 
   size_t len = btif_config_get_bin_length(bdstr, "HidReport");
-  if (!p_num_rpt && len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL;
+  if (!p_num_rpt || len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL;
 
   if (len > sizeof(sReportCache)) len = sizeof(sReportCache);
   btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
diff --git a/btif/co/bta_hl_co.cc b/btif/co/bta_hl_co.cc
index a4ddbb6..c818351 100644
--- a/btif/co/bta_hl_co.cc
+++ b/btif/co/bta_hl_co.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/co/bta_pan_co.cc b/btif/co/bta_pan_co.cc
index 1868c78..a799d93 100644
--- a/btif/co/bta_pan_co.cc
+++ b/btif/co/bta_pan_co.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_a2dp.h b/btif/include/btif_a2dp.h
index 26f370a..7b7b2ca 100644
--- a/btif/include/btif_a2dp.h
+++ b/btif/include/btif_a2dp.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,11 +29,13 @@
 
 // Process 'start' request from the BTIF state machine to prepare for A2DP
 // streaming.
+// |peer_addr| is the peer address.
 // |p_av_start| is the data associated with the request - see |tBTA_AV_START|.
 // |pending_start| should be set to true if the BTIF state machine is in
 // 'pending start' state.
 // Returns true if an ACK for the local command was sent, otherwise false.
-bool btif_a2dp_on_started(tBTA_AV_START* p_av_start, bool pending_start);
+bool btif_a2dp_on_started(const RawAddress& peer_addr,
+                          tBTA_AV_START* p_av_start, bool pending_start);
 
 // Process 'stop' request from the BTIF state machine to stop A2DP streaming.
 // |p_av_suspend| is the data associated with the request - see
@@ -48,10 +50,12 @@
 
 // Process 'offload start' request from the BTIF state machine to start
 // offloading of the A2DP streaming.
+// |peer_addr| is the peer address.
 // |status| is the processing status of the request prior to this call.
 // The value can be |BTA_AV_SUCCESS| if the processing has been successful
 // so far, or |BTA_AV_FAIL*| if the request has already failed.
-void btif_a2dp_on_offload_started(tBTA_AV_STATUS status);
+void btif_a2dp_on_offload_started(const RawAddress& peer_addr,
+                                  tBTA_AV_STATUS status);
 
 // Dump debug-related information for the A2DP module.
 // |fd| is the file descriptor to use for writing the ASCII formatted
diff --git a/btif/include/btif_a2dp_audio_interface.h b/btif/include/btif_a2dp_audio_interface.h
new file mode 100644
index 0000000..d9babaa
--- /dev/null
+++ b/btif/include/btif_a2dp_audio_interface.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_AUDIO_INTERFACE_H
+#define BTIF_A2DP_AUDIO_INTERFACE_H
+
+#include "bta_av_api.h"
+
+/*Default LDAC bitrate */
+#define DEFAULT_LDAC_BITRATE_48KHZ 660000
+#define DEFAULT_LDAC_BITRATE_441KHZ 606000
+
+void btif_a2dp_audio_on_started(tBTA_AV_STATUS status);
+void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status);
+void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status);
+void btif_a2dp_audio_interface_start_session(void);
+void btif_a2dp_audio_interface_end_session(void);
+
+#endif /* BTIF_A2DP_AUDIO_INTERFACE_H */
diff --git a/btif/include/btif_a2dp_control.h b/btif/include/btif_a2dp_control.h
index fb935f5..37a0f1b 100644
--- a/btif/include/btif_a2dp_control.h
+++ b/btif/include/btif_a2dp_control.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,4 +34,17 @@
 // |status| is the acknowledement status - see |tA2DP_CTRL_ACK|.
 void btif_a2dp_command_ack(tA2DP_CTRL_ACK status);
 
+// Increment the total number audio data bytes that have been encoded since
+// last encoding attempt.
+// |bytes_read| is the number of bytes to increment by.
+void btif_a2dp_control_log_bytes_read(uint32_t bytes_read);
+
+// Set the audio delay reported to the audio HAL in uints of 1/10ms.
+// |delay| is the audio delay to set.
+void btif_a2dp_control_set_audio_delay(uint16_t delay);
+
+// Reset the remote audio device's delay value and reset the counter that keeps
+// track of the number of audio bytes sent
+void btif_a2dp_control_reset_audio_delay(void);
+
 #endif /* BTIF_A2DP_CONTROL_H */
diff --git a/btif/include/btif_a2dp_sink.h b/btif/include/btif_a2dp_sink.h
index 5057a39..25e65f4 100644
--- a/btif/include/btif_a2dp_sink.h
+++ b/btif/include/btif_a2dp_sink.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -38,16 +38,47 @@
   BTIF_A2DP_SINK_FOCUS_GRANTED = 1
 } btif_a2dp_sink_focus_state_t;
 
-// Initialize and startup the A2DP Sink module.
+// Initialize the A2DP Sink module.
 // This function should be called by the BTIF state machine prior to using the
 // module.
+bool btif_a2dp_sink_init(void);
+
+// Startup the A2DP Sink module.
+// This function should be called by the BTIF state machine after
+// btif_a2dp_sink_init() to prepare for receiving and processing audio
+// streaming.
 bool btif_a2dp_sink_startup(void);
 
-// Shutdown and cleanup the A2DP Sink module.
-// This function should be called by the BTIF state machine during
-// graceful shutdown and cleanup.
+// Start the A2DP Sink session.
+// This function should be called by the BTIF state machine after
+// 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|.
+bool btif_a2dp_sink_end_session(const RawAddress& peer_address);
+
+// Shutdown the A2DP Sink module.
+// This function should be called by the BTIF state machine before
+// btif_a2dp_sink_cleanup() to shutdown the processing of the audio streaming.
 void btif_a2dp_sink_shutdown(void);
 
+// Cleanup the A2DP Sink module.
+// This function should be called by the BTIF state machine during graceful
+// cleanup.
+void btif_a2dp_sink_cleanup(void);
+
 // Get the audio sample rate for the A2DP Sink module.
 tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void);
 
@@ -88,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 2f1763d..bb96e1a 100644
--- a/btif/include/btif_a2dp_source.h
+++ b/btif/include/btif_a2dp_source.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,16 +24,45 @@
 
 #include "bta_av_api.h"
 
-// Initialize and startup the A2DP Source module.
+// Initialize the A2DP Source module.
 // This function should be called by the BTIF state machine prior to using the
 // module.
+bool btif_a2dp_source_init(void);
+
+// Startup the A2DP Source module.
+// This function should be called by the BTIF state machine after
+// btif_a2dp_source_init() to prepare to start streaming.
 bool btif_a2dp_source_startup(void);
 
-// Shutdown and cleanup the A2DP Source module.
-// This function should be called by the BTIF state machine during
-// graceful shutdown and cleanup.
+// Start the A2DP Source session.
+// This function should be called by the BTIF state machine after
+// 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|.
+bool btif_a2dp_source_end_session(const RawAddress& peer_address);
+
+// Shutdown the A2DP Source module.
+// This function should be called by the BTIF state machine to stop streaming.
 void btif_a2dp_source_shutdown(void);
 
+// Cleanup the A2DP Source module.
+// This function should be called by the BTIF state machine during graceful
+// cleanup.
+void btif_a2dp_source_cleanup(void);
+
 // Check whether the A2DP Source media task is running.
 // Returns true if the A2DP Source media task is running, otherwise false.
 bool btif_a2dp_source_media_task_is_running(void);
@@ -45,10 +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.
-// This function should be called prior to starting A2DP streaming.
-void btif_a2dp_source_setup_codec(void);
-
 // Process a request to start the A2DP audio encoding task.
 void btif_a2dp_source_start_audio_req(void);
 
@@ -57,8 +82,10 @@
 
 // Process a request to update the A2DP audio encoder with user preferred
 // codec configuration.
+// The peer address is |peer_addr|.
 // |codec_user_config| contains the preferred codec user configuration.
 void btif_a2dp_source_encoder_user_config_update_req(
+    const RawAddress& peer_addr,
     const btav_a2dp_codec_config_t& codec_user_config);
 
 // Process a request to update the A2DP audio encoding with new audio
@@ -95,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_api.h b/btif/include/btif_api.h
index 739eabe..519fc9c 100644
--- a/btif/include/btif_api.h
+++ b/btif/include/btif_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -184,8 +184,8 @@
  * Returns          bt_status_t
  *
  ******************************************************************************/
-bt_status_t btif_get_remote_service_record(RawAddress* remote_addr,
-                                           bt_uuid_t* uuid);
+bt_status_t btif_get_remote_service_record(const RawAddress& remote_addr,
+                                           const bluetooth::Uuid& uuid);
 
 /*******************************************************************************
  *  BTIF DM API
@@ -329,8 +329,8 @@
  * Returns          bt_status_t
  *
  ******************************************************************************/
-bt_status_t btif_dm_get_remote_service_record(RawAddress* remote_addr,
-                                              bt_uuid_t* uuid);
+bt_status_t btif_dm_get_remote_service_record(const RawAddress& remote_addr,
+                                              const bluetooth::Uuid& uuid);
 
 /*******************************************************************************
  *
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
index 3ba2d7d..486c2af 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,177 +16,195 @@
  *
  ******************************************************************************/
 
-/*******************************************************************************
- *
- *  Filename:      btif_av.h
- *
- *  Description:   Main API header file for all BTIF AV functions accessed
- *                 from internal stack.
- *
- ******************************************************************************/
+/**
+ * BTIF AV API functions accessed internally.
+ */
 
 #ifndef BTIF_AV_H
 #define BTIF_AV_H
 
 #include "bta_av_api.h"
 #include "btif_common.h"
-#include "btif_sm.h"
 
-/*******************************************************************************
- *  Type definitions for callback functions
- ******************************************************************************/
+/**
+ * When the local device is A2DP source, get the address of the active peer.
+ */
+RawAddress btif_av_source_active_peer(void);
 
-typedef enum {
-  /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */
-  BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT,
-  BTIF_AV_DISCONNECT_REQ_EVT,
-  BTIF_AV_START_STREAM_REQ_EVT,
-  BTIF_AV_STOP_STREAM_REQ_EVT,
-  BTIF_AV_SUSPEND_STREAM_REQ_EVT,
-  BTIF_AV_SOURCE_CONFIG_REQ_EVT,
-  BTIF_AV_SOURCE_CONFIG_UPDATED_EVT,
-  BTIF_AV_SINK_CONFIG_REQ_EVT,
-  BTIF_AV_OFFLOAD_START_REQ_EVT,
-  BTIF_AV_CLEANUP_REQ_EVT,
-} btif_av_sm_event_t;
+/**
+ * When the local device is A2DP sink, get the address of the active peer.
+ */
+RawAddress btif_av_sink_active_peer(void);
 
-/*******************************************************************************
- *  BTIF AV API
- ******************************************************************************/
-
-/*******************************************************************************
- *
- * Function         btif_av_get_addr
- *
- * Description      Fetches current AV BD address
- *
- * Returns          BD address
- *
- ******************************************************************************/
-
-RawAddress btif_av_get_addr(void);
-
-/*******************************************************************************
- * Function         btif_av_is_sink_enabled
- *
- * Description      Checks if A2DP Sink is enabled or not
- *
- * Returns          true if A2DP Sink is enabled, false otherwise
- *
- ******************************************************************************/
-
+/**
+ * Check whether A2DP Sink is enabled.
+ */
 bool btif_av_is_sink_enabled(void);
 
-/*******************************************************************************
- *
- * Function         btif_av_stream_ready
- *
- * Description      Checks whether AV is ready for starting a stream
- *
- * Returns          None
- *
- ******************************************************************************/
+/**
+ * Start streaming.
+ */
+void btif_av_stream_start(void);
 
+/**
+ * Stop streaming.
+ *
+ * @param peer_address the peer address or RawAddress::kEmpty to stop all peers
+ */
+void btif_av_stream_stop(const RawAddress& peer_address);
+
+/**
+ * Suspend streaming.
+ */
+void btif_av_stream_suspend(void);
+
+/**
+ * Start offload streaming.
+ */
+void btif_av_stream_start_offload(void);
+
+/**
+ * Check whether ready to start the A2DP stream.
+ */
 bool btif_av_stream_ready(void);
 
-/*******************************************************************************
- *
- * Function         btif_av_stream_started_ready
- *
- * Description      Checks whether AV ready for media start in streaming state
- *
- * Returns          None
- *
- ******************************************************************************/
-
+/**
+ * Check whether the A2DP stream is in started state and ready
+ * for media start.
+ */
 bool btif_av_stream_started_ready(void);
 
-/*******************************************************************************
- *
- * Function         btif_dispatch_sm_event
- *
- * Description      Send event to AV statemachine
- *
- * Returns          None
- *
- ******************************************************************************/
-
-/* used to pass events to AV statemachine from other tasks */
-void btif_dispatch_sm_event(btif_av_sm_event_t event, void* p_data, int len);
-
-/*******************************************************************************
- *
- * Function         btif_av_init
- *
- * Description      Initializes btif AV if not already done
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-
-bt_status_t btif_av_init(int service_id);
-
-/*******************************************************************************
- *
- * Function         btif_av_is_connected
- *
- * Description      Checks if av has a connected sink
- *
- * Returns          bool
- *
- ******************************************************************************/
-
+/**
+ * Check whether there is a connected peer (either Source or Sink)
+ */
 bool btif_av_is_connected(void);
 
-/*******************************************************************************
+/**
+ * Get the Stream Endpoint Type of the Active peer.
  *
- * Function         btif_av_get_peer_sep
- *
- * Description      Get the stream endpoint type.
- *
- * Returns          The stream endpoint type: either AVDT_TSEP_SRC or
- *                  AVDT_TSEP_SNK.
- *
- ******************************************************************************/
-
+ * @return the stream endpoint type: either AVDT_TSEP_SRC or AVDT_TSEP_SNK
+ */
 uint8_t btif_av_get_peer_sep(void);
 
-/*******************************************************************************
- *
- * Function         btif_av_is_peer_edr
- *
- * Description      Check if the connected a2dp device supports
- *                  EDR or not. Only when connected this function
- *                  will accurately provide a true capability of
- *                  remote peer. If not connected it will always be false.
- *
- * Returns          true if remote device is capable of EDR
- *
- ******************************************************************************/
-
-bool btif_av_is_peer_edr(void);
-
-/******************************************************************************
- *
- * Function         btif_av_clear_remote_suspend_flag
- *
- * Description      Clears remote suspended flag
- *
- * Returns          Void
- ******************************************************************************/
+/**
+ * Clear the remote suspended flag for the active peer.
+ */
 void btif_av_clear_remote_suspend_flag(void);
 
-/*******************************************************************************
+/**
+ * Process AVRCP Open event.
  *
- * Function         btif_av_peer_supports_3mbps
- *
- * Description      Check if the connected A2DP device supports
- *                  3 Mbps EDR. This function will only work while connected.
- *                  If not connected it will always return false.
- *
- * Returns          true if remote device is EDR and supports 3 Mbps
- *
- ******************************************************************************/
-bool btif_av_peer_supports_3mbps(void);
+ * @param peer_address the peer address
+ */
+void btif_av_avrcp_event_open(const RawAddress& peer_address);
 
+/**
+ * Process AVRCP Close event.
+ *
+ * @param peer_address the peer address
+ */
+void btif_av_avrcp_event_close(const RawAddress& peer_address);
+
+/**
+ * Process AVRCP Remote Play event.
+ *
+ * @param peer_address the peer address
+ */
+void btif_av_avrcp_event_remote_play(const RawAddress& peer_address);
+
+/**
+ * Check whether the connected A2DP peer supports EDR.
+ *
+ * The value can be provided only if the remote peer is connected.
+ * Otherwise, the answer will be always false.
+ *
+ * @param peer_address the peer address
+ * @return true if the remote peer is capable of EDR
+ */
+bool btif_av_is_peer_edr(const RawAddress& peer_address);
+
+/**
+ * Check whether the connected A2DP peer supports 3 Mbps EDR.
+ *
+ * The value can be provided only if the remote peer is connected.
+ * Otherwise, the answer will be always false.
+ *
+ * @param peer_address the peer address
+ * @return true if the remote peer is capable of EDR and supports 3 Mbps
+ */
+bool btif_av_peer_supports_3mbps(const RawAddress& peer_address);
+
+/**
+ * Report A2DP Source Codec State for a peer.
+ *
+ * @param peer_address the address of the peer to report
+ * @param codec_config the codec config to report
+ * @param codecs_local_capabilities the codecs local capabilities to report
+ * @param codecs_selectable_capabilities the codecs selectable capabilities
+ * to report
+ */
+void btif_av_report_source_codec_state(
+    const RawAddress& peer_address,
+    const btav_a2dp_codec_config_t& codec_config,
+    const std::vector<btav_a2dp_codec_config_t>& codecs_local_capabilities,
+    const std::vector<btav_a2dp_codec_config_t>&
+        codecs_selectable_capabilities);
+
+/**
+ * Initialize / shut down the A2DP Source service.
+ *
+ * @param enable true to enable the A2DP Source service, false to disable it
+ * @return BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ */
+bt_status_t btif_av_source_execute_service(bool enable);
+
+/**
+ * Initialize / shut down the A2DP Sink service.
+ *
+ * @param enable true to enable the A2DP Sink service, false to disable it
+ * @return BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ */
+bt_status_t btif_av_sink_execute_service(bool enable);
+
+/**
+ * Peer ACL disconnected.
+ *
+ * @param peer_address the disconnected peer address
+ */
+void btif_av_acl_disconnected(const RawAddress& peer_address);
+
+/**
+ * Dump debug-related information for the BTIF AV module.
+ *
+ * @param fd the file descriptor to use for writing the ASCII formatted
+ * information
+ */
+void btif_debug_av_dump(int fd);
+
+/**
+ * Set the audio delay for the stream.
+ *
+ * @param delay the delay to set in units of 1/10ms
+ */
+void btif_av_set_audio_delay(uint16_t delay);
+
+/**
+ * Reset the audio delay and count of audio bytes sent to zero.
+ */
+void btif_av_reset_audio_delay(void);
+
+/**
+ * Called to disconnect peer device when
+ *  remote initiatied offload start failed
+ *
+ * @param peer_address to disconnect
+ *
+ */
+void btif_av_src_disconnect_sink(const RawAddress& peer_address);
+
+/**
+ *  check A2DP offload support enabled
+ *  @param  none
+ */
+bool btif_av_is_a2dp_offload_enabled(void);
 #endif /* BTIF_AV_H */
diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h
index 8c1266f..df7454f 100644
--- a/btif/include/btif_av_co.h
+++ b/btif/include/btif_av_co.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,14 +22,16 @@
 #include "btif/include/btif_a2dp_source.h"
 #include "stack/include/a2dp_codec_api.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+// Sets the active peer to |peer_addr|.
+// Returns true on success, otherwise false.
+bool bta_av_co_set_active_peer(const RawAddress& peer_addr);
 
 // Gets the A2DP peer parameters that are used to initialize the encoder.
+// The peer address is |peer_addr|.
 // The parameters are stored in |p_peer_params|.
 // |p_peer_params| cannot be null.
-void bta_av_co_get_peer_params(tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params);
+void bta_av_co_get_peer_params(const RawAddress& peer_addr,
+                               tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params);
 
 // Gets the current A2DP encoder interface that can be used to encode and
 // prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
@@ -37,10 +39,18 @@
 // otherwise NULL.
 const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);
 
+// Gets the current A2DP decoder interface that can be used to decode received
+// A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// Returns the A2DP decoder interface if the current codec is setup, otherwise
+// NULL.
+const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void);
+
 // Sets the user preferred codec configuration.
+// The peer address is |peer_addr|.
 // |codec_user_config| contains the preferred codec configuration.
 // Returns true on success, otherwise false.
 bool bta_av_co_set_codec_user_config(
+    const RawAddress& peer_addr,
     const btav_a2dp_codec_config_t& codec_user_config);
 
 // Sets the Audio HAL selected audio feeding parameters.
@@ -55,17 +65,20 @@
 void bta_av_co_init(
     const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
 
-// Gets the initialized A2DP codecs.
-// Returns a pointer to the |A2dpCodecs| object with the initialized A2DP
-// codecs, or nullptr if no codecs are initialized.
-A2dpCodecs* bta_av_get_a2dp_codecs(void);
-
-// Gets the current A2DP codec.
-// Returns a pointer to the current |A2dpCodec| if valid, otherwise nullptr.
+// Gets the current A2DP codec for the active peer.
+// Returns a pointer to the current |A2dpCodecConfig| if valid, otherwise
+// nullptr.
 A2dpCodecConfig* bta_av_get_a2dp_current_codec(void);
 
-#ifdef __cplusplus
-}
-#endif
+// Gets the current A2DP codec for a peer identified by |peer_address|.
+// Returns a pointer to the current |A2dpCodecConfig| if valid, otherwise
+// nullptr.
+A2dpCodecConfig* bta_av_get_a2dp_peer_current_codec(
+    const RawAddress& peer_address);
+
+// Dump A2DP codec debug-related information for the A2DP module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_a2dp_codec_debug_dump(int fd);
 
 #endif  // BTIF_AV_CO_H
diff --git a/btif/include/btif_avrcp_audio_track.h b/btif/include/btif_avrcp_audio_track.h
index 6986e43..720fe60 100644
--- a/btif/include/btif_avrcp_audio_track.h
+++ b/btif/include/btif_avrcp_audio_track.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright 2015 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.
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
index ae726e7..af0beb0 100644
--- a/btif/include/btif_common.h
+++ b/btif/include/btif_common.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 
 #include <base/bind.h>
+#include <base/message_loop/message_loop.h>
 #include <base/tracked_objects.h>
 #include <hardware/bluetooth.h>
 
@@ -77,14 +78,14 @@
 
 extern bt_callbacks_t* bt_hal_cbacks;
 
-#define HAL_CBACK(P_CB, P_CBACK, ...)                \
-  do {                                               \
-    if ((P_CB) && (P_CB)->P_CBACK) {                 \
-      BTIF_TRACE_API("HAL %s->%s", #P_CB, #P_CBACK); \
-      (P_CB)->P_CBACK(__VA_ARGS__);                  \
-    } else {                                         \
-      ASSERTC(0, "Callback is NULL", 0);             \
-    }                                                \
+#define HAL_CBACK(P_CB, P_CBACK, ...)                              \
+  do {                                                             \
+    if ((P_CB) && (P_CB)->P_CBACK) {                               \
+      BTIF_TRACE_API("%s: HAL %s->%s", __func__, #P_CB, #P_CBACK); \
+      (P_CB)->P_CBACK(__VA_ARGS__);                                \
+    } else {                                                       \
+      ASSERTC(0, "Callback is NULL", 0);                           \
+    }                                                              \
   } while (0)
 
 /**
@@ -176,6 +177,8 @@
 extern bt_status_t do_in_jni_thread(const base::Closure& task);
 extern bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
                                     const base::Closure& task);
+extern bool is_on_jni_thread();
+extern base::MessageLoop* get_jni_message_loop();
 /**
  * This template wraps callback into callback that will be executed on jni
  * thread
diff --git a/btif/include/btif_config.h b/btif/include/btif_config.h
index 7031802..028afa7 100644
--- a/btif/include/btif_config.h
+++ b/btif/include/btif_config.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,31 +23,36 @@
 
 #include "bt_types.h"
 
+#include <list>
+#include <string>
+#include "osi/include/config.h"
+
 static const char BTIF_CONFIG_MODULE[] = "btif_config_module";
 
-typedef struct btif_config_section_iter_t btif_config_section_iter_t;
-
 bool btif_config_has_section(const char* section);
-bool btif_config_exist(const char* section, const char* key);
-bool btif_config_get_int(const char* section, const char* key, int* value);
-bool btif_config_set_int(const char* section, const char* key, int value);
-bool btif_config_get_str(const char* section, const char* key, char* value,
-                         int* size_bytes);
-bool btif_config_set_str(const char* section, const char* key,
-                         const char* value);
-bool btif_config_get_bin(const char* section, const char* key, uint8_t* value,
-                         size_t* length);
-bool btif_config_set_bin(const char* section, const char* key,
+bool btif_config_exist(const std::string& section, const std::string& key);
+bool btif_config_get_int(const std::string& section, const std::string& key,
+                         int* value);
+bool btif_config_set_int(const std::string& section, const std::string& key,
+                         int value);
+bool btif_config_get_uint64(const std::string& section, const std::string& key,
+                            uint64_t* value);
+bool btif_config_set_uint64(const std::string& section, const std::string& key,
+                            uint64_t value);
+bool btif_config_get_str(const std::string& section, const std::string& key,
+                         char* value, int* size_bytes);
+bool btif_config_set_str(const std::string& section, const std::string& key,
+                         const std::string& value);
+bool btif_config_get_bin(const std::string& section, const std::string& key,
+                         uint8_t* value, size_t* length);
+bool btif_config_set_bin(const std::string& section, const std::string& key,
                          const uint8_t* value, size_t length);
-bool btif_config_remove(const char* section, const char* key);
+bool btif_config_remove(const std::string& section, const std::string& key);
 
-size_t btif_config_get_bin_length(const char* section, const char* key);
+size_t btif_config_get_bin_length(const std::string& section,
+                                  const std::string& key);
 
-const btif_config_section_iter_t* btif_config_section_begin(void);
-const btif_config_section_iter_t* btif_config_section_end(void);
-const btif_config_section_iter_t* btif_config_section_next(
-    const btif_config_section_iter_t* section);
-const char* btif_config_section_name(const btif_config_section_iter_t* section);
+std::list<section_t>& btif_config_sections();
 
 void btif_config_save(void);
 void btif_config_flush(void);
diff --git a/btif/include/btif_config_transcode.h b/btif/include/btif_config_transcode.h
index 66aac8a..e61b943 100644
--- a/btif/include/btif_config_transcode.h
+++ b/btif/include/btif_config_transcode.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,6 +18,6 @@
 
 #pragma once
 
-typedef struct config_t config_t;
+#include "osi/include/config.h"
 
-config_t* btif_config_transcode(const char* xml_filename);
+std::unique_ptr<config_t> btif_config_transcode(const char* xml_filename);
diff --git a/btif/include/btif_debug.h b/btif/include/btif_debug.h
index 463a4a1..55e4e50 100644
--- a/btif/include/btif_debug.h
+++ b/btif/include/btif_debug.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_debug_btsnoop.h b/btif/include/btif_debug_btsnoop.h
index e82421a..766057d 100644
--- a/btif/include/btif_debug_btsnoop.h
+++ b/btif/include/btif_debug_btsnoop.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_debug_conn.h b/btif/include/btif_debug_conn.h
index 6ee374e..19703dd 100644
--- a/btif/include/btif_debug_conn.h
+++ b/btif/include/btif_debug_conn.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
index adafdef..6105ab5 100644
--- a/btif/include/btif_dm.h
+++ b/btif/include/btif_dm.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_gatt.h b/btif/include/btif_gatt.h
index e84811e..88f18a7 100644
--- a/btif/include/btif_gatt.h
+++ b/btif/include/btif_gatt.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_gatt_util.h b/btif/include/btif_gatt_util.h
index 731f519..284a45c 100644
--- a/btif/include/btif_gatt_util.h
+++ b/btif/include/btif_gatt_util.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,18 +24,10 @@
 
 #include "bta/include/bta_gatt_api.h"
 
-void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src);
-void btif_to_bta_response(tBTA_GATTS_RSP* p_dest, btgatt_response_t* p_src);
-void btif_to_bta_uuid_mask(tBTM_BLE_PF_COND_MASK* p_mask,
-                           const bt_uuid_t* p_src, const bt_uuid_t* svc_uuid);
-
-void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src);
-
-uint16_t set_read_value(btgatt_read_params_t* p_dest, tBTA_GATTC_READ* p_src);
-uint16_t get_uuid16(tBT_UUID* p_uuid);
+void btif_to_bta_response(tGATTS_RSP* p_dest, btgatt_response_t* p_src);
 
 void btif_gatt_check_encrypted_link(RawAddress bd_addr,
-                                    tBTA_GATT_TRANSPORT transport);
+                                    tGATT_TRANSPORT transport);
 extern void btif_gatt_move_track_adv_data(btgatt_track_adv_info_t* p_dest,
                                           btgatt_track_adv_info_t* p_src);
 
diff --git a/btif/include/btif_hd.h b/btif/include/btif_hd.h
index a119ebd..7ed7d56 100644
--- a/btif/include/btif_hd.h
+++ b/btif/include/btif_hd.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_hf.h b/btif/include/btif_hf.h
index 1cafb8b..68553b4 100644
--- a/btif/include/btif_hf.h
+++ b/btif/include/btif_hf.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,13 +16,34 @@
  *
  ******************************************************************************/
 
-#ifndef BTIF_HF_H
-#define BTIF_HF_H
+#pragma once
 
-#include <stdbool.h>
+#include <hardware/bluetooth_headset_interface.h>
 
-// Check whether there is a Hands-Free call in progress.
-// Returns true if no call is in progress.
-bool btif_hf_is_call_idle(void);
+namespace bluetooth {
+namespace headset {
 
-#endif /* BTIF_HF_H */
+/**
+ * Get an instance of the headset interface from the loaded shared library
+ *
+ * @return an instance of the headset interface
+ */
+Interface* GetInterface();
+
+/**
+ * Check whether there is a Hands-Free call in progress.
+ *
+ * @return true if no call is in progress.
+ */
+bool IsCallIdle();
+
+/**
+ * Start up or shutdown the service
+ *
+ * @param b_enable true to enable, false to disable
+ * @return BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ */
+bt_status_t ExecuteService(bool b_enable);
+
+}  // namespace headset
+}  // namespace bluetooth
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index 8505b08..2364544 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -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_hl.h b/btif/include/btif_hl.h
index b5022ef..69a99b5 100644
--- a/btif/include/btif_hl.h
+++ b/btif/include/btif_hl.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_mce.h b/btif/include/btif_mce.h
index dabcb39..1eea206 100644
--- a/btif/include/btif_mce.h
+++ b/btif/include/btif_mce.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_pan.h b/btif/include/btif_pan.h
index 96874d6..dada5b3 100644
--- a/btif/include/btif_pan.h
+++ b/btif/include/btif_pan.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_pan_internal.h b/btif/include/btif_pan_internal.h
index a902946..5b536af 100644
--- a/btif/include/btif_pan_internal.h
+++ b/btif/include/btif_pan_internal.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_profile_queue.h b/btif/include/btif_profile_queue.h
index df48c77..da4e992 100644
--- a/btif/include/btif_profile_queue.h
+++ b/btif/include/btif_profile_queue.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,7 +35,16 @@
                                btif_connect_cb_t connect_cb);
 void btif_queue_cleanup(uint16_t uuid);
 void btif_queue_advance();
+
+/**
+ * Dispatch the next pending connect request.
+ * NOTE: Must be called on the JNI thread.
+ *
+ * @return BT_STATUS_SUCCESS on success, otherwise the corresponding error
+ * code
+ */
 bt_status_t btif_queue_connect_next(void);
+
 void btif_queue_release();
 
 #endif
diff --git a/btif/include/btif_rc.h b/btif/include/btif_rc.h
new file mode 100644
index 0000000..cd2d0cc
--- /dev/null
+++ b/btif/include/btif_rc.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef BTIF_RC_H
+#define BTIF_RC_H
+
+#include "bta_av_api.h"
+
+class RawAddress;
+
+void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data);
+uint8_t btif_rc_get_connected_peer_handle(const RawAddress& peer_addr);
+void btif_rc_check_handle_pending_play(const RawAddress& peer_addr,
+                                       bool bSendToApp);
+bool btif_rc_is_connected_peer(const RawAddress& peer_addr);
+
+#endif  // BTIF_RC_H
diff --git a/btif/include/btif_sdp.h b/btif/include/btif_sdp.h
index 7e224b0..9f0daed 100644
--- a/btif/include/btif_sdp.h
+++ b/btif/include/btif_sdp.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 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.
diff --git a/btif/include/btif_sm.h b/btif/include/btif_sm.h
deleted file mode 100644
index 129e312..0000000
--- a/btif/include/btif_sm.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2009-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/*****************************************************************************
- *
- *  Filename:      btif_sm.h
- *
- *  Description:   Generic BTIF state machine API
- *
- *****************************************************************************/
-
-#ifndef BTIF_SM_H
-#define BTIF_SM_H
-
-#include <hardware/bluetooth.h>
-
-#include "stack/include/bt_types.h"
-
-/*****************************************************************************
- *  Constants & Macros
- *****************************************************************************/
-
-/* Generic Enter/Exit state machine events */
-#define BTIF_SM_ENTER_EVT 0xFFFF
-#define BTIF_SM_EXIT_EVT 0xFFFE
-
-/*****************************************************************************
- *  Type definitions and return values
- *****************************************************************************/
-typedef uint32_t btif_sm_state_t;
-typedef uint32_t btif_sm_event_t;
-typedef void* btif_sm_handle_t;
-typedef bool (*btif_sm_handler_t)(btif_sm_event_t event, void* data);
-
-/*****************************************************************************
- *  Functions
- *
- *  NOTE: THESE APIs SHOULD BE INVOKED ONLY IN THE BTIF CONTEXT
- *
- *****************************************************************************/
-
-/*****************************************************************************
- *
- * Function     btif_sm_init
- *
- * Description  Initializes the state machine with the state handlers
- *              The caller should ensure that the table and the corresponding
- *              states match. The location that 'p_handlers' points to shall
- *              be available until the btif_sm_shutdown API is invoked.
- *
- * Returns      Returns a pointer to the initialized state machine handle.
- *
- *****************************************************************************/
-btif_sm_handle_t btif_sm_init(const btif_sm_handler_t* p_handlers,
-                              btif_sm_state_t initial_state);
-
-/*****************************************************************************
- *
- * Function     btif_sm_shutdown
- *
- * Description  Tears down the state machine
- *
- * Returns      None
- *
- *****************************************************************************/
-void btif_sm_shutdown(btif_sm_handle_t handle);
-
-/*****************************************************************************
- *
- * Function     btif_sm_get_state
- *
- * Description  Fetches the current state of the state machine
- *
- * Returns      Current state
- *
- *****************************************************************************/
-btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle);
-
-/*****************************************************************************
- *
- * Function     btif_sm_dispatch
- *
- * Description  Dispatches the 'event' along with 'data' to the current state
- *              handler
- *
- * Returns      Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
- *
- *****************************************************************************/
-bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
-                             void* data);
-
-/*****************************************************************************
- *
- * Function     btif_sm_change_state
- *
- * Description  Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
- *              shall be invoked before exiting the current state. The
- *              'BTIF_SM_ENTER_EVT' shall be invoked before entering the new
- *              state
- *
- * Returns      Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
- *
- *****************************************************************************/
-bt_status_t btif_sm_change_state(btif_sm_handle_t handle,
-                                 btif_sm_state_t state);
-
-#endif /* BTIF_SM_H */
diff --git a/btif/include/btif_sock.h b/btif/include/btif_sock.h
index e65def6..cb0378e 100644
--- a/btif/include/btif_sock.h
+++ b/btif/include/btif_sock.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
 
 #include <hardware/bt_sock.h>
 
-btsock_interface_t* btif_sock_get_interface(void);
+const btsock_interface_t* btif_sock_get_interface(void);
 
 bt_status_t btif_sock_init(uid_set_t* uid_set);
 void btif_sock_cleanup(void);
diff --git a/btif/include/btif_sock_l2cap.h b/btif/include/btif_sock_l2cap.h
index 2715be0..f921279 100644
--- a/btif/include/btif_sock_l2cap.h
+++ b/btif/include/btif_sock_l2cap.h
@@ -10,7 +10,6 @@
 #include <hardware/bluetooth.h>
 
 #define L2CAP_MASK_FIXED_CHANNEL 0x10000
-#define L2CAP_MASK_LE_COC_CHANNEL 0x20000
 
 bt_status_t btsock_l2cap_init(int handle, uid_set_t* set);
 bt_status_t btsock_l2cap_cleanup();
diff --git a/btif/include/btif_sock_rfc.h b/btif/include/btif_sock_rfc.h
index 5c588b5..a37447e 100644
--- a/btif/include/btif_sock_rfc.h
+++ b/btif/include/btif_sock_rfc.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,12 +31,12 @@
 
 bt_status_t btsock_rfc_init(int handle, uid_set_t* set);
 bt_status_t btsock_rfc_cleanup();
-bt_status_t btsock_rfc_listen(const char* name, const uint8_t* uuid,
+bt_status_t btsock_rfc_listen(const char* name, const bluetooth::Uuid* uuid,
                               int channel, int* sock_fd, int flags,
                               int app_uid);
-bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, const uint8_t* uuid,
-                               int channel, int* sock_fd, int flags,
-                               int app_uid);
+bt_status_t btsock_rfc_connect(const RawAddress* bd_addr,
+                               const bluetooth::Uuid* uuid, int channel,
+                               int* sock_fd, int flags, int app_uid);
 void btsock_rfc_signaled(int fd, int flags, uint32_t user_id);
 
 #endif
diff --git a/btif/include/btif_sock_sco.h b/btif/include/btif_sock_sco.h
index 50530ce..9d1d805 100644
--- a/btif/include/btif_sock_sco.h
+++ b/btif/include/btif_sock_sco.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2013 Google, Inc.
+ *  Copyright 2013 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_sock_sdp.h b/btif/include/btif_sock_sdp.h
index 7672c7c..5421cd1 100644
--- a/btif/include/btif_sock_sdp.h
+++ b/btif/include/btif_sock_sdp.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,34 +19,21 @@
 #ifndef BTIF_SOCK_SDP_H
 #define BTIF_SOCK_SDP_H
 
+#include <bluetooth/uuid.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
 
-static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
-    0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
-    0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00,
-                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                        0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00,
-                                       0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                       0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00,
-                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                   0x5F, 0x9B, 0x34, 0xFB};
-static const uint8_t UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00,
-                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                   0x5F, 0x9B, 0x34, 0xFB};
+static const bluetooth::Uuid UUID_OBEX_OBJECT_PUSH =
+    bluetooth::Uuid::From16Bit(0x1105);
+static const bluetooth::Uuid UUID_PBAP_PSE = bluetooth::Uuid::From16Bit(0x112F);
+static const bluetooth::Uuid UUID_MAP_MAS = bluetooth::Uuid::From16Bit(0x1132);
+static const bluetooth::Uuid UUID_SAP = bluetooth::Uuid::From16Bit(0x112D);
+static const bluetooth::Uuid UUID_SPP = bluetooth::Uuid::From16Bit(0x1101);
 
-static inline bool is_uuid_empty(const uint8_t* uuid) {
-  static uint8_t empty_uuid[16];
-  return uuid == NULL || memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0;
-}
-
-int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn);
+int add_rfc_sdp_rec(const char* name, bluetooth::Uuid uuid, int scn);
 void del_rfc_sdp_rec(int handle);
 bool is_reserved_rfc_channel(int channel);
-int get_reserved_rfc_channel(const uint8_t* uuid);
+int get_reserved_rfc_channel(const bluetooth::Uuid& uuid);
 
 #endif
diff --git a/btif/include/btif_sock_thread.h b/btif/include/btif_sock_thread.h
index d50a09d..4b111a4 100644
--- a/btif/include/btif_sock_thread.h
+++ b/btif/include/btif_sock_thread.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/include/btif_sock_util.h b/btif/include/btif_sock_util.h
index 90cfb9a..0dfbbfb 100644
--- a/btif/include/btif_sock_util.h
+++ b/btif/include/btif_sock_util.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,8 +29,6 @@
 
 #include <stdint.h>
 
-void dump_bin(const char* title, const char* data, int size);
-
 int sock_send_fd(int sock_fd, const uint8_t* buffer, int len, int send_fd);
 int sock_send_all(int sock_fd, const uint8_t* buf, int len);
 int sock_recv_all(int sock_fd, uint8_t* buf, int len);
diff --git a/btif/include/btif_state_machine.h b/btif/include/btif_state_machine.h
new file mode 100644
index 0000000..49b1583
--- /dev/null
+++ b/btif/include/btif_state_machine.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#ifndef BTIF_STATE_MACHINE_H
+#define BTIF_STATE_MACHINE_H
+
+#include <map>
+#include <utility>
+
+#include <base/logging.h>
+
+/**
+ * State machine used by BTIF components.
+ */
+class BtifStateMachine {
+ public:
+  enum { kStateInvalid = -1 };
+
+  /**
+   * A class to represent the state in the State Machine.
+   */
+  class State {
+    friend class BtifStateMachine;
+
+   public:
+    /**
+     * Constructor.
+     *
+     * @param sm the State Machine to use
+     * @param state_id the unique State ID. It should be a non-negative number.
+     */
+    State(BtifStateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}
+
+    virtual ~State() = default;
+
+    /**
+     * Process an event.
+     * TODO: The arguments are wrong - used for backward compatibility.
+     * Will be replaced later.
+     *
+     * @param event the event type
+     * @param p_data the event data
+     * @return true if the processing was completed, otherwise false
+     */
+    virtual bool ProcessEvent(uint32_t event, void* p_data) = 0;
+
+    /**
+     * Get the State ID.
+     *
+     * @return the State ID
+     */
+    int StateId() const { return state_id_; }
+
+   protected:
+    /**
+     * Called when a state is entered.
+     */
+    virtual void OnEnter() {}
+
+    /**
+     * Called when a state is exited.
+     */
+    virtual void OnExit() {}
+
+    /**
+     * Transition the State Machine to a new state.
+     *
+     * @param dest_state_id the state ID to transition to. It must be one
+     * of the unique state IDs when the corresponding state was created.
+     */
+    void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); }
+
+    /**
+     * Transition the State Machine to a new state.
+     *
+     * @param dest_state the state to transition to. It cannot be nullptr.
+     */
+    void TransitionTo(BtifStateMachine::State* dest_state) {
+      sm_.TransitionTo(dest_state);
+    }
+
+   private:
+    BtifStateMachine& sm_;
+    int state_id_;
+  };
+
+  BtifStateMachine()
+      : initial_state_(nullptr),
+        previous_state_(nullptr),
+        current_state_(nullptr) {}
+  ~BtifStateMachine() {
+    for (auto& kv : states_) delete kv.second;
+  }
+
+  /**
+   * Start the State Machine operation.
+   */
+  void Start() { TransitionTo(initial_state_); }
+
+  /**
+   * Quit the State Machine operation.
+   */
+  void Quit() { previous_state_ = current_state_ = nullptr; }
+
+  /**
+   * Get the current State ID.
+   *
+   * @return the current State ID
+   */
+  int StateId() const {
+    if (current_state_ != nullptr) {
+      return current_state_->StateId();
+    }
+    return kStateInvalid;
+  }
+
+  /**
+   * Get the previous current State ID.
+   *
+   * @return the previous State ID
+   */
+  int PreviousStateId() const {
+    if (previous_state_ != nullptr) {
+      return previous_state_->StateId();
+    }
+    return kStateInvalid;
+  }
+
+  /**
+   * Process an event.
+   * TODO: The arguments are wrong - used for backward compatibility.
+   * Will be replaced later.
+   *
+   * @param event the event type
+   * @param p_data the event data
+   * @return true if the processing was completed, otherwise false
+   */
+  bool ProcessEvent(uint32_t event, void* p_data) {
+    if (current_state_ == nullptr) return false;
+    return current_state_->ProcessEvent(event, p_data);
+  }
+
+  /**
+   * Transition the State Machine to a new state.
+   *
+   * @param dest_state_id the state ID to transition to. It must be one
+   * of the unique state IDs when the corresponding state was created.
+   */
+  void TransitionTo(int dest_state_id) {
+    auto it = states_.find(dest_state_id);
+
+    CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id;
+    State* dest_state = it->second;
+    TransitionTo(dest_state);
+  }
+
+  /**
+   * Transition the State Machine to a new state.
+   *
+   * @param dest_state the state to transition to. It cannot be nullptr.
+   */
+  void TransitionTo(BtifStateMachine::State* dest_state) {
+    if (current_state_ != nullptr) {
+      current_state_->OnExit();
+    }
+    previous_state_ = current_state_;
+    current_state_ = dest_state;
+    current_state_->OnEnter();
+  }
+
+  /**
+   * Add a state to the State Machine.
+   * The state machine takes ownership on the state - i.e., the state will
+   * be deleted by the State Machine itself.
+   *
+   * @param state the state to add
+   */
+  void AddState(State* state) {
+    states_.insert(std::make_pair(state->StateId(), state));
+  }
+
+  /**
+   * Set the initial state of the State Machine.
+   *
+   * @param initial_state the initial state
+   */
+  void SetInitialState(State* initial_state) { initial_state_ = initial_state; }
+
+ private:
+  State* initial_state_;
+  State* previous_state_;
+  State* current_state_;
+  std::map<int, State*> states_;
+};
+
+#endif  // BTIF_STATE_MACHINE_H
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index 1f7efd3..fb90673 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 #ifndef BTIF_STORAGE_H
 #define BTIF_STORAGE_H
 
+#include <bluetooth/uuid.h>
 #include <hardware/bluetooth.h>
 
 #include "bt_target.h"
@@ -194,6 +195,15 @@
  ******************************************************************************/
 bt_status_t btif_storage_remove_hid_info(RawAddress* remote_bd_addr);
 
+/** Loads information about bonded hearing aid devices */
+void btif_storage_load_bonded_hearing_aids();
+
+/** 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
@@ -208,10 +218,12 @@
 bool btif_storage_is_restricted_device(const RawAddress* remote_bd_addr);
 
 bt_status_t btif_storage_add_ble_bonding_key(RawAddress* remote_bd_addr,
-                                             char* key, uint8_t key_type,
+                                             const uint8_t* key,
+                                             uint8_t key_type,
                                              uint8_t key_length);
 bt_status_t btif_storage_get_ble_bonding_key(RawAddress* remote_bd_addr,
-                                             uint8_t key_type, char* key_value,
+                                             uint8_t key_type,
+                                             uint8_t* key_value,
                                              int key_length);
 
 bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
@@ -272,7 +284,7 @@
 /******************************************************************************
  * Exported for unit tests
  *****************************************************************************/
-size_t btif_split_uuids_string(const char* str, bt_uuid_t* p_uuid,
+size_t btif_split_uuids_string(const char* str, bluetooth::Uuid* p_uuid,
                                size_t max_uuids);
 
 #endif /* BTIF_STORAGE_H */
diff --git a/btif/include/btif_uid.h b/btif/include/btif_uid.h
index 35faedb..de71906 100644
--- a/btif/include/btif_uid.h
+++ b/btif/include/btif_uid.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/btif/include/btif_util.h b/btif/include/btif_util.h
index a1a6492..007cfa5 100644
--- a/btif/include/btif_util.h
+++ b/btif/include/btif_util.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
 #define BTIF_UTIL_H
 
 #include <hardware/bluetooth.h>
-#include <hardware/bt_hf.h>
 #include <stdbool.h>
 #include <sys/time.h>
 
@@ -51,10 +50,7 @@
 const char* dump_hf_client_event(uint16_t event);
 const char* dump_hh_event(uint16_t event);
 const char* dump_hd_event(uint16_t event);
-const char* dump_hf_conn_state(uint16_t event);
-const char* dump_hf_call_state(bthf_call_state_t call_state);
 const char* dump_property_type(bt_property_type_t type);
-const char* dump_hf_audio_state(uint16_t event);
 const char* dump_adapter_scan_mode(bt_scan_mode_t mode);
 const char* dump_thread_evt(bt_cb_thread_evt evt);
 const char* dump_av_conn_state(uint16_t event);
@@ -65,17 +61,7 @@
 
 uint32_t devclass2uint(DEV_CLASS dev_class);
 void uint2devclass(uint32_t dev, DEV_CLASS dev_class);
-void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128);
-
-// Takes a |str| containing a 128-bit GUID formatted UUID and stores the
-// result in |p_uuid|. |str| must be formatted in this format:
-//   "12345678-1234-1234-1234-123456789012"
-// |p_uuid| cannot be null. Returns true if parsing was successful, false
-// otherwise. Returns false if |str| is null.
-bool string_to_uuid(const char* str, bt_uuid_t* p_uuid);
 
 int ascii_2_hex(const char* p_ascii, int len, uint8_t* p_hex);
 
-void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len);
-
 #endif /* BTIF_UTIL_H */
diff --git a/btif/include/stack_manager.h b/btif/include/stack_manager.h
index 90d81c5..1920ddd 100644
--- a/btif/include/stack_manager.h
+++ b/btif/include/stack_manager.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 1d2c66a..92a4092 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -33,10 +33,11 @@
 #include <unistd.h>
 
 #include <hardware/bluetooth.h>
+#include <hardware/bluetooth_headset_interface.h>
 #include <hardware/bt_av.h>
 #include <hardware/bt_gatt.h>
 #include <hardware/bt_hd.h>
-#include <hardware/bt_hf.h>
+#include <hardware/bt_hearing_aid.h>
 #include <hardware/bt_hf_client.h>
 #include <hardware/bt_hh.h>
 #include <hardware/bt_hl.h>
@@ -46,14 +47,18 @@
 #include <hardware/bt_sdp.h>
 #include <hardware/bt_sock.h>
 
+#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/include/btif_debug_btsnoop.h"
-#include "btif/include/btif_debug_conn.h"
 #include "btif_a2dp.h"
 #include "btif_api.h"
+#include "btif_av.h"
 #include "btif_config.h"
 #include "btif_debug.h"
+#include "btif_debug_btsnoop.h"
+#include "btif_debug_conn.h"
+#include "btif_hf.h"
 #include "btif_storage.h"
 #include "btsnoop.h"
 #include "btsnoop_mem.h"
@@ -69,6 +74,8 @@
 /* Test interface includes */
 #include "mca_api.h"
 
+using bluetooth::hearing_aid::HearingAidInterface;
+
 /*******************************************************************************
  *  Static variables
  ******************************************************************************/
@@ -82,36 +89,36 @@
 
 /* list all extended interfaces here */
 
-/* handsfree profile */
-extern bthf_interface_t* btif_hf_get_interface();
 /* handsfree profile - client */
-extern bthf_client_interface_t* btif_hf_client_get_interface();
+extern const bthf_client_interface_t* btif_hf_client_get_interface();
 /* advanced audio profile */
-extern btav_source_interface_t* btif_av_get_src_interface();
-extern btav_sink_interface_t* btif_av_get_sink_interface();
+extern const btav_source_interface_t* btif_av_get_src_interface();
+extern const btav_sink_interface_t* btif_av_get_sink_interface();
 /*rfc l2cap*/
-extern btsock_interface_t* btif_sock_get_interface();
+extern const btsock_interface_t* btif_sock_get_interface();
 /* hid host profile */
-extern bthh_interface_t* btif_hh_get_interface();
+extern const bthh_interface_t* btif_hh_get_interface();
 /* hid device profile */
-extern bthd_interface_t* btif_hd_get_interface();
+extern const bthd_interface_t* btif_hd_get_interface();
 /* health device profile */
-extern bthl_interface_t* btif_hl_get_interface();
+extern const bthl_interface_t* btif_hl_get_interface();
 /*pan*/
-extern btpan_interface_t* btif_pan_get_interface();
+extern const btpan_interface_t* btif_pan_get_interface();
 /*map client*/
-extern btmce_interface_t* btif_mce_get_interface();
+extern const btmce_interface_t* btif_mce_get_interface();
 /* gatt */
 extern const btgatt_interface_t* btif_gatt_get_interface();
 /* avrc target */
-extern btrc_interface_t* btif_rc_get_interface();
+extern const btrc_interface_t* btif_rc_get_interface();
 /* avrc controller */
-extern btrc_interface_t* btif_rc_ctrl_get_interface();
+extern const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface();
 /*SDP search client*/
-extern btsdp_interface_t* btif_sdp_get_interface();
+extern const btsdp_interface_t* btif_sdp_get_interface();
+/*Hearing Aid client*/
+extern HearingAidInterface* btif_hearing_aid_get_interface();
 
 /* List all test interface here */
-extern btmcap_test_interface_t* stack_mcap_get_interface();
+extern const btmcap_test_interface_t* stack_mcap_get_interface();
 
 /*******************************************************************************
  *  Functions
@@ -170,28 +177,28 @@
 
 static int get_adapter_properties(void) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_get_adapter_properties();
 }
 
 static int get_adapter_property(bt_property_type_t type) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_get_adapter_property(type);
 }
 
 static int set_adapter_property(const bt_property_t* property) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_set_adapter_property(property);
 }
 
 int get_remote_device_properties(RawAddress* remote_addr) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_get_remote_device_properties(remote_addr);
 }
@@ -199,7 +206,7 @@
 int get_remote_device_property(RawAddress* remote_addr,
                                bt_property_type_t type) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_get_remote_device_property(remote_addr, type);
 }
@@ -207,42 +214,43 @@
 int set_remote_device_property(RawAddress* remote_addr,
                                const bt_property_t* property) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_set_remote_device_property(remote_addr, property);
 }
 
-int get_remote_service_record(RawAddress* remote_addr, bt_uuid_t* uuid) {
+int get_remote_service_record(const RawAddress& remote_addr,
+                              const bluetooth::Uuid& uuid) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_get_remote_service_record(remote_addr, uuid);
 }
 
 int get_remote_services(RawAddress* remote_addr) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_get_remote_services(*remote_addr);
 }
 
 static int start_discovery(void) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_start_discovery();
 }
 
 static int cancel_discovery(void) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_cancel_discovery();
 }
 
 static int create_bond(const RawAddress* bd_addr, int transport) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_create_bond(bd_addr, transport);
 }
@@ -250,14 +258,14 @@
 static int create_bond_out_of_band(const RawAddress* bd_addr, int transport,
                                    const bt_out_of_band_data_t* oob_data) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_create_bond_out_of_band(bd_addr, transport, oob_data);
 }
 
 static int cancel_bond(const RawAddress* bd_addr) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_cancel_bond(bd_addr);
 }
@@ -267,14 +275,14 @@
     return BT_STATUS_SUCCESS;
 
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_remove_bond(bd_addr);
 }
 
 static int get_connection_state(const RawAddress* bd_addr) {
   /* sanity check */
-  if (interface_ready() == false) return 0;
+  if (!interface_ready()) return 0;
 
   return btif_dm_get_connection_state(bd_addr);
 }
@@ -282,7 +290,7 @@
 static int pin_reply(const RawAddress* bd_addr, uint8_t accept, uint8_t pin_len,
                      bt_pin_code_t* pin_code) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_pin_reply(bd_addr, accept, pin_len, pin_code);
 }
@@ -290,33 +298,31 @@
 static int ssp_reply(const RawAddress* bd_addr, bt_ssp_variant_t variant,
                      uint8_t accept, uint32_t passkey) {
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dm_ssp_reply(bd_addr, variant, accept, passkey);
 }
 
 static int read_energy_info() {
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
   btif_dm_read_energy_info();
   return BT_STATUS_SUCCESS;
 }
 
 static void dump(int fd, const char** arguments) {
-  if (arguments != NULL && arguments[0] != NULL) {
-    if (strncmp(arguments[0], "--proto-bin", 11) == 0) {
-      system_bt_osi::BluetoothMetricsLogger::GetInstance()->WriteBase64(fd,
-                                                                        true);
-      return;
-    }
-  }
   btif_debug_conn_dump(fd);
   btif_debug_bond_event_dump(fd);
   btif_debug_a2dp_dump(fd);
+  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
@@ -324,15 +330,19 @@
   close(fd);
 }
 
+static void dumpMetrics(std::string* output) {
+  system_bt_osi::BluetoothMetricsLogger::GetInstance()->WriteString(output);
+}
+
 static const void* get_profile_interface(const char* profile_id) {
   LOG_INFO(LOG_TAG, "%s: id = %s", __func__, profile_id);
 
   /* sanity check */
-  if (interface_ready() == false) return NULL;
+  if (!interface_ready()) return NULL;
 
   /* check for supported profile interfaces */
   if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
-    return btif_hf_get_interface();
+    return bluetooth::headset::GetInterface();
 
   if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
     return btif_hf_client_get_interface();
@@ -373,6 +383,8 @@
   if (is_profile(profile_id, BT_TEST_INTERFACE_MCAP_ID))
     return stack_mcap_get_interface();
 
+  if (is_profile(profile_id, BT_PROFILE_HEARING_AID_ID))
+    return btif_hearing_aid_get_interface();
   return NULL;
 }
 
@@ -380,7 +392,7 @@
   LOG_INFO(LOG_TAG, "%s", __func__);
 
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dut_mode_configure(enable);
 }
@@ -389,7 +401,7 @@
   LOG_INFO(LOG_TAG, "%s", __func__);
 
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_dut_mode_send(opcode, buf, len);
 }
@@ -398,7 +410,7 @@
   LOG_INFO(LOG_TAG, "%s", __func__);
 
   /* sanity check */
-  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   return btif_le_test_mode(opcode, buf, len);
 }
@@ -413,7 +425,11 @@
   return btif_config_clear() ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 
-static const bt_interface_t bluetoothInterface = {
+static bluetooth::avrcp::ServiceInterface* get_avrcp_service(void) {
+  return bluetooth::avrcp::AvrcpService::GetServiceInterface();
+}
+
+EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
     sizeof(bluetoothInterface),
     init,
     enable,
@@ -443,44 +459,9 @@
     set_os_callouts,
     read_energy_info,
     dump,
+    dumpMetrics,
     config_clear,
     interop_database_clear,
     interop_database_add,
+    get_avrcp_service,
 };
-
-const bt_interface_t* bluetooth__get_bluetooth_interface() {
-  /* fixme -- add property to disable bt interface ? */
-
-  return &bluetoothInterface;
-}
-
-static int close_bluetooth_stack(UNUSED_ATTR struct hw_device_t* device) {
-  cleanup();
-  return 0;
-}
-
-static int open_bluetooth_stack(const struct hw_module_t* module,
-                                UNUSED_ATTR char const* name,
-                                struct hw_device_t** abstraction) {
-  static bluetooth_device_t device;
-  device.common.tag = HARDWARE_DEVICE_TAG;
-  device.common.version = 0;
-  device.common.close = close_bluetooth_stack;
-  device.get_bluetooth_interface = bluetooth__get_bluetooth_interface;
-  device.common.module = (struct hw_module_t*)module;
-  *abstraction = (struct hw_device_t*)&device;
-  return 0;
-}
-
-static struct hw_module_methods_t bt_stack_module_methods = {
-    .open = open_bluetooth_stack,
-};
-
-EXPORT_SYMBOL struct hw_module_t HAL_MODULE_INFO_SYM = {
-    .tag = HARDWARE_MODULE_TAG,
-    .version_major = 1,
-    .version_minor = 0,
-    .id = BT_HARDWARE_MODULE_ID,
-    .name = "Bluetooth Stack",
-    .author = "The Android Open Source Project",
-    .methods = &bt_stack_module_methods};
diff --git a/btif/src/btif_a2dp.cc b/btif/src/btif_a2dp.cc
index 62a217a..86485d4 100644
--- a/btif/src/btif_a2dp.cc
+++ b/btif/src/btif_a2dp.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,16 +25,19 @@
 #include "bt_common.h"
 #include "bta_av_api.h"
 #include "btif_a2dp.h"
+#include "btif_a2dp_audio_interface.h"
 #include "btif_a2dp_control.h"
 #include "btif_a2dp_sink.h"
 #include "btif_a2dp_source.h"
 #include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_hf.h"
 #include "btif_util.h"
 #include "osi/include/log.h"
 
 void btif_a2dp_on_idle(void) {
-  APPL_TRACE_WARNING("## ON A2DP IDLE ## peer_sep = %d",
-                     btif_av_get_peer_sep());
+  LOG_INFO(LOG_TAG, "%s: ## ON A2DP IDLE ## peer_sep = %d", __func__,
+           btif_av_get_peer_sep());
   if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
     btif_a2dp_source_on_idle();
   } else if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
@@ -42,88 +45,138 @@
   }
 }
 
-bool btif_a2dp_on_started(tBTA_AV_START* p_av_start, bool pending_start) {
+bool btif_a2dp_on_started(const RawAddress& peer_addr,
+                          tBTA_AV_START* p_av_start, bool pending_start) {
   bool ack = false;
 
-  APPL_TRACE_WARNING("## ON A2DP STARTED ##");
+  LOG_INFO(LOG_TAG,
+           "%s: ## ON A2DP STARTED ## peer %s pending_start:%s p_av_start:%p",
+           __func__, peer_addr.ToString().c_str(),
+           logbool(pending_start).c_str(), p_av_start);
 
   if (p_av_start == NULL) {
     /* ack back a local start request */
-    btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+
+    if (!btif_av_is_a2dp_offload_enabled()) {
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+      return true;
+    } else if (bluetooth::headset::IsCallIdle()) {
+      btif_av_stream_start_offload();
+    } else {
+      LOG_ERROR(LOG_TAG, "%s: peer %s call in progress, do not start offload",
+                __func__, peer_addr.ToString().c_str());
+      btif_a2dp_audio_on_started(A2DP_CTRL_ACK_INCALL_FAILURE);
+    }
     return true;
   }
 
-  APPL_TRACE_WARNING(
-      "%s: pending_start = %d status = %d suspending = %d initiator = %d",
-      __func__, pending_start, p_av_start->status, p_av_start->suspending,
-      p_av_start->initiator);
+  LOG_INFO(LOG_TAG,
+           "%s: peer %s pending_start:%s status:%d suspending:%s initiator:%s",
+           __func__, peer_addr.ToString().c_str(),
+           logbool(pending_start).c_str(), p_av_start->status,
+           logbool(p_av_start->suspending).c_str(),
+           logbool(p_av_start->initiator).c_str());
 
   if (p_av_start->status == BTA_AV_SUCCESS) {
     if (!p_av_start->suspending) {
       if (p_av_start->initiator) {
         if (pending_start) {
-          btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+          if (btif_av_is_a2dp_offload_enabled()) {
+            btif_av_stream_start_offload();
+          } else {
+            btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+          }
           ack = true;
         }
       } else {
-        /* We were remotely started, make sure codec
-         * is setup before datapath is started.
-         */
-        btif_a2dp_source_setup_codec();
+        // We were started remotely
+        if (btif_av_is_a2dp_offload_enabled()) {
+          btif_av_stream_start_offload();
+        }
       }
 
       /* media task is autostarted upon a2dp audiopath connection */
     }
   } else if (pending_start) {
-    APPL_TRACE_WARNING("%s: A2DP start request failed: status = %d", __func__,
-                       p_av_start->status);
-    btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+    LOG_ERROR(LOG_TAG, "%s: peer %s A2DP start request failed: status = %d",
+              __func__, peer_addr.ToString().c_str(), p_av_start->status);
+    if (btif_av_is_a2dp_offload_enabled()) {
+      btif_a2dp_audio_on_started(p_av_start->status);
+    } else {
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+    }
     ack = true;
   }
   return ack;
 }
 
 void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
-  APPL_TRACE_WARNING("## ON A2DP STOPPED ##");
+  LOG_INFO(LOG_TAG, "%s: ## ON A2DP STOPPED ## p_av_suspend=%p", __func__,
+           p_av_suspend);
 
   if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
     btif_a2dp_sink_on_stopped(p_av_suspend);
     return;
   }
-
-  btif_a2dp_source_on_stopped(p_av_suspend);
-}
-
-void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
-  APPL_TRACE_WARNING("## ON A2DP SUSPENDED ##");
-  if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
-    btif_a2dp_sink_on_suspended(p_av_suspend);
-  } else {
-    btif_a2dp_source_on_suspended(p_av_suspend);
+  if (!btif_av_is_a2dp_offload_enabled()) {
+    btif_a2dp_source_on_stopped(p_av_suspend);
+  } else if (p_av_suspend != NULL) {
+    btif_a2dp_audio_on_stopped(p_av_suspend->status);
   }
 }
 
-void btif_a2dp_on_offload_started(tBTA_AV_STATUS status) {
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
+  LOG_INFO(LOG_TAG, "%s: ## ON A2DP SUSPENDED ## p_av_suspend=%p", __func__,
+           p_av_suspend);
+  if (!btif_av_is_a2dp_offload_enabled()) {
+    if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+      btif_a2dp_sink_on_suspended(p_av_suspend);
+    } else {
+      btif_a2dp_source_on_suspended(p_av_suspend);
+    }
+  } else {
+    btif_a2dp_audio_on_suspended(p_av_suspend->status);
+  }
+}
+
+void btif_a2dp_on_offload_started(const RawAddress& peer_addr,
+                                  tBTA_AV_STATUS status) {
   tA2DP_CTRL_ACK ack;
-  APPL_TRACE_EVENT("%s status %d", __func__, status);
+  LOG_INFO(LOG_TAG, "%s: peer %s status %d", __func__,
+           peer_addr.ToString().c_str(), status);
 
   switch (status) {
     case BTA_AV_SUCCESS:
       ack = A2DP_CTRL_ACK_SUCCESS;
       break;
     case BTA_AV_FAIL_RESOURCES:
-      APPL_TRACE_ERROR("%s FAILED UNSUPPORTED", __func__);
+      LOG_ERROR(LOG_TAG, "%s: peer %s FAILED UNSUPPORTED", __func__,
+                peer_addr.ToString().c_str());
       ack = A2DP_CTRL_ACK_UNSUPPORTED;
       break;
     default:
-      APPL_TRACE_ERROR("%s FAILED: status = %d", __func__, status);
+      LOG_ERROR(LOG_TAG, "%s: peer %s FAILED: status = %d", __func__,
+                peer_addr.ToString().c_str(), status);
       ack = A2DP_CTRL_ACK_FAILURE;
       break;
   }
-  btif_a2dp_command_ack(ack);
+  if (btif_av_is_a2dp_offload_enabled()) {
+    btif_a2dp_audio_on_started(status);
+    if (ack != BTA_AV_SUCCESS && btif_av_stream_started_ready()) {
+      // Offload request will return with failure from btif_av sm if
+      // suspend is triggered for remote start. Disconnect only if SoC
+      // returned failure for offload VSC
+      LOG_ERROR(LOG_TAG, "%s: peer %s offload start failed", __func__,
+                peer_addr.ToString().c_str());
+      btif_av_src_disconnect_sink(peer_addr);
+    }
+  } else {
+    btif_a2dp_command_ack(ack);
+  }
 }
 
 void btif_debug_a2dp_dump(int fd) {
   btif_a2dp_source_debug_dump(fd);
   btif_a2dp_sink_debug_dump(fd);
+  btif_a2dp_codec_debug_dump(fd);
 }
diff --git a/btif/src/btif_a2dp_audio_interface.cc b/btif/src/btif_a2dp_audio_interface.cc
new file mode 100644
index 0000000..7343bbe
--- /dev/null
+++ b/btif/src/btif_a2dp_audio_interface.cc
@@ -0,0 +1,506 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2017 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "btif_a2dp_audio_interface"
+
+#include "btif_a2dp_audio_interface.h"
+
+#include <mutex>
+
+#include <a2dp_vendor.h>
+#include <a2dp_vendor_ldac_constants.h>
+#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioHost.h>
+#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
+#include <android/hardware/bluetooth/a2dp/1.0/types.h>
+#include <base/logging.h>
+#include <hwbinder/ProcessState.h>
+#include <utils/RefBase.h>
+#include "a2dp_sbc.h"
+#include "bt_common.h"
+#include "bta/av/bta_av_int.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_hf.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+
+using system_bt_osi::A2dpSessionMetrics;
+using system_bt_osi::BluetoothMetricsLogger;
+
+using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
+using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
+using android::hardware::bluetooth::a2dp::V1_0::Status;
+using android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration;
+using android::hardware::bluetooth::a2dp::V1_0::CodecType;
+using android::hardware::bluetooth::a2dp::V1_0::SampleRate;
+using android::hardware::bluetooth::a2dp::V1_0::BitsPerSample;
+using android::hardware::bluetooth::a2dp::V1_0::ChannelMode;
+using android::hardware::ProcessState;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::android::wp;
+android::sp<IBluetoothAudioOffload> btAudio;
+
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+static uint8_t a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+static Status mapToStatus(uint8_t resp);
+uint8_t btif_a2dp_audio_process_request(uint8_t cmd);
+
+static void btif_a2dp_audio_send_start_req();
+static void btif_a2dp_audio_send_suspend_req();
+static void btif_a2dp_audio_send_stop_req();
+static void btif_a2dp_audio_interface_init();
+static void btif_a2dp_audio_interface_deinit();
+static void btif_a2dp_audio_interface_restart_session();
+// Delay reporting
+// static void btif_a2dp_audio_send_sink_latency();
+
+class A2dpOffloadAudioStats {
+ public:
+  A2dpOffloadAudioStats() { Reset(); }
+  void Reset() {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    ResetPreserveSession();
+    codec_index_ = -1;
+  }
+  void ResetPreserveSession() {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    audio_start_time_ms_ = -1;
+    audio_stop_time_ms_ = -1;
+  }
+  void StoreMetrics() {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    if (audio_start_time_ms_ < 0 || audio_stop_time_ms_ < 0) {
+      return;
+    }
+    A2dpSessionMetrics metrics;
+    metrics.codec_index = codec_index_;
+    metrics.is_a2dp_offload = true;
+    if (audio_stop_time_ms_ > audio_start_time_ms_) {
+      metrics.audio_duration_ms = audio_stop_time_ms_ - audio_start_time_ms_;
+    }
+    BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics);
+  }
+  void LogAudioStart() {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    audio_start_time_ms_ = time_get_os_boottime_ms();
+  }
+  void LogAudioStop() {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    audio_stop_time_ms_ = time_get_os_boottime_ms();
+  }
+  void LogAudioStopMetricsAndReset() {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    LogAudioStop();
+    StoreMetrics();
+    ResetPreserveSession();
+  }
+  void SetCodecIndex(int64_t codec_index) {
+    std::lock_guard<std::recursive_mutex> lock(lock_);
+    codec_index_ = codec_index;
+  }
+
+ private:
+  std::recursive_mutex lock_;
+  int64_t audio_start_time_ms_ = -1;
+  int64_t audio_stop_time_ms_ = -1;
+  int64_t codec_index_ = -1;
+};
+
+static A2dpOffloadAudioStats a2dp_offload_audio_stats;
+
+class BluetoothAudioHost : public IBluetoothAudioHost {
+ public:
+  Return<void> startStream() {
+    btif_a2dp_audio_send_start_req();
+    return Void();
+  }
+  Return<void> suspendStream() {
+    btif_a2dp_audio_send_suspend_req();
+    return Void();
+  }
+  Return<void> stopStream() {
+    btif_a2dp_audio_send_stop_req();
+    return Void();
+  }
+
+  // TODO : Delay reporting
+  /*    Return<void> a2dp_get_sink_latency() {
+          LOG_INFO(LOG_TAG,"%s:start ", __func__);
+          btif_a2dp_audio_send_sink_latency();
+          return Void();
+      }*/
+};
+
+class BluetoothAudioDeathRecipient : public hidl_death_recipient {
+ public:
+  virtual void serviceDied(
+      uint64_t /*cookie*/,
+      const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+    LOG_ERROR(LOG_TAG, "%s", __func__);
+    // Restart the session on the correct thread
+    do_in_bta_thread(FROM_HERE,
+                     base::Bind(&btif_a2dp_audio_interface_restart_session));
+  }
+};
+sp<BluetoothAudioDeathRecipient> bluetoothAudioDeathRecipient =
+    new BluetoothAudioDeathRecipient();
+
+static Status mapToStatus(uint8_t resp) {
+  switch (resp) {
+    case A2DP_CTRL_ACK_SUCCESS:
+      return Status::SUCCESS;
+      break;
+    case A2DP_CTRL_ACK_PENDING:
+      return Status::PENDING;
+      break;
+    case A2DP_CTRL_ACK_FAILURE:
+    case A2DP_CTRL_ACK_INCALL_FAILURE:
+    case A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS:
+      return Status::FAILURE;
+    default:
+      APPL_TRACE_WARNING("%s: unknown status recevied :%d", __func__, resp);
+      return Status::FAILURE;
+      break;
+  }
+}
+
+static void btif_a2dp_get_codec_configuration(
+    CodecConfiguration* p_codec_info) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  tBT_A2DP_OFFLOAD a2dp_offload;
+  A2dpCodecConfig* a2dpCodecConfig = bta_av_get_a2dp_current_codec();
+  a2dpCodecConfig->getCodecSpecificConfig(&a2dp_offload);
+  btav_a2dp_codec_config_t codec_config;
+  codec_config = a2dpCodecConfig->getCodecConfig();
+  a2dp_offload_audio_stats.SetCodecIndex(a2dpCodecConfig->codecIndex());
+  switch (codec_config.codec_type) {
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+      p_codec_info->codecType =
+          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
+              BTA_AV_CODEC_TYPE_SBC;
+      p_codec_info->codecSpecific.sbcData.codecParameters =
+          a2dp_offload.codec_info[0];
+      LOG_INFO(LOG_TAG, " %s: codec parameters =%d", __func__,
+               a2dp_offload.codec_info[0]);
+      p_codec_info->codecSpecific.sbcData.minBitpool =
+          a2dp_offload.codec_info[1];
+      p_codec_info->codecSpecific.sbcData.maxBitpool =
+          a2dp_offload.codec_info[2];
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      p_codec_info->codecType =
+          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
+              BTA_AV_CODEC_TYPE_AAC;
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+      p_codec_info->codecType =
+          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
+              BTA_AV_CODEC_TYPE_APTX;
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+      p_codec_info->codecType =
+          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
+              BTA_AV_CODEC_TYPE_APTXHD;
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+      p_codec_info->codecType =
+          (::android::hardware::bluetooth::a2dp::V1_0::CodecType)
+              BTA_AV_CODEC_TYPE_LDAC;
+      p_codec_info->codecSpecific.ldacData.bitrateIndex =
+          a2dp_offload.codec_info[6];
+      break;
+    default:
+      APPL_TRACE_ERROR("%s: Unknown Codec type :%d ", __func__,
+                       codec_config.codec_type);
+  }
+
+  // Obtain the MTU
+  RawAddress peer_addr = btif_av_source_active_peer();
+  tA2DP_ENCODER_INIT_PEER_PARAMS peer_param;
+  bta_av_co_get_peer_params(peer_addr, &peer_param);
+  int effectiveMtu = a2dpCodecConfig->getEffectiveMtu();
+  if (effectiveMtu > 0 && effectiveMtu < peer_param.peer_mtu) {
+    p_codec_info->peerMtu = effectiveMtu;
+  } else {
+    p_codec_info->peerMtu = peer_param.peer_mtu;
+  }
+  LOG_INFO(LOG_TAG, "%s: peer MTU: %d effective MTU: %d result MTU: %d",
+           __func__, peer_param.peer_mtu, effectiveMtu, p_codec_info->peerMtu);
+
+  p_codec_info->sampleRate =
+      (::android::hardware::bluetooth::a2dp::V1_0::SampleRate)
+          codec_config.sample_rate;
+  p_codec_info->bitsPerSample =
+      (::android::hardware::bluetooth::a2dp::V1_0::BitsPerSample)
+          codec_config.bits_per_sample;
+  p_codec_info->channelMode =
+      (::android::hardware::bluetooth::a2dp::V1_0::ChannelMode)
+          codec_config.channel_mode;
+  p_codec_info->encodedAudioBitrate = a2dpCodecConfig->getTrackBitRate();
+}
+
+static void btif_a2dp_audio_interface_init() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  btAudio = IBluetoothAudioOffload::getService();
+  CHECK(btAudio != nullptr);
+
+  auto death_link = btAudio->linkToDeath(bluetoothAudioDeathRecipient, 0);
+  if (!death_link.isOk()) {
+    LOG_ERROR(LOG_TAG, "%s: Cannot observe the Bluetooth Audio HAL's death",
+              __func__);
+  }
+
+  LOG_DEBUG(
+      LOG_TAG, "%s: IBluetoothAudioOffload::getService() returned %p (%s)",
+      __func__, btAudio.get(), (btAudio->isRemote() ? "remote" : "local"));
+
+  LOG_INFO(LOG_TAG, "%s:Init returned", __func__);
+}
+
+static void btif_a2dp_audio_interface_deinit() {
+  LOG_INFO(LOG_TAG, "%s: start", __func__);
+  if (btAudio != nullptr) {
+    auto death_unlink = btAudio->unlinkToDeath(bluetoothAudioDeathRecipient);
+    if (!death_unlink.isOk()) {
+      LOG_ERROR(LOG_TAG,
+                "%s: Error unlinking death observer from Bluetooth Audio HAL",
+                __func__);
+    }
+  }
+  btAudio = nullptr;
+}
+
+void btif_a2dp_audio_interface_start_session() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+      system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+  a2dp_offload_audio_stats.Reset();
+  btif_a2dp_audio_interface_init();
+  CHECK(btAudio != nullptr);
+  CodecConfiguration codec_info;
+  btif_a2dp_get_codec_configuration(&codec_info);
+  android::sp<IBluetoothAudioHost> host_if = new BluetoothAudioHost();
+  btAudio->startSession(host_if, codec_info);
+}
+
+void btif_a2dp_audio_interface_end_session() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+      system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+  a2dp_offload_audio_stats.Reset();
+  if (btAudio == nullptr) return;
+  auto ret = btAudio->endSession();
+  if (!ret.isOk()) {
+    LOG_ERROR(LOG_TAG, "HAL server is dead");
+  }
+  btif_a2dp_audio_interface_deinit();
+}
+
+// Conditionally restart the session only if it was started before
+static void btif_a2dp_audio_interface_restart_session() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  if (btAudio == nullptr) {
+    LOG_INFO(LOG_TAG, "%s: nothing to restart - session was not started",
+             __func__);
+    return;
+  }
+  btAudio = nullptr;
+  btif_a2dp_audio_interface_start_session();
+}
+
+void btif_a2dp_audio_on_started(tBTA_AV_STATUS status) {
+  LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
+  if (btAudio != nullptr) {
+    if (a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
+      LOG_INFO(LOG_TAG, "%s: calling method onStarted", __func__);
+      auto hal_status = mapToStatus(status);
+      btAudio->streamStarted(hal_status);
+      if (hal_status == Status::SUCCESS) {
+        a2dp_offload_audio_stats.LogAudioStart();
+      }
+    }
+  }
+}
+
+void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status) {
+  LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
+  if (btAudio != nullptr) {
+    if (a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND) {
+      LOG_INFO(LOG_TAG, "calling method onSuspended");
+      auto hal_status = mapToStatus(status);
+      btAudio->streamSuspended(hal_status);
+      if (hal_status == Status::SUCCESS) {
+        a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+      }
+    }
+  }
+}
+
+void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
+  LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
+  if (btAudio != nullptr && a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
+    LOG_INFO(LOG_TAG, "%s: Remote disconnected when start under progress",
+             __func__);
+    btAudio->streamStarted(mapToStatus(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS));
+    a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+  }
+}
+void btif_a2dp_audio_send_start_req() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  uint8_t resp;
+  resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_START);
+  if (btAudio != nullptr) {
+    auto status = mapToStatus(resp);
+    auto ret = btAudio->streamStarted(status);
+    if (status == Status::SUCCESS) {
+      a2dp_offload_audio_stats.LogAudioStart();
+    }
+    if (!ret.isOk()) LOG_ERROR(LOG_TAG, "HAL server died");
+  }
+}
+void btif_a2dp_audio_send_suspend_req() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  uint8_t resp;
+  resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_SUSPEND);
+  if (btAudio != nullptr) {
+    auto status = mapToStatus(resp);
+    auto ret = btAudio->streamSuspended(status);
+    if (status == Status::SUCCESS) {
+      a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+    }
+    if (!ret.isOk()) LOG_ERROR(LOG_TAG, "HAL server died");
+  }
+}
+
+void btif_a2dp_audio_send_stop_req() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  btif_a2dp_audio_process_request(A2DP_CTRL_CMD_STOP);
+  a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+}
+
+/*void btif_a2dp_audio_send_sink_latency()
+{
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  uint16_t sink_latency = btif_av_get_sink_latency();
+  if (btAudio != nullptr) {
+    auto ret = btAudio->a2dp_on_get_sink_latency(sink_latency);
+    if (!ret.isOk()) LOG_ERROR(LOG_TAG, "server died");
+  }
+}*/
+
+uint8_t btif_a2dp_audio_process_request(uint8_t cmd) {
+  LOG_INFO(LOG_TAG, "%s: cmd: %s", __func__,
+           audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
+  a2dp_cmd_pending = cmd;
+  uint8_t status;
+  switch (cmd) {
+    case A2DP_CTRL_CMD_START:
+      /*
+       * Don't send START request to stack while we are in a call.
+       * Some headsets such as "Sony MW600", don't allow AVDTP START
+       * 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;
+      }
+      if (btif_av_stream_started_ready()) {
+        /*
+         * Already started, setup audio data channel listener and ACK
+         * back immediately.
+         */
+        status = A2DP_CTRL_ACK_SUCCESS;
+        break;
+      }
+      if (btif_av_stream_ready()) {
+        /*
+         * Post start event and wait for audio path to open.
+         * If we are the source, the ACK will be sent after the start
+         * procedure is completed, othewise send it now.
+         */
+        btif_av_stream_start();
+        if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+          status = A2DP_CTRL_ACK_SUCCESS;
+          break;
+        }
+        /*Return pending and ack when start stream cfm received from remote*/
+        status = A2DP_CTRL_ACK_PENDING;
+        break;
+      }
+
+      APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
+                         __func__,
+                         audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
+      return A2DP_CTRL_ACK_FAILURE;
+      break;
+
+    case A2DP_CTRL_CMD_STOP:
+      if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
+          !btif_a2dp_source_is_streaming()) {
+        /* We are already stopped, just ack back */
+        status = A2DP_CTRL_ACK_SUCCESS;
+        break;
+      }
+      btif_av_stream_stop(RawAddress::kEmpty);
+      return A2DP_CTRL_ACK_SUCCESS;
+      break;
+
+    case A2DP_CTRL_CMD_SUSPEND:
+      /* Local suspend */
+      if (btif_av_stream_started_ready()) {
+        btif_av_stream_suspend();
+        status = A2DP_CTRL_ACK_PENDING;
+        break;
+      }
+      /* If we are not in started state, just ack back ok and let
+       * audioflinger close the channel. This can happen if we are
+       * remotely suspended, clear REMOTE SUSPEND flag.
+       */
+      btif_av_clear_remote_suspend_flag();
+      status = A2DP_CTRL_ACK_SUCCESS;
+      break;
+
+    case A2DP_CTRL_CMD_OFFLOAD_START:
+      btif_av_stream_start_offload();
+      status = A2DP_CTRL_ACK_PENDING;
+      break;
+
+    default:
+      APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
+      status = A2DP_CTRL_ACK_FAILURE;
+      break;
+  }
+  LOG_INFO(LOG_TAG, "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 af59644..fb62480 100644
--- a/btif/src/btif_a2dp_control.cc
+++ b/btif/src/btif_a2dp_control.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -37,20 +37,27 @@
 
 #define A2DP_DATA_READ_POLL_MS 10
 
+struct {
+  uint64_t total_bytes_read = 0;
+  uint16_t audio_delay = 0;
+  struct timespec timestamp = {};
+} delay_report_stats;
+
 static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
 static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
 
 /* We can have max one command pending */
 static tA2DP_CTRL_CMD a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+std::unique_ptr<tUIPC_STATE> a2dp_uipc;
 
 void btif_a2dp_control_init(void) {
-  UIPC_Init(NULL);
-  UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
+  a2dp_uipc = UIPC_Init();
+  UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb, A2DP_CTRL_PATH);
 }
 
 void btif_a2dp_control_cleanup(void) {
   /* This calls blocks until UIPC is fully closed */
-  UIPC_Close(UIPC_CH_ID_ALL);
+  UIPC_Close(*a2dp_uipc, UIPC_CH_ID_ALL);
 }
 
 static void btif_a2dp_recv_ctrl_data(void) {
@@ -58,20 +65,27 @@
   int n;
 
   uint8_t read_cmd = 0; /* The read command size is one octet */
-  n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &read_cmd, 1);
+  n = UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, NULL, &read_cmd, 1);
   cmd = static_cast<tA2DP_CTRL_CMD>(read_cmd);
 
   /* detach on ctrl channel means audioflinger process was terminated */
   if (n == 0) {
     APPL_TRACE_WARNING("%s: CTRL CH DETACHED", __func__);
-    UIPC_Close(UIPC_CH_ID_AV_CTRL);
+    UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_CTRL);
     return;
   }
 
-  APPL_TRACE_WARNING("%s: a2dp-ctrl-cmd : %s", __func__,
+  // Don't log A2DP_CTRL_GET_PRESENTATION_POSITION by default, because it
+  // could be very chatty when audio is streaming.
+  if (cmd == A2DP_CTRL_GET_PRESENTATION_POSITION) {
+    APPL_TRACE_DEBUG("%s: a2dp-ctrl-cmd : %s", __func__,
                      audio_a2dp_hw_dump_ctrl_event(cmd));
-  a2dp_cmd_pending = cmd;
+  } else {
+    APPL_TRACE_WARNING("%s: a2dp-ctrl-cmd : %s", __func__,
+                       audio_a2dp_hw_dump_ctrl_event(cmd));
+  }
 
+  a2dp_cmd_pending = cmd;
   switch (cmd) {
     case A2DP_CTRL_CMD_CHECK_READY:
       if (btif_a2dp_source_media_task_is_shutting_down()) {
@@ -97,7 +111,9 @@
        * Some headsets such as "Sony MW600", don't allow AVDTP START
        * while in a call, and respond with BAD_STATE.
        */
-      if (!btif_hf_is_call_idle()) {
+      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;
       }
@@ -111,14 +127,15 @@
 
       if (btif_av_stream_ready()) {
         /* Setup audio data channel listener */
-        UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+        UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb,
+                  A2DP_DATA_PATH);
 
         /*
          * Post start event and wait for audio path to open.
          * If we are the source, the ACK will be sent after the start
          * procedure is completed, othewise send it now.
          */
-        btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+        btif_av_stream_start();
         if (btif_av_get_peer_sep() == AVDT_TSEP_SRC)
           btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
         break;
@@ -129,7 +146,8 @@
          * Already started, setup audio data channel listener and ACK
          * back immediately.
          */
-        UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+        UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb,
+                  A2DP_DATA_PATH);
         btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
         break;
       }
@@ -145,15 +163,14 @@
         btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
         break;
       }
-
-      btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+      btif_av_stream_stop(RawAddress::kEmpty);
       btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
       break;
 
     case A2DP_CTRL_CMD_SUSPEND:
       /* Local suspend */
       if (btif_av_stream_started_ready()) {
-        btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+        btif_av_stream_suspend();
         break;
       }
       /* If we are not in started state, just ack back ok and let
@@ -169,9 +186,10 @@
       tA2DP_CHANNEL_COUNT channel_count = btif_a2dp_sink_get_channel_count();
 
       btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<uint8_t*>(&sample_rate),
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
+                reinterpret_cast<uint8_t*>(&sample_rate),
                 sizeof(tA2DP_SAMPLE_RATE));
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &channel_count,
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0, &channel_count,
                 sizeof(tA2DP_CHANNEL_COUNT));
       break;
     }
@@ -194,25 +212,27 @@
 
       btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
       // Send the current codec config
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                 reinterpret_cast<const uint8_t*>(&codec_config.sample_rate),
                 sizeof(btav_a2dp_codec_sample_rate_t));
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                 reinterpret_cast<const uint8_t*>(&codec_config.bits_per_sample),
                 sizeof(btav_a2dp_codec_bits_per_sample_t));
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                 reinterpret_cast<const uint8_t*>(&codec_config.channel_mode),
                 sizeof(btav_a2dp_codec_channel_mode_t));
       // Send the current codec capability
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                 reinterpret_cast<const uint8_t*>(&codec_capability.sample_rate),
                 sizeof(btav_a2dp_codec_sample_rate_t));
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<const uint8_t*>(
-                                           &codec_capability.bits_per_sample),
-                sizeof(btav_a2dp_codec_bits_per_sample_t));
-      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<const uint8_t*>(
-                                           &codec_capability.channel_mode),
-                sizeof(btav_a2dp_codec_channel_mode_t));
+      UIPC_Send(
+          *a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
+          reinterpret_cast<const uint8_t*>(&codec_capability.bits_per_sample),
+          sizeof(btav_a2dp_codec_bits_per_sample_t));
+      UIPC_Send(
+          *a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
+          reinterpret_cast<const uint8_t*>(&codec_capability.channel_mode),
+          sizeof(btav_a2dp_codec_channel_mode_t));
       break;
     }
 
@@ -224,7 +244,7 @@
 
       btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
       // Send the current codec config
-      if (UIPC_Read(UIPC_CH_ID_AV_CTRL, 0,
+      if (UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                     reinterpret_cast<uint8_t*>(&codec_config.sample_rate),
                     sizeof(btav_a2dp_codec_sample_rate_t)) !=
           sizeof(btav_a2dp_codec_sample_rate_t)) {
@@ -232,7 +252,7 @@
                          __func__);
         break;
       }
-      if (UIPC_Read(UIPC_CH_ID_AV_CTRL, 0,
+      if (UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                     reinterpret_cast<uint8_t*>(&codec_config.bits_per_sample),
                     sizeof(btav_a2dp_codec_bits_per_sample_t)) !=
           sizeof(btav_a2dp_codec_bits_per_sample_t)) {
@@ -240,7 +260,7 @@
                          __func__);
         break;
       }
-      if (UIPC_Read(UIPC_CH_ID_AV_CTRL, 0,
+      if (UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
                     reinterpret_cast<uint8_t*>(&codec_config.channel_mode),
                     sizeof(btav_a2dp_codec_channel_mode_t)) !=
           sizeof(btav_a2dp_codec_channel_mode_t)) {
@@ -259,22 +279,55 @@
     }
 
     case A2DP_CTRL_CMD_OFFLOAD_START:
-      btif_dispatch_sm_event(BTIF_AV_OFFLOAD_START_REQ_EVT, NULL, 0);
+      btif_av_stream_start_offload();
       break;
 
+    case A2DP_CTRL_GET_PRESENTATION_POSITION: {
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
+                (uint8_t*)&(delay_report_stats.total_bytes_read),
+                sizeof(uint64_t));
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0,
+                (uint8_t*)&(delay_report_stats.audio_delay), sizeof(uint16_t));
+
+      uint32_t seconds = delay_report_stats.timestamp.tv_sec;
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0, (uint8_t*)&seconds,
+                sizeof(seconds));
+
+      uint32_t nsec = delay_report_stats.timestamp.tv_nsec;
+      UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0, (uint8_t*)&nsec,
+                sizeof(nsec));
+      break;
+    }
     default:
       APPL_TRACE_ERROR("%s: UNSUPPORTED CMD (%d)", __func__, cmd);
       btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
       break;
   }
-  APPL_TRACE_WARNING("%s: a2dp-ctrl-cmd : %s DONE", __func__,
+
+  // Don't log A2DP_CTRL_GET_PRESENTATION_POSITION by default, because it
+  // could be very chatty when audio is streaming.
+  if (cmd == A2DP_CTRL_GET_PRESENTATION_POSITION) {
+    APPL_TRACE_DEBUG("%s: a2dp-ctrl-cmd : %s DONE", __func__,
                      audio_a2dp_hw_dump_ctrl_event(cmd));
+  } else {
+    APPL_TRACE_WARNING("%s: a2dp-ctrl-cmd : %s DONE", __func__,
+                       audio_a2dp_hw_dump_ctrl_event(cmd));
+  }
 }
 
 static void btif_a2dp_ctrl_cb(UNUSED_ATTR tUIPC_CH_ID ch_id,
                               tUIPC_EVENT event) {
-  APPL_TRACE_WARNING("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__,
+  // Don't log UIPC_RX_DATA_READY_EVT by default, because it
+  // could be very chatty when audio is streaming.
+  if (event == UIPC_RX_DATA_READY_EVT) {
+    APPL_TRACE_DEBUG("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__,
                      dump_uipc_event(event));
+  } else {
+    APPL_TRACE_WARNING("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__,
+                       dump_uipc_event(event));
+  }
 
   switch (event) {
     case UIPC_OPEN_EVT:
@@ -283,7 +336,8 @@
     case UIPC_CLOSE_EVT:
       /* restart ctrl server unless we are shutting down */
       if (btif_a2dp_source_media_task_is_running())
-        UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
+        UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb,
+                  A2DP_CTRL_PATH);
       break;
 
     case UIPC_RX_DATA_READY_EVT:
@@ -308,8 +362,9 @@
        * Read directly from media task from here on (keep callback for
        * connection events.
        */
-      UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
-      UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
+      UIPC_Ioctl(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO,
+                 UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
+      UIPC_Ioctl(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
                  reinterpret_cast<void*>(A2DP_DATA_READ_POLL_MS));
 
       if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
@@ -330,7 +385,7 @@
        */
       if (btif_a2dp_source_is_streaming()) {
         /* Post stop event and wait for audio path to stop */
-        btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+        btif_av_stream_stop(RawAddress::kEmpty);
       }
       break;
 
@@ -344,8 +399,15 @@
 void btif_a2dp_command_ack(tA2DP_CTRL_ACK status) {
   uint8_t ack = status;
 
-  APPL_TRACE_WARNING("%s: ## a2dp ack : %s, status %d ##", __func__,
+  // Don't log A2DP_CTRL_GET_PRESENTATION_POSITION by default, because it
+  // could be very chatty when audio is streaming.
+  if (a2dp_cmd_pending == A2DP_CTRL_GET_PRESENTATION_POSITION) {
+    APPL_TRACE_DEBUG("%s: ## a2dp ack : %s, status %d ##", __func__,
                      audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status);
+  } else {
+    APPL_TRACE_WARNING("%s: ## a2dp ack : %s, status %d ##", __func__,
+                       audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status);
+  }
 
   /* Sanity check */
   if (a2dp_cmd_pending == A2DP_CTRL_CMD_NONE) {
@@ -357,5 +419,22 @@
   a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
 
   /* Acknowledge start request */
-  UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+  UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+}
+
+void btif_a2dp_control_log_bytes_read(uint32_t bytes_read) {
+  delay_report_stats.total_bytes_read += bytes_read;
+  clock_gettime(CLOCK_MONOTONIC, &delay_report_stats.timestamp);
+}
+
+void btif_a2dp_control_set_audio_delay(uint16_t delay) {
+  APPL_TRACE_DEBUG("%s: DELAY: %.1f ms", __func__, (float)delay / 10);
+  delay_report_stats.audio_delay = delay;
+}
+
+void btif_a2dp_control_reset_audio_delay(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  delay_report_stats.audio_delay = 0;
+  delay_report_stats.total_bytes_read = 0;
+  delay_report_stats.timestamp = {};
 }
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index 4ccf39f..c17b33a 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,7 +19,9 @@
 
 #define LOG_TAG "bt_btif_a2dp_sink"
 
-#include <string.h>
+#include <atomic>
+#include <cstring>
+#include <mutex>
 
 #include "bt_common.h"
 #include "btif_a2dp.h"
@@ -33,8 +35,7 @@
 #include "osi/include/osi.h"
 #include "osi/include/thread.h"
 
-#include "oi_codec_sbc.h"
-#include "oi_status.h"
+using LockGuard = std::lock_guard<std::mutex>;
 
 /**
  * The receiving queue buffer size.
@@ -71,13 +72,6 @@
   btif_a2dp_sink_focus_state_t focus_state;
 } tBTIF_MEDIA_SINK_FOCUS_UPDATE;
 
-typedef struct {
-  uint16_t num_frames_to_be_processed;
-  uint16_t len;
-  uint16_t offset;
-  uint16_t layer_specific;
-} tBT_SBC_HDR;
-
 /* BTIF A2DP Sink control block */
 typedef struct {
   thread_t* worker_thread;
@@ -85,25 +79,26 @@
   fixed_queue_t* rx_audio_queue;
   bool rx_flush; /* discards any incoming data when true */
   alarm_t* decode_alarm;
-  uint8_t frames_to_process;
   tA2DP_SAMPLE_RATE sample_rate;
   tA2DP_CHANNEL_COUNT channel_count;
   btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
   void* audio_track;
+  const tA2DP_DECODER_INTERFACE* decoder_interface;
 } tBTIF_A2DP_SINK_CB;
 
+// Mutex for below data structures.
+static std::mutex g_mutex;
+
 static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
 
-static int btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};
 
-static OI_CODEC_SBC_DECODER_CONTEXT btif_a2dp_sink_context;
-static uint32_t btif_a2dp_sink_context_data[CODEC_DATA_WORDS(
-    2, SBC_CODEC_FAST_FILTER_BUFFERS)];
-static int16_t
-    btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
-
+static void btif_a2dp_sink_init_delayed(void* context);
 static void btif_a2dp_sink_startup_delayed(void* context);
+static void btif_a2dp_sink_start_session_delayed(void* context);
+static void btif_a2dp_sink_end_session_delayed(void* context);
 static void btif_a2dp_sink_shutdown_delayed(void* context);
+static void btif_a2dp_sink_cleanup_delayed(void* context);
 static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
 static void btif_a2dp_sink_audio_handle_stop_decoding(void);
 static void btif_decode_alarm_cb(void* context);
@@ -111,7 +106,7 @@
 static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
 static void btif_a2dp_sink_audio_rx_flush_req(void);
 /* Handle incoming media packets A2DP SINK streaming */
-static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg);
+static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg);
 static void btif_a2dp_sink_decoder_update_event(
     tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
 static void btif_a2dp_sink_clear_track_event(void);
@@ -132,21 +127,22 @@
   return "UNKNOWN A2DP SINK EVENT";
 }
 
-bool btif_a2dp_sink_startup(void) {
+bool btif_a2dp_sink_init(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+
   if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
-    APPL_TRACE_ERROR("%s: A2DP Sink media task already running", __func__);
+    LOG_ERROR(LOG_TAG, "%s: A2DP Sink media task already running", __func__);
     return false;
   }
 
   memset(&btif_a2dp_sink_cb, 0, sizeof(btif_a2dp_sink_cb));
   btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_STARTING_UP;
 
-  APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
-
   /* Start A2DP Sink media task */
   btif_a2dp_sink_cb.worker_thread = thread_new("btif_a2dp_sink_worker_thread");
   if (btif_a2dp_sink_cb.worker_thread == NULL) {
-    APPL_TRACE_ERROR("%s: unable to start up media thread", __func__);
+    LOG_ERROR(LOG_TAG, "%s: unable to start up media thread", __func__);
     btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
     return false;
   }
@@ -161,56 +157,152 @@
       thread_get_reactor(btif_a2dp_sink_cb.worker_thread),
       btif_a2dp_sink_command_ready, NULL);
 
-  APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##");
-
-  /* Schedule the rest of the startup operations */
-  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
+  /* Schedule the rest of the operations */
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_init_delayed,
               NULL);
 
   return true;
 }
 
-static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_init_delayed(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   raise_priority_a2dp(TASK_HIGH_MEDIA);
   btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
 }
 
-void btif_a2dp_sink_shutdown(void) {
-  if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
-      (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
-    return;
+bool btif_a2dp_sink_startup(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
+              NULL);
+  return true;
+}
+
+static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+  // Nothing to do
+}
+
+bool btif_a2dp_sink_start_session(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
+           peer_address.ToString().c_str());
+  thread_post(btif_a2dp_sink_cb.worker_thread,
+              btif_a2dp_sink_start_session_delayed, NULL);
+  return true;
+}
+
+static void btif_a2dp_sink_start_session_delayed(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+  // 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);
   }
 
-  /* Make sure no channels are restarted while shutting down */
-  btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
+  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;
+  }
 
-  APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
+  if (old_peer_address.IsEmpty()) {
+    btif_a2dp_sink_startup();
+  }
+  btif_a2dp_sink_start_session(new_peer_address);
 
-  // Stop the timer
-  alarm_free(btif_a2dp_sink_cb.decode_alarm);
-  btif_a2dp_sink_cb.decode_alarm = NULL;
+  return true;
+}
 
-  // Exit the thread
-  fixed_queue_free(btif_a2dp_sink_cb.cmd_msg_queue, NULL);
-  btif_a2dp_sink_cb.cmd_msg_queue = NULL;
+bool btif_a2dp_sink_end_session(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
+           peer_address.ToString().c_str());
+  thread_post(btif_a2dp_sink_cb.worker_thread,
+              btif_a2dp_sink_end_session_delayed, NULL);
+  return true;
+}
+
+static void btif_a2dp_sink_end_session_delayed(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+  // Nothing to do
+}
+
+void btif_a2dp_sink_shutdown(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
               NULL);
-  thread_free(btif_a2dp_sink_cb.worker_thread);
-  btif_a2dp_sink_cb.worker_thread = NULL;
 }
 
 static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+  // Nothing to do
+}
+
+void btif_a2dp_sink_cleanup(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  alarm_t* decode_alarm;
+  fixed_queue_t* cmd_msg_queue;
+  thread_t* worker_thread;
+
+  // Make sure the sink is shutdown
+  btif_a2dp_sink_shutdown();
+
+  {
+    LockGuard lock(g_mutex);
+    if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
+        (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
+      return;
+    }
+    // Make sure no channels are restarted while shutting down
+    btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
+
+    decode_alarm = btif_a2dp_sink_cb.decode_alarm;
+    btif_a2dp_sink_cb.decode_alarm = NULL;
+
+    cmd_msg_queue = btif_a2dp_sink_cb.cmd_msg_queue;
+    btif_a2dp_sink_cb.cmd_msg_queue = NULL;
+
+    worker_thread = btif_a2dp_sink_cb.worker_thread;
+    btif_a2dp_sink_cb.worker_thread = NULL;
+  }
+
+  // Stop the timer
+  alarm_free(decode_alarm);
+
+  // Exit the thread
+  fixed_queue_free(cmd_msg_queue, NULL);
+  thread_post(worker_thread, btif_a2dp_sink_cleanup_delayed, NULL);
+  thread_free(worker_thread);
+}
+
+static void btif_a2dp_sink_cleanup_delayed(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+
   fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL);
   btif_a2dp_sink_cb.rx_audio_queue = NULL;
-
   btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
 }
 
 tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void) {
+  LockGuard lock(g_mutex);
   return btif_a2dp_sink_cb.sample_rate;
 }
 
 tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void) {
+  LockGuard lock(g_mutex);
   return btif_a2dp_sink_cb.channel_count;
 }
 
@@ -239,7 +331,7 @@
       btif_a2dp_sink_audio_rx_flush_event();
       break;
     default:
-      APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
+      LOG_ERROR(LOG_TAG, "%s: unknown event %d", __func__, p_msg->event);
       break;
   }
 
@@ -248,6 +340,7 @@
 }
 
 void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf =
       reinterpret_cast<tBTIF_MEDIA_SINK_DECODER_UPDATE*>(
           osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE)));
@@ -263,37 +356,51 @@
 }
 
 void btif_a2dp_sink_on_idle(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
-
   btif_a2dp_sink_audio_handle_stop_decoding();
   btif_a2dp_sink_clear_track_event_req();
-  APPL_TRACE_DEBUG("Stopped BT track");
 }
 
 void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
-
   btif_a2dp_sink_audio_handle_stop_decoding();
 }
 
 void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
-
   btif_a2dp_sink_audio_handle_stop_decoding();
 }
 
 static void btif_a2dp_sink_audio_handle_stop_decoding(void) {
-  btif_a2dp_sink_cb.rx_flush = true;
-  btif_a2dp_sink_audio_rx_flush_req();
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  alarm_t* old_alarm;
+  {
+    LockGuard lock(g_mutex);
+    btif_a2dp_sink_cb.rx_flush = true;
+    btif_a2dp_sink_audio_rx_flush_req();
+    old_alarm = btif_a2dp_sink_cb.decode_alarm;
+    btif_a2dp_sink_cb.decode_alarm = NULL;
+  }
 
-  alarm_free(btif_a2dp_sink_cb.decode_alarm);
-  btif_a2dp_sink_cb.decode_alarm = NULL;
+  // Drop the lock here, btif_decode_alarm_cb may in the process of being called
+  // while we alarm free leading to deadlock.
+  //
+  // alarm_free waits for btif_decode_alarm_cb which is waiting for g_mutex.
+  alarm_free(old_alarm);
+
+  {
+    LockGuard lock(g_mutex);
 #ifndef OS_GENERIC
-  BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
+    BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
 #endif
+  }
 }
 
 static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
+  LockGuard lock(g_mutex);
   if (btif_a2dp_sink_cb.worker_thread != NULL) {
     thread_post(btif_a2dp_sink_cb.worker_thread,
                 btif_a2dp_sink_avk_handle_timer, NULL);
@@ -301,7 +408,8 @@
 }
 
 static void btif_a2dp_sink_clear_track_event(void) {
-  APPL_TRACE_DEBUG("%s", __func__);
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
 
 #ifndef OS_GENERIC
   BtifAvrcpAudioTrackStop(btif_a2dp_sink_cb.audio_track);
@@ -310,7 +418,9 @@
   btif_a2dp_sink_cb.audio_track = NULL;
 }
 
+// Must be called while locked.
 static void btif_a2dp_sink_audio_handle_start_decoding(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   if (btif_a2dp_sink_cb.decode_alarm != NULL)
     return;  // Already started decoding
 
@@ -327,54 +437,31 @@
             btif_decode_alarm_cb, NULL);
 }
 
-static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
-  uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
-  int count;
-  uint32_t pcmBytes, availPcmBytes;
-  int16_t* pcmDataPointer =
-      btif_a2dp_sink_pcm_data; /* Will be overwritten on next packet receipt */
-  OI_STATUS status;
-  int num_sbc_frames = p_msg->num_frames_to_be_processed;
-  uint32_t sbc_frame_len = p_msg->len - 1;
-  availPcmBytes = sizeof(btif_a2dp_sink_pcm_data);
-
-  if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
-      (btif_a2dp_sink_cb.rx_flush)) {
-    APPL_TRACE_DEBUG("State Changed happened in this tick");
-    return;
-  }
-
-  APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
-                   num_sbc_frames, sbc_frame_len);
-
-  for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count++) {
-    pcmBytes = availPcmBytes;
-    status = OI_CODEC_SBC_DecodeFrame(
-        &btif_a2dp_sink_context, (const OI_BYTE**)&sbc_start_frame,
-        (uint32_t*)&sbc_frame_len, (int16_t*)pcmDataPointer,
-        (uint32_t*)&pcmBytes);
-    if (!OI_SUCCESS(status)) {
-      APPL_TRACE_ERROR("%s: Decoding failure: %d", __func__, status);
-      break;
-    }
-    availPcmBytes -= pcmBytes;
-    pcmDataPointer += pcmBytes / 2;
-    p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
-    p_msg->len = sbc_frame_len + 1;
-  }
-
+static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) {
 #ifndef OS_GENERIC
-  BtifAvrcpAudioTrackWriteData(
-      btif_a2dp_sink_cb.audio_track, (void*)btif_a2dp_sink_pcm_data,
-      (sizeof(btif_a2dp_sink_pcm_data) - availPcmBytes));
+  BtifAvrcpAudioTrackWriteData(btif_a2dp_sink_cb.audio_track,
+                               reinterpret_cast<void*>(data), len);
 #endif
 }
 
-static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
-  tBT_SBC_HDR* p_msg;
-  int num_sbc_frames;
-  int num_frames_to_process;
+// Must be called while locked.
+static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg) {
+  if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
+      (btif_a2dp_sink_cb.rx_flush)) {
+    APPL_TRACE_DEBUG("%s: state changed happened in this tick", __func__);
+    return;
+  }
 
+  CHECK(btif_a2dp_sink_cb.decoder_interface);
+  if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
+    LOG_ERROR(LOG_TAG, "%s: decoding failed", __func__);
+  }
+}
+
+static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
+  LockGuard lock(g_mutex);
+
+  BT_HDR* p_msg;
   if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
     APPL_TRACE_DEBUG("%s: empty queue", __func__);
     return;
@@ -392,63 +479,41 @@
     return;
   }
 
-  num_frames_to_process = btif_a2dp_sink_cb.frames_to_process;
-  APPL_TRACE_DEBUG(" Process Frames + ");
-
-  do {
-    p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
-        btif_a2dp_sink_cb.rx_audio_queue);
-    if (p_msg == NULL) return;
-    /* Number of frames in queue packets */
-    num_sbc_frames = p_msg->num_frames_to_be_processed;
-    APPL_TRACE_DEBUG("Frames left in topmost packet %d", num_sbc_frames);
-    APPL_TRACE_DEBUG("Remaining frames to process in tick %d",
-                     num_frames_to_process);
-    APPL_TRACE_DEBUG("Number of packets in queue %d",
+  APPL_TRACE_DEBUG("%s: process frames begin", __func__);
+  while (true) {
+    p_msg = (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
+    if (p_msg == NULL) {
+      break;
+    }
+    APPL_TRACE_DEBUG("%s: number of packets in queue %zu", __func__,
                      fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));
 
-    if (num_sbc_frames > num_frames_to_process) {
-      /* Queue packet has more frames */
-      p_msg->num_frames_to_be_processed = num_frames_to_process;
-      btif_a2dp_sink_handle_inc_media(p_msg);
-      p_msg->num_frames_to_be_processed =
-          num_sbc_frames - num_frames_to_process;
-      num_frames_to_process = 0;
-      break;
-    }
     /* Queue packet has less frames */
     btif_a2dp_sink_handle_inc_media(p_msg);
-    p_msg =
-        (tBT_SBC_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
-    if (p_msg == NULL) {
-      APPL_TRACE_ERROR("Insufficient data in queue");
-      break;
-    }
-    num_frames_to_process =
-        num_frames_to_process - p_msg->num_frames_to_be_processed;
     osi_free(p_msg);
-  } while (num_frames_to_process > 0);
-
-  APPL_TRACE_DEBUG("Process Frames - ");
+  }
+  APPL_TRACE_DEBUG("%s: process frames end", __func__);
 }
 
 /* when true media task discards any rx frames */
 void btif_a2dp_sink_set_rx_flush(bool enable) {
-  APPL_TRACE_EVENT("## DROP RX %d ##", enable);
+  LOG_INFO(LOG_TAG, "%s: enable=%s", __func__, (enable) ? "true" : "false");
+  LockGuard lock(g_mutex);
+
   btif_a2dp_sink_cb.rx_flush = enable;
 }
 
 static void btif_a2dp_sink_audio_rx_flush_event(void) {
-  /* Flush all received SBC buffers (encoded) */
-  APPL_TRACE_DEBUG("%s", __func__);
-
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
+  // Flush all received encoded audio buffers
   fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
 }
 
 static void btif_a2dp_sink_decoder_update_event(
     tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
-  OI_STATUS status;
-
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  LockGuard lock(g_mutex);
   APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
                    p_buf->codec_info[1], p_buf->codec_info[2],
                    p_buf->codec_info[3], p_buf->codec_info[4],
@@ -456,33 +521,39 @@
 
   int sample_rate = A2DP_GetTrackSampleRate(p_buf->codec_info);
   if (sample_rate == -1) {
-    APPL_TRACE_ERROR("%s: cannot get the track frequency", __func__);
+    LOG_ERROR(LOG_TAG, "%s: cannot get the track frequency", __func__);
     return;
   }
   int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
   if (channel_count == -1) {
-    APPL_TRACE_ERROR("%s: cannot get the channel count", __func__);
+    LOG_ERROR(LOG_TAG, "%s: cannot get the channel count", __func__);
     return;
   }
   int channel_type = A2DP_GetSinkTrackChannelType(p_buf->codec_info);
   if (channel_type == -1) {
-    APPL_TRACE_ERROR("%s: cannot get the Sink channel type", __func__);
+    LOG_ERROR(LOG_TAG, "%s: cannot get the Sink channel type", __func__);
     return;
   }
   btif_a2dp_sink_cb.sample_rate = sample_rate;
   btif_a2dp_sink_cb.channel_count = channel_count;
 
   btif_a2dp_sink_cb.rx_flush = false;
-  APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
-  status = OI_CODEC_SBC_DecoderReset(
-      &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
-      sizeof(btif_a2dp_sink_context_data), 2, 2, false);
-  if (!OI_SUCCESS(status)) {
-    APPL_TRACE_ERROR("%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
-                     __func__, status);
+  APPL_TRACE_DEBUG("%s: reset to Sink role", __func__);
+
+  btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
+  if (btif_a2dp_sink_cb.decoder_interface == NULL) {
+    LOG_ERROR(LOG_TAG, "%s: cannot stream audio: no source decoder interface",
+              __func__);
+    return;
   }
 
-  APPL_TRACE_DEBUG("%s: A2dpSink: SBC create track", __func__);
+  if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
+          btif_a2dp_sink_on_decode_complete)) {
+    LOG_ERROR(LOG_TAG, "%s: failed to initialize decoder", __func__);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("%s: create audio track", __func__);
   btif_a2dp_sink_cb.audio_track =
 #ifndef OS_GENERIC
       BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
@@ -490,21 +561,13 @@
       NULL;
 #endif
   if (btif_a2dp_sink_cb.audio_track == NULL) {
-    APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
+    LOG_ERROR(LOG_TAG, "%s: track creation failed", __func__);
     return;
   }
-
-  btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
-      BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
-  APPL_TRACE_DEBUG("%s: Frames to be processed in 20 ms %d", __func__,
-                   btif_a2dp_sink_cb.frames_to_process);
-  if (btif_a2dp_sink_cb.frames_to_process == 0) {
-    APPL_TRACE_ERROR("%s: Cannot compute the number of frames to process",
-                     __func__);
-  }
 }
 
 uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
+  LockGuard lock(g_mutex);
   if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */
     return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
 
@@ -517,17 +580,11 @@
 
   BTIF_TRACE_VERBOSE("%s +", __func__);
   /* Allocate and queue this buffer */
-  tBT_SBC_HDR* p_msg = reinterpret_cast<tBT_SBC_HDR*>(
-      osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len));
-  memcpy((uint8_t*)(p_msg + 1), (uint8_t*)(p_pkt + 1) + p_pkt->offset,
-         p_pkt->len);
-  p_msg->num_frames_to_be_processed =
-      (*((uint8_t*)(p_pkt + 1) + p_pkt->offset)) & 0x0f;
-  p_msg->len = p_pkt->len;
+  BT_HDR* p_msg =
+      reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(*p_msg) + p_pkt->len));
+  memcpy(p_msg, p_pkt, sizeof(*p_msg));
   p_msg->offset = 0;
-  p_msg->layer_specific = p_pkt->layer_specific;
-  BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__,
-                     p_msg->num_frames_to_be_processed, p_msg->len);
+  memcpy(p_msg->data, p_pkt->data + p_pkt->offset, p_pkt->len);
   fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
   if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
       MAX_A2DP_DELAYED_START_FRAME_COUNT) {
@@ -539,6 +596,7 @@
 }
 
 void btif_a2dp_sink_audio_rx_flush_req(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
     /* Queue is already empty */
     return;
@@ -554,12 +612,10 @@
 }
 
 void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   tBTIF_MEDIA_SINK_FOCUS_UPDATE* p_buf =
       reinterpret_cast<tBTIF_MEDIA_SINK_FOCUS_UPDATE*>(
           osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));
-
-  APPL_TRACE_EVENT("%s", __func__);
-
   p_buf->focus_state = state;
   p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
   fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
@@ -567,6 +623,9 @@
 
 static void btif_a2dp_sink_set_focus_state_event(
     btif_a2dp_sink_focus_state_t state) {
+  LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
+  LockGuard lock(g_mutex);
+
   if (!btif_av_is_connected()) return;
   APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
   btif_a2dp_sink_cb.rx_focus_state = state;
@@ -579,13 +638,16 @@
 }
 
 void btif_a2dp_sink_set_audio_track_gain(float gain) {
-  APPL_TRACE_DEBUG("%s set gain to %f", __func__, gain);
+  LOG_INFO(LOG_TAG, "%s: set gain to %f", __func__, gain);
+  LockGuard lock(g_mutex);
+
 #ifndef OS_GENERIC
   BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain);
 #endif
 }
 
 static void btif_a2dp_sink_clear_track_event_req(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
 
   p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc
index 8d264ce..efd842b 100644
--- a/btif/src/btif_a2dp_source.cc
+++ b/btif/src/btif_a2dp_source.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,10 +20,11 @@
 #define LOG_TAG "bt_btif_a2dp_source"
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
-#include <base/logging.h>
+#include <base/run_loop.h>
 #ifndef OS_GENERIC
 #include <cutils/trace.h>
 #endif
+#include <inttypes.h>
 #include <limits.h>
 #include <string.h>
 #include <algorithm>
@@ -32,6 +33,7 @@
 #include "bt_common.h"
 #include "bta_av_ci.h"
 #include "btif_a2dp.h"
+#include "btif_a2dp_audio_interface.h"
 #include "btif_a2dp_control.h"
 #include "btif_a2dp_source.h"
 #include "btif_av.h"
@@ -40,15 +42,19 @@
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
 #include "osi/include/metrics.h"
-#include "osi/include/mutex.h"
 #include "osi/include/osi.h"
 #include "osi/include/thread.h"
 #include "osi/include/time.h"
 #include "uipc.h"
 
+#include <condition_variable>
+#include <mutex>
+
 using system_bt_osi::BluetoothMetricsLogger;
 using system_bt_osi::A2dpSessionMetrics;
 
+extern std::unique_ptr<tUIPC_STATE> a2dp_uipc;
+
 /**
  * The typical runlevel of the tx queue size is ~1 buffer
  * but due to link flow control or thread preemption in lower
@@ -56,42 +62,22 @@
  */
 #define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (MAX_PCM_FRAME_NUM_PER_TICK * 2)
 
-enum {
-  BTIF_A2DP_SOURCE_STATE_OFF,
-  BTIF_A2DP_SOURCE_STATE_STARTING_UP,
-  BTIF_A2DP_SOURCE_STATE_RUNNING,
-  BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN
-};
+class SchedulingStats {
+ public:
+  SchedulingStats() { Reset(); }
+  void Reset() {
+    total_updates = 0;
+    last_update_us = 0;
+    overdue_scheduling_count = 0;
+    total_overdue_scheduling_delta_us = 0;
+    max_overdue_scheduling_delta_us = 0;
+    premature_scheduling_count = 0;
+    total_premature_scheduling_delta_us = 0;
+    max_premature_scheduling_delta_us = 0;
+    exact_scheduling_count = 0;
+    total_scheduling_time_us = 0;
+  }
 
-/* BTIF Media Source event definition */
-enum {
-  BTIF_MEDIA_AUDIO_TX_START = 1,
-  BTIF_MEDIA_AUDIO_TX_STOP,
-  BTIF_MEDIA_AUDIO_TX_FLUSH,
-  BTIF_MEDIA_SOURCE_ENCODER_INIT,
-  BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE,
-  BTIF_MEDIA_AUDIO_FEEDING_UPDATE
-};
-
-/* tBTIF_A2DP_SOURCE_ENCODER_INIT msg structure */
-typedef struct {
-  BT_HDR hdr;
-  tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
-} tBTIF_A2DP_SOURCE_ENCODER_INIT;
-
-/* tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE msg structure */
-typedef struct {
-  BT_HDR hdr;
-  btav_a2dp_codec_config_t user_config;
-} tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE;
-
-/* tBTIF_A2DP_AUDIO_FEEDING_UPDATE msg structure */
-typedef struct {
-  BT_HDR hdr;
-  btav_a2dp_codec_config_t feeding_params;
-} tBTIF_A2DP_AUDIO_FEEDING_UPDATE;
-
-typedef struct {
   // Counter for total updates
   size_t total_updates;
 
@@ -121,14 +107,39 @@
 
   // Accumulated and counted scheduling time (in us)
   uint64_t total_scheduling_time_us;
-} scheduling_stats_t;
+};
 
-typedef struct {
+class BtifMediaStats {
+ public:
+  BtifMediaStats() { Reset(); }
+  void Reset() {
+    session_start_us = 0;
+    session_end_us = 0;
+    tx_queue_enqueue_stats.Reset();
+    tx_queue_dequeue_stats.Reset();
+    tx_queue_total_frames = 0;
+    tx_queue_max_frames_per_packet = 0;
+    tx_queue_total_queueing_time_us = 0;
+    tx_queue_max_queueing_time_us = 0;
+    tx_queue_total_readbuf_calls = 0;
+    tx_queue_last_readbuf_us = 0;
+    tx_queue_total_flushed_messages = 0;
+    tx_queue_last_flushed_us = 0;
+    tx_queue_total_dropped_messages = 0;
+    tx_queue_max_dropped_messages = 0;
+    tx_queue_dropouts = 0;
+    tx_queue_last_dropouts_us = 0;
+    media_read_total_underflow_bytes = 0;
+    media_read_total_underflow_count = 0;
+    media_read_last_underflow_us = 0;
+    codec_index = -1;
+  }
+
   uint64_t session_start_us;
   uint64_t session_end_us;
 
-  scheduling_stats_t tx_queue_enqueue_stats;
-  scheduling_stats_t tx_queue_dequeue_stats;
+  SchedulingStats tx_queue_enqueue_stats;
+  SchedulingStats tx_queue_dequeue_stats;
 
   size_t tx_queue_total_frames;
   size_t tx_queue_max_frames_per_packet;
@@ -150,64 +161,201 @@
   size_t media_read_total_underflow_bytes;
   size_t media_read_total_underflow_count;
   uint64_t media_read_last_underflow_us;
-} btif_media_stats_t;
 
-typedef struct {
-  thread_t* worker_thread;
-  fixed_queue_t* cmd_msg_queue;
+  int codec_index = -1;
+};
+
+class BtWorkerThread {
+ public:
+  BtWorkerThread(const std::string& thread_name)
+      : thread_name_(thread_name),
+        message_loop_(nullptr),
+        run_loop_(nullptr),
+        message_loop_thread_(nullptr),
+        started_(false) {}
+
+  void StartUp() {
+    if (message_loop_thread_ != nullptr) {
+      return;  // Already started up
+    }
+    message_loop_thread_ = thread_new(thread_name_.c_str());
+    CHECK(message_loop_thread_ != nullptr);
+    started_ = false;
+    thread_post(message_loop_thread_, &BtWorkerThread::RunThread, this);
+    {
+      // Block until run_loop_ is allocated and ready to run
+      std::unique_lock<std::mutex> start_lock(start_up_mutex_);
+      while (!started_) {
+        start_up_cv_.wait(start_lock);
+      }
+    }
+  }
+
+  bool DoInThread(const tracked_objects::Location& from_here,
+                  const base::Closure& task) {
+    if ((message_loop_ == nullptr) || !message_loop_->task_runner().get()) {
+      LOG_ERROR(
+          LOG_TAG,
+          "%s: Dropping message for thread %s: message loop is not initialized",
+          __func__, thread_name_.c_str());
+      return false;
+    }
+    if (!message_loop_->task_runner()->PostTask(from_here, task)) {
+      LOG_ERROR(LOG_TAG,
+                "%s: Posting task to message loop for thread %s failed",
+                __func__, thread_name_.c_str());
+      return false;
+    }
+    return true;
+  }
+
+  void ShutDown() {
+    if ((run_loop_ != nullptr) && (message_loop_ != nullptr)) {
+      message_loop_->task_runner()->PostTask(FROM_HERE,
+                                             run_loop_->QuitClosure());
+    }
+    thread_free(message_loop_thread_);
+    message_loop_thread_ = nullptr;
+  }
+
+ private:
+  static void RunThread(void* context) {
+    auto wt = static_cast<BtWorkerThread*>(context);
+    wt->Run();
+  }
+
+  void Run() {
+    LOG_INFO(LOG_TAG, "%s: message loop for thread %s started", __func__,
+             thread_name_.c_str());
+    message_loop_ = new base::MessageLoop();
+    run_loop_ = new base::RunLoop();
+    {
+      std::unique_lock<std::mutex> start_lock(start_up_mutex_);
+      started_ = true;
+      start_up_cv_.notify_all();
+    }
+    // Blocking util ShutDown() is called
+    run_loop_->Run();
+    delete message_loop_;
+    message_loop_ = nullptr;
+    delete run_loop_;
+    run_loop_ = nullptr;
+    LOG_INFO(LOG_TAG, "%s: message loop for thread %s finished", __func__,
+             thread_name_.c_str());
+  }
+
+  std::string thread_name_;
+  base::MessageLoop* message_loop_;
+  base::RunLoop* run_loop_;
+  thread_t* message_loop_thread_;
+  // For start-up
+  bool started_;
+  std::mutex start_up_mutex_;
+  std::condition_variable start_up_cv_;
+};
+
+class BtifA2dpSource {
+ public:
+  enum RunState {
+    kStateOff,
+    kStateStartingUp,
+    kStateRunning,
+    kStateShuttingDown
+  };
+
+  BtifA2dpSource()
+      : tx_audio_queue(nullptr),
+        tx_flush(false),
+        media_alarm(nullptr),
+        encoder_interface(nullptr),
+        encoder_interval_ms(0),
+        state_(kStateOff) {}
+
+  void Reset() {
+    fixed_queue_free(tx_audio_queue, nullptr);
+    tx_audio_queue = nullptr;
+    tx_flush = false;
+    alarm_free(media_alarm);
+    media_alarm = nullptr;
+    encoder_interface = nullptr;
+    encoder_interval_ms = 0;
+    stats.Reset();
+    accumulated_stats.Reset();
+    state_ = kStateOff;
+  }
+
+  BtifA2dpSource::RunState State() const { return state_; }
+  std::string StateStr() const {
+    switch (state_) {
+      case kStateOff:
+        return "STATE_OFF";
+      case kStateStartingUp:
+        return "STATE_STARTING_UP";
+      case kStateRunning:
+        return "STATE_RUNNING";
+      case kStateShuttingDown:
+        return "STATE_SHUTTING_DOWN";
+    }
+  }
+
+  void SetState(BtifA2dpSource::RunState state) { state_ = state; }
+
   fixed_queue_t* tx_audio_queue;
   bool tx_flush; /* Discards any outgoing data when true */
   alarm_t* media_alarm;
   const tA2DP_ENCODER_INTERFACE* encoder_interface;
   period_ms_t encoder_interval_ms; /* Local copy of the encoder interval */
-  btif_media_stats_t stats;
-  btif_media_stats_t accumulated_stats;
-} tBTIF_A2DP_SOURCE_CB;
+  BtifMediaStats stats;
+  BtifMediaStats accumulated_stats;
 
-static tBTIF_A2DP_SOURCE_CB btif_a2dp_source_cb;
-static int btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+ private:
+  BtifA2dpSource::RunState state_;
+};
 
-static void btif_a2dp_source_command_ready(fixed_queue_t* queue, void* context);
-static void btif_a2dp_source_startup_delayed(void* context);
-static void btif_a2dp_source_shutdown_delayed(void* context);
+static BtWorkerThread btif_a2dp_source_thread("btif_a2dp_source_thread");
+static BtifA2dpSource btif_a2dp_source_cb;
+
+static void btif_a2dp_source_init_delayed(void);
+static void btif_a2dp_source_startup_delayed(void);
+static void btif_a2dp_source_start_session_delayed(
+    const RawAddress& peer_address);
+static void btif_a2dp_source_end_session_delayed(
+    const RawAddress& peer_address);
+static void btif_a2dp_source_shutdown_delayed(void);
+static void btif_a2dp_source_cleanup_delayed(void);
 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(BT_HDR* p_msg);
-static void btif_a2dp_source_encoder_init_event(BT_HDR* p_msg);
-static void btif_a2dp_source_encoder_user_config_update_event(BT_HDR* p_msg);
-static void btif_a2dp_source_audio_feeding_update_event(BT_HDR* p_msg);
-static void btif_a2dp_source_encoder_init(void);
-static void btif_a2dp_source_encoder_init_req(
-    tBTIF_A2DP_SOURCE_ENCODER_INIT* p_msg);
+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(
+    const RawAddress& peer_address,
+    const btav_a2dp_codec_config_t& codec_user_config);
+static void btif_a2dp_source_audio_feeding_update_event(
+    const btav_a2dp_codec_config_t& codec_audio_config);
 static bool btif_a2dp_source_audio_tx_flush_req(void);
 static void btif_a2dp_source_alarm_cb(void* context);
-static void btif_a2dp_source_audio_handle_timer(void* context);
+static void btif_a2dp_source_audio_handle_timer(void);
 static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len);
-static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n);
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
+                                              uint32_t bytes_read);
 static void log_tstamps_us(const char* comment, uint64_t timestamp_us);
-static void update_scheduling_stats(scheduling_stats_t* stats, uint64_t now_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);
 static void btm_read_tx_power_cb(void* data);
 
-UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
-  switch (event) {
-    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_START)
-    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_STOP)
-    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_FLUSH)
-    CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_INIT)
-    CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE)
-    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_UPDATE)
-    default:
-      break;
-  }
-  return "UNKNOWN A2DP SOURCE EVENT";
-}
-
-void btif_a2dp_source_accumulate_scheduling_stats(scheduling_stats_t* src,
-                                                  scheduling_stats_t* dst) {
+void btif_a2dp_source_accumulate_scheduling_stats(SchedulingStats* src,
+                                                  SchedulingStats* dst) {
   dst->total_updates += src->total_updates;
   dst->last_update_us = src->last_update_us;
   dst->overdue_scheduling_count += src->overdue_scheduling_count;
@@ -226,8 +374,8 @@
   dst->total_scheduling_time_us += src->total_scheduling_time_us;
 }
 
-void btif_a2dp_source_accumulate_stats(btif_media_stats_t* src,
-                                       btif_media_stats_t* dst) {
+void btif_a2dp_source_accumulate_stats(BtifMediaStats* src,
+                                       BtifMediaStats* dst) {
   dst->tx_queue_total_frames += src->tx_queue_total_frames;
   dst->tx_queue_max_frames_per_packet = std::max(
       dst->tx_queue_max_frames_per_packet, src->tx_queue_max_frames_per_packet);
@@ -248,304 +396,346 @@
   dst->media_read_total_underflow_count +=
       src->media_read_total_underflow_count;
   dst->media_read_last_underflow_us = src->media_read_last_underflow_us;
+  if (dst->codec_index < 0) dst->codec_index = src->codec_index;
   btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_enqueue_stats,
                                                &dst->tx_queue_enqueue_stats);
   btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_dequeue_stats,
                                                &dst->tx_queue_dequeue_stats);
-  memset(src, 0, sizeof(btif_media_stats_t));
+  src->Reset();
+}
+
+bool btif_a2dp_source_init(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  // Start A2DP Source media task
+  btif_a2dp_source_thread.StartUp();
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_init_delayed));
+  return true;
+}
+
+static void btif_a2dp_source_init_delayed(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  // Nothing to do
 }
 
 bool btif_a2dp_source_startup(void) {
-  if (btif_a2dp_source_state != BTIF_A2DP_SOURCE_STATE_OFF) {
-    APPL_TRACE_ERROR("%s: A2DP Source media task already running", __func__);
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+
+  if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateOff) {
+    LOG_ERROR(LOG_TAG, "%s: A2DP Source media task already running", __func__);
     return false;
   }
 
-  memset(&btif_a2dp_source_cb, 0, sizeof(btif_a2dp_source_cb));
-  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_STARTING_UP;
-
-  APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
-
-  /* Start A2DP Source media task */
-  btif_a2dp_source_cb.worker_thread =
-      thread_new("btif_a2dp_source_worker_thread");
-  if (btif_a2dp_source_cb.worker_thread == NULL) {
-    APPL_TRACE_ERROR("%s: unable to start up media thread", __func__);
-    btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
-    return false;
-  }
-
+  btif_a2dp_source_cb.Reset();
+  btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateStartingUp);
   btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX);
 
-  btif_a2dp_source_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX);
-  fixed_queue_register_dequeue(
-      btif_a2dp_source_cb.cmd_msg_queue,
-      thread_get_reactor(btif_a2dp_source_cb.worker_thread),
-      btif_a2dp_source_command_ready, NULL);
-
-  APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##");
-
-  /* Schedule the rest of the startup operations */
-  thread_post(btif_a2dp_source_cb.worker_thread,
-              btif_a2dp_source_startup_delayed, NULL);
+  // Schedule the rest of the operations
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_startup_delayed));
 
   return true;
 }
 
-static void btif_a2dp_source_startup_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_source_startup_delayed(void) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+
   raise_priority_a2dp(TASK_HIGH_MEDIA);
   btif_a2dp_control_init();
-  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_RUNNING;
-  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
-      system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+  btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateRunning);
+}
+
+bool btif_a2dp_source_start_session(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
+  btif_a2dp_source_setup_codec(peer_address);
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE,
+      base::Bind(&btif_a2dp_source_start_session_delayed, peer_address));
+  return true;
+}
+
+static void btif_a2dp_source_start_session_delayed(
+    const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
+  if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateRunning) {
+    LOG_ERROR(LOG_TAG, "%s: A2DP Source media task is not running", __func__);
+    return;
+  }
+  if (btif_av_is_a2dp_offload_enabled()) {
+    btif_a2dp_audio_interface_start_session();
+  } else {
+    BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+        system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+  }
+}
+
+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 "
+           "state=%s",
+           __func__, old_peer_address.ToString().c_str(),
+           new_peer_address.ToString().c_str(), logbool(is_streaming).c_str(),
+           btif_a2dp_source_cb.StateStr().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 state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE,
+      base::Bind(&btif_a2dp_source_end_session_delayed, peer_address));
+  return true;
+}
+
+static void btif_a2dp_source_end_session_delayed(
+    const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
+  if (!btif_av_is_a2dp_offload_enabled()) {
+    BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+        system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+  }
+  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateRunning) {
+    btif_av_stream_stop(peer_address);
+  } else {
+    LOG_ERROR(LOG_TAG, "%s: A2DP Source media task is not running", __func__);
+  }
+  if (btif_av_is_a2dp_offload_enabled()) {
+    btif_a2dp_audio_interface_end_session();
+  }
 }
 
 void btif_a2dp_source_shutdown(void) {
-  if ((btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) ||
-      (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN)) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+
+  if ((btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) ||
+      (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateShuttingDown)) {
     return;
   }
 
   /* Make sure no channels are restarted while shutting down */
-  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN;
+  btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateShuttingDown);
 
-  APPL_TRACE_EVENT("## A2DP SOURCE STOP MEDIA THREAD ##");
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_shutdown_delayed));
+}
+
+static void btif_a2dp_source_shutdown_delayed(void) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
   // Stop the timer
   alarm_free(btif_a2dp_source_cb.media_alarm);
-  btif_a2dp_source_cb.media_alarm = NULL;
+  btif_a2dp_source_cb.media_alarm = nullptr;
 
-  // Exit the thread
-  fixed_queue_free(btif_a2dp_source_cb.cmd_msg_queue, NULL);
-  btif_a2dp_source_cb.cmd_msg_queue = NULL;
-  thread_post(btif_a2dp_source_cb.worker_thread,
-              btif_a2dp_source_shutdown_delayed, NULL);
-  thread_free(btif_a2dp_source_cb.worker_thread);
-  btif_a2dp_source_cb.worker_thread = NULL;
+  btif_a2dp_control_cleanup();
+  if (btif_av_is_a2dp_offload_enabled())
+    btif_a2dp_audio_interface_end_session();
+  fixed_queue_free(btif_a2dp_source_cb.tx_audio_queue, nullptr);
+  btif_a2dp_source_cb.tx_audio_queue = nullptr;
+
+  btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateOff);
 }
 
-static void btif_a2dp_source_shutdown_delayed(UNUSED_ATTR void* context) {
-  btif_a2dp_control_cleanup();
-  fixed_queue_free(btif_a2dp_source_cb.tx_audio_queue, NULL);
-  btif_a2dp_source_cb.tx_audio_queue = NULL;
+void btif_a2dp_source_cleanup(void) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
-  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
-      system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+  // Make sure the source is shutdown
+  btif_a2dp_source_shutdown();
+
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_cleanup_delayed));
+
+  // Exit the thread
+  btif_a2dp_source_thread.ShutDown();
+}
+
+static void btif_a2dp_source_cleanup_delayed(void) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+  // Nothing to do
 }
 
 bool btif_a2dp_source_media_task_is_running(void) {
-  return (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_RUNNING);
+  return (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateRunning);
 }
 
 bool btif_a2dp_source_media_task_is_shutting_down(void) {
-  return (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN);
+  return (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateShuttingDown);
 }
 
 bool btif_a2dp_source_is_streaming(void) {
   return alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
 }
 
-static void btif_a2dp_source_command_ready(fixed_queue_t* queue,
-                                           UNUSED_ATTR void* context) {
-  BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
-
-  LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
-              dump_media_event(p_msg->event));
-
-  switch (p_msg->event) {
-    case BTIF_MEDIA_AUDIO_TX_START:
-      btif_a2dp_source_audio_tx_start_event();
-      break;
-    case BTIF_MEDIA_AUDIO_TX_STOP:
-      btif_a2dp_source_audio_tx_stop_event();
-      break;
-    case BTIF_MEDIA_AUDIO_TX_FLUSH:
-      btif_a2dp_source_audio_tx_flush_event(p_msg);
-      break;
-    case BTIF_MEDIA_SOURCE_ENCODER_INIT:
-      btif_a2dp_source_encoder_init_event(p_msg);
-      break;
-    case BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE:
-      btif_a2dp_source_encoder_user_config_update_event(p_msg);
-      break;
-    case BTIF_MEDIA_AUDIO_FEEDING_UPDATE:
-      btif_a2dp_source_audio_feeding_update_event(p_msg);
-      break;
-    default:
-      APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
-      break;
-  }
-
-  osi_free(p_msg);
-  LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
-}
-
-void btif_a2dp_source_setup_codec(void) {
-  APPL_TRACE_EVENT("## A2DP SOURCE SETUP CODEC ##");
-
-  mutex_global_lock();
-
-  /* Init the encoding task */
-  btif_a2dp_source_encoder_init();
-
-  mutex_global_unlock();
-}
-
-void btif_a2dp_source_start_audio_req(void) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTIF_MEDIA_AUDIO_TX_START;
-  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
-  memset(&btif_a2dp_source_cb.stats, 0, sizeof(btif_media_stats_t));
-  // Assign session_start_us to 1 when time_get_os_boottime_us() is 0 to
-  // indicate btif_a2dp_source_start_audio_req() has been called
-  btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
-  if (btif_a2dp_source_cb.stats.session_start_us == 0) {
-    btif_a2dp_source_cb.stats.session_start_us = 1;
-  }
-  btif_a2dp_source_cb.stats.session_end_us = 0;
-}
-
-void btif_a2dp_source_stop_audio_req(void) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
-  p_buf->event = BTIF_MEDIA_AUDIO_TX_STOP;
-
-  /*
-   * Explicitly check whether btif_a2dp_source_cb.cmd_msg_queue is not NULL
-   * to avoid a race condition during shutdown of the Bluetooth stack.
-   * This race condition is triggered when A2DP audio is streaming on
-   * shutdown:
-   * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_stop_audio_req()"
-   * is called to stop the particular audio stream, and this happens right
-   * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()"
-   * processing during the shutdown of the Bluetooth stack.
-   */
-  if (btif_a2dp_source_cb.cmd_msg_queue != NULL) {
-    fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
-  }
-  btif_a2dp_source_cb.stats.session_end_us = time_get_os_boottime_us();
-  btif_a2dp_source_update_metrics();
-  btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
-                                    &btif_a2dp_source_cb.accumulated_stats);
-}
-
-static void btif_a2dp_source_encoder_init(void) {
-  tBTIF_A2DP_SOURCE_ENCODER_INIT msg;
+static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
 
   // Check to make sure the platform has 8 bits/byte since
   // we're using that in frame size calculations now.
   CHECK(CHAR_BIT == 8);
 
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  bta_av_co_get_peer_params(&msg.peer_params);
-  btif_a2dp_source_encoder_init_req(&msg);
+  btif_a2dp_source_audio_tx_flush_req();
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE,
+      base::Bind(&btif_a2dp_source_setup_codec_delayed, peer_address));
 }
 
-static void btif_a2dp_source_encoder_init_req(
-    tBTIF_A2DP_SOURCE_ENCODER_INIT* p_msg) {
-  tBTIF_A2DP_SOURCE_ENCODER_INIT* p_buf =
-      (tBTIF_A2DP_SOURCE_ENCODER_INIT*)osi_malloc(
-          sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT));
+static void btif_a2dp_source_setup_codec_delayed(
+    const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT));
-  p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_INIT;
-  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
-}
+  tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
+  bta_av_co_get_peer_params(peer_address, &peer_params);
 
-static void btif_a2dp_source_encoder_init_event(BT_HDR* p_msg) {
-  tBTIF_A2DP_SOURCE_ENCODER_INIT* p_encoder_init =
-      (tBTIF_A2DP_SOURCE_ENCODER_INIT*)p_msg;
-
-  APPL_TRACE_DEBUG("%s", __func__);
-
+  if (!bta_av_co_set_active_peer(peer_address)) {
+    LOG_ERROR(LOG_TAG, "%s: Cannot stream audio: cannot set active peer to %s",
+              __func__, peer_address.ToString().c_str());
+    return;
+  }
   btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface();
-  if (btif_a2dp_source_cb.encoder_interface == NULL) {
-    APPL_TRACE_ERROR("%s: Cannot stream audio: no source encoder interface",
-                     __func__);
+  if (btif_a2dp_source_cb.encoder_interface == nullptr) {
+    LOG_ERROR(LOG_TAG, "%s: Cannot stream audio: no source encoder interface",
+              __func__);
     return;
   }
 
   A2dpCodecConfig* a2dp_codec_config = bta_av_get_a2dp_current_codec();
   if (a2dp_codec_config == nullptr) {
-    APPL_TRACE_ERROR("%s: Cannot stream audio: current codec is not set",
-                     __func__);
+    LOG_ERROR(LOG_TAG, "%s: Cannot stream audio: current codec is not set",
+              __func__);
     return;
   }
 
   btif_a2dp_source_cb.encoder_interface->encoder_init(
-      &p_encoder_init->peer_params, a2dp_codec_config,
-      btif_a2dp_source_read_callback, btif_a2dp_source_enqueue_callback);
+      &peer_params, a2dp_codec_config, btif_a2dp_source_read_callback,
+      btif_a2dp_source_enqueue_callback);
 
   // Save a local copy of the encoder_interval_ms
   btif_a2dp_source_cb.encoder_interval_ms =
       btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms();
 }
 
-void btif_a2dp_source_encoder_user_config_update_req(
-    const btav_a2dp_codec_config_t& codec_user_config) {
-  tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE* p_buf =
-      (tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE*)osi_malloc(
-          sizeof(tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE));
+void btif_a2dp_source_start_audio_req(void) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  p_buf->user_config = codec_user_config;
-  p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE;
-  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_audio_tx_start_event));
 }
 
-static void btif_a2dp_source_encoder_user_config_update_event(BT_HDR* p_msg) {
-  tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE* p_user_config =
-      (tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE*)p_msg;
+void btif_a2dp_source_stop_audio_req(void) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  APPL_TRACE_DEBUG("%s", __func__);
-  if (!bta_av_co_set_codec_user_config(p_user_config->user_config)) {
-    APPL_TRACE_ERROR("%s: cannot update codec user configuration", __func__);
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_audio_tx_stop_event));
+}
+
+void btif_a2dp_source_encoder_user_config_update_req(
+    const RawAddress& peer_address,
+    const btav_a2dp_codec_config_t& codec_user_config) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_encoder_user_config_update_event,
+                            peer_address, codec_user_config));
+}
+
+static void btif_a2dp_source_encoder_user_config_update_event(
+    const RawAddress& peer_address,
+    const btav_a2dp_codec_config_t& codec_user_config) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+           peer_address.ToString().c_str(),
+           btif_a2dp_source_cb.StateStr().c_str());
+  if (!bta_av_co_set_codec_user_config(peer_address, codec_user_config)) {
+    LOG_ERROR(LOG_TAG, "%s: cannot update codec user configuration", __func__);
   }
 }
 
 void btif_a2dp_source_feeding_update_req(
     const btav_a2dp_codec_config_t& codec_audio_config) {
-  tBTIF_A2DP_AUDIO_FEEDING_UPDATE* p_buf =
-      (tBTIF_A2DP_AUDIO_FEEDING_UPDATE*)osi_malloc(
-          sizeof(tBTIF_A2DP_AUDIO_FEEDING_UPDATE));
-
-  p_buf->feeding_params = codec_audio_config;
-  p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_UPDATE;
-  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_audio_feeding_update_event,
+                            codec_audio_config));
 }
 
-static void btif_a2dp_source_audio_feeding_update_event(BT_HDR* p_msg) {
-  tBTIF_A2DP_AUDIO_FEEDING_UPDATE* p_feeding =
-      (tBTIF_A2DP_AUDIO_FEEDING_UPDATE*)p_msg;
-
-  APPL_TRACE_DEBUG("%s", __func__);
-  if (!bta_av_co_set_codec_audio_config(p_feeding->feeding_params)) {
-    APPL_TRACE_ERROR("%s: cannot update codec audio feeding parameters",
-                     __func__);
+static void btif_a2dp_source_audio_feeding_update_event(
+    const btav_a2dp_codec_config_t& codec_audio_config) {
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+  if (!bta_av_co_set_codec_audio_config(codec_audio_config)) {
+    LOG_ERROR(LOG_TAG, "%s: cannot update codec audio feeding parameters",
+              __func__);
   }
 }
 
 void btif_a2dp_source_on_idle(void) {
-  if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
 
   /* Make sure media task is stopped */
   btif_a2dp_source_stop_audio_req();
 }
 
 void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
-  APPL_TRACE_EVENT("## ON A2DP SOURCE STOPPED ##");
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
 
   /* allow using this api for other than suspend */
-  if (p_av_suspend != NULL) {
+  if (p_av_suspend != nullptr) {
     if (p_av_suspend->status != BTA_AV_SUCCESS) {
-      APPL_TRACE_EVENT("AV STOP FAILED (%d)", p_av_suspend->status);
+      LOG_ERROR(LOG_TAG, "%s: A2DP stop request failed: status=%d", __func__,
+                p_av_suspend->status);
       if (p_av_suspend->initiator) {
-        APPL_TRACE_WARNING("%s: A2DP stop request failed: status = %d",
-                           __func__, p_av_suspend->status);
+        LOG_WARN(LOG_TAG, "%s: A2DP stop request failed: status=%d", __func__,
+                 p_av_suspend->status);
         btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
       }
       return;
@@ -563,15 +753,16 @@
 }
 
 void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
-  APPL_TRACE_EVENT("## ON A2DP SOURCE SUSPENDED ##");
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
 
   /* check for status failures */
   if (p_av_suspend->status != BTA_AV_SUCCESS) {
     if (p_av_suspend->initiator) {
-      APPL_TRACE_WARNING("%s: A2DP suspend request failed: status = %d",
-                         __func__, p_av_suspend->status);
+      LOG_WARN(LOG_TAG, "%s: A2DP suspend request failed: status=%d", __func__,
+               p_av_suspend->status);
       btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
     }
   }
@@ -587,50 +778,79 @@
 
 /* when true media task discards any tx frames */
 void btif_a2dp_source_set_tx_flush(bool enable) {
-  APPL_TRACE_EVENT("## DROP TX %d ##", enable);
+  LOG_INFO(LOG_TAG, "%s: enable=%s state=%s", __func__,
+           (enable) ? "true" : "false", btif_a2dp_source_cb.StateStr().c_str());
   btif_a2dp_source_cb.tx_flush = enable;
 }
 
 static void btif_a2dp_source_audio_tx_start_event(void) {
-  APPL_TRACE_DEBUG(
-      "%s media_alarm is %srunning, streaming %s", __func__,
-      alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
-      btif_a2dp_source_is_streaming() ? "true" : "false");
+  LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s state=%s",
+           __func__,
+           alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+           btif_a2dp_source_is_streaming() ? "true" : "false",
+           btif_a2dp_source_cb.StateStr().c_str());
+
+  if (btif_av_is_a2dp_offload_enabled()) return;
 
   /* Reset the media feeding state */
-  CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
+  CHECK(btif_a2dp_source_cb.encoder_interface != nullptr);
   btif_a2dp_source_cb.encoder_interface->feeding_reset();
 
   APPL_TRACE_EVENT(
-      "starting timer %dms",
+      "%s: starting timer %" PRIu64 " ms", __func__,
       btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms());
-
   alarm_free(btif_a2dp_source_cb.media_alarm);
   btif_a2dp_source_cb.media_alarm =
       alarm_new_periodic("btif.a2dp_source_media_alarm");
-  if (btif_a2dp_source_cb.media_alarm == NULL) {
-    LOG_ERROR(LOG_TAG, "%s unable to allocate media alarm", __func__);
+  if (btif_a2dp_source_cb.media_alarm == nullptr) {
+    LOG_ERROR(LOG_TAG, "%s: unable to allocate media alarm", __func__);
     return;
   }
 
   alarm_set(btif_a2dp_source_cb.media_alarm,
             btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(),
-            btif_a2dp_source_alarm_cb, NULL);
+            btif_a2dp_source_alarm_cb, nullptr);
+
+  btif_a2dp_source_cb.stats.Reset();
+  // Assign session_start_us to 1 when time_get_os_boottime_us() is 0 to
+  // indicate btif_a2dp_source_start_audio_req() has been called
+  btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
+  if (btif_a2dp_source_cb.stats.session_start_us == 0) {
+    btif_a2dp_source_cb.stats.session_start_us = 1;
+  }
+  btif_a2dp_source_cb.stats.session_end_us = 0;
+  A2dpCodecConfig* codec_config = bta_av_get_a2dp_current_codec();
+  if (codec_config != nullptr) {
+    btif_a2dp_source_cb.stats.codec_index = codec_config->codecIndex();
+  }
 }
 
 static void btif_a2dp_source_audio_tx_stop_event(void) {
-  APPL_TRACE_DEBUG(
-      "%s media_alarm is %srunning, streaming %s", __func__,
-      alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
-      btif_a2dp_source_is_streaming() ? "true" : "false");
+  LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s state=%s",
+           __func__,
+           alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+           btif_a2dp_source_is_streaming() ? "true" : "false",
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  const bool send_ack = btif_a2dp_source_is_streaming();
+  if (btif_av_is_a2dp_offload_enabled()) return;
+
+  btif_a2dp_source_cb.stats.session_end_us = time_get_os_boottime_us();
+  btif_a2dp_source_update_metrics();
+  btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
+                                    &btif_a2dp_source_cb.accumulated_stats);
+
+  uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
+  uint16_t event;
+
+  // Keep track of audio data still left in the pipe
+  btif_a2dp_control_log_bytes_read(
+      UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, &event, p_buf, sizeof(p_buf)));
 
   /* Stop the timer first */
   alarm_free(btif_a2dp_source_cb.media_alarm);
-  btif_a2dp_source_cb.media_alarm = NULL;
+  btif_a2dp_source_cb.media_alarm = nullptr;
 
-  UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+  UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO);
 
   /*
    * Try to send acknowldegment once the media stream is
@@ -645,50 +865,54 @@
    * to get the ACK for any pending command in such cases.
    */
 
-  if (send_ack) btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+  btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
 
   /* audio engine stopped, reset tx suspended flag */
   btif_a2dp_source_cb.tx_flush = false;
 
   /* Reset the media feeding state */
-  if (btif_a2dp_source_cb.encoder_interface != NULL)
+  if (btif_a2dp_source_cb.encoder_interface != nullptr)
     btif_a2dp_source_cb.encoder_interface->feeding_reset();
 }
 
 static void btif_a2dp_source_alarm_cb(UNUSED_ATTR void* context) {
-  thread_post(btif_a2dp_source_cb.worker_thread,
-              btif_a2dp_source_audio_handle_timer, NULL);
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_audio_handle_timer));
 }
 
-static void btif_a2dp_source_audio_handle_timer(UNUSED_ATTR void* context) {
+static void btif_a2dp_source_audio_handle_timer(void) {
+  if (btif_av_is_a2dp_offload_enabled()) return;
+
   uint64_t timestamp_us = time_get_os_boottime_us();
   log_tstamps_us("A2DP Source tx timer", timestamp_us);
 
-  if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
-    CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
-    size_t transmit_queue_length =
-        fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
-#ifndef OS_GENERIC
-    ATRACE_INT("btif TX queue", transmit_queue_length);
-#endif
-    if (btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length !=
-        NULL) {
-      btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length(
-          transmit_queue_length);
-    }
-    btif_a2dp_source_cb.encoder_interface->send_frames(timestamp_us);
-    bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
-    update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats,
-                            timestamp_us,
-                            btif_a2dp_source_cb.encoder_interval_ms * 1000);
-  } else {
-    APPL_TRACE_ERROR("ERROR Media task Scheduled after Suspend");
+  if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+    LOG_ERROR(LOG_TAG, "%s: ERROR Media task Scheduled after Suspend",
+              __func__);
+    return;
   }
+  CHECK(btif_a2dp_source_cb.encoder_interface != nullptr);
+  size_t transmit_queue_length =
+      fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+#ifndef OS_GENERIC
+  ATRACE_INT("btif TX queue", transmit_queue_length);
+#endif
+  if (btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length !=
+      nullptr) {
+    btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length(
+        transmit_queue_length);
+  }
+  btif_a2dp_source_cb.encoder_interface->send_frames(timestamp_us);
+  bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
+  update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats,
+                          timestamp_us,
+                          btif_a2dp_source_cb.encoder_interval_ms * 1000);
 }
 
 static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) {
   uint16_t event;
-  uint32_t bytes_read = UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);
+  uint32_t bytes_read =
+      UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);
 
   if (bytes_read < len) {
     LOG_WARN(LOG_TAG, "%s: UNDERFLOW: ONLY READ %d BYTES OUT OF %d", __func__,
@@ -703,8 +927,10 @@
   return bytes_read;
 }
 
-static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n) {
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
+                                              uint32_t bytes_read) {
   uint64_t now_us = time_get_os_boottime_us();
+  btif_a2dp_control_log_bytes_read(bytes_read);
 
   /* Check if timer was stopped (media task stopped) */
   if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
@@ -747,7 +973,7 @@
     }
 
     // Request additional debug info if we had to flush buffers
-    RawAddress peer_bda = btif_av_get_addr();
+    RawAddress peer_bda = btif_av_source_active_peer();
     tBTM_STATUS status = BTM_ReadRSSI(peer_bda, btm_read_rssi_cb);
     if (status != BTM_CMD_STARTED) {
       LOG_WARN(LOG_TAG, "%s: Cannot read RSSI: status %d", __func__, status);
@@ -776,18 +1002,20 @@
   btif_a2dp_source_cb.stats.tx_queue_total_frames += frames_n;
   btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet = std::max(
       frames_n, btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet);
-  CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
+  CHECK(btif_a2dp_source_cb.encoder_interface != nullptr);
 
   fixed_queue_enqueue(btif_a2dp_source_cb.tx_audio_queue, p_buf);
 
   return true;
 }
 
-static void btif_a2dp_source_audio_tx_flush_event(UNUSED_ATTR BT_HDR* p_msg) {
+static void btif_a2dp_source_audio_tx_flush_event(void) {
   /* Flush all enqueued audio buffers (encoded) */
-  APPL_TRACE_DEBUG("%s", __func__);
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
+  if (btif_av_is_a2dp_offload_enabled()) return;
 
-  if (btif_a2dp_source_cb.encoder_interface != NULL)
+  if (btif_a2dp_source_cb.encoder_interface != nullptr)
     btif_a2dp_source_cb.encoder_interface->feeding_flush();
 
   btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages +=
@@ -796,27 +1024,15 @@
       time_get_os_boottime_us();
   fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free);
 
-  UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, NULL);
+  UIPC_Ioctl(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, nullptr);
 }
 
 static bool btif_a2dp_source_audio_tx_flush_req(void) {
-  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+  LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+           btif_a2dp_source_cb.StateStr().c_str());
 
-  p_buf->event = BTIF_MEDIA_AUDIO_TX_FLUSH;
-
-  /*
-   * Explicitly check whether the btif_a2dp_source_cb.cmd_msg_queue is not
-   * NULL to avoid a race condition during shutdown of the Bluetooth stack.
-   * This race condition is triggered when A2DP audio is streaming on
-   * shutdown:
-   * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_audio_tx_flush_req()"
-   * is called to stop the particular audio stream, and this happens right
-   * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()"
-   * processing during the shutdown of the Bluetooth stack.
-   */
-  if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
-    fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
-
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_audio_tx_flush_event));
   return true;
 }
 
@@ -827,7 +1043,7 @@
 
   btif_a2dp_source_cb.stats.tx_queue_total_readbuf_calls++;
   btif_a2dp_source_cb.stats.tx_queue_last_readbuf_us = now_us;
-  if (p_buf != NULL) {
+  if (p_buf != nullptr) {
     // Update the statistics
     update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_dequeue_stats,
                             now_us,
@@ -839,13 +1055,14 @@
 
 static void log_tstamps_us(const char* comment, uint64_t timestamp_us) {
   static uint64_t prev_us = 0;
-  APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment,
-                   timestamp_us, timestamp_us - prev_us,
+  APPL_TRACE_DEBUG("%s: [%s] ts %08" PRIu64 ", diff : %08" PRIu64
+                   ", queue sz %zu",
+                   __func__, comment, timestamp_us, timestamp_us - prev_us,
                    fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue));
   prev_us = timestamp_us;
 }
 
-static void update_scheduling_stats(scheduling_stats_t* stats, uint64_t now_us,
+static void update_scheduling_stats(SchedulingStats* stats, uint64_t now_us,
                                     uint64_t expected_delta) {
   uint64_t last_us = stats->last_update_us;
 
@@ -888,12 +1105,9 @@
   btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
                                     &btif_a2dp_source_cb.accumulated_stats);
   uint64_t now_us = time_get_os_boottime_us();
-  btif_media_stats_t* accumulated_stats =
-      &btif_a2dp_source_cb.accumulated_stats;
-  scheduling_stats_t* enqueue_stats =
-      &accumulated_stats->tx_queue_enqueue_stats;
-  scheduling_stats_t* dequeue_stats =
-      &accumulated_stats->tx_queue_dequeue_stats;
+  BtifMediaStats* accumulated_stats = &btif_a2dp_source_cb.accumulated_stats;
+  SchedulingStats* enqueue_stats = &accumulated_stats->tx_queue_enqueue_stats;
+  SchedulingStats* dequeue_stats = &accumulated_stats->tx_queue_dequeue_stats;
   size_t ave_size;
   uint64_t ave_time_us;
 
@@ -1050,53 +1264,49 @@
       (unsigned long long)dequeue_stats->max_premature_scheduling_delta_us /
           1000,
       (unsigned long long)ave_time_us / 1000);
-
-  //
-  // Codec-specific stats
-  //
-  A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs();
-  if (a2dp_codecs != nullptr) {
-    a2dp_codecs->debug_codec_dump(fd);
-  }
 }
 
-void btif_a2dp_source_update_metrics(void) {
-  btif_media_stats_t* stats = &btif_a2dp_source_cb.stats;
-  scheduling_stats_t* enqueue_stats = &stats->tx_queue_enqueue_stats;
+static void btif_a2dp_source_update_metrics(void) {
+  BtifMediaStats stats = btif_a2dp_source_cb.stats;
+  SchedulingStats enqueue_stats = stats.tx_queue_enqueue_stats;
   A2dpSessionMetrics metrics;
+  metrics.codec_index = stats.codec_index;
+  metrics.is_a2dp_offload = btif_av_is_a2dp_offload_enabled();
   // session_start_us is 0 when btif_a2dp_source_start_audio_req() is not called
   // mark the metric duration as invalid (-1) in this case
-  if (stats->session_start_us != 0) {
-    int64_t session_end_us = stats->session_end_us == 0
+  if (stats.session_start_us != 0) {
+    int64_t session_end_us = stats.session_end_us == 0
                                  ? time_get_os_boottime_us()
-                                 : stats->session_end_us;
-    metrics.audio_duration_ms =
-        (session_end_us - stats->session_start_us) / 1000;
+                                 : stats.session_end_us;
+    if (static_cast<uint64_t>(session_end_us) > stats.session_start_us) {
+      metrics.audio_duration_ms =
+          (session_end_us - stats.session_start_us) / 1000;
+    }
   }
 
-  if (enqueue_stats->total_updates > 1) {
+  if (enqueue_stats.total_updates > 1) {
     metrics.media_timer_min_ms =
         btif_a2dp_source_cb.encoder_interval_ms -
-        (enqueue_stats->max_premature_scheduling_delta_us / 1000);
+        (enqueue_stats.max_premature_scheduling_delta_us / 1000);
     metrics.media_timer_max_ms =
         btif_a2dp_source_cb.encoder_interval_ms +
-        (enqueue_stats->max_overdue_scheduling_delta_us / 1000);
+        (enqueue_stats.max_overdue_scheduling_delta_us / 1000);
 
-    metrics.total_scheduling_count = enqueue_stats->overdue_scheduling_count +
-                                     enqueue_stats->premature_scheduling_count +
-                                     enqueue_stats->exact_scheduling_count;
+    metrics.total_scheduling_count = enqueue_stats.overdue_scheduling_count +
+                                     enqueue_stats.premature_scheduling_count +
+                                     enqueue_stats.exact_scheduling_count;
     if (metrics.total_scheduling_count > 0) {
-      metrics.media_timer_avg_ms = enqueue_stats->total_scheduling_time_us /
+      metrics.media_timer_avg_ms = enqueue_stats.total_scheduling_time_us /
                                    (1000 * metrics.total_scheduling_count);
     }
 
-    metrics.buffer_overruns_max_count = stats->tx_queue_max_dropped_messages;
-    metrics.buffer_overruns_total = stats->tx_queue_total_dropped_messages;
-    metrics.buffer_underruns_count = stats->media_read_total_underflow_count;
+    metrics.buffer_overruns_max_count = stats.tx_queue_max_dropped_messages;
+    metrics.buffer_overruns_total = stats.tx_queue_total_dropped_messages;
+    metrics.buffer_underruns_count = stats.media_read_total_underflow_count;
     metrics.buffer_underruns_average = 0;
     if (metrics.buffer_underruns_count > 0) {
       metrics.buffer_underruns_average =
-          stats->media_read_total_underflow_bytes /
+          stats.media_read_total_underflow_bytes /
           metrics.buffer_underruns_count;
     }
   }
@@ -1105,24 +1315,24 @@
 
 static void btm_read_rssi_cb(void* data) {
   if (data == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s Read RSSI request timed out", __func__);
+    LOG_ERROR(LOG_TAG, "%s: Read RSSI request timed out", __func__);
     return;
   }
 
   tBTM_RSSI_RESULT* result = (tBTM_RSSI_RESULT*)data;
   if (result->status != BTM_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s unable to read remote RSSI (status %d)", __func__,
+    LOG_ERROR(LOG_TAG, "%s: unable to read remote RSSI (status %d)", __func__,
               result->status);
     return;
   }
 
-  LOG_WARN(LOG_TAG, "%s device: %s, rssi: %d", __func__,
+  LOG_WARN(LOG_TAG, "%s: device: %s, rssi: %d", __func__,
            result->rem_bda.ToString().c_str(), result->rssi);
 }
 
 static void btm_read_failed_contact_counter_cb(void* data) {
   if (data == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s Read Failed Contact Counter request timed out",
+    LOG_ERROR(LOG_TAG, "%s: Read Failed Contact Counter request timed out",
               __func__);
     return;
   }
@@ -1130,18 +1340,18 @@
   tBTM_FAILED_CONTACT_COUNTER_RESULT* result =
       (tBTM_FAILED_CONTACT_COUNTER_RESULT*)data;
   if (result->status != BTM_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s unable to read Failed Contact Counter (status %d)",
+    LOG_ERROR(LOG_TAG, "%s: unable to read Failed Contact Counter (status %d)",
               __func__, result->status);
     return;
   }
 
-  LOG_WARN(LOG_TAG, "%s device: %s, Failed Contact Counter: %u", __func__,
+  LOG_WARN(LOG_TAG, "%s: device: %s, Failed Contact Counter: %u", __func__,
            result->rem_bda.ToString().c_str(), result->failed_contact_counter);
 }
 
 static void btm_read_automatic_flush_timeout_cb(void* data) {
   if (data == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s Read Automatic Flush Timeout request timed out",
+    LOG_ERROR(LOG_TAG, "%s: Read Automatic Flush Timeout request timed out",
               __func__);
     return;
   }
@@ -1149,28 +1359,28 @@
   tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT* result =
       (tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT*)data;
   if (result->status != BTM_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s unable to read Automatic Flush Timeout (status %d)",
+    LOG_ERROR(LOG_TAG, "%s: unable to read Automatic Flush Timeout (status %d)",
               __func__, result->status);
     return;
   }
 
-  LOG_WARN(LOG_TAG, "%s device: %s, Automatic Flush Timeout: %u", __func__,
+  LOG_WARN(LOG_TAG, "%s: device: %s, Automatic Flush Timeout: %u", __func__,
            result->rem_bda.ToString().c_str(), result->automatic_flush_timeout);
 }
 
 static void btm_read_tx_power_cb(void* data) {
   if (data == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s Read Tx Power request timed out", __func__);
+    LOG_ERROR(LOG_TAG, "%s: Read Tx Power request timed out", __func__);
     return;
   }
 
   tBTM_TX_POWER_RESULT* result = (tBTM_TX_POWER_RESULT*)data;
   if (result->status != BTM_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s unable to read Tx Power (status %d)", __func__,
+    LOG_ERROR(LOG_TAG, "%s: unable to read Tx Power (status %d)", __func__,
               result->status);
     return;
   }
 
-  LOG_WARN(LOG_TAG, "%s device: %s, Tx Power: %d", __func__,
+  LOG_WARN(LOG_TAG, "%s: device: %s, Tx Power: %d", __func__,
            result->rem_bda.ToString().c_str(), result->tx_power);
 }
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index 0178e36..8d416c1 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2016 Broadcom Corporation
+ *  Copyright 2009-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,8 +20,11 @@
 
 #include "btif_av.h"
 
+#include <base/bind.h>
 #include <base/logging.h>
+#include <base/strings/stringprintf.h>
 #include <string.h>
+#include <map>
 
 #include <hardware/bluetooth.h>
 #include <hardware/bt_av.h>
@@ -30,87 +33,556 @@
 #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"
 #include "btif_a2dp_control.h"
 #include "btif_a2dp_sink.h"
 #include "btif_av_co.h"
 #include "btif_profile_queue.h"
+#include "btif_rc.h"
+#include "btif_state_machine.h"
 #include "btif_util.h"
 #include "btu.h"
 #include "osi/include/allocator.h"
 #include "osi/include/osi.h"
+#include "osi/include/properties.h"
 
 /*****************************************************************************
  *  Constants & Macros
  *****************************************************************************/
-#define BTIF_AV_SERVICE_NAME "Advanced Audio"
-#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink"
-
-#define BTIF_TIMEOUT_AV_OPEN_ON_RC_MS (2 * 1000)
-
-typedef enum {
-  BTIF_AV_STATE_IDLE = 0x0,
-  BTIF_AV_STATE_OPENING,
-  BTIF_AV_STATE_OPENED,
-  BTIF_AV_STATE_STARTED,
-  BTIF_AV_STATE_CLOSING
-} btif_av_state_t;
-
-/* Should not need dedicated suspend state as actual actions are no
-   different than open state. Suspend flags are needed however to prevent
-   media task from trying to restart stream during remote suspend or while
-   we are in the process of a local suspend */
-
-#define BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1
-#define BTIF_AV_FLAG_REMOTE_SUSPEND 0x2
-#define BTIF_AV_FLAG_PENDING_START 0x4
-#define BTIF_AV_FLAG_PENDING_STOP 0x8
+static const std::string kBtifAvSourceServiceName = "Advanced Audio Source";
+static const std::string kBtifAvSinkServiceName = "Advanced Audio Sink";
+static constexpr int kDefaultMaxConnectedAudioDevices = 1;
+static constexpr tBTA_AV_HNDL kBtaHandleUnknown = 0;
 
 /*****************************************************************************
  *  Local type definitions
  *****************************************************************************/
 
 typedef struct {
-  tBTA_AV_HNDL bta_handle;
-  RawAddress peer_bda;
-  bool self_initiated_connection;
-  btif_sm_handle_t sm_handle;
-  uint8_t flags;
-  tBTA_AV_EDR edr;
-  uint8_t peer_sep; /* sep type of peer device */
-  std::vector<btav_a2dp_codec_config_t> codec_priorities;
-} btif_av_cb_t;
-
-typedef struct {
-  RawAddress* target_bda;
-  uint16_t uuid;
-} btif_av_connect_req_t;
-
-typedef struct {
   int sample_rate;
   int channel_count;
-  RawAddress peer_bd;
+  RawAddress peer_address;
 } btif_av_sink_config_req_t;
 
+/**
+ * BTIF AV events
+ */
+typedef enum {
+  /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */
+  BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT,
+  BTIF_AV_DISCONNECT_REQ_EVT,
+  BTIF_AV_START_STREAM_REQ_EVT,
+  BTIF_AV_STOP_STREAM_REQ_EVT,
+  BTIF_AV_SUSPEND_STREAM_REQ_EVT,
+  BTIF_AV_SINK_CONFIG_REQ_EVT,
+  BTIF_AV_ACL_DISCONNECTED,
+  BTIF_AV_OFFLOAD_START_REQ_EVT,
+  BTIF_AV_AVRCP_OPEN_EVT,
+  BTIF_AV_AVRCP_CLOSE_EVT,
+  BTIF_AV_AVRCP_REMOTE_PLAY_EVT,
+} btif_av_sm_event_t;
+
+class BtifAvEvent {
+ public:
+  BtifAvEvent(uint32_t event, const void* p_data, size_t data_length);
+  BtifAvEvent(const BtifAvEvent& other);
+  BtifAvEvent() = delete;
+  ~BtifAvEvent();
+  BtifAvEvent& operator=(const BtifAvEvent& other);
+
+  uint32_t Event() const { return event_; }
+  void* Data() const { return data_; }
+  size_t DataLength() const { return data_length_; }
+  std::string ToString() const;
+  static std::string EventName(uint32_t event);
+
+ private:
+  void DeepCopy(uint32_t event, const void* p_data, size_t data_length);
+  void DeepFree();
+
+  uint32_t event_;
+  void* data_;
+  size_t data_length_;
+};
+
+class BtifAvPeer;
+
+// Should not need dedicated Suspend state as actual actions are no
+// different than Open state. Suspend flags are needed however to prevent
+// media task from trying to restart stream during remote Suspend or while
+// we are in the process of a local Suspend.
+class BtifAvStateMachine : public BtifStateMachine {
+ public:
+  enum {
+    kStateIdle,     // AVDTP disconnected
+    kStateOpening,  // Opening AVDTP connection
+    kStateOpened,   // AVDTP is in OPEN state
+    kStateStarted,  // A2DP stream started
+    kStateClosing,  // Closing AVDTP connection
+  };
+
+  class StateIdle : public State {
+   public:
+    StateIdle(BtifAvStateMachine& sm)
+        : State(sm, kStateIdle), peer_(sm.Peer()) {}
+    void OnEnter() override;
+    void OnExit() override;
+    bool ProcessEvent(uint32_t event, void* p_data) override;
+
+   private:
+    BtifAvPeer& peer_;
+  };
+
+  class StateOpening : public State {
+   public:
+    StateOpening(BtifAvStateMachine& sm)
+        : State(sm, kStateOpening), peer_(sm.Peer()) {}
+    void OnEnter() override;
+    void OnExit() override;
+    bool ProcessEvent(uint32_t event, void* p_data) override;
+
+   private:
+    BtifAvPeer& peer_;
+  };
+
+  class StateOpened : public State {
+   public:
+    StateOpened(BtifAvStateMachine& sm)
+        : State(sm, kStateOpened), peer_(sm.Peer()) {}
+    void OnEnter() override;
+    void OnExit() override;
+    bool ProcessEvent(uint32_t event, void* p_data) override;
+
+   private:
+    BtifAvPeer& peer_;
+  };
+
+  class StateStarted : public State {
+   public:
+    StateStarted(BtifAvStateMachine& sm)
+        : State(sm, kStateStarted), peer_(sm.Peer()) {}
+    void OnEnter() override;
+    void OnExit() override;
+    bool ProcessEvent(uint32_t event, void* p_data) override;
+
+   private:
+    BtifAvPeer& peer_;
+  };
+
+  class StateClosing : public State {
+   public:
+    StateClosing(BtifAvStateMachine& sm)
+        : State(sm, kStateClosing), peer_(sm.Peer()) {}
+    void OnEnter() override;
+    void OnExit() override;
+    bool ProcessEvent(uint32_t event, void* p_data) override;
+
+   private:
+    BtifAvPeer& peer_;
+  };
+
+  BtifAvStateMachine(BtifAvPeer& btif_av_peer) : peer_(btif_av_peer) {
+    state_idle_ = new StateIdle(*this);
+    state_opening_ = new StateOpening(*this);
+    state_opened_ = new StateOpened(*this);
+    state_started_ = new StateStarted(*this);
+    state_closing_ = new StateClosing(*this);
+
+    AddState(state_idle_);
+    AddState(state_opening_);
+    AddState(state_opened_);
+    AddState(state_started_);
+    AddState(state_closing_);
+    SetInitialState(state_idle_);
+  }
+
+  BtifAvPeer& Peer() { return peer_; }
+
+ private:
+  BtifAvPeer& peer_;
+  StateIdle* state_idle_;
+  StateOpening* state_opening_;
+  StateOpened* state_opened_;
+  StateStarted* state_started_;
+  StateClosing* state_closing_;
+};
+
+class BtifAvPeer {
+ public:
+  enum {
+    kFlagLocalSuspendPending = 0x1,
+    kFlagRemoteSuspend = 0x2,
+    kFlagPendingStart = 0x4,
+    kFlagPendingStop = 0x8,
+  };
+  static constexpr period_ms_t kTimeoutAvOpenOnRcMs = 2 * 1000;  // 2s
+
+  BtifAvPeer(const RawAddress& peer_address, uint8_t peer_sep,
+             tBTA_AV_HNDL bta_handle, uint8_t peer_id);
+  ~BtifAvPeer();
+
+  bt_status_t Init();
+  void Cleanup();
+
+  /**
+   * Check whether the peer can be deleted.
+   *
+   * @return true if the pair can be deleted, otherwise false
+   */
+  bool CanBeDeleted() const;
+
+  /**
+   * Check whether the peer is the active one.
+   *
+   * @return true if this peer is the active one
+   */
+  bool IsActivePeer() const { return (PeerAddress() == ActivePeerAddress()); }
+
+  /**
+   * Get the address of the active peer.
+   *
+   * @return the address of the active peer
+   */
+  const RawAddress& ActivePeerAddress() const;
+
+  const RawAddress& PeerAddress() const { return peer_address_; }
+  bool IsSource() const { return (peer_sep_ == AVDT_TSEP_SRC); }
+  bool IsSink() const { return (peer_sep_ == AVDT_TSEP_SNK); }
+  uint8_t PeerSep() const { return peer_sep_; }
+  /**
+   * Get the local device's Service Class UUID
+   *
+   * @return the local device's Service Class UUID: UUID_SERVCLASS_AUDIO_SOURCE
+   * or UUID_SERVCLASS_AUDIO_SINK
+   */
+  uint16_t LocalUuidServiceClass() const {
+    return (IsSink() ? UUID_SERVCLASS_AUDIO_SOURCE : UUID_SERVCLASS_AUDIO_SINK);
+  }
+  tBTA_AV_HNDL BtaHandle() const { return bta_handle_; }
+  void SetBtaHandle(tBTA_AV_HNDL bta_handle) { bta_handle_ = bta_handle; }
+  uint8_t PeerId() const { return peer_id_; }
+
+  BtifAvStateMachine& StateMachine() { return state_machine_; }
+  const BtifAvStateMachine& StateMachine() const { return state_machine_; }
+  alarm_t* AvOpenOnRcTimer() { return av_open_on_rc_timer_; }
+  const alarm_t* AvOpenOnRcTimer() const { return av_open_on_rc_timer_; }
+
+  void SetEdr(tBTA_AV_EDR edr) { edr_ = edr; }
+  bool IsEdr() const { return (edr_ != 0); }
+  bool Is3Mbps() const { return ((edr_ & BTA_AV_EDR_3MBPS) != 0); }
+
+  bool IsConnected() const;
+  bool IsStreaming() const;
+
+  /**
+   * Check whether any of the flags specified by the bitlags mask is set.
+   *
+   * @param bitflags_mask the bitflags to check
+   * @return true if any of the flags to check is set, otherwise false.
+   */
+  bool CheckFlags(uint8_t bitflags_mask) const {
+    return ((flags_ & bitflags_mask) != 0);
+  }
+
+  /**
+   * Set only the flags as specified by the bitflags mask.
+   *
+   * @param bitflags_mask the bitflags to set
+   */
+  void SetFlags(uint8_t bitflags_mask) { flags_ |= bitflags_mask; }
+
+  /**
+   * Clear only the flags as specified by the bitflags mask.
+   *
+   * @param bitflags_mask the bitflags to clear
+   */
+  void ClearFlags(uint8_t bitflags_mask) { flags_ &= ~bitflags_mask; }
+
+  /**
+   * Clear all flags.
+   */
+  void ClearAllFlags() { flags_ = 0; }
+
+  /**
+   * Get a string representation of the flags that are set.
+   */
+  std::string FlagsToString() const;
+
+  bool SelfInitiatedConnection() const { return self_initiated_connection_; }
+  void SetSelfInitiatedConnection(bool v) { self_initiated_connection_ = v; }
+
+ private:
+  const RawAddress peer_address_;
+  const uint8_t peer_sep_;  // SEP type of peer device
+  tBTA_AV_HNDL bta_handle_;
+  const uint8_t peer_id_;
+  BtifAvStateMachine state_machine_;
+  alarm_t* av_open_on_rc_timer_;
+  tBTA_AV_EDR edr_;
+  uint8_t flags_;
+  bool self_initiated_connection_;
+};
+
+class BtifAvSource {
+ public:
+  // The PeerId is used as AppId for BTA_AvRegister() purpose
+  static constexpr uint8_t kPeerIdMin = 0;
+  static constexpr uint8_t kPeerIdMax = BTA_AV_NUM_STRS;
+
+  BtifAvSource()
+      : callbacks_(nullptr),
+        enabled_(false),
+        a2dp_offload_enabled_(false),
+        max_connected_peers_(kDefaultMaxConnectedAudioDevices) {}
+  ~BtifAvSource();
+
+  bt_status_t Init(
+      btav_source_callbacks_t* callbacks, int max_connected_audio_devices,
+      const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
+  void Cleanup();
+
+  btav_source_callbacks_t* Callbacks() { return callbacks_; }
+  bool Enabled() const { return enabled_; }
+  bool A2dpOffloadEnabled() const { return a2dp_offload_enabled_; }
+
+  BtifAvPeer* FindPeer(const RawAddress& peer_address);
+  BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle);
+  BtifAvPeer* FindPeerByPeerId(uint8_t peer_id);
+  BtifAvPeer* FindOrCreatePeer(const RawAddress& peer_address,
+                               tBTA_AV_HNDL bta_handle);
+
+  /**
+   * Check whether a connection to a peer is allowed.
+   * The check considers the maximum number of connected peers.
+   *
+   * @param peer_address the peer address to connect to
+   * @return true if connection is allowed, otherwise false
+   */
+  bool AllowedToConnect(const RawAddress& peer_address) const;
+
+  /**
+   * Delete a peer.
+   *
+   * @param peer_address the peer to delete
+   * @return true on success, otherwise false
+   */
+  bool DeletePeer(const RawAddress& peer_address);
+
+  /**
+   * Delete all peers that have transitioned to Idle state and can be deleted.
+   * If a peer was just created/initialized, then it cannot be deleted yet.
+   */
+  void DeleteIdlePeers();
+
+  /**
+   * Get the active peer.
+   *
+   * @return the active peer
+   */
+  const RawAddress& ActivePeer() const { return active_peer_; }
+
+  /**
+   * Set the active peer.
+   *
+   * @param peer_address the active peer address or RawAddress::kEmpty to
+   * reset the active peer
+   * @return true on success, otherwise false
+   */
+  bool SetActivePeer(const RawAddress& peer_address) {
+    LOG_INFO(LOG_TAG, "%s: peer: %s", __PRETTY_FUNCTION__,
+             peer_address.ToString().c_str());
+
+    if (active_peer_ == peer_address) return true;  // Nothing has changed
+    if (peer_address.IsEmpty()) {
+      BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio source",
+                       __func__);
+      if (!bta_av_co_set_active_peer(peer_address)) {
+        BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
+                           __func__);
+      }
+      btif_a2dp_source_end_session(active_peer_);
+      btif_a2dp_source_shutdown();
+      active_peer_ = peer_address;
+      return true;
+    }
+
+    BtifAvPeer* peer = FindPeer(peer_address);
+    if (peer != nullptr && !peer->IsConnected()) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
+                       peer->PeerAddress().ToString().c_str());
+      return false;
+    }
+
+    if (!btif_a2dp_source_restart_session(active_peer_, peer_address)) {
+      return false;
+    }
+    active_peer_ = peer_address;
+    return true;
+  }
+
+  /**
+   * Update source codec configuration for a peer.
+   *
+   * @param peer_address the address of the peer to update
+   * @param codec_preferences the updated codec preferences
+   */
+  void UpdateCodecConfig(
+      const RawAddress& peer_address,
+      const std::vector<btav_a2dp_codec_config_t>& codec_preferences) {
+    // Restart the session if the codec for the active peer is updated
+    bool restart_session =
+        ((active_peer_ == peer_address) && !active_peer_.IsEmpty());
+    if (restart_session) {
+      btif_a2dp_source_end_session(active_peer_);
+    }
+
+    for (auto cp : codec_preferences) {
+      BTIF_TRACE_DEBUG("%s: codec_preference=%s", __func__,
+                       cp.ToString().c_str());
+      btif_a2dp_source_encoder_user_config_update_req(peer_address, cp);
+    }
+    if (restart_session) {
+      btif_a2dp_source_start_session(active_peer_);
+    }
+  }
+
+  const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
+
+  void RegisterAllBtaHandles();
+  void DeregisterAllBtaHandles();
+  void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle);
+
+ private:
+  void CleanupAllPeers();
+
+  btav_source_callbacks_t* callbacks_;
+  bool enabled_;
+  bool a2dp_offload_enabled_;
+  int max_connected_peers_;
+  std::map<RawAddress, BtifAvPeer*> peers_;
+  RawAddress active_peer_;
+  std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;
+};
+
+class BtifAvSink {
+ public:
+  // The PeerId is used as AppId for BTA_AvRegister() purpose
+  static constexpr uint8_t kPeerIdMin = 0;
+  static constexpr uint8_t kPeerIdMax = BTA_AV_NUM_STRS;
+
+  BtifAvSink()
+      : callbacks_(nullptr),
+        enabled_(false),
+        max_connected_peers_(kDefaultMaxConnectedAudioDevices) {}
+  ~BtifAvSink();
+
+  bt_status_t Init(btav_sink_callbacks_t* callbacks);
+  void Cleanup();
+
+  btav_sink_callbacks_t* Callbacks() { return callbacks_; }
+  bool Enabled() const { return enabled_; }
+
+  BtifAvPeer* FindPeer(const RawAddress& peer_address);
+  BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle);
+  BtifAvPeer* FindPeerByPeerId(uint8_t peer_id);
+  BtifAvPeer* FindOrCreatePeer(const RawAddress& peer_address,
+                               tBTA_AV_HNDL bta_handle);
+
+  /**
+   * Check whether a connection to a peer is allowed.
+   * The check considers the maximum number of connected peers.
+   *
+   * @param peer_address the peer address to connect to
+   * @return true if connection is allowed, otherwise false
+   */
+  bool AllowedToConnect(const RawAddress& peer_address) const;
+
+  /**
+   * Delete a peer.
+   *
+   * @param peer_address the peer to delete
+   * @return true on success, otherwise false
+   */
+  bool DeletePeer(const RawAddress& peer_address);
+
+  /**
+   * Delete all peers that have transitioned to Idle state and can be deleted.
+   * If a peer was just created/initialized, then it cannot be deleted yet.
+   */
+  void DeleteIdlePeers();
+
+  /**
+   * Get the active peer.
+   *
+   * @return the active peer
+   */
+  const RawAddress& ActivePeer() const { return active_peer_; }
+
+  /**
+   * Set the active peer.
+   *
+   * @param peer_address the active peer address or RawAddress::kEmpty to
+   * reset the active peer
+   * @return true on success, otherwise false
+   */
+  bool SetActivePeer(const RawAddress& peer_address) {
+    LOG_INFO(LOG_TAG, "%s: peer: %s", __PRETTY_FUNCTION__,
+             peer_address.ToString().c_str());
+
+    if (active_peer_ == peer_address) return true;  // Nothing has changed
+    if (peer_address.IsEmpty()) {
+      BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio sink",
+                       __func__);
+      if (!bta_av_co_set_active_peer(peer_address)) {
+        BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
+                           __func__);
+      }
+      btif_a2dp_sink_end_session(active_peer_);
+      btif_a2dp_sink_shutdown();
+      active_peer_ = peer_address;
+      return true;
+    }
+
+    BtifAvPeer* peer = FindPeer(peer_address);
+    if (peer != nullptr && !peer->IsConnected()) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
+                       peer->PeerAddress().ToString().c_str());
+      return false;
+    }
+
+    if (!btif_a2dp_sink_restart_session(active_peer_, peer_address)) {
+      return false;
+    }
+    active_peer_ = peer_address;
+    return true;
+  }
+
+  const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
+
+  void RegisterAllBtaHandles();
+  void DeregisterAllBtaHandles();
+  void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle);
+
+ private:
+  void CleanupAllPeers();
+
+  btav_sink_callbacks_t* callbacks_;
+  bool enabled_;
+  int max_connected_peers_;
+  std::map<RawAddress, BtifAvPeer*> peers_;
+  RawAddress active_peer_;
+  std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;
+};
+
 /*****************************************************************************
  *  Static variables
  *****************************************************************************/
-static btav_source_callbacks_t* bt_av_src_callbacks = NULL;
-static btav_sink_callbacks_t* bt_av_sink_callbacks = NULL;
-static btif_av_cb_t btif_av_cb = {
-    0, {{0}}, false, 0, 0, 0, 0, std::vector<btav_a2dp_codec_config_t>()};
-static alarm_t* av_open_on_rc_timer = NULL;
-
-/* both interface and media task needs to be ready to alloc incoming request */
-#define CHECK_BTAV_INIT()                                                    \
-  do {                                                                       \
-    if (((bt_av_src_callbacks == NULL) && (bt_av_sink_callbacks == NULL)) || \
-        (btif_av_cb.sm_handle == NULL)) {                                    \
-      BTIF_TRACE_WARNING("%s: BTAV not initialized", __func__);              \
-      return BT_STATUS_NOT_READY;                                            \
-    }                                                                        \
-  } while (0)
+static BtifAvSource btif_av_source;
+static BtifAvSink btif_av_sink;
 
 /* Helper macro to avoid code duplication in the state machine handlers */
 #define CHECK_RC_EVENT(e, d)       \
@@ -126,44 +598,50 @@
     btif_rc_handler(e, d);         \
   } break;
 
-static bool btif_av_state_idle_handler(btif_sm_event_t event, void* data);
-static bool btif_av_state_opening_handler(btif_sm_event_t event, void* data);
-static bool btif_av_state_opened_handler(btif_sm_event_t event, void* data);
-static bool btif_av_state_started_handler(btif_sm_event_t event, void* data);
-static bool btif_av_state_closing_handler(btif_sm_event_t event, void* data);
+static bt_status_t src_disconnect_sink(const RawAddress& peer_address);
+static bt_status_t sink_disconnect_src(const RawAddress& peer_address);
+static void btif_av_source_dispatch_sm_event(const RawAddress& peer_address,
+                                             btif_av_sm_event_t event);
+static void btif_av_sink_dispatch_sm_event(const RawAddress& peer_address,
+                                           btif_av_sm_event_t event);
+static void btif_av_handle_event(uint8_t peer_sep,
+                                 const RawAddress& peer_address,
+                                 tBTA_AV_HNDL bta_handle,
+                                 const BtifAvEvent& btif_av_event);
+static void btif_report_connection_state(const RawAddress& peer_address,
+                                         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,
+                                       tBTA_AV_MEDIA* p_data);
 
-static const btif_sm_handler_t btif_av_state_handlers[] = {
-    btif_av_state_idle_handler, btif_av_state_opening_handler,
-    btif_av_state_opened_handler, btif_av_state_started_handler,
-    btif_av_state_closing_handler};
-
-static void btif_av_event_free_data(btif_sm_event_t event, void* p_data);
-
-/*************************************************************************
- * Extern functions
- ************************************************************************/
-extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data);
-extern bool btif_rc_get_connected_peer(RawAddress* peer_addr);
-extern uint8_t btif_rc_get_connected_peer_handle(const RawAddress& peer_addr);
-extern void btif_rc_check_handle_pending_play(const RawAddress& peer_addr,
-                                              bool bSendToApp);
+static BtifAvPeer* btif_av_source_find_peer(const RawAddress& peer_address) {
+  return btif_av_source.FindPeer(peer_address);
+}
+static BtifAvPeer* btif_av_sink_find_peer(const RawAddress& peer_address) {
+  return btif_av_sink.FindPeer(peer_address);
+}
+static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address) {
+  if (btif_av_source.Enabled()) return btif_av_source_find_peer(peer_address);
+  if (btif_av_sink.Enabled()) return btif_av_sink_find_peer(peer_address);
+  return nullptr;
+}
+static BtifAvPeer* btif_av_find_active_peer() {
+  if (btif_av_source.Enabled())
+    return btif_av_source_find_peer(btif_av_source.ActivePeer());
+  if (btif_av_sink.Enabled())
+    return btif_av_sink_find_peer(btif_av_sink.ActivePeer());
+  return nullptr;
+}
 
 /*****************************************************************************
  * Local helper functions
  *****************************************************************************/
 
-const char* dump_av_sm_state_name(btif_av_state_t state) {
-  switch (state) {
-    CASE_RETURN_STR(BTIF_AV_STATE_IDLE)
-    CASE_RETURN_STR(BTIF_AV_STATE_OPENING)
-    CASE_RETURN_STR(BTIF_AV_STATE_OPENED)
-    CASE_RETURN_STR(BTIF_AV_STATE_STARTED)
-    CASE_RETURN_STR(BTIF_AV_STATE_CLOSING)
-    default:
-      return "UNKNOWN_STATE";
-  }
-}
-
 const char* dump_av_sm_event_name(btif_av_sm_event_t event) {
   switch ((int)event) {
     CASE_RETURN_STR(BTA_AV_ENABLE_EVT)
@@ -189,976 +667,67 @@
     CASE_RETURN_STR(BTA_AV_REJECT_EVT)
     CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
     CASE_RETURN_STR(BTA_AV_OFFLOAD_START_RSP_EVT)
-    CASE_RETURN_STR(BTIF_SM_ENTER_EVT)
-    CASE_RETURN_STR(BTIF_SM_EXIT_EVT)
     CASE_RETURN_STR(BTIF_AV_CONNECT_REQ_EVT)
     CASE_RETURN_STR(BTIF_AV_DISCONNECT_REQ_EVT)
     CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT)
     CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT)
     CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
-    CASE_RETURN_STR(BTIF_AV_SOURCE_CONFIG_REQ_EVT)
-    CASE_RETURN_STR(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT)
     CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_ACL_DISCONNECTED)
     CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_AVRCP_OPEN_EVT)
+    CASE_RETURN_STR(BTIF_AV_AVRCP_CLOSE_EVT)
+    CASE_RETURN_STR(BTIF_AV_AVRCP_REMOTE_PLAY_EVT)
     default:
       return "UNKNOWN_EVENT";
   }
 }
 
-/****************************************************************************
- *  Local helper functions
- ****************************************************************************/
-/*******************************************************************************
- *
- * Function         btif_initiate_av_open_timer_timeout
- *
- * Description      Timer to trigger AV open if the remote headset establishes
- *                  RC connection w/o AV connection. The timer is needed to IOP
- *                  with headsets that do establish AV after RC connection.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void btif_initiate_av_open_timer_timeout(UNUSED_ATTR void* data) {
-  RawAddress peer_addr;
-  btif_av_connect_req_t connect_req;
+BtifAvEvent::BtifAvEvent(uint32_t event, const void* p_data, size_t data_length)
+    : event_(event), data_(nullptr), data_length_(0) {
+  DeepCopy(event, p_data, data_length);
+}
 
-  /* is there at least one RC connection - There should be */
-  if (btif_rc_get_connected_peer(&peer_addr)) {
-    BTIF_TRACE_DEBUG("%s: Issuing connect to the remote RC peer", __func__);
-    /* In case of AVRCP connection request, we will initiate SRC connection */
-    connect_req.target_bda = &peer_addr;
-    if (bt_av_sink_callbacks != NULL)
-      connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
-    else if (bt_av_src_callbacks != NULL)
-      connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
-    btif_dispatch_sm_event(BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req,
-                           sizeof(connect_req));
+BtifAvEvent::BtifAvEvent(const BtifAvEvent& other)
+    : event_(0), data_(nullptr), data_length_(0) {
+  *this = other;
+}
+
+BtifAvEvent& BtifAvEvent::operator=(const BtifAvEvent& other) {
+  DeepFree();
+  DeepCopy(other.Event(), other.Data(), other.DataLength());
+  return *this;
+}
+
+BtifAvEvent::~BtifAvEvent() { DeepFree(); }
+
+std::string BtifAvEvent::ToString() const {
+  return BtifAvEvent::EventName(event_);
+}
+
+std::string BtifAvEvent::EventName(uint32_t event) {
+  std::string name = dump_av_sm_event_name((btif_av_sm_event_t)event);
+  std::stringstream ss_value;
+  ss_value << "(0x" << std::hex << event << ")";
+  return name + ss_value.str();
+}
+
+void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data,
+                           size_t data_length) {
+  event_ = event;
+  data_length_ = data_length;
+  if (data_length == 0) {
+    data_ = nullptr;
   } else {
-    BTIF_TRACE_ERROR("%s: No connected RC peers", __func__);
-  }
-}
-
-/*****************************************************************************
- *  Static functions
- *****************************************************************************/
-
-/*******************************************************************************
- *
- * Function         btif_report_connection_state
- *
- * Description      Updates the components via the callbacks about the
- *                  connection state of a2dp connection.
- *
- * Returns          None
- *
- ******************************************************************************/
-static void btif_report_connection_state(btav_connection_state_t state,
-                                         RawAddress* bd_addr) {
-  if (bt_av_sink_callbacks != NULL) {
-    HAL_CBACK(bt_av_sink_callbacks, connection_state_cb, state, bd_addr);
-  } else if (bt_av_src_callbacks != NULL) {
-    HAL_CBACK(bt_av_src_callbacks, connection_state_cb, state, bd_addr);
-  }
-}
-
-/*******************************************************************************
- *
- * Function         btif_report_audio_state
- *
- * Description      Updates the components via the callbacks about the audio
- *                  state of a2dp connection. The state is updated when either
- *                  the remote ends starts streaming (started state) or whenever
- *                  it transitions out of started state (to opened or streaming)
- *                  state.
- *
- * Returns          None
- *
- ******************************************************************************/
-static void btif_report_audio_state(btav_audio_state_t state,
-                                    RawAddress* bd_addr) {
-  if (bt_av_sink_callbacks != NULL) {
-    HAL_CBACK(bt_av_sink_callbacks, audio_state_cb, state, bd_addr);
-  } else if (bt_av_src_callbacks != NULL) {
-    HAL_CBACK(bt_av_src_callbacks, audio_state_cb, state, bd_addr);
-  }
-}
-
-static void btif_update_source_codec(void* p_data) {
-  BTIF_TRACE_DEBUG("%s", __func__);
-
-  // copy to avoid alignment problems
-  btav_a2dp_codec_config_t req;
-  memcpy(&req, p_data, sizeof(req));
-
-  btif_a2dp_source_encoder_user_config_update_req(req);
-}
-
-static void btif_report_source_codec_state(UNUSED_ATTR void* p_data) {
-  btav_a2dp_codec_config_t codec_config;
-  std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
-  std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;
-
-  A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs();
-  if (a2dp_codecs == nullptr) return;
-  if (!a2dp_codecs->getCodecConfigAndCapabilities(
-          &codec_config, &codecs_local_capabilities,
-          &codecs_selectable_capabilities)) {
-    BTIF_TRACE_WARNING(
-        "%s: error reporting audio source codec state: "
-        "cannot get codec config and capabilities",
-        __func__);
-    return;
-  }
-  if (bt_av_src_callbacks != NULL) {
-    HAL_CBACK(bt_av_src_callbacks, audio_config_cb, codec_config,
-              codecs_local_capabilities, codecs_selectable_capabilities);
-  }
-}
-
-/*****************************************************************************
- *
- * Function     btif_av_state_idle_handler
- *
- * Description  State managing disconnected AV link
- *
- * Returns      true if event was processed, false otherwise
- *
- ******************************************************************************/
-
-static bool btif_av_state_idle_handler(btif_sm_event_t event, void* p_data) {
-  BTIF_TRACE_DEBUG("%s: event=%s flags=0x%x", __func__,
-                   dump_av_sm_event_name((btif_av_sm_event_t)event),
-                   btif_av_cb.flags);
-
-  switch (event) {
-    case BTIF_SM_ENTER_EVT:
-      /* clear the peer_bda */
-      btif_av_cb.peer_bda = RawAddress::kEmpty;
-      btif_av_cb.flags = 0;
-      btif_av_cb.edr = 0;
-      bta_av_co_init(btif_av_cb.codec_priorities);
-      btif_a2dp_on_idle();
-      break;
-
-    case BTIF_SM_EXIT_EVT:
-      break;
-
-    case BTA_AV_ENABLE_EVT:
-      break;
-
-    case BTA_AV_REGISTER_EVT:
-      btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
-      break;
-
-    case BTA_AV_PENDING_EVT:
-    case BTIF_AV_CONNECT_REQ_EVT: {
-      if (event == BTIF_AV_CONNECT_REQ_EVT) {
-        btif_av_connect_req_t* connect_req_p = (btif_av_connect_req_t*)p_data;
-        btif_av_cb.peer_bda = *connect_req_p->target_bda;
-        btif_av_cb.self_initiated_connection = true;
-        BTA_AvOpen(btif_av_cb.peer_bda, btif_av_cb.bta_handle, true,
-                   BTA_SEC_AUTHENTICATE, connect_req_p->uuid);
-      } else if (event == BTA_AV_PENDING_EVT) {
-        btif_av_cb.peer_bda = ((tBTA_AV*)p_data)->pend.bd_addr;
-        btif_av_cb.self_initiated_connection = false;
-        if (bt_av_src_callbacks != NULL) {
-          BTA_AvOpen(btif_av_cb.peer_bda, btif_av_cb.bta_handle, true,
-                     BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
-        }
-        if (bt_av_sink_callbacks != NULL) {
-          BTA_AvOpen(btif_av_cb.peer_bda, btif_av_cb.bta_handle, true,
-                     BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
-        }
-      }
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
-    } break;
-
-    case BTA_AV_RC_OPEN_EVT:
-      /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it
-       * connects. So
-       * as per the AV WP, an AVRC connection cannot exist without an AV
-       * connection. Therefore,
-       * we initiate an AV connection if an RC_OPEN_EVT is received when we are
-       * in AV_CLOSED state.
-       * We initiate the AV connection after a small 3s timeout to avoid any
-       * collisions from the
-       * headsets, as some headsets initiate the AVRC connection first and then
-       * immediately initiate the AV connection
-       *
-       * TODO: We may need to do this only on an AVRCP Play. FixMe
-       */
-
-      BTIF_TRACE_WARNING("%s: BTA_AV_RC_OPEN_EVT received w/o AV", __func__);
-      alarm_set_on_mloop(av_open_on_rc_timer, BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
-                         btif_initiate_av_open_timer_timeout, NULL);
-      btif_rc_handler(event, (tBTA_AV*)p_data);
-      break;
-
-    case BTA_AV_RC_BROWSE_OPEN_EVT:
-      BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_OPEN_EVT received", __func__);
-      btif_rc_handler(event, (tBTA_AV*)p_data);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
-      btif_update_source_codec(p_data);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
-      btif_report_source_codec_state(p_data);
-      break;
-
-    /*
-     * In case Signalling channel is not down
-     * and remote started Streaming 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));
-
-      BTIF_TRACE_WARNING(
-          "%s: BTIF_AV_SINK_CONFIG_REQ_EVT sample_rate=%d "
-          "channel_count=%d",
-          __func__, req.sample_rate, req.channel_count);
-      if (bt_av_sink_callbacks != NULL) {
-        HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(req.peer_bd),
-                  req.sample_rate, req.channel_count);
-      }
-    } break;
-
-    case BTA_AV_OPEN_EVT: {
-      tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
-      btav_connection_state_t state;
-      btif_sm_state_t av_state;
-      BTIF_TRACE_WARNING("%s: BTA_AV_OPEN_EVT status=%d, edr=0x%x", __func__,
-                         p_bta_data->open.status, p_bta_data->open.edr);
-
-      if (p_bta_data->open.status == BTA_AV_SUCCESS) {
-        state = BTAV_CONNECTION_STATE_CONNECTED;
-        av_state = BTIF_AV_STATE_OPENED;
-        btif_av_cb.edr = p_bta_data->open.edr;
-
-        btif_av_cb.peer_sep = p_bta_data->open.sep;
-      } else {
-        BTIF_TRACE_WARNING("%s: BTA_AV_OPEN_EVT::FAILED status=%d", __func__,
-                           p_bta_data->open.status);
-        state = BTAV_CONNECTION_STATE_DISCONNECTED;
-        av_state = BTIF_AV_STATE_IDLE;
-      }
-
-      /* inform the application of the event */
-      btif_report_connection_state(state, &(btif_av_cb.peer_bda));
-      /* change state to open/idle based on the status */
-      btif_sm_change_state(btif_av_cb.sm_handle, av_state);
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-        /* if queued PLAY command,  send it now */
-        btif_rc_check_handle_pending_play(
-            p_bta_data->open.bd_addr,
-            (p_bta_data->open.status == BTA_AV_SUCCESS));
-      } else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
-                 (p_bta_data->open.status == BTA_AV_SUCCESS)) {
-        /* Bring up AVRCP connection too */
-        BTA_AvOpenRc(btif_av_cb.bta_handle);
-      }
-      btif_queue_advance();
-    } break;
-
-    case BTA_AV_REMOTE_CMD_EVT:
-    case BTA_AV_VENDOR_CMD_EVT:
-    case BTA_AV_META_MSG_EVT:
-    case BTA_AV_RC_FEAT_EVT:
-    case BTA_AV_REMOTE_RSP_EVT:
-      btif_rc_handler(event, (tBTA_AV*)p_data);
-      break;
-
-    case BTA_AV_RC_CLOSE_EVT:
-      BTIF_TRACE_DEBUG("%s: BTA_AV_RC_CLOSE_EVT: Stopping AV timer.", __func__);
-      alarm_cancel(av_open_on_rc_timer);
-      btif_rc_handler(event, (tBTA_AV*)p_data);
-      break;
-
-    case BTIF_AV_OFFLOAD_START_REQ_EVT:
-      BTIF_TRACE_ERROR(
-          "%s: BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started IDLE",
-          __func__);
-      btif_a2dp_on_offload_started(BTA_AV_FAIL);
-      break;
-
-    default:
-      BTIF_TRACE_WARNING("%s: unhandled event=%s", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event));
-      return false;
-  }
-
-  return true;
-}
-/*****************************************************************************
- *
- * Function        btif_av_state_opening_handler
- *
- * Description     Intermediate state managing events during establishment
- *                 of avdtp channel
- *
- * Returns         true if event was processed, false otherwise
- *
- ******************************************************************************/
-
-static bool btif_av_state_opening_handler(btif_sm_event_t event, void* p_data) {
-  BTIF_TRACE_DEBUG("%s: event=%s flags=0x%x", __func__,
-                   dump_av_sm_event_name((btif_av_sm_event_t)event),
-                   btif_av_cb.flags);
-
-  switch (event) {
-    case BTIF_SM_ENTER_EVT:
-      /* inform the application that we are entering connecting state */
-      btif_report_connection_state(BTAV_CONNECTION_STATE_CONNECTING,
-                                   &(btif_av_cb.peer_bda));
-      break;
-
-    case BTIF_SM_EXIT_EVT:
-      break;
-
-    case BTA_AV_REJECT_EVT:
-      BTIF_TRACE_WARNING("%s: Received BTA_AV_REJECT_EVT", __func__);
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                   &(btif_av_cb.peer_bda));
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
-      if (btif_av_cb.self_initiated_connection) {
-        btif_queue_advance();
-      }
-      break;
-
-    case BTA_AV_OPEN_EVT: {
-      tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
-      btav_connection_state_t state;
-      btif_sm_state_t av_state;
-      BTIF_TRACE_WARNING("%s: BTA_AV_OPEN_EVT status=%d, edr=0x%x", __func__,
-                         p_bta_data->open.status, p_bta_data->open.edr);
-
-      if (p_bta_data->open.status == BTA_AV_SUCCESS) {
-        state = BTAV_CONNECTION_STATE_CONNECTED;
-        av_state = BTIF_AV_STATE_OPENED;
-        btif_av_cb.edr = p_bta_data->open.edr;
-
-        btif_av_cb.peer_sep = p_bta_data->open.sep;
-      } else {
-        BTIF_TRACE_WARNING("%s: BTA_AV_OPEN_EVT::FAILED status: %d", __func__,
-                           p_bta_data->open.status);
-        RawAddress peer_addr;
-        uint8_t peer_handle = BTRC_HANDLE_NONE;
-        if (btif_rc_get_connected_peer(&peer_addr) &&
-            btif_av_cb.peer_bda == peer_addr) {
-          /*
-           * Disconnect AVRCP connection, if
-           * A2DP conneciton failed, for any reason
-           */
-          BTIF_TRACE_WARNING("%s: Disconnecting AVRCP: peer_addr=%s", __func__,
-                             peer_addr.ToString().c_str());
-          peer_handle = btif_rc_get_connected_peer_handle(peer_addr);
-          if (peer_handle != BTRC_HANDLE_NONE) {
-            BTA_AvCloseRc(peer_handle);
-          }
-        }
-        state = BTAV_CONNECTION_STATE_DISCONNECTED;
-        av_state = BTIF_AV_STATE_IDLE;
-      }
-
-      /* inform the application of the event */
-      btif_report_connection_state(state, &(btif_av_cb.peer_bda));
-      /* change state to open/idle based on the status */
-      btif_sm_change_state(btif_av_cb.sm_handle, av_state);
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-        /* if queued PLAY command,  send it now */
-        btif_rc_check_handle_pending_play(
-            p_bta_data->open.bd_addr,
-            (p_bta_data->open.status == BTA_AV_SUCCESS));
-      } else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
-                 (p_bta_data->open.status == BTA_AV_SUCCESS)) {
-        /* Bring up AVRCP connection too */
-        BTA_AvOpenRc(btif_av_cb.bta_handle);
-      }
-      if (btif_av_cb.self_initiated_connection) {
-        btif_queue_advance();
-      }
-    } break;
-
-    case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
-      btif_update_source_codec(p_data);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
-      btif_report_source_codec_state(p_data);
-      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));
-
-      BTIF_TRACE_WARNING(
-          "%s: BTIF_AV_SINK_CONFIG_REQ_EVT sample_rate=%d "
-          "channel_count=%d",
-          __func__, req.sample_rate, req.channel_count);
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC &&
-          bt_av_sink_callbacks != NULL) {
-        HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb.peer_bda),
-                  req.sample_rate, req.channel_count);
-      }
-    } break;
-
-    case BTIF_AV_CONNECT_REQ_EVT: {
-      // Check for device, if same device which moved to opening then ignore
-      // callback
-      btif_av_connect_req_t* connect_req_p = (btif_av_connect_req_t*)p_data;
-      RawAddress& target_bda = *connect_req_p->target_bda;
-      if (btif_av_cb.peer_bda == target_bda) {
-        BTIF_TRACE_WARNING(
-            "%s: device %s is already connecting, ignore Connect request",
-            __func__, btif_av_cb.peer_bda.ToString().c_str());
-      } else {
-        BTIF_TRACE_WARNING(
-            "%s: device %s is already connecting, reject Connect request to %s",
-            __func__, btif_av_cb.peer_bda.ToString().c_str(),
-            target_bda.ToString().c_str());
-        btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                     &target_bda);
-      }
-      // Ignore all connection request if we are already opening
-      btif_queue_advance();
-    } break;
-
-    case BTA_AV_PENDING_EVT: {
-      // Check for device, if same device which moved to opening then ignore
-      // callback
-      const RawAddress& bd_addr = ((tBTA_AV*)p_data)->pend.bd_addr;
-      if (bd_addr == btif_av_cb.peer_bda) {
-        BTIF_TRACE_WARNING(
-            "%s: device %s is already connecting, ignore incoming request",
-            __func__, btif_av_cb.peer_bda.ToString().c_str());
-      } else {
-        BTIF_TRACE_WARNING(
-            "%s: device %s is already connecting, reject incoming request "
-            "from %s",
-            __func__, btif_av_cb.peer_bda.ToString().c_str(),
-            bd_addr.ToString().c_str());
-        BTA_AvDisconnect(bd_addr);
-      }
-    } break;
-
-    case BTIF_AV_OFFLOAD_START_REQ_EVT:
-      BTIF_TRACE_ERROR(
-          "%s: BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started OPENING",
-          __func__);
-      btif_a2dp_on_offload_started(BTA_AV_FAIL);
-      break;
-
-    case BTA_AV_CLOSE_EVT:
-      btif_a2dp_on_stopped(NULL);
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                   &(btif_av_cb.peer_bda));
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
-      if (btif_av_cb.self_initiated_connection) {
-        btif_queue_advance();
-      }
-      break;
-
-    case BTIF_AV_DISCONNECT_REQ_EVT:
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                   &(btif_av_cb.peer_bda));
-      BTA_AvClose(btif_av_cb.bta_handle);
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
-      if (btif_av_cb.self_initiated_connection) {
-        btif_queue_advance();
-      }
-      break;
-
-      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
-
-    default:
-      BTIF_TRACE_WARNING("%s: unhandled event=%s", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event));
-      return false;
-  }
-  return true;
-}
-
-/*****************************************************************************
- *
- * Function        btif_av_state_closing_handler
- *
- * Description     Intermediate state managing events during closing
- *                 of avdtp channel
- *
- * Returns         true if event was processed, false otherwise
- *
- ******************************************************************************/
-
-static bool btif_av_state_closing_handler(btif_sm_event_t event, void* p_data) {
-  BTIF_TRACE_DEBUG("%s: event=%s flags=0x%x", __func__,
-                   dump_av_sm_event_name((btif_av_sm_event_t)event),
-                   btif_av_cb.flags);
-
-  switch (event) {
-    case BTIF_SM_ENTER_EVT:
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-        /* immediately stop transmission of frames */
-        btif_a2dp_source_set_tx_flush(true);
-        /* wait for audioflinger to stop a2dp */
-      }
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
-        btif_a2dp_sink_set_rx_flush(true);
-      }
-      break;
-
-    case BTA_AV_STOP_EVT:
-    case BTIF_AV_STOP_STREAM_REQ_EVT:
-      btif_a2dp_on_stopped(NULL);
-      break;
-
-    case BTIF_SM_EXIT_EVT:
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
-      btif_update_source_codec(p_data);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
-      btif_report_source_codec_state(p_data);
-      break;
-
-    case BTA_AV_CLOSE_EVT:
-
-      /* inform the application that we are disconnecting */
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                   &(btif_av_cb.peer_bda));
-
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
-      break;
-
-    /* Handle the RC_CLOSE event for the cleanup */
-    case BTA_AV_RC_CLOSE_EVT:
-      btif_rc_handler(event, (tBTA_AV*)p_data);
-      break;
-
-    /* Handle the RC_BROWSE_CLOSE event for tetsing*/
-    case BTA_AV_RC_BROWSE_CLOSE_EVT:
-      btif_rc_handler(event, (tBTA_AV*)p_data);
-      break;
-
-    case BTIF_AV_OFFLOAD_START_REQ_EVT:
-      BTIF_TRACE_ERROR(
-          "%s: BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Closing",
-          __func__);
-      btif_a2dp_on_offload_started(BTA_AV_FAIL);
-      break;
-
-    default:
-      BTIF_TRACE_WARNING("%s: unhandled event=%s", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event));
-      return false;
-  }
-  return true;
-}
-
-/*****************************************************************************
- *
- * Function     btif_av_state_opened_handler
- *
- * Description  Handles AV events while AVDTP is in OPEN state
- *
- * Returns      true if event was processed, false otherwise
- *
- ******************************************************************************/
-
-static bool btif_av_state_opened_handler(btif_sm_event_t event, void* p_data) {
-  tBTA_AV* p_av = (tBTA_AV*)p_data;
-
-  BTIF_TRACE_DEBUG("%s: event=%s flags=0x%x", __func__,
-                   dump_av_sm_event_name((btif_av_sm_event_t)event),
-                   btif_av_cb.flags);
-
-  if ((event == BTA_AV_REMOTE_CMD_EVT) &&
-      (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
-      (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY)) {
-    BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY", __func__);
-    btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+    data_ = osi_malloc(data_length_);
+    memcpy(data_, p_data, data_length);
   }
 
   switch (event) {
-    case BTIF_SM_ENTER_EVT:
-      btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_STOP;
-      btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
-      break;
-
-    case BTIF_SM_EXIT_EVT:
-      btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
-      break;
-
-    case BTIF_AV_START_STREAM_REQ_EVT:
-      if (btif_av_cb.peer_sep != AVDT_TSEP_SRC) btif_a2dp_source_setup_codec();
-      BTA_AvStart();
-      btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START;
-      break;
-
-    case BTA_AV_START_EVT: {
-      BTIF_TRACE_WARNING(
-          "%s: BTA_AV_START_EVT status=%d suspending=%d initiator=%d "
-          "flags=0x%x",
-          __func__, p_av->start.status, p_av->start.suspending,
-          p_av->start.initiator, btif_av_cb.flags);
-
-      if ((p_av->start.status == BTA_SUCCESS) &&
-          (p_av->start.suspending == true))
-        return true;
-
-      /* if remote tries to start a2dp when DUT is a2dp source
-       * then suspend. In case a2dp is sink and call is active
-       * then disconnect the AVDTP channel
-       */
-      if (!(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START)) {
-        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-          BTIF_TRACE_WARNING("%s: trigger suspend as remote initiated!!",
-                             __func__);
-          btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
-        }
-      }
-
-      /*  In case peer is A2DP SRC we do not want to ack commands on UIPC*/
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-        if (btif_a2dp_on_started(
-                &p_av->start,
-                ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0))) {
-          /* only clear pending flag after acknowledgement */
-          btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
-        }
-      }
-
-      /* remain in open state if status failed */
-      if (p_av->start.status != BTA_AV_SUCCESS) return false;
-
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
-        btif_a2dp_sink_set_rx_flush(
-            false); /*  remove flush state, ready for streaming*/
-      }
-
-      /* change state to started, send acknowledgement if start is pending */
-      if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
-        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
-          btif_a2dp_on_started(NULL, true);
-        /* pending start flag will be cleared when exit current state */
-      }
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
-
-    } break;
-
-    case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
-      btif_update_source_codec(p_data);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
-      btif_report_source_codec_state(p_data);
-      break;
-
-    case BTIF_AV_DISCONNECT_REQ_EVT:
-      BTA_AvClose(btif_av_cb.bta_handle);
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
-        BTA_AvCloseRc(btif_av_cb.bta_handle);
-      }
-
-      /* inform the application that we are disconnecting */
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING,
-                                   &(btif_av_cb.peer_bda));
-      break;
-
-    case BTA_AV_CLOSE_EVT:
-      /* avdtp link is closed */
-      btif_a2dp_on_stopped(NULL);
-
-      /* inform the application that we are disconnected */
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                   &(btif_av_cb.peer_bda));
-
-      /* change state to idle, send acknowledgement if start is pending */
-      if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
-        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
-        /* pending start flag will be cleared when exit current state */
-      }
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
-      break;
-
-    case BTA_AV_RECONFIG_EVT:
-      if ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) &&
-          (p_av->reconfig.status == BTA_AV_SUCCESS)) {
-        APPL_TRACE_WARNING("reconfig done BTA_AVstart()");
-        BTA_AvStart();
-      } else if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
-        btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
-        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
-      }
-      break;
-
-    case BTIF_AV_CONNECT_REQ_EVT: {
-      btif_av_connect_req_t* connect_req_p = (btif_av_connect_req_t*)p_data;
-      RawAddress& target_bda = *connect_req_p->target_bda;
-      if (btif_av_cb.peer_bda == target_bda) {
-        BTIF_TRACE_WARNING(
-            "%s: Ignore BTIF_AV_CONNECT_REQ_EVT for same device: target_bda=%s",
-            __func__, target_bda.ToString().c_str());
-      } else {
-        BTIF_TRACE_WARNING(
-            "%s: Moved to opened by Other incoming Connect request: "
-            "target_bda=%s",
-            __func__, target_bda.ToString().c_str());
-        btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                     &target_bda);
-      }
-      btif_queue_advance();
-    } break;
-
-    case BTIF_AV_OFFLOAD_START_REQ_EVT:
-      BTIF_TRACE_ERROR(
-          "%s: BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Opened",
-          __func__);
-      btif_a2dp_on_offload_started(BTA_AV_FAIL);
-      break;
-
-      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
-
-    default:
-      BTIF_TRACE_WARNING("%s: unhandled event=%s", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event));
-      return false;
-  }
-  return true;
-}
-
-/*****************************************************************************
- *
- * Function     btif_av_state_started_handler
- *
- * Description  Handles AV events while A2DP stream is started
- *
- * Returns      true if event was processed, false otherwise
- *
- ******************************************************************************/
-
-static bool btif_av_state_started_handler(btif_sm_event_t event, void* p_data) {
-  tBTA_AV* p_av = (tBTA_AV*)p_data;
-
-  BTIF_TRACE_DEBUG("%s: event=%s flags=0x%x", __func__,
-                   dump_av_sm_event_name((btif_av_sm_event_t)event),
-                   btif_av_cb.flags);
-
-  switch (event) {
-    case BTIF_SM_ENTER_EVT:
-
-      /* we are again in started state, clear any remote suspend flags */
-      btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
-
-      /**
-       * Report to components above that we have entered the streaming
-       * stage, this should usually be followed by focus grant.
-       * see update_audio_focus_state()
-       */
-      btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
-      break;
-
-    case BTIF_SM_EXIT_EVT:
-      break;
-
-    case BTIF_AV_START_STREAM_REQ_EVT:
-      /* we were remotely started, just ack back the local request */
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
-        btif_a2dp_on_started(NULL, true);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
-      btif_update_source_codec(p_data);
-      break;
-
-    case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
-      btif_report_source_codec_state(p_data);
-      break;
-
-    /* fixme -- use suspend = true always to work around issue with BTA AV */
-    case BTIF_AV_STOP_STREAM_REQ_EVT:
-    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
-      BTIF_TRACE_WARNING("%s: event=%s flags=0x%x", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event),
-                         btif_av_cb.flags);
-      /* set pending flag to ensure btif task is not trying to restart
-         stream while suspend is in progress */
-      btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
-
-      /* if we were remotely suspended but suspend locally, local suspend
-         always overrides */
-      btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
-
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-        /*
-         * Immediately stop transmission of frames while suspend is
-         * pending.
-         */
-        btif_a2dp_source_set_tx_flush(true);
-      }
-
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
-        btif_a2dp_on_stopped(NULL);
-      }
-
-      BTA_AvStop(true);
-      break;
-
-    case BTIF_AV_DISCONNECT_REQ_EVT:
-      BTIF_TRACE_WARNING("%s: event=%s flags=0x%x", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event),
-                         btif_av_cb.flags);
-
-      /* request avdtp to close */
-      BTA_AvClose(btif_av_cb.bta_handle);
-      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
-        BTA_AvCloseRc(btif_av_cb.bta_handle);
-      }
-
-      /* inform the application that we are disconnecting */
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING,
-                                   &(btif_av_cb.peer_bda));
-
-      /* wait in closing state until fully closed */
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING);
-      break;
-
-    case BTA_AV_SUSPEND_EVT:
-      BTIF_TRACE_WARNING(
-          "%s: BTA_AV_SUSPEND_EVT status=%d initiator=%d flags=0x%x", __func__,
-          p_av->suspend.status, p_av->suspend.initiator, btif_av_cb.flags);
-
-      /* a2dp suspended, stop media task until resumed */
-      btif_a2dp_on_suspended(&p_av->suspend);
-
-      /* if not successful, remain in current state */
-      if (p_av->suspend.status != BTA_AV_SUCCESS) {
-        btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
-
-        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
-          /* suspend failed, reset back tx flush state */
-          btif_a2dp_source_set_tx_flush(false);
-        }
-        return false;
-      }
-
-      if (p_av->suspend.initiator != true) {
-        /* remote suspend, notify HAL and await audioflinger to
-           suspend/stop stream */
-
-        /* set remote suspend flag to block media task from restarting
-           stream only if we did not already initiate a local suspend */
-        if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
-          btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
-
-        btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND,
-                                &(btif_av_cb.peer_bda));
-      } else {
-        btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED,
-                                &(btif_av_cb.peer_bda));
-      }
-
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
-
-      /* suspend completed and state changed, clear pending status */
-      btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
-      break;
-
-    case BTA_AV_STOP_EVT:
-      BTIF_TRACE_WARNING("%s: event=%s flags=0x%x", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event),
-                         btif_av_cb.flags);
-
-      btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
-      btif_a2dp_on_stopped(&p_av->suspend);
-
-      btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
-
-      /* if stop was successful, change state to open */
-      if (p_av->suspend.status == BTA_AV_SUCCESS)
-        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
-
-      break;
-
-    case BTA_AV_CLOSE_EVT:
-      BTIF_TRACE_WARNING("%s: event=%s flags=0x%x", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event),
-                         btif_av_cb.flags);
-
-      btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
-
-      /* avdtp link is closed */
-      btif_a2dp_on_stopped(NULL);
-
-      /* inform the application that we are disconnected */
-      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                   &(btif_av_cb.peer_bda));
-
-      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
-      break;
-
-    case BTIF_AV_OFFLOAD_START_REQ_EVT:
-      BTA_AvOffloadStart(btif_av_cb.bta_handle);
-      break;
-
-    case BTA_AV_OFFLOAD_START_RSP_EVT:
-      btif_a2dp_on_offload_started(p_av->status);
-      break;
-
-      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
-
-    default:
-      BTIF_TRACE_WARNING("%s: unhandled event=%s", __func__,
-                         dump_av_sm_event_name((btif_av_sm_event_t)event));
-      return false;
-  }
-
-  return true;
-}
-
-/*****************************************************************************
- *  Local event handlers
- *****************************************************************************/
-
-static void btif_av_handle_event(uint16_t event, char* p_param) {
-  BTIF_TRACE_EVENT("%s: event=%s", __func__,
-                   dump_av_sm_event_name((btif_av_sm_event_t)event));
-  switch (event) {
-    case BTIF_AV_CLEANUP_REQ_EVT:
-      btif_a2dp_source_shutdown();
-      btif_a2dp_sink_shutdown();
-      break;
-
-    case BTA_AV_REGISTER_EVT:
-      if (btif_av_cb.sm_handle == NULL) {
-        btif_av_cb.bta_handle = ((tBTA_AV*)p_param)->registr.hndl;
-        BTIF_TRACE_DEBUG("%s: BTA AV Handle updated", __func__);
-      }
-    /* FALLTHROUGH */
-    default:
-      btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
-      btif_av_event_free_data(event, p_param);
-  }
-}
-
-void btif_av_event_deep_copy(uint16_t event, char* p_dest, char* p_src) {
-  BTIF_TRACE_DEBUG("%s", __func__);
-  tBTA_AV* av_src = (tBTA_AV*)p_src;
-  tBTA_AV* av_dest = (tBTA_AV*)p_dest;
-
-  // First copy the structure
-  maybe_non_aligned_memcpy(av_dest, av_src, sizeof(*av_src));
-  switch (event) {
-    case BTA_AV_META_MSG_EVT:
+    case BTA_AV_META_MSG_EVT: {
+      CHECK(data_length >= sizeof(tBTA_AV));
+      const tBTA_AV* av_src = (const tBTA_AV*)p_data;
+      tBTA_AV* av_dest = (tBTA_AV*)data_;
       if (av_src->meta_msg.p_data && av_src->meta_msg.len) {
         av_dest->meta_msg.p_data = (uint8_t*)osi_calloc(av_src->meta_msg.len);
         memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data,
@@ -1186,20 +755,19 @@
               (uint8_t*)osi_calloc(p_msg_src->browse.browse_len);
           memcpy(p_msg_dest->browse.p_browse_data,
                  p_msg_src->browse.p_browse_data, p_msg_src->browse.browse_len);
-          android_errorWriteLog(0x534e4554, "109699112");
         }
       }
-      break;
+    } break;
 
     default:
       break;
   }
 }
 
-static void btif_av_event_free_data(btif_sm_event_t event, void* p_data) {
-  switch (event) {
+void BtifAvEvent::DeepFree() {
+  switch (event_) {
     case BTA_AV_META_MSG_EVT: {
-      tBTA_AV* av = (tBTA_AV*)p_data;
+      tBTA_AV* av = (tBTA_AV*)data_;
       osi_free_and_reset((void**)&av->meta_msg.p_data);
 
       if (av->meta_msg.p_msg) {
@@ -1216,46 +784,1753 @@
     default:
       break;
   }
+
+  osi_free_and_reset((void**)&data_);
+  data_length_ = 0;
 }
 
-static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
-  btif_transfer_context(btif_av_handle_event, event, (char*)p_data,
-                        sizeof(tBTA_AV), btif_av_event_deep_copy);
+BtifAvPeer::BtifAvPeer(const RawAddress& peer_address, uint8_t peer_sep,
+                       tBTA_AV_HNDL bta_handle, uint8_t peer_id)
+    : peer_address_(peer_address),
+      peer_sep_(peer_sep),
+      bta_handle_(bta_handle),
+      peer_id_(peer_id),
+      state_machine_(*this),
+      av_open_on_rc_timer_(nullptr),
+      edr_(0),
+      flags_(0),
+      self_initiated_connection_(false) {}
+
+BtifAvPeer::~BtifAvPeer() { alarm_free(av_open_on_rc_timer_); }
+
+std::string BtifAvPeer::FlagsToString() const {
+  std::string result;
+
+  if (flags_ & BtifAvPeer::kFlagLocalSuspendPending) {
+    if (!result.empty()) result += "|";
+    result += "LOCAL_SUSPEND_PENDING";
+  }
+  if (flags_ & BtifAvPeer::kFlagRemoteSuspend) {
+    if (!result.empty()) result += "|";
+    result += "REMOTE_SUSPEND";
+  }
+  if (flags_ & BtifAvPeer::kFlagPendingStart) {
+    if (!result.empty()) result += "|";
+    result += "PENDING_START";
+  }
+  if (flags_ & BtifAvPeer::kFlagPendingStop) {
+    if (!result.empty()) result += "|";
+    result += "PENDING_STOP";
+  }
+  if (result.empty()) result = "None";
+
+  return base::StringPrintf("0x%x(%s)", flags_, result.c_str());
 }
 
-static void bte_av_sink_media_callback(tBTA_AV_EVT event,
+bt_status_t BtifAvPeer::Init() {
+  alarm_free(av_open_on_rc_timer_);
+  av_open_on_rc_timer_ = alarm_new("btif_av_peer.av_open_on_rc_timer");
+
+  state_machine_.Start();
+  return BT_STATUS_SUCCESS;
+}
+
+void BtifAvPeer::Cleanup() {
+  state_machine_.Quit();
+  alarm_free(av_open_on_rc_timer_);
+  av_open_on_rc_timer_ = nullptr;
+}
+
+bool BtifAvPeer::CanBeDeleted() const {
+  return (
+      (state_machine_.StateId() == BtifAvStateMachine::kStateIdle) &&
+      (state_machine_.PreviousStateId() != BtifAvStateMachine::kStateInvalid));
+}
+
+const RawAddress& BtifAvPeer::ActivePeerAddress() const {
+  if (IsSource()) {
+    return btif_av_sink.ActivePeer();
+  }
+  if (IsSink()) {
+    return btif_av_source.ActivePeer();
+  }
+  LOG(FATAL) << __PRETTY_FUNCTION__ << ": A2DP peer " << PeerAddress()
+             << " is neither Source nor Sink";
+  return RawAddress::kEmpty;
+}
+
+bool BtifAvPeer::IsConnected() const {
+  int state = state_machine_.StateId();
+  return ((state == BtifAvStateMachine::kStateOpened) ||
+          (state == BtifAvStateMachine::kStateStarted));
+}
+
+bool BtifAvPeer::IsStreaming() const {
+  int state = state_machine_.StateId();
+  return (state == BtifAvStateMachine::kStateStarted);
+}
+
+BtifAvSource::~BtifAvSource() { CleanupAllPeers(); }
+
+bt_status_t BtifAvSource::Init(
+    btav_source_callbacks_t* callbacks, int max_connected_audio_devices,
+    const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
+  LOG_INFO(LOG_TAG, "%s: max_connected_audio_devices=%d", __PRETTY_FUNCTION__,
+           max_connected_audio_devices);
+  if (enabled_) return BT_STATUS_SUCCESS;
+  CleanupAllPeers();
+  max_connected_peers_ = max_connected_audio_devices;
+
+  /* A2DP OFFLOAD */
+  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;
+  bta_av_co_init(codec_priorities);
+
+  if (!btif_a2dp_source_init()) {
+    return BT_STATUS_FAIL;
+  }
+  btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
+  enabled_ = true;
+  return BT_STATUS_SUCCESS;
+}
+
+void BtifAvSource::Cleanup() {
+  LOG_INFO(LOG_TAG, "%s", __PRETTY_FUNCTION__);
+  if (!enabled_) return;
+
+  btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE);
+
+  do_in_bta_thread(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&BtifAvSource::SetActivePeer),
+                 base::Unretained(&btif_av_source), RawAddress::kEmpty));
+  do_in_bta_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup));
+
+  btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
+  CleanupAllPeers();
+
+  callbacks_ = nullptr;
+  enabled_ = false;
+}
+
+BtifAvPeer* BtifAvSource::FindPeer(const RawAddress& peer_address) {
+  auto it = peers_.find(peer_address);
+  if (it != peers_.end()) return it->second;
+  return nullptr;
+}
+
+BtifAvPeer* BtifAvSource::FindPeerByHandle(tBTA_AV_HNDL bta_handle) {
+  for (auto it : peers_) {
+    BtifAvPeer* peer = it.second;
+    if (peer->BtaHandle() == bta_handle) {
+      return peer;
+    }
+  }
+  return nullptr;
+}
+
+BtifAvPeer* BtifAvSource::FindPeerByPeerId(uint8_t peer_id) {
+  for (auto it : peers_) {
+    BtifAvPeer* peer = it.second;
+    if (peer->PeerId() == peer_id) {
+      return peer;
+    }
+  }
+  return nullptr;
+}
+
+BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address,
+                                           tBTA_AV_HNDL bta_handle) {
+  BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__,
+                   peer_address.ToString().c_str(), bta_handle);
+
+  BtifAvPeer* peer = FindPeer(peer_address);
+  if (peer != nullptr) return peer;
+
+  // Find next availabie Peer ID to use
+  uint8_t peer_id;
+  for (peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
+    if (FindPeerByPeerId(peer_id) == nullptr) break;
+  }
+  if (peer_id == kPeerIdMax) {
+    BTIF_TRACE_ERROR(
+        "%s: Cannot create peer for peer_address=%s : "
+        "cannot allocate unique Peer ID",
+        __PRETTY_FUNCTION__, peer_address.ToString().c_str());
+    return nullptr;
+  }
+  // Get the BTA Handle (if known)
+  if (bta_handle == kBtaHandleUnknown) {
+    auto it = peer_id2bta_handle_.find(peer_id);
+    if (it != peer_id2bta_handle_.end()) {
+      bta_handle = it->second;
+    }
+  }
+
+  LOG_INFO(LOG_TAG,
+           "%s: Create peer: peer_address=%s bta_handle=0x%x peer_id=%d",
+           __PRETTY_FUNCTION__, peer_address.ToString().c_str(), bta_handle,
+           peer_id);
+  peer = new BtifAvPeer(peer_address, AVDT_TSEP_SNK, bta_handle, peer_id);
+  peers_.insert(std::make_pair(peer_address, peer));
+  peer->Init();
+  return peer;
+}
+
+bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const {
+  int connected = 0;
+
+  // Count peers that are in the process of connecting or already connected
+  for (auto it : peers_) {
+    const BtifAvPeer* peer = it.second;
+    switch (peer->StateMachine().StateId()) {
+      case BtifAvStateMachine::kStateOpening:
+      case BtifAvStateMachine::kStateOpened:
+      case BtifAvStateMachine::kStateStarted:
+        if (peer->PeerAddress() == peer_address) {
+          return true;  // Already connected or accounted for
+        }
+        connected++;
+        break;
+      default:
+        break;
+    }
+  }
+  return (connected < max_connected_peers_);
+}
+
+bool BtifAvSource::DeletePeer(const RawAddress& peer_address) {
+  auto it = peers_.find(peer_address);
+  if (it == peers_.end()) return false;
+  BtifAvPeer* peer = it->second;
+  peer->Cleanup();
+  peers_.erase(it);
+  delete peer;
+  return true;
+}
+
+void BtifAvSource::DeleteIdlePeers() {
+  for (auto it = peers_.begin(); it != peers_.end();) {
+    BtifAvPeer* peer = it->second;
+    auto prev_it = it++;
+    if (!peer->CanBeDeleted()) continue;
+    LOG_INFO(LOG_TAG, "%s: Deleting idle peer: %s bta_handle=0x%x", __func__,
+             peer->PeerAddress().ToString().c_str(), peer->BtaHandle());
+    peer->Cleanup();
+    peers_.erase(prev_it);
+    delete peer;
+  }
+}
+
+void BtifAvSource::CleanupAllPeers() {
+  while (!peers_.empty()) {
+    auto it = peers_.begin();
+    BtifAvPeer* peer = it->second;
+    peer->Cleanup();
+    peers_.erase(it);
+    delete peer;
+  }
+}
+
+void BtifAvSource::RegisterAllBtaHandles() {
+  for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
+    BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSourceServiceName.c_str(), peer_id,
+                   nullptr, UUID_SERVCLASS_AUDIO_SOURCE);
+  }
+}
+
+void BtifAvSource::DeregisterAllBtaHandles() {
+  for (auto it : peer_id2bta_handle_) {
+    tBTA_AV_HNDL bta_handle = it.second;
+    BTA_AvDeregister(bta_handle);
+  }
+  peer_id2bta_handle_.clear();
+}
+
+void BtifAvSource::BtaHandleRegistered(uint8_t peer_id,
+                                       tBTA_AV_HNDL bta_handle) {
+  peer_id2bta_handle_.insert(std::make_pair(peer_id, bta_handle));
+
+  // Set the BTA Handle for the Peer (if exists)
+  BtifAvPeer* peer = FindPeerByPeerId(peer_id);
+  if (peer != nullptr) {
+    peer->SetBtaHandle(bta_handle);
+  }
+}
+
+BtifAvSink::~BtifAvSink() { CleanupAllPeers(); }
+
+bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks) {
+  LOG_INFO(LOG_TAG, "%s", __PRETTY_FUNCTION__);
+  if (enabled_) return BT_STATUS_SUCCESS;
+
+  CleanupAllPeers();
+  max_connected_peers_ = kDefaultMaxConnectedAudioDevices;
+  callbacks_ = callbacks;
+
+  std::vector<btav_a2dp_codec_config_t> codec_priorities;  // Default priorities
+  bta_av_co_init(codec_priorities);
+
+  if (!btif_a2dp_sink_init()) {
+    return BT_STATUS_FAIL;
+  }
+  btif_enable_service(BTA_A2DP_SINK_SERVICE_ID);
+  enabled_ = true;
+  return BT_STATUS_SUCCESS;
+}
+
+void BtifAvSink::Cleanup() {
+  LOG_INFO(LOG_TAG, "%s", __PRETTY_FUNCTION__);
+  if (!enabled_) return;
+
+  btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK);
+
+  do_in_bta_thread(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&BtifAvSink::SetActivePeer),
+                 base::Unretained(&btif_av_sink), RawAddress::kEmpty));
+  do_in_bta_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup));
+
+  btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
+  CleanupAllPeers();
+
+  callbacks_ = nullptr;
+  enabled_ = false;
+}
+
+BtifAvPeer* BtifAvSink::FindPeer(const RawAddress& peer_address) {
+  auto it = peers_.find(peer_address);
+  if (it != peers_.end()) return it->second;
+  return nullptr;
+}
+
+BtifAvPeer* BtifAvSink::FindPeerByHandle(tBTA_AV_HNDL bta_handle) {
+  for (auto it : peers_) {
+    BtifAvPeer* peer = it.second;
+    if (peer->BtaHandle() == bta_handle) {
+      return peer;
+    }
+  }
+  return nullptr;
+}
+
+BtifAvPeer* BtifAvSink::FindPeerByPeerId(uint8_t peer_id) {
+  for (auto it : peers_) {
+    BtifAvPeer* peer = it.second;
+    if (peer->PeerId() == peer_id) {
+      return peer;
+    }
+  }
+  return nullptr;
+}
+
+BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address,
+                                         tBTA_AV_HNDL bta_handle) {
+  BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__,
+                   peer_address.ToString().c_str(), bta_handle);
+
+  BtifAvPeer* peer = FindPeer(peer_address);
+  if (peer != nullptr) return peer;
+
+  // Find next availabie Peer ID to use
+  uint8_t peer_id;
+  for (peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
+    if (FindPeerByPeerId(peer_id) == nullptr) break;
+  }
+  if (peer_id == kPeerIdMax) {
+    BTIF_TRACE_ERROR(
+        "%s: Cannot create peer for peer_address=%s : "
+        "cannot allocate unique Peer ID",
+        __PRETTY_FUNCTION__, peer_address.ToString().c_str());
+    return nullptr;
+  }
+
+  // Get the BTA Handle (if known)
+  if (bta_handle == kBtaHandleUnknown) {
+    auto it = peer_id2bta_handle_.find(peer_id);
+    if (it != peer_id2bta_handle_.end()) {
+      bta_handle = it->second;
+    }
+  }
+
+  LOG_INFO(LOG_TAG,
+           "%s: Create peer: peer_address=%s bta_handle=0x%x peer_id=%d",
+           __PRETTY_FUNCTION__, peer_address.ToString().c_str(), bta_handle,
+           peer_id);
+  peer = new BtifAvPeer(peer_address, AVDT_TSEP_SRC, bta_handle, peer_id);
+  peers_.insert(std::make_pair(peer_address, peer));
+  peer->Init();
+  return peer;
+}
+
+bool BtifAvSink::AllowedToConnect(const RawAddress& peer_address) const {
+  int connected = 0;
+
+  // Count peers that are in the process of connecting or already connected
+  for (auto it : peers_) {
+    const BtifAvPeer* peer = it.second;
+    switch (peer->StateMachine().StateId()) {
+      case BtifAvStateMachine::kStateOpening:
+      case BtifAvStateMachine::kStateOpened:
+      case BtifAvStateMachine::kStateStarted:
+        if (peer->PeerAddress() == peer_address) {
+          return true;  // Already connected or accounted for
+        }
+        connected++;
+        break;
+      default:
+        break;
+    }
+  }
+  return (connected < max_connected_peers_);
+}
+
+bool BtifAvSink::DeletePeer(const RawAddress& peer_address) {
+  auto it = peers_.find(peer_address);
+  if (it == peers_.end()) return false;
+  BtifAvPeer* peer = it->second;
+  peer->Cleanup();
+  peers_.erase(it);
+  delete peer;
+  return true;
+}
+
+void BtifAvSink::DeleteIdlePeers() {
+  for (auto it = peers_.begin(); it != peers_.end();) {
+    BtifAvPeer* peer = it->second;
+    auto prev_it = it++;
+    if (!peer->CanBeDeleted()) continue;
+    LOG_INFO(LOG_TAG, "%s: Deleting idle peer: %s bta_handle=0x%x", __func__,
+             peer->PeerAddress().ToString().c_str(), peer->BtaHandle());
+    peer->Cleanup();
+    peers_.erase(prev_it);
+    delete peer;
+  }
+}
+
+void BtifAvSink::CleanupAllPeers() {
+  while (!peers_.empty()) {
+    auto it = peers_.begin();
+    BtifAvPeer* peer = it->second;
+    peer->Cleanup();
+    peers_.erase(it);
+    delete peer;
+  }
+}
+
+void BtifAvSink::RegisterAllBtaHandles() {
+  for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
+    BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSinkServiceName.c_str(), peer_id,
+                   bta_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
+  }
+}
+
+void BtifAvSink::DeregisterAllBtaHandles() {
+  for (auto it : peer_id2bta_handle_) {
+    tBTA_AV_HNDL bta_handle = it.second;
+    BTA_AvDeregister(bta_handle);
+  }
+  peer_id2bta_handle_.clear();
+}
+
+void BtifAvSink::BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle) {
+  peer_id2bta_handle_.insert(std::make_pair(peer_id, bta_handle));
+
+  // Set the BTA Handle for the Peer (if exists)
+  BtifAvPeer* peer = FindPeerByPeerId(peer_id);
+  if (peer != nullptr) {
+    peer->SetBtaHandle(bta_handle);
+  }
+}
+
+void BtifAvStateMachine::StateIdle::OnEnter() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+
+  peer_.SetEdr(0);
+  peer_.ClearAllFlags();
+
+  // Stop A2DP if this is the active peer
+  if (peer_.IsActivePeer() || peer_.ActivePeerAddress().IsEmpty()) {
+    btif_a2dp_on_idle();
+  }
+
+  // Reset the active peer if this was the active peer and
+  // the Idle state was reentered
+  if (peer_.IsActivePeer() && peer_.CanBeDeleted()) {
+    if (peer_.IsSink()) {
+      btif_av_source.SetActivePeer(RawAddress::kEmpty);
+    } else if (peer_.IsSource()) {
+      btif_av_sink.SetActivePeer(RawAddress::kEmpty);
+    }
+  }
+
+  // Delete peers that are re-entering the Idle state
+  if (peer_.IsSink()) {
+    do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSource::DeleteIdlePeers,
+                                           base::Unretained(&btif_av_source)));
+  } else if (peer_.IsSource()) {
+    do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSink::DeleteIdlePeers,
+                                           base::Unretained(&btif_av_sink)));
+  }
+}
+
+void BtifAvStateMachine::StateIdle::OnExit() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+}
+
+bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
+  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(),
+                   logbool(peer_.IsActivePeer()).c_str());
+
+  switch (event) {
+    case BTA_AV_ENABLE_EVT:
+      break;
+
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+    case BTIF_AV_ACL_DISCONNECTED:
+      // Ignore. Just re-enter Idle so the peer can be deleted
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      break;
+
+    case BTIF_AV_DISCONNECT_REQ_EVT:
+      if (peer_.BtaHandle() != kBtaHandleUnknown) {
+        BTA_AvClose(peer_.BtaHandle());
+        if (peer_.IsSource()) {
+          BTA_AvCloseRc(peer_.BtaHandle());
+        }
+      }
+      // Re-enter Idle so the peer can be deleted
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      break;
+
+    case BTIF_AV_CONNECT_REQ_EVT:
+    case BTA_AV_PENDING_EVT: {
+      bool can_connect = true;
+      peer_.SetSelfInitiatedConnection(event == BTIF_AV_CONNECT_REQ_EVT);
+      // Check whether connection is allowed
+      if (peer_.IsSink()) {
+        can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress());
+        if (!can_connect) src_disconnect_sink(peer_.PeerAddress());
+      } else if (peer_.IsSource()) {
+        can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress());
+        if (!can_connect) sink_disconnect_src(peer_.PeerAddress());
+      }
+      if (!can_connect) {
+        BTIF_TRACE_ERROR(
+            "%s: Cannot connect to peer %s: too many connected "
+            "peers",
+            __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str());
+        if (peer_.SelfInitiatedConnection()) {
+          btif_queue_advance();
+        }
+        break;
+      }
+      BTA_AvOpen(peer_.PeerAddress(), peer_.BtaHandle(), true,
+                 BTA_SEC_AUTHENTICATE, peer_.LocalUuidServiceClass());
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpening);
+    } break;
+    case BTIF_AV_AVRCP_OPEN_EVT:
+    case BTA_AV_RC_OPEN_EVT: {
+      // IOP_FIX: Jabra 620 only does AVRCP Open without AV Open whenever it
+      // connects. So as per the AV WP, an AVRCP connection cannot exist
+      // without an AV connection. Therefore, we initiate an AV connection
+      // if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
+      // We initiate the AV connection after a small 3s timeout to avoid any
+      // collisions from the headsets, as some headsets initiate the AVRCP
+      // connection first and then immediately initiate the AV connection
+      //
+      // TODO: We may need to do this only on an AVRCP Play. FixMe
+      BTIF_TRACE_WARNING("%s: Peer %s : event=%s received without AV",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+
+      bool can_connect = true;
+      // Check whether connection is allowed
+      if (peer_.IsSink()) {
+        can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress());
+        if (!can_connect) src_disconnect_sink(peer_.PeerAddress());
+      } else if (peer_.IsSource()) {
+        can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress());
+        if (!can_connect) sink_disconnect_src(peer_.PeerAddress());
+      }
+      if (!can_connect) {
+        BTIF_TRACE_ERROR(
+            "%s: Cannot connect to peer %s: too many connected "
+            "peers",
+            __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str());
+        break;
+      }
+      if (btif_av_source.Enabled()) {
+        alarm_set_on_mloop(
+            peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs,
+            btif_av_source_initiate_av_open_timer_timeout, &peer_);
+      } else if (btif_av_sink.Enabled()) {
+        alarm_set_on_mloop(peer_.AvOpenOnRcTimer(),
+                           BtifAvPeer::kTimeoutAvOpenOnRcMs,
+                           btif_av_sink_initiate_av_open_timer_timeout, &peer_);
+      }
+      if (event == BTA_AV_RC_OPEN_EVT) {
+        btif_rc_handler(event, (tBTA_AV*)p_data);
+      }
+    } break;
+
+    case BTA_AV_RC_BROWSE_OPEN_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    // In case Signalling channel is not down and remote started Streaming
+    // 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: {
+      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: {
+      tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+      btav_connection_state_t state;
+      int av_state;
+      tBTA_AV_STATUS status = p_bta_data->open.status;
+      bool can_connect = true;
+
+      LOG_INFO(
+          LOG_TAG, "%s: Peer %s : event=%s flags=%s status=%d(%s) edr=0x%x",
+          __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
+          BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(),
+          status, (status == BTA_AV_SUCCESS) ? "SUCCESS" : "FAILED",
+          p_bta_data->open.edr);
+
+      if (p_bta_data->open.status == BTA_AV_SUCCESS) {
+        state = BTAV_CONNECTION_STATE_CONNECTED;
+        av_state = BtifAvStateMachine::kStateOpened;
+        peer_.SetEdr(p_bta_data->open.edr);
+        CHECK(peer_.PeerSep() == p_bta_data->open.sep);
+        // Check whether connection is allowed
+        if (peer_.IsSink()) {
+          can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress());
+          if (!can_connect) src_disconnect_sink(peer_.PeerAddress());
+        } else if (peer_.IsSource()) {
+          can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress());
+          if (!can_connect) sink_disconnect_src(peer_.PeerAddress());
+        }
+      } else {
+        state = BTAV_CONNECTION_STATE_DISCONNECTED;
+        av_state = BtifAvStateMachine::kStateIdle;
+      }
+
+      if (!can_connect) {
+        BTIF_TRACE_ERROR(
+            "%s: Cannot connect to peer %s: too many connected "
+            "peers",
+            __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str());
+      } else {
+        // Report the connection state to the application
+        btif_report_connection_state(peer_.PeerAddress(), state);
+        // Change state to Open/Idle based on the status
+        peer_.StateMachine().TransitionTo(av_state);
+        if (peer_.IsSink()) {
+          // If queued PLAY command, send it now
+          btif_rc_check_handle_pending_play(
+              p_bta_data->open.bd_addr,
+              (p_bta_data->open.status == BTA_AV_SUCCESS));
+        } else if (peer_.IsSource() &&
+                   (p_bta_data->open.status == BTA_AV_SUCCESS)) {
+          // Bring up AVRCP connection as well
+          BTA_AvOpenRc(peer_.BtaHandle());
+        }
+      }
+      btif_queue_advance();
+    } break;
+
+    case BTA_AV_REMOTE_CMD_EVT:
+    case BTA_AV_VENDOR_CMD_EVT:
+    case BTA_AV_META_MSG_EVT:
+    case BTA_AV_RC_FEAT_EVT:
+    case BTA_AV_REMOTE_RSP_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    case BTIF_AV_AVRCP_CLOSE_EVT:
+    case BTA_AV_RC_CLOSE_EVT: {
+      BTIF_TRACE_DEBUG("%s: Peer %s : event=%s : Stopping AV timer",
+                       __PRETTY_FUNCTION__,
+                       peer_.PeerAddress().ToString().c_str(),
+                       BtifAvEvent::EventName(event).c_str());
+      alarm_cancel(peer_.AvOpenOnRcTimer());
+
+      if (event == BTA_AV_RC_CLOSE_EVT) {
+        btif_rc_handler(event, (tBTA_AV*)p_data);
+      }
+    } break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened",
+                       __PRETTY_FUNCTION__,
+                       peer_.PeerAddress().ToString().c_str(),
+                       BtifAvEvent::EventName(event).c_str());
+      btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL);
+      break;
+
+    default:
+      BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+      return false;
+  }
+
+  return true;
+}
+
+void BtifAvStateMachine::StateOpening::OnEnter() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+
+  // Inform the application that we are entering connecting state
+  btif_report_connection_state(peer_.PeerAddress(),
+                               BTAV_CONNECTION_STATE_CONNECTING);
+}
+
+void BtifAvStateMachine::StateOpening::OnExit() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+}
+
+bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event,
+                                                    void* p_data) {
+  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(),
+                   logbool(peer_.IsActivePeer()).c_str());
+
+  switch (event) {
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+      break;  // Ignore
+
+    case BTIF_AV_ACL_DISCONNECTED:
+      // ACL Disconnected needs to be handled only in Opening state, because
+      // it is in an intermediate state. In other states we can handle
+      // incoming/outgoing connect/disconnect requests.
+      BTIF_TRACE_WARNING(
+          "%s: Peer %s : event=%s: transitioning to Idle due to ACL Disconnect",
+          __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
+          BtifAvEvent::EventName(event).c_str());
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTED);
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      if (peer_.SelfInitiatedConnection()) {
+        btif_queue_advance();
+      }
+      break;
+    case BTA_AV_REJECT_EVT:
+      BTIF_TRACE_WARNING("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str(),
+                         peer_.FlagsToString().c_str());
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTED);
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      if (peer_.SelfInitiatedConnection()) {
+        btif_queue_advance();
+      }
+      break;
+
+    case BTA_AV_OPEN_EVT: {
+      tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+      btav_connection_state_t state;
+      int av_state;
+      tBTA_AV_STATUS status = p_bta_data->open.status;
+
+      LOG_INFO(
+          LOG_TAG, "%s: Peer %s : event=%s flags=%s status=%d(%s) edr=0x%x",
+          __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
+          BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(),
+          status, (status == BTA_AV_SUCCESS) ? "SUCCESS" : "FAILED",
+          p_bta_data->open.edr);
+
+      if (p_bta_data->open.status == BTA_AV_SUCCESS) {
+        state = BTAV_CONNECTION_STATE_CONNECTED;
+        av_state = BtifAvStateMachine::kStateOpened;
+        peer_.SetEdr(p_bta_data->open.edr);
+        CHECK(peer_.PeerSep() == p_bta_data->open.sep);
+      } else {
+        if (btif_rc_is_connected_peer(peer_.PeerAddress())) {
+          // Disconnect the AVRCP connection, in case the A2DP connectiton
+          // failed for any reason.
+          BTIF_TRACE_WARNING("%s: Peer %s : Disconnecting AVRCP",
+                             __PRETTY_FUNCTION__,
+                             peer_.PeerAddress().ToString().c_str());
+          uint8_t peer_handle =
+              btif_rc_get_connected_peer_handle(peer_.PeerAddress());
+          if (peer_handle != BTRC_HANDLE_NONE) {
+            BTA_AvCloseRc(peer_handle);
+          }
+        }
+        state = BTAV_CONNECTION_STATE_DISCONNECTED;
+        av_state = BtifAvStateMachine::kStateIdle;
+      }
+
+      // Report the connection state to the application
+      btif_report_connection_state(peer_.PeerAddress(), state);
+      // Change state to Open/Idle based on the status
+      peer_.StateMachine().TransitionTo(av_state);
+      if (peer_.IsSink()) {
+        // If queued PLAY command, send it now
+        btif_rc_check_handle_pending_play(
+            p_bta_data->open.bd_addr,
+            (p_bta_data->open.status == BTA_AV_SUCCESS));
+      } else if (peer_.IsSource() &&
+                 (p_bta_data->open.status == BTA_AV_SUCCESS)) {
+        // Bring up AVRCP connection as well
+        BTA_AvOpenRc(peer_.BtaHandle());
+      }
+      if (peer_.SelfInitiatedConnection()) {
+        btif_queue_advance();
+      }
+    } break;
+
+    case BTIF_AV_SINK_CONFIG_REQ_EVT: {
+      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;
+
+    case BTIF_AV_CONNECT_REQ_EVT: {
+      // The device has moved already to Opening, hence don't report the
+      // connection state.
+      BTIF_TRACE_WARNING(
+          "%s: Peer %s : event=%s : device is already connecting, "
+          "ignore Connect request",
+          __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
+          BtifAvEvent::EventName(event).c_str());
+      btif_queue_advance();
+    } break;
+
+    case BTA_AV_PENDING_EVT: {
+      // The device has moved already to Opening, hence don't report the
+      // connection state.
+      BTIF_TRACE_WARNING(
+          "%s: Peer %s : event=%s : device is already connecting, "
+          "ignore incoming request",
+          __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
+          BtifAvEvent::EventName(event).c_str());
+    } break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened",
+                       __PRETTY_FUNCTION__,
+                       peer_.PeerAddress().ToString().c_str(),
+                       BtifAvEvent::EventName(event).c_str());
+      btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL);
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+      btif_a2dp_on_stopped(nullptr);
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTED);
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      if (peer_.SelfInitiatedConnection()) {
+        btif_queue_advance();
+      }
+      break;
+
+    case BTIF_AV_DISCONNECT_REQ_EVT:
+      BTA_AvClose(peer_.BtaHandle());
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTED);
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      if (peer_.SelfInitiatedConnection()) {
+        btif_queue_advance();
+      }
+      break;
+
+      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+    default:
+      BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+      return false;
+  }
+  return true;
+}
+
+void BtifAvStateMachine::StateOpened::OnEnter() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+
+  peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending |
+                   BtifAvPeer::kFlagPendingStart |
+                   BtifAvPeer::kFlagPendingStop);
+
+  // Set the active peer if the first connected device.
+  // NOTE: This should be done only if we are A2DP Sink, because the A2DP Sink
+  // implementation in Java doesn't support active devices (yet).
+  // For A2DP Source, the setting of the Active device is done by the
+  // ActiveDeviceManager in Java.
+  if (peer_.IsSource() && btif_av_sink.ActivePeer().IsEmpty()) {
+    if (!btif_av_sink.SetActivePeer(peer_.PeerAddress())) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
+                       peer_.PeerAddress().ToString().c_str());
+    }
+  }
+}
+
+void BtifAvStateMachine::StateOpened::OnExit() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+
+  peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
+}
+
+bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
+                                                   void* p_data) {
+  tBTA_AV* p_av = (tBTA_AV*)p_data;
+
+  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(),
+                   logbool(peer_.IsActivePeer()).c_str());
+
+  if ((event == BTA_AV_REMOTE_CMD_EVT) &&
+      peer_.CheckFlags(BtifAvPeer::kFlagRemoteSuspend) &&
+      (p_av->remote_cmd.rc_id == AVRC_ID_PLAY)) {
+    BTIF_TRACE_EVENT("%s: Peer %s : Resetting remote suspend flag on RC PLAY",
+                     __PRETTY_FUNCTION__,
+                     peer_.PeerAddress().ToString().c_str());
+    peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+  }
+
+  switch (event) {
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+    case BTIF_AV_ACL_DISCONNECTED:
+      break;  // Ignore
+
+    case BTIF_AV_START_STREAM_REQ_EVT:
+      LOG_INFO(LOG_TAG, "%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str());
+      BTA_AvStart(peer_.BtaHandle());
+      peer_.SetFlags(BtifAvPeer::kFlagPendingStart);
+      break;
+
+    case BTA_AV_START_EVT: {
+      LOG_INFO(LOG_TAG,
+               "%s: Peer %s : event=%s status=%d suspending=%d "
+               "initiator=%d flags=%s",
+               __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(), p_av->start.status,
+               p_av->start.suspending, p_av->start.initiator,
+               peer_.FlagsToString().c_str());
+
+      if ((p_av->start.status == BTA_SUCCESS) && p_av->start.suspending)
+        return true;
+
+      // If remote tries to start A2DP when DUT is A2DP Source, then Suspend.
+      // If A2DP is Sink and call is active, then disconnect the AVDTP channel.
+      bool should_suspend = false;
+      if (peer_.IsSink() && !peer_.CheckFlags(BtifAvPeer::kFlagPendingStart |
+                                              BtifAvPeer::kFlagRemoteSuspend)) {
+        BTIF_TRACE_WARNING("%s: Peer %s : trigger Suspend as remote initiated",
+                           __PRETTY_FUNCTION__,
+                           peer_.PeerAddress().ToString().c_str());
+        should_suspend = true;
+      }
+
+      // If peer is A2DP Source, we do not want to ACK commands on UIPC
+      if (peer_.IsSink() &&
+          btif_a2dp_on_started(
+              peer_.PeerAddress(), &p_av->start,
+              peer_.CheckFlags(BtifAvPeer::kFlagPendingStart))) {
+        // Only clear pending flag after acknowledgement
+        peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
+      }
+
+      // Remain in Open state if status failed
+      if (p_av->start.status != BTA_AV_SUCCESS) return false;
+
+      if (peer_.IsSource() && peer_.IsActivePeer()) {
+        // Remove flush state, ready for streaming
+        btif_a2dp_sink_set_rx_flush(false);
+      }
+
+      // Change state to Started, send acknowledgement if start is pending
+      if (peer_.IsSink() && peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
+        btif_a2dp_on_started(peer_.PeerAddress(), nullptr, true);
+        // Pending start flag will be cleared when exit current state
+      }
+
+      if (should_suspend) {
+        btif_av_source_dispatch_sm_event(peer_.PeerAddress(),
+                                         BTIF_AV_SUSPEND_STREAM_REQ_EVT);
+      }
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateStarted);
+
+    } break;
+
+    case BTIF_AV_DISCONNECT_REQ_EVT:
+      BTA_AvClose(peer_.BtaHandle());
+      if (peer_.IsSource()) {
+        BTA_AvCloseRc(peer_.BtaHandle());
+      }
+
+      // Inform the application that we are disconnecting
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTING);
+
+      // Wait in closing state until fully closed
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateClosing);
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+      // AVDTP link is closed
+      if (peer_.IsActivePeer()) {
+        btif_a2dp_on_stopped(nullptr);
+      }
+
+      // 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;
+
+    case BTA_AV_RECONFIG_EVT:
+      if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart) &&
+          (p_av->reconfig.status == BTA_AV_SUCCESS)) {
+        LOG_INFO(LOG_TAG,
+                 "%s : Peer %s : Reconfig done - calling BTA_AvStart()",
+                 __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);
+      }
+      break;
+
+    case BTIF_AV_CONNECT_REQ_EVT: {
+      BTIF_TRACE_WARNING("%s: Peer %s : Ignore %s for same device",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+      btif_queue_advance();
+    } break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened",
+                       __PRETTY_FUNCTION__,
+                       peer_.PeerAddress().ToString().c_str(),
+                       BtifAvEvent::EventName(event).c_str());
+      btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL);
+      break;
+
+    case BTIF_AV_AVRCP_REMOTE_PLAY_EVT:
+      if (peer_.CheckFlags(BtifAvPeer::kFlagRemoteSuspend)) {
+        BTIF_TRACE_EVENT(
+            "%s: Peer %s : Resetting remote suspend flag on RC PLAY",
+            __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str());
+        peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+      }
+      break;
+
+      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+    default:
+      BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+      return false;
+  }
+  return true;
+}
+
+void BtifAvStateMachine::StateStarted::OnEnter() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+
+  // We are again in started state, clear any remote suspend flags
+  peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+
+  // Report that we have entered the Streaming stage. Usually, this should
+  // be followed by focus grant. See update_audio_focus_state()
+  btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STARTED);
+}
+
+void BtifAvStateMachine::StateStarted::OnExit() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+}
+
+bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
+                                                    void* p_data) {
+  tBTA_AV* p_av = (tBTA_AV*)p_data;
+
+  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(),
+                   logbool(peer_.IsActivePeer()).c_str());
+
+  switch (event) {
+    case BTIF_AV_ACL_DISCONNECTED:
+      break;  // Ignore
+
+    case BTIF_AV_START_STREAM_REQ_EVT:
+      LOG_INFO(LOG_TAG, "%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str());
+      // We were started remotely, just ACK back the local request
+      if (peer_.IsSink())
+        btif_a2dp_on_started(peer_.PeerAddress(), nullptr, true);
+      break;
+
+    // FIXME -- use suspend = true always to work around issue with BTA AV
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+      LOG_INFO(LOG_TAG, "%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str());
+      // Set pending flag to ensure the BTIF task is not trying to restart
+      // the stream while suspend is in progress.
+      peer_.SetFlags(BtifAvPeer::kFlagLocalSuspendPending);
+
+      // If we were remotely suspended but suspend locally, local suspend
+      // always overrides.
+      peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+
+      if (peer_.IsSink()) {
+        // Immediately stop transmission of frames while suspend is pending
+        if (peer_.IsActivePeer()) {
+          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);
+      }
+      BTA_AvStop(peer_.BtaHandle(), true);
+      break;
+
+    case BTIF_AV_DISCONNECT_REQ_EVT:
+      LOG_INFO(LOG_TAG, "%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str());
+
+      // Request AVDTP to close
+      BTA_AvClose(peer_.BtaHandle());
+      if (peer_.IsSource()) {
+        BTA_AvCloseRc(peer_.BtaHandle());
+      }
+
+      // Inform the application that we are disconnecting
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTING);
+
+      // Wait in closing state until fully closed
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateClosing);
+      break;
+
+    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(),
+               BtifAvEvent::EventName(event).c_str(), p_av->suspend.status,
+               p_av->suspend.initiator, peer_.FlagsToString().c_str());
+
+      // A2DP suspended, stop A2DP encoder/decoder until resumed
+      btif_a2dp_on_suspended(&p_av->suspend);
+
+      // If not successful, remain in current state
+      if (p_av->suspend.status != BTA_AV_SUCCESS) {
+        peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
+
+        if (peer_.IsSink() && peer_.IsActivePeer()) {
+          // Suspend failed, reset back tx flush state
+          btif_a2dp_source_set_tx_flush(false);
+        }
+        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.
+        //
+        // Set remote suspend flag to block media task from restarting
+        // stream only if we did not already initiate a local suspend.
+        if (!peer_.CheckFlags(BtifAvPeer::kFlagLocalSuspendPending))
+          peer_.SetFlags(BtifAvPeer::kFlagRemoteSuspend);
+      } else {
+        state = BTAV_AUDIO_STATE_STOPPED;
+      }
+
+      // Suspend completed, clear pending status
+      peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
+
+      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__,
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str());
+
+      peer_.SetFlags(BtifAvPeer::kFlagPendingStop);
+      peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
+
+      btif_a2dp_on_stopped(&p_av->suspend);
+
+      btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STOPPED);
+
+      // If stop was successful, change state to Open
+      if (p_av->suspend.status == BTA_AV_SUCCESS)
+        peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpened);
+
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+      LOG_INFO(LOG_TAG, "%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str());
+
+      peer_.SetFlags(BtifAvPeer::kFlagPendingStop);
+
+      // AVDTP link is closed
+      if (peer_.IsActivePeer()) {
+        btif_a2dp_on_stopped(nullptr);
+      }
+
+      // Inform the application that we are disconnected
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTED);
+
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTA_AvOffloadStart(peer_.BtaHandle());
+      break;
+
+    case BTA_AV_OFFLOAD_START_RSP_EVT:
+      btif_a2dp_on_offload_started(peer_.PeerAddress(), p_av->status);
+      break;
+
+      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+    default:
+      BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+      return false;
+  }
+
+  return true;
+}
+
+void BtifAvStateMachine::StateClosing::OnEnter() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+
+  if (peer_.IsActivePeer()) {
+    if (peer_.IsSink()) {
+      // Immediately stop transmission of frames
+      btif_a2dp_source_set_tx_flush(true);
+      // Wait for Audio Flinger to stop A2DP
+    } else if (peer_.IsSource()) {
+      btif_a2dp_sink_set_rx_flush(true);
+    }
+  }
+}
+
+void BtifAvStateMachine::StateClosing::OnExit() {
+  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
+                   peer_.PeerAddress().ToString().c_str());
+}
+
+bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event,
+                                                    void* p_data) {
+  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(),
+                   logbool(peer_.IsActivePeer()).c_str());
+
+  switch (event) {
+    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+    case BTIF_AV_ACL_DISCONNECTED:
+      break;  // Ignore
+
+    case BTA_AV_STOP_EVT:
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+      if (peer_.IsActivePeer()) {
+        btif_a2dp_on_stopped(nullptr);
+      }
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+      // Inform the application that we are disconnecting
+      btif_report_connection_state(peer_.PeerAddress(),
+                                   BTAV_CONNECTION_STATE_DISCONNECTED);
+
+      peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);
+      break;
+
+    // Handle the RC_CLOSE event for the cleanup
+    case BTA_AV_RC_CLOSE_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    // Handle the RC_BROWSE_CLOSE event for testing
+    case BTA_AV_RC_BROWSE_CLOSE_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened",
+                       __PRETTY_FUNCTION__,
+                       peer_.PeerAddress().ToString().c_str(),
+                       BtifAvEvent::EventName(event).c_str());
+      btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL);
+      break;
+
+    default:
+      BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s",
+                         __PRETTY_FUNCTION__,
+                         peer_.PeerAddress().ToString().c_str(),
+                         BtifAvEvent::EventName(event).c_str());
+      return false;
+  }
+  return true;
+}
+
+/**
+ * Timer to trigger AV Open on the Source if the remote Sink device establishes
+ * AVRCP connection without AV connection. The timer is needed to interoperate
+ * with headsets that do establish AV after AVRCP connection.
+ */
+static void btif_av_source_initiate_av_open_timer_timeout(void* data) {
+  BtifAvPeer* peer = (BtifAvPeer*)data;
+
+  BTIF_TRACE_DEBUG("%s: Peer %s", __func__,
+                   peer->PeerAddress().ToString().c_str());
+
+  // Check if AVRCP is connected to the peer
+  if (!btif_rc_is_connected_peer(peer->PeerAddress())) {
+    BTIF_TRACE_ERROR("%s: AVRCP peer %s is not connected", __func__,
+                     peer->PeerAddress().ToString().c_str());
+    return;
+  }
+
+  // Connect to the AVRCP peer
+  if (btif_av_source.Enabled() &&
+      btif_av_source.FindPeer(peer->PeerAddress()) == peer) {
+    BTIF_TRACE_DEBUG("%s: Connecting to AVRCP peer %s", __func__,
+                     peer->PeerAddress().ToString().c_str());
+    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
+                                     BTIF_AV_CONNECT_REQ_EVT);
+  }
+}
+
+/**
+ * Timer to trigger AV Open on the Sink if the remote Source device establishes
+ * AVRCP connection without AV connection.
+ */
+static void btif_av_sink_initiate_av_open_timer_timeout(void* data) {
+  BtifAvPeer* peer = (BtifAvPeer*)data;
+
+  BTIF_TRACE_DEBUG("%s: Peer %s", __func__,
+                   peer->PeerAddress().ToString().c_str());
+
+  // Check if AVRCP is connected to the peer
+  if (!btif_rc_is_connected_peer(peer->PeerAddress())) {
+    BTIF_TRACE_ERROR("%s: AVRCP peer %s is not connected", __func__,
+                     peer->PeerAddress().ToString().c_str());
+    return;
+  }
+
+  // Connect to the AVRCP peer
+  if (btif_av_sink.Enabled() &&
+      btif_av_sink.FindPeer(peer->PeerAddress()) == peer) {
+    BTIF_TRACE_DEBUG("%s: Connecting to AVRCP peer %s", __func__,
+                     peer->PeerAddress().ToString().c_str());
+    btif_av_sink_dispatch_sm_event(peer->PeerAddress(),
+                                   BTIF_AV_CONNECT_REQ_EVT);
+  }
+}
+
+/**
+ * Report the A2DP connection state
+ *
+ * @param peer_address the peer address
+ * @param state the connection state
+ */
+static void btif_report_connection_state(const RawAddress& peer_address,
+                                         btav_connection_state_t state) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%d", __func__,
+           peer_address.ToString().c_str(), state);
+
+  if (btif_av_source.Enabled()) {
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(btif_av_source.Callbacks()->connection_state_cb,
+                                peer_address, state));
+  } else if (btif_av_sink.Enabled()) {
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(btif_av_sink.Callbacks()->connection_state_cb,
+                                peer_address, state));
+  }
+}
+
+/**
+ * Report the audio state of the A2DP connection.
+ * The state is updated when either the remote ends starts streaming
+ * (Started state) or whenever it transitions out of Started state
+ * (to Opened or Streaming state).
+ *
+ * @param peer_address the peer address
+ * @param state the audio state
+ */
+static void btif_report_audio_state(const RawAddress& peer_address,
+                                    btav_audio_state_t state) {
+  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%d", __func__,
+           peer_address.ToString().c_str(), state);
+
+  if (btif_av_source.Enabled()) {
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(btif_av_source.Callbacks()->audio_state_cb,
+                                peer_address, state));
+  } else if (btif_av_sink.Enabled()) {
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(btif_av_sink.Callbacks()->audio_state_cb,
+                                peer_address, state));
+  }
+}
+
+void btif_av_report_source_codec_state(
+    const RawAddress& peer_address,
+    const btav_a2dp_codec_config_t& codec_config,
+    const std::vector<btav_a2dp_codec_config_t>& codecs_local_capabilities,
+    const std::vector<btav_a2dp_codec_config_t>&
+        codecs_selectable_capabilities) {
+  BTIF_TRACE_EVENT("%s: peer_address=%s", __func__,
+                   peer_address.ToString().c_str());
+  if (btif_av_source.Enabled()) {
+    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));
+  }
+}
+
+/**
+ * Process BTIF or BTA AV or BTA AVRCP events. The processing is done on the
+ * JNI thread.
+ *
+ * @param peer_sep the corresponding peer's SEP: AVDT_TSEP_SRC if the peer
+ * is A2DP Source, or AVDT_TSEP_SNK if the peer is A2DP Sink.
+ * @param peer_address the peer address if known, otherwise RawAddress::kEmpty
+ * @param bta_handle the BTA handle for the peer if known, otherwise
+ * kBtaHandleUnknown
+ * @param btif_av_event the corresponding event
+ */
+static void btif_av_handle_event(uint8_t peer_sep,
+                                 const RawAddress& peer_address,
+                                 tBTA_AV_HNDL bta_handle,
+                                 const BtifAvEvent& btif_av_event) {
+  BtifAvPeer* peer = nullptr;
+  BTIF_TRACE_EVENT("%s: peer_sep=%s (%d) peer_address=%s handle=0x%x event=%s",
+                   __func__, (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink",
+                   peer_sep, peer_address.ToString().c_str(), bta_handle,
+                   btif_av_event.ToString().c_str());
+
+  // Find the peer
+  if (peer_address != RawAddress::kEmpty) {
+    if (peer_sep == AVDT_TSEP_SNK) {
+      peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle);
+    } else if (peer_sep == AVDT_TSEP_SRC) {
+      peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle);
+    }
+  } else if (bta_handle != kBtaHandleUnknown) {
+    if (peer_sep == AVDT_TSEP_SNK) {
+      peer = btif_av_source.FindPeerByHandle(bta_handle);
+    } else if (peer_sep == AVDT_TSEP_SRC) {
+      peer = btif_av_sink.FindPeerByHandle(bta_handle);
+    }
+  }
+  if (peer == nullptr) {
+    BTIF_TRACE_ERROR(
+        "%s: Cannot find or create %s peer for peer_address=%s handle=0x%x : "
+        "event dropped: %s",
+        __func__, (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink",
+        peer_address.ToString().c_str(), bta_handle,
+        btif_av_event.ToString().c_str());
+    return;
+  }
+
+  peer->StateMachine().ProcessEvent(btif_av_event.Event(),
+                                    btif_av_event.Data());
+}
+
+/**
+ * Process BTA AV or BTA AVRCP events. The processing is done on the JNI
+ * thread.
+ *
+ * @param peer_sep the corresponding peer's SEP: AVDT_TSEP_SRC if the peer
+ * is A2DP Source, or AVDT_TSEP_SNK if the peer is A2DP Sink.
+ * @param btif_av_event the corresponding event
+ */
+static void btif_av_handle_bta_av_event(uint8_t peer_sep,
+                                        const BtifAvEvent& btif_av_event) {
+  RawAddress peer_address = RawAddress::kEmpty;
+  tBTA_AV_HNDL bta_handle = kBtaHandleUnknown;
+  tBTA_AV_EVT event = btif_av_event.Event();
+  tBTA_AV* p_data = (tBTA_AV*)btif_av_event.Data();
+
+  BTIF_TRACE_DEBUG("%s: peer_sep=%s (%d) event=%s", __func__,
+                   (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep,
+                   btif_av_event.ToString().c_str());
+
+  switch (event) {
+    case BTA_AV_ENABLE_EVT: {
+      const tBTA_AV_ENABLE& enable = p_data->enable;
+      BTIF_TRACE_DEBUG("%s: features=0x%x", __func__, enable.features);
+      return;  // Nothing to do
+    }
+    case BTA_AV_REGISTER_EVT: {
+      const tBTA_AV_REGISTER& registr = p_data->registr;
+      bta_handle = registr.hndl;
+      uint8_t peer_id = registr.app_id;  // The PeerId is used as AppId
+      BTIF_TRACE_DEBUG("%s: handle=0x%x app_id=%d", __func__, bta_handle,
+                       registr.app_id);
+      if (peer_sep == AVDT_TSEP_SNK) {
+        btif_av_source.BtaHandleRegistered(peer_id, bta_handle);
+      } else if (peer_sep == AVDT_TSEP_SRC) {
+        btif_av_sink.BtaHandleRegistered(peer_id, bta_handle);
+      }
+      return;  // Nothing else to do
+    }
+    case BTA_AV_OPEN_EVT: {
+      const tBTA_AV_OPEN& open = p_data->open;
+      peer_address = open.bd_addr;
+      bta_handle = open.hndl;
+      break;
+    }
+    case BTA_AV_CLOSE_EVT: {
+      const tBTA_AV_CLOSE& close = p_data->close;
+      bta_handle = close.hndl;
+      break;
+    }
+    case BTA_AV_START_EVT: {
+      const tBTA_AV_START& start = p_data->start;
+      bta_handle = start.hndl;
+      break;
+    }
+    case BTA_AV_SUSPEND_EVT:
+    case BTA_AV_STOP_EVT: {
+      const tBTA_AV_SUSPEND& suspend = p_data->suspend;
+      bta_handle = suspend.hndl;
+      break;
+    }
+    case BTA_AV_PROTECT_REQ_EVT: {
+      const tBTA_AV_PROTECT_REQ& protect_req = p_data->protect_req;
+      bta_handle = protect_req.hndl;
+      break;
+    }
+    case BTA_AV_PROTECT_RSP_EVT: {
+      const tBTA_AV_PROTECT_RSP& protect_rsp = p_data->protect_rsp;
+      bta_handle = protect_rsp.hndl;
+      break;
+    }
+    case BTA_AV_RC_OPEN_EVT: {
+      const tBTA_AV_RC_OPEN& rc_open = p_data->rc_open;
+      peer_address = rc_open.peer_addr;
+      break;
+    }
+    case BTA_AV_RC_CLOSE_EVT: {
+      const tBTA_AV_RC_CLOSE& rc_close = p_data->rc_close;
+      peer_address = rc_close.peer_addr;
+      break;
+    }
+    case BTA_AV_RC_BROWSE_OPEN_EVT: {
+      const tBTA_AV_RC_BROWSE_OPEN& rc_browse_open = p_data->rc_browse_open;
+      peer_address = rc_browse_open.peer_addr;
+      break;
+    }
+    case BTA_AV_RC_BROWSE_CLOSE_EVT: {
+      const tBTA_AV_RC_BROWSE_CLOSE& rc_browse_close = p_data->rc_browse_close;
+      peer_address = rc_browse_close.peer_addr;
+      break;
+    }
+    case BTA_AV_REMOTE_CMD_EVT:
+    case BTA_AV_REMOTE_RSP_EVT:
+    case BTA_AV_VENDOR_CMD_EVT:
+    case BTA_AV_VENDOR_RSP_EVT:
+    case BTA_AV_META_MSG_EVT:
+    case BTA_AV_OFFLOAD_START_RSP_EVT: {
+      // TODO: Might be wrong - this code will be removed once those
+      // events are received from the AVRCP module.
+      if (peer_sep == AVDT_TSEP_SNK) {
+        peer_address = btif_av_source.ActivePeer();
+      } else if (peer_sep == AVDT_TSEP_SRC) {
+        peer_address = btif_av_sink.ActivePeer();
+      }
+      break;
+    }
+    case BTA_AV_RECONFIG_EVT: {
+      const tBTA_AV_RECONFIG& reconfig = p_data->reconfig;
+      bta_handle = reconfig.hndl;
+      break;
+    }
+    case BTA_AV_PENDING_EVT: {
+      const tBTA_AV_PEND& pend = p_data->pend;
+      peer_address = pend.bd_addr;
+      break;
+    }
+    case BTA_AV_REJECT_EVT: {
+      const tBTA_AV_REJECT& reject = p_data->reject;
+      peer_address = reject.bd_addr;
+      bta_handle = reject.hndl;
+      break;
+    }
+    case BTA_AV_RC_FEAT_EVT: {
+      const tBTA_AV_RC_FEAT& rc_feat = p_data->rc_feat;
+      peer_address = rc_feat.peer_addr;
+      break;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s: peer_address=%s handle=0x%x", __func__,
+                   peer_address.ToString().c_str(), bta_handle);
+
+  btif_av_handle_event(peer_sep, peer_address, bta_handle, btif_av_event);
+}
+
+static void bta_av_source_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
+  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_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_bta_thread(FROM_HERE,
+                   base::Bind(&btif_av_handle_bta_av_event,
+                              AVDT_TSEP_SRC /* peer_sep */, btif_av_event));
+}
+
+// TODO: All processing should be done on the JNI thread
+static void bta_av_sink_media_callback(tBTA_AV_EVT event,
                                        tBTA_AV_MEDIA* p_data) {
+  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+
   switch (event) {
     case BTA_AV_SINK_MEDIA_DATA_EVT: {
-      btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-      if ((state == BTIF_AV_STATE_STARTED) || (state == BTIF_AV_STATE_OPENED)) {
-        uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data);
-        BTIF_TRACE_DEBUG("%s: packets in sink queue %d", __func__, queue_len);
+      BtifAvPeer* peer = btif_av_sink_find_peer(btif_av_sink.ActivePeer());
+      if (peer != nullptr) {
+        int state = peer->StateMachine().StateId();
+        if ((state == BtifAvStateMachine::kStateStarted) ||
+            (state == BtifAvStateMachine::kStateOpened)) {
+          uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data);
+          BTIF_TRACE_DEBUG("%s: Packets in Sink queue %d", __func__, queue_len);
+        }
       }
       break;
     }
     case BTA_AV_SINK_MEDIA_CFG_EVT: {
       btif_av_sink_config_req_t config_req;
 
-      /* send a command to BT Media Task */
+      // Update the codec info of the A2DP Sink decoder
       btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info));
-      /* Switch to BTIF context */
+
       config_req.sample_rate =
           A2DP_GetTrackSampleRate(p_data->avk_config.codec_info);
       if (config_req.sample_rate == -1) {
-        APPL_TRACE_ERROR("%s: cannot get the track frequency", __func__);
+        APPL_TRACE_ERROR("%s: Cannot get the track frequency", __func__);
         break;
       }
       config_req.channel_count =
           A2DP_GetTrackChannelCount(p_data->avk_config.codec_info);
       if (config_req.channel_count == -1) {
-        APPL_TRACE_ERROR("%s: cannot get the channel count", __func__);
+        APPL_TRACE_ERROR("%s: Cannot get the channel count", __func__);
         break;
       }
-
-      config_req.peer_bd = p_data->avk_config.bd_addr;
-      btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT,
-                            (char*)&config_req, sizeof(config_req), NULL);
+      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_bta_thread(FROM_HERE, base::Bind(&btif_av_handle_event,
+                                             AVDT_TSEP_SRC,  // peer_sep
+                                             config_req.peer_address,
+                                             kBtaHandleUnknown, btif_av_event));
       break;
     }
     default:
@@ -1263,548 +2538,605 @@
   }
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_init
- *
- * Description      Initializes btif AV if not already done
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-
-bt_status_t btif_av_init(int service_id) {
-  if (btif_av_cb.sm_handle == NULL) {
-    alarm_free(av_open_on_rc_timer);
-    av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");
-
-    switch (service_id) {
-      case BTA_A2DP_SOURCE_SERVICE_ID:
-        if (!btif_a2dp_source_startup())
-          return BT_STATUS_FAIL;  // Already running
-        break;
-      case BTA_A2DP_SINK_SERVICE_ID:
-        if (!btif_a2dp_sink_startup())
-          return BT_STATUS_FAIL;  // Already running
-        break;
-      default:
-        break;
-    }
-
-    btif_enable_service(service_id);
-
-    /* Also initialize the AV state machine */
-    btif_av_cb.sm_handle = btif_sm_init(
-        (const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
-  }
-
-  return BT_STATUS_SUCCESS;
-}
-
-/*******************************************************************************
- *
- * Function         init_src
- *
- * Description      Initializes the AV interface for source mode
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-
+// Initializes the AV interface for source mode
 static bt_status_t init_src(
-    btav_source_callbacks_t* callbacks,
+    btav_source_callbacks_t* callbacks, int max_connected_audio_devices,
     std::vector<btav_a2dp_codec_config_t> codec_priorities) {
   BTIF_TRACE_EVENT("%s", __func__);
-
-  btif_av_cb.codec_priorities = codec_priorities;
-  bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
-  if (status == BT_STATUS_SUCCESS) bt_av_src_callbacks = callbacks;
-
-  return status;
+  return btif_av_source.Init(callbacks, max_connected_audio_devices,
+                             codec_priorities);
 }
 
-/*******************************************************************************
- *
- * Function         init_sink
- *
- * Description      Initializes the AV interface for sink mode
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-
+// Initializes the AV interface for sink mode
 static bt_status_t init_sink(btav_sink_callbacks_t* callbacks) {
   BTIF_TRACE_EVENT("%s", __func__);
-
-  bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
-  if (status == BT_STATUS_SUCCESS) bt_av_sink_callbacks = callbacks;
-
-  return status;
+  return btif_av_sink.Init(callbacks);
 }
 
-/*******************************************************************************
- *
- * Function         update_audio_focus_state
- *
- * Description      Updates the final focus state reported by components calling
- *                  this module.
- *
- * Returns          None
- *
- ******************************************************************************/
+// Updates the final focus state reported by components calling this module
 static void update_audio_focus_state(int state) {
   BTIF_TRACE_DEBUG("%s: state=%d", __func__, state);
   btif_a2dp_sink_set_focus_state_req((btif_a2dp_sink_focus_state_t)state);
 }
 
-/*******************************************************************************
- *
- * Function         update_audio_track_gain
- *
- * Description      Updates the track gain (used for ducking).
- *
- * Returns          None
- *
- ******************************************************************************/
+// Updates the track gain (used for ducking).
 static void update_audio_track_gain(float gain) {
   BTIF_TRACE_DEBUG("%s: gain=%f", __func__, gain);
   btif_a2dp_sink_set_audio_track_gain(gain);
 }
 
-/*******************************************************************************
- *
- * Function         connect
- *
- * Description      Establishes the AV signalling channel with the remote
- *                  headset
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
+// Establishes the AV signalling channel with the remote headset
+static bt_status_t connect_int(RawAddress* peer_address, uint16_t uuid) {
+  BTIF_TRACE_EVENT("%s: peer_address=%s uuid=0x%x", __func__,
+                   peer_address->ToString().c_str(), uuid);
 
-static bt_status_t connect_int(RawAddress* bd_addr, uint16_t uuid) {
-  btif_av_connect_req_t connect_req;
-  connect_req.target_bda = bd_addr;
-  connect_req.uuid = uuid;
-  BTIF_TRACE_EVENT("%s", __func__);
-
-  btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT,
-                   (char*)&connect_req);
-
+  BtifAvPeer* peer = nullptr;
+  if (uuid == UUID_SERVCLASS_AUDIO_SOURCE) {
+    peer = btif_av_source.FindOrCreatePeer(*peer_address, kBtaHandleUnknown);
+    if (peer == nullptr) {
+      return BT_STATUS_FAIL;
+    }
+  } else if (uuid == UUID_SERVCLASS_AUDIO_SINK) {
+    peer = btif_av_sink.FindOrCreatePeer(*peer_address, kBtaHandleUnknown);
+    if (peer == nullptr) {
+      return BT_STATUS_FAIL;
+    }
+  }
+  peer->StateMachine().ProcessEvent(BTIF_AV_CONNECT_REQ_EVT, nullptr);
   return BT_STATUS_SUCCESS;
 }
 
-static bt_status_t src_connect_sink(RawAddress* bd_addr) {
-  BTIF_TRACE_EVENT("%s", __func__);
-  CHECK_BTAV_INIT();
-
-  return btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, bd_addr, connect_int);
+// Set the active peer
+static void set_active_peer_int(uint8_t peer_sep,
+                                const RawAddress& peer_address) {
+  BTIF_TRACE_EVENT("%s: peer_sep=%s (%d) peer_address=%s", __func__,
+                   (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep,
+                   peer_address.ToString().c_str());
+  BtifAvPeer* peer = nullptr;
+  if (peer_sep == AVDT_TSEP_SNK) {
+    if (!btif_av_source.SetActivePeer(peer_address)) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
+                       peer_address.ToString().c_str());
+    }
+    return;
+  }
+  if (peer_sep == AVDT_TSEP_SRC) {
+    if (!btif_av_sink.SetActivePeer(peer_address)) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
+                       peer_address.ToString().c_str());
+    }
+    return;
+  }
+  // If reached here, we could not set the active peer
+  BTIF_TRACE_ERROR("%s: Cannot set active %s peer to %s: peer not %s", __func__,
+                   (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink",
+                   peer_address.ToString().c_str(),
+                   (peer == nullptr) ? "found" : "connected");
 }
 
-static bt_status_t sink_connect_src(RawAddress* bd_addr) {
-  BTIF_TRACE_EVENT("%s", __func__);
-  CHECK_BTAV_INIT();
+static bt_status_t src_connect_sink(const RawAddress& peer_address) {
+  BTIF_TRACE_EVENT("%s: Peer %s", __func__, peer_address.ToString().c_str());
 
-  return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, bd_addr, connect_int);
+  if (!btif_av_source.Enabled()) {
+    BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  RawAddress peer_address_copy(peer_address);
+  return btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, &peer_address_copy,
+                            connect_int);
 }
 
-/*******************************************************************************
- *
- * Function         disconnect
- *
- * Description      Tears down the AV signalling channel with the remote headset
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t disconnect(RawAddress* bd_addr) {
-  BTIF_TRACE_EVENT("%s", __func__);
-  CHECK_BTAV_INIT();
+static bt_status_t sink_connect_src(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: Peer %s", __func__, peer_address.ToString().c_str());
 
-  /* Switch to BTIF context */
-  return btif_transfer_context(btif_av_handle_event, BTIF_AV_DISCONNECT_REQ_EVT,
-                               (char*)bd_addr, sizeof(RawAddress), NULL);
+  if (!btif_av_sink.Enabled()) {
+    BTIF_TRACE_WARNING("%s: BTIF AV Sink is not enabled", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  RawAddress peer_address_copy(peer_address);
+  return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, &peer_address_copy,
+                            connect_int);
+}
+
+static bt_status_t src_disconnect_sink(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: Peer %s", __func__, peer_address.ToString().c_str());
+
+  if (!btif_av_source.Enabled()) {
+    BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address,
+                            sizeof(peer_address));
+  return do_in_bta_thread(
+      FROM_HERE, base::Bind(&btif_av_handle_event,
+                            AVDT_TSEP_SNK,  // peer_sep
+                            peer_address, kBtaHandleUnknown, btif_av_event));
+}
+
+static bt_status_t sink_disconnect_src(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: Peer %s", __func__, peer_address.ToString().c_str());
+
+  if (!btif_av_sink.Enabled()) {
+    BTIF_TRACE_WARNING("%s: BTIF AV Sink is not enabled", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address,
+                            sizeof(peer_address));
+  return do_in_bta_thread(
+      FROM_HERE, base::Bind(&btif_av_handle_event,
+                            AVDT_TSEP_SRC,  // peer_sep
+                            peer_address, kBtaHandleUnknown, btif_av_event));
+}
+
+static bt_status_t src_set_active_sink(const RawAddress& peer_address) {
+  BTIF_TRACE_EVENT("%s: Peer %s", __func__, peer_address.ToString().c_str());
+
+  if (!btif_av_source.Enabled()) {
+    BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  return do_in_bta_thread(FROM_HERE, base::Bind(&set_active_peer_int,
+                                                AVDT_TSEP_SNK,  // peer_sep
+                                                peer_address));
 }
 
 static bt_status_t codec_config_src(
+    const RawAddress& peer_address,
     std::vector<btav_a2dp_codec_config_t> codec_preferences) {
   BTIF_TRACE_EVENT("%s", __func__);
-  CHECK_BTAV_INIT();
 
-  for (auto cp : codec_preferences) {
-    BTIF_TRACE_DEBUG(
-        "%s: codec_type=%d codec_priority=%d "
-        "sample_rate=0x%x bits_per_sample=0x%x "
-        "channel_mode=0x%x codec_specific_1=%d "
-        "codec_specific_2=%d codec_specific_3=%d "
-        "codec_specific_4=%d",
-        __func__, cp.codec_type, cp.codec_priority, cp.sample_rate,
-        cp.bits_per_sample, cp.channel_mode, cp.codec_specific_1,
-        cp.codec_specific_2, cp.codec_specific_3, cp.codec_specific_4);
-    btif_transfer_context(btif_av_handle_event, BTIF_AV_SOURCE_CONFIG_REQ_EVT,
-                          reinterpret_cast<char*>(&cp), sizeof(cp), NULL);
+  if (!btif_av_source.Enabled()) {
+    BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+    return BT_STATUS_NOT_READY;
   }
 
-  return BT_STATUS_SUCCESS;
-}
-
-/*******************************************************************************
- *
- * Function         cleanup
- *
- * Description      Shuts down the AV interface and does the cleanup
- *
- * Returns          None
- *
- ******************************************************************************/
-static void cleanup(int service_uuid) {
-  BTIF_TRACE_EVENT("%s", __func__);
-
-  btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0,
-                        NULL);
-
-  btif_disable_service(service_uuid);
-
-  alarm_free(av_open_on_rc_timer);
-  av_open_on_rc_timer = NULL;
-
-  /* Also shut down the AV state machine */
-  btif_sm_shutdown(btif_av_cb.sm_handle);
-  btif_av_cb.sm_handle = NULL;
+  return do_in_bta_thread(
+      FROM_HERE, base::Bind(&BtifAvSource::UpdateCodecConfig,
+                            base::Unretained(&btif_av_source), peer_address,
+                            codec_preferences));
 }
 
 static void cleanup_src(void) {
   BTIF_TRACE_EVENT("%s", __func__);
-
-  btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE);
-  if (bt_av_src_callbacks) {
-    bt_av_src_callbacks = NULL;
-    if (bt_av_sink_callbacks == NULL) cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
-  }
+  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__);
-
-  btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK);
-  if (bt_av_sink_callbacks) {
-    bt_av_sink_callbacks = NULL;
-    if (bt_av_src_callbacks == NULL) cleanup(BTA_A2DP_SINK_SERVICE_ID);
-  }
+  do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSink::Cleanup,
+                                         base::Unretained(&btif_av_sink)));
 }
 
 static const btav_source_interface_t bt_av_src_interface = {
     sizeof(btav_source_interface_t),
     init_src,
     src_connect_sink,
-    disconnect,
+    src_disconnect_sink,
+    src_set_active_sink,
     codec_config_src,
     cleanup_src,
 };
 
 static const btav_sink_interface_t bt_av_sink_interface = {
-    sizeof(btav_sink_interface_t),
-    init_sink,
-    sink_connect_src,
-    disconnect,
-    cleanup_sink,
-    update_audio_focus_state,
+    sizeof(btav_sink_interface_t), init_sink,    sink_connect_src,
+    sink_disconnect_src,           cleanup_sink, update_audio_focus_state,
     update_audio_track_gain,
 };
 
-/*******************************************************************************
- *
- * Function         btif_av_get_addr
- *
- * Description      Fetches current AV BD address
- *
- * Returns          BD address
- *
- ******************************************************************************/
+RawAddress btif_av_source_active_peer(void) {
+  return btif_av_source.ActivePeer();
+}
+RawAddress btif_av_sink_active_peer(void) { return btif_av_sink.ActivePeer(); }
 
-RawAddress btif_av_get_addr(void) { return btif_av_cb.peer_bda; }
+bool btif_av_is_sink_enabled(void) { return btif_av_sink.Enabled(); }
 
-/*******************************************************************************
- * Function         btif_av_is_sink_enabled
- *
- * Description      Checks if A2DP Sink is enabled or not
- *
- * Returns          true if A2DP Sink is enabled, false otherwise
- *
- ******************************************************************************/
-
-bool btif_av_is_sink_enabled(void) {
-  return (bt_av_sink_callbacks != NULL) ? true : false;
+void btif_av_stream_start(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  btif_av_source_dispatch_sm_event(btif_av_source_active_peer(),
+                                   BTIF_AV_START_STREAM_REQ_EVT);
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_stream_ready
- *
- * Description      Checks whether AV is ready for starting a stream
- *
- * Returns          None
- *
- ******************************************************************************/
+void btif_av_stream_stop(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s peer %s", __func__, peer_address.ToString().c_str());
+
+  if (!peer_address.IsEmpty()) {
+    btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_STOP_STREAM_REQ_EVT);
+    return;
+  }
+
+  // The active peer might have changed and we might be in the process
+  // of reconfiguring the stream. We need to stop the appopriate peer(s).
+  for (auto it : btif_av_source.Peers()) {
+    const BtifAvPeer* peer = it.second;
+    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
+                                     BTIF_AV_STOP_STREAM_REQ_EVT);
+  }
+}
+
+void btif_av_stream_suspend(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  // The active peer might have changed and we might be in the process
+  // of reconfiguring the stream. We need to suspend the appropriate peer(s).
+  for (auto it : btif_av_source.Peers()) {
+    const BtifAvPeer* peer = it.second;
+    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
+                                     BTIF_AV_SUSPEND_STREAM_REQ_EVT);
+  }
+}
+
+void btif_av_stream_start_offload(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  btif_av_source_dispatch_sm_event(btif_av_source_active_peer(),
+                                   BTIF_AV_OFFLOAD_START_REQ_EVT);
+}
+
+void btif_av_src_disconnect_sink(const RawAddress& peer_address) {
+  LOG_INFO(LOG_TAG, "%s: peer %s", __func__, peer_address.ToString().c_str());
+  src_disconnect_sink(peer_address);
+}
 
 bool btif_av_stream_ready(void) {
-  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-
-  BTIF_TRACE_DEBUG("%s: sm_handle=%d, state=%d, flags=0x%x", __func__,
-                   btif_av_cb.sm_handle, state, btif_av_cb.flags);
-
-  /* also make sure main adapter is enabled */
+  // Make sure the main adapter is enabled
   if (btif_is_enabled() == 0) {
-    BTIF_TRACE_EVENT("%s: main adapter not enabled", __func__);
+    BTIF_TRACE_EVENT("%s: Main adapter is not enabled", __func__);
     return false;
   }
 
-  /* check if we are remotely suspended or stop is pending */
-  if (btif_av_cb.flags &
-      (BTIF_AV_FLAG_REMOTE_SUSPEND | BTIF_AV_FLAG_PENDING_STOP))
+  BtifAvPeer* peer = btif_av_find_active_peer();
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No active peer found", __func__);
     return false;
+  }
 
-  return (state == BTIF_AV_STATE_OPENED);
+  int state = peer->StateMachine().StateId();
+  LOG_INFO(LOG_TAG, "%s: Peer %s : state=%d, flags=%s", __func__,
+           peer->PeerAddress().ToString().c_str(), state,
+           peer->FlagsToString().c_str());
+  // check if we are remotely suspended or stop is pending
+  if (peer->CheckFlags(BtifAvPeer::kFlagRemoteSuspend |
+                       BtifAvPeer::kFlagPendingStop)) {
+    return false;
+  }
+
+  return (state == BtifAvStateMachine::kStateOpened);
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_stream_started_ready
- *
- * Description      Checks whether AV ready for media start in streaming state
- *
- * Returns          None
- *
- ******************************************************************************/
-
 bool btif_av_stream_started_ready(void) {
-  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-  bool ready = false;
-
-  /* disallow media task to start if we have pending actions */
-  if (btif_av_cb.flags &
-      (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND |
-       BTIF_AV_FLAG_PENDING_STOP)) {
-    ready = false;
-  } else {
-    ready = (state == BTIF_AV_STATE_STARTED);
+  BtifAvPeer* peer = btif_av_find_active_peer();
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No active peer found", __func__);
+    return false;
   }
 
-  BTIF_TRACE_WARNING("%s: sm_handle=%d state=%d flags=0x%x ready=%d", __func__,
-                     btif_av_cb.sm_handle, state, btif_av_cb.flags, ready);
+  int state = peer->StateMachine().StateId();
+  bool ready = false;
+  if (peer->CheckFlags(BtifAvPeer::kFlagLocalSuspendPending |
+                       BtifAvPeer::kFlagRemoteSuspend |
+                       BtifAvPeer::kFlagPendingStop)) {
+    // Disallow media task to start if we have pending actions
+    ready = false;
+  } else {
+    ready = (state == BtifAvStateMachine::kStateStarted);
+  }
+  LOG_INFO(LOG_TAG, "%s: Peer %s : state=%d flags=%s ready=%d", __func__,
+           peer->PeerAddress().ToString().c_str(), state,
+           peer->FlagsToString().c_str(), ready);
 
   return ready;
 }
 
-/*******************************************************************************
- *
- * Function         btif_dispatch_sm_event
- *
- * Description      Send event to AV statemachine
- *
- * Returns          None
- *
- ******************************************************************************/
+static void btif_av_source_dispatch_sm_event(const RawAddress& peer_address,
+                                             btif_av_sm_event_t event) {
+  BtifAvEvent btif_av_event(event, nullptr, 0);
+  BTIF_TRACE_EVENT("%s: peer_address=%s event=%s", __func__,
+                   peer_address.ToString().c_str(),
+                   btif_av_event.ToString().c_str());
 
-/* used to pass events to AV statemachine from other tasks */
-void btif_dispatch_sm_event(btif_av_sm_event_t event, void* p_data, int len) {
-  /* Switch to BTIF context */
-  btif_transfer_context(btif_av_handle_event, event, (char*)p_data, len, NULL);
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&btif_av_handle_event,
+                              AVDT_TSEP_SNK,  // peer_sep
+                              peer_address, kBtaHandleUnknown, btif_av_event));
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_execute_service
- *
- * Description      Initializes/Shuts down the service
- *
- * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
- *
- ******************************************************************************/
-bt_status_t btif_av_execute_service(bool b_enable) {
-  if (b_enable) {
-/* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
- * handle this request in order to allow incoming connections to succeed.
- * We need to put this back once support for this is added */
+static void btif_av_sink_dispatch_sm_event(const RawAddress& peer_address,
+                                           btif_av_sm_event_t event) {
+  BtifAvEvent btif_av_event(event, nullptr, 0);
+  BTIF_TRACE_EVENT("%s: peer_address=%s event=%s", __func__,
+                   peer_address.ToString().c_str(),
+                   btif_av_event.ToString().c_str());
 
-/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
- * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
- * be initiated by the app/audioflinger layers */
-/* Support for browsing for SDP record should work only if we enable BROWSE
- * while registering. */
-#if (AVRC_METADATA_INCLUDED == TRUE)
-    BTA_AvEnable(BTA_SEC_AUTHENTICATE,
-                 BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
-                     BTA_AV_FEAT_NO_SCO_SSPD
+  do_in_bta_thread(FROM_HERE,
+                   base::Bind(&btif_av_handle_event,
+                              AVDT_TSEP_SRC,  // peer_sep
+                              peer_address, kBtaHandleUnknown, btif_av_event));
+}
+
+bt_status_t btif_av_source_execute_service(bool enable) {
+  BTIF_TRACE_EVENT("%s: Source service: %s", __func__,
+                   (enable) ? "enable" : "disable");
+
+  if (enable) {
+    // TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+    // handle this request in order to allow incoming connections to succeed.
+    // We need to put this back once support for this is added.
+
+    // Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+    // auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+    // be initiated by the app/audioflinger layers.
+    // Support for browsing for SDP record should work only if we enable BROWSE
+    // while registering.
+    tBTA_AV_FEAT features = BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA |
+                            BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_NO_SCO_SSPD;
+
+    if (delay_reporting_enabled()) {
+      features |= BTA_AV_FEAT_DELAY_RPT;
+    }
+
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-                     | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL |
-                     BTA_AV_FEAT_BROWSE
+    features |= BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_BROWSE;
 #endif
-                 ,
-                 bte_av_callback);
-#else
-    BTA_AvEnable(BTA_SEC_AUTHENTICATE,
-                 (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD), bte_av_callback);
-#endif
-    BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, NULL,
-                   UUID_SERVCLASS_AUDIO_SOURCE);
-  } else {
-    BTA_AvDeregister(btif_av_cb.bta_handle);
-    BTA_AvDisable();
+    BTA_AvEnable(BTA_SEC_AUTHENTICATE, features, bta_av_source_callback);
+    btif_av_source.RegisterAllBtaHandles();
+    return BT_STATUS_SUCCESS;
   }
+
+  // Disable the service
+  btif_av_source.DeregisterAllBtaHandles();
+  BTA_AvDisable();
   return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_sink_execute_service
- *
- * Description      Initializes/Shuts down the service
- *
- * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
- *
- ******************************************************************************/
-bt_status_t btif_av_sink_execute_service(bool b_enable) {
-  if (b_enable) {
-    /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
-     * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
-     * be initiated by the app/audioflinger layers */
-    BTA_AvEnable(BTA_SEC_AUTHENTICATE,
-                 BTA_AV_FEAT_NO_SCO_SSPD | BTA_AV_FEAT_RCCT |
-                     BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
-                     BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCTG |
-                     BTA_AV_FEAT_BROWSE,
-                 bte_av_callback);
-    BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0,
-                   bte_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
-  } else {
-    BTA_AvDeregister(btif_av_cb.bta_handle);
-    BTA_AvDisable();
+bt_status_t btif_av_sink_execute_service(bool enable) {
+  BTIF_TRACE_EVENT("%s: Sink service: %s", __func__,
+                   (enable) ? "enable" : "disable");
+
+  if (enable) {
+    // Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+    // auto-suspend AV streaming on AG events (SCO or Call). The suspend shall
+    // be initiated by the app/audioflinger layers.
+    tBTA_AV_FEAT features = BTA_AV_FEAT_NO_SCO_SSPD | BTA_AV_FEAT_RCCT |
+                            BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
+                            BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCTG |
+                            BTA_AV_FEAT_BROWSE;
+    BTA_AvEnable(BTA_SEC_AUTHENTICATE, features, bta_av_sink_callback);
+    btif_av_sink.RegisterAllBtaHandles();
+    return BT_STATUS_SUCCESS;
   }
+
+  // Disable the service
+  btif_av_sink.DeregisterAllBtaHandles();
+  BTA_AvDisable();
   return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_get_src_interface
- *
- * Description      Get the AV callback interface for A2DP source profile
- *
- * Returns          btav_source_interface_t
- *
- ******************************************************************************/
+// Get the AV callback interface for A2DP source profile
 const btav_source_interface_t* btif_av_get_src_interface(void) {
   BTIF_TRACE_EVENT("%s", __func__);
   return &bt_av_src_interface;
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_get_sink_interface
- *
- * Description      Get the AV callback interface for A2DP sink profile
- *
- * Returns          btav_sink_interface_t
- *
- ******************************************************************************/
+// Get the AV callback interface for A2DP sink profile
 const btav_sink_interface_t* btif_av_get_sink_interface(void) {
   BTIF_TRACE_EVENT("%s", __func__);
   return &bt_av_sink_interface;
 }
 
-/*******************************************************************************
- *
- * Function         btif_av_is_connected
- *
- * Description      Checks if av has a connected sink
- *
- * Returns          bool
- *
- ******************************************************************************/
 bool btif_av_is_connected(void) {
-  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-  return ((state == BTIF_AV_STATE_OPENED) || (state == BTIF_AV_STATE_STARTED));
-}
-
-uint8_t btif_av_get_peer_sep(void) { return btif_av_cb.peer_sep; }
-
-/*******************************************************************************
- *
- * Function         btif_av_is_peer_edr
- *
- * Description      Check if the connected a2dp device supports
- *                  EDR or not. Only when connected this function
- *                  will accurately provide a true capability of
- *                  remote peer. If not connected it will always be false.
- *
- * Returns          true if remote device is capable of EDR
- *
- ******************************************************************************/
-bool btif_av_is_peer_edr(void) {
-  ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
-
-  if (btif_av_cb.edr)
-    return true;
-  else
+  BtifAvPeer* peer = btif_av_find_active_peer();
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No active peer found", __func__);
     return false;
-}
-
-/******************************************************************************
- *
- * Function        btif_av_clear_remote_suspend_flag
- *
- * Description     Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
- *
- * Returns          void
- *****************************************************************************/
-void btif_av_clear_remote_suspend_flag(void) {
-  BTIF_TRACE_DEBUG("%s: flags=0x%x", __func__, btif_av_cb.flags);
-  btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
-}
-
-/*******************************************************************************
- *
- * Function         btif_av_peer_supports_3mbps
- *
- * Description      Check if the connected A2DP device supports
- *                  3 Mbps EDR. This function only works if connected.
- *                  If not connected it will always be false.
- *
- * Returns          true if remote device is EDR and supports 3 Mbps
- *
- ******************************************************************************/
-bool btif_av_peer_supports_3mbps(void) {
-  bool is3mbps = ((btif_av_cb.edr & BTA_AV_EDR_3MBPS) != 0);
-  BTIF_TRACE_DEBUG("%s: connected %d, edr_3mbps %d", __func__,
-                   btif_av_is_connected(), is3mbps);
-  return (btif_av_is_connected() && is3mbps);
-}
-
-/*******************************************************************************
- *
- * Function         btif_av_move_idle
- *
- * Description      Opening state is intermediate state. It cannot handle
- *                  incoming/outgoing connect/disconnect requests.When ACL
- *                  is disconnected and we are in opening state then move back
- *                  to idle state which is proper to handle connections.
- *
- * Returns          Void
- *
- ******************************************************************************/
-void btif_av_move_idle(RawAddress bd_addr) {
-  /* inform the application that ACL is disconnected and move to idle state */
-  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-  BTIF_TRACE_WARNING("%s: ACL Disconnected state %d bd_addr=%s peer_bda=%s",
-                     __func__, state, bd_addr.ToString().c_str(),
-                     btif_av_cb.peer_bda.ToString().c_str());
-
-  if (state == BTIF_AV_STATE_OPENING && (bd_addr == btif_av_cb.peer_bda)) {
-    BTIF_TRACE_DEBUG(
-        "%s: Moving State from Opening to Idle due to ACL disconnect",
-        __func__);
-    btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
-                                 &(btif_av_cb.peer_bda));
-    btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
   }
+
+  bool connected = peer->IsConnected();
+  BTIF_TRACE_DEBUG("%s: Peer %s is %s", __func__,
+                   peer->PeerAddress().ToString().c_str(),
+                   (connected) ? "connected" : "not connected");
+  return connected;
+}
+
+uint8_t btif_av_get_peer_sep(void) {
+  BtifAvPeer* peer = btif_av_find_active_peer();
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No active peer found", __func__);
+    return AVDT_TSEP_SNK;
+  }
+
+  uint8_t peer_sep = peer->PeerSep();
+  BTIF_TRACE_DEBUG("%s: Peer %s SEP is %s (%d)", __func__,
+                   peer->PeerAddress().ToString().c_str(),
+                   (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep);
+  return peer_sep;
+}
+
+void btif_av_clear_remote_suspend_flag(void) {
+  BtifAvPeer* peer = btif_av_find_active_peer();
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No active peer found", __func__);
+    return;
+  }
+
+  BTIF_TRACE_DEBUG("%s: Peer %s : flags=%s are cleared", __func__,
+                   peer->PeerAddress().ToString().c_str(),
+                   peer->FlagsToString().c_str());
+  peer->ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+}
+
+void btif_av_avrcp_event_open(const RawAddress& peer_address) {
+  // TODO: We need a better demultipexing mechanism whether the remote device
+  // is an A2DP Source or a Sink.
+  if (btif_av_source.Enabled()) {
+    BtifAvPeer* peer =
+        btif_av_source.FindOrCreatePeer(peer_address, kBtaHandleUnknown);
+    if (peer != nullptr) {
+      btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_OPEN_EVT);
+      return;
+    }
+  } else if (btif_av_sink.Enabled()) {
+    BtifAvPeer* peer =
+        btif_av_sink.FindOrCreatePeer(peer_address, kBtaHandleUnknown);
+    if (peer != nullptr) {
+      btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_OPEN_EVT);
+      return;
+    }
+  }
+  BTIF_TRACE_ERROR("%s: event ignored: cannot find or create peer state for %s",
+                   __func__, peer_address.ToString().c_str());
+}
+
+void btif_av_avrcp_event_close(const RawAddress& peer_address) {
+  // TODO: We need a better demultipexing mechanism whether the remote device
+  // is an A2DP Source or a Sink.
+  if (btif_av_source.Enabled()) {
+    btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_CLOSE_EVT);
+  } else if (btif_av_sink.Enabled()) {
+    btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_CLOSE_EVT);
+  }
+}
+
+void btif_av_avrcp_event_remote_play(const RawAddress& peer_address) {
+  // TODO: We need a better demultipexing mechanism whether the remote device
+  // is an A2DP Source or a Sink.
+  if (btif_av_source.Enabled()) {
+    btif_av_source_dispatch_sm_event(peer_address,
+                                     BTIF_AV_AVRCP_REMOTE_PLAY_EVT);
+  } else if (btif_av_sink.Enabled()) {
+    btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_REMOTE_PLAY_EVT);
+  }
+}
+
+bool btif_av_is_peer_edr(const RawAddress& peer_address) {
+  BtifAvPeer* peer = btif_av_find_peer(peer_address);
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No peer found for peer_address=%s", __func__,
+                       peer_address.ToString().c_str());
+    return false;
+  }
+  if (!peer->IsConnected()) {
+    BTIF_TRACE_WARNING("%s: Peer %s is not connected", __func__,
+                       peer_address.ToString().c_str());
+    return false;
+  }
+
+  bool is_edr = peer->IsEdr();
+  BTIF_TRACE_DEBUG("%s: Peer %s : is_edr=%d", __func__,
+                   peer_address.ToString().c_str(), is_edr);
+  return is_edr;
+}
+
+bool btif_av_peer_supports_3mbps(const RawAddress& peer_address) {
+  BtifAvPeer* peer = btif_av_find_peer(peer_address);
+  if (peer == nullptr) {
+    BTIF_TRACE_WARNING("%s: No peer found for peer_address=%s", __func__,
+                       peer_address.ToString().c_str());
+    return false;
+  }
+
+  bool is3mbps = peer->Is3Mbps();
+  bool is_connected = peer->IsConnected();
+  BTIF_TRACE_DEBUG("%s: Peer %s : connected=%d, edr_3mbps=%d", __func__,
+                   peer_address.ToString().c_str(), is_connected, is3mbps);
+  return (is_connected && is3mbps);
+}
+
+void btif_av_acl_disconnected(const RawAddress& peer_address) {
+  // Inform the application that ACL is disconnected and move to idle state
+  LOG_INFO(LOG_TAG, "%s: Peer %s : ACL Disconnected", __func__,
+           peer_address.ToString().c_str());
+
+  if (btif_av_source.Enabled()) {
+    btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_ACL_DISCONNECTED);
+  } else if (btif_av_sink.Enabled()) {
+    btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_ACL_DISCONNECTED);
+  }
+}
+
+static void btif_debug_av_peer_dump(int fd, const BtifAvPeer& peer) {
+  std::string state_str;
+  int state = peer.StateMachine().StateId();
+  switch (state) {
+    case BtifAvStateMachine::kStateIdle:
+      state_str = "Idle";
+      break;
+    case BtifAvStateMachine::kStateOpening:
+      state_str = "Opening";
+      break;
+    case BtifAvStateMachine::kStateOpened:
+      state_str = "Opened";
+      break;
+    case BtifAvStateMachine::kStateStarted:
+      state_str = "Started";
+      break;
+    case BtifAvStateMachine::kStateClosing:
+      state_str = "Closing";
+      break;
+    default:
+      state_str = "Unknown(" + std::to_string(state) + ")";
+      break;
+  }
+
+  dprintf(fd, "  Peer: %s\n", peer.PeerAddress().ToString().c_str());
+  dprintf(fd, "    Connected: %s\n", peer.IsConnected() ? "true" : "false");
+  dprintf(fd, "    Streaming: %s\n", peer.IsStreaming() ? "true" : "false");
+  dprintf(fd, "    SEP: %d(%s)\n", peer.PeerSep(),
+          (peer.IsSource()) ? "Source" : "Sink");
+  dprintf(fd, "    State Machine: %s\n", state_str.c_str());
+  dprintf(fd, "    Flags: %s\n", peer.FlagsToString().c_str());
+  dprintf(fd, "    OpenOnRcTimer: %s\n",
+          alarm_is_scheduled(peer.AvOpenOnRcTimer()) ? "Scheduled"
+                                                     : "Not scheduled");
+  dprintf(fd, "    BTA Handle: 0x%x\n", peer.BtaHandle());
+  dprintf(fd, "    Peer ID: %d\n", peer.PeerId());
+  dprintf(fd, "    EDR: %s\n", peer.IsEdr() ? "true" : "false");
+  dprintf(fd, "    Support 3Mbps: %s\n", peer.Is3Mbps() ? "true" : "false");
+  dprintf(fd, "    Self Initiated Connection: %s\n",
+          peer.SelfInitiatedConnection() ? "true" : "false");
+}
+
+static void btif_debug_av_source_dump(int fd) {
+  bool enabled = btif_av_source.Enabled();
+
+  dprintf(fd, "\nA2DP Source State: %s\n", (enabled) ? "Enabled" : "Disabled");
+  if (!enabled) return;
+  dprintf(fd, "  Active peer: %s\n",
+          btif_av_source.ActivePeer().ToString().c_str());
+  for (auto it : btif_av_source.Peers()) {
+    const BtifAvPeer* peer = it.second;
+    btif_debug_av_peer_dump(fd, *peer);
+  }
+}
+
+static void btif_debug_av_sink_dump(int fd) {
+  bool enabled = btif_av_sink.Enabled();
+
+  dprintf(fd, "\nA2DP Sink State: %s\n", (enabled) ? "Enabled" : "Disabled");
+  if (!enabled) return;
+  dprintf(fd, "  Active peer: %s\n",
+          btif_av_sink.ActivePeer().ToString().c_str());
+  dprintf(fd, "  Peers:\n");
+  for (auto it : btif_av_sink.Peers()) {
+    const BtifAvPeer* peer = it.second;
+    btif_debug_av_peer_dump(fd, *peer);
+  }
+}
+
+void btif_debug_av_dump(int fd) {
+  btif_debug_av_source_dump(fd);
+  btif_debug_av_sink_dump(fd);
+}
+
+void btif_av_set_audio_delay(uint16_t delay) {
+  btif_a2dp_control_set_audio_delay(delay);
+}
+
+void btif_av_reset_audio_delay(void) { btif_a2dp_control_reset_audio_delay(); }
+
+bool btif_av_is_a2dp_offload_enabled() {
+  return btif_av_source.A2dpOffloadEnabled();
 }
diff --git a/btif/src/btif_avrcp_audio_track.cc b/btif/src/btif_avrcp_audio_track.cc
index 8e192f7..76da406 100644
--- a/btif/src/btif_avrcp_audio_track.cc
+++ b/btif/src/btif_avrcp_audio_track.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright 2015 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.
diff --git a/btif/src/btif_ble_advertiser.cc b/btif/src/btif_ble_advertiser.cc
index 3c02882..e24bcde 100644
--- a/btif/src/btif_ble_advertiser.cc
+++ b/btif/src/btif_ble_advertiser.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google Inc.
+ *  Copyright 2016 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -95,7 +95,7 @@
   void RegisterAdvertiser(IdStatusCallback cb) override {
     do_in_bta_thread(
         FROM_HERE, Bind(&BleAdvertisingManager::RegisterAdvertiser,
-                        base::Unretained(BleAdvertisingManager::Get()),
+                        BleAdvertisingManager::Get(),
                         Bind(&BleAdvertiserInterfaceImpl::RegisterAdvertiserCb,
                              base::Unretained(this), cb)));
   }
@@ -115,33 +115,35 @@
   }
 
   void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override {
+    if (!BleAdvertisingManager::IsInitialized()) return;
     do_in_bta_thread(FROM_HERE,
                      Bind(&BleAdvertisingManager::GetOwnAddress,
-                          base::Unretained(BleAdvertisingManager::Get()),
-                          advertiser_id, jni_thread_wrapper(FROM_HERE, cb)));
+                          BleAdvertisingManager::Get(), advertiser_id,
+                          jni_thread_wrapper(FROM_HERE, cb)));
   }
 
   void SetParameters(uint8_t advertiser_id, AdvertiseParameters params,
                      ParametersCallback cb) override {
     VLOG(1) << __func__;
 
+    if (!BleAdvertisingManager::IsInitialized()) return;
     tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
     parseParams(p_params, params);
 
-    do_in_bta_thread(
-        FROM_HERE,
-        Bind(&BleAdvertisingManager::SetParameters,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
-             base::Owned(p_params), jni_thread_wrapper(FROM_HERE, cb)));
+    do_in_bta_thread(FROM_HERE, Bind(&BleAdvertisingManager::SetParameters,
+                                     BleAdvertisingManager::Get(),
+                                     advertiser_id, base::Owned(p_params),
+                                     jni_thread_wrapper(FROM_HERE, cb)));
   }
 
   void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
                StatusCallback cb) override {
+    if (!BleAdvertisingManager::IsInitialized()) return;
     do_in_bta_thread(
         FROM_HERE,
-        Bind(&BleAdvertisingManager::SetData,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
-             set_scan_rsp, std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
+        Bind(&BleAdvertisingManager::SetData, BleAdvertisingManager::Get(),
+             advertiser_id, set_scan_rsp, std::move(data),
+             jni_thread_wrapper(FROM_HERE, cb)));
   }
 
   void Enable(uint8_t advertiser_id, bool enable, StatusCallback cb,
@@ -150,11 +152,11 @@
     VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id
             << " ,enable: " << enable;
 
+    if (!BleAdvertisingManager::IsInitialized()) return;
     do_in_bta_thread(
         FROM_HERE,
-        Bind(&BleAdvertisingManager::Enable,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
-             enable, jni_thread_wrapper(FROM_HERE, cb), duration,
+        Bind(&BleAdvertisingManager::Enable, BleAdvertisingManager::Get(),
+             advertiser_id, enable, jni_thread_wrapper(FROM_HERE, cb), duration,
              maxExtAdvEvents, jni_thread_wrapper(FROM_HERE, timeout_cb)));
   }
 
@@ -165,13 +167,14 @@
                         MultiAdvCb timeout_cb) override {
     VLOG(1) << __func__;
 
+    if (!BleAdvertisingManager::IsInitialized()) return;
     tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
     parseParams(p_params, params);
 
     do_in_bta_thread(
         FROM_HERE,
         Bind(&BleAdvertisingManager::StartAdvertising,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+             BleAdvertisingManager::Get(), advertiser_id,
              jni_thread_wrapper(FROM_HERE, cb), base::Owned(p_params),
              std::move(advertise_data), std::move(scan_response_data),
              timeout_s * 100, jni_thread_wrapper(FROM_HERE, timeout_cb)));
@@ -187,6 +190,7 @@
                            IdStatusCallback timeout_cb) override {
     VLOG(1) << __func__;
 
+    if (!BleAdvertisingManager::IsInitialized()) return;
     tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
     parseParams(p_params, params);
 
@@ -196,11 +200,11 @@
     do_in_bta_thread(
         FROM_HERE,
         Bind(&BleAdvertisingManager::StartAdvertisingSet,
-             base::Unretained(BleAdvertisingManager::Get()),
-             jni_thread_wrapper(FROM_HERE, cb), base::Owned(p_params),
-             std::move(advertise_data), std::move(scan_response_data),
-             base::Owned(p_periodic_params), std::move(periodic_data), duration,
-             maxExtAdvEvents, jni_thread_wrapper(FROM_HERE, timeout_cb)));
+             BleAdvertisingManager::Get(), jni_thread_wrapper(FROM_HERE, cb),
+             base::Owned(p_params), std::move(advertise_data),
+             std::move(scan_response_data), base::Owned(p_periodic_params),
+             std::move(periodic_data), duration, maxExtAdvEvents,
+             jni_thread_wrapper(FROM_HERE, timeout_cb)));
   }
 
   void SetPeriodicAdvertisingParameters(
@@ -208,13 +212,14 @@
       StatusCallback cb) override {
     VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id;
 
+    if (!BleAdvertisingManager::IsInitialized()) return;
     tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS;
     parsePeriodicParams(p_periodic_params, periodic_params);
 
     do_in_bta_thread(
         FROM_HERE,
         Bind(&BleAdvertisingManager::SetPeriodicAdvertisingParameters,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+             BleAdvertisingManager::Get(), advertiser_id,
              base::Owned(p_periodic_params),
              jni_thread_wrapper(FROM_HERE, cb)));
   }
@@ -223,11 +228,11 @@
                                   StatusCallback cb) override {
     VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id;
 
-    do_in_bta_thread(
-        FROM_HERE,
-        Bind(&BleAdvertisingManager::SetPeriodicAdvertisingData,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
-             std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
+    if (!BleAdvertisingManager::IsInitialized()) return;
+    do_in_bta_thread(FROM_HERE,
+                     Bind(&BleAdvertisingManager::SetPeriodicAdvertisingData,
+                          BleAdvertisingManager::Get(), advertiser_id,
+                          std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
   }
 
   void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable,
@@ -235,11 +240,11 @@
     VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id
             << " ,enable: " << enable;
 
-    do_in_bta_thread(
-        FROM_HERE,
-        Bind(&BleAdvertisingManager::SetPeriodicAdvertisingEnable,
-             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
-             enable, jni_thread_wrapper(FROM_HERE, cb)));
+    if (!BleAdvertisingManager::IsInitialized()) return;
+    do_in_bta_thread(FROM_HERE,
+                     Bind(&BleAdvertisingManager::SetPeriodicAdvertisingEnable,
+                          BleAdvertisingManager::Get(), advertiser_id, enable,
+                          jni_thread_wrapper(FROM_HERE, cb)));
   }
 };
 
diff --git a/btif/src/btif_ble_scanner.cc b/btif/src/btif_ble_scanner.cc
index 02538c6..2587c8d 100644
--- a/btif/src/btif_ble_scanner.cc
+++ b/btif/src/btif_ble_scanner.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -90,33 +90,6 @@
   remote_bdaddr_cache_ordered = {};
 }
 
-void btif_gatts_upstreams_evt(uint16_t event, char* p_param) {
-  LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
-
-  tBTA_GATTC* p_data = (tBTA_GATTC*)p_param;
-  switch (event) {
-    case BTA_GATTC_DEREG_EVT:
-      break;
-
-    case BTA_GATTC_SEARCH_CMPL_EVT: {
-      HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb,
-                p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
-      break;
-    }
-
-    default:
-      LOG_DEBUG(LOG_TAG, "%s: Unhandled event (%d)", __func__, event);
-      break;
-  }
-}
-
-void bta_gatts_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
-  bt_status_t status =
-      btif_transfer_context(btif_gatts_upstreams_evt, (uint16_t)event,
-                            (char*)p_data, sizeof(tBTA_GATTC), NULL);
-  ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
-}
-
 void bta_batch_scan_threshold_cb(tBTM_BLE_REF_VALUE ref_value) {
   SCAN_CBACK_IN_JNI(batchscan_threshold_cb, ref_value);
 }
@@ -227,6 +200,8 @@
   SCAN_CBACK_IN_JNI(track_adv_event_cb, Owned(btif_scan_track_cb));
 }
 
+void bta_cback(tBTA_GATTC_EVT, tBTA_GATTC*) {}
+
 class BleScannerInterfaceImpl : public BleScannerInterface {
   ~BleScannerInterfaceImpl(){};
 
@@ -235,7 +210,7 @@
                      Bind(
                          [](RegisterCallback cb) {
                            BTA_GATTC_AppRegister(
-                               bta_gatts_cback,
+                               bta_cback,
                                jni_thread_wrapper(FROM_HERE, std::move(cb)));
                          },
                          std::move(cb)));
@@ -255,9 +230,8 @@
           }
 
           btif_gattc_init_dev_cb();
-          do_in_bta_thread(FROM_HERE,
-                           Bind(&BTA_DmBleObserve, true, 0,
-                                (tBTA_DM_SEARCH_CBACK*)bta_scan_results_cb));
+          do_in_bta_thread(
+              FROM_HERE, Bind(&BTA_DmBleObserve, true, 0, bta_scan_results_cb));
         },
         start));
   }
@@ -280,93 +254,18 @@
                                 jni_thread_wrapper(FROM_HERE, std::move(cb))));
   }
 
-  void ScanFilterAddRemove(int action, int filt_type, int filt_index,
-                           int company_id, int company_id_mask,
-                           const bt_uuid_t* p_uuid,
-                           const bt_uuid_t* p_uuid_mask,
-                           const RawAddress* bd_addr, char addr_type,
-                           vector<uint8_t> data, vector<uint8_t> mask,
-                           FilterConfigCallback cb) override {
-    BTIF_TRACE_DEBUG("%s, %d, %d", __func__, action, filt_type);
+  void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
+                     FilterConfigCallback cb) override {
+    BTIF_TRACE_DEBUG("%s: %d", __func__, filter_index);
 
-    /* If data is passed, both mask and data have to be the same length */
-    if (data.size() != mask.size() && data.size() != 0 && mask.size() != 0)
-      return;
-
-    switch (filt_type) {
-      case BTM_BLE_PF_ADDR_FILTER: {
-        tBLE_BD_ADDR target_addr;
-        target_addr.bda = *bd_addr;
-        target_addr.type = addr_type;
-
-        do_in_bta_thread(
-            FROM_HERE,
-            base::Bind(&BTM_LE_PF_addr_filter, action, filt_index,
-                       std::move(target_addr),
-                       jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
-        return;
-      }
-
-      case BTM_BLE_PF_SRVC_DATA:
-        do_in_bta_thread(FROM_HERE,
-                         base::Bind(&BTM_LE_PF_srvc_data, action, filt_index));
-        return;
-
-      case BTM_BLE_PF_SRVC_UUID:
-      case BTM_BLE_PF_SRVC_SOL_UUID: {
-        tBT_UUID bt_uuid;
-        btif_to_bta_uuid(&bt_uuid, p_uuid);
-
-        if (p_uuid_mask == NULL) {
-          do_in_bta_thread(
-              FROM_HERE,
-              base::Bind(&BTM_LE_PF_uuid_filter, action, filt_index, filt_type,
-                         bt_uuid, BTM_BLE_PF_LOGIC_AND, nullptr,
-                         jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
-          return;
-        }
-
-        tBTM_BLE_PF_COND_MASK* mask = new tBTM_BLE_PF_COND_MASK;
-        btif_to_bta_uuid_mask(mask, p_uuid_mask, p_uuid);
-        do_in_bta_thread(
-            FROM_HERE,
-            base::Bind(&BTM_LE_PF_uuid_filter, action, filt_index, filt_type,
-                       bt_uuid, BTM_BLE_PF_LOGIC_AND, base::Owned(mask),
-                       jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
-        return;
-      }
-
-      case BTM_BLE_PF_LOCAL_NAME: {
-        do_in_bta_thread(
-            FROM_HERE,
-            base::Bind(&BTM_LE_PF_local_name, action, filt_index,
-                       std::move(data),
-                       jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
-        return;
-      }
-
-      case BTM_BLE_PF_MANU_DATA: {
-        do_in_bta_thread(
-            FROM_HERE,
-            base::Bind(&BTM_LE_PF_manu_data, action, filt_index, company_id,
-                       company_id_mask, std::move(data), std::move(mask),
-                       jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
-        return;
-      }
-
-      case BTM_BLE_PF_SRVC_DATA_PATTERN: {
-        do_in_bta_thread(
-            FROM_HERE,
-            base::Bind(&BTM_LE_PF_srvc_data_pattern, action, filt_index,
-                       std::move(data), std::move(mask),
-                       jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
-        return;
-      }
-
-      default:
-        LOG_ERROR(LOG_TAG, "%s: Unknown filter type (%d)!", __func__, action);
-        return;
-    }
+    do_in_bta_thread(
+        FROM_HERE,
+        base::Bind(
+            &BTM_LE_PF_set, filter_index, std::move(filters),
+            jni_thread_wrapper(
+                FROM_HERE,
+                Bind(std::move(cb),
+                     0 /*TODO: this used to be filter type, unused ?*/))));
   }
 
   void ScanFilterClear(int filter_index, FilterConfigCallback cb) override {
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index 1af751a..3155dc6 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@
 static void delete_config_files(void);
 static void btif_config_remove_unpaired(config_t* config);
 static void btif_config_remove_restricted(config_t* config);
-static config_t* btif_config_open(const char* filename);
+static std::unique_ptr<config_t> btif_config_open(const char* filename);
 
 static enum ConfigSource {
   NOT_LOADED,
@@ -115,7 +115,7 @@
 }
 
 static std::mutex config_lock;  // protects operations on |config|.
-static config_t* config;
+static std::unique_ptr<config_t> config;
 static alarm_t* config_timer;
 
 // Module lifecycle functions
@@ -154,29 +154,24 @@
   }
 
   if (!file_source.empty())
-    config_set_string(config, INFO_SECTION, FILE_SOURCE, file_source.c_str());
+    config_set_string(config.get(), INFO_SECTION, FILE_SOURCE, file_source);
 
-  if (!config) {
-    LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
-    goto error;
-  }
-
-  btif_config_remove_unpaired(config);
+  btif_config_remove_unpaired(config.get());
 
   // Cleanup temporary pairings if we have left guest mode
-  if (!is_restricted_mode()) btif_config_remove_restricted(config);
+  if (!is_restricted_mode()) btif_config_remove_restricted(config.get());
 
   // Read or set config file creation timestamp
-  const char* time_str;
-  time_str = config_get_string(config, INFO_SECTION, FILE_TIMESTAMP, NULL);
+  const std::string* time_str;
+  time_str = config_get_string(*config, INFO_SECTION, FILE_TIMESTAMP, NULL);
   if (time_str != NULL) {
-    strlcpy(btif_config_time_created, time_str, TIME_STRING_LENGTH);
+    strlcpy(btif_config_time_created, time_str->c_str(), TIME_STRING_LENGTH);
   } else {
     time_t current_time = time(NULL);
     struct tm* time_created = localtime(&current_time);
     strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT,
              time_created);
-    config_set_string(config, INFO_SECTION, FILE_TIMESTAMP,
+    config_set_string(config.get(), INFO_SECTION, FILE_TIMESTAMP,
                       btif_config_time_created);
   }
 
@@ -195,21 +190,19 @@
 
 error:
   alarm_free(config_timer);
-  config_free(config);
+  config.reset();
   config_timer = NULL;
-  config = NULL;
   btif_config_source = NOT_LOADED;
   return future_new_immediate(FUTURE_FAIL);
 }
 
-static config_t* btif_config_open(const char* filename) {
-  config_t* config = config_new(filename);
-  if (!config) return NULL;
+static std::unique_ptr<config_t> btif_config_open(const char* filename) {
+  std::unique_ptr<config_t> config = config_new(filename);
+  if (!config) return nullptr;
 
-  if (!config_has_section(config, "Adapter")) {
+  if (!config_has_section(*config, "Adapter")) {
     LOG_ERROR(LOG_TAG, "Config is missing adapter section");
-    config_free(config);
-    return NULL;
+    return nullptr;
   }
 
   return config;
@@ -227,8 +220,7 @@
   config_timer = NULL;
 
   std::unique_lock<std::mutex> lock(config_lock);
-  config_free(config);
-  config = NULL;
+  config.reset();
   return future_new_immediate(FUTURE_SUCCESS);
 }
 
@@ -243,118 +235,128 @@
   CHECK(section != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  return config_has_section(config, section);
+  return config_has_section(*config, section);
 }
 
-bool btif_config_exist(const char* section, const char* key) {
+bool btif_config_exist(const std::string& section, const std::string& key) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  return config_has_key(config, section, key);
+  return config_has_key(*config, section, key);
 }
 
-bool btif_config_get_int(const char* section, const char* key, int* value) {
+bool btif_config_get_int(const std::string& section, const std::string& key,
+                         int* value) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
   CHECK(value != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  bool ret = config_has_key(config, section, key);
-  if (ret) *value = config_get_int(config, section, key, *value);
+  bool ret = config_has_key(*config, section, key);
+  if (ret) *value = config_get_int(*config, section, key, *value);
 
   return ret;
 }
 
-bool btif_config_set_int(const char* section, const char* key, int value) {
+bool btif_config_set_int(const std::string& section, const std::string& key,
+                         int value) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  config_set_int(config, section, key, value);
+  config_set_int(config.get(), section, key, value);
 
   return true;
 }
 
-bool btif_config_get_str(const char* section, const char* key, char* value,
-                         int* size_bytes) {
+bool btif_config_get_uint64(const std::string& section, const std::string& key,
+                            uint64_t* value) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  bool ret = config_has_key(*config, section, key);
+  if (ret) *value = config_get_uint64(*config, section, key, *value);
+
+  return ret;
+}
+
+bool btif_config_set_uint64(const std::string& section, const std::string& key,
+                            uint64_t value) {
+  CHECK(config != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_set_uint64(config.get(), section, key, value);
+
+  return true;
+}
+
+bool btif_config_get_str(const std::string& section, const std::string& key,
+                         char* value, int* size_bytes) {
+  CHECK(config != NULL);
   CHECK(value != NULL);
   CHECK(size_bytes != NULL);
 
   {
     std::unique_lock<std::mutex> lock(config_lock);
-    const char* stored_value = config_get_string(config, section, key, NULL);
+    const std::string* stored_value =
+        config_get_string(*config, section, key, NULL);
     if (!stored_value) return false;
-    strlcpy(value, stored_value, *size_bytes);
+    strlcpy(value, stored_value->c_str(), *size_bytes);
   }
 
   *size_bytes = strlen(value) + 1;
   return true;
 }
 
-bool btif_config_set_str(const char* section, const char* key,
-                         const char* value) {
+bool btif_config_set_str(const std::string& section, const std::string& key,
+                         const std::string& value) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
-  CHECK(value != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  config_set_string(config, section, key, value);
+  config_set_string(config.get(), section, key, value);
   return true;
 }
 
-bool btif_config_get_bin(const char* section, const char* key, uint8_t* value,
-                         size_t* length) {
+bool btif_config_get_bin(const std::string& section, const std::string& key,
+                         uint8_t* value, size_t* length) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
   CHECK(value != NULL);
   CHECK(length != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  const char* value_str = config_get_string(config, section, key, NULL);
+  const std::string* value_str = config_get_string(*config, section, key, NULL);
 
   if (!value_str) return false;
 
-  size_t value_len = strlen(value_str);
+  size_t value_len = value_str->length();
   if ((value_len % 2) != 0 || *length < (value_len / 2)) return false;
 
   for (size_t i = 0; i < value_len; ++i)
-    if (!isxdigit(value_str[i])) return false;
+    if (!isxdigit(value_str->c_str()[i])) return false;
 
-  for (*length = 0; *value_str; value_str += 2, *length += 1)
-    sscanf(value_str, "%02hhx", &value[*length]);
+  const char* ptr = value_str->c_str();
+  for (*length = 0; *ptr; ptr += 2, *length += 1)
+    sscanf(ptr, "%02hhx", &value[*length]);
 
   return true;
 }
 
-size_t btif_config_get_bin_length(const char* section, const char* key) {
+size_t btif_config_get_bin_length(const std::string& section,
+                                  const std::string& key) {
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  const char* value_str = config_get_string(config, section, key, NULL);
+  const std::string* value_str = config_get_string(*config, section, key, NULL);
   if (!value_str) return 0;
 
-  size_t value_len = strlen(value_str);
+  size_t value_len = value_str->length();
   return ((value_len % 2) != 0) ? 0 : (value_len / 2);
 }
 
-bool btif_config_set_bin(const char* section, const char* key,
+bool btif_config_set_bin(const std::string& section, const std::string& key,
                          const uint8_t* value, size_t length) {
   const char* lookup = "0123456789abcdef";
 
   CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
 
   if (length > 0) CHECK(value != NULL);
 
@@ -367,45 +369,20 @@
 
   {
     std::unique_lock<std::mutex> lock(config_lock);
-    config_set_string(config, section, key, str);
+    config_set_string(config.get(), section, key, str);
   }
 
   osi_free(str);
   return true;
 }
 
-const btif_config_section_iter_t* btif_config_section_begin(void) {
-  CHECK(config != NULL);
-  return (const btif_config_section_iter_t*)config_section_begin(config);
-}
+std::list<section_t>& btif_config_sections() { return config->sections; }
 
-const btif_config_section_iter_t* btif_config_section_end(void) {
+bool btif_config_remove(const std::string& section, const std::string& key) {
   CHECK(config != NULL);
-  return (const btif_config_section_iter_t*)config_section_end(config);
-}
-
-const btif_config_section_iter_t* btif_config_section_next(
-    const btif_config_section_iter_t* section) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  return (const btif_config_section_iter_t*)config_section_next(
-      (const config_section_node_t*)section);
-}
-
-const char* btif_config_section_name(
-    const btif_config_section_iter_t* section) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  return config_section_name((const config_section_node_t*)section);
-}
-
-bool btif_config_remove(const char* section, const char* key) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  return config_remove_key(config, section, key);
+  return config_remove_key(config.get(), section, key);
 }
 
 void btif_config_save(void) {
@@ -430,12 +407,10 @@
   alarm_cancel(config_timer);
 
   std::unique_lock<std::mutex> lock(config_lock);
-  config_free(config);
 
   config = config_new_empty();
-  if (config == NULL) return false;
 
-  bool ret = config_save(config, CONFIG_FILE_PATH);
+  bool ret = config_save(*config, CONFIG_FILE_PATH);
   btif_config_source = RESET;
   return ret;
 }
@@ -454,10 +429,9 @@
 
   std::unique_lock<std::mutex> lock(config_lock);
   rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
-  config_t* config_paired = config_new_clone(config);
-  btif_config_remove_unpaired(config_paired);
-  config_save(config_paired, CONFIG_FILE_PATH);
-  config_free(config_paired);
+  std::unique_ptr<config_t> config_paired = config_new_clone(*config);
+  btif_config_remove_unpaired(config_paired.get());
+  config_save(*config_paired, CONFIG_FILE_PATH);
 }
 
 static void btif_config_remove_unpaired(config_t* conf) {
@@ -467,23 +441,23 @@
   // The paired config used to carry information about
   // discovered devices during regular inquiry scans.
   // We remove these now and cache them in memory instead.
-  const config_section_node_t* snode = config_section_begin(conf);
-  while (snode != config_section_end(conf)) {
-    const char* section = config_section_name(snode);
+  for (auto it = conf->sections.begin(); it != conf->sections.end();) {
+    std::string& section = it->name;
     if (RawAddress::IsValidAddress(section)) {
-      if (!config_has_key(conf, section, "LinkKey") &&
-          !config_has_key(conf, section, "LE_KEY_PENC") &&
-          !config_has_key(conf, section, "LE_KEY_PID") &&
-          !config_has_key(conf, section, "LE_KEY_PCSRK") &&
-          !config_has_key(conf, section, "LE_KEY_LENC") &&
-          !config_has_key(conf, section, "LE_KEY_LCSRK")) {
-        snode = config_section_next(snode);
-        config_remove_section(conf, section);
+      // TODO: config_has_key loop thorugh all data, maybe just make it so we
+      // loop just once ?
+      if (!config_has_key(*conf, section, "LinkKey") &&
+          !config_has_key(*conf, section, "LE_KEY_PENC") &&
+          !config_has_key(*conf, section, "LE_KEY_PID") &&
+          !config_has_key(*conf, section, "LE_KEY_PCSRK") &&
+          !config_has_key(*conf, section, "LE_KEY_LENC") &&
+          !config_has_key(*conf, section, "LE_KEY_LCSRK")) {
+        it = conf->sections.erase(it);
         continue;
       }
       paired_devices++;
     }
-    snode = config_section_next(snode);
+    it++;
   }
 
   // should only happen once, at initial load time
@@ -516,24 +490,27 @@
       break;
   }
 
+  std::string original = "Original";
   dprintf(fd, "  Devices loaded: %d\n", btif_config_devices_loaded);
   dprintf(fd, "  File created/tagged: %s\n", btif_config_time_created);
   dprintf(fd, "  File source: %s\n",
-          config_get_string(config, INFO_SECTION, FILE_SOURCE, "Original"));
+          config_get_string(*config, INFO_SECTION, FILE_SOURCE, &original)
+              ->c_str());
 }
 
 static void btif_config_remove_restricted(config_t* config) {
   CHECK(config != NULL);
 
-  const config_section_node_t* snode = config_section_begin(config);
-  while (snode != config_section_end(config)) {
-    const char* section = config_section_name(snode);
+  for (auto it = config->sections.begin(); it != config->sections.end();) {
+    const std::string& section = it->name;
     if (RawAddress::IsValidAddress(section) &&
-        config_has_key(config, section, "Restricted")) {
-      BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__, section);
-      config_remove_section(config, section);
+        config_has_key(*config, section, "Restricted")) {
+      BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__,
+                       section.c_str());
+      it = config->sections.erase(it);
+      continue;
     }
-    snode = config_section_next(snode);
+    it++;
   }
 }
 
diff --git a/btif/src/btif_config_transcode.cc b/btif/src/btif_config_transcode.cc
index 102a3af..75ebd77 100644
--- a/btif/src/btif_config_transcode.cc
+++ b/btif/src/btif_config_transcode.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
 
 using namespace tinyxml2;
 
-config_t* btif_config_transcode(const char* xml_filename) {
+std::unique_ptr<config_t> btif_config_transcode(const char* xml_filename) {
   XMLDocument document;
   int error = document.LoadFile(xml_filename);
   if (error != XML_SUCCESS) {
@@ -42,11 +42,7 @@
     return NULL;
   }
 
-  config_t* config = config_new_empty();
-  if (!config) {
-    LOG_ERROR(LOG_TAG, "%s unable to allocate config object.", __func__);
-    return NULL;
-  }
+  std::unique_ptr<config_t> config = config_new_empty();
 
   for (XMLElement* i = rootElement->FirstChildElement(); i != NULL;
        i = i->NextSiblingElement())
@@ -58,7 +54,7 @@
         const char* key = k->Attribute("Tag");
         const char* value = k->GetText();
         if (section && key && value)
-          config_set_string(config, section, key, value);
+          config_set_string(config.get(), section, key, value);
       }
     }
 
diff --git a/btif/src/btif_core.cc b/btif/src/btif_core.cc
index febf945..582ae47 100644
--- a/btif/src/btif_core.cc
+++ b/btif/src/btif_core.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
 #include <base/at_exit.h>
 #include <base/bind.h>
 #include <base/run_loop.h>
+#include <base/threading/platform_thread.h>
 #include <base/threading/thread.h>
 #include <ctype.h>
 #include <dirent.h>
@@ -45,6 +46,7 @@
 #include "bt_common.h"
 #include "bt_utils.h"
 #include "bta_api.h"
+#include "bta_closure_api.h"
 #include "bte.h"
 #include "btif_api.h"
 #include "btif_av.h"
@@ -65,6 +67,9 @@
 #include "osi/include/thread.h"
 #include "stack_manager.h"
 
+using base::PlatformThread;
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *  Constants & Macros
  ******************************************************************************/
@@ -128,6 +133,7 @@
 static uid_set_t* uid_set = NULL;
 base::MessageLoop* message_loop_ = NULL;
 base::RunLoop* jni_run_loop = NULL;
+static base::PlatformThreadId btif_thread_id_ = -1;
 
 /*******************************************************************************
  *  Static functions
@@ -219,14 +225,20 @@
  **/
 bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
                              const base::Closure& task) {
-  if (!message_loop_ || !message_loop_->task_runner().get()) {
+  if (!message_loop_) {
     BTIF_TRACE_WARNING("%s: Dropped message, message_loop not initialized yet!",
                        __func__);
     return BT_STATUS_FAIL;
   }
 
-  if (message_loop_->task_runner()->PostTask(from_here, task))
-    return BT_STATUS_SUCCESS;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      message_loop_->task_runner();
+  if (!task_runner.get()) {
+    BTIF_TRACE_WARNING("%s: task runner is dead", __func__);
+    return BT_STATUS_FAIL;
+  }
+
+  if (task_runner->PostTask(from_here, task)) return BT_STATUS_SUCCESS;
 
   BTIF_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
   return BT_STATUS_FAIL;
@@ -236,6 +248,12 @@
   return do_in_jni_thread(FROM_HERE, task);
 }
 
+bool is_on_jni_thread() {
+  return btif_thread_id_ == PlatformThread::CurrentId();
+}
+
+base::MessageLoop* get_jni_message_loop() { return message_loop_; }
+
 /*******************************************************************************
  *
  * Function         btif_is_dut_mode
@@ -315,6 +333,7 @@
 
 void run_message_loop(UNUSED_ATTR void* context) {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
+  btif_thread_id_ = PlatformThread::CurrentId();
 
   // TODO(jpawlowski): exit_manager should be defined in main(), but there is no
   // main method.
@@ -337,6 +356,7 @@
   delete jni_run_loop;
   jni_run_loop = NULL;
 
+  btif_thread_id_ = -1;
   LOG_INFO(LOG_TAG, "%s finished", __func__);
 }
 /*******************************************************************************
@@ -458,7 +478,7 @@
 bt_status_t btif_disable_bluetooth(void) {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
 
-  btm_ble_multi_adv_cleanup();
+  do_in_bta_thread(FROM_HERE, base::Bind(&btm_ble_multi_adv_cleanup));
   // TODO(jpawlowski): this should do whole BTA_VendorCleanup(), but it would
   // kill the stack now.
 
@@ -509,7 +529,7 @@
 bt_status_t btif_cleanup_bluetooth(void) {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
 
-  BTA_VendorCleanup();
+  do_in_bta_thread(FROM_HERE, base::Bind(&BTA_VendorCleanup));
 
   btif_dm_cleanup();
   btif_jni_disassociate();
@@ -608,7 +628,7 @@
   bt_scan_mode_t mode;
   uint32_t disc_timeout;
   RawAddress bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
-  bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+  Uuid local_uuids[BT_MAX_NUM_UUIDS];
   bt_status_t status;
 
   /* RawAddress */
@@ -666,7 +686,7 @@
 
   bt_bdname_t name, alias;
   uint32_t cod, devtype;
-  bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+  Uuid remote_uuids[BT_MAX_NUM_UUIDS];
 
   memset(remote_properties, 0, sizeof(remote_properties));
   BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_BDNAME,
@@ -900,7 +920,7 @@
 
   /* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */
   if (!btif_is_enabled() && (type != BT_PROPERTY_BDADDR) &&
-      (type != BT_PROPERTY_BDNAME))
+      (type != BT_PROPERTY_BDNAME) && (type != BT_PROPERTY_CLASS_OF_DEVICE))
     return BT_STATUS_NOT_READY;
 
   req.read_req.bd_addr = RawAddress::kEmpty;
@@ -987,6 +1007,15 @@
          if required */
       storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
     } break;
+    case BT_PROPERTY_CLASS_OF_DEVICE: {
+      DEV_CLASS dev_class;
+      memcpy(dev_class, property->val, DEV_CLASS_LEN);
+
+      BTIF_TRACE_EVENT("set property dev_class : 0x%02x%02x%02x", dev_class[0],
+                       dev_class[1], dev_class[2]);
+
+      BTM_SetDeviceClass(dev_class);
+    } break;
     case BT_PROPERTY_BDADDR:
     case BT_PROPERTY_UUIDS:
     case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
@@ -1095,8 +1124,8 @@
  * Returns          bt_status_t
  *
  ******************************************************************************/
-bt_status_t btif_get_remote_service_record(RawAddress* remote_addr,
-                                           bt_uuid_t* uuid) {
+bt_status_t btif_get_remote_service_record(const RawAddress& remote_addr,
+                                           const Uuid& uuid) {
   if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
 
   return btif_dm_get_remote_service_record(remote_addr, uuid);
diff --git a/btif/src/btif_debug.cc b/btif/src/btif_debug.cc
index a26c301..04b6474 100644
--- a/btif/src/btif_debug.cc
+++ b/btif/src/btif_debug.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
 
 #include "btif/include/btif_debug.h"
 #include "btif/include/btif_debug_btsnoop.h"
-#include "include/bt_target.h"
+#include "internal_include/bt_target.h"
 
 void btif_debug_init(void) {
 #if (BTSNOOP_MEM == TRUE)
diff --git a/btif/src/btif_debug_btsnoop.cc b/btif/src/btif_debug_btsnoop.cc
index e52a177..1dcb835 100644
--- a/btif/src/btif_debug_btsnoop.cc
+++ b/btif/src/btif_debug_btsnoop.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
 #include "btif/include/btif_debug.h"
 #include "btif/include/btif_debug_btsnoop.h"
 #include "hci/include/btsnoop_mem.h"
-#include "include/bt_target.h"
+#include "internal_include/bt_target.h"
 #include "osi/include/ringbuffer.h"
 #include "osi/include/time.h"
 
@@ -207,7 +207,7 @@
     rc = btsnoop_compress(ringbuffer, buffer);
   }
 
-  if (rc == false) {
+  if (!rc) {
     dprintf(fd, "%s Log compression failed", __func__);
     goto error;
   }
diff --git a/btif/src/btif_debug_conn.cc b/btif/src/btif_debug_conn.cc
index 9252a02..6b4d96f 100644
--- a/btif/src/btif_debug_conn.cc
+++ b/btif/src/btif_debug_conn.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index eceab10..d1bb61c 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -41,16 +41,20 @@
 
 #include <mutex>
 
+#include <bluetooth/uuid.h>
 #include <hardware/bluetooth.h>
+#include <hardware/bt_hearing_aid.h>
 
 #include "advertise_data_parser.h"
 #include "bt_common.h"
 #include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "btif_api.h"
+#include "btif_av.h"
 #include "btif_config.h"
 #include "btif_dm.h"
 #include "btif_hd.h"
+#include "btif_hf.h"
 #include "btif_hh.h"
 #include "btif_sdp.h"
 #include "btif_storage.h"
@@ -58,7 +62,7 @@
 #include "btu.h"
 #include "device/include/controller.h"
 #include "device/include/interop.h"
-#include "include/stack_config.h"
+#include "internal_include/stack_config.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
 #include "osi/include/metrics.h"
@@ -67,10 +71,13 @@
 #include "stack/btm/btm_int.h"
 #include "stack_config.h"
 
+using bluetooth::Uuid;
 /******************************************************************************
  *  Constants & Macros
  *****************************************************************************/
 
+const Uuid UUID_HEARING_AID = Uuid::FromString("FDF0");
+
 #define COD_MASK 0x07FF
 
 #define COD_UNCLASSIFIED ((0x1F) << 8)
@@ -97,13 +104,6 @@
 #error "default btif local name size exceeds stack supported length"
 #endif
 
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-#define BTIF_DM_INTERLEAVE_DURATION_BR_ONE 2
-#define BTIF_DM_INTERLEAVE_DURATION_LE_ONE 2
-#define BTIF_DM_INTERLEAVE_DURATION_BR_TWO 3
-#define BTIF_DM_INTERLEAVE_DURATION_LE_TWO 4
-#endif
-
 #define ENCRYPTED_BREDR 2
 #define ENCRYPTED_LE 4
 
@@ -182,8 +182,6 @@
 
 #define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
 
-#define UUID_HUMAN_INTERFACE_DEVICE "00001124-0000-1000-8000-00805f9b34fb"
-
 #define MAX_BTIF_BOND_EVENT_ENTRIES 15
 
 static skip_sdp_entry_t sdp_blacklist[] = {{76}};  // Apple Mouse and Keyboard
@@ -240,17 +238,15 @@
 /******************************************************************************
  *  Externs
  *****************************************************************************/
-extern bt_status_t btif_hf_execute_service(bool b_enable);
 extern bt_status_t btif_av_execute_service(bool b_enable);
 extern bt_status_t btif_av_sink_execute_service(bool b_enable);
 extern bt_status_t btif_hh_execute_service(bool b_enable);
 extern bt_status_t btif_hf_client_execute_service(bool b_enable);
 extern bt_status_t btif_sdp_execute_service(bool b_enable);
 extern int btif_hh_connect(const RawAddress* bd_addr);
-extern void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
-                                               uint16_t uuid_16);
-extern void btif_av_move_idle(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
@@ -300,10 +296,10 @@
   switch (service_id) {
     case BTA_HFP_SERVICE_ID:
     case BTA_HSP_SERVICE_ID: {
-      btif_hf_execute_service(b_enable);
+      bluetooth::headset::ExecuteService(b_enable);
     } break;
     case BTA_A2DP_SOURCE_SERVICE_ID: {
-      btif_av_execute_service(b_enable);
+      btif_av_source_execute_service(b_enable);
     } break;
     case BTA_A2DP_SINK_SERVICE_ID: {
       btif_av_sink_execute_service(b_enable);
@@ -802,10 +798,10 @@
       if (p_src_data->disc_res.result == BTA_SUCCESS) {
         if (p_src_data->disc_res.num_uuids > 0) {
           p_dest_data->disc_res.p_uuid_list =
-              (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+              (Uuid*)(p_dest + sizeof(tBTA_DM_SEARCH));
           memcpy(p_dest_data->disc_res.p_uuid_list,
                  p_src_data->disc_res.p_uuid_list,
-                 p_src_data->disc_res.num_uuids * MAX_UUID_SIZE);
+                 p_src_data->disc_res.num_uuids * sizeof(Uuid));
           osi_free_and_reset((void**)&p_src_data->disc_res.p_uuid_list);
         }
         osi_free_and_reset((void**)&p_src_data->disc_res.p_raw_data);
@@ -845,6 +841,14 @@
   const RawAddress& bd_addr = p_pin_req->bd_addr;
   memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
 
+  if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+      bd_addr != pairing_cb.bd_addr) {
+    BTIF_TRACE_WARNING("%s(): already in bonding state, reject request",
+                       __FUNCTION__);
+    btif_dm_pin_reply(&bd_addr, 0, 0, NULL);
+    return;
+  }
+
   bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
 
   cod = devclass2uint(p_pin_req->dev_class);
@@ -856,7 +860,7 @@
 
   /* check for auto pair possiblity only if bond was initiated by local device
    */
-  if (pairing_cb.is_local_initiated && (p_pin_req->min_16_digit == false)) {
+  if (pairing_cb.is_local_initiated && !p_pin_req->min_16_digit) {
     if (check_cod(&bd_addr, COD_AV_HEADSETS) ||
         check_cod(&bd_addr, COD_AV_HEADPHONES) ||
         check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) ||
@@ -928,10 +932,22 @@
   RawAddress bd_addr = p_ssp_cfm_req->bd_addr;
   memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
 
+  if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+      bd_addr != pairing_cb.bd_addr) {
+    BTIF_TRACE_WARNING("%s(): already in bonding state, reject request",
+                       __FUNCTION__);
+    btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 0, 0);
+    return;
+  }
+
   /* Set the pairing_cb based on the local & remote authentication requirements
    */
   bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
 
+  BTIF_TRACE_EVENT("%s: just_works:%d, loc_auth_req=%d, rmt_auth_req=%d",
+                   __func__, p_ssp_cfm_req->just_works,
+                   p_ssp_cfm_req->loc_auth_req, p_ssp_cfm_req->rmt_auth_req);
+
   /* if just_works and bonding bit is not set treat this as temporary */
   if (p_ssp_cfm_req->just_works &&
       !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) &&
@@ -1026,10 +1042,12 @@
   bt_bond_state_t state = BT_BOND_STATE_NONE;
   bool skip_sdp = false;
 
-  BTIF_TRACE_DEBUG("%s: bond state=%d", __func__, pairing_cb.state);
+  BTIF_TRACE_DEBUG("%s: bond state=%d, success=%d, key_present=%d", __func__,
+                   pairing_cb.state, p_auth_cmpl->success,
+                   p_auth_cmpl->key_present);
 
   RawAddress bd_addr = p_auth_cmpl->bd_addr;
-  if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) {
+  if ((p_auth_cmpl->success) && (p_auth_cmpl->key_present)) {
     if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) ||
         (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||
         (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) ||
@@ -1056,23 +1074,22 @@
     }
   }
 
-  // We could have received a new link key without going through the pairing
-  // flow.  If so, we don't want to perform SDP or any other operations on the
-  // authenticated device. Also, make sure that the link key is not derived from
-  // secure LTK, because we will need to perform SDP in case of link key
-  // derivation to allow bond state change notification for the BR/EDR transport
-  // so that the subsequent BR/EDR connections to the remote can use the derived
-  // link key.
-  if (p_auth_cmpl->bd_addr != pairing_cb.bd_addr &&
-      (!pairing_cb.ble.is_penc_key_rcvd)) {
-    LOG(INFO) << __func__
-              << " skipping SDP since we did not initiate pairing to "
-              << p_auth_cmpl->bd_addr;
-    return;
-  }
-
-  // Skip SDP for certain  HID Devices
   if (p_auth_cmpl->success) {
+    // We could have received a new link key without going through the pairing
+    // flow.  If so, we don't want to perform SDP or any other operations on the
+    // authenticated device. Also, make sure that the link key is not derived
+    // from secure LTK, because we will need to perform SDP in case of link key
+    // derivation to allow bond state change notification for the BR/EDR
+    // transport so that the subsequent BR/EDR connections to the remote can use
+    // the derived link key.
+    if (p_auth_cmpl->bd_addr != pairing_cb.bd_addr &&
+        (!pairing_cb.ble.is_penc_key_rcvd)) {
+      LOG(INFO) << __func__
+                << " skipping SDP since we did not initiate pairing to "
+                << p_auth_cmpl->bd_addr;
+      return;
+    }
+
     btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);
     btif_update_remote_properties(p_auth_cmpl->bd_addr, p_auth_cmpl->bd_name,
                                   NULL, p_auth_cmpl->dev_type);
@@ -1091,14 +1108,11 @@
       LOG_WARN(LOG_TAG, "%s: Incoming HID Connection", __func__);
       bt_property_t prop;
       RawAddress bd_addr;
-      bt_uuid_t uuid;
-      char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
-
-      string_to_uuid(uuid_str, &uuid);
+      Uuid uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
 
       prop.type = BT_PROPERTY_UUIDS;
-      prop.val = uuid.uu;
-      prop.len = MAX_UUID_SIZE;
+      prop.val = &uuid;
+      prop.len = Uuid::kNumBytes128;
 
       /* Send the event to the BTIF */
       HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
@@ -1341,7 +1355,7 @@
        * but instead wait for the cancel_cmpl_evt via the Busy Level
        *
        */
-      if (btif_dm_inquiry_in_progress == false) {
+      if (!btif_dm_inquiry_in_progress) {
         btgatt_filt_param_setup_t adv_filt_param;
         memset(&adv_filt_param, 0, sizeof(btgatt_filt_param_setup_t));
         do_in_bta_thread(
@@ -1392,13 +1406,10 @@
       if ((p_data->disc_res.result == BTA_SUCCESS) &&
           (p_data->disc_res.num_uuids > 0)) {
         prop.val = p_data->disc_res.p_uuid_list;
-        prop.len = p_data->disc_res.num_uuids * MAX_UUID_SIZE;
+        prop.len = p_data->disc_res.num_uuids * Uuid::kNumBytes128;
         for (i = 0; i < p_data->disc_res.num_uuids; i++) {
-          char temp[256];
-          uuid_to_string_legacy(
-              (bt_uuid_t*)(p_data->disc_res.p_uuid_list + (i * MAX_UUID_SIZE)),
-              temp, sizeof(temp));
-          LOG_INFO(LOG_TAG, "%s index:%d uuid:%s", __func__, i, temp);
+          std::string temp = ((p_data->disc_res.p_uuid_list + i))->ToString();
+          LOG_INFO(LOG_TAG, "%s index:%d uuid:%s", __func__, i, temp.c_str());
         }
       }
 
@@ -1442,36 +1453,21 @@
       break;
 
     case BTA_DM_DISC_BLE_RES_EVT: {
-      BTIF_TRACE_DEBUG("%s:, services 0x%x)", __func__,
-                       p_data->disc_ble_res.service.uu.uuid16);
-      bt_uuid_t uuid;
-      int i = 0;
-      int j = 15;
+      BTIF_TRACE_DEBUG("%s: service %s", __func__,
+                       p_data->disc_ble_res.service.ToString().c_str());
       int num_properties = 0;
-      if (p_data->disc_ble_res.service.uu.uuid16 == UUID_SERVCLASS_LE_HID) {
-        BTIF_TRACE_DEBUG("%s: Found HOGP UUID", __func__);
+      if (p_data->disc_ble_res.service.As16Bit() == UUID_SERVCLASS_LE_HID ||
+          p_data->disc_ble_res.service == UUID_HEARING_AID) {
+        BTIF_TRACE_DEBUG("%s: Found HOGP or HEARING AID UUID", __func__);
         bt_property_t prop[2];
-        char temp[256];
         bt_status_t ret;
 
-        bta_gatt_convert_uuid16_to_uuid128(
-            uuid.uu, p_data->disc_ble_res.service.uu.uuid16);
-
-        while (i < j) {
-          unsigned char c = uuid.uu[j];
-          uuid.uu[j] = uuid.uu[i];
-          uuid.uu[i] = c;
-          i++;
-          j--;
-        }
-
-        uuid_to_string_legacy(&uuid, temp, sizeof(temp));
-        LOG_INFO(LOG_TAG, "%s uuid:%s", __func__, temp);
+        const auto& arr = p_data->disc_ble_res.service.To128BitBE();
 
         RawAddress& bd_addr = p_data->disc_ble_res.bd_addr;
         prop[0].type = BT_PROPERTY_UUIDS;
-        prop[0].val = uuid.uu;
-        prop[0].len = MAX_UUID_SIZE;
+        prop[0].val = (void*)arr.data();
+        prop[0].len = Uuid::kNumBytes128;
 
         /* Also write this to the NVRAM */
         ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
@@ -1649,12 +1645,13 @@
       btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
 
 /*special handling for HID devices */
-#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == true))
+#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
       btif_hh_remove_device(bd_addr);
 #endif
 #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;
@@ -1688,7 +1685,7 @@
     case BTA_DM_LINK_DOWN_EVT:
       bd_addr = p_data->link_down.bd_addr;
       btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
-      btif_av_move_idle(bd_addr);
+      btif_av_acl_disconnected(bd_addr);
       BTIF_TRACE_DEBUG(
           "BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
       HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
@@ -1896,7 +1893,7 @@
     case BTA_DM_ROLE_CHG_EVT:
 
     default:
-      BTIF_TRACE_WARNING("btif_dm_cback : unhandled event (%d)", event);
+      BTIF_TRACE_WARNING("%s: unhandled event (%d)", __func__, event);
       break;
   }
 
@@ -2039,7 +2036,7 @@
     case BTA_DM_DISC_RES_EVT: {
       if ((p_data->disc_res.result == BTA_SUCCESS) &&
           (p_data->disc_res.num_uuids > 0)) {
-        param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE);
+        param_len += (p_data->disc_res.num_uuids * Uuid::kNumBytes128);
       }
     } break;
   }
@@ -2158,12 +2155,6 @@
 
   /* Set inquiry params and call API */
   inq_params.mode = BTA_DM_GENERAL_INQUIRY | BTA_BLE_GENERAL_INQUIRY;
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  inq_params.intl_duration[0] = BTIF_DM_INTERLEAVE_DURATION_BR_ONE;
-  inq_params.intl_duration[1] = BTIF_DM_INTERLEAVE_DURATION_LE_ONE;
-  inq_params.intl_duration[2] = BTIF_DM_INTERLEAVE_DURATION_BR_TWO;
-  inq_params.intl_duration[3] = BTIF_DM_INTERLEAVE_DURATION_LE_TWO;
-#endif
   inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
 
   inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
@@ -2442,6 +2433,12 @@
       prop->len = sizeof(uint32_t);
     } break;
 
+    case BT_PROPERTY_CLASS_OF_DEVICE: {
+      DEV_CLASS dev_class = BTA_DM_COD;
+      memcpy(prop->val, dev_class, sizeof(DEV_CLASS));
+      prop->len = sizeof(DEV_CLASS);
+    } break;
+
     default:
       prop->len = 0;
       return BT_STATUS_FAIL;
@@ -2478,7 +2475,8 @@
  ******************************************************************************/
 bt_status_t btif_dm_get_remote_services_by_transport(RawAddress* remote_addr,
                                                      const int transport) {
-  BTIF_TRACE_EVENT("%s", __func__);
+  BTIF_TRACE_EVENT("%s: transport=%d, remote_addr=%s", __func__, transport,
+                   remote_addr->ToString().c_str());
 
   /* Set the mask extension */
   tBTA_SERVICE_MASK_EXT mask_ext;
@@ -2501,16 +2499,10 @@
  *
  * Returns          bt_status_t
  ******************************************************************************/
-bt_status_t btif_dm_get_remote_service_record(RawAddress* remote_addr,
-                                              bt_uuid_t* uuid) {
-  BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__, remote_addr->ToString().c_str());
-
-  tSDP_UUID sdp_uuid;
-  sdp_uuid.len = MAX_UUID_SIZE;
-  memcpy(sdp_uuid.uu.uuid128, uuid->uu, MAX_UUID_SIZE);
-
-  BTA_DmDiscoverUUID(*remote_addr, &sdp_uuid, bte_dm_remote_service_record_evt,
-                     true);
+bt_status_t btif_dm_get_remote_service_record(const RawAddress& remote_addr,
+                                              const Uuid& uuid) {
+  BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__, remote_addr.ToString().c_str());
+  BTA_DmDiscoverUUID(remote_addr, uuid, bte_dm_remote_service_record_evt, true);
 
   return BT_STATUS_SUCCESS;
 }
@@ -2525,7 +2517,7 @@
       btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable);
   if (status == BT_STATUS_SUCCESS) {
     bt_property_t property;
-    bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+    Uuid local_uuids[BT_MAX_NUM_UUIDS];
 
     /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
     BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
@@ -2693,17 +2685,17 @@
  *
  ******************************************************************************/
 bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
-  if (!stack_config_get_interface()->get_pts_smp_options()) {
+  const std::string* recv = stack_config_get_interface()->get_pts_smp_options();
+  if (!recv) {
     BTIF_TRACE_DEBUG("%s: SMP options not found in configuration", __func__);
     return false;
   }
 
   char conf[64];
-  const char* recv = stack_config_get_interface()->get_pts_smp_options();
   char* pch;
   char* endptr;
 
-  strncpy(conf, recv, 64);
+  strncpy(conf, recv->c_str(), 64);
   conf[63] = 0;  // null terminate
 
   pch = strtok(conf, ",");
@@ -2819,7 +2811,7 @@
   /* Clear OOB data */
   memset(&oob_cb, 0, sizeof(oob_cb));
 
-  if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) {
+  if ((p_auth_cmpl->success) && (p_auth_cmpl->key_present)) {
     /* store keys */
   }
   if (p_auth_cmpl->success) {
@@ -2840,7 +2832,7 @@
     } else {
       btif_dm_save_ble_bonding_keys();
       BTA_GATTC_Refresh(bd_addr);
-      btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
+      btif_dm_get_remote_services_by_transport(&bd_addr, GATT_TRANSPORT_LE);
     }
   } else {
     /*Map the HCI fail reason  to  bt status  */
@@ -2913,33 +2905,33 @@
   RawAddress bd_addr = pairing_cb.bd_addr;
 
   if (pairing_cb.ble.is_penc_key_rcvd) {
-    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.penc_key,
-                                     BTIF_DM_LE_KEY_PENC,
-                                     sizeof(tBTM_LE_PENC_KEYS));
+    btif_storage_add_ble_bonding_key(
+        &bd_addr, (uint8_t*)&pairing_cb.ble.penc_key, BTIF_DM_LE_KEY_PENC,
+        sizeof(tBTM_LE_PENC_KEYS));
   }
 
   if (pairing_cb.ble.is_pid_key_rcvd) {
-    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.pid_key,
-                                     BTIF_DM_LE_KEY_PID,
-                                     sizeof(tBTM_LE_PID_KEYS));
+    btif_storage_add_ble_bonding_key(
+        &bd_addr, (uint8_t*)&pairing_cb.ble.pid_key, BTIF_DM_LE_KEY_PID,
+        sizeof(tBTM_LE_PID_KEYS));
   }
 
   if (pairing_cb.ble.is_pcsrk_key_rcvd) {
-    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.pcsrk_key,
-                                     BTIF_DM_LE_KEY_PCSRK,
-                                     sizeof(tBTM_LE_PCSRK_KEYS));
+    btif_storage_add_ble_bonding_key(
+        &bd_addr, (uint8_t*)&pairing_cb.ble.pcsrk_key, BTIF_DM_LE_KEY_PCSRK,
+        sizeof(tBTM_LE_PCSRK_KEYS));
   }
 
   if (pairing_cb.ble.is_lenc_key_rcvd) {
-    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.lenc_key,
-                                     BTIF_DM_LE_KEY_LENC,
-                                     sizeof(tBTM_LE_LENC_KEYS));
+    btif_storage_add_ble_bonding_key(
+        &bd_addr, (uint8_t*)&pairing_cb.ble.lenc_key, BTIF_DM_LE_KEY_LENC,
+        sizeof(tBTM_LE_LENC_KEYS));
   }
 
   if (pairing_cb.ble.is_lcsrk_key_rcvd) {
-    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.lcsrk_key,
-                                     BTIF_DM_LE_KEY_LCSRK,
-                                     sizeof(tBTM_LE_LCSRK_KEYS));
+    btif_storage_add_ble_bonding_key(
+        &bd_addr, (uint8_t*)&pairing_cb.ble.lcsrk_key, BTIF_DM_LE_KEY_LCSRK,
+        sizeof(tBTM_LE_LCSRK_KEYS));
   }
 
   if (pairing_cb.ble.is_lidk_key_rcvd) {
@@ -3159,7 +3151,7 @@
       BTM_BleReceiverTest(buf[0], btif_dm_ble_rx_test_cback);
       break;
     case HCI_BLE_TEST_END:
-      BTM_BleTestEnd((tBTM_CMPL_CB*)btif_dm_ble_test_end_cback);
+      BTM_BleTestEnd(btif_dm_ble_test_end_cback);
       break;
     default:
       BTIF_TRACE_ERROR("%s: Unknown LE Test Mode Command 0x%x", __func__,
diff --git a/btif/src/btif_gatt.cc b/btif/src/btif_gatt.cc
index 67296f9..b4d0b10 100644
--- a/btif/src/btif_gatt.cc
+++ b/btif/src/btif_gatt.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/btif_gatt_client.cc b/btif/src/btif_gatt_client.cc
index 262234b..0e06bbb 100644
--- a/btif/src/btif_gatt_client.cc
+++ b/btif/src/btif_gatt_client.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2014 Broadcom Corporation
+ *  Copyright 2009-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -53,6 +53,7 @@
 
 using base::Bind;
 using base::Owned;
+using bluetooth::Uuid;
 using std::vector;
 
 extern bt_status_t btif_gattc_test_command_impl(
@@ -127,7 +128,7 @@
       HAL_CBACK(bt_gatt_callbacks, client->notify_cb, p_data->notify.conn_id,
                 data);
 
-      if (p_data->notify.is_notify == false)
+      if (!p_data->notify.is_notify)
         BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, p_data->notify.handle);
 
       break;
@@ -144,7 +145,7 @@
                   p_data->open.conn_id, p_data->open.status, p_data->open.mtu);
       }
 
-      if (p_data->open.status == BTA_GATT_OK)
+      if (p_data->open.status == GATT_SUCCESS)
         btif_gatt_check_encrypted_link(p_data->open.remote_bda,
                                        p_data->open.transport);
       break;
@@ -203,7 +204,9 @@
   ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
 }
 
-void btm_read_rssi_cb(tBTM_RSSI_RESULT* p_result) {
+void btm_read_rssi_cb(void* p_void) {
+  tBTM_RSSI_RESULT* p_result = (tBTM_RSSI_RESULT*)p_void;
+
   if (!p_result) return;
 
   CLI_CBACK_IN_JNI(read_remote_rssi_cb, rssi_request_client_if,
@@ -214,30 +217,25 @@
  *  Client API Functions
  ******************************************************************************/
 
-bt_status_t btif_gattc_register_app(const bt_uuid_t& uuid) {
+bt_status_t btif_gattc_register_app(const Uuid& uuid) {
   CHECK_BTGATT_INIT();
 
-  tBT_UUID bt_uuid;
-  btif_to_bta_uuid(&bt_uuid, &uuid);
-
   return do_in_jni_thread(Bind(
-      [](tBT_UUID bt_uuid) {
+      [](const Uuid& uuid) {
         BTA_GATTC_AppRegister(
             bta_gattc_cback,
             base::Bind(
-                [](tBT_UUID bt_uuid, uint8_t client_id, uint8_t status) {
+                [](const Uuid& uuid, uint8_t client_id, uint8_t status) {
                   do_in_jni_thread(Bind(
-                      [](tBT_UUID bt_uuid, uint8_t client_id, uint8_t status) {
-                        bt_uuid_t app_uuid;
-                        bta_to_btif_uuid(&app_uuid, &bt_uuid);
+                      [](const Uuid& uuid, uint8_t client_id, uint8_t status) {
                         HAL_CBACK(bt_gatt_callbacks, client->register_client_cb,
-                                  status, client_id, app_uuid);
+                                  status, client_id, uuid);
                       },
-                      bt_uuid, client_id, status));
+                      uuid, client_id, status));
                 },
-                bt_uuid));
+                uuid));
       },
-      bt_uuid));
+      uuid));
 }
 
 void btif_gattc_unregister_app_impl(int client_if) {
@@ -255,7 +253,7 @@
   // Ensure device is in inquiry database
   int addr_type = 0;
   int device_type = 0;
-  tBTA_GATT_TRANSPORT transport = (tBTA_GATT_TRANSPORT)BTA_GATT_TRANSPORT_LE;
+  tGATT_TRANSPORT transport = (tGATT_TRANSPORT)GATT_TRANSPORT_LE;
 
   if (btif_get_address_type(address, &addr_type) &&
       btif_get_device_type(address, &device_type) &&
@@ -287,18 +285,18 @@
   } else {
     switch (device_type) {
       case BT_DEVICE_TYPE_BREDR:
-        transport = BTA_GATT_TRANSPORT_BR_EDR;
+        transport = GATT_TRANSPORT_BR_EDR;
         break;
 
       case BT_DEVICE_TYPE_BLE:
-        transport = BTA_GATT_TRANSPORT_LE;
+        transport = GATT_TRANSPORT_LE;
         break;
 
       case BT_DEVICE_TYPE_DUMO:
         if (transport_p == GATT_TRANSPORT_LE)
-          transport = BTA_GATT_TRANSPORT_LE;
+          transport = GATT_TRANSPORT_LE;
         else
-          transport = BTA_GATT_TRANSPORT_BR_EDR;
+          transport = GATT_TRANSPORT_BR_EDR;
         break;
     }
   }
@@ -343,13 +341,11 @@
   return do_in_jni_thread(Bind(&BTA_GATTC_Refresh, bd_addr));
 }
 
-bt_status_t btif_gattc_search_service(int conn_id,
-                                      const bt_uuid_t* filter_uuid) {
+bt_status_t btif_gattc_search_service(int conn_id, const Uuid* filter_uuid) {
   CHECK_BTGATT_INIT();
 
   if (filter_uuid) {
-    tBT_UUID* uuid = new tBT_UUID;
-    btif_to_bta_uuid(uuid, filter_uuid);
+    Uuid* uuid = new Uuid(*filter_uuid);
     return do_in_jni_thread(
         Bind(&BTA_GATTC_ServiceSearchRequest, conn_id, base::Owned(uuid)));
   } else {
@@ -358,11 +354,8 @@
   }
 }
 
-void btif_gattc_discover_service_by_uuid(int conn_id, const bt_uuid_t& p_uuid) {
-  tBT_UUID* uuid = new tBT_UUID;
-  btif_to_bta_uuid(uuid, &p_uuid);
-  do_in_jni_thread(
-      Bind(&BTA_GATTC_DiscoverServiceByUuid, conn_id, base::Owned(uuid)));
+void btif_gattc_discover_service_by_uuid(int conn_id, const Uuid& uuid) {
+  do_in_jni_thread(Bind(&BTA_GATTC_DiscoverServiceByUuid, conn_id, uuid));
 }
 
 void btif_gattc_get_gatt_db_impl(int conn_id) {
@@ -418,13 +411,11 @@
                    base::Owned(params));
 }
 
-bt_status_t btif_gattc_read_using_char_uuid(int conn_id, const bt_uuid_t& uuid,
+bt_status_t btif_gattc_read_using_char_uuid(int conn_id, const Uuid& uuid,
                                             uint16_t s_handle,
                                             uint16_t e_handle, int auth_req) {
   CHECK_BTGATT_INIT();
-  tBT_UUID bt_uuid;
-  btif_to_bta_uuid(&bt_uuid, &uuid);
-  return do_in_jni_thread(Bind(&BTA_GATTC_ReadUsingCharUuid, conn_id, bt_uuid,
+  return do_in_jni_thread(Bind(&BTA_GATTC_ReadUsingCharUuid, conn_id, uuid,
                                s_handle, e_handle, auth_req,
                                read_using_char_uuid_cb, nullptr));
 }
@@ -487,10 +478,10 @@
       Bind(&BTA_GATTC_ExecuteWrite, conn_id, (uint8_t)execute));
 }
 
-void btif_gattc_reg_for_notification_impl(tBTA_GATTC_IF client_if,
+void btif_gattc_reg_for_notification_impl(tGATT_IF client_if,
                                           const RawAddress& bda,
                                           uint16_t handle) {
-  tBTA_GATT_STATUS status =
+  tGATT_STATUS status =
       BTA_GATTC_RegisterForNotifications(client_if, bda, handle);
 
   // TODO(jpawlowski): conn_id is currently unused
@@ -508,10 +499,10 @@
            bd_addr, handle));
 }
 
-void btif_gattc_dereg_for_notification_impl(tBTA_GATTC_IF client_if,
+void btif_gattc_dereg_for_notification_impl(tGATT_IF client_if,
                                             const RawAddress& bda,
                                             uint16_t handle) {
-  tBTA_GATT_STATUS status =
+  tGATT_STATUS status =
       BTA_GATTC_DeregisterForNotifications(client_if, bda, handle);
 
   // TODO(jpawlowski): conn_id is currently unused
@@ -534,8 +525,8 @@
   CHECK_BTGATT_INIT();
   rssi_request_client_if = client_if;
 
-  return do_in_jni_thread(Bind(base::IgnoreResult(&BTM_ReadRSSI), bd_addr,
-                               (tBTM_CMPL_CB*)btm_read_rssi_cb));
+  return do_in_jni_thread(
+      Bind(base::IgnoreResult(&BTM_ReadRSSI), bd_addr, btm_read_rssi_cb));
 }
 
 bt_status_t btif_gattc_configure_mtu(int conn_id, int mtu) {
@@ -546,10 +537,11 @@
 
 void btif_gattc_conn_parameter_update_impl(RawAddress addr, int min_interval,
                                            int max_interval, int latency,
-                                           int timeout) {
+                                           int timeout, uint16_t min_ce_len,
+                                           uint16_t max_ce_len) {
   if (BTA_DmGetConnectionState(addr))
     BTA_DmBleUpdateConnectionParams(addr, min_interval, max_interval, latency,
-                                    timeout);
+                                    timeout, min_ce_len, max_ce_len);
   else
     BTA_DmSetBlePrefConnParams(addr, min_interval, max_interval, latency,
                                timeout);
@@ -557,11 +549,13 @@
 
 bt_status_t btif_gattc_conn_parameter_update(const RawAddress& bd_addr,
                                              int min_interval, int max_interval,
-                                             int latency, int timeout) {
+                                             int latency, int timeout,
+                                             uint16_t min_ce_len,
+                                             uint16_t max_ce_len) {
   CHECK_BTGATT_INIT();
-  return do_in_jni_thread(
-      Bind(base::IgnoreResult(&btif_gattc_conn_parameter_update_impl), bd_addr,
-           min_interval, max_interval, latency, timeout));
+  return do_in_jni_thread(Bind(
+      base::IgnoreResult(&btif_gattc_conn_parameter_update_impl), bd_addr,
+      min_interval, max_interval, latency, timeout, min_ce_len, max_ce_len));
 }
 
 bt_status_t btif_gattc_set_preferred_phy(const RawAddress& bd_addr,
diff --git a/btif/src/btif_gatt_server.cc b/btif/src/btif_gatt_server.cc
index bd3a94ce..b7fdc8c 100644
--- a/btif/src/btif_gatt_server.cc
+++ b/btif/src/btif_gatt_server.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@
 
 using base::Bind;
 using base::Owned;
+using bluetooth::Uuid;
 using std::vector;
 
 /*******************************************************************************
@@ -96,9 +97,9 @@
     case BTA_GATTS_EXEC_WRITE_EVT:
     case BTA_GATTS_MTU_EVT:
       p_dest_data->req_data.p_data =
-          (tBTA_GATTS_REQ_DATA*)osi_malloc(sizeof(tBTA_GATTS_REQ_DATA));
+          (tGATTS_DATA*)osi_malloc(sizeof(tGATTS_DATA));
       memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
-             sizeof(tBTA_GATTS_REQ_DATA));
+             sizeof(tGATTS_DATA));
       break;
 
     default:
@@ -128,10 +129,9 @@
   tBTA_GATTS* p_data = (tBTA_GATTS*)p_param;
   switch (event) {
     case BTA_GATTS_REG_EVT: {
-      bt_uuid_t app_uuid;
-      bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.uuid);
       HAL_CBACK(bt_gatt_callbacks, server->register_server_cb,
-                p_data->reg_oper.status, p_data->reg_oper.server_if, app_uuid);
+                p_data->reg_oper.status, p_data->reg_oper.server_if,
+                p_data->reg_oper.uuid);
       break;
     }
 
@@ -266,13 +266,11 @@
 /*******************************************************************************
  *  Server API Functions
  ******************************************************************************/
-static bt_status_t btif_gatts_register_app(const bt_uuid_t& bt_uuid) {
+static bt_status_t btif_gatts_register_app(const Uuid& bt_uuid) {
   CHECK_BTGATT_INIT();
-  tBT_UUID* uuid = new tBT_UUID;
-  btif_to_bta_uuid(uuid, &bt_uuid);
 
   return do_in_jni_thread(
-      Bind(&BTA_GATTS_AppRegister, base::Owned(uuid), &btapp_gatts_cback));
+      Bind(&BTA_GATTS_AppRegister, bt_uuid, &btapp_gatts_cback));
 }
 
 static bt_status_t btif_gatts_unregister_app(int server_if) {
@@ -285,7 +283,7 @@
   // Ensure device is in inquiry database
   int addr_type = 0;
   int device_type = 0;
-  tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE;
+  tGATT_TRANSPORT transport = GATT_TRANSPORT_LE;
 
   if (btif_get_address_type(address, &addr_type) &&
       btif_get_device_type(address, &device_type) &&
@@ -302,18 +300,18 @@
   } else {
     switch (device_type) {
       case BT_DEVICE_TYPE_BREDR:
-        transport = BTA_GATT_TRANSPORT_BR_EDR;
+        transport = GATT_TRANSPORT_BR_EDR;
         break;
 
       case BT_DEVICE_TYPE_BLE:
-        transport = BTA_GATT_TRANSPORT_LE;
+        transport = GATT_TRANSPORT_LE;
         break;
 
       case BT_DEVICE_TYPE_DUMO:
         if (transport_param == GATT_TRANSPORT_LE)
-          transport = BTA_GATT_TRANSPORT_LE;
+          transport = GATT_TRANSPORT_LE;
         else
-          transport = BTA_GATT_TRANSPORT_BR_EDR;
+          transport = GATT_TRANSPORT_BR_EDR;
         break;
     }
   }
@@ -348,33 +346,35 @@
       Bind(&btif_gatts_close_impl, server_if, bd_addr, conn_id));
 }
 
+static void on_service_added_cb(uint8_t status, int server_if,
+                                vector<btgatt_db_element_t> service) {
+  HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, status, server_if,
+            std::move(service));
+}
+
 static void add_service_impl(int server_if,
                              vector<btgatt_db_element_t> service) {
-  bt_uuid_t restricted_uuid1, restricted_uuid2;
-  uuid_128_from_16(&restricted_uuid1, UUID_SERVCLASS_GATT_SERVER);
-  uuid_128_from_16(&restricted_uuid2, UUID_SERVCLASS_GAP_SERVER);
-
   // TODO(jpawlowski): btif should be a pass through layer, and no checks should
   // be made here. This exception is added only until GATT server code is
   // refactored, and one can distinguish stack-internal aps from external apps
-  if (memcmp(&service[0].uuid, &restricted_uuid1, sizeof(bt_uuid_t)) == 0 ||
-      memcmp(&service[0].uuid, &restricted_uuid2, sizeof(bt_uuid_t)) == 0) {
+  if (service[0].uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER) ||
+      service[0].uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) {
     LOG_ERROR(LOG_TAG, "%s: Attept to register restricted service", __func__);
     HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, BT_STATUS_FAIL,
               server_if, std::move(service));
     return;
   }
 
-  int status = BTA_GATTS_AddService(server_if, service);
-  HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, status, server_if,
-            std::move(service));
+  BTA_GATTS_AddService(
+      server_if, service,
+      jni_thread_wrapper(FROM_HERE, base::Bind(&on_service_added_cb)));
 }
 
 static bt_status_t btif_gatts_add_service(int server_if,
                                           vector<btgatt_db_element_t> service) {
   CHECK_BTGATT_INIT();
   return do_in_jni_thread(
-      Bind(&add_service_impl, server_if, std::move(service)));
+      FROM_HERE, Bind(&add_service_impl, server_if, std::move(service)));
 }
 
 static bt_status_t btif_gatts_stop_service(int server_if, int service_handle) {
@@ -404,7 +404,7 @@
 
 static void btif_gatts_send_response_impl(int conn_id, int trans_id, int status,
                                           btgatt_response_t response) {
-  tBTA_GATTS_RSP rsp_struct;
+  tGATTS_RSP rsp_struct;
   btif_to_bta_response(&rsp_struct, &response);
 
   BTA_GATTS_SendRsp(conn_id, trans_id, status, &rsp_struct);
diff --git a/btif/src/btif_gatt_test.cc b/btif/src/btif_gatt_test.cc
index 4312533..1297d50 100644
--- a/btif/src/btif_gatt_test.cc
+++ b/btif/src/btif_gatt_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 
+using bluetooth::Uuid;
 /*******************************************************************************
  * Typedefs & Macros
  ******************************************************************************/
@@ -65,27 +66,6 @@
  * Callback functions
  ******************************************************************************/
 
-static char* format_uuid(tBT_UUID bt_uuid, char* str_buf, size_t buf_size) {
-  if (bt_uuid.len == LEN_UUID_16) {
-    snprintf(str_buf, buf_size, "0x%04x", bt_uuid.uu.uuid16);
-  } else if (bt_uuid.len == LEN_UUID_128) {
-    int x = snprintf(str_buf, buf_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x",
-                     bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
-                     bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
-                     bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
-                     bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
-    snprintf(&str_buf[x], buf_size - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
-             bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
-             bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
-             bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
-             bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
-  } else {
-    snprintf(str_buf, buf_size, "Unknown (len=%d)", bt_uuid.len);
-  }
-
-  return str_buf;
-}
-
 static void btif_test_connect_cback(tGATT_IF, const RawAddress&,
                                     uint16_t conn_id, bool connected,
                                     tGATT_DISCONN_REASON, tBT_TRANSPORT) {
@@ -121,8 +101,6 @@
 static void btif_test_discovery_result_cback(UNUSED_ATTR uint16_t conn_id,
                                              tGATT_DISC_TYPE disc_type,
                                              tGATT_DISC_RES* p_data) {
-  char str_buf[50];
-
   LOG_DEBUG(LOG_TAG, "------ GATT Discovery result %-22s -------",
             disc_name[disc_type]);
   LOG_DEBUG(LOG_TAG, "      Attribute handle: 0x%04x (%d)", p_data->handle,
@@ -130,7 +108,7 @@
 
   if (disc_type != GATT_DISC_CHAR_DSCPT) {
     LOG_DEBUG(LOG_TAG, "        Attribute type: %s",
-              format_uuid(p_data->type, str_buf, sizeof(str_buf)));
+              p_data->type.ToString().c_str());
   }
 
   switch (disc_type) {
@@ -139,8 +117,7 @@
                 p_data->handle, p_data->value.group_value.e_handle,
                 p_data->handle, p_data->value.group_value.e_handle);
       LOG_DEBUG(LOG_TAG, "          Service UUID: %s",
-                format_uuid(p_data->value.group_value.service_type, str_buf,
-                            sizeof(str_buf)));
+                p_data->value.group_value.service_type.ToString().c_str());
       break;
 
     case GATT_DISC_SRVC_BY_UUID:
@@ -156,21 +133,19 @@
                 p_data->value.incl_service.s_handle,
                 p_data->value.incl_service.e_handle);
       LOG_DEBUG(LOG_TAG, "          Service UUID: %s",
-                format_uuid(p_data->value.incl_service.service_type, str_buf,
-                            sizeof(str_buf)));
+                p_data->value.incl_service.service_type.ToString().c_str());
       break;
 
     case GATT_DISC_CHAR:
       LOG_DEBUG(LOG_TAG, "            Properties: 0x%02x",
                 p_data->value.dclr_value.char_prop);
       LOG_DEBUG(LOG_TAG, "   Characteristic UUID: %s",
-                format_uuid(p_data->value.dclr_value.char_uuid, str_buf,
-                            sizeof(str_buf)));
+                p_data->value.dclr_value.char_uuid.ToString().c_str());
       break;
 
     case GATT_DISC_CHAR_DSCPT:
       LOG_DEBUG(LOG_TAG, "       Descriptor UUID: %s",
-                format_uuid(p_data->type, str_buf, sizeof(str_buf)));
+                p_data->type.ToString().c_str());
       break;
   }
 
@@ -205,8 +180,10 @@
     {
       LOG_DEBUG(LOG_TAG, "%s: ENABLE - enable=%d", __func__, params->u1);
       if (params->u1) {
-        tBT_UUID app_uuid = {LEN_UUID_128, {0xAE}};
-        test_cb.gatt_if = GATT_Register(&app_uuid, &btif_test_callbacks);
+        std::array<uint8_t, Uuid::kNumBytes128> tmp;
+        tmp.fill(0xAE);
+        test_cb.gatt_if = GATT_Register(bluetooth::Uuid::From128BitBE(tmp),
+                                        &btif_test_callbacks);
         GATT_StartIf(test_cb.gatt_if);
       } else {
         GATT_Deregister(test_cb.gatt_if);
@@ -217,12 +194,8 @@
 
     case 0x02: /* Connect */
     {
-      LOG_DEBUG(LOG_TAG,
-                "%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x "
-                "(dev_type=%d, addr_type=%d)",
-                __func__, params->bda1->address[0], params->bda1->address[1],
-                params->bda1->address[2], params->bda1->address[3],
-                params->bda1->address[4], params->bda1->address[5], params->u1,
+      LOG_DEBUG(LOG_TAG, "%s: CONNECT - device=%s (dev_type=%d, addr_type=%d)",
+                __func__, params->bda1->ToString().c_str(), params->u1,
                 params->u2);
 
       if (params->u1 == BT_DEVICE_TYPE_BLE)
@@ -246,7 +219,6 @@
 
     case 0x04: /* Discover */
     {
-      char buf[50] = {0};
       tGATT_DISC_PARAM param;
       memset(&param, 0, sizeof(tGATT_DISC_PARAM));
 
@@ -258,13 +230,12 @@
 
       param.s_handle = params->u2;
       param.e_handle = params->u3;
-      btif_to_bta_uuid(&param.service, params->uuid1);
+      param.service = *params->uuid1;
 
       LOG_DEBUG(LOG_TAG,
                 "%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
                 __func__, disc_name[params->u1], test_cb.conn_id,
-                format_uuid(param.service, buf, sizeof(buf)), params->u2,
-                params->u3);
+                param.service.ToString().c_str(), params->u2, params->u3);
       GATTC_Discover(test_cb.conn_id, params->u1, &param);
       break;
     }
diff --git a/btif/src/btif_gatt_util.cc b/btif/src/btif_gatt_util.cc
index 9745917..16f2275 100644
--- a/btif/src/btif_gatt_util.cc
+++ b/btif/src/btif_gatt_util.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -40,63 +40,12 @@
 #include "btif_util.h"
 #include "osi/include/osi.h"
 
-#define GATTC_READ_VALUE_TYPE_VALUE 0x0000 /* Attribute value itself */
-#define GATTC_READ_VALUE_TYPE_AGG_FORMAT \
-  0x2905 /* Characteristic Aggregate Format*/
-
-static unsigned char BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
-                                      0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
-                                      0x00, 0x00, 0x00, 0x00};
-
-int uuidType(const unsigned char* p_uuid) {
-  int i = 0;
-  int match = 0;
-  int all_zero = 1;
-
-  for (i = 0; i != 16; ++i) {
-    if (i == 12 || i == 13) continue;
-
-    if (p_uuid[i] == BASE_UUID[i]) ++match;
-
-    if (p_uuid[i] != 0) all_zero = 0;
-  }
-  if (all_zero) return 0;
-  if (match == 12) return LEN_UUID_32;
-  if (match == 14) return LEN_UUID_16;
-  return LEN_UUID_128;
-}
+using bluetooth::Uuid;
 
 /*******************************************************************************
  * BTIF -> BTA conversion functions
  ******************************************************************************/
-
-void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src) {
-  char* p_byte = (char*)p_src;
-  int i = 0;
-
-  p_dest->len = uuidType(p_src->uu);
-
-  switch (p_dest->len) {
-    case LEN_UUID_16:
-      p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
-      break;
-
-    case LEN_UUID_32:
-      p_dest->uu.uuid32 = (p_src->uu[13] << 8) + p_src->uu[12];
-      p_dest->uu.uuid32 += (p_src->uu[15] << 24) + (p_src->uu[14] << 16);
-      break;
-
-    case LEN_UUID_128:
-      for (i = 0; i != 16; ++i) p_dest->uu.uuid128[i] = p_byte[i];
-      break;
-
-    default:
-      LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __func__, p_dest->len);
-      break;
-  }
-}
-
-void btif_to_bta_response(tBTA_GATTS_RSP* p_dest, btgatt_response_t* p_src) {
+void btif_to_bta_response(tGATTS_RSP* p_dest, btgatt_response_t* p_src) {
   p_dest->attr_value.auth_req = p_src->attr_value.auth_req;
   p_dest->attr_value.handle = p_src->attr_value.handle;
   p_dest->attr_value.len = p_src->attr_value.len;
@@ -104,108 +53,6 @@
   memcpy(p_dest->attr_value.value, p_src->attr_value.value, GATT_MAX_ATTR_LEN);
 }
 
-void btif_to_bta_uuid_mask(tBTM_BLE_PF_COND_MASK* p_mask,
-                           const bt_uuid_t* uuid_mask,
-                           const bt_uuid_t* svc_uuid) {
-  char* p_byte = (char*)uuid_mask;
-  int uuid_len = uuidType(svc_uuid->uu);
-  int i = 0;
-
-  switch (uuid_len) {
-    case LEN_UUID_16:
-      p_mask->uuid16_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
-      break;
-
-    case LEN_UUID_32:
-      p_mask->uuid32_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
-      p_mask->uuid32_mask +=
-          (uuid_mask->uu[15] << 24) + (uuid_mask->uu[14] << 16);
-      break;
-
-    case LEN_UUID_128:
-      for (i = 0; i != 16; ++i) p_mask->uuid128_mask[i] = p_byte[i];
-      break;
-
-    default:
-      break;
-  }
-}
-
-/*******************************************************************************
- * BTA -> BTIF conversion functions
- ******************************************************************************/
-
-void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src) {
-  int i = 0;
-
-  if (p_src->len == LEN_UUID_16 || p_src->len == LEN_UUID_32) {
-    for (i = 0; i != 16; ++i) p_dest->uu[i] = BASE_UUID[i];
-  }
-
-  switch (p_src->len) {
-    case 0:
-      break;
-
-    case LEN_UUID_16:
-      p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
-      p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
-      break;
-
-    case LEN_UUID_32:
-      p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
-      p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
-      p_dest->uu[14] = (p_src->uu.uuid32 >> 16) & 0xff;
-      p_dest->uu[15] = (p_src->uu.uuid32 >> 24) & 0xff;
-      break;
-
-    case LEN_UUID_128:
-      for (i = 0; i != 16; ++i) p_dest->uu[i] = p_src->uu.uuid128[i];
-      break;
-
-    default:
-      LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __func__, p_src->len);
-      break;
-  }
-}
-
-/*******************************************************************************
- * Utility functions
- ******************************************************************************/
-
-uint16_t get_uuid16(tBT_UUID* p_uuid) {
-  if (p_uuid->len == LEN_UUID_16) {
-    return p_uuid->uu.uuid16;
-  } else if (p_uuid->len == LEN_UUID_128) {
-    uint16_t u16;
-    uint8_t* p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4];
-    STREAM_TO_UINT16(u16, p);
-    return u16;
-  } else /* p_uuid->len == LEN_UUID_32 */
-  {
-    return (uint16_t)p_uuid->uu.uuid32;
-  }
-}
-
-uint16_t set_read_value(btgatt_read_params_t* p_dest, tBTA_GATTC_READ* p_src) {
-  uint16_t len = 0;
-
-  p_dest->status = p_src->status;
-  p_dest->handle = p_src->handle;
-
-  if ((p_src->status == BTA_GATT_OK) && (p_src->len != 0)) {
-    LOG_INFO(LOG_TAG, "%s len = %d ", __func__, p_src->len);
-    p_dest->value.len = p_src->len;
-    memcpy(p_dest->value.value, p_src->value, p_src->len);
-
-    len += p_src->len;
-  } else {
-    p_dest->value.len = 0;
-  }
-
-  p_dest->value_type = GATTC_READ_VALUE_TYPE_VALUE;
-  return len;
-}
-
 /*******************************************************************************
  * Encrypted link map handling
  ******************************************************************************/
@@ -226,12 +73,11 @@
 
 #if (BLE_DELAY_REQUEST_ENC == FALSE)
 void btif_gatt_check_encrypted_link(RawAddress bd_addr,
-                                    tBTA_GATT_TRANSPORT transport_link) {
-  char buf[100];
-
-  if ((btif_storage_get_ble_bonding_key(&bd_addr, BTIF_DM_LE_KEY_PENC, buf,
-                                        sizeof(tBTM_LE_PENC_KEYS)) ==
-       BT_STATUS_SUCCESS) &&
+                                    tGATT_TRANSPORT transport_link) {
+  tBTM_LE_PENC_KEYS key;
+  if ((btif_storage_get_ble_bonding_key(
+           &bd_addr, BTIF_DM_LE_KEY_PENC, (uint8_t*)&key,
+           sizeof(tBTM_LE_PENC_KEYS)) == BT_STATUS_SUCCESS) &&
       !btif_gatt_is_link_encrypted(bd_addr)) {
     BTIF_TRACE_DEBUG("%s: transport = %d", __func__, transport_link);
     BTA_DmSetEncryption(bd_addr, transport_link, &btif_gatt_set_encryption_cb,
@@ -240,7 +86,7 @@
 }
 #else
 void btif_gatt_check_encrypted_link(UNUSED_ATTR RawAddress bd_addr,
-                                    UNUSED_ATTR tBTA_GATT_TRANSPORT
+                                    UNUSED_ATTR tGATT_TRANSPORT
                                         transport_link) {}
 #endif
 
diff --git a/btif/src/btif_hd.cc b/btif/src/btif_hd.cc
index eb3dbbb..bc0992d 100644
--- a/btif/src/btif_hd.cc
+++ b/btif/src/btif_hd.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/btif_hearing_aid.cc b/btif/src/btif_hearing_aid.cc
new file mode 100644
index 0000000..48aab95
--- /dev/null
+++ b/btif/src/btif_hearing_aid.cc
@@ -0,0 +1,133 @@
+/******************************************************************************
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/* Hearing Aid Profile Interface */
+
+#include "bta_closure_api.h"
+#include "bta_hearing_aid_api.h"
+#include "btif_common.h"
+#include "btif_storage.h"
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hearing_aid.h>
+
+using base::Bind;
+using base::Unretained;
+using bluetooth::hearing_aid::ConnectionState;
+using bluetooth::hearing_aid::HearingAidCallbacks;
+using bluetooth::hearing_aid::HearingAidInterface;
+
+// template specialization
+template <>
+base::Callback<void()> jni_thread_wrapper(
+    const tracked_objects::Location& from_here, base::Callback<void()> cb) {
+  return base::Bind(
+      [](const tracked_objects::Location& from_here,
+         base::Callback<void()> cb) { do_in_jni_thread(from_here, cb); },
+      from_here, std::move(cb));
+}
+
+namespace {
+class HearingAidInterfaceImpl;
+std::unique_ptr<HearingAidInterface> hearingAidInstance;
+
+class HearingAidInterfaceImpl
+    : public bluetooth::hearing_aid::HearingAidInterface,
+      public HearingAidCallbacks {
+  ~HearingAidInterfaceImpl() = default;
+
+  void Init(HearingAidCallbacks* callbacks) {
+    DVLOG(2) << __func__;
+    this->callbacks = callbacks;
+    do_in_bta_thread(
+        FROM_HERE,
+        Bind(&HearingAid::Initialize, this,
+             jni_thread_wrapper(FROM_HERE,
+                                Bind(&btif_storage_load_bonded_hearing_aids))));
+  }
+
+  void OnConnectionState(ConnectionState state,
+                         const RawAddress& address) override {
+    DVLOG(2) << __func__ << " address: " << address;
+    do_in_jni_thread(FROM_HERE, Bind(&HearingAidCallbacks::OnConnectionState,
+                                     Unretained(callbacks), state, address));
+  }
+
+  void OnDeviceAvailable(uint8_t capabilities, uint64_t hiSyncId,
+                         const RawAddress& address) override {
+    DVLOG(2) << __func__ << " address: " << address
+             << ", hiSyncId: " << loghex(hiSyncId)
+             << ", capabilities: " << loghex(capabilities);
+    do_in_jni_thread(FROM_HERE, Bind(&HearingAidCallbacks::OnDeviceAvailable,
+                                     Unretained(callbacks), capabilities,
+                                     hiSyncId, address));
+  }
+
+  void Connect(const RawAddress& address) override {
+    DVLOG(2) << __func__ << " address: " << address;
+    do_in_bta_thread(FROM_HERE, Bind(&HearingAid::Connect,
+                                     Unretained(HearingAid::Get()), address));
+  }
+
+  void Disconnect(const RawAddress& address) override {
+    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_white_list, address));
+  }
+
+  void SetVolume(int8_t volume) override {
+    DVLOG(2) << __func__ << " volume: " << +volume;
+    do_in_bta_thread(FROM_HERE, Bind(&HearingAid::SetVolume,
+                                     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));
+  }
+
+ private:
+  HearingAidCallbacks* callbacks;
+};
+
+}  // namespace
+
+HearingAidInterface* btif_hearing_aid_get_interface() {
+  if (!hearingAidInstance)
+    hearingAidInstance.reset(new HearingAidInterfaceImpl());
+
+  return hearingAidInstance.get();
+}
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index 9ec6da8..37f9471 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,11 +27,14 @@
 
 #define LOG_TAG "bt_btif_hf"
 
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
+#include <cstdlib>
+#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>
 #include <hardware/bt_hf.h>
 
 #include "bta/include/utl.h"
@@ -40,7 +43,10 @@
 #include "btif_hf.h"
 #include "btif_profile_queue.h"
 #include "btif_util.h"
-#include "osi/include/properties.h"
+#include "osi/include/metrics.h"
+
+namespace bluetooth {
+namespace headset {
 
 /*******************************************************************************
  *  Constants & Macros
@@ -77,74 +83,41 @@
 /* HF features supported at runtime */
 static uint32_t btif_hf_features = BTIF_HF_FEATURES;
 
-#define BTIF_HF_CALL_END_TIMEOUT 6
-
 #define BTIF_HF_INVALID_IDX (-1)
 
-/* Number of BTIF-HF control blocks */
-#define BTIF_HF_NUM_CB 2
-
 /* Max HF clients supported from App */
-uint16_t btif_max_hf_clients = 1;
-
-/* HF app ids for service registration */
-typedef enum {
-  BTIF_HF_ID_1 = 0,
-  BTIF_HF_ID_2,
-#if (BTIF_HF_NUM_CB == 3)
-  BTIF_HF_ID_3
-#endif
-} bthf_hf_id_t;
-
-uint16_t bthf_hf_id[BTIF_HF_NUM_CB] = {BTIF_HF_ID_1, BTIF_HF_ID_2,
-#if (BTIF_HF_NUM_CB == 3)
-                                       BTIF_HF_ID_3
-#endif
-};
-
-/*******************************************************************************
- *  Local type definitions
- ******************************************************************************/
+static int btif_max_hf_clients = 1;
+static RawAddress active_bda = {};
 
 /*******************************************************************************
  *  Static variables
  ******************************************************************************/
-static bthf_callbacks_t* bt_hf_callbacks = NULL;
-static int hf_idx = BTIF_HF_INVALID_IDX;
+static Callbacks* bt_hf_callbacks = nullptr;
 
 #define CHECK_BTHF_INIT()                                             \
   do {                                                                \
-    if (bt_hf_callbacks == NULL) {                                    \
+    if (!bt_hf_callbacks) {                                           \
       BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__); \
       return BT_STATUS_NOT_READY;                                     \
     } else {                                                          \
       BTIF_TRACE_EVENT("BTHF: %s", __func__);                         \
     }                                                                 \
-  } while (0)
+  } while (false)
 
 /* BTIF-HF control block to map bdaddr to BTA handle */
-typedef struct _btif_hf_cb {
+struct btif_hf_cb_t {
   uint16_t handle;
+  bool is_initiator;
   RawAddress connected_bda;
   bthf_connection_state_t state;
-  bthf_vr_state_t vr_state;
   tBTA_AG_PEER_FEAT peer_feat;
   int num_active;
   int num_held;
-  struct timespec call_end_timestamp;
-  struct timespec connected_timestamp;
   bthf_call_state_t call_setup_state;
-} btif_hf_cb_t;
+};
 
-static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
+static btif_hf_cb_t btif_hf_cb[BTA_AG_MAX_NUM_CLIENTS];
 
-/*******************************************************************************
- *  Static functions
- ******************************************************************************/
-
-/*******************************************************************************
- *  Externs
- ******************************************************************************/
 /* By default, even though codec negotiation is enabled, we will not use WBS as
  * the default
  * codec unless this variable is set to true.
@@ -153,24 +126,47 @@
 #define BTIF_HF_WBS_PREFERRED false
 #endif
 
-bool btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
+static bool btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
 
-/*******************************************************************************
- *  Functions
- ******************************************************************************/
+static const char* dump_hf_call_state(bthf_call_state_t call_state) {
+  switch (call_state) {
+    CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
+    CASE_RETURN_STR(BTHF_CALL_STATE_HELD)
+    CASE_RETURN_STR(BTHF_CALL_STATE_DIALING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_ALERTING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_INCOMING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_WAITING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_ACTIVE)
+    CASE_RETURN_STR(BTHF_CALL_STATE_DISCONNECTED)
+    default:
+      return "UNKNOWN CALL STATE";
+  }
+}
+
+/**
+ * Check if bd_addr is the current active device.
+ *
+ * @param bd_addr target device address
+ * @return True if bd_addr is the current active device, False otherwise or if
+ * no active device is set (i.e. active_device_addr is empty)
+ */
+static bool is_active_device(const RawAddress& bd_addr) {
+  return !active_bda.IsEmpty() && active_bda == bd_addr;
+}
 
 /*******************************************************************************
  *
  * Function         is_connected
  *
  * Description      Internal function to check if HF is connected
+ *                  is_connected(nullptr) returns TRUE if one of the control
+ *                  blocks is connected
  *
  * Returns          true if connected
  *
  ******************************************************************************/
 static bool is_connected(RawAddress* bd_addr) {
-  int i;
-  for (i = 0; i < btif_max_hf_clients; ++i) {
+  for (int i = 0; i < btif_max_hf_clients; ++i) {
     if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
          (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
         (!bd_addr || *bd_addr == btif_hf_cb[i].connected_bda))
@@ -189,8 +185,7 @@
  *
  ******************************************************************************/
 static int btif_hf_idx_by_bdaddr(RawAddress* bd_addr) {
-  int i;
-  for (i = 0; i < btif_max_hf_clients; ++i) {
+  for (int i = 0; i < btif_max_hf_clients; ++i) {
     if (*bd_addr == btif_hf_cb[i].connected_bda) return i;
   }
   return BTIF_HF_INVALID_IDX;
@@ -206,12 +201,16 @@
  *
  ******************************************************************************/
 static uint8_t callstate_to_callsetup(bthf_call_state_t call_state) {
-  uint8_t call_setup = 0;
-  if (call_state == BTHF_CALL_STATE_INCOMING) call_setup = 1;
-  if (call_state == BTHF_CALL_STATE_DIALING) call_setup = 2;
-  if (call_state == BTHF_CALL_STATE_ALERTING) call_setup = 3;
-
-  return call_setup;
+  switch (call_state) {
+    case BTHF_CALL_STATE_INCOMING:
+      return 1;
+    case BTHF_CALL_STATE_DIALING:
+      return 2;
+    case BTHF_CALL_STATE_ALERTING:
+      return 3;
+    default:
+      return 0;
+  }
 }
 
 /*******************************************************************************
@@ -224,15 +223,12 @@
  *
  ******************************************************************************/
 static void send_at_result(uint8_t ok_flag, uint16_t errcode, int idx) {
-  tBTA_AG_RES_DATA ag_res;
-  memset(&ag_res, 0, sizeof(ag_res));
-
+  tBTA_AG_RES_DATA ag_res = {};
   ag_res.ok_flag = ok_flag;
   if (ok_flag == BTA_AG_OK_ERROR) {
     ag_res.errcode = errcode;
   }
-
-  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, ag_res);
 }
 
 /*******************************************************************************
@@ -244,86 +240,52 @@
  * Returns          void
  *
  ******************************************************************************/
-static void send_indicator_update(uint16_t indicator, uint16_t value) {
-  tBTA_AG_RES_DATA ag_res;
-
-  memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+static void send_indicator_update(const btif_hf_cb_t& control_block,
+                                  uint16_t indicator, uint16_t value) {
+  tBTA_AG_RES_DATA ag_res = {};
   ag_res.ind.id = indicator;
   ag_res.ind.value = value;
-
-  BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+  BTA_AgResult(control_block.handle, BTA_AG_IND_RES, ag_res);
 }
 
-void clear_phone_state_multihf(int idx) {
-  btif_hf_cb[idx].call_setup_state = BTHF_CALL_STATE_IDLE;
-  btif_hf_cb[idx].num_active = btif_hf_cb[idx].num_held = 0;
+static bool is_nth_bit_enabled(uint32_t value, int n) {
+  return (value & (static_cast<uint32_t>(1) << n)) != 0;
 }
 
-/*******************************************************************************
- *
- * Function         btif_hf_latest_connected_idx
- *
- * Description      Returns idx for latest connected HF
- *
- * Returns          int
- *
- ******************************************************************************/
-static int btif_hf_latest_connected_idx() {
-  struct timespec now, conn_time_delta;
-  int latest_conn_idx = BTIF_HF_INVALID_IDX, i;
+void clear_phone_state_multihf(btif_hf_cb_t* hf_cb) {
+  hf_cb->call_setup_state = BTHF_CALL_STATE_IDLE;
+  hf_cb->num_active = 0;
+  hf_cb->num_held = 0;
+}
 
-  clock_gettime(CLOCK_MONOTONIC, &now);
-  conn_time_delta.tv_sec = now.tv_sec;
+static void reset_control_block(btif_hf_cb_t* hf_cb) {
+  hf_cb->state = BTHF_CONNECTION_STATE_DISCONNECTED;
+  hf_cb->is_initiator = false;
+  hf_cb->connected_bda = RawAddress::kEmpty;
+  hf_cb->peer_feat = 0;
+  clear_phone_state_multihf(hf_cb);
+}
 
-  for (i = 0; i < btif_max_hf_clients; i++) {
-    if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
-      if ((now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec) <
-          conn_time_delta.tv_sec) {
-        conn_time_delta.tv_sec =
-            now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec;
-        latest_conn_idx = i;
-      }
-    }
+/**
+ * Check if Service Level Connection (SLC) is established for bd_addr
+ *
+ * @param bd_addr remote device address
+ * @return true if SLC is established for bd_addr
+ */
+static bool IsSlcConnected(RawAddress* bd_addr) {
+  if (!bd_addr) {
+    LOG(WARNING) << __func__ << ": bd_addr is null";
+    return false;
   }
-  return latest_conn_idx;
-}
-
-/*******************************************************************************
- *
- * Function         btif_hf_check_if_slc_connected
- *
- * Description      Returns BT_STATUS_SUCCESS if SLC is up for any HF
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t btif_hf_check_if_slc_connected() {
-  if (bt_hf_callbacks == NULL) {
-    BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__);
-    return BT_STATUS_NOT_READY;
-  } else {
-    int i;
-    for (i = 0; i < btif_max_hf_clients; i++) {
-      if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
-        BTIF_TRACE_EVENT("BTHF: %s: slc connected for idx = %d", __func__, i);
-        return BT_STATUS_SUCCESS;
-      }
-    }
-    BTIF_TRACE_WARNING("BTHF: %s: No SLC connection up", __func__);
-    return BT_STATUS_NOT_READY;
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if (idx < 0 || idx > BTA_AG_MAX_NUM_CLIENTS) {
+    LOG(WARNING) << __func__ << ": invalid index " << idx << " for "
+                 << *bd_addr;
+    return false;
   }
+  return btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_SLC_CONNECTED;
 }
 
-/*****************************************************************************
- *   Section name (Group of functions)
- ****************************************************************************/
-
-/*****************************************************************************
- *
- *   btif hf api functions (no context switch)
- *
- ****************************************************************************/
-
 /*******************************************************************************
  *
  * Function         btif_hf_upstreams_evt
@@ -334,155 +296,159 @@
  *
  ******************************************************************************/
 static void btif_hf_upstreams_evt(uint16_t event, char* p_param) {
+  if (event == BTA_AG_ENABLE_EVT || event == BTA_AG_DISABLE_EVT) {
+    LOG(INFO) << __func__ << ": AG enable/disable event " << event;
+    return;
+  }
+  if (p_param == nullptr) {
+    LOG(ERROR) << __func__ << ": parameter is null";
+    return;
+  }
   tBTA_AG* p_data = (tBTA_AG*)p_param;
   int idx = p_data->hdr.handle - 1;
 
   BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_hf_event(event));
 
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return;
   }
+  if (!bt_hf_callbacks) {
+    BTIF_TRACE_ERROR("%s: Headset callback is NULL", __func__);
+    return;
+  }
 
   switch (event) {
-    case BTA_AG_ENABLE_EVT:
-    case BTA_AG_DISABLE_EVT:
-      break;
-
     case BTA_AG_REGISTER_EVT:
       btif_hf_cb[idx].handle = p_data->reg.hdr.handle;
-      BTIF_TRACE_DEBUG(
-          "%s: BTA_AG_REGISTER_EVT,"
-          "btif_hf_cb.handle = %d",
-          __func__, btif_hf_cb[idx].handle);
+      BTIF_TRACE_DEBUG("%s: BTA_AG_REGISTER_EVT, btif_hf_cb.handle = %d",
+                       __func__, btif_hf_cb[idx].handle);
       break;
-
+    // RFCOMM connected or failed to connect
     case BTA_AG_OPEN_EVT:
+      // Check if an outoging connection is pending
+      if (btif_hf_cb[idx].is_initiator) {
+        CHECK_EQ(btif_hf_cb[idx].state, BTHF_CONNECTION_STATE_CONNECTING)
+            << "Control block must be in connecting state when initiating";
+        CHECK(!btif_hf_cb[idx].connected_bda.IsEmpty())
+            << "Remote device address must not be empty when initiating";
+        CHECK_EQ(btif_hf_cb[idx].connected_bda, p_data->open.bd_addr)
+            << "Incoming message's address must match expected one";
+      }
       if (p_data->open.status == BTA_AG_SUCCESS) {
+        // In case this is an incoming connection
         btif_hf_cb[idx].connected_bda = p_data->open.bd_addr;
         btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_CONNECTED;
         btif_hf_cb[idx].peer_feat = 0;
-        clear_phone_state_multihf(idx);
-      } else if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_CONNECTING) {
-        btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+        clear_phone_state_multihf(&btif_hf_cb[idx]);
+        system_bt_osi::BluetoothMetricsLogger::GetInstance()
+            ->LogHeadsetProfileRfcConnection(p_data->open.service_id);
+        bt_hf_callbacks->ConnectionStateCallback(
+            btif_hf_cb[idx].state, &btif_hf_cb[idx].connected_bda);
       } 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());
-        break;
+        if (!btif_hf_cb[idx].is_initiator) {
+          // Ignore remote initiated open failures
+          LOG(WARNING) << __func__ << ": Unexpected AG open failure "
+                       << std::to_string(p_data->open.status) << " for "
+                       << p_data->open.bd_addr << " is ignored";
+          break;
+        }
+        LOG(ERROR) << __func__ << ": self initiated AG open failed for "
+                   << btif_hf_cb[idx].connected_bda << ", status "
+                   << std::to_string(p_data->open.status);
+        RawAddress connected_bda = btif_hf_cb[idx].connected_bda;
+        reset_control_block(&btif_hf_cb[idx]);
+        bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state,
+                                                 &connected_bda);
+        btif_queue_advance();
       }
-
-      HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
-                &btif_hf_cb[idx].connected_bda);
-
-      if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_DISCONNECTED)
-        btif_hf_cb[idx].connected_bda = RawAddress::kAny;
-
-      if (p_data->open.status != BTA_AG_SUCCESS) btif_queue_advance();
       break;
-
-    case BTA_AG_CLOSE_EVT:
-      btif_hf_cb[idx].connected_timestamp.tv_sec = 0;
-      btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
-      BTIF_TRACE_DEBUG(
-          "%s: BTA_AG_CLOSE_EVT,"
-          "idx = %d, btif_hf_cb.handle = %d",
-          __func__, idx, btif_hf_cb[idx].handle);
-      HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
-                &btif_hf_cb[idx].connected_bda);
-      btif_hf_cb[idx].connected_bda = RawAddress::kAny;
-      btif_hf_cb[idx].peer_feat = 0;
-      clear_phone_state_multihf(idx);
-      hf_idx = btif_hf_latest_connected_idx();
-      /* If AG_OPEN was received but SLC was not setup in a specified time (10
-       *seconds),
-       ** then AG_CLOSE may be received. We need to advance the queue here
-       */
-      btif_queue_advance();
+    // SLC and RFCOMM both disconnected
+    case BTA_AG_CLOSE_EVT: {
+      BTIF_TRACE_DEBUG("%s: BTA_AG_CLOSE_EVT, idx = %d, btif_hf_cb.handle = %d",
+                       __func__, idx, btif_hf_cb[idx].handle);
+      // If AG_OPEN was received but SLC was not connected in time, then
+      // AG_CLOSE may be received. We need to advance the queue here.
+      bool failed_to_setup_slc =
+          (btif_hf_cb[idx].state != BTHF_CONNECTION_STATE_SLC_CONNECTED) &&
+          btif_hf_cb[idx].is_initiator;
+      RawAddress connected_bda = btif_hf_cb[idx].connected_bda;
+      reset_control_block(&btif_hf_cb[idx]);
+      bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state,
+                                               &connected_bda);
+      if (failed_to_setup_slc) {
+        LOG(ERROR) << __func__ << ": failed to setup SLC for " << connected_bda;
+        btif_queue_advance();
+      }
       break;
-
+    }
+    // SLC connected
     case BTA_AG_CONN_EVT:
-      clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[idx].connected_timestamp);
       BTIF_TRACE_DEBUG("%s: BTA_AG_CONN_EVT, idx = %d ", __func__, idx);
       btif_hf_cb[idx].peer_feat = p_data->conn.peer_feat;
       btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
-      hf_idx = btif_hf_latest_connected_idx();
-
-      HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
-                &btif_hf_cb[idx].connected_bda);
-      btif_queue_advance();
+      bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state,
+                                               &btif_hf_cb[idx].connected_bda);
+      if (btif_hf_cb[idx].is_initiator) {
+        btif_queue_advance();
+      }
       break;
 
     case BTA_AG_AUDIO_OPEN_EVT:
-      hf_idx = idx;
-      HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AudioStateCallback(BTHF_AUDIO_STATE_CONNECTED,
+                                          &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AUDIO_CLOSE_EVT:
-      HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AudioStateCallback(BTHF_AUDIO_STATE_DISCONNECTED,
+                                          &btif_hf_cb[idx].connected_bda);
       break;
 
     /* BTA auto-responds, silently discard */
     case BTA_AG_SPK_EVT:
     case BTA_AG_MIC_EVT:
-      HAL_CBACK(bt_hf_callbacks, volume_cmd_cb,
-                (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK
-                                          : BTHF_VOLUME_TYPE_MIC,
-                p_data->val.num, &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->VolumeControlCallback(
+          (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK
+                                    : BTHF_VOLUME_TYPE_MIC,
+          p_data->val.num, &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_A_EVT:
-      if ((btif_hf_cb[0].num_held + btif_hf_cb[0].num_active) == 0)
-        hf_idx = idx;
-      else
-        BTIF_TRACE_DEBUG("Donot set hf_idx for ATA since already in a call");
-
-      HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AnswerCallCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     /* Java needs to send OK/ERROR for these commands */
     case BTA_AG_AT_BLDN_EVT:
     case BTA_AG_AT_D_EVT:
-      if ((btif_hf_cb[0].num_held + btif_hf_cb[0].num_active) == 0)
-        hf_idx = idx;
-      else
-        BTIF_TRACE_DEBUG("Donot set hf_idx for BLDN/D since already in a call");
-
-      HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
-                (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->DialCallCallback(
+          (event == BTA_AG_AT_D_EVT) ? p_data->val.str : nullptr,
+          &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_CHUP_EVT:
-      HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->HangupCallCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_CIND_EVT:
-      HAL_CBACK(bt_hf_callbacks, cind_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AtCindCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_VTS_EVT:
-      HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0],
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->DtmfCmdCallback(p_data->val.str[0],
+                                       &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_BVRA_EVT:
-      HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
-                (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED
-                                       : BTHF_VR_STATE_STOPPED,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->VoiceRecognitionCallback((p_data->val.num == 1)
+                                                    ? BTHF_VR_STATE_STARTED
+                                                    : BTHF_VR_STATE_STOPPED,
+                                                &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_NREC_EVT:
-      HAL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
-                (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->NoiseReductionCallback(
+          (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP,
+          &btif_hf_cb[idx].connected_bda);
       break;
 
     /* TODO: Add a callback for CBC */
@@ -490,8 +456,7 @@
       break;
 
     case BTA_AG_AT_CKPD_EVT:
-      HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->KeyPressedCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_WBS_EVT:
@@ -499,39 +464,38 @@
           "BTA_AG_WBS_EVT Set codec status %d codec %d 1=CVSD 2=MSBC",
           p_data->val.hdr.status, p_data->val.num);
       if (p_data->val.num == BTA_AG_CODEC_CVSD) {
-        HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_NO,
-                  &btif_hf_cb[idx].connected_bda);
+        bt_hf_callbacks->WbsCallback(BTHF_WBS_NO,
+                                     &btif_hf_cb[idx].connected_bda);
       } else if (p_data->val.num == BTA_AG_CODEC_MSBC) {
-        HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_YES,
-                  &btif_hf_cb[idx].connected_bda);
+        bt_hf_callbacks->WbsCallback(BTHF_WBS_YES,
+                                     &btif_hf_cb[idx].connected_bda);
       } else {
-        HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_NONE,
-                  &btif_hf_cb[idx].connected_bda);
+        bt_hf_callbacks->WbsCallback(BTHF_WBS_NONE,
+                                     &btif_hf_cb[idx].connected_bda);
       }
       break;
 
     /* Java needs to send OK/ERROR for these commands */
     case BTA_AG_AT_CHLD_EVT:
-      HAL_CBACK(bt_hf_callbacks, chld_cmd_cb,
-                (bthf_chld_type_t)atoi(p_data->val.str),
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AtChldCallback((bthf_chld_type_t)atoi(p_data->val.str),
+                                      &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_CLCC_EVT:
-      HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AtClccCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_COPS_EVT:
-      HAL_CBACK(bt_hf_callbacks, cops_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AtCopsCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_UNAT_EVT:
-      HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb, p_data->val.str,
-                &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->UnknownAtCallback(p_data->val.str,
+                                         &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_CNUM_EVT:
-      HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      bt_hf_callbacks->AtCnumCallback(&btif_hf_cb[idx].connected_bda);
       break;
 
     /* TODO: Some of these commands may need to be sent to app. For now respond
@@ -547,8 +511,7 @@
       we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC
       at the time
       of SCO connection establishment */
-      if ((btif_conf_hf_force_wbs == true) &&
-          (p_data->val.num & BTA_AG_CODEC_MSBC)) {
+      if ((btif_conf_hf_force_wbs) && (p_data->val.num & BTA_AG_CODEC_MSBC)) {
         BTIF_TRACE_EVENT("%s: btif_hf override-Preferred Codec to MSBC",
                          __func__);
         BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
@@ -563,28 +526,38 @@
                        __func__, p_data->val.num);
       /* No BTHF_WBS_NONE case, because HF1.6 supported device can send BCS */
       /* Only CVSD is considered narrow band speech */
-      HAL_CBACK(
-          bt_hf_callbacks, wbs_cb,
+      bt_hf_callbacks->WbsCallback(
           (p_data->val.num == BTA_AG_CODEC_CVSD) ? BTHF_WBS_NO : BTHF_WBS_YES,
           &btif_hf_cb[idx].connected_bda);
       break;
 
     case BTA_AG_AT_BIND_EVT:
       if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
-        HAL_CBACK(bt_hf_callbacks, bind_cb, p_data->val.str,
-                  &btif_hf_cb[idx].connected_bda);
+        bt_hf_callbacks->AtBindCallback(p_data->val.str,
+                                        &btif_hf_cb[idx].connected_bda);
       }
       break;
 
     case BTA_AG_AT_BIEV_EVT:
       if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
-        HAL_CBACK(bt_hf_callbacks, biev_cb,
-                  (bthf_hf_ind_type_t)p_data->val.lidx, (int)p_data->val.num,
-                  &btif_hf_cb[idx].connected_bda);
+        bt_hf_callbacks->AtBievCallback((bthf_hf_ind_type_t)p_data->val.lidx,
+                                        (int)p_data->val.num,
+                                        &btif_hf_cb[idx].connected_bda);
+      }
+      break;
+    case BTA_AG_AT_BIA_EVT:
+      if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
+        uint32_t bia_mask_out = p_data->val.num;
+        bool service = !is_nth_bit_enabled(bia_mask_out, BTA_AG_IND_SERVICE);
+        bool roam = !is_nth_bit_enabled(bia_mask_out, BTA_AG_IND_ROAM);
+        bool signal = !is_nth_bit_enabled(bia_mask_out, BTA_AG_IND_SIGNAL);
+        bool battery = !is_nth_bit_enabled(bia_mask_out, BTA_AG_IND_BATTCHG);
+        bt_hf_callbacks->AtBiaCallback(service, roam, signal, battery,
+                                       &btif_hf_cb[idx].connected_bda);
       }
       break;
     default:
-      BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+      LOG(WARNING) << __func__ << ": unhandled event " << event;
       break;
   }
 }
@@ -620,7 +593,7 @@
   /* switch context to btif task context (copy full union size for convenience)
    */
   status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event,
-                                 (char*)p_data, param_len, NULL);
+                                 (char*)p_data, param_len, nullptr);
 
   /* catch any failed context transfers */
   ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
@@ -628,91 +601,6 @@
 
 /*******************************************************************************
  *
- * Function         btif_in_hf_generic_evt
- *
- * Description     Processes generic events to be sent to JNI that are not
- *                      triggered from the BTA.
- *                      Always runs in BTIF context
- *
- * Returns          void
- *
- ******************************************************************************/
-static void btif_in_hf_generic_evt(uint16_t event, char* p_param) {
-  int idx = btif_hf_idx_by_bdaddr((RawAddress*)p_param);
-
-  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
-    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
-    return;
-  }
-
-  switch (event) {
-    case BTIF_HFP_CB_AUDIO_CONNECTING: {
-      HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
-                &btif_hf_cb[idx].connected_bda);
-    } break;
-    default: {
-      BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
-    } break;
-  }
-}
-
-static bool inband_ringing_property_enabled() {
-  char inband_ringing_flag[PROPERTY_VALUE_MAX] = {0};
-  osi_property_get("persist.bluetooth.enableinbandringing", inband_ringing_flag,
-                   "true");
-  if (strncmp(inband_ringing_flag, "true", 4) == 0) {
-    BTIF_TRACE_DEBUG("%s: In-band ringing enabled by property", __func__);
-    return true;
-  }
-  return false;
-}
-
-/*******************************************************************************
- *
- * Function         btif_hf_init
- *
- * Description     initializes the hf interface
- *
- * Returns         bt_status_t
- *
- ******************************************************************************/
-static bt_status_t init(bthf_callbacks_t* callbacks, int max_hf_clients,
-                        bool inband_ringing_supported) {
-  bool inband_ringing_property_enable = inband_ringing_property_enabled();
-  if (inband_ringing_supported && inband_ringing_property_enable) {
-    btif_hf_features |= BTA_AG_FEAT_INBAND;
-  } else {
-    btif_hf_features &= ~BTA_AG_FEAT_INBAND;
-  }
-  btif_max_hf_clients = max_hf_clients;
-  BTIF_TRACE_DEBUG(
-      "%s: btif_hf_features=%zu, max_hf_clients=%d, "
-      "inband_ringing=[supported=%d, enabled=%d]",
-      __func__, btif_hf_features, btif_max_hf_clients, inband_ringing_supported,
-      inband_ringing_property_enable);
-  bt_hf_callbacks = callbacks;
-  memset(&btif_hf_cb, 0, sizeof(btif_hf_cb));
-
-/* Invoke the enable service API to the core to set the appropriate service_id
- * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled
- * (phone)
- * othwerwise only HSP is enabled (tablet)
- */
-#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
-  btif_enable_service(BTA_HFP_SERVICE_ID);
-#else
-  btif_enable_service(BTA_HSP_SERVICE_ID);
-#endif
-
-  for (int i = 0; i < btif_max_hf_clients; i++) clear_phone_state_multihf(i);
-
-  return BT_STATUS_SUCCESS;
-}
-
-/*******************************************************************************
- *
  * Function         connect
  *
  * Description     connect to headset
@@ -722,559 +610,500 @@
  ******************************************************************************/
 static bt_status_t connect_int(RawAddress* bd_addr, uint16_t uuid) {
   CHECK_BTHF_INIT();
-  int i;
-  for (i = 0; i < btif_max_hf_clients;) {
-    if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
-         (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)))
-      i++;
-    else
+  if (is_connected(bd_addr)) {
+    BTIF_TRACE_WARNING("%s: device %s is already connected", __func__,
+                       bd_addr->ToString().c_str());
+    return BT_STATUS_BUSY;
+  }
+  btif_hf_cb_t* hf_cb = nullptr;
+  for (int i = 0; i < btif_max_hf_clients; i++) {
+    if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_DISCONNECTED) {
+      hf_cb = &btif_hf_cb[i];
       break;
+    }
+    // Due to btif queue implementation, when connect_int is called, no btif
+    // control block should be in connecting state
+    // Crash here to prevent future code changes from breaking this mechanism
+    if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTING) {
+      LOG(FATAL) << __func__ << ": " << btif_hf_cb[i].connected_bda
+                 << ", handle " << btif_hf_cb[i].handle
+                 << ", is still in connecting state " << btif_hf_cb[i].state;
+    }
   }
-
-  if (i == btif_max_hf_clients) return BT_STATUS_BUSY;
-
-  if (!is_connected(bd_addr)) {
-    btif_hf_cb[i].state = BTHF_CONNECTION_STATE_CONNECTING;
-    btif_hf_cb[i].connected_bda = *bd_addr;
-
-    BTA_AgOpen(btif_hf_cb[i].handle, btif_hf_cb[i].connected_bda,
-               BTIF_HF_SECURITY, BTIF_HF_SERVICES);
-    return BT_STATUS_SUCCESS;
+  if (hf_cb == nullptr) {
+    BTIF_TRACE_WARNING(
+        "%s: Cannot connect %s: maximum %d clients already connected", __func__,
+        bd_addr->ToString().c_str(), btif_max_hf_clients);
+    return BT_STATUS_BUSY;
   }
-
-  return BT_STATUS_BUSY;
+  hf_cb->state = BTHF_CONNECTION_STATE_CONNECTING;
+  hf_cb->connected_bda = *bd_addr;
+  hf_cb->is_initiator = true;
+  hf_cb->peer_feat = 0;
+  BTA_AgOpen(hf_cb->handle, hf_cb->connected_bda, BTIF_HF_SECURITY);
+  return BT_STATUS_SUCCESS;
 }
 
-static bt_status_t connect(RawAddress* bd_addr) {
+static void UpdateCallStates(btif_hf_cb_t* control_block, int num_active,
+                             int num_held, bthf_call_state_t call_setup_state) {
+  control_block->num_active = num_active;
+  control_block->num_held = num_held;
+  control_block->call_setup_state = call_setup_state;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_is_call_idle
+ *
+ * Description      returns true if no call is in progress
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bool IsCallIdle() {
+  if (!bt_hf_callbacks) return true;
+
+  for (int i = 0; i < btif_max_hf_clients; ++i) {
+    if ((btif_hf_cb[i].call_setup_state != BTHF_CALL_STATE_IDLE) ||
+        ((btif_hf_cb[i].num_held + btif_hf_cb[i].num_active) > 0))
+      return false;
+  }
+
+  return true;
+}
+
+class HeadsetInterface : Interface {
+ public:
+  static Interface* GetInstance() {
+    static Interface* instance = new HeadsetInterface();
+    return instance;
+  }
+  bt_status_t Init(Callbacks* callbacks, int max_hf_clients,
+                   bool inband_ringing_enabled) override;
+  bt_status_t Connect(RawAddress* bd_addr) override;
+  bt_status_t Disconnect(RawAddress* bd_addr) override;
+  bt_status_t ConnectAudio(RawAddress* bd_addr) override;
+  bt_status_t DisconnectAudio(RawAddress* bd_addr) override;
+  bt_status_t StartVoiceRecognition(RawAddress* bd_addr) override;
+  bt_status_t StopVoiceRecognition(RawAddress* bd_addr) override;
+  bt_status_t VolumeControl(bthf_volume_type_t type, int volume,
+                            RawAddress* bd_addr) override;
+  bt_status_t DeviceStatusNotification(bthf_network_state_t ntk_state,
+                                       bthf_service_type_t svc_type, int signal,
+                                       int batt_chg,
+                                       RawAddress* bd_addr) override;
+  bt_status_t CopsResponse(const char* cops, RawAddress* bd_addr) override;
+  bt_status_t CindResponse(int svc, int num_active, int num_held,
+                           bthf_call_state_t call_setup_state, int signal,
+                           int roam, int batt_chg,
+                           RawAddress* bd_addr) override;
+  bt_status_t FormattedAtResponse(const char* rsp,
+                                  RawAddress* bd_addr) override;
+  bt_status_t AtResponse(bthf_at_response_t response_code, int error_code,
+                         RawAddress* bd_addr) override;
+  bt_status_t ClccResponse(int index, bthf_call_direction_t dir,
+                           bthf_call_state_t state, bthf_call_mode_t mode,
+                           bthf_call_mpty_type_t mpty, const char* number,
+                           bthf_call_addrtype_t type,
+                           RawAddress* bd_addr) override;
+  bt_status_t PhoneStateChange(int num_active, int num_held,
+                               bthf_call_state_t call_setup_state,
+                               const char* number, bthf_call_addrtype_t type,
+                               RawAddress* bd_addr) override;
+
+  void Cleanup() override;
+  bt_status_t SetScoAllowed(bool value) override;
+  bt_status_t SendBsir(bool value, RawAddress* bd_addr) override;
+  bt_status_t SetActiveDevice(RawAddress* active_device_addr) override;
+};
+
+bt_status_t HeadsetInterface::Init(Callbacks* callbacks, int max_hf_clients,
+                                   bool inband_ringing_enabled) {
+  if (inband_ringing_enabled) {
+    btif_hf_features |= BTA_AG_FEAT_INBAND;
+  } else {
+    btif_hf_features &= ~BTA_AG_FEAT_INBAND;
+  }
+  CHECK_LE(max_hf_clients, BTA_AG_MAX_NUM_CLIENTS)
+      << __func__
+      << "Too many HF clients,"
+         " maximum is "
+      << BTA_AG_MAX_NUM_CLIENTS << " was given " << max_hf_clients;
+  btif_max_hf_clients = max_hf_clients;
+  BTIF_TRACE_DEBUG(
+      "%s: btif_hf_features=%zu, max_hf_clients=%d, inband_ringing_enabled=%d",
+      __func__, btif_hf_features, btif_max_hf_clients, inband_ringing_enabled);
+  bt_hf_callbacks = callbacks;
+  for (btif_hf_cb_t& hf_cb : btif_hf_cb) {
+    reset_control_block(&hf_cb);
+  }
+
+// Invoke the enable service API to the core to set the appropriate service_id
+// Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled
+// (phone) otherwise only HSP is enabled (tablet)
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+  btif_enable_service(BTA_HFP_SERVICE_ID);
+#else
+  btif_enable_service(BTA_HSP_SERVICE_ID);
+#endif
+
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t HeadsetInterface::Connect(RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
   return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
 }
 
-/*******************************************************************************
- *
- * Function         disconnect
- *
- * Description      disconnect from headset
- *
- * Returns         bt_status_t
- *
- ******************************************************************************/
-static bt_status_t disconnect(RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::Disconnect(RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    BTA_AgClose(btif_hf_cb[idx].handle);
-    return BT_STATUS_SUCCESS;
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
   }
-
-  return BT_STATUS_FAIL;
+  BTA_AgClose(btif_hf_cb[idx].handle);
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         connect_audio
- *
- * Description     create an audio connection
- *
- * Returns         bt_status_t
- *
- ******************************************************************************/
-static bt_status_t connect_audio(RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::ConnectAudio(RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
-
   /* Check if SLC is connected */
-  if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+  if (!IsSlcConnected(bd_addr)) {
+    LOG(ERROR) << ": SLC not connected for " << *bd_addr;
     return BT_STATUS_NOT_READY;
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    BTA_AgAudioOpen(btif_hf_cb[idx].handle);
-
-    /* Inform the application that the audio connection has been initiated
-     * successfully */
-    btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
-                          (char*)bd_addr, sizeof(RawAddress), NULL);
-    return BT_STATUS_SUCCESS;
   }
-
-  return BT_STATUS_FAIL;
+  BTA_AgAudioOpen(btif_hf_cb[idx].handle);
+  // Inform the application that the audio connection has been initiated
+  // successfully
+  do_in_jni_thread(base::Bind(&Callbacks::AudioStateCallback,
+                              // Manual pointer management for now
+                              base::Unretained(bt_hf_callbacks),
+                              BTHF_AUDIO_STATE_CONNECTING,
+                              &btif_hf_cb[idx].connected_bda));
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         disconnect_audio
- *
- * Description      close the audio connection
- *
- * Returns         bt_status_t
- *
- ******************************************************************************/
-static bt_status_t disconnect_audio(RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::DisconnectAudio(RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    BTA_AgAudioClose(btif_hf_cb[idx].handle);
-    return BT_STATUS_SUCCESS;
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
   }
-
-  return BT_STATUS_FAIL;
+  BTA_AgAudioClose(btif_hf_cb[idx].handle);
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         start_voice_recognition
- *
- * Description      start voice recognition
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t start_voice_recognition(RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::StartVoiceRecognition(RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC) {
-      tBTA_AG_RES_DATA ag_res;
-      memset(&ag_res, 0, sizeof(ag_res));
-      ag_res.state = 1;
-      BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
-
-      return BT_STATUS_SUCCESS;
-    } else {
-      return BT_STATUS_UNSUPPORTED;
-    }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_NOT_READY;
   }
-
-  return BT_STATUS_NOT_READY;
+  if (!(btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)) {
+    BTIF_TRACE_ERROR("%s: voice recognition not supported, features=0x%x",
+                     __func__, btif_hf_cb[idx].peer_feat);
+    return BT_STATUS_UNSUPPORTED;
+  }
+  tBTA_AG_RES_DATA ag_res = {};
+  ag_res.state = true;
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, ag_res);
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         stop_voice_recognition
- *
- * Description      stop voice recognition
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t stop_voice_recognition(RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::StopVoiceRecognition(RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
 
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC) {
-      tBTA_AG_RES_DATA ag_res;
-      memset(&ag_res, 0, sizeof(ag_res));
-      ag_res.state = 0;
-      BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
-
-      return BT_STATUS_SUCCESS;
-    } else {
-      return BT_STATUS_UNSUPPORTED;
-    }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_NOT_READY;
   }
-
-  return BT_STATUS_NOT_READY;
+  if (!(btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)) {
+    BTIF_TRACE_ERROR("%s: voice recognition not supported, features=0x%x",
+                     __func__, btif_hf_cb[idx].peer_feat);
+    return BT_STATUS_UNSUPPORTED;
+  }
+  tBTA_AG_RES_DATA ag_res = {};
+  ag_res.state = false;
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, ag_res);
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         volume_control
- *
- * Description      volume control
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t volume_control(bthf_volume_type_t type, int volume,
-                                  RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::VolumeControl(bthf_volume_type_t type, int volume,
+                                            RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
-
-  tBTA_AG_RES_DATA ag_res;
-  memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    ag_res.num = volume;
-    BTA_AgResult(
-        btif_hf_cb[idx].handle,
-        (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
-        &ag_res);
-    return BT_STATUS_SUCCESS;
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
   }
-
-  return BT_STATUS_FAIL;
+  tBTA_AG_RES_DATA ag_res = {};
+  ag_res.num = static_cast<uint16_t>(volume);
+  BTA_AgResult(btif_hf_cb[idx].handle,
+               (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
+               ag_res);
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         device_status_notification
- *
- * Description      Combined device status change notification
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
-                                              bthf_service_type_t svc_type,
-                                              int signal, int batt_chg) {
+bt_status_t HeadsetInterface::DeviceStatusNotification(
+    bthf_network_state_t ntk_state, bthf_service_type_t svc_type, int signal,
+    int batt_chg, RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
-  if (is_connected(NULL)) {
-    /* send all indicators to BTA.
-    ** BTA will make sure no duplicates are sent out
-    */
-    send_indicator_update(BTA_AG_IND_SERVICE,
+  if (!bd_addr) {
+    BTIF_TRACE_WARNING("%s: bd_addr is null", __func__);
+    return BT_STATUS_FAIL;
+  }
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if (idx < 0 || idx > BTA_AG_MAX_NUM_CLIENTS) {
+    BTIF_TRACE_WARNING("%s: invalid index %d for %s", __func__, idx,
+                       bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  const btif_hf_cb_t& control_block = btif_hf_cb[idx];
+  // ok if no device is connected
+  if (is_connected(nullptr)) {
+    // send all indicators to BTA.
+    // BTA will make sure no duplicates are sent out
+    send_indicator_update(control_block, BTA_AG_IND_SERVICE,
                           (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
-    send_indicator_update(BTA_AG_IND_ROAM,
+    send_indicator_update(control_block, BTA_AG_IND_ROAM,
                           (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
-    send_indicator_update(BTA_AG_IND_SIGNAL, signal);
-    send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
-    return BT_STATUS_SUCCESS;
+    send_indicator_update(control_block, BTA_AG_IND_SIGNAL, signal);
+    send_indicator_update(control_block, BTA_AG_IND_BATTCHG, batt_chg);
   }
-
   return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         cops_response
- *
- * Description      Response for COPS command
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t cops_response(const char* cops, RawAddress* bd_addr) {
+bt_status_t HeadsetInterface::CopsResponse(const char* cops,
+                                           RawAddress* bd_addr) {
   CHECK_BTHF_INIT();
-
   int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
     BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
     return BT_STATUS_FAIL;
   }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  tBTA_AG_RES_DATA ag_res = {};
+  /* Format the response */
+  snprintf(ag_res.str, sizeof(ag_res.str), "0,0,\"%.16s\"", cops);
+  ag_res.ok_flag = BTA_AG_OK_DONE;
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_COPS_RES, ag_res);
+  return BT_STATUS_SUCCESS;
+}
 
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    tBTA_AG_RES_DATA ag_res;
+bt_status_t HeadsetInterface::CindResponse(int svc, int num_active,
+                                           int num_held,
+                                           bthf_call_state_t call_setup_state,
+                                           int signal, int roam, int batt_chg,
+                                           RawAddress* bd_addr) {
+  CHECK_BTHF_INIT();
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  tBTA_AG_RES_DATA ag_res = {};
+  // per the errata 2043, call=1 implies atleast one call is in progress
+  // (active/held), see:
+  // https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+  snprintf(ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d,%d,%d",
+           (num_active + num_held) ? 1 : 0,          /* Call state */
+           callstate_to_callsetup(call_setup_state), /* Callsetup state */
+           svc,                                      /* network service */
+           signal,                                   /* Signal strength */
+           roam,                                     /* Roaming indicator */
+           batt_chg,                                 /* Battery level */
+           ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CIND_RES, ag_res);
+  return BT_STATUS_SUCCESS;
+}
 
-    /* Format the response */
-    snprintf(ag_res.str, sizeof(ag_res.str), "0,0,\"%.16s\"", cops);
+bt_status_t HeadsetInterface::FormattedAtResponse(const char* rsp,
+                                                  RawAddress* bd_addr) {
+  CHECK_BTHF_INIT();
+  tBTA_AG_RES_DATA ag_res = {};
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  /* Format the response and send */
+  strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, ag_res);
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t HeadsetInterface::AtResponse(bthf_at_response_t response_code,
+                                         int error_code, RawAddress* bd_addr) {
+  CHECK_BTHF_INIT();
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  send_at_result(
+      (response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE : BTA_AG_OK_ERROR,
+      static_cast<uint16_t>(error_code), idx);
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t HeadsetInterface::ClccResponse(
+    int index, bthf_call_direction_t dir, bthf_call_state_t state,
+    bthf_call_mode_t mode, bthf_call_mpty_type_t mpty, const char* number,
+    bthf_call_addrtype_t type, RawAddress* bd_addr) {
+  CHECK_BTHF_INIT();
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s is not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  tBTA_AG_RES_DATA ag_res = {};
+  /* Format the response */
+  if (index == 0) {
     ag_res.ok_flag = BTA_AG_OK_DONE;
-
-    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_COPS_RES, &ag_res);
-    return BT_STATUS_SUCCESS;
-  }
-  return BT_STATUS_FAIL;
-}
-
-/*******************************************************************************
- *
- * Function         cind_response
- *
- * Description      Response for CIND command
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t cind_response(int svc, int num_active, int num_held,
-                                 bthf_call_state_t call_setup_state, int signal,
-                                 int roam, int batt_chg, RawAddress* bd_addr) {
-  CHECK_BTHF_INIT();
-
-  int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
-    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
-    return BT_STATUS_FAIL;
-  }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    tBTA_AG_RES_DATA ag_res;
-
-    memset(&ag_res, 0, sizeof(ag_res));
-    /* per the errata 2043, call=1 implies atleast one call is in progress
-     *(active/held)
-     ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
-     **/
-    snprintf(
-        ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d,%d,%d",
-        (num_active + num_held) ? 1 : 0,          /* Call state */
-        callstate_to_callsetup(call_setup_state), /* Callsetup state */
-        svc,                                      /* network service */
-        signal,                                   /* Signal strength */
-        roam,                                     /* Roaming indicator */
-        batt_chg,                                 /* Battery level */
-        ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
-
-    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CIND_RES, &ag_res);
-
-    return BT_STATUS_SUCCESS;
-  }
-
-  return BT_STATUS_FAIL;
-}
-
-/*******************************************************************************
- *
- * Function         bind_response
- *
- * Description      Send +BIND response
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t bind_response(bthf_hf_ind_type_t ind_id,
-                                 bthf_hf_ind_status_t ind_status,
-                                 RawAddress* bd_addr) {
-  CHECK_BTHF_INIT();
-
-  int index = btif_hf_idx_by_bdaddr(bd_addr);
-  if (!is_connected(bd_addr) || index == BTIF_HF_INVALID_IDX)
-    return BT_STATUS_FAIL;
-
-  tBTA_AG_RES_DATA ag_res;
-  memset(&ag_res, 0, sizeof(ag_res));
-  ag_res.ind.id = ind_id;
-  ag_res.ind.on_demand = (ind_status == BTHF_HF_IND_ENABLED);
-
-  BTA_AgResult(btif_hf_cb[index].handle, BTA_AG_BIND_RES, &ag_res);
-  return BT_STATUS_SUCCESS;
-}
-
-static bt_status_t set_sco_allowed(bool value) {
-  CHECK_BTHF_INIT();
-
-  BTA_AgSetScoAllowed(value);
-  return BT_STATUS_SUCCESS;
-}
-
-/*******************************************************************************
- *
- * Function         formatted_at_response
- *
- * Description      Pre-formatted AT response, typically in response to unknown
- *                  AT cmd
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t formatted_at_response(const char* rsp, RawAddress* bd_addr) {
-  CHECK_BTHF_INIT();
-  tBTA_AG_RES_DATA ag_res;
-  int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
-    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
-    return BT_STATUS_FAIL;
-  }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    /* Format the response and send */
-    memset(&ag_res, 0, sizeof(ag_res));
-    strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
-    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
-
-    return BT_STATUS_SUCCESS;
-  }
-
-  return BT_STATUS_FAIL;
-}
-
-/*******************************************************************************
- *
- * Function         at_response
- *
- * Description      ok/error response
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t at_response(bthf_at_response_t response_code, int error_code,
-                               RawAddress* bd_addr) {
-  CHECK_BTHF_INIT();
-
-  int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
-    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
-    return BT_STATUS_FAIL;
-  }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
-                                                          : BTA_AG_OK_ERROR,
-                   error_code, idx);
-    return BT_STATUS_SUCCESS;
-  }
-
-  return BT_STATUS_FAIL;
-}
-
-/*******************************************************************************
- *
- * Function         clcc_response
- *
- * Description      response for CLCC command
- *                  Can be iteratively called for each call index. Call index
- *                  of 0 will be treated as NULL termination (Completes
- *                  response)
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
-                                 bthf_call_state_t state, bthf_call_mode_t mode,
-                                 bthf_call_mpty_type_t mpty, const char* number,
-                                 bthf_call_addrtype_t type,
-                                 RawAddress* bd_addr) {
-  CHECK_BTHF_INIT();
-
-  int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
-    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
-    return BT_STATUS_FAIL;
-  }
-
-  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
-    tBTA_AG_RES_DATA ag_res;
-    memset(&ag_res, 0, sizeof(ag_res));
-
-    /* Format the response */
-    if (index == 0) {
-      ag_res.ok_flag = BTA_AG_OK_DONE;
-    } else {
-      BTIF_TRACE_EVENT(
-          "clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
-          index, dir, state, mode, number, type);
-      int res_strlen =
-          snprintf(ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d", index, dir,
-                   state, mode, mpty);
-
-      if (number) {
-        size_t rem_bytes = sizeof(ag_res.str) - res_strlen;
-        char dialnum[sizeof(ag_res.str)];
-        size_t newidx = 0;
-        if (type == BTHF_CALL_ADDRTYPE_INTERNATIONAL && *number != '+') {
-          dialnum[newidx++] = '+';
-        }
-        for (size_t i = 0; number[i] != 0; i++) {
-          if (utl_isdialchar(number[i])) {
-            dialnum[newidx++] = number[i];
-          }
-        }
-        dialnum[newidx] = 0;
-        snprintf(&ag_res.str[res_strlen], rem_bytes, ",\"%s\",%d", dialnum,
-                 type);
+  } else {
+    BTIF_TRACE_EVENT(
+        "clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
+        index, dir, state, mode, number, type);
+    int res_strlen = snprintf(ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d",
+                              index, dir, state, mode, mpty);
+    if (number) {
+      size_t rem_bytes = sizeof(ag_res.str) - res_strlen;
+      char dialnum[sizeof(ag_res.str)];
+      size_t newidx = 0;
+      if (type == BTHF_CALL_ADDRTYPE_INTERNATIONAL && *number != '+') {
+        dialnum[newidx++] = '+';
       }
+      for (size_t i = 0; number[i] != 0; i++) {
+        if (newidx >= (sizeof(dialnum) - res_strlen - 1)) {
+          android_errorWriteLog(0x534e4554, "79266386");
+          break;
+        }
+        if (utl_isdialchar(number[i])) {
+          dialnum[newidx++] = number[i];
+        }
+      }
+      dialnum[newidx] = 0;
+      // Reserve 5 bytes for ["][,][3_digit_type]
+      snprintf(&ag_res.str[res_strlen], rem_bytes - 5, ",\"%s", dialnum);
+      std::stringstream remaining_string;
+      remaining_string << "\"," << type;
+      strncat(&ag_res.str[res_strlen], remaining_string.str().c_str(), 5);
     }
-    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
-
-    return BT_STATUS_SUCCESS;
   }
-
-  return BT_STATUS_FAIL;
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, ag_res);
+  return BT_STATUS_SUCCESS;
 }
 
-/*******************************************************************************
- *
- * Function         phone_state_change
- *
- * Description      notify of a call state change
- *                  number & type: valid only for incoming & waiting call
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-
-static bt_status_t phone_state_change(int num_active, int num_held,
-                                      bthf_call_state_t call_setup_state,
-                                      const char* number,
-                                      bthf_call_addrtype_t type) {
-  tBTA_AG_RES res = 0xff;
-  tBTA_AG_RES_DATA ag_res;
-  bt_status_t status = BT_STATUS_SUCCESS;
-  bool activeCallUpdated = false;
-  int idx, i;
-
-  /* hf_idx is index of connected HS that sent ATA/BLDN,
-          otherwise index of latest connected HS */
-  if (hf_idx != BTIF_HF_INVALID_IDX)
-    idx = hf_idx;
-  else
-    idx = btif_hf_latest_connected_idx();
-
-  BTIF_TRACE_DEBUG("phone_state_change: idx = %d", idx);
-
-  /* Check if SLC is connected */
-  if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+bt_status_t HeadsetInterface::PhoneStateChange(
+    int num_active, int num_held, bthf_call_state_t call_setup_state,
+    const char* number, bthf_call_addrtype_t type, RawAddress* bd_addr) {
+  CHECK_BTHF_INIT();
+  if (!bd_addr) {
+    BTIF_TRACE_WARNING("%s: bd_addr is null", __func__);
+    return BT_STATUS_FAIL;
+  }
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if (idx < 0 || idx > BTA_AG_MAX_NUM_CLIENTS) {
+    BTIF_TRACE_WARNING("%s: invalid index %d for %s", __func__, idx,
+                       bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  const btif_hf_cb_t& control_block = btif_hf_cb[idx];
+  if (!IsSlcConnected(bd_addr)) {
+    LOG(WARNING) << ": SLC not connected for " << *bd_addr;
     return BT_STATUS_NOT_READY;
-
-  BTIF_TRACE_DEBUG(
-      "phone_state_change: num_active=%d [prev: %d]  num_held=%d[prev: %d]"
-      " call_setup=%s [prev: %s]",
-      num_active, btif_hf_cb[idx].num_active, num_held,
-      btif_hf_cb[idx].num_held, dump_hf_call_state(call_setup_state),
-      dump_hf_call_state(btif_hf_cb[idx].call_setup_state));
+  }
+  if (call_setup_state == BTHF_CALL_STATE_DISCONNECTED) {
+    // HFP spec does not handle cases when a call is being disconnected.
+    // Since DISCONNECTED state must lead to IDLE state, ignoring it here.s
+    LOG(INFO) << __func__
+              << ": Ignore call state change to DISCONNECTED, idx=" << idx
+              << ", addr=" << *bd_addr << ", num_active=" << num_active
+              << ", num_held=" << num_held;
+    return BT_STATUS_SUCCESS;
+  }
+  LOG(INFO) << __func__ << ": idx=" << idx << ", addr=" << *bd_addr
+            << ", active_bda=" << active_bda << ", num_active=" << num_active
+            << ", prev_num_active" << control_block.num_active
+            << ", num_held=" << num_held
+            << ", prev_num_held=" << control_block.num_held
+            << ", call_state=" << dump_hf_call_state(call_setup_state)
+            << ", prev_call_state="
+            << dump_hf_call_state(control_block.call_setup_state);
+  tBTA_AG_RES res = 0xFF;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  bool active_call_updated = false;
 
   /* if all indicators are 0, send end call and return */
   if (num_active == 0 && num_held == 0 &&
       call_setup_state == BTHF_CALL_STATE_IDLE) {
-    BTIF_TRACE_DEBUG("%s: Phone on hook", __func__);
-
-    /* record call termination timestamp  if  there was an active/held call  or
-               callsetup state > BTHF_CALL_STATE_IDLE */
-    if ((btif_hf_cb[idx].call_setup_state != BTHF_CALL_STATE_IDLE) ||
-        (btif_hf_cb[idx].num_active) || (btif_hf_cb[idx].num_held)) {
-      BTIF_TRACE_DEBUG("%s: Record call termination timestamp", __func__);
-      clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[0].call_end_timestamp);
-    }
-    BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
-    hf_idx = BTIF_HF_INVALID_IDX;
-
+    VLOG(1) << __func__ << ": call ended";
+    BTA_AgResult(control_block.handle, BTA_AG_END_CALL_RES,
+                 tBTA_AG_RES_DATA::kEmpty);
     /* if held call was present, reset that as well */
-    if (btif_hf_cb[idx].num_held) send_indicator_update(BTA_AG_IND_CALLHELD, 0);
-
-    goto update_call_states;
+    if (control_block.num_held) {
+      send_indicator_update(control_block, BTA_AG_IND_CALLHELD, 0);
+    }
+    UpdateCallStates(&btif_hf_cb[idx], num_active, num_held, call_setup_state);
+    return status;
   }
 
   /* active state can change when:
@@ -1288,57 +1117,60 @@
   ** force the SCO to be setup. Handle this special case here prior to
   ** call setup handling
   */
-  if (((num_active + num_held) > 0) && (btif_hf_cb[idx].num_active == 0) &&
-      (btif_hf_cb[idx].num_held == 0) &&
-      (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE)) {
+  if (((num_active + num_held) > 0) && (control_block.num_active == 0) &&
+      (control_block.num_held == 0) &&
+      (control_block.call_setup_state == BTHF_CALL_STATE_IDLE)) {
+    tBTA_AG_RES_DATA ag_res = {};
     BTIF_TRACE_DEBUG(
-        "%s: Active/Held call notification received without call setup update",
+        "%s: Active/Held call notification received without call setup "
+        "update",
         __func__);
 
-    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
     ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
-    /* Addition call setup with the Active call
-    ** CIND response should have been updated.
-    ** just open SCO connection.
-    */
-    if (call_setup_state != BTHF_CALL_STATE_IDLE)
+    // Addition call setup with the Active call
+    // CIND response should have been updated.
+    // just open SCO connection.
+    if (call_setup_state != BTHF_CALL_STATE_IDLE) {
       res = BTA_AG_MULTI_CALL_RES;
-    else
+    } else {
       res = BTA_AG_OUT_CALL_CONN_RES;
-    BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
-    activeCallUpdated = true;
+    }
+    BTA_AgResult(control_block.handle, res, ag_res);
+    active_call_updated = true;
   }
 
   /* Ringing call changed? */
-  if (call_setup_state != btif_hf_cb[idx].call_setup_state) {
+  if (call_setup_state != control_block.call_setup_state) {
+    tBTA_AG_RES_DATA ag_res = {};
+    ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
     BTIF_TRACE_DEBUG("%s: Call setup states changed. old: %s new: %s", __func__,
-                     dump_hf_call_state(btif_hf_cb[idx].call_setup_state),
+                     dump_hf_call_state(control_block.call_setup_state),
                      dump_hf_call_state(call_setup_state));
-    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
-
     switch (call_setup_state) {
       case BTHF_CALL_STATE_IDLE: {
-        switch (btif_hf_cb[idx].call_setup_state) {
+        switch (control_block.call_setup_state) {
           case BTHF_CALL_STATE_INCOMING:
-            if (num_active > btif_hf_cb[idx].num_active) {
+            if (num_active > control_block.num_active) {
               res = BTA_AG_IN_CALL_CONN_RES;
-              ag_res.audio_handle = btif_hf_cb[idx].handle;
-            } else if (num_held > btif_hf_cb[idx].num_held)
+              if (is_active_device(*bd_addr)) {
+                ag_res.audio_handle = control_block.handle;
+              }
+            } else if (num_held > control_block.num_held)
               res = BTA_AG_IN_CALL_HELD_RES;
             else
               res = BTA_AG_CALL_CANCEL_RES;
             break;
           case BTHF_CALL_STATE_DIALING:
           case BTHF_CALL_STATE_ALERTING:
-            if (num_active > btif_hf_cb[idx].num_active) {
-              ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+            if (num_active > control_block.num_active) {
               res = BTA_AG_OUT_CALL_CONN_RES;
             } else
               res = BTA_AG_CALL_CANCEL_RES;
             break;
           default:
-            BTIF_TRACE_ERROR("%s: Incorrect Call setup state transition",
-                             __func__);
+            BTIF_TRACE_ERROR("%s: Incorrect call state prev=%d, now=%d",
+                             __func__, control_block.call_setup_state,
+                             call_setup_state);
             status = BT_STATUS_PARM_INVALID;
             break;
         }
@@ -1349,6 +1181,9 @@
           res = BTA_AG_CALL_WAIT_RES;
         } else {
           res = BTA_AG_IN_CALL_RES;
+          if (is_active_device(*bd_addr)) {
+            ag_res.audio_handle = control_block.handle;
+          }
         }
         if (number) {
           int xx = 0;
@@ -1357,141 +1192,114 @@
           else
             xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"%s\"", number);
           ag_res.num = type;
+          // 5 = [,][3_digit_type][null_terminator]
+          if (xx > static_cast<int>(sizeof(ag_res.str) - 5)) {
+            android_errorWriteLog(0x534e4554, "79431031");
+            xx = sizeof(ag_res.str) - 5;
+            // Null terminating the string
+            memset(&ag_res.str[xx], 0, 5);
+          }
 
           if (res == BTA_AG_CALL_WAIT_RES)
             snprintf(&ag_res.str[xx], sizeof(ag_res.str) - xx, ",%d", type);
         }
         break;
       case BTHF_CALL_STATE_DIALING:
-        if (!(num_active + num_held))
-          ag_res.audio_handle = btif_hf_cb[idx].handle;
+        if (!(num_active + num_held) && is_active_device(*bd_addr)) {
+          ag_res.audio_handle = control_block.handle;
+        }
         res = BTA_AG_OUT_CALL_ORIG_RES;
         break;
       case BTHF_CALL_STATE_ALERTING:
         /* if we went from idle->alert, force SCO setup here. dialing usually
          * triggers it */
-        if ((btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) &&
-            !(num_active + num_held))
-          ag_res.audio_handle = btif_hf_cb[idx].handle;
+        if ((control_block.call_setup_state == BTHF_CALL_STATE_IDLE) &&
+            !(num_active + num_held) && is_active_device(*bd_addr)) {
+          ag_res.audio_handle = control_block.handle;
+        }
         res = BTA_AG_OUT_CALL_ALERT_RES;
         break;
       default:
-        BTIF_TRACE_ERROR("%s: Incorrect new ringing call state", __func__);
+        BTIF_TRACE_ERROR("%s: Incorrect call state prev=%d, now=%d", __func__,
+                         control_block.call_setup_state, call_setup_state);
         status = BT_STATUS_PARM_INVALID;
         break;
     }
     BTIF_TRACE_DEBUG("%s: Call setup state changed. res=%d, audio_handle=%d",
                      __func__, res, ag_res.audio_handle);
 
-    if (res) BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+    if (res != 0xFF) {
+      BTA_AgResult(control_block.handle, res, ag_res);
+    }
 
     /* if call setup is idle, we have already updated call indicator, jump out
      */
     if (call_setup_state == BTHF_CALL_STATE_IDLE) {
       /* check & update callheld */
-      if ((num_held > 0) && (num_active > 0))
-        send_indicator_update(BTA_AG_IND_CALLHELD, 1);
-      goto update_call_states;
+      if ((num_held > 0) && (num_active > 0)) {
+        send_indicator_update(control_block, BTA_AG_IND_CALLHELD, 1);
+      }
+      UpdateCallStates(&btif_hf_cb[idx], num_active, num_held,
+                       call_setup_state);
+      return status;
     }
   }
 
-  memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
-
-  /* per the errata 2043, call=1 implies atleast one call is in progress
-   *(active/held)
-   ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
-   ** Handle call indicator change
+  /**
+   * Handle call indicator change
+   *
+   * Per the errata 2043, call=1 implies at least one call is in progress
+   * (active or held)
+   * See: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+   *
    **/
-  if (!activeCallUpdated &&
+  if (!active_call_updated &&
       ((num_active + num_held) !=
-       (btif_hf_cb[idx].num_active + btif_hf_cb[idx].num_held))) {
-    BTIF_TRACE_DEBUG("%s: Active call states changed. old: %d new: %d",
-                     __func__, btif_hf_cb[idx].num_active, num_active);
-    send_indicator_update(BTA_AG_IND_CALL,
-                          ((num_active + num_held) > 0) ? 1 : 0);
+       (control_block.num_active + control_block.num_held))) {
+    VLOG(1) << __func__ << ": in progress call states changed, active=["
+            << control_block.num_active << "->" << num_active << "], held=["
+            << control_block.num_held << "->" << num_held;
+    send_indicator_update(control_block, BTA_AG_IND_CALL,
+                          ((num_active + num_held) > 0) ? BTA_AG_CALL_ACTIVE
+                                                        : BTA_AG_CALL_INACTIVE);
   }
 
   /* Held Changed? */
-  if (num_held != btif_hf_cb[idx].num_held ||
-      ((num_active == 0) && ((num_held + btif_hf_cb[idx].num_held) > 1))) {
+  if (num_held != control_block.num_held ||
+      ((num_active == 0) && ((num_held + control_block.num_held) > 1))) {
     BTIF_TRACE_DEBUG("%s: Held call states changed. old: %d new: %d", __func__,
-                     btif_hf_cb[idx].num_held, num_held);
-    send_indicator_update(BTA_AG_IND_CALLHELD,
+                     control_block.num_held, num_held);
+    send_indicator_update(control_block, BTA_AG_IND_CALLHELD,
                           ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
   }
 
   /* Calls Swapped? */
-  if ((call_setup_state == btif_hf_cb[idx].call_setup_state) &&
-      (num_active && num_held) && (num_active == btif_hf_cb[idx].num_active) &&
-      (num_held == btif_hf_cb[idx].num_held)) {
+  if ((call_setup_state == control_block.call_setup_state) &&
+      (num_active && num_held) && (num_active == control_block.num_active) &&
+      (num_held == control_block.num_held)) {
     BTIF_TRACE_DEBUG("%s: Calls swapped", __func__);
-    send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+    send_indicator_update(control_block, BTA_AG_IND_CALLHELD, 1);
   }
 
-update_call_states:
-  for (i = 0; i < btif_max_hf_clients; i++) {
-    if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
-      btif_hf_cb[i].num_active = num_active;
-      btif_hf_cb[i].num_held = num_held;
-      btif_hf_cb[i].call_setup_state = call_setup_state;
-    }
+  /* When call is hung up and still there is another call is in active,
+   * some of the HF cannot acquire the call states by its own. If HF try
+   * to terminate a call, it may not send the command AT+CHUP because the
+   * call states are not updated properly. HF should get informed the call
+   * status forcibly.
+   */
+  if ((control_block.num_active == num_active && num_active != 0) &&
+      (control_block.num_held != num_held && num_held == 0)) {
+    tBTA_AG_RES_DATA ag_res = {};
+    ag_res.ind.id = BTA_AG_IND_CALL;
+    ag_res.ind.value = num_active;
+    BTA_AgResult(control_block.handle, BTA_AG_IND_RES_ON_DEMAND, ag_res);
   }
+
+  UpdateCallStates(&btif_hf_cb[idx], num_active, num_held, call_setup_state);
   return status;
 }
 
-/*******************************************************************************
- *
- * Function         btif_hf_is_call_idle
- *
- * Description      returns true if no call is in progress
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-bool btif_hf_is_call_idle(void) {
-  if (bt_hf_callbacks == NULL) return true;
-
-  for (int i = 0; i < btif_max_hf_clients; ++i) {
-    if ((btif_hf_cb[i].call_setup_state != BTHF_CALL_STATE_IDLE) ||
-        ((btif_hf_cb[i].num_held + btif_hf_cb[i].num_active) > 0))
-      return false;
-  }
-
-  return true;
-}
-
-/*******************************************************************************
- *
- * Function         btif_hf_call_terminated_recently
- *
- * Description      Checks if a call has been terminated
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-bool btif_hf_call_terminated_recently() {
-  struct timespec now;
-
-  clock_gettime(CLOCK_MONOTONIC, &now);
-  if (now.tv_sec <
-      btif_hf_cb[0].call_end_timestamp.tv_sec + BTIF_HF_CALL_END_TIMEOUT) {
-    return true;
-  } else {
-    btif_hf_cb[0].call_end_timestamp.tv_sec = 0;
-    return false;
-  }
-}
-
-/*******************************************************************************
- *
- * Function         cleanup
- *
- * Description      Closes the HF interface
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static void cleanup(void) {
+void HeadsetInterface::Cleanup() {
   BTIF_TRACE_EVENT("%s", __func__);
 
   btif_queue_cleanup(UUID_SERVCLASS_AG_HANDSFREE);
@@ -1501,65 +1309,41 @@
 #else
     btif_disable_service(BTA_HSP_SERVICE_ID);
 #endif
-    bt_hf_callbacks = NULL;
+    bt_hf_callbacks = nullptr;
   }
 }
 
-/*******************************************************************************
- *
- * Function         configure_wbs
- *
- * Description      set to over-ride the current WBS configuration.
- *                  It will not send codec setting cmd to the controller now.
- *                  It just change the configure.
- *
- * Returns          bt_status_t
- *
- ******************************************************************************/
-static bt_status_t configure_wbs(RawAddress* bd_addr,
-                                 bthf_wbs_config_t config) {
+bt_status_t HeadsetInterface::SetScoAllowed(bool value) {
   CHECK_BTHF_INIT();
-
-  int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
-  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
-    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
-    return BT_STATUS_FAIL;
-  }
-
-  BTIF_TRACE_EVENT("%s config is %d", __func__, config);
-  if (config == BTHF_WBS_YES)
-    BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
-  else if (config == BTHF_WBS_NO)
-    BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_CVSD);
-  else
-    BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_NONE);
-
+  BTA_AgSetScoAllowed(value);
   return BT_STATUS_SUCCESS;
 }
 
-static const bthf_interface_t bthfInterface = {
-    sizeof(bthfInterface),
-    init,
-    connect,
-    disconnect,
-    connect_audio,
-    disconnect_audio,
-    start_voice_recognition,
-    stop_voice_recognition,
-    volume_control,
-    device_status_notification,
-    cops_response,
-    cind_response,
-    formatted_at_response,
-    at_response,
-    clcc_response,
-    phone_state_change,
-    cleanup,
-    configure_wbs,
-    bind_response,
-    set_sco_allowed,
-};
+bt_status_t HeadsetInterface::SendBsir(bool value, RawAddress* bd_addr) {
+  CHECK_BTHF_INIT();
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+  if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d for %s", __func__, idx,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  if (!is_connected(bd_addr)) {
+    BTIF_TRACE_ERROR("%s: %s not connected", __func__,
+                     bd_addr->ToString().c_str());
+    return BT_STATUS_FAIL;
+  }
+  tBTA_AG_RES_DATA ag_result = {};
+  ag_result.state = value;
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_INBAND_RING_RES, ag_result);
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t HeadsetInterface::SetActiveDevice(RawAddress* active_device_addr) {
+  CHECK_BTHF_INIT();
+  active_bda = *active_device_addr;
+  BTA_AgSetActiveDevice(*active_device_addr);
+  return BT_STATUS_SUCCESS;
+}
 
 /*******************************************************************************
  *
@@ -1570,19 +1354,24 @@
  * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
  *
  ******************************************************************************/
-bt_status_t btif_hf_execute_service(bool b_enable) {
-  const char* p_service_names[] = BTIF_HF_SERVICE_NAMES;
-  int i;
+bt_status_t ExecuteService(bool b_enable) {
+  const char* service_names_raw[] = BTIF_HF_SERVICE_NAMES;
+  std::vector<std::string> service_names;
+  for (const char* service_name_raw : service_names_raw) {
+    if (service_name_raw) {
+      service_names.emplace_back(service_name_raw);
+    }
+  }
   if (b_enable) {
     /* Enable and register with BTA-AG */
-    BTA_AgEnable(BTA_AG_PARSE, bte_hf_evt);
-    for (i = 0; i < btif_max_hf_clients; i++) {
+    BTA_AgEnable(bte_hf_evt);
+    for (uint8_t app_id = 0; app_id < btif_max_hf_clients; app_id++) {
       BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY, btif_hf_features,
-                     p_service_names, bthf_hf_id[i]);
+                     service_names, app_id);
     }
   } else {
     /* De-register AG */
-    for (i = 0; i < btif_max_hf_clients; i++) {
+    for (int i = 0; i < btif_max_hf_clients; i++) {
       BTA_AgDeregister(btif_hf_cb[i].handle);
     }
     /* Disable AG */
@@ -1600,7 +1389,10 @@
  * Returns          bthf_interface_t
  *
  ******************************************************************************/
-const bthf_interface_t* btif_hf_get_interface() {
-  BTIF_TRACE_EVENT("%s", __func__);
-  return &bthfInterface;
+Interface* GetInterface() {
+  VLOG(0) << __func__;
+  return HeadsetInterface::GetInstance();
 }
+
+}  // namespace headset
+}  // namespace bluetooth
diff --git a/btif/src/btif_hf_client.cc b/btif/src/btif_hf_client.cc
index c1f3c8b..7c65bf7 100644
--- a/btif/src/btif_hf_client.cc
+++ b/btif/src/btif_hf_client.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -109,6 +109,18 @@
 
 char btif_hf_client_version[PROPERTY_VALUE_MAX];
 
+static const char* dump_hf_client_conn_state(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED)
+    CASE_RETURN_STR(BTHF_CLIENT_CONNECTION_STATE_CONNECTING)
+    CASE_RETURN_STR(BTHF_CLIENT_CONNECTION_STATE_CONNECTED)
+    CASE_RETURN_STR(BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED)
+    CASE_RETURN_STR(BTHF_CLIENT_CONNECTION_STATE_DISCONNECTING)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
 #define CHECK_BTHF_CLIENT_INIT()                                        \
   do {                                                                  \
     if (bt_hf_client_callbacks == NULL) {                               \
@@ -126,7 +138,7 @@
       return BT_STATUS_NOT_READY;                                            \
     } else if ((cb)->state != BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) {  \
       BTIF_TRACE_WARNING("BTHF CLIENT: %s: SLC connection not up. state=%s", \
-                         __func__, dump_hf_conn_state((cb)->state));         \
+                         __func__, dump_hf_client_conn_state((cb)->state));  \
       return BT_STATUS_NOT_READY;                                            \
     } else {                                                                 \
       BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__);                         \
@@ -162,7 +174,7 @@
   switch (event) {
     case BTIF_HF_CLIENT_CB_AUDIO_CONNECTING: {
       HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda,
-                (bthf_client_audio_state_t)BTHF_AUDIO_STATE_CONNECTING);
+                (bthf_client_audio_state_t)BTHF_CLIENT_AUDIO_STATE_CONNECTING);
     } break;
     default: {
       BTIF_TRACE_WARNING("%s: : Unknown event 0x%x", __func__, event);
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index 7c7352e..c5a9021 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -503,6 +503,7 @@
 
 bool btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest,
                            tBTA_HH_DEV_DSCP_INFO* src) {
+  memset(dest, 0, sizeof(tBTA_HH_DEV_DSCP_INFO));
   dest->descriptor.dl_len = 0;
   if (src->descriptor.dl_len > 0) {
     dest->descriptor.dsc_list = (uint8_t*)osi_malloc(src->descriptor.dl_len);
@@ -533,10 +534,6 @@
 bt_status_t btif_hh_virtual_unplug(const RawAddress* bd_addr) {
   BTIF_TRACE_DEBUG("%s", __func__);
   btif_hh_device_t* p_dev;
-  char bd_str[18];
-  snprintf(bd_str, sizeof(bd_str), "%02X:%02X:%02X:%02X:%02X:%02X",
-           bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
-           bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
   p_dev = btif_hh_find_dev_by_bda(*bd_addr);
   if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED) &&
       (p_dev->attr_mask & HID_VIRTUAL_CABLE)) {
@@ -547,7 +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_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;
   }
 }
@@ -602,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!
@@ -749,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) {
@@ -1264,17 +1269,14 @@
   CHECK_BTHH_INIT();
   BTIF_TRACE_EVENT("BTHH: %s", __func__);
   btif_hh_device_t* p_dev;
-  char bd_str[18];
-  snprintf(bd_str, sizeof(bd_str), "%02X:%02X:%02X:%02X:%02X:%02X",
-           bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
-           bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
   if (btif_hh_cb.status == BTIF_HH_DISABLED) {
     BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
     return BT_STATUS_FAIL;
   }
   p_dev = btif_hh_find_dev_by_bda(*bd_addr);
   if (!p_dev) {
-    BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, bd_str);
+    BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__,
+                     bd_addr->ToString().c_str());
     return BT_STATUS_FAIL;
   }
   btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT, (char*)bd_addr,
@@ -1364,6 +1366,7 @@
     return BT_STATUS_FAIL;
   }
 
+  memset(&dscp_info, 0, sizeof(dscp_info));
   dscp_info.vendor_id = hid_info.vendor_id;
   dscp_info.product_id = hid_info.product_id;
   dscp_info.version = hid_info.version;
@@ -1480,7 +1483,7 @@
     return BT_STATUS_FAIL;
   } else if (((int)reportType) <= BTA_HH_RPTT_RESRV ||
              ((int)reportType) > BTA_HH_RPTT_FEATURE) {
-    LOG(ERROR) << " Error, device" << *bd_addr << " not opened";
+    LOG(ERROR) << " Error, report type=" << +reportType << " not supported";
     return BT_STATUS_FAIL;
   } else {
     BTA_HhGetReport(p_dev->dev_handle, reportType, reportId, bufferSize);
@@ -1517,7 +1520,7 @@
     return BT_STATUS_FAIL;
   } else if (((int)reportType) <= BTA_HH_RPTT_RESRV ||
              ((int)reportType) > BTA_HH_RPTT_FEATURE) {
-    LOG(ERROR) << " Error, device" << *bd_addr << " not opened";
+    LOG(ERROR) << " Error, report type=" << +reportType << " not supported";
     return BT_STATUS_FAIL;
   } else {
     int hex_bytes_filled;
diff --git a/btif/src/btif_hl.cc b/btif/src/btif_hl.cc
index 4f701fb..a317f79 100644
--- a/btif/src/btif_hl.cc
+++ b/btif/src/btif_hl.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/btif_mce.cc b/btif/src/btif_mce.cc
index 53102e8..d9326db 100644
--- a/btif/src/btif_mce.cc
+++ b/btif/src/btif_mce.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2014 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -38,7 +38,6 @@
 #include "bta_api.h"
 #include "bta_mce_api.h"
 #include "btif_common.h"
-#include "btif_profile_queue.h"
 #include "btif_util.h"
 
 /*****************************************************************************
diff --git a/btif/src/btif_pan.cc b/btif/src/btif_pan.cc
index 7b2c861..9828c4b 100644
--- a/btif/src/btif_pan.cc
+++ b/btif/src/btif_pan.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
 
 #define LOG_TAG "bt_btif_pan"
 
+#include <base/bind.h>
 #include <base/logging.h>
 #include <ctype.h>
 #include <errno.h>
@@ -53,6 +54,7 @@
 
 #include "bt_common.h"
 #include "bta_api.h"
+#include "bta_closure_api.h"
 #include "bta_pan_api.h"
 #include "btif_common.h"
 #include "btif_pan_internal.h"
@@ -105,13 +107,13 @@
                                   uint32_t user_id);
 static void btpan_cleanup_conn(btpan_conn_t* conn);
 static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN* p_data);
-static void btu_exec_tap_fd_read(void* p_param);
+static void btu_exec_tap_fd_read(const int fd);
 
 static btpan_interface_t pan_if = {
     sizeof(pan_if), btpan_jni_init,   btpan_enable,     btpan_get_local_role,
     btpan_connect,  btpan_disconnect, btpan_jni_cleanup};
 
-btpan_interface_t* btif_pan_get_interface() { return &pan_if; }
+const btpan_interface_t* btif_pan_get_interface() { return &pan_if; }
 
 /*******************************************************************************
  **
@@ -286,7 +288,7 @@
 
   // set mac addr
   memset(&ifr, 0, sizeof(ifr));
-  strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+  strlcpy(ifr.ifr_name, devname, IFNAMSIZ);
   err = ioctl(sk, SIOCGIFHWADDR, &ifr);
   if (err < 0) {
     BTIF_TRACE_ERROR(
@@ -296,7 +298,7 @@
     return -1;
   }
 
-  strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+  strlcpy(ifr.ifr_name, devname, IFNAMSIZ);
   memcpy(ifr.ifr_hwaddr.sa_data, addr->address, 6);
 
   /* The IEEE has specified that the most significant bit of the most
@@ -324,7 +326,7 @@
 
   // bring it up
   memset(&ifr, 0, sizeof(ifr));
-  strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+  strlcpy(ifr.ifr_name, devname, IF_NAMESIZE);
 
   ifr.ifr_flags |= IFF_UP;
   ifr.ifr_flags |= IFF_MULTICAST;
@@ -350,7 +352,7 @@
   if (sk < 0) return -1;
 
   memset(&ifr, 0, sizeof(ifr));
-  strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+  strlcpy(ifr.ifr_name, devname, IF_NAMESIZE);
 
   ifr.ifr_flags &= ~IFF_UP;
 
@@ -367,7 +369,8 @@
   btpan_cb.flow = enable;
   if (enable) {
     btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0);
-    bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(btpan_cb.tap_fd));
+    do_in_bta_thread(FROM_HERE,
+                     base::Bind(btu_exec_tap_fd_read, btpan_cb.tap_fd));
   }
 }
 
@@ -387,7 +390,7 @@
   memset(&ifr, 0, sizeof(ifr));
   ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
 
-  strncpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
+  strlcpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
 
   /* try to create the device */
   err = ioctl(fd, TUNSETIFF, (void*)&ifr);
@@ -663,9 +666,8 @@
 }
 
 #define IS_EXCEPTION(e) ((e) & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))
-static void btu_exec_tap_fd_read(void* p_param) {
+static void btu_exec_tap_fd_read(int fd) {
   struct pollfd ufd;
-  int fd = PTR_TO_INT(p_param);
 
   if (fd == INVALID_FD || fd != btpan_cb.tap_fd) return;
 
@@ -770,6 +772,7 @@
     btpan_cb.tap_fd = INVALID_FD;
     btpan_tap_close(fd);
     btif_pan_close_all_conns();
-  } else if (flags & SOCK_THREAD_FD_RD)
-    bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(fd));
+  } else if (flags & SOCK_THREAD_FD_RD) {
+    do_in_bta_thread(FROM_HERE, base::Bind(btu_exec_tap_fd_read, fd));
+  }
 }
diff --git a/btif/src/btif_profile_queue.cc b/btif/src/btif_profile_queue.cc
index 152f11d..10acade 100644
--- a/btif/src/btif_profile_queue.cc
+++ b/btif/src/btif_profile_queue.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,129 +28,115 @@
 
 #include "btif_profile_queue.h"
 
+#include <base/bind.h>
 #include <base/logging.h>
+#include <base/strings/stringprintf.h>
 #include <string.h>
+#include <list>
 
 #include "bt_common.h"
 #include "btif_common.h"
-#include "osi/include/allocator.h"
-#include "osi/include/list.h"
 #include "stack_manager.h"
 
 /*******************************************************************************
  *  Local type definitions
  ******************************************************************************/
 
-typedef enum {
-  BTIF_QUEUE_CONNECT_EVT,
-  BTIF_QUEUE_ADVANCE_EVT,
-  BTIF_QUEUE_CLEANUP_EVT
-} btif_queue_event_t;
+// Class to store connect info.
+class ConnectNode {
+ public:
+  ConnectNode(const RawAddress& address, uint16_t uuid,
+              btif_connect_cb_t connect_cb)
+      : address_(address), uuid_(uuid), busy_(false), connect_cb_(connect_cb) {}
 
-typedef struct {
-  RawAddress bda;
-  uint16_t uuid;
-  bool busy;
-  btif_connect_cb_t connect_cb;
-} connect_node_t;
+  std::string ToString() const {
+    return base::StringPrintf("address=%s UUID=%04X busy=%s",
+                              address_.ToString().c_str(), uuid_,
+                              (busy_) ? "true" : "false");
+  }
+
+  const RawAddress& address() const { return address_; }
+  uint16_t uuid() const { return uuid_; }
+
+  /**
+   * Initiate the connection.
+   *
+   * @return BT_STATUS_SUCCESS on success, othewise the corresponding error
+   * code. Note: if a previous connect request hasn't been completed, the
+   * return value is BT_STATUS_SUCCESS.
+   */
+  bt_status_t connect() {
+    if (busy_) return BT_STATUS_SUCCESS;
+    busy_ = true;
+    return connect_cb_(&address_, uuid_);
+  }
+
+ private:
+  RawAddress address_;
+  uint16_t uuid_;
+  bool busy_;
+  btif_connect_cb_t connect_cb_;
+};
 
 /*******************************************************************************
  *  Static variables
  ******************************************************************************/
 
-static list_t* connect_queue;
+static std::list<ConnectNode> connect_queue;
 
-static const size_t MAX_REASONABLE_REQUESTS = 10;
+static const size_t MAX_REASONABLE_REQUESTS = 20;
 
 /*******************************************************************************
  *  Queue helper functions
  ******************************************************************************/
 
-static void queue_int_add(connect_node_t* p_param) {
-  if (!connect_queue) {
-    LOG_INFO(LOG_TAG, "%s: allocating profile queue", __func__);
-    connect_queue = list_new(osi_free);
-    CHECK(connect_queue != NULL);
-  }
-
+static void queue_int_add(uint16_t uuid, const RawAddress& bda,
+                          btif_connect_cb_t connect_cb) {
   // Sanity check to make sure we're not leaking connection requests
-  CHECK(list_length(connect_queue) < MAX_REASONABLE_REQUESTS);
+  CHECK(connect_queue.size() < MAX_REASONABLE_REQUESTS);
 
-  for (const list_node_t* node = list_begin(connect_queue);
-       node != list_end(connect_queue); node = list_next(node)) {
-    if (((connect_node_t*)list_node(node))->uuid == p_param->uuid) {
-      LOG_ERROR(LOG_TAG,
-                "%s dropping duplicate connection request UUID=%04X, "
-                "bd_addr=%s, busy=%d",
-                __func__, p_param->uuid, p_param->bda.ToString().c_str(),
-                p_param->busy);
+  ConnectNode param(bda, uuid, connect_cb);
+  for (const auto& node : connect_queue) {
+    if (node.uuid() == param.uuid() && node.address() == param.address()) {
+      LOG_ERROR(LOG_TAG, "%s: dropping duplicate connection request: %s",
+                __func__, param.ToString().c_str());
       return;
     }
   }
 
-  LOG_INFO(
-      LOG_TAG, "%s: adding connection request UUID=%04X, bd_addr=%s, busy=%d",
-      __func__, p_param->uuid, p_param->bda.ToString().c_str(), p_param->busy);
-  connect_node_t* p_node = (connect_node_t*)osi_malloc(sizeof(connect_node_t));
-  memcpy(p_node, p_param, sizeof(connect_node_t));
-  list_append(connect_queue, p_node);
+  LOG_INFO(LOG_TAG, "%s: adding connection request: %s", __func__,
+           param.ToString().c_str());
+  connect_queue.push_back(param);
+
+  btif_queue_connect_next();
 }
 
 static void queue_int_advance() {
-  if (connect_queue && !list_is_empty(connect_queue)) {
-    connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
-    LOG_INFO(LOG_TAG,
-             "%s: removing connection request UUID=%04X, bd_addr=%s, busy=%d",
-             __func__, p_head->uuid, p_head->bda.ToString().c_str(),
-             p_head->busy);
-    list_remove(connect_queue, p_head);
-  }
+  if (connect_queue.empty()) return;
+
+  const ConnectNode& head = connect_queue.front();
+  LOG_INFO(LOG_TAG, "%s: removing connection request: %s", __func__,
+           head.ToString().c_str());
+  connect_queue.pop_front();
+
+  btif_queue_connect_next();
 }
 
-static void queue_int_cleanup(uint16_t* p_uuid) {
-  if (!p_uuid) {
-    LOG_ERROR(LOG_TAG, "%s: UUID is null", __func__);
-    return;
-  }
-  uint16_t uuid = *p_uuid;
+static void queue_int_cleanup(uint16_t uuid) {
   LOG_INFO(LOG_TAG, "%s: UUID=%04X", __func__, uuid);
-  if (!connect_queue) {
-    return;
-  }
-  connect_node_t* connection_request;
-  const list_node_t* node = list_begin(connect_queue);
-  while (node && node != list_end(connect_queue)) {
-    connection_request = (connect_node_t*)list_node(node);
-    node = list_next(node);
-    if (connection_request->uuid == uuid) {
-      LOG_INFO(LOG_TAG,
-               "%s: removing connection request UUID=%04X, bd_addr=%s, busy=%d",
-               __func__, connection_request->uuid,
-               connection_request->bda.ToString().c_str(),
-               connection_request->busy);
-      list_remove(connect_queue, connection_request);
+
+  for (auto it = connect_queue.begin(); it != connect_queue.end();) {
+    auto it_prev = it++;
+    const ConnectNode& node = *it_prev;
+    if (node.uuid() == uuid) {
+      LOG_INFO(LOG_TAG, "%s: removing connection request: %s", __func__,
+               node.ToString().c_str());
+      connect_queue.erase(it_prev);
     }
   }
 }
 
-static void queue_int_handle_evt(uint16_t event, char* p_param) {
-  switch (event) {
-    case BTIF_QUEUE_CONNECT_EVT:
-      queue_int_add((connect_node_t*)p_param);
-      break;
-
-    case BTIF_QUEUE_ADVANCE_EVT:
-      queue_int_advance();
-      break;
-
-    case BTIF_QUEUE_CLEANUP_EVT:
-      queue_int_cleanup((uint16_t*)(p_param));
-      return;
-  }
-
-  if (stack_manager_get_interface()->get_stack_is_running())
-    btif_queue_connect_next();
-}
+static void queue_int_release() { connect_queue.clear(); }
 
 /*******************************************************************************
  *
@@ -164,14 +150,8 @@
  ******************************************************************************/
 bt_status_t btif_queue_connect(uint16_t uuid, const RawAddress* bda,
                                btif_connect_cb_t connect_cb) {
-  connect_node_t node;
-  memset(&node, 0, sizeof(connect_node_t));
-  node.bda = *bda;
-  node.uuid = uuid;
-  node.connect_cb = connect_cb;
-
-  return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
-                               (char*)&node, sizeof(connect_node_t), NULL);
+  return do_in_jni_thread(FROM_HERE,
+                          base::Bind(&queue_int_add, uuid, *bda, connect_cb));
 }
 
 /*******************************************************************************
@@ -184,8 +164,7 @@
  *
  ******************************************************************************/
 void btif_queue_cleanup(uint16_t uuid) {
-  btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CLEANUP_EVT,
-                        (char*)&uuid, sizeof(uint16_t), NULL);
+  do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_cleanup, uuid));
 }
 
 /*******************************************************************************
@@ -199,27 +178,23 @@
  *
  ******************************************************************************/
 void btif_queue_advance() {
-  btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_ADVANCE_EVT, NULL, 0,
-                        NULL);
+  do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_advance));
 }
 
-// This function dispatches the next pending connect request. It is called from
-// stack_manager when the stack comes up.
 bt_status_t btif_queue_connect_next(void) {
-  if (!connect_queue || list_is_empty(connect_queue)) return BT_STATUS_FAIL;
+  // The call must be on the JNI thread, otherwise the access to connect_queue
+  // is not thread-safe.
+  CHECK(is_on_jni_thread());
 
-  connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
+  if (connect_queue.empty()) return BT_STATUS_FAIL;
+  if (!stack_manager_get_interface()->get_stack_is_running())
+    return BT_STATUS_FAIL;
 
-  LOG_INFO(LOG_TAG,
-           "%s: executing connection request UUID=%04X, bd_addr=%s, busy=%d",
-           __func__, p_head->uuid, p_head->bda.ToString().c_str(),
-           p_head->busy);
-  // If the queue is currently busy, we return success anyway,
-  // since the connection has been queued...
-  if (p_head->busy) return BT_STATUS_SUCCESS;
+  ConnectNode& head = connect_queue.front();
 
-  p_head->busy = true;
-  return p_head->connect_cb(&p_head->bda, p_head->uuid);
+  LOG_INFO(LOG_TAG, "%s: executing connection request: %s", __func__,
+           head.ToString().c_str());
+  return head.connect();
 }
 
 /*******************************************************************************
@@ -233,6 +208,9 @@
  ******************************************************************************/
 void btif_queue_release() {
   LOG_INFO(LOG_TAG, "%s", __func__);
-  list_free(connect_queue);
-  connect_queue = NULL;
+  if (do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_release)) !=
+      BT_STATUS_SUCCESS) {
+    // Scheduling failed - the thread to schedule on is probably dead
+    queue_int_release();
+  }
 }
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index edd0730..c226b5f 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright 2015 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.
@@ -42,6 +42,7 @@
 #include "bta_av_api.h"
 #include "btif_av.h"
 #include "btif_common.h"
+#include "btif_rc.h"
 #include "btif_util.h"
 #include "btu.h"
 #include "device/include/interop.h"
@@ -49,6 +50,7 @@
 #include "osi/include/list.h"
 #include "osi/include/osi.h"
 #include "osi/include/properties.h"
+
 #define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL)
 
 /*****************************************************************************
@@ -89,7 +91,7 @@
 
 #define CHECK_RC_CONNECTED(p_dev)                                          \
   do {                                                                     \
-    if ((p_dev) == NULL || (p_dev)->rc_connected == false) {               \
+    if ((p_dev) == NULL || !(p_dev)->rc_connected) {                       \
       BTIF_TRACE_WARNING("%s: called when RC is not connected", __func__); \
       return BT_STATUS_NOT_READY;                                          \
     }                                                                      \
@@ -97,7 +99,7 @@
 
 #define CHECK_BR_CONNECTED(p_dev)                                          \
   do {                                                                     \
-    if ((p_dev) == NULL || (p_dev)->br_connected == false) {               \
+    if ((p_dev) == NULL || !(p_dev)->br_connected) {                       \
       BTIF_TRACE_WARNING("%s: called when BR is not connected", __func__); \
       return BT_STATUS_NOT_READY;                                          \
     }                                                                      \
@@ -285,10 +287,14 @@
                                          tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp);
 static void handle_app_attr_val_txt_response(tBTA_AV_META_MSG* pmeta_msg,
                                              tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp);
+static void cleanup_app_attr_val_txt_response(
+    btif_rc_player_app_settings_t* p_app_settings);
 static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
                                            tAVRC_GET_PLAY_STATUS_RSP* p_rsp);
 static void handle_set_addressed_player_response(tBTA_AV_META_MSG* pmeta_msg,
                                                  tAVRC_RSP* p_rsp);
+static void cleanup_btrc_folder_items(btrc_folder_items_t* btrc_items,
+                                      uint8_t item_count);
 static void handle_get_elem_attr_response(tBTA_AV_META_MSG* pmeta_msg,
                                           tAVRC_GET_ATTRS_RSP* p_rsp);
 static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg,
@@ -319,8 +325,9 @@
                                  btrc_folder_items_t* btrc_item);
 void get_folder_item_type_player(const tAVRC_ITEM* avrc_item,
                                  btrc_folder_items_t* btrc_item);
-static bt_status_t get_folder_items_cmd(RawAddress* bd_addr, uint8_t scope,
-                                        uint8_t start_item, uint8_t num_items);
+static bt_status_t get_folder_items_cmd(const RawAddress& bd_addr,
+                                        uint8_t scope, uint32_t start_item,
+                                        uint32_t end_item);
 
 static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* p_param,
                                   uint8_t ctype, uint8_t label,
@@ -348,8 +355,7 @@
 /*****************************************************************************
  *  Externs
  *****************************************************************************/
-extern bool btif_hf_call_terminated_recently();
-extern bool check_cod(const RawAddress* remote_bdaddr, uint32_t cod);
+extern bool check_cod(const RawAddress& remote_bdaddr, uint32_t cod);
 
 /*****************************************************************************
  *  Functions
@@ -392,13 +398,13 @@
   return connected_devices;
 }
 
-btif_rc_device_cb_t* btif_rc_get_device_by_bda(const RawAddress* bd_addr) {
-  VLOG(1) << __func__ << ": bd_addr: " << *bd_addr;
+btif_rc_device_cb_t* btif_rc_get_device_by_bda(const RawAddress& bd_addr) {
+  VLOG(1) << __func__ << ": bd_addr: " << bd_addr;
 
   for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
     if ((btif_rc_cb.rc_multi_cb[idx].rc_state !=
          BTRC_CONNECTION_STATE_DISCONNECTED) &&
-        btif_rc_cb.rc_multi_cb[idx].rc_addr == *bd_addr) {
+        btif_rc_cb.rc_multi_cb[idx].rc_addr == bd_addr) {
       return (&btif_rc_cb.rc_multi_cb[idx]);
     }
   }
@@ -481,23 +487,30 @@
   }
 
   BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, rc_features);
-  RawAddress rc_addr = p_dev->rc_addr;
-  HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+  do_in_jni_thread(FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->getrcfeatures_cb,
+                                         p_dev->rc_addr, rc_features));
 }
 
 void handle_rc_features(btif_rc_device_cb_t* p_dev) {
-  RawAddress rc_addr = p_dev->rc_addr;
 
   CHECK(bt_rc_callbacks);
 
   btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
-  RawAddress avdtp_addr = btif_av_get_addr();
+  RawAddress avdtp_source_active_peer_addr = btif_av_source_active_peer();
+  RawAddress avdtp_sink_active_peer_addr = btif_av_sink_active_peer();
 
-  BTIF_TRACE_DEBUG("%s: AVDTP Address: %s AVCTP address: %s", __func__,
-                   avdtp_addr.ToString().c_str(), rc_addr.ToString().c_str());
+  BTIF_TRACE_DEBUG(
+      "%s: AVDTP Source Active Peer Address: %s "
+      "AVDTP Sink Active Peer Address: %s "
+      "AVCTP address: %s",
+      __func__, avdtp_source_active_peer_addr.ToString().c_str(),
+      avdtp_sink_active_peer_addr.ToString().c_str(),
+      p_dev->rc_addr.ToString().c_str());
 
-  if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr) ||
-      absolute_volume_disabled() || avdtp_addr != rc_addr) {
+  if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &p_dev->rc_addr) ||
+      absolute_volume_disabled() ||
+      (avdtp_source_active_peer_addr != p_dev->rc_addr &&
+       avdtp_sink_active_peer_addr != p_dev->rc_addr)) {
     p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
   }
 
@@ -518,7 +531,7 @@
   }
 
   BTIF_TRACE_DEBUG("%s: rc_features: 0x%x", __func__, rc_features);
-  HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features);
+  HAL_CBACK(bt_rc_callbacks, remote_features_cb, p_dev->rc_addr, rc_features);
 
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
   BTIF_TRACE_DEBUG(
@@ -572,9 +585,10 @@
    * to a browse when not connected to the control channel over AVRCP is
    * probably not preferred anyways. */
   if (p_rc_br_open->status == BTA_AV_SUCCESS) {
-    RawAddress rc_addr = p_dev->rc_addr;
     p_dev->br_connected = true;
-    HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, true, &rc_addr);
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true,
+                                true, p_dev->rc_addr));
   }
 }
 
@@ -632,8 +646,9 @@
 
   p_dev->rc_playing_uid = RC_INVALID_TRACK_ID;
   if (bt_rc_ctrl_callbacks != NULL) {
-    RawAddress rc_addr = p_dev->rc_addr;
-    HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, false, &rc_addr);
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true,
+                                false, p_dev->rc_addr));
   }
   /* report connection state if remote device is AVRCP target */
   handle_rc_ctrl_features(p_dev);
@@ -662,7 +677,12 @@
     BTIF_TRACE_ERROR("Got disconnect of unknown device");
     return;
   }
-  RawAddress rc_addr = p_dev->rc_addr;
+  /* report connection state if device is AVRCP target */
+  if (bt_rc_ctrl_callbacks != NULL) {
+    do_in_jni_thread(
+        FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, false,
+                              false, p_dev->rc_addr));
+  }
   /* Clean up AVRCP procedure flags */
   memset(&p_dev->rc_app_settings, 0, sizeof(btif_rc_player_app_settings_t));
   p_dev->rc_features_processed = false;
@@ -694,11 +714,6 @@
   }
 
   p_dev->rc_addr = RawAddress::kEmpty;
-  /* report connection state if device is AVRCP target */
-  if (bt_rc_ctrl_callbacks != NULL) {
-    HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, false,
-              &rc_addr);
-  }
 }
 
 /***************************************************************************
@@ -724,14 +739,13 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id: %d", __func__,
                    p_remote_cmd->rc_id);
 
   /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up
    * this PLAY */
-  if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected())) {
+  if ((p_remote_cmd->rc_id == AVRC_ID_PLAY) && (!btif_av_is_connected())) {
     if (p_remote_cmd->key_state == AVRC_STATE_PRESS) {
       APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command",
                          __func__);
@@ -741,14 +755,14 @@
   }
 
   /* If we previously queued a play and we get a PAUSE, clear it. */
-  if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (p_dev->rc_pending_play)) {
+  if ((p_remote_cmd->rc_id == AVRC_ID_PAUSE) && (p_dev->rc_pending_play)) {
     APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received",
                        __func__);
     p_dev->rc_pending_play = false;
     return;
   }
 
-  if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) &&
+  if ((p_remote_cmd->rc_id == AVRC_ID_STOP) &&
       (!btif_av_stream_started_ready())) {
     APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd", __func__);
     return;
@@ -760,7 +774,7 @@
   BTIF_TRACE_DEBUG("%s: rc_features: %d, cmd->rc_id: %d, pressed: %d", __func__,
                    p_dev->rc_features, p_remote_cmd->rc_id, pressed);
   HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed,
-            &rc_addr);
+            p_dev->rc_addr);
 }
 
 /***************************************************************************
@@ -781,7 +795,6 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG)) {
     BTIF_TRACE_ERROR("%s: DUT does not support AVRCP controller role",
@@ -795,8 +808,10 @@
 
   release_transaction(p_remote_rsp->label);
   if (bt_rc_ctrl_callbacks != NULL) {
-    HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, &rc_addr,
-              p_remote_rsp->rc_id, p_remote_rsp->key_state);
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->passthrough_rsp_cb, p_dev->rc_addr,
+                   p_remote_rsp->rc_id, p_remote_rsp->key_state));
   }
 }
 
@@ -839,8 +854,9 @@
                      status);
 
     release_transaction(p_remote_rsp->label);
-    HAL_CBACK(bt_rc_ctrl_callbacks, groupnavigation_rsp_cb, vendor_id,
-              key_state);
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(bt_rc_ctrl_callbacks->groupnavigation_rsp_cb,
+                                vendor_id, key_state));
   } else {
     BTIF_TRACE_ERROR("%s: Remote does not support AVRCP TG role", __func__);
   }
@@ -1074,18 +1090,11 @@
   }
 }
 
-/***************************************************************************
- **
- ** Function       btif_rc_get_connected_peer
- **
- ** Description    Fetches the connected headset's address if any
- **
- ***************************************************************************/
-bool btif_rc_get_connected_peer(RawAddress* peer_addr) {
+bool btif_rc_is_connected_peer(const RawAddress& peer_addr) {
   for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
     btif_rc_device_cb_t* p_dev = get_connected_device(idx);
-    if (p_dev != NULL && (p_dev->rc_connected == TRUE)) {
-      *peer_addr = p_dev->rc_addr;
+    if (p_dev != NULL && (p_dev->rc_connected == TRUE) &&
+        peer_addr == p_dev->rc_addr) {
       return true;
     }
   }
@@ -1101,7 +1110,7 @@
  ***************************************************************************/
 uint8_t btif_rc_get_connected_peer_handle(const RawAddress& peer_addr) {
   btif_rc_device_cb_t* p_dev = NULL;
-  p_dev = btif_rc_get_device_by_bda(&peer_addr);
+  p_dev = btif_rc_get_device_by_bda(peer_addr);
 
   if (p_dev == NULL) {
     BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
@@ -1123,7 +1132,7 @@
 void btif_rc_check_handle_pending_play(const RawAddress& peer_addr,
                                        bool bSendToApp) {
   btif_rc_device_cb_t* p_dev = NULL;
-  p_dev = btif_rc_get_device_by_bda(&peer_addr);
+  p_dev = btif_rc_get_device_by_bda(peer_addr);
 
   if (p_dev == NULL) {
     BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
@@ -1243,7 +1252,7 @@
       __func__, p_dev->rc_handle, index, label, code,
       dump_rc_pdu(pmetamsg_resp->rsp.pdu));
 
-  if (index >= 0 && p_dev->rc_pdu_info[index].is_rsp_pending == false) {
+  if (index >= 0 && !p_dev->rc_pdu_info[index].is_rsp_pending) {
     BTIF_TRACE_ERROR("%s: is_rsp_pending false, returning", __func__);
     return;
   }
@@ -1414,12 +1423,11 @@
   BTIF_TRACE_EVENT("%s: pdu: %s handle: 0x%x ctype: %x label: %x event ID: %x",
                    __func__, dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle,
                    ctype, label, pavrc_cmd->reg_notif.event_id);
-  RawAddress rc_addr = p_dev->rc_addr;
 
   switch (event) {
     case AVRC_PDU_GET_PLAY_STATUS: {
       fill_pdu_queue(IDX_GET_PLAY_STATUS_RSP, ctype, label, true, p_dev);
-      HAL_CBACK(bt_rc_callbacks, get_play_status_cb, &rc_addr);
+      HAL_CBACK(bt_rc_callbacks, get_play_status_cb, p_dev->rc_addr);
     } break;
     case AVRC_PDU_LIST_PLAYER_APP_ATTR:
     case AVRC_PDU_LIST_PLAYER_APP_VALUES:
@@ -1447,7 +1455,7 @@
       }
       fill_pdu_queue(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs,
-                &rc_addr);
+                p_dev->rc_addr);
     } break;
     case AVRC_PDU_REGISTER_NOTIFICATION: {
       if (pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
@@ -1463,12 +1471,12 @@
       }
       HAL_CBACK(bt_rc_callbacks, register_notification_cb,
                 (btrc_event_id_t)pavrc_cmd->reg_notif.event_id,
-                pavrc_cmd->reg_notif.param, &rc_addr);
+                pavrc_cmd->reg_notif.param, p_dev->rc_addr);
     } break;
     case AVRC_PDU_INFORM_DISPLAY_CHARSET: {
       tAVRC_RESPONSE avrc_rsp;
       BTIF_TRACE_EVENT("%s: AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__);
-      if (p_dev->rc_connected == true) {
+      if (p_dev->rc_connected) {
         memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
         avrc_rsp.inform_charset.opcode =
             opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
@@ -1510,19 +1518,20 @@
       fill_pdu_queue(IDX_GET_FOLDER_ITEMS_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, get_folder_items_cb,
                 pavrc_cmd->get_items.scope, pavrc_cmd->get_items.start_item,
-                pavrc_cmd->get_items.end_item, num_attr, attr_ids, &rc_addr);
+                pavrc_cmd->get_items.end_item, num_attr, attr_ids,
+                p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_SET_ADDRESSED_PLAYER: {
       fill_pdu_queue(IDX_SET_ADDR_PLAYER_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, set_addressed_player_cb,
-                pavrc_cmd->addr_player.player_id, &rc_addr);
+                pavrc_cmd->addr_player.player_id, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_SET_BROWSED_PLAYER: {
       fill_pdu_queue(IDX_SET_BROWSED_PLAYER_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb,
-                pavrc_cmd->br_player.player_id, &rc_addr);
+                pavrc_cmd->br_player.player_id, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_REQUEST_CONTINUATION_RSP: {
@@ -1558,14 +1567,14 @@
     case AVRC_PDU_CHANGE_PATH: {
       fill_pdu_queue(IDX_CHG_PATH_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction,
-                pavrc_cmd->chg_path.folder_uid, &rc_addr);
+                pavrc_cmd->chg_path.folder_uid, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_SEARCH: {
       fill_pdu_queue(IDX_SEARCH_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, search_cb, pavrc_cmd->search.string.charset_id,
                 pavrc_cmd->search.string.str_len,
-                pavrc_cmd->search.string.p_str, &rc_addr);
+                pavrc_cmd->search.string.p_str, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_GET_ITEM_ATTRIBUTES: {
@@ -1587,27 +1596,27 @@
                        num_attr);
       HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, pavrc_cmd->get_attrs.scope,
                 pavrc_cmd->get_attrs.uid, pavrc_cmd->get_attrs.uid_counter,
-                num_attr, item_attrs, &rc_addr);
+                num_attr, item_attrs, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: {
       fill_pdu_queue(IDX_GET_TOTAL_NUM_OF_ITEMS_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, get_total_num_of_items_cb,
-                pavrc_cmd->get_num_of_items.scope, &rc_addr);
+                pavrc_cmd->get_num_of_items.scope, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_ADD_TO_NOW_PLAYING: {
       fill_pdu_queue(IDX_ADD_TO_NOW_PLAYING_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, add_to_now_playing_cb,
                 pavrc_cmd->add_to_play.scope, pavrc_cmd->add_to_play.uid,
-                pavrc_cmd->add_to_play.uid_counter, &rc_addr);
+                pavrc_cmd->add_to_play.uid_counter, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_PLAY_ITEM: {
       fill_pdu_queue(IDX_PLAY_ITEM_RSP, ctype, label, true, p_dev);
       HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
                 pavrc_cmd->play_item.uid_counter, pavrc_cmd->play_item.uid,
-                &rc_addr);
+                p_dev->rc_addr);
     } break;
 
     default: {
@@ -1633,16 +1642,19 @@
                                            btif_rc_device_cb_t* p_dev) {
   BTIF_TRACE_DEBUG("%s: pdu: %s: handle: 0x%x", __func__,
                    dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle);
-  RawAddress rc_addr = p_dev->rc_addr;
   switch (event) {
     case AVRC_PDU_SET_ABSOLUTE_VOLUME:
-      HAL_CBACK(bt_rc_ctrl_callbacks, setabsvol_cmd_cb, &rc_addr,
-                pavrc_cmd->volume.volume, label);
+      do_in_jni_thread(
+          FROM_HERE,
+          base::Bind(bt_rc_ctrl_callbacks->setabsvol_cmd_cb, p_dev->rc_addr,
+                     pavrc_cmd->volume.volume, label));
       break;
     case AVRC_PDU_REGISTER_NOTIFICATION:
       if (pavrc_cmd->reg_notif.event_id == AVRC_EVT_VOLUME_CHANGE) {
-        HAL_CBACK(bt_rc_ctrl_callbacks, registernotification_absvol_cb,
-                  &rc_addr, label);
+        do_in_jni_thread(
+            FROM_HERE,
+            base::Bind(bt_rc_ctrl_callbacks->registernotification_absvol_cb,
+                       p_dev->rc_addr, label));
       }
       break;
   }
@@ -1664,14 +1676,13 @@
   BTIF_TRACE_EVENT("%s: pdu: %s: handle: 0x%x ctype: %x label: %x", __func__,
                    dump_rc_pdu(pavrc_resp->pdu), p_dev->rc_handle, ctype,
                    label);
-  RawAddress rc_addr = p_dev->rc_addr;
 
   switch (event) {
     case AVRC_PDU_REGISTER_NOTIFICATION: {
       if (AVRC_RSP_CHANGED == ctype)
         p_dev->rc_volume = pavrc_resp->reg_notif.param.volume;
       HAL_CBACK(bt_rc_callbacks, volume_change_cb,
-                pavrc_resp->reg_notif.param.volume, ctype, &rc_addr);
+                pavrc_resp->reg_notif.param.volume, ctype, p_dev->rc_addr);
     } break;
 
     case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
@@ -1682,7 +1693,7 @@
       if (AVRC_RSP_ACCEPT == ctype)
         p_dev->rc_volume = pavrc_resp->volume.volume;
       HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->volume.volume,
-                ctype, &rc_addr);
+                ctype, p_dev->rc_addr);
     } break;
 
     default:
@@ -1755,7 +1766,7 @@
     return;
   }
 
-  if (p_dev->rc_procedure_complete == true) {
+  if (p_dev->rc_procedure_complete) {
     return;
   }
   p_dev->rc_procedure_complete = true;
@@ -1778,7 +1789,7 @@
  * Returns          bt_status_t
  *
  **************************************************************************/
-static bt_status_t get_play_status_rsp(RawAddress* bd_addr,
+static bt_status_t get_play_status_rsp(const RawAddress& bd_addr,
                                        btrc_play_status_t play_status,
                                        uint32_t song_len, uint32_t song_pos) {
   tAVRC_RESPONSE avrc_rsp;
@@ -1818,7 +1829,8 @@
  * Returns          bt_status_t
  *
  **************************************************************************/
-static bt_status_t get_element_attr_rsp(RawAddress* bd_addr, uint8_t num_attr,
+static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr,
+                                        uint8_t num_attr,
                                         btrc_element_attr_val_t* p_attrs) {
   tAVRC_RESPONSE avrc_rsp;
   uint32_t i;
@@ -1893,7 +1905,7 @@
       continue;
     }
 
-    if (btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].bNotify == false) {
+    if (!btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].bNotify) {
       BTIF_TRACE_WARNING(
           "%s: Avrcp Event id is not registered: event_id: %x, handle: 0x%x",
           __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
@@ -1963,7 +1975,7 @@
  *                                            get_folder_items_list PDU
  *
  **************************************************************************/
-static bt_status_t get_folder_items_list_rsp(RawAddress* bd_addr,
+static bt_status_t get_folder_items_list_rsp(const RawAddress& bd_addr,
                                              btrc_status_t rsp_status,
                                              uint16_t uid_counter,
                                              uint8_t num_items,
@@ -1982,7 +1994,7 @@
   CHECK_RC_CONNECTED(p_dev);
 
   /* check if rsp to previous cmd was completed */
-  if (p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending == false) {
+  if (!p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending) {
     BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered",
                        __func__);
     return BT_STATUS_UNHANDLED;
@@ -2127,7 +2139,7 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t set_addressed_player_rsp(RawAddress* bd_addr,
+static bt_status_t set_addressed_player_rsp(const RawAddress& bd_addr,
                                             btrc_status_t rsp_status) {
   tAVRC_RESPONSE avrc_rsp;
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
@@ -2165,7 +2177,7 @@
  *                                            set_browsed_player PDU
  *
  **************************************************************************/
-static bt_status_t set_browsed_player_rsp(RawAddress* bd_addr,
+static bt_status_t set_browsed_player_rsp(const RawAddress& bd_addr,
                                           btrc_status_t rsp_status,
                                           uint32_t num_items,
                                           uint16_t charset_id,
@@ -2193,7 +2205,7 @@
                    __func__, rsp_status, avrc_rsp.br_player.status);
 
   /* check if rsp to previous cmd was completed */
-  if (p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending == false) {
+  if (!p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending) {
     BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered",
                        __func__);
     return BT_STATUS_UNHANDLED;
@@ -2283,7 +2295,7 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t change_path_rsp(RawAddress* bd_addr,
+static bt_status_t change_path_rsp(const RawAddress& bd_addr,
                                    btrc_status_t rsp_status,
                                    uint32_t num_items) {
   tAVRC_RESPONSE avrc_rsp;
@@ -2316,8 +2328,9 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t search_rsp(RawAddress* bd_addr, btrc_status_t rsp_status,
-                              uint32_t uid_counter, uint32_t num_items) {
+static bt_status_t search_rsp(const RawAddress& bd_addr,
+                              btrc_status_t rsp_status, uint32_t uid_counter,
+                              uint32_t num_items) {
   tAVRC_RESPONSE avrc_rsp;
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
 
@@ -2349,7 +2362,7 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t get_item_attr_rsp(RawAddress* bd_addr,
+static bt_status_t get_item_attr_rsp(const RawAddress& bd_addr,
                                      btrc_status_t rsp_status, uint8_t num_attr,
                                      btrc_element_attr_val_t* p_attrs) {
   tAVRC_RESPONSE avrc_rsp;
@@ -2391,7 +2404,7 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t add_to_now_playing_rsp(RawAddress* bd_addr,
+static bt_status_t add_to_now_playing_rsp(const RawAddress& bd_addr,
                                           btrc_status_t rsp_status) {
   tAVRC_RESPONSE avrc_rsp;
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
@@ -2423,7 +2436,7 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t play_item_rsp(RawAddress* bd_addr,
+static bt_status_t play_item_rsp(const RawAddress& bd_addr,
                                  btrc_status_t rsp_status) {
   tAVRC_RESPONSE avrc_rsp;
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
@@ -2455,7 +2468,7 @@
  *                      BT_STATUS_SUCCESS   - always if RC is connected
  *
  **************************************************************************/
-static bt_status_t get_total_num_of_items_rsp(RawAddress* bd_addr,
+static bt_status_t get_total_num_of_items_rsp(const RawAddress& bd_addr,
                                               btrc_status_t rsp_status,
                                               uint32_t uid_counter,
                                               uint32_t num_items) {
@@ -2498,15 +2511,9 @@
 static bt_status_t set_volume(uint8_t volume) {
   BTIF_TRACE_DEBUG("%s: volume: %d", __func__, volume);
   tAVRC_STS status = BT_STATUS_UNSUPPORTED;
-  rc_transaction_t* p_transaction = NULL;
 
   for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
-    if (!btif_rc_cb.rc_multi_cb[idx].rc_connected) {
-      status = BT_STATUS_NOT_READY;
-      BTIF_TRACE_ERROR("%s: RC is not connected for device: 0x%x", __func__,
-                       btif_rc_cb.rc_multi_cb[idx].rc_addr);
-      continue;
-    }
+    if (!btif_rc_cb.rc_multi_cb[idx].rc_connected) continue;
 
     if (btif_rc_cb.rc_multi_cb[idx].rc_volume == volume) {
       status = BT_STATUS_DONE;
@@ -2515,49 +2522,54 @@
       continue;
     }
 
-    if ((btif_rc_cb.rc_multi_cb[idx].rc_volume != volume) &&
-        btif_rc_cb.rc_multi_cb[idx].rc_state ==
+    if ((btif_rc_cb.rc_multi_cb[idx].rc_volume == volume) ||
+        btif_rc_cb.rc_multi_cb[idx].rc_state !=
             BTRC_CONNECTION_STATE_CONNECTED) {
-      if ((btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_RCTG) == 0) {
-        status = BT_STATUS_NOT_READY;
-        continue;
-      } else {
-        tAVRC_COMMAND avrc_cmd = {0};
-        BT_HDR* p_msg = NULL;
-
-        if (btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_ADV_CTRL) {
-          BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
-                           __func__, volume);
-          avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
-          avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
-          avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
-          avrc_cmd.volume.volume = volume;
-
-          if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
-            bt_status_t tran_status = get_transaction(&p_transaction);
-
-            if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) {
-              BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
-                               __func__, p_transaction->lbl);
-              BTA_AvMetaCmd(btif_rc_cb.rc_multi_cb[idx].rc_handle,
-                            p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
-              status = BT_STATUS_SUCCESS;
-            } else {
-              osi_free_and_reset((void**)&p_msg);
-              BTIF_TRACE_ERROR(
-                  "%s: failed to obtain transaction details. status: 0x%02x",
-                  __func__, tran_status);
-              status = BT_STATUS_FAIL;
-            }
-          } else {
-            BTIF_TRACE_ERROR(
-                "%s: failed to build absolute volume command. status: 0x%02x",
-                __func__, status);
-            status = BT_STATUS_FAIL;
-          }
-        }
-      }
+      continue;
     }
+
+    if ((btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_RCTG) == 0) {
+      status = BT_STATUS_NOT_READY;
+      continue;
+    }
+
+    if (!(btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_ADV_CTRL))
+      continue;
+
+    BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
+                     __func__, volume);
+
+    tAVRC_COMMAND avrc_cmd = {.volume = {.opcode = AVRC_OP_VENDOR,
+                                         .pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME,
+                                         .status = AVRC_STS_NO_ERROR,
+                                         .volume = volume}};
+
+    BT_HDR* p_msg = NULL;
+    if (AVRC_BldCommand(&avrc_cmd, &p_msg) != AVRC_STS_NO_ERROR) {
+      BTIF_TRACE_ERROR(
+          "%s: failed to build absolute volume command. status: 0x%02x",
+          __func__, status);
+      status = BT_STATUS_FAIL;
+      continue;
+    }
+
+    rc_transaction_t* p_transaction = NULL;
+    bt_status_t tran_status = get_transaction(&p_transaction);
+
+    if (tran_status != BT_STATUS_SUCCESS || !p_transaction) {
+      osi_free_and_reset((void**)&p_msg);
+      BTIF_TRACE_ERROR(
+          "%s: failed to obtain transaction details. status: 0x%02x", __func__,
+          tran_status);
+      status = BT_STATUS_FAIL;
+      continue;
+    }
+
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvMetaCmd(btif_rc_cb.rc_multi_cb[idx].rc_handle, p_transaction->lbl,
+                  AVRC_CMD_CTRL, p_msg);
+    status = BT_STATUS_SUCCESS;
   }
   return (bt_status_t)status;
 }
@@ -2726,7 +2738,7 @@
 bool iterate_supported_event_list_for_timeout(void* data, void* cb_data) {
   rc_context_t* cntxt = (rc_context_t*)cb_data;
   uint8_t label = cntxt->label & 0xFF;
-  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(&cntxt->rc_addr);
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(cntxt->rc_addr);
   btif_rc_supported_event_t* p_event = (btif_rc_supported_event_t*)data;
 
   if (p_event->label == label) {
@@ -2792,7 +2804,7 @@
 
   p_context = (btif_rc_timer_context_t*)data;
   memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
-  p_dev = btif_rc_get_device_by_bda(&p_context->rc_addr);
+  p_dev = btif_rc_get_device_by_bda(p_context->rc_addr);
   if (p_dev == NULL) {
     BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
     return;
@@ -2877,7 +2889,7 @@
   btif_rc_timer_context_t* p_context = (btif_rc_timer_context_t*)data;
   tAVRC_RESPONSE avrc_response = {0};
   tBTA_AV_META_MSG meta_msg;
-  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(&p_context->rc_addr);
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(p_context->rc_addr);
   if (p_dev == NULL) {
     BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
     return;
@@ -3112,6 +3124,7 @@
       if ((p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_STATUS_CHANGE) ||
           (p_rsp->param.event_id[xx] == AVRC_EVT_TRACK_CHANGE) ||
           (p_rsp->param.event_id[xx] == AVRC_EVT_APP_SETTING_CHANGE) ||
+          (p_rsp->param.event_id[xx] == AVRC_EVT_ADDR_PLAYER_CHANGE) ||
           (p_rsp->param.event_id[xx] == AVRC_EVT_UIDS_CHANGE)) {
         p_event = (btif_rc_supported_event_t*)osi_malloc(
             sizeof(btif_rc_supported_event_t));
@@ -3179,7 +3192,6 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (pmeta_msg->code == AVRC_RSP_INTERIM) {
     btif_rc_supported_event_t* p_event;
@@ -3191,11 +3203,16 @@
         /* Start timer to get play status periodically
          * if the play state is playing.
          */
-        if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING) {
+        if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING ||
+            p_rsp->param.play_status == AVRC_PLAYSTATE_REV_SEEK ||
+            p_rsp->param.play_status == AVRC_PLAYSTATE_FWD_SEEK) {
           rc_start_play_status_timer(p_dev);
         }
-        HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb, &rc_addr,
-                  (btrc_play_status_t)p_rsp->param.play_status);
+        do_in_jni_thread(
+            FROM_HERE,
+            base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb,
+                       p_dev->rc_addr,
+                       (btrc_play_status_t)p_rsp->param.play_status));
         break;
 
       case AVRC_EVT_TRACK_CHANGE:
@@ -3220,6 +3237,9 @@
         break;
 
       case AVRC_EVT_ADDR_PLAYER_CHANGE:
+        do_in_jni_thread(
+            FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->set_addressed_player_cb,
+                                  p_dev->rc_addr, BTRC_STS_ADDR_PLAY_CHGD));
         break;
 
       case AVRC_EVT_UIDS_CHANGE:
@@ -3252,7 +3272,7 @@
       p_event = NULL;
     }
     /* Registered for all events, we can request application settings */
-    if (p_event == NULL && p_dev->rc_app_settings.query_started == false) {
+    if (p_event == NULL && !p_dev->rc_app_settings.query_started) {
       /* we need to do this only if remote TG supports
        * player application settings
        */
@@ -3296,8 +3316,11 @@
         } else {
           rc_stop_play_status_timer(p_dev);
         }
-        HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb, &rc_addr,
-                  (btrc_play_status_t)p_rsp->param.play_status);
+        do_in_jni_thread(
+            FROM_HERE,
+            base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb,
+                       p_dev->rc_addr,
+                       (btrc_play_status_t)p_rsp->param.play_status));
 
         break;
 
@@ -3318,8 +3341,11 @@
           app_settings.attr_values[xx] =
               p_rsp->param.player_setting.attr_value[xx];
         }
-        HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
-                  &rc_addr, &app_settings);
+        do_in_jni_thread(
+            FROM_HERE,
+            base::Bind(
+                bt_rc_ctrl_callbacks->playerapplicationsetting_changed_cb,
+                p_dev->rc_addr, app_settings));
       } break;
 
       case AVRC_EVT_NOW_PLAYING_CHANGE:
@@ -3421,7 +3447,6 @@
   }
 
   p_app_settings = &p_dev->rc_app_settings;
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (p_app_settings->attr_index < p_app_settings->num_attrs) {
     attr_index = p_app_settings->attr_index;
@@ -3444,8 +3469,11 @@
         attrs[xx] = p_app_settings->attrs[xx].attr_id;
       }
       get_player_app_setting_cmd(p_app_settings->num_attrs, attrs, p_dev);
-      HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
-                p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+      do_in_jni_thread(
+          FROM_HERE,
+          base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb,
+                     p_dev->rc_addr, p_app_settings->num_attrs,
+                     p_app_settings->attrs, 0, nullptr));
     }
   } else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs) {
     attr_index = p_app_settings->ext_attr_index;
@@ -3500,7 +3528,6 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   app_settings.num_attr = p_rsp->num_val;
 
@@ -3514,8 +3541,10 @@
     app_settings.attr_values[xx] = p_rsp->p_vals[xx].attr_val;
   }
 
-  HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb, &rc_addr,
-            &app_settings);
+  do_in_jni_thread(
+      FROM_HERE,
+      base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_changed_cb,
+                 p_dev->rc_addr, app_settings));
   /* Application settings are fetched only once for initial values
    * initiate anything that follows after RC procedure.
    * Defer it if browsing is supported till players query
@@ -3548,7 +3577,6 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
   p_app_settings = &p_dev->rc_app_settings;
 
   /* Todo: Do we need to retry on command timeout */
@@ -3572,8 +3600,11 @@
         attrs[xx] = p_app_settings->attrs[xx].attr_id;
       }
 
-      HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
-                p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+      do_in_jni_thread(
+          FROM_HERE,
+          base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb,
+                     p_dev->rc_addr, p_app_settings->num_attrs,
+                     p_app_settings->attrs, 0, nullptr));
       get_player_app_setting_cmd(xx, attrs, p_dev);
     }
     return;
@@ -3621,7 +3652,6 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
   p_app_settings = &p_dev->rc_app_settings;
 
   /* Todo: Do we need to retry on command timeout */
@@ -3650,8 +3680,10 @@
     for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
       attrs[xx] = p_app_settings->attrs[xx].attr_id;
     }
-    HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
-              p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+    do_in_jni_thread(
+        FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb,
+                              p_dev->rc_addr, p_app_settings->num_attrs,
+                              p_app_settings->attrs, 0, nullptr));
 
     get_player_app_setting_cmd(xx, attrs, p_dev);
     return;
@@ -3687,29 +3719,46 @@
     for (x = 0; x < p_app_settings->num_ext_attrs; x++) {
       attrs[xx + x] = p_app_settings->ext_attrs[x].attr_id;
     }
-    HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
-              p_app_settings->num_attrs, p_app_settings->attrs,
-              p_app_settings->num_ext_attrs, p_app_settings->ext_attrs);
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb,
+                   p_dev->rc_addr, p_app_settings->num_attrs,
+                   p_app_settings->attrs, p_app_settings->num_ext_attrs,
+                   p_app_settings->ext_attrs));
     get_player_app_setting_cmd(xx + x, attrs, p_dev);
 
     /* Free the application settings information after sending to
      * application.
      */
-    for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
-      int x;
-      btrc_player_app_ext_attr_t* p_ext_attr = &p_app_settings->ext_attrs[xx];
-
-      for (x = 0; x < p_ext_attr->num_val; x++)
-        osi_free_and_reset((void**)&p_ext_attr->ext_attr_val[x].p_str);
-      p_ext_attr->num_val = 0;
-      osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
-    }
+    do_in_jni_thread(FROM_HERE, base::Bind(cleanup_app_attr_val_txt_response,
+                                           p_app_settings));
     p_app_settings->num_attrs = 0;
   }
 }
 
 /***************************************************************************
  *
+ * Function         cleanup_app_attr_val_txt_response
+ *
+ * Description      Frees the memory that was allocated for reporting player
+ *                  application settings.
+ * Returns          None
+ **************************************************************************/
+static void cleanup_app_attr_val_txt_response(
+    btif_rc_player_app_settings_t* p_app_settings) {
+  for (uint8_t xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+    int x;
+    btrc_player_app_ext_attr_t* p_ext_attr = &p_app_settings->ext_attrs[xx];
+    for (x = 0; x < p_ext_attr->num_val; x++) {
+      osi_free_and_reset((void**)&p_ext_attr->ext_attr_val[x].p_str);
+    }
+    p_ext_attr->num_val = 0;
+    osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+  }
+}
+
+/***************************************************************************
+ *
  * Function         handle_set_app_attr_val_response
  *
  * Description      handles the the set attributes value response, if fails
@@ -3728,7 +3777,6 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   /* For timeout pmeta_msg will be NULL, else we need to
    * check if this is accepted by TG
@@ -3736,8 +3784,9 @@
   if (pmeta_msg && (pmeta_msg->code == AVRC_RSP_ACCEPT)) {
     accepted = 1;
   }
-  HAL_CBACK(bt_rc_ctrl_callbacks, setplayerappsetting_rsp_cb, &rc_addr,
-            accepted);
+  do_in_jni_thread(FROM_HERE,
+                   base::Bind(bt_rc_ctrl_callbacks->setplayerappsetting_rsp_cb,
+                              p_dev->rc_addr, accepted));
 }
 
 /***************************************************************************
@@ -3764,7 +3813,6 @@
       return;
     }
 
-    RawAddress rc_addr = p_dev->rc_addr;
 
     for (int i = 0; i < p_rsp->num_attrs; i++) {
       p_attr[i].attr_id = p_rsp->p_attrs[i].attr_id;
@@ -3775,9 +3823,10 @@
         osi_free_and_reset((void**)&p_rsp->p_attrs[i].name.p_str);
       }
     }
-    HAL_CBACK(bt_rc_ctrl_callbacks, track_changed_cb, &rc_addr,
-              p_rsp->num_attrs, p_attr);
-    osi_free(p_attr);
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(bt_rc_ctrl_callbacks->track_changed_cb,
+                                p_dev->rc_addr, p_rsp->num_attrs, p_attr));
+    do_in_jni_thread(FROM_HERE, base::Bind(osi_free, p_attr));
   } else if (p_rsp->status == BTIF_RC_STS_TIMEOUT) {
     /* Retry for timeout case, this covers error handling
      * for continuation failure also.
@@ -3814,11 +3863,12 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (p_rsp->status == AVRC_STS_NO_ERROR) {
-    HAL_CBACK(bt_rc_ctrl_callbacks, play_position_changed_cb, &rc_addr,
-              p_rsp->song_len, p_rsp->song_pos);
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb,
+                   p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos));
   } else {
     BTIF_TRACE_ERROR("%s: Error in get play status procedure: %d", __func__,
                      p_rsp->status);
@@ -3845,11 +3895,11 @@
     return;
   }
 
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (p_rsp->status == AVRC_STS_NO_ERROR) {
-    HAL_CBACK(bt_rc_ctrl_callbacks, set_addressed_player_cb, &rc_addr,
-              p_rsp->status);
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(bt_rc_ctrl_callbacks->set_addressed_player_cb,
+                                p_dev->rc_addr, p_rsp->status));
   } else {
     BTIF_TRACE_ERROR("%s: Error in get play status procedure %d", __func__,
                      p_rsp->status);
@@ -3869,7 +3919,6 @@
                                              tAVRC_GET_ITEMS_RSP* p_rsp) {
   btif_rc_device_cb_t* p_dev =
       btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (p_rsp->status == AVRC_STS_NO_ERROR) {
     /* Convert the internal folder listing into a response that can
@@ -3886,6 +3935,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;
 
@@ -3905,20 +3958,54 @@
       }
     }
 
-    HAL_CBACK(bt_rc_ctrl_callbacks, get_folder_items_cb, &rc_addr,
-              BTRC_STS_NO_ERROR,
-              /* We want to make the ownership explicit in native */
-              (const btrc_folder_items_t*)btrc_items, item_count);
-    BTIF_TRACE_DEBUG("%s HAL CBACK get_folder_items_cb finished", __func__);
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->get_folder_items_cb, p_dev->rc_addr,
+                   BTRC_STS_NO_ERROR,
+                   /* We want to make the ownership explicit in native */
+                   btrc_items, item_count));
 
-    /* Release the memory block for items since we OWN the object */
-    osi_free(btrc_items);
+    /* Release the memory block for items and attributes allocated here.
+     * Since the executor for do_in_jni_thread is a Single Thread Task Runner it
+     * is okay to queue up the cleanup of btrc_items */
+    do_in_jni_thread(FROM_HERE, base::Bind(cleanup_btrc_folder_items,
+                                           btrc_items, item_count));
+
+    BTIF_TRACE_DEBUG("%s get_folder_items_cb sent to JNI thread", __func__);
   } else {
     BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status);
-    HAL_CBACK(bt_rc_ctrl_callbacks, get_folder_items_cb, &rc_addr,
-              (btrc_status_t)p_rsp->status, NULL, 0);
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->get_folder_items_cb, p_dev->rc_addr,
+                   (btrc_status_t)p_rsp->status, nullptr, 0));
   }
 }
+/***************************************************************************
+ *
+ * Function         cleanup_btrc_folder_items
+ *
+ * Description      Frees the memory that was allocated for a list of folder
+ *                  items.
+ * Returns          None
+ **************************************************************************/
+static void cleanup_btrc_folder_items(btrc_folder_items_t* btrc_items,
+                                      uint8_t item_count) {
+  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);
+}
 
 /***************************************************************************
  *
@@ -3959,11 +4046,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]);
@@ -4084,6 +4166,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);
@@ -4106,11 +4190,11 @@
                                         tAVRC_CHG_PATH_RSP* p_rsp) {
   btif_rc_device_cb_t* p_dev =
       btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (p_rsp->status == AVRC_STS_NO_ERROR) {
-    HAL_CBACK(bt_rc_ctrl_callbacks, change_folder_path_cb, &rc_addr,
-              p_rsp->num_items);
+    do_in_jni_thread(FROM_HERE,
+                     base::Bind(bt_rc_ctrl_callbacks->change_folder_path_cb,
+                                p_dev->rc_addr, p_rsp->num_items));
   } else {
     BTIF_TRACE_ERROR("%s error in handle_change_path_response %d", __func__,
                      p_rsp->status);
@@ -4130,11 +4214,12 @@
                                                tAVRC_SET_BR_PLAYER_RSP* p_rsp) {
   btif_rc_device_cb_t* p_dev =
       btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
-  RawAddress rc_addr = p_dev->rc_addr;
 
   if (p_rsp->status == AVRC_STS_NO_ERROR) {
-    HAL_CBACK(bt_rc_ctrl_callbacks, set_browsed_player_cb, &rc_addr,
-              p_rsp->num_items, p_rsp->folder_depth);
+    do_in_jni_thread(
+        FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->set_browsed_player_cb, p_dev->rc_addr,
+                   p_rsp->num_items, p_rsp->folder_depth));
   } else {
     BTIF_TRACE_ERROR("%s error %d", __func__, p_rsp->status);
   }
@@ -4479,7 +4564,7 @@
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t get_playback_state_cmd(RawAddress* bd_addr) {
+static bt_status_t get_playback_state_cmd(const RawAddress& bd_addr) {
   BTIF_TRACE_DEBUG("%s", __func__);
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
   return get_play_status_cmd(p_dev);
@@ -4492,18 +4577,18 @@
  * Description      Fetch the now playing list
  *
  * Paramters        start_item: First item to fetch (0 to fetch from beganning)
- *                  end_item: Last item to fetch (0xff to fetch until end)
+ *                  end_item: Last item to fetch (0xffffffff to fetch until end)
  *
  * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t get_now_playing_list_cmd(RawAddress* bd_addr,
-                                            uint8_t start_item,
-                                            uint8_t num_items) {
-  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+static bt_status_t get_now_playing_list_cmd(const RawAddress& bd_addr,
+                                            uint32_t start_item,
+                                            uint32_t end_item) {
+  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, end_item);
   return get_folder_items_cmd(bd_addr, AVRC_SCOPE_NOW_PLAYING, start_item,
-                              num_items);
+                              end_item);
 }
 
 /***************************************************************************
@@ -4513,17 +4598,17 @@
  * Description      Fetch the currently selected folder list
  *
  * Paramters        start_item: First item to fetch (0 to fetch from beganning)
- *                  end_item: Last item to fetch (0xff to fetch until end)
+ *                  end_item: Last item to fetch (0xffffffff to fetch until end)
  *
  * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t get_folder_list_cmd(RawAddress* bd_addr, uint8_t start_item,
-                                       uint8_t num_items) {
-  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+static bt_status_t get_folder_list_cmd(const RawAddress& bd_addr,
+                                       uint32_t start_item, uint32_t end_item) {
+  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, end_item);
   return get_folder_items_cmd(bd_addr, AVRC_SCOPE_FILE_SYSTEM, start_item,
-                              num_items);
+                              end_item);
 }
 
 /***************************************************************************
@@ -4533,17 +4618,17 @@
  * Description      Fetch the player list
  *
  * Paramters        start_item: First item to fetch (0 to fetch from beganning)
- *                  end_item: Last item to fetch (0xff to fetch until end)
+ *                  end_item: Last item to fetch (0xffffffff to fetch until end)
  *
  * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t get_player_list_cmd(RawAddress* bd_addr, uint8_t start_item,
-                                       uint8_t num_items) {
-  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+static bt_status_t get_player_list_cmd(const RawAddress& bd_addr,
+                                       uint32_t start_item, uint32_t end_item) {
+  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, end_item);
   return get_folder_items_cmd(bd_addr, AVRC_SCOPE_PLAYER_LIST, start_item,
-                              num_items);
+                              end_item);
 }
 
 /***************************************************************************
@@ -4555,13 +4640,13 @@
  * Paramters        direction: Direction (Up/Down) to change folder
  *                  uid: The UID of folder to move to
  *                  start_item: First item to fetch (0 to fetch from beganning)
- *                  end_item: Last item to fetch (0xff to fetch until end)
+ *                  end_item: Last item to fetch (0xffffffff to fetch until end)
  *
  * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t change_folder_path_cmd(RawAddress* bd_addr,
+static bt_status_t change_folder_path_cmd(const RawAddress& bd_addr,
                                           uint8_t direction, uint8_t* uid) {
   BTIF_TRACE_DEBUG("%s: direction %d", __func__, direction);
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
@@ -4613,7 +4698,8 @@
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t set_browsed_player_cmd(RawAddress* bd_addr, uint16_t id) {
+static bt_status_t set_browsed_player_cmd(const RawAddress& bd_addr,
+                                          uint16_t id) {
   BTIF_TRACE_DEBUG("%s: id %d", __func__, id);
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
   CHECK_RC_CONNECTED(p_dev);
@@ -4660,7 +4746,8 @@
  **                  BT_STATUS_FAIL.
  **
  ***************************************************************************/
-static bt_status_t set_addressed_player_cmd(RawAddress* bd_addr, uint16_t id) {
+static bt_status_t set_addressed_player_cmd(const RawAddress& bd_addr,
+                                            uint16_t id) {
   BTIF_TRACE_DEBUG("%s: id %d", __func__, id);
 
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
@@ -4707,14 +4794,15 @@
  * Paramters        scope: AVRC_SCOPE_NOW_PLAYING (etc) for various browseable
  *                  content
  *                  start_item: First item to fetch (0 to fetch from beganning)
- *                  end_item: Last item to fetch (0xff to fetch until end)
+ *                  end_item: Last item to fetch (0xffff to fetch until end)
  *
  * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
  *                  BT_STATUS_FAIL.
  *
  **************************************************************************/
-static bt_status_t get_folder_items_cmd(RawAddress* bd_addr, uint8_t scope,
-                                        uint8_t start_item, uint8_t end_item) {
+static bt_status_t get_folder_items_cmd(const RawAddress& bd_addr,
+                                        uint8_t scope, uint32_t start_item,
+                                        uint32_t end_item) {
   /* Check that both avrcp and browse channel are connected. */
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
   BTIF_TRACE_DEBUG("%s", __func__);
@@ -4764,7 +4852,7 @@
  * Returns          void
  *
  **************************************************************************/
-static bt_status_t change_player_app_setting(RawAddress* bd_addr,
+static bt_status_t change_player_app_setting(const RawAddress& bd_addr,
                                              uint8_t num_attrib,
                                              uint8_t* attrib_ids,
                                              uint8_t* attrib_vals) {
@@ -4798,7 +4886,7 @@
  * Returns          void
  *
  **************************************************************************/
-static bt_status_t play_item_cmd(RawAddress* bd_addr, uint8_t scope,
+static bt_status_t play_item_cmd(const RawAddress& bd_addr, uint8_t scope,
                                  uint8_t* uid, uint16_t uid_counter) {
   BTIF_TRACE_DEBUG("%s: scope %d uid_counter %d", __func__, scope, uid_counter);
   btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
@@ -4968,7 +5056,7 @@
  * Returns          void
  *
  **************************************************************************/
-static bt_status_t set_volume_rsp(RawAddress* bd_addr, uint8_t abs_vol,
+static bt_status_t set_volume_rsp(const RawAddress& bd_addr, uint8_t abs_vol,
                                   uint8_t label) {
   tAVRC_STS status = BT_STATUS_UNSUPPORTED;
   tAVRC_RESPONSE avrc_rsp;
@@ -4989,7 +5077,7 @@
     BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
                      p_dev->rc_vol_label);
     if (p_msg != NULL) {
-      BTA_AvVendorRsp(p_dev->rc_handle, label, BTA_AV_RSP_ACCEPT, data_start,
+      BTA_AvVendorRsp(p_dev->rc_handle, label, AVRC_RSP_ACCEPT, data_start,
                       p_msg->len, 0);
       status = BT_STATUS_SUCCESS;
     }
@@ -5011,8 +5099,8 @@
  *
  **************************************************************************/
 static bt_status_t volume_change_notification_rsp(
-    RawAddress* bd_addr, btrc_notification_type_t rsp_type, uint8_t abs_vol,
-    uint8_t label) {
+    const RawAddress& bd_addr, btrc_notification_type_t rsp_type,
+    uint8_t abs_vol, uint8_t label) {
   tAVRC_STS status = BT_STATUS_UNSUPPORTED;
   tAVRC_RESPONSE avrc_rsp;
   BT_HDR* p_msg = NULL;
@@ -5057,7 +5145,7 @@
  * Returns          void
  *
  **************************************************************************/
-static bt_status_t send_groupnavigation_cmd(RawAddress* bd_addr,
+static bt_status_t send_groupnavigation_cmd(const RawAddress& bd_addr,
                                             uint8_t key_code,
                                             uint8_t key_state) {
   tAVRC_STS status = BT_STATUS_UNSUPPORTED;
@@ -5102,8 +5190,8 @@
  * Returns          void
  *
  **************************************************************************/
-static bt_status_t send_passthrough_cmd(RawAddress* bd_addr, uint8_t key_code,
-                                        uint8_t key_state) {
+static bt_status_t send_passthrough_cmd(const RawAddress& bd_addr,
+                                        uint8_t key_code, uint8_t key_state) {
   tAVRC_STS status = BT_STATUS_UNSUPPORTED;
   btif_rc_device_cb_t* p_dev = NULL;
   BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda", __func__);
@@ -5213,7 +5301,7 @@
  *      Returns          void
  ******************************************************************************/
 static void initialize_transaction(int lbl) {
-  std::unique_lock<std::recursive_mutex>(device.lbllock);
+  std::unique_lock<std::recursive_mutex> lock(device.lbllock);
   if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
     if (alarm_is_scheduled(device.transaction[lbl].txn_timer)) {
       clear_cmd_timeout(lbl);
@@ -5266,7 +5354,7 @@
 
   /* Determine if this is a valid label */
   if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
-    if (false == device.transaction[lbl].in_use) {
+    if (!device.transaction[lbl].in_use) {
       transaction = NULL;
     } else {
       transaction = &(device.transaction[lbl]);
@@ -5291,7 +5379,7 @@
 
   // Check for unused transactions
   for (uint8_t i = 0; i < MAX_TRANSACTIONS_PER_SESSION; i++) {
-    if (false == device.transaction[i].in_use) {
+    if (!device.transaction[i].in_use) {
       BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__,
                        device.transaction[i].lbl);
       device.transaction[i].in_use = true;
diff --git a/btif/src/btif_sdp.cc b/btif/src/btif_sdp.cc
index de39c42..d7c3f67 100644
--- a/btif/src/btif_sdp.cc
+++ b/btif/src/btif_sdp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright (C) 2014 Samsung System LSI
+ * Copyright 2014 Samsung System LSI
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -40,6 +40,8 @@
 #include "btif_profile_queue.h"
 #include "btif_util.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Functions implemented in sdp_server.c
  *****************************************************************************/
@@ -64,16 +66,13 @@
 
 static void btif_sdp_search_comp_evt(uint16_t event, char* p_param) {
   tBTA_SDP_SEARCH_COMP* evt_data = (tBTA_SDP_SEARCH_COMP*)p_param;
-  RawAddress addr;
   BTIF_TRACE_DEBUG("%s:  event = %d", __func__, event);
 
   if (event != BTA_SDP_SEARCH_COMP_EVT) return;
 
-  addr = evt_data->remote_addr;
-
   HAL_CBACK(bt_sdp_callbacks, sdp_search_cb, (bt_status_t)evt_data->status,
-            &addr, (uint8_t*)(evt_data->uuid.uu.uuid128),
-            evt_data->record_count, evt_data->records);
+            evt_data->remote_addr, evt_data->uuid, evt_data->record_count,
+            evt_data->records);
 }
 
 static void sdp_search_comp_copy_cb(uint16_t event, char* p_dest, char* p_src) {
@@ -137,13 +136,8 @@
   return BT_STATUS_SUCCESS;
 }
 
-static bt_status_t search(RawAddress* bd_addr, const uint8_t* uuid) {
-  tSDP_UUID sdp_uuid;
-  sdp_uuid.len = 16;
-  memcpy(sdp_uuid.uu.uuid128, uuid, sizeof(sdp_uuid.uu.uuid128));
-
-  BTA_SdpSearch(*bd_addr, &sdp_uuid);
-
+static bt_status_t search(RawAddress* bd_addr, const Uuid& uuid) {
+  BTA_SdpSearch(*bd_addr, uuid);
   return BT_STATUS_SUCCESS;
 }
 
diff --git a/btif/src/btif_sdp_server.cc b/btif/src/btif_sdp_server.cc
index b84d694..4738da4 100644
--- a/btif/src/btif_sdp_server.cc
+++ b/btif/src/btif_sdp_server.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright (C) 2014 Samsung System LSI
+ * Copyright 2014 Samsung System LSI
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -356,7 +356,7 @@
   if (handle != -1 && handle != 0) {
     bool result;
     result = SDP_DeleteRecord(handle);
-    if (result == false) {
+    if (!result) {
       BTIF_TRACE_ERROR("  Unable to remove handle 0x%08x", handle);
     }
   }
diff --git a/btif/src/btif_sm.cc b/btif/src/btif_sm.cc
deleted file mode 100644
index 8f7bbb2..0000000
--- a/btif/src/btif_sm.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 2009-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/*****************************************************************************
- *
- *  Filename:      btif_sm.c
- *
- *  Description:   Generic BTIF state machine API
- *
- *****************************************************************************/
-
-#define LOG_TAG "bt_btif"
-
-#include "btif_sm.h"
-
-#include "bt_common.h"
-#include "btif_common.h"
-#include "osi/include/allocator.h"
-
-/*****************************************************************************
- *  Local type definitions
- *****************************************************************************/
-typedef struct {
-  btif_sm_state_t state;
-  btif_sm_handler_t* p_handlers;
-} btif_sm_cb_t;
-
-/*****************************************************************************
- *  Functions
- *****************************************************************************/
-
-/*****************************************************************************
- *
- * Function     btif_sm_init
- *
- * Description  Initializes the state machine with the state handlers
- *              The caller should ensure that the table and the corresponding
- *              states match. The location that 'p_handlers' points to shall
- *              be available until the btif_sm_shutdown API is invoked.
- *
- * Returns      Returns a pointer to the initialized state machine handle.
- *
- *****************************************************************************/
-
-btif_sm_handle_t btif_sm_init(const btif_sm_handler_t* p_handlers,
-                              btif_sm_state_t initial_state) {
-  if (p_handlers == NULL) {
-    BTIF_TRACE_ERROR("%s : p_handlers is NULL", __func__);
-    return NULL;
-  }
-
-  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)osi_malloc(sizeof(btif_sm_cb_t));
-  p_cb->state = initial_state;
-  p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;
-
-  /* Send BTIF_SM_ENTER_EVT to the initial state */
-  p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);
-
-  return (btif_sm_handle_t)p_cb;
-}
-
-/*****************************************************************************
- *
- * Function     btif_sm_shutdown
- *
- * Description  Tears down the state machine
- *
- * Returns      None
- *
- *****************************************************************************/
-void btif_sm_shutdown(btif_sm_handle_t handle) {
-  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
-
-  if (p_cb == NULL) {
-    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
-    return;
-  }
-  osi_free(p_cb);
-}
-
-/*****************************************************************************
- *
- * Function     btif_sm_get_state
- *
- * Description  Fetches the current state of the state machine
- *
- * Returns      Current state
- *
- *****************************************************************************/
-btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle) {
-  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
-
-  if (p_cb == NULL) {
-    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
-    return 0;
-  }
-
-  return p_cb->state;
-}
-
-/*****************************************************************************
- *
- * Function     btif_sm_dispatch
- *
- * Description  Dispatches the 'event' along with 'data' to the current state
- *              handler
- *
- * Returns      BT_STATUS_SUCCESS on success
- *              BT_STATUS_UNHANDLED if event was not processed
- *              BT_STATUS_FAIL otherwise
- *
- *****************************************************************************/
-bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
-                             void* data) {
-  bt_status_t status = BT_STATUS_SUCCESS;
-
-  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
-
-  if (p_cb == NULL) {
-    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
-    return BT_STATUS_FAIL;
-  }
-
-  if (p_cb->p_handlers[p_cb->state](event, data) == false)
-    return BT_STATUS_UNHANDLED;
-
-  return status;
-}
-
-/*****************************************************************************
- *
- * Function     btif_sm_change_state
- *
- * Description  Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
- *              shall be invoked before exiting the current state. The
- *              'BTIF_SM_ENTER_EVT' shall be invoked before entering the new
- *              state
- *
- * Returns      BT_STATUS_SUCCESS on success
- *              BT_STATUS_UNHANDLED if event was not processed
- *              BT_STATUS_FAIL otherwise
- *
- *****************************************************************************/
-bt_status_t btif_sm_change_state(btif_sm_handle_t handle,
-                                 btif_sm_state_t state) {
-  bt_status_t status = BT_STATUS_SUCCESS;
-  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
-
-  if (p_cb == NULL) {
-    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
-    return BT_STATUS_FAIL;
-  }
-
-  /* Send exit event to the current state */
-  if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL) == false)
-    status = BT_STATUS_UNHANDLED;
-
-  /* Change to the new state */
-  p_cb->state = state;
-
-  /* Send enter event to the new state */
-  if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL) == false)
-    status = BT_STATUS_UNHANDLED;
-
-  return status;
-}
diff --git a/btif/src/btif_sock.cc b/btif/src/btif_sock.cc
index a41ab13..90121b1 100644
--- a/btif/src/btif_sock.cc
+++ b/btif/src/btif_sock.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,23 +34,31 @@
 #include "btif_sock_thread.h"
 #include "btif_uid.h"
 #include "btif_util.h"
+#include "device/include/controller.h"
 #include "osi/include/thread.h"
 
+using bluetooth::Uuid;
+
 static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
-                                 const uint8_t* uuid, int channel, int* sock_fd,
+                                 const Uuid* uuid, int channel, int* sock_fd,
                                  int flags, int app_uid);
 static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
-                                  const uint8_t* uuid, int channel,
-                                  int* sock_fd, int flags, int app_uid);
+                                  const Uuid* uuid, int channel, int* sock_fd,
+                                  int flags, int app_uid);
+
+static void btsock_request_max_tx_data_length(const RawAddress& bd_addr);
 
 static void btsock_signaled(int fd, int type, int flags, uint32_t user_id);
 
 static std::atomic_int thread_handle{-1};
 static thread_t* thread;
 
-btsock_interface_t* btif_sock_get_interface(void) {
-  static btsock_interface_t interface = {sizeof(interface), btsock_listen,
-                                         btsock_connect};
+const btsock_interface_t* btif_sock_get_interface(void) {
+  static btsock_interface_t interface = {
+      sizeof(interface), btsock_listen, /* listen */
+      btsock_connect,                   /* connect */
+      btsock_request_max_tx_data_length /* request_max_tx_data_length */
+  };
 
   return &interface;
 }
@@ -120,15 +128,15 @@
 }
 
 static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
-                                 const uint8_t* service_uuid, int channel,
+                                 const Uuid* service_uuid, int channel,
                                  int* sock_fd, int flags, int app_uid) {
   if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
-    CHECK(service_uuid != NULL || channel > 0);
     CHECK(sock_fd != NULL);
   }
 
   *sock_fd = INVALID_FD;
   bt_status_t status = BT_STATUS_FAIL;
+  int original_channel = channel;
 
   switch (type) {
     case BTSOCK_RFCOMM:
@@ -139,7 +147,23 @@
       status =
           btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
       break;
-
+    case BTSOCK_L2CAP_LE:
+      if (flags & BTSOCK_FLAG_NO_SDP) {
+        /* Set channel to zero so that it will be assigned */
+        channel = 0;
+      } else if (channel <= 0) {
+        LOG_ERROR(LOG_TAG, "%s: type BTSOCK_L2CAP_LE: invalid channel=%d",
+                  __func__, channel);
+        break;
+      }
+      flags |= BTSOCK_FLAG_LE_COC;
+      LOG_DEBUG(
+          LOG_TAG,
+          "%s: type=BTSOCK_L2CAP_LE, channel=0x%x, original=0x%x, flags=0x%x",
+          __func__, channel, original_channel, flags);
+      status =
+          btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
+      break;
     case BTSOCK_SCO:
       status = btsock_sco_listen(sock_fd, flags);
       break;
@@ -154,9 +178,8 @@
 }
 
 static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
-                                  const uint8_t* uuid, int channel,
-                                  int* sock_fd, int flags, int app_uid) {
-  CHECK(uuid != NULL || channel > 0);
+                                  const Uuid* uuid, int channel, int* sock_fd,
+                                  int flags, int app_uid) {
   CHECK(bd_addr != NULL);
   CHECK(sock_fd != NULL);
 
@@ -173,6 +196,13 @@
       status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
       break;
 
+    case BTSOCK_L2CAP_LE:
+      flags |= BTSOCK_FLAG_LE_COC;
+      LOG_DEBUG(LOG_TAG, "%s: type=BTSOCK_L2CAP_LE, channel=0x%x, flags=0x%x",
+                __func__, channel, flags);
+      status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
+      break;
+
     case BTSOCK_SCO:
       status = btsock_sco_connect(bd_addr, sock_fd, flags);
       break;
@@ -186,12 +216,24 @@
   return status;
 }
 
+static void btsock_request_max_tx_data_length(const RawAddress& remote_device) {
+  const controller_t* controller = controller_get_interface();
+  uint16_t max_len = controller->get_ble_maximum_tx_data_length();
+
+  DVLOG(2) << __func__ << ": max_len=" << max_len;
+
+  BTA_DmBleSetDataLength(remote_device, max_len);
+}
+
 static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) {
   switch (type) {
     case BTSOCK_RFCOMM:
       btsock_rfc_signaled(fd, flags, user_id);
       break;
     case BTSOCK_L2CAP:
+    case BTSOCK_L2CAP_LE:
+      /* Note: The caller may not distinguish between BTSOCK_L2CAP and
+       * BTSOCK_L2CAP_LE correctly */
       btsock_l2cap_signaled(fd, flags, user_id);
       break;
     default:
diff --git a/btif/src/btif_sock_l2cap.cc b/btif/src/btif_sock_l2cap.cc
index 90e3755..43f2372 100644
--- a/btif/src/btif_sock_l2cap.cc
+++ b/btif/src/btif_sock_l2cap.cc
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Samsung System LSI
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2014 Samsung System LSI
+ * Copyright 2013 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.
@@ -15,23 +15,22 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "bt_btif_sock"
-
 #include "btif_sock_l2cap.h"
 
+#include <base/logging.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <vector>
 
 #include <mutex>
 
 #include <hardware/bt_sock.h>
 
 #include "osi/include/allocator.h"
-#include "osi/include/log.h"
 
 #include "bt_common.h"
 #include "bt_target.h"
@@ -49,6 +48,7 @@
 #include "btu.h"
 #include "hcimsgs.h"
 #include "l2c_api.h"
+#include "l2c_int.h"
 #include "l2cdefs.h"
 #include "port_api.h"
 #include "sdp_api.h"
@@ -76,16 +76,17 @@
   struct packet* first_packet;  // fist packet to be delivered to app
   struct packet* last_packet;   // last packet to be delivered to app
 
-  fixed_queue_t* incoming_que;    // data that came in but has not yet been read
   unsigned fixed_chan : 1;        // fixed channel (or psm?)
   unsigned server : 1;            // is a server? (or connecting?)
   unsigned connected : 1;         // is connected?
   unsigned outgoing_congest : 1;  // should we hold?
   unsigned server_psm_sent : 1;   // The server shall only send PSM once.
   bool is_le_coc;                 // is le connection oriented channel?
+  uint16_t rx_mtu;
+  uint16_t tx_mtu;
 } l2cap_socket;
 
-static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock);
+static void btsock_l2cap_server_listen(l2cap_socket* sock);
 
 static std::mutex state_lock;
 
@@ -172,18 +173,12 @@
 /* makes a copy of the data, returns true on success */
 static char packet_put_tail_l(l2cap_socket* sock, const void* data,
                               uint32_t len) {
-  struct packet* p = packet_alloc((const uint8_t*)data, len);
-
   if (sock->bytes_buffered >= L2CAP_MAX_RX_BUFFER) {
-    LOG_ERROR(LOG_TAG, "packet_put_tail_l: buffer overflow");
+    LOG(ERROR) << __func__ << ": buffer overflow";
     return false;
   }
 
-  if (!p) {
-    LOG_ERROR(LOG_TAG, "packet_put_tail_l: unable to allocate packet...");
-    return false;
-  }
-
+  struct packet* p = packet_alloc((const uint8_t*)data, len);
   p->next = NULL;
   p->prev = sock->last_packet;
   sock->last_packet = p;
@@ -232,7 +227,7 @@
   if (sock->app_fd != -1) {
     close(sock->app_fd);
   } else {
-    APPL_TRACE_ERROR("SOCK_LIST: free(id = %d) - NO app_fd!", sock->id);
+    LOG(ERROR) << "SOCK_LIST: free(id = " << sock->id << ") - NO app_fd!";
   }
 
   while (packet_get_head_l(sock, &buf, NULL)) osi_free(buf);
@@ -240,35 +235,35 @@
   // lower-level close() should be idempotent... so let's call it and see...
   if (sock->is_le_coc) {
     // Only call if we are non server connections
-    if (sock->handle >= 0 && (sock->server == false)) {
+    if (sock->handle >= 0 && (!sock->server)) {
       BTA_JvL2capClose(sock->handle);
     }
-    if ((sock->channel >= 0) && (sock->server == true)) {
-      BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+    if ((sock->channel >= 0) && (sock->server)) {
+      BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
     }
   } else {
     // Only call if we are non server connections
-    if ((sock->handle >= 0) && (sock->server == false)) {
+    if ((sock->handle >= 0) && (!sock->server)) {
       if (sock->fixed_chan)
         BTA_JvL2capCloseLE(sock->handle);
       else
         BTA_JvL2capClose(sock->handle);
     }
-    if ((sock->channel >= 0) && (sock->server == true)) {
+    if ((sock->channel >= 0) && (sock->server)) {
       if (sock->fixed_chan)
         BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
       else
         BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
 
       if (!sock->fixed_chan) {
-        APPL_TRACE_DEBUG("%s stopping L2CAP server channel %d", __func__,
-                         sock->channel);
+        DVLOG(2) << __func__ << ": stopping L2CAP server channel "
+                 << sock->channel;
         BTA_JvL2capStopServer(sock->channel, sock->id);
       }
     }
   }
 
-  APPL_TRACE_DEBUG("%s: free(id = %d)", __func__, sock->id);
+  DVLOG(2) << __func__ << ": free id:" << sock->id;
   osi_free(sock);
 }
 
@@ -289,7 +284,7 @@
     security |= BTM_SEC_IN_MIN_16_DIGIT_PIN;
 
   if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, fds)) {
-    APPL_TRACE_ERROR("socketpair failed, errno:%d", errno);
+    LOG(ERROR) << "socketpair failed, errno:" << errno;
     goto fail_sockpair;
   }
 
@@ -308,6 +303,8 @@
   sock->first_packet = NULL;
   sock->last_packet = NULL;
 
+  sock->tx_mtu = L2CAP_LE_MIN_MTU;
+
   sock->next = socks;
   sock->prev = NULL;
   if (socks) socks->prev = sock;
@@ -327,7 +324,7 @@
     if (!++sock->id) /* no zero IDs allowed */
       sock->id++;
   }
-  APPL_TRACE_DEBUG("SOCK_LIST: alloc(id = %d)", sock->id);
+  DVLOG(2) << __func__ << " SOCK_LIST: alloc id:" << sock->id;
   return sock;
 
 fail_sockpair:
@@ -336,7 +333,7 @@
 }
 
 bt_status_t btsock_l2cap_init(int handle, uid_set_t* set) {
-  APPL_TRACE_DEBUG("%s handle = %d", __func__);
+  DVLOG(2) << __func__ << ": handle: " << handle;
   std::unique_lock<std::mutex> lock(state_lock);
   pth = handle;
   socks = NULL;
@@ -352,25 +349,28 @@
 }
 
 static inline bool send_app_psm_or_chan_l(l2cap_socket* sock) {
+  DVLOG(2) << __func__ << ": channel: " << sock->channel;
   return sock_send_all(sock->our_fd, (const uint8_t*)&sock->channel,
                        sizeof(sock->channel)) == sizeof(sock->channel);
 }
 
 static bool send_app_connect_signal(int fd, const RawAddress* addr, int channel,
-                                    int status, int send_fd, int tx_mtu) {
+                                    int status, int send_fd, uint16_t rx_mtu,
+                                    uint16_t tx_mtu) {
   sock_connect_signal_t cs;
   cs.size = sizeof(cs);
   cs.bd_addr = *addr;
   cs.channel = channel;
   cs.status = status;
-  cs.max_rx_packet_size = L2CAP_MAX_SDU_LENGTH;
+  cs.max_rx_packet_size = rx_mtu;
   cs.max_tx_packet_size = tx_mtu;
   if (send_fd != -1) {
     if (sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) ==
         sizeof(cs))
       return true;
     else
-      APPL_TRACE_ERROR("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd);
+      LOG(ERROR) << "sock_send_fd failed, fd: " << fd
+                 << ", send_fd:" << send_fd;
   } else if (sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs)) {
     return true;
   }
@@ -386,20 +386,20 @@
   if (!sock) return;
 
   if (p_start->status != BTA_JV_SUCCESS) {
-    APPL_TRACE_ERROR("Error starting l2cap_listen - status: 0x%04x",
-                     p_start->status);
+    LOG(ERROR) << "Error starting l2cap_listen - status: "
+               << loghex(p_start->status);
     btsock_l2cap_free_l(sock);
     return;
   }
 
   sock->handle = p_start->handle;
-  APPL_TRACE_DEBUG("on_srv_l2cap_listen_started() sock->handle =%d id:%d",
-                   sock->handle, sock->id);
+  DVLOG(2) << __func__ << ": sock->handle: " << sock->handle
+           << ", id: " << sock->id;
 
-  if (sock->server_psm_sent == false) {
+  if (!sock->server_psm_sent) {
     if (!send_app_psm_or_chan_l(sock)) {
       // closed
-      APPL_TRACE_DEBUG("send_app_psm() failed, close rs->id:%d", sock->id);
+      DVLOG(2) << "send_app_psm() failed, close rs->id: " << sock->id;
       btsock_l2cap_free_l(sock);
     } else {
       sock->server_psm_sent = true;
@@ -424,16 +424,13 @@
 
 /**
  * Here we allocate a new sock instance to mimic the BluetoothSocket. The socket
- * will be a clone
- * of the sock representing the BluetoothServerSocket.
+ * will be a clone of the sock representing the BluetoothServerSocket.
  * */
 static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
                                        l2cap_socket* sock) {
-  l2cap_socket* accept_rs;
-  uint32_t new_listen_id;
-
   // std::mutex locked by caller
-  accept_rs = btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
+  l2cap_socket* accept_rs =
+      btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
   accept_rs->connected = true;
   accept_rs->security = sock->security;
   accept_rs->fixed_chan = sock->fixed_chan;
@@ -443,121 +440,114 @@
   sock->handle =
       -1; /* We should no longer associate this handle with the server socket */
   accept_rs->is_le_coc = sock->is_le_coc;
+  accept_rs->tx_mtu = sock->tx_mtu = p_open->tx_mtu;
 
   /* Swap IDs to hand over the GAP connection to the accepted socket, and start
-     a new server on
-     the newly create socket ID. */
-  new_listen_id = accept_rs->id;
+     a new server on the newly create socket ID. */
+  uint32_t new_listen_id = accept_rs->id;
   accept_rs->id = sock->id;
   sock->id = new_listen_id;
 
-  if (accept_rs) {
-    // start monitor the socket
-    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
-                         SOCK_THREAD_FD_EXCEPTION, sock->id);
-    btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP,
-                         SOCK_THREAD_FD_RD, accept_rs->id);
-    APPL_TRACE_DEBUG(
-        "sending connect signal & app fd: %d to app server to accept() the"
-        " connection",
-        accept_rs->app_fd);
-    APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
-    send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
-                            accept_rs->app_fd, p_open->tx_mtu);
-    accept_rs->app_fd =
-        -1;  // The fd is closed after sent to app in send_app_connect_signal()
-    // But for some reason we still leak a FD - either the server socket
-    // one or the accept socket one.
-    if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS) {
-      btsock_l2cap_free_l(sock);
-    }
-  }
+  // start monitor the socket
+  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                       SOCK_THREAD_FD_EXCEPTION, sock->id);
+  btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                       accept_rs->id);
+  DVLOG(2) << "sending connect signal & app fd: " << accept_rs->app_fd
+           << " to app server to accept() the connection";
+  DVLOG(2) << "server fd: << " << sock->our_fd << ", scn:" << sock->channel;
+  send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+                          accept_rs->app_fd, sock->rx_mtu, p_open->tx_mtu);
+  accept_rs->app_fd =
+      -1;  // The fd is closed after sent to app in send_app_connect_signal()
+  // But for some reason we still leak a FD - either the server socket
+  // one or the accept socket one.
+  btsock_l2cap_server_listen(sock);
 }
 
 static void on_srv_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
                                       l2cap_socket* sock) {
-  l2cap_socket* accept_rs;
-  uint32_t new_listen_id;
-
   // std::mutex locked by caller
-  accept_rs = btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
-  if (accept_rs) {
-    // swap IDs
-    new_listen_id = accept_rs->id;
-    accept_rs->id = sock->id;
-    sock->id = new_listen_id;
+  l2cap_socket* accept_rs =
+      btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
+  if (!accept_rs) return;
 
-    accept_rs->handle = p_open->handle;
-    accept_rs->connected = true;
-    accept_rs->security = sock->security;
-    accept_rs->fixed_chan = sock->fixed_chan;
-    accept_rs->channel = sock->channel;
-    accept_rs->app_uid = sock->app_uid;
+  // swap IDs
+  uint32_t new_listen_id = accept_rs->id;
+  accept_rs->id = sock->id;
+  sock->id = new_listen_id;
 
-    // if we do not set a callback, this socket will be dropped */
-    *(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
-    *(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);
+  accept_rs->handle = p_open->handle;
+  accept_rs->connected = true;
+  accept_rs->security = sock->security;
+  accept_rs->fixed_chan = sock->fixed_chan;
+  accept_rs->channel = sock->channel;
+  accept_rs->app_uid = sock->app_uid;
+  accept_rs->tx_mtu = sock->tx_mtu = p_open->tx_mtu;
 
-    // start monitor the socket
-    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
-                         SOCK_THREAD_FD_EXCEPTION, sock->id);
-    btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP,
-                         SOCK_THREAD_FD_RD, accept_rs->id);
-    APPL_TRACE_DEBUG(
-        "sending connect signal & app fd:%dto app server to accept() the"
-        " connection",
-        accept_rs->app_fd);
-    APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
-    send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
-                            accept_rs->app_fd, p_open->tx_mtu);
-    accept_rs->app_fd = -1;  // the fd is closed after sent to app
-  }
+  // if we do not set a callback, this socket will be dropped */
+  *(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
+  *(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);
+
+  // start monitor the socket
+  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                       SOCK_THREAD_FD_EXCEPTION, sock->id);
+  btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                       accept_rs->id);
+  DVLOG(2) << "sending connect signal & app fd: " << accept_rs->app_fd
+           << " to app server to accept() the connection";
+  DVLOG(2) << "server fd: << " << sock->our_fd << ", scn:" << sock->channel;
+  send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+                          accept_rs->app_fd, sock->rx_mtu, p_open->tx_mtu);
+  accept_rs->app_fd = -1;  // the fd is closed after sent to app
 }
 
 static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
                                       l2cap_socket* sock) {
   sock->addr = p_open->rem_bda;
+  sock->tx_mtu = p_open->tx_mtu;
 
   if (!send_app_psm_or_chan_l(sock)) {
-    APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+    LOG(ERROR) << "send_app_psm_or_chan_l failed";
     return;
   }
 
-  if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
-                              p_open->tx_mtu)) {
-    // start monitoring the socketpair to get call back when app writing data
-    APPL_TRACE_DEBUG(
-        "on_l2cap_connect_ind, connect signal sent, slot id:%d, psm:%d,"
-        " server:%d",
-        sock->id, sock->channel, sock->server);
-    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
-                         sock->id);
-    sock->connected = true;
-  } else
-    APPL_TRACE_ERROR("send_app_connect_signal failed");
+  if (!send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
+                               sock->rx_mtu, p_open->tx_mtu)) {
+    LOG(ERROR) << "send_app_connect_signal failed";
+    return;
+  }
+
+  // start monitoring the socketpair to get call back when app writing data
+  DVLOG(2) << " connect signal sent, slot id: " << sock->id
+           << ", chan: " << sock->channel << ", server: " << sock->server;
+  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                       sock->id);
+  sock->connected = true;
 }
 
 static void on_cl_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
                                      l2cap_socket* sock) {
   sock->addr = p_open->rem_bda;
+  sock->tx_mtu = p_open->tx_mtu;
 
   if (!send_app_psm_or_chan_l(sock)) {
-    APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+    LOG(ERROR) << "send_app_psm_or_chan_l failed";
     return;
   }
 
-  if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
-                              p_open->tx_mtu)) {
-    // start monitoring the socketpair to get call back when app writing data
-    APPL_TRACE_DEBUG(
-        "on_l2cap_connect_ind, connect signal sent, slot id:%d, Chan:%d,"
-        " server:%d",
-        sock->id, sock->channel, sock->server);
-    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
-                         sock->id);
-    sock->connected = true;
-  } else
-    APPL_TRACE_ERROR("send_app_connect_signal failed");
+  if (!send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
+                               sock->rx_mtu, p_open->tx_mtu)) {
+    LOG(ERROR) << "send_app_connect_signal failed";
+    return;
+  }
+
+  // start monitoring the socketpair to get call back when app writing data
+  DVLOG(2) << " connect signal sent, slot id: " << sock->id
+           << ", chan: " << sock->channel << ", server: " << sock->server;
+  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                       sock->id);
+  sock->connected = true;
 }
 
 static void on_l2cap_connect(tBTA_JV* p_data, uint32_t id) {
@@ -568,10 +558,11 @@
   std::unique_lock<std::mutex> lock(state_lock);
   sock = btsock_l2cap_find_by_id_l(id);
   if (!sock) {
-    APPL_TRACE_ERROR("on_l2cap_connect on unknown socket");
+    LOG(ERROR) << __func__ << ": unknown socket";
     return;
   }
 
+  sock->tx_mtu = le_open->tx_mtu;
   if (sock->fixed_chan && le_open->status == BTA_JV_SUCCESS) {
     if (!sock->server)
       on_cl_l2cap_le_connect_l(le_open, sock);
@@ -593,13 +584,12 @@
   sock = btsock_l2cap_find_by_id_l(id);
   if (!sock) return;
 
-  APPL_TRACE_DEBUG("on_l2cap_close, slot id:%d, fd:%d, %s:%d, server:%d",
-                   sock->id, sock->our_fd,
-                   sock->fixed_chan ? "fixed_chan" : "PSM", sock->channel,
-                   sock->server);
+  DVLOG(2) << __func__ << ": slot id: " << sock->id << ", fd: " << sock->our_fd
+           << (sock->fixed_chan ? ", fixed_chan:" : ", PSM: ") << sock->channel
+           << ", server:" << sock->server;
   // TODO: This does not seem to be called...
   // I'm not sure if this will be called for non-server sockets?
-  if (!sock->fixed_chan && (sock->server == true)) {
+  if (!sock->fixed_chan && (sock->server)) {
     BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
   }
   btsock_l2cap_free_l(sock);
@@ -615,30 +605,21 @@
   sock->outgoing_congest = p->cong ? 1 : 0;
   // mointer the fd for any outgoing data
   if (!sock->outgoing_congest) {
-    APPL_TRACE_DEBUG(
-        "on_l2cap_outgoing_congest: adding fd to btsock_thread...");
+    DVLOG(2) << __func__ << ": adding fd to btsock_thread...";
     btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
                          sock->id);
   }
 }
 
-static void on_l2cap_write_done(void* req_id, uint16_t len, uint32_t id) {
-  l2cap_socket* sock;
-
-  if (req_id != NULL) {
-    osi_free(req_id);  // free the buffer
-  }
-
-  int app_uid = -1;
-
+static void on_l2cap_write_done(uint16_t len, uint32_t id) {
   std::unique_lock<std::mutex> lock(state_lock);
-  sock = btsock_l2cap_find_by_id_l(id);
+  l2cap_socket* sock = btsock_l2cap_find_by_id_l(id);
   if (!sock) return;
 
-  app_uid = sock->app_uid;
+  int app_uid = sock->app_uid;
   if (!sock->outgoing_congest) {
     // monitor the fd for any outgoing data
-    APPL_TRACE_DEBUG("on_l2cap_write_done: adding fd to btsock_thread...");
+    DVLOG(2) << __func__ << ": adding fd to btsock_thread...";
     btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
                          sock->id);
   }
@@ -646,27 +627,6 @@
   uid_set_add_tx(uid_set, app_uid, len);
 }
 
-static void on_l2cap_write_fixed_done(void* req_id, uint16_t len, uint32_t id) {
-  l2cap_socket* sock;
-
-  if (req_id != NULL) {
-    osi_free(req_id);  // free the buffer
-  }
-
-  int app_uid = -1;
-  std::unique_lock<std::mutex> lock(state_lock);
-  sock = btsock_l2cap_find_by_id_l(id);
-  if (!sock) return;
-
-  app_uid = sock->app_uid;
-  if (!sock->outgoing_congest) {
-    // monitor the fd for any outgoing data
-    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
-                         sock->id);
-  }
-  uid_set_add_tx(uid_set, app_uid, len);
-}
-
 static void on_l2cap_data_ind(tBTA_JV* evt, uint32_t id) {
   l2cap_socket* sock;
 
@@ -690,28 +650,26 @@
       btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR,
                            sock->id);
     } else {  // connection must be dropped
-      APPL_TRACE_DEBUG(
-          "on_l2cap_data_ind() unable to push data to socket - closing"
-          " fixed channel");
+      DVLOG(2) << __func__
+               << ": unable to push data to socket - closing  fixed channel";
       BTA_JvL2capCloseLE(sock->handle);
       btsock_l2cap_free_l(sock);
     }
 
   } else {
-    uint8_t buffer[L2CAP_MAX_SDU_LENGTH];
     uint32_t count;
 
     if (BTA_JvL2capReady(sock->handle, &count) == BTA_JV_SUCCESS) {
-      if (BTA_JvL2capRead(sock->handle, sock->id, buffer, count) ==
+      std::vector<uint8_t> buffer(count);
+      if (BTA_JvL2capRead(sock->handle, sock->id, buffer.data(), count) ==
           BTA_JV_SUCCESS) {
-        if (packet_put_tail_l(sock, buffer, count)) {
+        if (packet_put_tail_l(sock, buffer.data(), count)) {
           bytes_read = count;
           btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
                                SOCK_THREAD_FD_WR, sock->id);
         } else {  // connection must be dropped
-          APPL_TRACE_DEBUG(
-              "on_l2cap_data_ind() unable to push data to socket"
-              " - closing channel");
+          DVLOG(2) << __func__
+                   << ": unable to push data to socket - closing channel";
           BTA_JvL2capClose(sock->handle);
           btsock_l2cap_free_l(sock);
         }
@@ -740,29 +698,27 @@
       break;
 
     case BTA_JV_L2CAP_CLOSE_EVT:
-      APPL_TRACE_DEBUG("BTA_JV_L2CAP_CLOSE_EVT: id: %u", l2cap_socket_id);
+      DVLOG(2) << "BTA_JV_L2CAP_CLOSE_EVT: id: " << l2cap_socket_id;
       on_l2cap_close(&p_data->l2c_close, l2cap_socket_id);
       break;
 
     case BTA_JV_L2CAP_DATA_IND_EVT:
       on_l2cap_data_ind(p_data, l2cap_socket_id);
-      APPL_TRACE_DEBUG("BTA_JV_L2CAP_DATA_IND_EVT");
+      DVLOG(2) << "BTA_JV_L2CAP_DATA_IND_EVT";
       break;
 
     case BTA_JV_L2CAP_READ_EVT:
-      APPL_TRACE_DEBUG("BTA_JV_L2CAP_READ_EVT not used");
+      DVLOG(2) << "BTA_JV_L2CAP_READ_EVT not used";
       break;
 
     case BTA_JV_L2CAP_WRITE_EVT:
-      APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_EVT: id: %u", l2cap_socket_id);
-      on_l2cap_write_done(p_data->l2c_write.p_data, p_data->l2c_write.len,
-                          l2cap_socket_id);
+      DVLOG(2) << "BTA_JV_L2CAP_WRITE_EVT: id: " << l2cap_socket_id;
+      on_l2cap_write_done(p_data->l2c_write.len, l2cap_socket_id);
       break;
 
     case BTA_JV_L2CAP_WRITE_FIXED_EVT:
-      APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_FIXED_EVT: id: %u", l2cap_socket_id);
-      on_l2cap_write_fixed_done(p_data->l2c_write_fixed.p_data,
-                                p_data->l2c_write.len, l2cap_socket_id);
+      DVLOG(2) << "BTA_JV_L2CAP_WRITE_FIXED_EVT: id: " << l2cap_socket_id;
+      on_l2cap_write_done(p_data->l2c_write.len, l2cap_socket_id);
       break;
 
     case BTA_JV_L2CAP_CONG_EVT:
@@ -770,8 +726,8 @@
       break;
 
     default:
-      APPL_TRACE_ERROR("unhandled event %d, slot id: %u", event,
-                       l2cap_socket_id);
+      LOG(ERROR) << "unhandled event: " << event
+                 << ", slot id: " << l2cap_socket_id;
       break;
   }
 }
@@ -805,62 +761,47 @@
   std::unique_lock<std::mutex> lock(state_lock);
   l2cap_socket* sock = btsock_l2cap_find_by_id_l(id);
   if (!sock) {
-    APPL_TRACE_ERROR("%s: Error: sock is null", __func__);
+    LOG(ERROR) << __func__ << ": sock is null";
     return;
   }
 
   sock->channel = psm;
 
-  if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS)
-    btsock_l2cap_free_l(sock);
+  btsock_l2cap_server_listen(sock);
 }
 
-static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock) {
-  tL2CAP_CFG_INFO cfg;
-  bt_status_t stat = BT_STATUS_SUCCESS;
-  /* Setup ETM settings:
-   *  mtu will be set below */
-  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
-  cfg.fcr_present = true;
-  cfg.fcr = obex_l2c_fcr_opts_def;
+static void btsock_l2cap_server_listen(l2cap_socket* sock) {
+  DVLOG(2) << __func__ << ": fixed_chan: " << sock->fixed_chan
+           << ", channel: " << sock->channel
+           << ", is_le_coc: " << sock->is_le_coc;
 
   if (sock->fixed_chan) {
-    if (BTA_JvL2capStartServerLE(sock->security, 0, NULL, sock->channel,
-                                 L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk,
-                                 sock->id) != BTA_JV_SUCCESS)
-      stat = BT_STATUS_FAIL;
-
-  } else {
-    /* If we have a channel specified in the request, just start the server,
-     * else we request a PSM and start the server after we receive a PSM. */
-    if (sock->channel < 0) {
-      if (sock->is_le_coc) {
-        if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP_LE, sock->id, 0) !=
-            BTA_JV_SUCCESS)
-          stat = BT_STATUS_FAIL;
-      } else {
-        if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP, sock->id, 0) !=
-            BTA_JV_SUCCESS)
-          stat = BT_STATUS_FAIL;
-      }
-    } else {
-      if (sock->is_le_coc) {
-        if (BTA_JvL2capStartServer(BTA_JV_CONN_TYPE_L2CAP_LE, sock->security, 0,
-                                   NULL, sock->channel, L2CAP_MAX_SDU_LENGTH,
-                                   &cfg, btsock_l2cap_cbk,
-                                   sock->id) != BTA_JV_SUCCESS)
-          stat = BT_STATUS_FAIL;
-      } else {
-        if (BTA_JvL2capStartServer(BTA_JV_CONN_TYPE_L2CAP, sock->security, 0,
-                                   &obex_l2c_etm_opt, sock->channel,
-                                   L2CAP_MAX_SDU_LENGTH, &cfg, btsock_l2cap_cbk,
-                                   sock->id) != BTA_JV_SUCCESS)
-          stat = BT_STATUS_FAIL;
-      }
-    }
+    BTA_JvL2capStartServerLE(sock->channel, btsock_l2cap_cbk, sock->id);
+    return;
   }
-  return stat;
+
+  int connection_type =
+      sock->is_le_coc ? BTA_JV_CONN_TYPE_L2CAP_LE : BTA_JV_CONN_TYPE_L2CAP;
+
+  /* If we have a channel specified in the request, just start the server,
+   * else we request a PSM and start the server after we receive a PSM. */
+  if (sock->channel <= 0) {
+    BTA_JvGetChannelId(connection_type, sock->id, 0);
+    return;
+  }
+
+  /* Setup ETM settings: mtu will be set below */
+  std::unique_ptr<tL2CAP_CFG_INFO> cfg = std::make_unique<tL2CAP_CFG_INFO>(
+      tL2CAP_CFG_INFO{.fcr_present = true, .fcr = obex_l2c_fcr_opts_def});
+
+  std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info;
+  if (!sock->is_le_coc) {
+    ertm_info.reset(new tL2CAP_ERTM_INFO(obex_l2c_etm_opt));
+  }
+
+  BTA_JvL2capStartServer(connection_type, sock->security, 0,
+                         std::move(ertm_info), sock->channel, sock->rx_mtu,
+                         std::move(cfg), btsock_l2cap_cbk, sock->id);
 }
 
 static bt_status_t btsock_l2cap_listen_or_connect(const char* name,
@@ -868,10 +809,7 @@
                                                   int channel, int* sock_fd,
                                                   int flags, char listen,
                                                   int app_uid) {
-  bt_status_t stat;
   int fixed_chan = 1;
-  l2cap_socket* sock;
-  tL2CAP_CFG_INFO cfg;
   bool is_le_coc = false;
 
   if (!sock_fd) return BT_STATUS_PARM_INVALID;
@@ -880,9 +818,9 @@
     // We need to auto assign a PSM
     fixed_chan = 0;
   } else {
+    is_le_coc = (flags & BTSOCK_FLAG_LE_COC) != 0;
     fixed_chan = (channel & L2CAP_MASK_FIXED_CHANNEL) != 0;
-    is_le_coc = (channel & L2CAP_MASK_LE_COC_CHANNEL) != 0;
-    channel &= ~(L2CAP_MASK_FIXED_CHANNEL | L2CAP_MASK_LE_COC_CHANNEL);
+    channel &= ~L2CAP_MASK_FIXED_CHANNEL;
   }
 
   if (!is_inited()) return BT_STATUS_NOT_READY;
@@ -890,7 +828,7 @@
   // TODO: This is kind of bad to lock here, but it is needed for the current
   // design.
   std::unique_lock<std::mutex> lock(state_lock);
-  sock = btsock_l2cap_alloc_l(name, addr, listen, flags);
+  l2cap_socket* sock = btsock_l2cap_alloc_l(name, addr, listen, flags);
   if (!sock) {
     return BT_STATUS_NOMEM;
   }
@@ -899,60 +837,44 @@
   sock->channel = channel;
   sock->app_uid = app_uid;
   sock->is_le_coc = is_le_coc;
-
-  stat = BT_STATUS_SUCCESS;
-
-  /* Setup ETM settings:
-   *  mtu will be set below */
-  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
-  cfg.fcr_present = true;
-  cfg.fcr = obex_l2c_fcr_opts_def;
+  sock->rx_mtu = is_le_coc ? L2CAP_SDU_LENGTH_LE_MAX : L2CAP_SDU_LENGTH_MAX;
 
   /* "role" is never initialized in rfcomm code */
   if (listen) {
-    stat = btSock_start_l2cap_server_l(sock);
+    btsock_l2cap_server_listen(sock);
   } else {
     if (fixed_chan) {
-      if (BTA_JvL2capConnectLE(sock->security, 0, NULL, channel,
-                               L2CAP_DEFAULT_MTU, NULL, sock->addr,
-                               btsock_l2cap_cbk, sock->id) != BTA_JV_SUCCESS)
-        stat = BT_STATUS_FAIL;
-
+      BTA_JvL2capConnectLE(channel, sock->addr, btsock_l2cap_cbk, sock->id);
     } else {
-      if (sock->is_le_coc) {
-        if (BTA_JvL2capConnect(BTA_JV_CONN_TYPE_L2CAP_LE, sock->security, 0,
-                               NULL, channel, L2CAP_MAX_SDU_LENGTH, &cfg,
-                               sock->addr, btsock_l2cap_cbk,
-                               sock->id) != BTA_JV_SUCCESS)
-          stat = BT_STATUS_FAIL;
-      } else {
-        if (BTA_JvL2capConnect(BTA_JV_CONN_TYPE_L2CAP, sock->security, 0,
-                               &obex_l2c_etm_opt, channel, L2CAP_MAX_SDU_LENGTH,
-                               &cfg, sock->addr, btsock_l2cap_cbk,
-                               sock->id) != BTA_JV_SUCCESS)
-          stat = BT_STATUS_FAIL;
+      int connection_type =
+          sock->is_le_coc ? BTA_JV_CONN_TYPE_L2CAP_LE : BTA_JV_CONN_TYPE_L2CAP;
+
+      /* Setup ETM settings: mtu will be set below */
+      std::unique_ptr<tL2CAP_CFG_INFO> cfg = std::make_unique<tL2CAP_CFG_INFO>(
+          tL2CAP_CFG_INFO{.fcr_present = true, .fcr = obex_l2c_fcr_opts_def});
+
+      std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info;
+      if (!sock->is_le_coc) {
+        ertm_info.reset(new tL2CAP_ERTM_INFO(obex_l2c_etm_opt));
       }
+
+      BTA_JvL2capConnect(
+          connection_type, sock->security, 0, std::move(ertm_info), channel,
+          sock->rx_mtu, std::move(cfg), sock->addr, btsock_l2cap_cbk, sock->id);
     }
   }
 
-  if (stat == BT_STATUS_SUCCESS) {
-    *sock_fd = sock->app_fd;
-    /* We pass the FD to JAVA, but since it runs in another process, we need to
-     * also close
-     * it in native, either straight away, as done when accepting an incoming
-     * connection,
-     * or when doing cleanup after this socket */
-    sock->app_fd =
-        -1; /*This leaks the file descriptor. The FD should be closed in
-              JAVA but it apparently do not work */
-    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
-                         SOCK_THREAD_FD_EXCEPTION, sock->id);
-  } else {
-    btsock_l2cap_free_l(sock);
-  }
+  *sock_fd = sock->app_fd;
+  /* We pass the FD to JAVA, but since it runs in another process, we need to
+   * also close it in native, either straight away, as done when accepting an
+   * incoming connection, or when doing cleanup after this socket */
+  sock->app_fd = -1;
+  /*This leaks the file descriptor. The FD should be closed in JAVA but it
+   * apparently do not work */
+  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                       SOCK_THREAD_FD_EXCEPTION, sock->id);
 
-  return stat;
+  return BT_STATUS_SUCCESS;
 }
 
 bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd,
@@ -997,60 +919,69 @@
   return false;
 }
 
+inline BT_HDR* malloc_l2cap_buf(uint16_t len) {
+  // We need FCS only for L2CAP_FCR_ERTM_MODE, but it's just 2 bytes so it's ok
+  BT_HDR* msg = (BT_HDR*)osi_malloc(BT_HDR_SIZE + L2CAP_MIN_OFFSET + len +
+                                    L2CAP_FCS_LENGTH);
+  msg->offset = L2CAP_MIN_OFFSET;
+  msg->len = len;
+  return msg;
+}
+
+inline uint8_t* get_l2cap_sdu_start_ptr(BT_HDR* msg) {
+  return (uint8_t*)(msg) + BT_HDR_SIZE + msg->offset;
+}
+
 void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
-  l2cap_socket* sock;
   char drop_it = false;
 
   /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
    * hold the lock. */
   std::unique_lock<std::mutex> lock(state_lock);
-  sock = btsock_l2cap_find_by_id_l(user_id);
+  l2cap_socket* sock = btsock_l2cap_find_by_id_l(user_id);
   if (!sock) return;
 
   if ((flags & SOCK_THREAD_FD_RD) && !sock->server) {
     // app sending data
     if (sock->connected) {
       int size = 0;
+      bool ioctl_success = ioctl(sock->our_fd, FIONREAD, &size) == 0;
+      if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl_success && size)) {
+        /* FIONREAD return number of bytes that are immediately available for
+           reading, might be bigger than awaiting packet.
 
-      if (!(flags & SOCK_THREAD_FD_EXCEPTION) ||
-          (ioctl(sock->our_fd, FIONREAD, &size) == 0 && size)) {
-        uint8_t* buffer = (uint8_t*)osi_malloc(L2CAP_MAX_SDU_LENGTH);
+           BluetoothSocket.write(...) guarantees that any packet send to this
+           socket is broken into pieces no bigger than MTU bytes (as requested
+           by BT spec). */
+        size = std::min(size, (int)sock->tx_mtu);
+
+        BT_HDR* buffer = malloc_l2cap_buf(size);
         /* The socket is created with SOCK_SEQPACKET, hence we read one message
-         * at the time. The maximum size of a message is allocated to ensure
-         * data is not lost. This is okay to do as Android uses virtual memory,
-         * hence even if we only use a fraction of the memory it should not
-         * block for others to use the memory. As the definition of
-         * ioctl(FIONREAD) do not clearly define what value will be returned if
-         * multiple messages are written to the socket before any message is
-         * read from the socket, we could potentially risk to allocate way more
-         * memory than needed. One of the use cases for this socket is obex
-         * where multiple 64kbyte messages are typically written to the socket
-         * in a tight loop, hence we risk the ioctl will return the total amount
-         * of data in the buffer, which could be multiple 64kbyte chunks.
-         * UPDATE: As the stack cannot handle 64kbyte buffers, the size is
-         * reduced to around 8kbyte - and using malloc for buffer allocation
-         * here seems to be wrong
-         * UPDATE: Since we are responsible for freeing the buffer in the
-         * write_complete_ind, it is OK to use malloc. */
+         * at the time. */
         ssize_t count;
-        OSI_NO_INTR(count = recv(fd, buffer, L2CAP_MAX_SDU_LENGTH,
-                                 MSG_NOSIGNAL | MSG_DONTWAIT));
-        APPL_TRACE_DEBUG(
-            "btsock_l2cap_signaled - %d bytes received from socket", count);
+        OSI_NO_INTR(count = recv(fd, get_l2cap_sdu_start_ptr(buffer), size,
+                                 MSG_NOSIGNAL | MSG_DONTWAIT | MSG_TRUNC));
+        if (count > sock->tx_mtu) {
+          /* This can't happen thanks to check in BluetoothSocket.java but leave
+           * this in case this socket is ever used anywhere else*/
+          LOG(ERROR) << "recv more than MTU. Data will be lost: " << count;
+          count = sock->tx_mtu;
+        }
+
+        /* When multiple packets smaller than MTU are flushed to the socket, the
+           size of the single packet read could be smaller than the ioctl
+           reported total size of awaiting packets. Hence, we adjust the buffer
+           length. */
+        buffer->len = count;
+        DVLOG(2) << __func__ << ": bytes received from socket: " << count;
 
         if (sock->fixed_chan) {
-          if (BTA_JvL2capWriteFixed(sock->channel, sock->addr,
-                                    PTR_TO_UINT(buffer), btsock_l2cap_cbk,
-                                    buffer, count, user_id) != BTA_JV_SUCCESS) {
-            // On fail, free the buffer
-            on_l2cap_write_fixed_done(buffer, count, user_id);
-          }
+          // will take care of freeing buffer
+          BTA_JvL2capWriteFixed(sock->channel, sock->addr, PTR_TO_UINT(buffer),
+                                btsock_l2cap_cbk, buffer, user_id);
         } else {
-          if (BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, count,
-                               user_id) != BTA_JV_SUCCESS) {
-            // On fail, free the buffer
-            on_l2cap_write_done(buffer, count, user_id);
-          }
+          // will take care of freeing buffer
+          BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, user_id);
         }
       }
     } else
diff --git a/btif/src/btif_sock_rfc.cc b/btif/src/btif_sock_rfc.cc
index 2ea2a15..4b490a0 100644
--- a/btif/src/btif_sock_rfc.cc
+++ b/btif/src/btif_sock_rfc.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -59,6 +59,8 @@
  * L2CAP functions from this file. */
 #include "btif_sock_l2cap.h"
 
+using bluetooth::Uuid;
+
 // Maximum number of RFCOMM channels (1-30 inclusive).
 #define MAX_RFC_CHANNEL 30
 
@@ -82,7 +84,7 @@
   int scn_notified;
   RawAddress addr;
   int is_service_uuid_valid;
-  uint8_t service_uuid[16];
+  Uuid service_uuid;
   char service_name[256];
   int fd;
   int app_fd;   // Temporary storage for the half of the socketpair that's sent
@@ -157,7 +159,7 @@
   for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
     if (rfc_slots[i].id == id) return &rfc_slots[i];
 
-  LOG_ERROR(LOG_TAG, "%s unable to find RFCOMM slot id: %d", __func__, id);
+  LOG_ERROR(LOG_TAG, "%s unable to find RFCOMM slot id: %u", __func__, id);
   return NULL;
 }
 
@@ -181,7 +183,7 @@
 }
 
 static rfc_slot_t* alloc_rfc_slot(const RawAddress* addr, const char* name,
-                                  const uint8_t* uuid, int channel, int flags,
+                                  const Uuid& uuid, int channel, int flags,
                                   bool server) {
   int security = 0;
   if (flags & BTSOCK_FLAG_ENCRYPT)
@@ -215,13 +217,9 @@
   slot->scn = channel;
   slot->app_uid = -1;
 
-  if (!is_uuid_empty(uuid)) {
-    memcpy(slot->service_uuid, uuid, sizeof(slot->service_uuid));
-    slot->is_service_uuid_valid = true;
-  } else {
-    memset(slot->service_uuid, 0, sizeof(slot->service_uuid));
-    slot->is_service_uuid_valid = false;
-  }
+  slot->is_service_uuid_valid = !uuid.IsEmpty();
+  slot->service_uuid = uuid;
+
   if (name && *name) {
     strlcpy(slot->service_name, name, sizeof(slot->service_name));
   } else {
@@ -269,7 +267,7 @@
 }
 
 bt_status_t btsock_rfc_listen(const char* service_name,
-                              const uint8_t* service_uuid, int channel,
+                              const Uuid* service_uuid, int channel,
                               int* sock_fd, int flags, int app_uid) {
   CHECK(sock_fd != NULL);
   CHECK((service_uuid != NULL) ||
@@ -285,15 +283,16 @@
   if (!is_init_done()) return BT_STATUS_NOT_READY;
 
   if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
-    if (is_uuid_empty(service_uuid)) {
+    if (!service_uuid || service_uuid->IsEmpty()) {
       APPL_TRACE_DEBUG(
-          "BTA_JvGetChannelId: service_uuid not set AND "
-          "BTSOCK_FLAG_NO_SDP is not set - changing to SPP");
-      service_uuid =
-          UUID_SPP;  // Use serial port profile to listen to specified channel
+          "%s: service_uuid not set AND BTSOCK_FLAG_NO_SDP is not set - "
+          "changing to SPP",
+          __func__);
+      // Use serial port profile to listen to specified channel
+      service_uuid = &UUID_SPP;
     } else {
       // Check the service_uuid. overwrite the channel # if reserved
-      int reserved_channel = get_reserved_rfc_channel(service_uuid);
+      int reserved_channel = get_reserved_rfc_channel(*service_uuid);
       if (reserved_channel > 0) {
         channel = reserved_channel;
       }
@@ -303,7 +302,7 @@
   std::unique_lock<std::recursive_mutex> lock(slot_lock);
 
   rfc_slot_t* slot =
-      alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true);
+      alloc_rfc_slot(NULL, service_name, *service_uuid, channel, flags, true);
   if (!slot) {
     LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
     return BT_STATUS_FAIL;
@@ -329,10 +328,10 @@
 }
 
 bt_status_t btsock_rfc_connect(const RawAddress* bd_addr,
-                               const uint8_t* service_uuid, int channel,
+                               const Uuid* service_uuid, int channel,
                                int* sock_fd, int flags, int app_uid) {
   CHECK(sock_fd != NULL);
-  CHECK(service_uuid != NULL || (channel >= 1 && channel <= MAX_RFC_CHANNEL));
+  CHECK((service_uuid != NULL) || (channel >= 1 && channel <= MAX_RFC_CHANNEL));
 
   *sock_fd = INVALID_FD;
 
@@ -345,13 +344,13 @@
   std::unique_lock<std::recursive_mutex> lock(slot_lock);
 
   rfc_slot_t* slot =
-      alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false);
+      alloc_rfc_slot(bd_addr, NULL, *service_uuid, channel, flags, false);
   if (!slot) {
     LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
     return BT_STATUS_FAIL;
   }
 
-  if (is_uuid_empty(service_uuid)) {
+  if (!service_uuid || service_uuid->IsEmpty()) {
     tBTA_JV_STATUS ret =
         BTA_JvRfcommConnect(slot->security, slot->role, slot->scn, slot->addr,
                             rfcomm_cback, slot->id);
@@ -368,12 +367,8 @@
       return BT_STATUS_FAIL;
     }
   } else {
-    tSDP_UUID sdp_uuid;
-    sdp_uuid.len = 16;
-    memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128));
-
     if (!is_requesting_sdp()) {
-      BTA_JvStartDiscovery(*bd_addr, 1, &sdp_uuid, slot->id);
+      BTA_JvStartDiscovery(*bd_addr, 1, service_uuid, slot->id);
       slot->f.pending_sdp_request = false;
       slot->f.doing_sdp_request = true;
     } else {
@@ -444,7 +439,7 @@
 }
 
 static bool send_app_scn(rfc_slot_t* slot) {
-  if (slot->scn_notified == true) {
+  if (slot->scn_notified) {
     // already send, just return success.
     return true;
   }
@@ -625,7 +620,7 @@
       break;
 
     default:
-      LOG_ERROR(LOG_TAG, "%s unhandled event %d, slot id: %zi", __func__, event,
+      LOG_ERROR(LOG_TAG, "%s unhandled event %d, slot id: %u", __func__, event,
                 rfcomm_slot_id);
       break;
   }
@@ -658,7 +653,7 @@
           APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id);
           cleanup_rfc_slot(rs);
         } else {
-          if (rs->is_service_uuid_valid == true) {
+          if (rs->is_service_uuid_valid) {
             // We already have data for SDP record, create it (RFC-only
             // profiles)
             BTA_JvCreateRecordByUser(rs->id);
@@ -732,11 +727,7 @@
       // Find the next slot that needs to perform an SDP request and service it.
       slot = find_rfc_slot_by_pending_sdp();
       if (slot) {
-        tSDP_UUID sdp_uuid;
-        sdp_uuid.len = 16;
-        memcpy(sdp_uuid.uu.uuid128, slot->service_uuid,
-               sizeof(sdp_uuid.uu.uuid128));
-        BTA_JvStartDiscovery(slot->addr, 1, &sdp_uuid, slot->id);
+        BTA_JvStartDiscovery(slot->addr, 1, &slot->service_uuid, slot->id);
         slot->f.pending_sdp_request = false;
         slot->f.doing_sdp_request = true;
       }
diff --git a/btif/src/btif_sock_sco.cc b/btif/src/btif_sock_sco.cc
index f3e2bb9..6283196 100644
--- a/btif/src/btif_sock_sco.cc
+++ b/btif/src/btif_sock_sco.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/btif_sock_sdp.cc b/btif/src/btif_sock_sdp.cc
index afbfab4..d7993e5 100644
--- a/btif/src/btif_sock_sdp.cc
+++ b/btif/src/btif_sock_sdp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -43,6 +43,8 @@
 #include "sdp_api.h"
 #include "utl.h"
 
+using bluetooth::Uuid;
+
 // This module provides an abstraction on top of the lower-level SDP database
 // code for registration and discovery of various bluetooth sockets.
 //
@@ -85,7 +87,8 @@
 #define RESERVED_SCN_OPS 12
 
 #define UUID_MAX_LENGTH 16
-#define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
+
+#define SPP_PROFILE_VERSION 0x0102
 
 // Adds a protocol list and service name (if provided) to an SDP record given by
 // |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
@@ -111,7 +114,7 @@
   proto_list[1].num_params = 1;
   proto_list[1].params[0] = channel;
 
-  if (with_obex == true) {
+  if (with_obex) {
     proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
     proto_list[2].num_params = 0;
   }
@@ -152,15 +155,15 @@
 // Registers a service with the given |name|, |uuid|, and |channel| in the SDP
 // database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service
 // class sequence.
-static int add_sdp_by_uuid(const char* name, const uint8_t* uuid,
+static int add_sdp_by_uuid(const char* name, const Uuid& uuid,
                            const uint16_t channel) {
-  APPL_TRACE_DEBUG("add_sdp_by_uuid: scn: %d, service_name: %s", channel, name);
+  APPL_TRACE_DEBUG("%s: uuid: %s, scn: %d, service_name: %s", __func__,
+                   uuid.ToString().c_str(), channel, name);
 
   uint32_t handle = SDP_CreateRecord();
   if (handle == 0) {
     APPL_TRACE_ERROR(
-        "add_sdp_by_uuid: failed to create sdp record, "
-        "scn: %d, service_name: %s",
+        "%s: failed to create sdp record, scn: %d, service_name: %s", __func__,
         channel, name);
     return 0;
   }
@@ -183,7 +186,8 @@
   // Do the conversion to big-endian -- tmp is only used to iterate through the
   // UUID array in the macro and serves no other purpose as the conversion
   // macros are not hygenic.
-  { ARRAY_TO_BE_STREAM(tmp, uuid, UUID_MAX_LENGTH); }
+
+  { ARRAY_TO_BE_STREAM(tmp, uuid.To128BitBE().data(), UUID_MAX_LENGTH); }
 
   stage = "service_class_sequence";
   if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SERVICE_CLASS_ID_LIST, 1,
@@ -191,17 +195,14 @@
     goto error;
 
   APPL_TRACE_DEBUG(
-      "add_sdp_by_uuid: service registered successfully, "
-      "service_name: %s, handle: 0x%08x",
-      name, handle);
+      "%s: service registered successfully, service_name: %s, handle: 0x%08x",
+      __func__, name, handle);
   return handle;
 
 error:
   SDP_DeleteRecord(handle);
-  APPL_TRACE_ERROR(
-      "add_sdp_by_uuid: failed to register service "
-      "stage: %s, service_name: %s",
-      stage, name);
+  APPL_TRACE_ERROR("%s: failed to register service stage: %s, service_name: %s",
+                   __func__, stage, name);
   return 0;
 }
 
@@ -357,6 +358,11 @@
   stage = "service_class";
   if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
 
+  stage = "profile_descriptor_list";
+  if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_SERIAL_PORT,
+                                    SPP_PROFILE_VERSION))
+    goto error;
+
   APPL_TRACE_DEBUG(
       "add_spp_sdp: service registered successfully, "
       "service_name: %s, handle 0x%08x)",
@@ -377,10 +383,10 @@
 // |channel|. This function attempts to identify the type of the service based
 // upon its |uuid|, and will override the |channel| with a reserved channel
 // number if the |uuid| matches one of the preregistered bluez SDP records.
-static int add_rfc_sdp_by_uuid(const char* name, const uint8_t* uuid,
+static int add_rfc_sdp_by_uuid(const char* name, const Uuid& uuid,
                                const int channel) {
-  APPL_TRACE_DEBUG("add_rfc_sdp_by_uuid: service_name: %s, channel: %d", name,
-                   channel);
+  APPL_TRACE_DEBUG("%s: uuid: %s, service_name: %s, channel: %d", __func__,
+                   uuid.ToString().c_str(), name, channel);
 
   /*
    * Bluetooth Socket API relies on having preregistered bluez sdp records for
@@ -402,14 +408,14 @@
 
   int handle = 0;
 
-  if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
+  if (uuid == UUID_OBEX_OBJECT_PUSH) {
     handle = add_ops_sdp(name, final_channel);
-  } else if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
+  } else if (uuid == UUID_PBAP_PSE) {
     // PBAP Server is always channel 19
     handle = add_pbap_sdp(name, final_channel);
-  } else if (UUID_MATCHES(UUID_SPP, uuid)) {
+  } else if (uuid == UUID_SPP) {
     handle = add_spp_sdp(name, final_channel);
-  } else if (UUID_MATCHES(UUID_MAP_MAS, uuid)) {
+  } else if (uuid == UUID_MAP_MAS) {
     // Record created by new SDP create record interface
     handle = 0xff;
   } else {
@@ -429,10 +435,10 @@
   return false;
 }
 
-int get_reserved_rfc_channel(const uint8_t* uuid) {
-  if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
+int get_reserved_rfc_channel(const bluetooth::Uuid& uuid) {
+  if (uuid == UUID_PBAP_PSE) {
     return RESERVED_SCN_PBS;
-  } else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
+  } else if (uuid == UUID_OBEX_OBJECT_PUSH) {
     return RESERVED_SCN_OPS;
   }
 
@@ -442,8 +448,8 @@
 // Adds an SDP record to the SDP database using the given |name|, |uuid|, and
 // |channel|. Note that if the |uuid| is empty, the |uuid| will be set based
 // upon the |channel| passed in.
-int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, const int channel) {
-  if (is_uuid_empty(uuid)) {
+int add_rfc_sdp_rec(const char* name, Uuid uuid, const int channel) {
+  if (uuid.IsEmpty()) {
     switch (channel) {
       case RESERVED_SCN_PBS:  // PBAP Reserved port
         uuid = UUID_PBAP_PSE;
diff --git a/btif/src/btif_sock_thread.cc b/btif/src/btif_sock_thread.cc
index b206892..a49568b 100644
--- a/btif/src/btif_sock_thread.cc
+++ b/btif/src/btif_sock_thread.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/btif/src/btif_sock_util.cc b/btif/src/btif_sock_util.cc
index bf76100..68afa2a 100644
--- a/btif/src/btif_sock_util.cc
+++ b/btif/src/btif_sock_util.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -145,89 +145,3 @@
   close(send_fd);
   return ret_len;
 }
-
-static const char* hex_table = "0123456789abcdef";
-static inline void byte2hex(const char* data, char** str) {
-  **str = hex_table[(*data >> 4) & 0xf];
-  ++*str;
-  **str = hex_table[*data & 0xf];
-  ++*str;
-}
-static inline void byte2char(const char* data, char** str) {
-  **str = *data < ' ' ? '.' : *data > '~' ? '.' : *data;
-  ++(*str);
-}
-static inline void word2hex(const char* data, char** hex) {
-  byte2hex(&data[1], hex);
-  byte2hex(&data[0], hex);
-}
-void dump_bin(const char* title, const char* data, int size) {
-  char line_buff[256];
-  char* line;
-  int i, j, addr;
-  const int width = 16;
-  LOG_DEBUG(LOG_TAG, "%s, size:%d, dump started {", title, size);
-  if (size <= 0) return;
-  // write offset
-  line = line_buff;
-  *line++ = ' ';
-  *line++ = ' ';
-  *line++ = ' ';
-  *line++ = ' ';
-  *line++ = ' ';
-  *line++ = ' ';
-  for (j = 0; j < width; j++) {
-    byte2hex((const char*)&j, &line);
-    *line++ = ' ';
-  }
-  *line = 0;
-  LOG_DEBUG(LOG_TAG, "%s", line_buff);
-
-  for (i = 0; i < size / width; i++) {
-    line = line_buff;
-    // write address:
-    addr = i * width;
-    word2hex((const char*)&addr, &line);
-    *line++ = ':';
-    *line++ = ' ';
-    // write hex of data
-    for (j = 0; j < width; j++) {
-      byte2hex(&data[j], &line);
-      *line++ = ' ';
-    }
-    // write char of data
-    for (j = 0; j < width; j++) byte2char(data++, &line);
-    // wirte the end of line
-    *line = 0;
-    // output the line
-    LOG_DEBUG(LOG_TAG, "%s", line_buff);
-  }
-  // last line of left over if any
-  int leftover = size % width;
-  if (leftover > 0) {
-    line = line_buff;
-    // write address:
-    addr = i * width;
-    word2hex((const char*)&addr, &line);
-    *line++ = ':';
-    *line++ = ' ';
-    // write hex of data
-    for (j = 0; j < leftover; j++) {
-      byte2hex(&data[j], &line);
-      *line++ = ' ';
-    }
-    // write hex padding
-    for (; j < width; j++) {
-      *line++ = ' ';
-      *line++ = ' ';
-      *line++ = ' ';
-    }
-    // write char of data
-    for (j = 0; j < leftover; j++) byte2char(data++, &line);
-    // write the end of line
-    *line = 0;
-    // output the line
-    LOG_DEBUG(LOG_TAG, "%s", line_buff);
-  }
-  LOG_DEBUG(LOG_TAG, "%s, size:%d, dump ended }", title, size);
-}
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index 1c34787..fe00a2b 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -40,7 +40,9 @@
 #include <time.h>
 
 #include "bt_common.h"
+#include "bta_closure_api.h"
 #include "bta_hd_api.h"
+#include "bta_hearing_aid_api.h"
 #include "bta_hh_api.h"
 #include "btif_api.h"
 #include "btif_config.h"
@@ -54,6 +56,9 @@
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 
+using base::Bind;
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *  Constants & Macros
  ******************************************************************************/
@@ -88,7 +93,7 @@
     (p).type = (t);                                  \
     (p).val = (v);                                   \
     (p).len = (l);                                   \
-    s = btif_storage_get_adapter_property(&(p));     \
+    (s) = btif_storage_get_adapter_property(&(p));   \
   } while (0)
 
 // TODO: This macro should be converted to a function
@@ -167,26 +172,24 @@
  ******************************************************************************/
 
 static bt_status_t btif_in_fetch_bonded_ble_device(
-    const char* remote_bd_addr, int add,
+    const std::string& remote_bd_addr, int add,
     btif_bonded_devices_t* p_bonded_devices);
-static bt_status_t btif_in_fetch_bonded_device(const char* bdstr);
+static bt_status_t btif_in_fetch_bonded_device(const std::string& bdstr);
 
-static bool btif_has_ble_keys(const char* bdstr);
+static bool btif_has_ble_keys(const std::string& bdstr);
 
 /*******************************************************************************
  *  Static functions
  ******************************************************************************/
 
 static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) {
-  std::string addrstr;
-  const char* bdstr = addrstr.c_str();
+  std::string bdstr;
   if (remote_bd_addr) {
-    addrstr = remote_bd_addr->ToString();
-    bdstr = addrstr.c_str();
+    bdstr = remote_bd_addr->ToString();
   }
 
-  BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type,
-                   prop->len);
+  BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr.c_str(),
+                   prop->type, prop->len);
   char value[1024];
   if (prop->len <= 0 || prop->len > (int)sizeof(value) - 1) {
     BTIF_TRACE_ERROR("property type:%d, len:%d is invalid", prop->type,
@@ -198,14 +201,18 @@
       btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,
                           (int)time(NULL));
       break;
-    case BT_PROPERTY_BDNAME:
-      strncpy(value, (char*)prop->val, prop->len);
-      value[prop->len] = '\0';
+    case BT_PROPERTY_BDNAME: {
+      int name_length = prop->len > BTM_MAX_LOC_BD_NAME_LEN
+                            ? BTM_MAX_LOC_BD_NAME_LEN
+                            : prop->len;
+      strncpy(value, (char*)prop->val, name_length);
+      value[name_length] = '\0';
       if (remote_bd_addr)
         btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME, value);
       else
         btif_config_set_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME, value);
       break;
+    }
     case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
       strncpy(value, (char*)prop->val, prop->len);
       value[prop->len] = '\0';
@@ -228,22 +235,12 @@
                           *(int*)prop->val);
       break;
     case BT_PROPERTY_UUIDS: {
-      uint32_t i;
-      char buf[64];
-      value[0] = 0;
-      for (i = 0; i < (prop->len) / sizeof(bt_uuid_t); i++) {
-        bt_uuid_t* p_uuid = (bt_uuid_t*)prop->val + i;
-        memset(buf, 0, sizeof(buf));
-        uuid_to_string_legacy(p_uuid, buf, sizeof(buf));
-        if (strlen(value) + strlen(buf) + 1 > (int) sizeof(value) - 1) {
-          android_errorWriteLog(0x534e4554, "73963551");
-          return false;
-        }
-        strcat(value, buf);
-        // strcat(value, ";");
-        strcat(value, " ");
+      std::string val;
+      size_t cnt = (prop->len) / sizeof(Uuid);
+      for (size_t i = 0; i < cnt; i++) {
+        val += (reinterpret_cast<Uuid*>(prop->val) + i)->ToString() + " ";
       }
-      btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value);
+      btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, val);
       break;
     }
     case BT_PROPERTY_REMOTE_VERSION_INFO: {
@@ -264,8 +261,10 @@
       return false;
   }
 
-  /* save changes if the device was bonded */
-  if (btif_in_fetch_bonded_device(bdstr) == BT_STATUS_SUCCESS) {
+  /* No need to look for bonded device with address of NULL */
+  if (remote_bd_addr &&
+      btif_in_fetch_bonded_device(bdstr) == BT_STATUS_SUCCESS) {
+    /* save changes if the device was bonded */
     btif_config_flush();
   }
 
@@ -273,14 +272,12 @@
 }
 
 static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) {
-  std::string addrstr;
-  const char* bdstr = addrstr.c_str();
+  std::string bdstr;
   if (remote_bd_addr) {
-    addrstr = remote_bd_addr->ToString();
-    bdstr = addrstr.c_str();
+    bdstr = remote_bd_addr->ToString();
   }
-  BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type,
-                   prop->len);
+  BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr.c_str(),
+                   prop->type, prop->len);
   if (prop->len <= 0) {
     BTIF_TRACE_ERROR("property type:%d, len:%d is invalid", prop->type,
                      prop->len);
@@ -346,10 +343,10 @@
       int size = sizeof(value);
       if (btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value,
                               &size)) {
-        bt_uuid_t* p_uuid = (bt_uuid_t*)prop->val;
+        Uuid* p_uuid = reinterpret_cast<Uuid*>(prop->val);
         size_t num_uuids =
             btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS);
-        prop->len = num_uuids * sizeof(bt_uuid_t);
+        prop->len = num_uuids * sizeof(Uuid);
         ret = true;
       } else {
         prop->val = NULL;
@@ -364,11 +361,11 @@
         ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_MFCT,
                                   &info->manufacturer);
 
-        if (ret == true)
+        if (ret)
           ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_VER,
                                     &info->version);
 
-        if (ret == true)
+        if (ret)
           ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_SUBVER,
                                     &info->sub_ver);
       }
@@ -391,7 +388,7 @@
  * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
  *
  ******************************************************************************/
-static bt_status_t btif_in_fetch_bonded_device(const char* bdstr) {
+static bt_status_t btif_in_fetch_bonded_device(const std::string& bdstr) {
   bool bt_linkkey_file_found = false;
 
   LINK_KEY link_key;
@@ -407,7 +404,8 @@
   if ((btif_in_fetch_bonded_ble_device(bdstr, false, NULL) !=
        BT_STATUS_SUCCESS) &&
       (!bt_linkkey_file_found)) {
-    BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", bdstr);
+    BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found",
+                     bdstr.c_str());
     return BT_STATUS_FAIL;
   }
   return BT_STATUS_SUCCESS;
@@ -430,13 +428,13 @@
   bool bt_linkkey_file_found = false;
   int device_type;
 
-  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
-       iter != btif_config_section_end();
-       iter = btif_config_section_next(iter)) {
-    const char* name = btif_config_section_name(iter);
+  // TODO: this code is not thread safe, it can corrupt config content.
+  // b/67595284
+  for (const section_t& section : btif_config_sections()) {
+    const std::string& name = section.name;
     if (!RawAddress::IsValidAddress(name)) continue;
 
-    BTIF_TRACE_DEBUG("Remote device:%s", name);
+    BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
     LINK_KEY link_key;
     size_t size = sizeof(link_key);
     if (btif_config_get_bin(name, "LinkKey", link_key, &size)) {
@@ -465,9 +463,10 @@
         bt_linkkey_file_found = false;
       }
     }
-    if (!btif_in_fetch_bonded_ble_device(name, add, p_bonded_devices) &&
+    if (!btif_in_fetch_bonded_ble_device(name.c_str(), add, p_bonded_devices) &&
         !bt_linkkey_file_found) {
-      BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", name);
+      BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found",
+                       name.c_str());
     }
   }
   return BT_STATUS_SUCCESS;
@@ -480,11 +479,11 @@
   CHECK(device_added);
   CHECK(key_found);
 
-  char buffer[100];
-  memset(buffer, 0, sizeof(buffer));
+  tBTA_LE_KEY_VALUE key;
+  memset(&key, 0, sizeof(key));
 
-  if (btif_storage_get_ble_bonding_key(&bd_addr, key_type, buffer, key_len) ==
-      BT_STATUS_SUCCESS) {
+  if (btif_storage_get_ble_bonding_key(&bd_addr, key_type, (uint8_t*)&key,
+                                       key_len) == BT_STATUS_SUCCESS) {
     if (add_key) {
       if (!*device_added) {
         BTA_DmAddBleDevice(bd_addr, addr_type, BT_DEVICE_TYPE_BLE);
@@ -493,7 +492,7 @@
 
       BTIF_TRACE_DEBUG("%s() Adding key type %d for %s", __func__, key_type,
                        bd_addr.ToString().c_str());
-      BTA_DmAddBleKey(bd_addr, (tBTA_LE_KEY_VALUE*)buffer, key_type);
+      BTA_DmAddBleKey(bd_addr, &key, key_type);
     }
 
     *key_found = true;
@@ -520,15 +519,21 @@
  * Returns          Number of UUIDs parsed from the supplied string
  *
  ******************************************************************************/
-size_t btif_split_uuids_string(const char* str, bt_uuid_t* p_uuid,
+size_t btif_split_uuids_string(const char* str, bluetooth::Uuid* p_uuid,
                                size_t max_uuids) {
   CHECK(str);
   CHECK(p_uuid);
 
   size_t num_uuids = 0;
   while (str && num_uuids < max_uuids) {
-    bool rc = string_to_uuid(str, p_uuid++);
-    if (!rc) break;
+    bool is_valid;
+    bluetooth::Uuid tmp =
+        Uuid::FromString(std::string(str, Uuid::kString128BitLen), &is_valid);
+    if (!is_valid) break;
+
+    *p_uuid = tmp;
+    p_uuid++;
+
     num_uuids++;
     str = strchr(str, ' ');
     if (str) str++;
@@ -556,7 +561,7 @@
     RawAddress* bd_addr = (RawAddress*)property->val;
     /* Fetch the local BD ADDR */
     const controller_t* controller = controller_get_interface();
-    if (controller->get_is_ready() == false) {
+    if (!controller->get_is_ready()) {
       LOG_ERROR(LOG_TAG,
                 "%s: Controller not ready! Unable to return Bluetooth Address",
                 __func__);
@@ -587,7 +592,7 @@
     return BT_STATUS_SUCCESS;
   } else if (property->type == BT_PROPERTY_UUIDS) {
     /* publish list of local supported services */
-    bt_uuid_t* p_uuid = (bt_uuid_t*)property->val;
+    Uuid* p_uuid = reinterpret_cast<Uuid*>(property->val);
     uint32_t num_uuids = 0;
     uint32_t i;
 
@@ -599,32 +604,35 @@
       if (service_mask & (tBTA_SERVICE_MASK)(1 << i)) {
         switch (i) {
           case BTA_HFP_SERVICE_ID: {
-            uuid16_to_uuid128(UUID_SERVCLASS_AG_HANDSFREE, p_uuid + num_uuids);
+            *(p_uuid + num_uuids) =
+                Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
             num_uuids++;
           }
           /* intentional fall through: Send both BFP & HSP UUIDs if HFP is
            * enabled */
           case BTA_HSP_SERVICE_ID: {
-            uuid16_to_uuid128(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
-                              p_uuid + num_uuids);
+            *(p_uuid + num_uuids) =
+                Uuid::From16Bit(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY);
             num_uuids++;
           } break;
           case BTA_A2DP_SOURCE_SERVICE_ID: {
-            uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SOURCE, p_uuid + num_uuids);
+            *(p_uuid + num_uuids) =
+                Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SOURCE);
             num_uuids++;
           } break;
           case BTA_A2DP_SINK_SERVICE_ID: {
-            uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SINK, p_uuid + num_uuids);
+            *(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SINK);
             num_uuids++;
           } break;
           case BTA_HFP_HS_SERVICE_ID: {
-            uuid16_to_uuid128(UUID_SERVCLASS_HF_HANDSFREE, p_uuid + num_uuids);
+            *(p_uuid + num_uuids) =
+                Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);
             num_uuids++;
           } break;
         }
       }
     }
-    property->len = (num_uuids) * sizeof(bt_uuid_t);
+    property->len = (num_uuids) * sizeof(Uuid);
     return BT_STATUS_SUCCESS;
   }
 
@@ -736,15 +744,14 @@
 bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr,
                                            LINK_KEY link_key, uint8_t key_type,
                                            uint8_t pin_length) {
-  std::string addrstr = remote_bd_addr->ToString();
-  const char* bdstr = addrstr.c_str();
+  std::string bdstr = remote_bd_addr->ToString();
   int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type);
   ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length);
   ret &= btif_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY));
 
   if (is_restricted_mode()) {
     BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted",
-                       __func__, bdstr);
+                       __func__, bdstr.c_str());
     btif_config_set_int(bdstr, "Restricted", 1);
   }
 
@@ -765,9 +772,8 @@
  ******************************************************************************/
 bt_status_t btif_storage_remove_bonded_device(
     const RawAddress* remote_bd_addr) {
-  std::string addrstr = remote_bd_addr->ToString();
-  const char* bdstr = addrstr.c_str();
-  BTIF_TRACE_DEBUG("in bd addr:%s", bdstr);
+  std::string bdstr = remote_bd_addr->ToString();
+  BTIF_TRACE_DEBUG("in bd addr:%s", bdstr.c_str());
 
   btif_storage_remove_ble_bonding_keys(remote_bd_addr);
 
@@ -778,6 +784,9 @@
     ret &= btif_config_remove(bdstr, "PinLength");
   if (btif_config_exist(bdstr, "LinkKey"))
     ret &= btif_config_remove(bdstr, "LinkKey");
+  if (btif_config_exist(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE)) {
+    ret &= btif_config_remove(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE);
+  }
   /* write bonded info immediately */
   btif_config_flush();
   return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
@@ -806,8 +815,8 @@
   bt_bdname_t name, alias;
   bt_scan_mode_t mode;
   uint32_t disc_timeout;
-  bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
-  bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+  Uuid local_uuids[BT_MAX_NUM_UUIDS];
+  Uuid remote_uuids[BT_MAX_NUM_UUIDS];
   bt_status_t status;
 
   btif_in_fetch_bonded_devices(&bonded_devices, 1);
@@ -930,7 +939,8 @@
  ******************************************************************************/
 
 bt_status_t btif_storage_add_ble_bonding_key(RawAddress* remote_bd_addr,
-                                             char* key, uint8_t key_type,
+                                             const uint8_t* key,
+                                             uint8_t key_type,
                                              uint8_t key_length) {
   const char* name;
   switch (key_type) {
@@ -955,8 +965,8 @@
     default:
       return BT_STATUS_FAIL;
   }
-  int ret = btif_config_set_bin(remote_bd_addr->ToString().c_str(), name,
-                                (const uint8_t*)key, key_length);
+  int ret =
+      btif_config_set_bin(remote_bd_addr->ToString(), name, key, key_length);
   btif_config_save();
   return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
@@ -972,7 +982,8 @@
  *
  ******************************************************************************/
 bt_status_t btif_storage_get_ble_bonding_key(RawAddress* remote_bd_addr,
-                                             uint8_t key_type, char* key_value,
+                                             uint8_t key_type,
+                                             uint8_t* key_value,
                                              int key_length) {
   const char* name;
   switch (key_type) {
@@ -997,8 +1008,8 @@
       return BT_STATUS_FAIL;
   }
   size_t length = key_length;
-  int ret = btif_config_get_bin(remote_bd_addr->ToString().c_str(), name,
-                                (uint8_t*)key_value, &length);
+  int ret =
+      btif_config_get_bin(remote_bd_addr->ToString(), name, key_value, &length);
   return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 
@@ -1014,9 +1025,8 @@
  ******************************************************************************/
 bt_status_t btif_storage_remove_ble_bonding_keys(
     const RawAddress* remote_bd_addr) {
-  std::string addrstr = remote_bd_addr->ToString();
-  const char* bdstr = addrstr.c_str();
-  BTIF_TRACE_DEBUG(" %s in bd addr:%s", __func__, bdstr);
+  std::string bdstr = remote_bd_addr->ToString();
+  BTIF_TRACE_DEBUG(" %s in bd addr:%s", __func__, bdstr.c_str());
   int ret = 1;
   if (btif_config_exist(bdstr, "LE_KEY_PENC"))
     ret &= btif_config_remove(bdstr, "LE_KEY_PENC");
@@ -1126,7 +1136,7 @@
 }
 
 static bt_status_t btif_in_fetch_bonded_ble_device(
-    const char* remote_bd_addr, int add,
+    const std::string& remote_bd_addr, int add,
     btif_bonded_devices_t* p_bonded_devices) {
   int device_type;
   int addr_type;
@@ -1138,7 +1148,8 @@
 
   if ((device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE ||
       btif_has_ble_keys(remote_bd_addr)) {
-    BTIF_TRACE_DEBUG("%s Found a LE device: %s", __func__, remote_bd_addr);
+    BTIF_TRACE_DEBUG("%s Found a LE device: %s", __func__,
+                     remote_bd_addr.c_str());
 
     RawAddress bd_addr;
     RawAddress::FromString(remote_bd_addr, bd_addr);
@@ -1180,12 +1191,12 @@
 
 bt_status_t btif_storage_set_remote_addr_type(const RawAddress* remote_bd_addr,
                                               uint8_t addr_type) {
-  int ret = btif_config_set_int(remote_bd_addr->ToString().c_str(), "AddrType",
+  int ret = btif_config_set_int(remote_bd_addr->ToString(), "AddrType",
                                 (int)addr_type);
   return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 
-bool btif_has_ble_keys(const char* bdstr) {
+bool btif_has_ble_keys(const std::string& bdstr) {
   return btif_config_exist(bdstr, "LE_KEY_PENC");
 }
 
@@ -1201,8 +1212,8 @@
  ******************************************************************************/
 bt_status_t btif_storage_get_remote_addr_type(const RawAddress* remote_bd_addr,
                                               int* addr_type) {
-  int ret = btif_config_get_int(remote_bd_addr->ToString().c_str(), "AddrType",
-                                addr_type);
+  int ret =
+      btif_config_get_int(remote_bd_addr->ToString(), "AddrType", addr_type);
   return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 /*******************************************************************************
@@ -1223,8 +1234,7 @@
     uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
     uint16_t dl_len, uint8_t* dsc_list) {
   BTIF_TRACE_DEBUG("btif_storage_add_hid_device_info:");
-  std::string addrstr = remote_bd_addr->ToString();
-  const char* bdstr = addrstr.c_str();
+  std::string bdstr = remote_bd_addr->ToString();
   btif_config_set_int(bdstr, "HidAttrMask", attr_mask);
   btif_config_set_int(bdstr, "HidSubClass", sub_class);
   btif_config_set_int(bdstr, "HidAppId", app_id);
@@ -1250,69 +1260,67 @@
  *
  ******************************************************************************/
 bt_status_t btif_storage_load_bonded_hid_info(void) {
-  RawAddress bd_addr;
-  tBTA_HH_DEV_DSCP_INFO dscp_info;
-  uint16_t attr_mask;
-  uint8_t sub_class;
-  uint8_t app_id;
-
-  memset(&dscp_info, 0, sizeof(dscp_info));
-  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
-       iter != btif_config_section_end();
-       iter = btif_config_section_next(iter)) {
-    const char* name = btif_config_section_name(iter);
+  // TODO: this code is not thread safe, it can corrupt config content.
+  // b/67595284
+  for (const section_t& section : btif_config_sections()) {
+    const std::string& name = section.name;
     if (!RawAddress::IsValidAddress(name)) continue;
 
-    BTIF_TRACE_DEBUG("Remote device:%s", name);
+    BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
+
     int value;
-    if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
-      if (btif_config_get_int(name, "HidAttrMask", &value)) {
-        attr_mask = (uint16_t)value;
+    if (!btif_config_get_int(name, "HidAttrMask", &value)) continue;
+    uint16_t attr_mask = (uint16_t)value;
 
-        btif_config_get_int(name, "HidSubClass", &value);
-        sub_class = (uint8_t)value;
+    if (btif_in_fetch_bonded_device(name) != BT_STATUS_SUCCESS) {
+      RawAddress bd_addr;
+      RawAddress::FromString(name, bd_addr);
+      btif_storage_remove_hid_info(&bd_addr);
+      continue;
+    }
 
-        btif_config_get_int(name, "HidAppId", &value);
-        app_id = (uint8_t)value;
+    tBTA_HH_DEV_DSCP_INFO dscp_info;
+    memset(&dscp_info, 0, sizeof(dscp_info));
 
-        btif_config_get_int(name, "HidVendorId", &value);
-        dscp_info.vendor_id = (uint16_t)value;
+    btif_config_get_int(name, "HidSubClass", &value);
+    uint8_t sub_class = (uint8_t)value;
 
-        btif_config_get_int(name, "HidProductId", &value);
-        dscp_info.product_id = (uint16_t)value;
+    btif_config_get_int(name, "HidAppId", &value);
+    uint8_t app_id = (uint8_t)value;
 
-        btif_config_get_int(name, "HidVersion", &value);
-        dscp_info.version = (uint8_t)value;
+    btif_config_get_int(name, "HidVendorId", &value);
+    dscp_info.vendor_id = (uint16_t)value;
 
-        btif_config_get_int(name, "HidCountryCode", &value);
-        dscp_info.ctry_code = (uint8_t)value;
+    btif_config_get_int(name, "HidProductId", &value);
+    dscp_info.product_id = (uint16_t)value;
 
-        value = 0;
-        btif_config_get_int(name, "HidSSRMaxLatency", &value);
-        dscp_info.ssr_max_latency = (uint16_t)value;
+    btif_config_get_int(name, "HidVersion", &value);
+    dscp_info.version = (uint8_t)value;
 
-        value = 0;
-        btif_config_get_int(name, "HidSSRMinTimeout", &value);
-        dscp_info.ssr_min_tout = (uint16_t)value;
+    btif_config_get_int(name, "HidCountryCode", &value);
+    dscp_info.ctry_code = (uint8_t)value;
 
-        size_t len = btif_config_get_bin_length(name, "HidDescriptor");
-        if (len > 0) {
-          dscp_info.descriptor.dl_len = (uint16_t)len;
-          dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
-          btif_config_get_bin(name, "HidDescriptor",
-                              (uint8_t*)dscp_info.descriptor.dsc_list, &len);
-        }
-        RawAddress::FromString(name, bd_addr);
-        // add extracted information to BTA HH
-        if (btif_hh_add_added_dev(bd_addr, attr_mask)) {
-          BTA_HhAddDev(bd_addr, attr_mask, sub_class, app_id, dscp_info);
-        }
-      }
-    } else {
-      if (btif_config_get_int(name, "HidAttrMask", &value)) {
-        btif_storage_remove_hid_info(&bd_addr);
-        RawAddress::FromString(name, bd_addr);
-      }
+    value = 0;
+    btif_config_get_int(name, "HidSSRMaxLatency", &value);
+    dscp_info.ssr_max_latency = (uint16_t)value;
+
+    value = 0;
+    btif_config_get_int(name, "HidSSRMinTimeout", &value);
+    dscp_info.ssr_min_tout = (uint16_t)value;
+
+    size_t len = btif_config_get_bin_length(name, "HidDescriptor");
+    if (len > 0) {
+      dscp_info.descriptor.dl_len = (uint16_t)len;
+      dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
+      btif_config_get_bin(name, "HidDescriptor",
+                          (uint8_t*)dscp_info.descriptor.dsc_list, &len);
+    }
+
+    RawAddress bd_addr;
+    RawAddress::FromString(name, bd_addr);
+    // add extracted information to BTA HH
+    if (btif_hh_add_added_dev(bd_addr, attr_mask)) {
+      BTA_HhAddDev(bd_addr, attr_mask, sub_class, app_id, dscp_info);
     }
   }
 
@@ -1331,8 +1339,7 @@
  *
  ******************************************************************************/
 bt_status_t btif_storage_remove_hid_info(RawAddress* remote_bd_addr) {
-  std::string addrstr = remote_bd_addr->ToString();
-  const char* bdstr = addrstr.c_str();
+  std::string bdstr = remote_bd_addr->ToString();
 
   btif_config_remove(bdstr, "HidAttrMask");
   btif_config_remove(bdstr, "HidSubClass");
@@ -1348,6 +1355,135 @@
   return BT_STATUS_SUCCESS;
 }
 
+constexpr char HEARING_AID_PSM[] = "HearingAidPsm";
+constexpr char HEARING_AID_CAPABILITIES[] = "HearingAidCapabilities";
+constexpr char HEARING_AID_CODECS[] = "HearingAidCodecs";
+constexpr char HEARING_AID_AUDIO_CONTROL_POINT[] =
+    "HearingAidAudioControlPoint";
+constexpr char HEARING_AID_VOLUME_HANDLE[] = "HearingAidVolumeHandle";
+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,
+                                  uint16_t audio_control_point_handle,
+                                  uint16_t volume_handle, uint64_t hi_sync_id,
+                                  uint16_t render_delay,
+                                  uint16_t preparation_delay) {
+  do_in_jni_thread(
+      FROM_HERE,
+      Bind(
+          [](const RawAddress& address, uint16_t psm, uint8_t capabilities,
+             uint16_t codecs, uint16_t audio_control_point_handle,
+             uint16_t volume_handle, uint64_t hi_sync_id, uint16_t render_delay,
+             uint16_t preparation_delay) {
+            std::string bdstr = address.ToString();
+            VLOG(2) << "saving hearing aid device: " << bdstr;
+            btif_config_set_int(bdstr, HEARING_AID_PSM, psm);
+            btif_config_set_int(bdstr, HEARING_AID_CAPABILITIES, capabilities);
+            btif_config_set_int(bdstr, HEARING_AID_CODECS, codecs);
+            btif_config_set_int(bdstr, HEARING_AID_AUDIO_CONTROL_POINT,
+                                audio_control_point_handle);
+            btif_config_set_int(bdstr, HEARING_AID_VOLUME_HANDLE,
+                                volume_handle);
+            btif_config_set_uint64(bdstr, HEARING_AID_SYNC_ID, hi_sync_id);
+            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,
+          volume_handle, hi_sync_id, render_delay, preparation_delay));
+}
+
+/** Loads information about bonded hearing aid devices */
+void btif_storage_load_bonded_hearing_aids() {
+  // TODO: this code is not thread safe, it can corrupt config content.
+  // b/67595284
+  for (const section_t& section : btif_config_sections()) {
+    const std::string& name = section.name;
+    if (!RawAddress::IsValidAddress(name)) continue;
+
+    BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
+
+    int value;
+    if (!btif_config_get_int(name, HEARING_AID_PSM, &value)) continue;
+    uint16_t psm = value;
+
+    if (btif_in_fetch_bonded_device(name.c_str()) != BT_STATUS_SUCCESS) {
+      RawAddress bd_addr;
+      RawAddress::FromString(name, bd_addr);
+      btif_storage_remove_hearing_aid(bd_addr);
+      continue;
+    }
+
+    uint8_t capabilities = 0;
+    if (btif_config_get_int(name, HEARING_AID_CAPABILITIES, &value))
+      capabilities = value;
+
+    uint16_t codecs = 0;
+    if (btif_config_get_int(name, HEARING_AID_CODECS, &value)) codecs = value;
+
+    uint16_t audio_control_point_handle = 0;
+    if (btif_config_get_int(name, HEARING_AID_AUDIO_CONTROL_POINT, &value))
+      audio_control_point_handle = value;
+
+    uint16_t volume_handle = 0;
+    if (btif_config_get_int(name, HEARING_AID_VOLUME_HANDLE, &value))
+      volume_handle = value;
+
+    uint64_t lvalue;
+    uint64_t hi_sync_id = 0;
+    if (btif_config_get_uint64(name, HEARING_AID_SYNC_ID, &lvalue))
+      hi_sync_id = lvalue;
+
+    uint16_t render_delay = 0;
+    if (btif_config_get_int(name, HEARING_AID_RENDER_DELAY, &value))
+      render_delay = value;
+
+    uint16_t preparation_delay = 0;
+    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, is_white_listed));
+  }
+}
+
+/** Deletes the bonded hearing aid device info from NVRAM */
+void btif_storage_remove_hearing_aid(const RawAddress& address) {
+  std::string addrstr = address.ToString();
+
+  btif_config_remove(addrstr, HEARING_AID_PSM);
+  btif_config_remove(addrstr, HEARING_AID_CAPABILITIES);
+  btif_config_remove(addrstr, HEARING_AID_CODECS);
+  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
@@ -1360,7 +1496,7 @@
  *
  ******************************************************************************/
 bool btif_storage_is_restricted_device(const RawAddress* remote_bd_addr) {
-  return btif_config_exist(remote_bd_addr->ToString().c_str(), "Restricted");
+  return btif_config_exist(remote_bd_addr->ToString(), "Restricted");
 }
 
 /*******************************************************************************
@@ -1372,14 +1508,13 @@
  *
  ******************************************************************************/
 bt_status_t btif_storage_load_hidd(void) {
-
-  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
-       iter != btif_config_section_end();
-       iter = btif_config_section_next(iter)) {
-    const char* name = btif_config_section_name(iter);
+  // TODO: this code is not thread safe, it can corrupt config content.
+  // b/67595284
+  for (const section_t& section : btif_config_sections()) {
+    const std::string& name = section.name;
     if (!RawAddress::IsValidAddress(name)) continue;
 
-    BTIF_TRACE_DEBUG("Remote device:%s", name);
+    BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
     int value;
     if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
       if (btif_config_get_int(name, "HidDeviceCabled", &value)) {
@@ -1398,13 +1533,23 @@
  *
  * Function         btif_storage_set_hidd
  *
- * Description      Stores hidd bonded device info in nvram.
+ * Description      Stores currently used HIDD device info in nvram and remove
+ *                  the "HidDeviceCabled" flag from unused devices
  *
  * Returns          BT_STATUS_SUCCESS
  *
  ******************************************************************************/
 bt_status_t btif_storage_set_hidd(RawAddress* remote_bd_addr) {
-  btif_config_set_int(remote_bd_addr->ToString().c_str(), "HidDeviceCabled", 1);
+  std::string remote_device_address_string = remote_bd_addr->ToString();
+  for (const section_t& section : btif_config_sections()) {
+    if (!RawAddress::IsValidAddress(section.name)) continue;
+    if (section.name == remote_device_address_string) continue;
+    if (btif_in_fetch_bonded_device(section.name) == BT_STATUS_SUCCESS) {
+      btif_config_remove(section.name, "HidDeviceCabled");
+    }
+  }
+
+  btif_config_set_int(remote_device_address_string, "HidDeviceCabled", 1);
   btif_config_save();
   return BT_STATUS_SUCCESS;
 }
@@ -1419,7 +1564,7 @@
  *
  ******************************************************************************/
 bt_status_t btif_storage_remove_hidd(RawAddress* remote_bd_addr) {
-  btif_config_remove(remote_bd_addr->ToString().c_str(), "HidDeviceCabled");
+  btif_config_remove(remote_bd_addr->ToString(), "HidDeviceCabled");
   btif_config_save();
 
   return BT_STATUS_SUCCESS;
diff --git a/btif/src/btif_uid.cc b/btif/src/btif_uid.cc
index 45e3456..4ee5fe8 100644
--- a/btif/src/btif_uid.cc
+++ b/btif/src/btif_uid.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -27,13 +27,14 @@
 #include "bt_common.h"
 #include "btif_uid.h"
 
+static std::mutex set_lock;
+
 typedef struct uid_set_node_t {
   struct uid_set_node_t* next;
   bt_uid_traffic_t data;
 } uid_set_node_t;
 
 typedef struct uid_set_t {
-  std::mutex lock;
   uid_set_node_t* head;
 } uid_set_t;
 
@@ -43,7 +44,7 @@
 }
 
 void uid_set_destroy(uid_set_t* set) {
-  std::unique_lock<std::mutex> lock(set->lock);
+  std::unique_lock<std::mutex> guard(set_lock);
   uid_set_node_t* node = set->head;
   while (node) {
     uid_set_node_t* temp = node;
@@ -74,7 +75,7 @@
 void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
   if (app_uid == -1 || bytes == 0) return;
 
-  std::unique_lock<std::mutex> lock(set->lock);
+  std::unique_lock<std::mutex> guard(set_lock);
   uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
   node->data.tx_bytes += bytes;
 }
@@ -82,13 +83,13 @@
 void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
   if (app_uid == -1 || bytes == 0) return;
 
-  std::unique_lock<std::mutex> lock(set->lock);
+  std::unique_lock<std::mutex> guard(set_lock);
   uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
   node->data.rx_bytes += bytes;
 }
 
 bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
-  std::unique_lock<std::mutex> lock(set->lock);
+  std::unique_lock<std::mutex> guard(set_lock);
 
   // Find the length
   size_t len = 0;
diff --git a/btif/src/btif_util.cc b/btif/src/btif_util.cc
index 932c55a..26d84fd 100644
--- a/btif/src/btif_util.cc
+++ b/btif/src/btif_util.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 2009-2016 Broadcom Corporation
+ *  Copyright 2009-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -56,29 +56,6 @@
  *  Constants & Macros
  ******************************************************************************/
 #define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
-#define ISXDIGIT(a)                                                    \
-  ((((a) >= '0') && ((a) <= '9')) || (((a) >= 'A') && ((a) <= 'F')) || \
-   (((a) >= 'a') && ((a) <= 'f')))
-
-/*******************************************************************************
- *  Local type definitions
- ******************************************************************************/
-
-/*******************************************************************************
- *  Static variables
- ******************************************************************************/
-
-/*******************************************************************************
- *  Static functions
- ******************************************************************************/
-
-/*******************************************************************************
- *  Externs
- ******************************************************************************/
-
-/*******************************************************************************
- *  Functions
- ******************************************************************************/
 
 /*****************************************************************************
  *   Logging helper functions
@@ -100,64 +77,6 @@
   dev_class[0] = (uint8_t)(cod >> 16);
 }
 
-static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                        0x5F, 0x9B, 0x34, 0xFB};
-
-void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128) {
-  uint16_t uuid16_bo;
-  memset(uuid128, 0, sizeof(bt_uuid_t));
-
-  memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE);
-  uuid16_bo = ntohs(uuid16);
-  memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t));
-}
-
-bool string_to_uuid(const char* str, bt_uuid_t* p_uuid) {
-  CHECK(p_uuid);
-  if (str == NULL) return false;
-
-  uint32_t uuid0, uuid4;
-  uint16_t uuid1, uuid2, uuid3, uuid5;
-
-  int rc = sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx", &uuid0, &uuid1,
-                  &uuid2, &uuid3, &uuid4, &uuid5);
-  if (rc != 6) return false;
-
-  uuid0 = htonl(uuid0);
-  uuid1 = htons(uuid1);
-  uuid2 = htons(uuid2);
-  uuid3 = htons(uuid3);
-  uuid4 = htonl(uuid4);
-  uuid5 = htons(uuid5);
-
-  memcpy(&(p_uuid->uu[0]), &uuid0, 4);
-  memcpy(&(p_uuid->uu[4]), &uuid1, 2);
-  memcpy(&(p_uuid->uu[6]), &uuid2, 2);
-  memcpy(&(p_uuid->uu[8]), &uuid3, 2);
-  memcpy(&(p_uuid->uu[10]), &uuid4, 4);
-  memcpy(&(p_uuid->uu[14]), &uuid5, 2);
-
-  return true;
-}
-
-void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len) {
-  uint32_t uuid0, uuid4;
-  uint16_t uuid1, uuid2, uuid3, uuid5;
-
-  memcpy(&uuid0, &(p_uuid->uu[0]), 4);
-  memcpy(&uuid1, &(p_uuid->uu[4]), 2);
-  memcpy(&uuid2, &(p_uuid->uu[6]), 2);
-  memcpy(&uuid3, &(p_uuid->uu[8]), 2);
-  memcpy(&uuid4, &(p_uuid->uu[10]), 4);
-  memcpy(&uuid5, &(p_uuid->uu[14]), 2);
-
-  snprintf(str, str_len, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", ntohl(uuid0),
-           ntohs(uuid1), ntohs(uuid2), ntohs(uuid3), ntohl(uuid4),
-           ntohs(uuid5));
-  return;
-}
-
 /*****************************************************************************
  *  Function        ascii_2_hex
  *
@@ -291,6 +210,7 @@
     CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
     CASE_RETURN_STR(BTA_AG_AT_BIND_EVT)
     CASE_RETURN_STR(BTA_AG_AT_BIEV_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BIA_EVT)
 
     default:
       return "UNKNOWN MSG ID";
@@ -349,18 +269,6 @@
   }
 }
 
-const char* dump_hf_conn_state(uint16_t event) {
-  switch (event) {
-    CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTED)
-    CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTING)
-    CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTED)
-    CASE_RETURN_STR(BTHF_CONNECTION_STATE_SLC_CONNECTED)
-    CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTING)
-    default:
-      return "UNKNOWN MSG ID";
-  }
-}
-
 const char* dump_hd_event(uint16_t event) {
   switch (event) {
     CASE_RETURN_STR(BTA_HD_ENABLE_EVT)
@@ -381,20 +289,6 @@
   }
 }
 
-const char* dump_hf_call_state(bthf_call_state_t call_state) {
-  switch (call_state) {
-    CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
-    CASE_RETURN_STR(BTHF_CALL_STATE_HELD)
-    CASE_RETURN_STR(BTHF_CALL_STATE_DIALING)
-    CASE_RETURN_STR(BTHF_CALL_STATE_ALERTING)
-    CASE_RETURN_STR(BTHF_CALL_STATE_INCOMING)
-    CASE_RETURN_STR(BTHF_CALL_STATE_WAITING)
-    CASE_RETURN_STR(BTHF_CALL_STATE_ACTIVE)
-    default:
-      return "UNKNOWN CALL STATE";
-  }
-}
-
 const char* dump_thread_evt(bt_cb_thread_evt evt) {
   switch (evt) {
     CASE_RETURN_STR(ASSOCIATE_JVM)
@@ -405,17 +299,6 @@
   }
 }
 
-const char* dump_hf_audio_state(uint16_t event) {
-  switch (event) {
-    CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTED)
-    CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTING)
-    CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTED)
-    CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTING)
-    default:
-      return "UNKNOWN MSG ID";
-  }
-}
-
 const char* dump_av_conn_state(uint16_t event) {
   switch (event) {
     CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTED)
diff --git a/btif/src/stack_manager.cc b/btif/src/stack_manager.cc
index eb0ac22..e37db87 100644
--- a/btif/src/stack_manager.cc
+++ b/btif/src/stack_manager.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -194,8 +194,6 @@
 
 // Synchronous function to clean up the stack
 static void event_clean_up_stack(void* context) {
-  future_t* local_hack_future;
-
   if (!stack_is_initialized) {
     LOG_INFO(LOG_TAG, "%s found the stack already in a clean state", __func__);
     goto cleanup;
@@ -204,8 +202,6 @@
   ensure_stack_is_not_running();
 
   LOG_INFO(LOG_TAG, "%s is cleaning up the stack", __func__);
-  local_hack_future = future_new();
-  hack_future = local_hack_future;
   stack_is_initialized = false;
 
   btif_cleanup_bluetooth();
diff --git a/btif/test/btif_profile_queue_test.cc b/btif/test/btif_profile_queue_test.cc
index 79a283f..f7bce86 100644
--- a/btif/test/btif_profile_queue_test.cc
+++ b/btif/test/btif_profile_queue_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 Google, Inc.
+ *  Copyright 2017 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -17,27 +17,28 @@
  ******************************************************************************/
 #include <gtest/gtest.h>
 
+#include <base/bind.h>
+
+#include "base/location.h"
 #include "btif/include/btif_profile_queue.h"
 #include "stack_manager.h"
 #include "types/raw_address.h"
 
-static bool sStackRunning;
-
-bool get_stack_is_running(void) { return sStackRunning; }
-
-static stack_manager_t sStackManager = {nullptr, nullptr, nullptr, nullptr,
-                                        get_stack_is_running};
-
-const stack_manager_t* stack_manager_get_interface() { return &sStackManager; }
-
 typedef void(tBTIF_CBACK)(uint16_t event, char* p_param);
 typedef void(tBTIF_COPY_CBACK)(uint16_t event, char* p_dest, char* p_src);
-bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
-                                  char* p_params, int param_len,
-                                  tBTIF_COPY_CBACK* p_copy_cback) {
-  p_cback(event, p_params);
+
+// NOTE: Local re-implementation of functions to avoid thread context switching
+static bool sStackRunning;
+bool get_stack_is_running(void) { return sStackRunning; }
+static stack_manager_t sStackManager = {nullptr, nullptr, nullptr, nullptr,
+                                        get_stack_is_running};
+const stack_manager_t* stack_manager_get_interface() { return &sStackManager; }
+bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
+                             const base::Closure& task) {
+  task.Run();
   return BT_STATUS_SUCCESS;
 }
+bool is_on_jni_thread() { return true; }
 
 enum ResultType {
   NOT_SET = 0,
@@ -130,14 +131,30 @@
   sResult = NOT_SET;
   btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb);
   EXPECT_EQ(sResult, NOT_SET);
+  // Third item for same UUID1, but different address ADDR2
   sResult = NOT_SET;
+  btif_queue_connect(kTestUuid1, &kTestAddr2, test_connect_cb);
+  EXPECT_EQ(sResult, NOT_SET);
+  // Fourth item for same UUID2, but different address ADDR2
+  sResult = NOT_SET;
+  btif_queue_connect(kTestUuid2, &kTestAddr2, test_connect_cb);
+  EXPECT_EQ(sResult, NOT_SET);
   // Connect next doesn't work
+  sResult = NOT_SET;
   btif_queue_connect_next();
   EXPECT_EQ(sResult, NOT_SET);
-  // Advance moves queue to execute next item
+  // Advance moves queue to execute second item
   sResult = NOT_SET;
   btif_queue_advance();
   EXPECT_EQ(sResult, UUID2_ADDR1);
+  // Advance moves queue to execute third item
+  sResult = NOT_SET;
+  btif_queue_advance();
+  EXPECT_EQ(sResult, UUID1_ADDR2);
+  // Advance moves queue to execute fourth item
+  sResult = NOT_SET;
+  btif_queue_advance();
+  EXPECT_EQ(sResult, UUID2_ADDR2);
 }
 
 TEST_F(BtifProfileQueueTest, test_cleanup_first_allow_second) {
diff --git a/btif/test/btif_state_machine_test.cc b/btif/test/btif_state_machine_test.cc
new file mode 100644
index 0000000..d413a4a
--- /dev/null
+++ b/btif/test/btif_state_machine_test.cc
@@ -0,0 +1,261 @@
+/******************************************************************************
+ *
+ *  Copyright 2017 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 <gtest/gtest.h>
+
+#include "btif/include/btif_state_machine.h"
+
+namespace {
+static constexpr uint32_t kInvalidEvent = 0xffffffff;
+static constexpr uint32_t kEventZero = 0;
+static constexpr uint32_t kEventOne = 1;
+static constexpr uint32_t kEventTwo = 2;
+
+static char dataZero = 0;
+static char dataOne = 1;
+static char dataTwo = 2;
+}  // namespace
+
+class BtifStateMachineImpl : public BtifStateMachine {
+ public:
+  enum {
+    kStateZero,
+    kStateOne,
+    kStateTwo,
+  };
+
+  class StateZero : public State {
+   public:
+    StateZero(BtifStateMachine& sm)
+        : State(sm, kStateZero),
+          on_enter_(false),
+          on_exit_(false),
+          event_(kInvalidEvent),
+          data_(nullptr) {}
+    void OnEnter() override {
+      on_enter_ = true;
+      on_exit_ = false;
+    }
+    void OnExit() override {
+      on_exit_ = true;
+      on_enter_ = false;
+    }
+    bool ProcessEvent(uint32_t event, void* p_data) override {
+      event_ = event;
+      data_ = p_data;
+      TransitionTo(kStateOne);
+      return true;
+    }
+
+    bool on_enter_;
+    bool on_exit_;
+    uint32_t event_;
+    void* data_;
+  };
+
+  class StateOne : public State {
+   public:
+    StateOne(BtifStateMachine& sm)
+        : State(sm, kStateOne),
+          on_enter_(false),
+          on_exit_(false),
+          event_(kInvalidEvent),
+          data_(nullptr) {}
+    void OnEnter() override {
+      on_enter_ = true;
+      on_exit_ = false;
+    }
+    void OnExit() override {
+      on_exit_ = true;
+      on_enter_ = false;
+    }
+    bool ProcessEvent(uint32_t event, void* p_data) override {
+      event_ = event;
+      data_ = p_data;
+      TransitionTo(kStateTwo);
+      return true;
+    }
+
+    bool on_enter_;
+    bool on_exit_;
+    uint32_t event_;
+    void* data_;
+  };
+
+  class StateTwo : public State {
+   public:
+    StateTwo(BtifStateMachine& sm)
+        : State(sm, kStateTwo),
+          on_enter_(false),
+          on_exit_(false),
+          event_(kInvalidEvent),
+          data_(nullptr) {}
+    void OnEnter() override {
+      on_enter_ = true;
+      on_exit_ = false;
+    }
+    void OnExit() override {
+      on_exit_ = true;
+      on_enter_ = false;
+    }
+    bool ProcessEvent(uint32_t event, void* p_data) override {
+      event_ = event;
+      data_ = p_data;
+      TransitionTo(kStateZero);
+      return true;
+    }
+
+    bool on_enter_;
+    bool on_exit_;
+    uint32_t event_;
+    void* data_;
+  };
+
+  BtifStateMachineImpl() {
+    state_zero_ = new StateZero(*this);
+    state_one_ = new StateOne(*this);
+    state_two_ = new StateTwo(*this);
+
+    AddState(state_zero_);
+    AddState(state_one_);
+    AddState(state_two_);
+    SetInitialState(state_zero_);
+  }
+
+  StateZero* state_zero_;
+  StateOne* state_one_;
+  StateTwo* state_two_;
+};
+
+class BtifStateMachineTest : public ::testing::Test {
+ protected:
+  BtifStateMachineTest() {}
+
+  void SetUp() override { sm_.Start(); }
+
+  void TearDown() override { sm_.Quit(); }
+
+  BtifStateMachineImpl sm_;
+};
+
+TEST_F(BtifStateMachineTest, test_initial_state) {
+  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+}
+
+TEST_F(BtifStateMachineTest, test_invalid_state) {
+  sm_.Quit();
+  ASSERT_EQ(sm_.kStateInvalid, sm_.StateId());
+  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+  sm_.Start();
+  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+}
+
+TEST_F(BtifStateMachineTest, test_transition_to) {
+  // Initial state: StateZero
+  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+  ASSERT_TRUE(sm_.state_zero_->on_enter_);
+  ASSERT_FALSE(sm_.state_zero_->on_exit_);
+
+  // Transition to StateOne
+  ASSERT_FALSE(sm_.state_one_->on_enter_);
+  ASSERT_FALSE(sm_.state_one_->on_exit_);
+  sm_.TransitionTo(sm_.kStateOne);
+  ASSERT_EQ(sm_.kStateOne, sm_.StateId());
+  ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
+  ASSERT_TRUE(sm_.state_zero_->on_exit_);
+  ASSERT_TRUE(sm_.state_one_->on_enter_);
+  ASSERT_FALSE(sm_.state_one_->on_exit_);
+
+  // Transition to StateTwo
+  ASSERT_FALSE(sm_.state_two_->on_enter_);
+  ASSERT_FALSE(sm_.state_two_->on_exit_);
+  sm_.TransitionTo(sm_.kStateTwo);
+  ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
+  ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
+  ASSERT_TRUE(sm_.state_one_->on_exit_);
+  ASSERT_TRUE(sm_.state_two_->on_enter_);
+  ASSERT_FALSE(sm_.state_two_->on_exit_);
+}
+
+TEST_F(BtifStateMachineTest, test_process_event) {
+  // Initial state: StateZero
+  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+  ASSERT_TRUE(sm_.state_zero_->on_enter_);
+  ASSERT_FALSE(sm_.state_zero_->on_exit_);
+  ASSERT_EQ(sm_.state_zero_->event_, kInvalidEvent);
+  ASSERT_EQ(sm_.state_zero_->data_, nullptr);
+
+  // Process an event and transition to StateOne
+  ASSERT_FALSE(sm_.state_one_->on_enter_);
+  ASSERT_FALSE(sm_.state_one_->on_exit_);
+  ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
+  ASSERT_EQ(sm_.state_one_->data_, nullptr);
+  ASSERT_TRUE(sm_.ProcessEvent(kEventZero, &dataZero));
+  ASSERT_EQ(sm_.kStateOne, sm_.StateId());
+  ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
+  // Check StateZero
+  ASSERT_EQ(sm_.state_zero_->event_, kEventZero);
+  ASSERT_EQ(sm_.state_zero_->data_, &dataZero);
+  ASSERT_TRUE(sm_.state_zero_->on_exit_);
+  // Check StateOne
+  ASSERT_TRUE(sm_.state_one_->on_enter_);
+  ASSERT_FALSE(sm_.state_one_->on_exit_);
+  ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
+  ASSERT_EQ(sm_.state_one_->data_, nullptr);
+
+  // Process an event and transition to StateTwo
+  ASSERT_FALSE(sm_.state_two_->on_enter_);
+  ASSERT_FALSE(sm_.state_two_->on_exit_);
+  ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
+  ASSERT_EQ(sm_.state_two_->data_, nullptr);
+  ASSERT_TRUE(sm_.ProcessEvent(kEventOne, &dataOne));
+  ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
+  ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
+  // Check StateOne
+  ASSERT_EQ(sm_.state_one_->event_, kEventOne);
+  ASSERT_EQ(sm_.state_one_->data_, &dataOne);
+  ASSERT_TRUE(sm_.state_one_->on_exit_);
+  // Check StateTwo
+  ASSERT_TRUE(sm_.state_two_->on_enter_);
+  ASSERT_FALSE(sm_.state_two_->on_exit_);
+  ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
+  ASSERT_EQ(sm_.state_two_->data_, nullptr);
+
+  // Process an event and transition to StateZero
+  // NOTE: StateZero was exited before and has local state
+  ASSERT_FALSE(sm_.state_zero_->on_enter_);
+  ASSERT_TRUE(sm_.state_zero_->on_exit_);  // NOTE: already exited before
+  ASSERT_EQ(sm_.state_zero_->event_, kEventZero);  // NOTE: state from before
+  ASSERT_EQ(sm_.state_zero_->data_, &dataZero);    // NOTE: state from before
+  ASSERT_TRUE(sm_.ProcessEvent(kEventTwo, &dataTwo));
+  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+  ASSERT_EQ(sm_.kStateTwo, sm_.PreviousStateId());
+  // Check StateTwo
+  ASSERT_EQ(sm_.state_two_->event_, kEventTwo);
+  ASSERT_EQ(sm_.state_two_->data_, &dataTwo);
+  ASSERT_TRUE(sm_.state_two_->on_exit_);
+  // Check StateZero
+  ASSERT_TRUE(sm_.state_zero_->on_enter_);
+  ASSERT_FALSE(sm_.state_zero_->on_exit_);
+  ASSERT_EQ(sm_.state_zero_->event_, kEventZero);  // NOTE: state from before
+  ASSERT_EQ(sm_.state_zero_->data_, &dataZero);    // NOTE: state from before
+}
diff --git a/btif/test/btif_storage_test.cc b/btif/test/btif_storage_test.cc
index 988e23f..f98776d 100644
--- a/btif/test/btif_storage_test.cc
+++ b/btif/test/btif_storage_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,25 +21,7 @@
 #include "btif/include/btif_storage.h"
 #include "btif/include/btif_util.h"
 
-TEST(BtifStorageTest, test_string_to_uuid) {
-  const char* s1 = "e39c6285-867f-4b1d-9db0-35fbd9aebf22";
-  const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
-                        0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
-
-  bt_uuid_t uuid;
-  memset(&uuid, 0, sizeof(uuid));
-  EXPECT_FALSE(memcmp(&uuid, u1, sizeof(u1)) == 0);
-
-  bool rc = string_to_uuid(s1, &uuid);
-  EXPECT_TRUE(rc);
-  EXPECT_TRUE(memcmp(&uuid, u1, sizeof(u1)) == 0);
-}
-
-TEST(BtifStorageTest, test_string_to_uuid_invalid) {
-  bt_uuid_t uuid;
-  bool rc = string_to_uuid("This is not a UUID", &uuid);
-  EXPECT_FALSE(rc);
-}
+using bluetooth::Uuid;
 
 TEST(BtifStorageTest, test_uuid_split_multiple) {
   const char* s1 =
@@ -50,11 +32,11 @@
   const uint8_t u2[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
                         0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x23};
 
-  bt_uuid_t uuids[2];
+  Uuid uuids[2];
   size_t num_uuids = btif_split_uuids_string(s1, uuids, 2);
   EXPECT_EQ(num_uuids, 2u);
-  EXPECT_TRUE(memcmp(&uuids[0], u1, sizeof(u1)) == 0);
-  EXPECT_TRUE(memcmp(&uuids[1], u2, sizeof(u2)) == 0);
+  EXPECT_TRUE(memcmp(uuids[0].To128BitBE().data(), u1, sizeof(u1)) == 0);
+  EXPECT_TRUE(memcmp(uuids[1].To128BitBE().data(), u2, sizeof(u2)) == 0);
 }
 
 TEST(BtifStorageTest, test_uuid_split_partial) {
@@ -62,7 +44,7 @@
       "e39c6285-867f-4b1d-9db0-35fbd9aebf22 "
       "e39c6285-867f-4b1d-9db0-35fbd9aebf23";
 
-  bt_uuid_t uuids[2];
+  Uuid uuids[2];
   size_t num_uuids = btif_split_uuids_string(s1, uuids, 1);
   EXPECT_EQ(num_uuids, 1u);
 }
diff --git a/build/Android.bp b/build/Android.bp
index fc6eae8..b8abb0f 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -15,18 +15,28 @@
 }
 
 fluoride_defaults {
-    name: "fluoride_types_defaults",
+    name: "libchrome_support_defaults",
+    shared_libs: ["libchrome"],
     cflags: [
-        "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
-        "-fvisibility=hidden",
         "-Wall",
         "-Wextra",
         "-Werror",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+fluoride_defaults {
+    name: "fluoride_types_defaults",
+    defaults: ["libchrome_support_defaults"],
+    cflags: [
+        "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
+        "-fvisibility=hidden",
         // struct BT_HDR is defined as a variable-size header in a struct.
         "-Wno-gnu-variable-sized-type-not-at-end",
-        // needed because of the way the struct typedef is done in osi/include
-        // header files. This issue can be obsoleted by switching to C11 or C++.
-        "-Wno-typedef-redefinition",
         // there are too many unused parameters in all the code.
         "-Wno-unused-parameter",
         "-DLOG_NDEBUG=1",
@@ -38,17 +48,15 @@
         debuggable: {
             cflags: [
                 "-DBLUEDROID_DEBUG",
-                "-DDCHECK_ALWAYS_ON"
             ],
         },
     },
-    shared_libs: [ "libchrome" ]
-    // Setup Bluetooth local make variables for handling configuration
 }
 
 fluoride_defaults {
     name: "fluoride_defaults",
     defaults: ["fluoride_types_defaults"],
+    header_libs: ["libbluetooth_headers"],
     static_libs: [
         "libbluetooth-types",
     ],
diff --git a/build/BUILD.gn b/build/BUILD.gn
index af7d5d8..f09a274 100644
--- a/build/BUILD.gn
+++ b/build/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 
 config("default_include_dirs") {
   include_dirs = [
-    "//third_party/libhardware/include/",
+    "//include/",
     "//types/",
   ]
 }
@@ -28,6 +28,7 @@
     #TODO(jpawlowski): uncomment once we have no warnings on linux build
     #    "-Wall",
     #    "-Werror",
+    "-Wno-gnu-variable-sized-type-not-at-end",
     "-g",
     "-O0",
     "-fpic",
@@ -54,11 +55,6 @@
     "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
     "KERNEL_MISSING_CLOCK_BOOTTIME_ALARM=TRUE",
 
-    # This is a macro to that can be used by android hardware/libhardware
-    # to not include dependencies on core project. This is a temporary
-    # workaround until we get rid of dependency on hardware.
-    "_HW_DONT_INCLUDE_CORE_=1",
-
     # This is a macro to that can be used by source code to detect if the
     # current build is done by GN or via Android.mk. This is a temporary
     # workaround until we can remove all Android-specific dependencies.
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 148230b..765b21e 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/build/fluoride.go b/build/fluoride.go
index 7b9ac97..6a511a5 100644
--- a/build/fluoride.go
+++ b/build/fluoride.go
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// Copyright 2016 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.
diff --git a/build/secondary/third_party/aac/BUILD.gn b/build/secondary/third_party/aac/BUILD.gn
index 183e2a2..d9e79a7 100644
--- a/build/secondary/third_party/aac/BUILD.gn
+++ b/build/secondary/third_party/aac/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2017 Google, Inc.
+#  Copyright 2017 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/build/secondary/third_party/googletest/BUILD.gn b/build/secondary/third_party/googletest/BUILD.gn
index 0122adc..54c53d7 100644
--- a/build/secondary/third_party/googletest/BUILD.gn
+++ b/build/secondary/third_party/googletest/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2016 Google, Inc.
+#  Copyright 2016 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/build/secondary/third_party/libchrome/BUILD.gn b/build/secondary/third_party/libchrome/BUILD.gn
index d0d94b2..c84b293 100644
--- a/build/secondary/third_party/libchrome/BUILD.gn
+++ b/build/secondary/third_party/libchrome/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/build/secondary/third_party/libldac/BUILD.gn b/build/secondary/third_party/libldac/BUILD.gn
index faf85a2..23b191d 100644
--- a/build/secondary/third_party/libldac/BUILD.gn
+++ b/build/secondary/third_party/libldac/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2017 Google, Inc.
+#  Copyright 2017 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/build/secondary/third_party/tinyxml2/BUILD.gn b/build/secondary/third_party/tinyxml2/BUILD.gn
index 335960b..aeb66a1 100644
--- a/build/secondary/third_party/tinyxml2/BUILD.gn
+++ b/build/secondary/third_party/tinyxml2/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/build/toolchain/clang/BUILD.gn b/build/toolchain/clang/BUILD.gn
index fcd6d56..ee86e27 100644
--- a/build/toolchain/clang/BUILD.gn
+++ b/build/toolchain/clang/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2016 Android Open Source Project
+#  Copyright 2016 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.
diff --git a/build/toolchain/gcc/BUILD.gn b/build/toolchain/gcc/BUILD.gn
index 888b015..1c92d0a 100644
--- a/build/toolchain/gcc/BUILD.gn
+++ b/build/toolchain/gcc/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index f1557b1..d1e7756 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -50,6 +50,9 @@
 # SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
 #PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
 
+# PTS AVRCP Test mode
+#PTS_AvrcpTest=true
+
 # SMP Certification Failure Cases
 # Set any of the following SMP error values (from smp_api_types.h)
 # to induce pairing failues for various PTS SMP test cases.
diff --git a/device/Android.bp b/device/Android.bp
index c113113..f72a16b 100644
--- a/device/Android.bp
+++ b/device/Android.bp
@@ -10,7 +10,7 @@
         "system/bt",
         "system/bt/btcore/include",
         "system/bt/hci/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/stack/include",
     ],
     srcs: [
diff --git a/device/AndroidTest.xml b/device/AndroidTest.xml
index 45a7e51..0960fb4 100644
--- a/device/AndroidTest.xml
+++ b/device/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright 2017 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.
diff --git a/device/BUILD.gn b/device/BUILD.gn
index f93b70d..5de439d 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
     "//",
     "//btcore/include",
     "//hci/include",
-    "//include",
+    "//internal_include",
     "//stack/include",
   ]
 
diff --git a/device/include/controller.h b/device/include/controller.h
index 135cdcd..c1fe337 100644
--- a/device/include/controller.h
+++ b/device/include/controller.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -72,6 +72,7 @@
   uint16_t (*get_acl_packet_size_ble)(void);
 
   uint16_t (*get_ble_default_data_packet_length)(void);
+  uint16_t (*get_ble_maximum_tx_data_length)(void);
   uint16_t (*get_ble_maxium_advertising_data_length)(void);
   uint8_t (*get_ble_number_of_supported_advertising_sets)(void);
 
diff --git a/device/include/esco_parameters.h b/device/include/esco_parameters.h
index f906c8d..b79948d 100644
--- a/device/include/esco_parameters.h
+++ b/device/include/esco_parameters.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Broadcom Corporation
+ *  Copyright 2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/device/include/interop.h b/device/include/interop.h
index 96a3b9a..b31efc3 100644
--- a/device/include/interop.h
+++ b/device/include/interop.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -113,7 +113,7 @@
 // |length| must be greater than 0 and less than RawAddress::kLength.
 // As |interop_feature_t| is not exposed in the public API, feature must be a
 // valid integer representing an option in the enum.
-void interop_database_add(const uint16_t feature, const RawAddress* addr,
+void interop_database_add(uint16_t feature, const RawAddress* addr,
                           size_t length);
 
 // Clear the dynamic portion of the interoperability workaround database.
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index 38c3a24..ad1bb5a 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/device/src/controller.cc b/device/src/controller.cc
index 8e1d887..a07e54b 100644
--- a/device/src/controller.cc
+++ b/device/src/controller.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -65,6 +65,11 @@
 static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE];
 static bt_device_features_t features_ble;
 static uint16_t ble_suggested_default_data_length;
+static uint16_t ble_supported_max_tx_octets;
+static uint16_t ble_supported_max_tx_time;
+static uint16_t ble_supported_max_rx_octets;
+static uint16_t ble_supported_max_rx_time;
+
 static uint16_t ble_maxium_advertising_data_length;
 static uint8_t ble_number_of_supported_advertising_sets;
 static uint8_t local_supported_codecs[MAX_LOCAL_SUPPORTED_CODECS_SIZE];
@@ -212,6 +217,12 @@
     }
 
     if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) {
+      response =
+          AWAIT_COMMAND(packet_factory->make_ble_read_maximum_data_length());
+      packet_parser->parse_ble_read_maximum_data_length_response(
+          response, &ble_supported_max_tx_octets, &ble_supported_max_tx_time,
+          &ble_supported_max_rx_octets, &ble_supported_max_rx_time);
+
       response = AWAIT_COMMAND(
           packet_factory->make_ble_read_suggested_default_data_length());
       packet_parser->parse_ble_read_suggested_default_data_length_response(
@@ -448,6 +459,12 @@
   return ble_suggested_default_data_length;
 }
 
+static uint16_t get_ble_maximum_tx_data_length(void) {
+  CHECK(readable);
+  CHECK(ble_supported);
+  return ble_supported_max_tx_octets;
+}
+
 static uint16_t get_ble_maxium_advertising_data_length(void) {
   CHECK(readable);
   CHECK(ble_supported);
@@ -540,6 +557,7 @@
     get_acl_packet_size_classic,
     get_acl_packet_size_ble,
     get_ble_suggested_default_data_length,
+    get_ble_maximum_tx_data_length,
     get_ble_maxium_advertising_data_length,
     get_ble_number_of_supported_advertising_sets,
 
diff --git a/device/src/esco_parameters.cc b/device/src/esco_parameters.cc
index 80f5e76..7f550a1 100644
--- a/device/src/esco_parameters.cc
+++ b/device/src/esco_parameters.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Broadcom Corporation
+ *  Copyright 2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/device/src/interop.cc b/device/src/interop.cc
index 7b1fe59..c2ed2a8 100644
--- a/device/src/interop.cc
+++ b/device/src/interop.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -76,7 +76,7 @@
   return false;
 }
 
-void interop_database_add(const uint16_t feature, const RawAddress* addr,
+void interop_database_add(uint16_t feature, const RawAddress* addr,
                           size_t length) {
   CHECK(addr);
   CHECK(length > 0);
diff --git a/device/test/interop_test.cc b/device/test/interop_test.cc
index e82a3b5..71cc8cb 100644
--- a/device/test/interop_test.cc
+++ b/device/test/interop_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/doc/style_guide.md b/doc/style_guide.md
index 8490fd2..5fc786e 100644
--- a/doc/style_guide.md
+++ b/doc/style_guide.md
@@ -235,7 +235,7 @@
 ```
 /******************************************************************************
  *
- *  Copyright (C) <year> <owner>
+ *  Copyright <year> <owner>
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/Android.bp b/embdrv/Android.bp
deleted file mode 100644
index 7c6328e..0000000
--- a/embdrv/Android.bp
+++ /dev/null
@@ -1,3 +0,0 @@
-subdirs = [
-    "sbc",
-]
diff --git a/embdrv/g722/Android.bp b/embdrv/g722/Android.bp
new file mode 100644
index 0000000..cc635d8
--- /dev/null
+++ b/embdrv/g722/Android.bp
@@ -0,0 +1,12 @@
+
+cc_library_static {
+    name: "libg722codec",
+    defaults: ["fluoride_defaults"],
+    cflags: [
+        "-DG722_SUPPORT_MALLOC"
+    ],
+    srcs: [
+        "g722_decode.cc",
+        "g722_encode.cc",
+    ],
+}
\ No newline at end of file
diff --git a/embdrv/g722/g722_decode.cc b/embdrv/g722/g722_decode.cc
new file mode 100644
index 0000000..4d812ac
--- /dev/null
+++ b/embdrv/g722/g722_decode.cc
@@ -0,0 +1,422 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g722_decode.c - The ITU G.722 codec, decode part.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2005 Steve Underwood
+ *
+ *  Despite my general liking of the GPL, I place my own contributions 
+ *  to this code in the public domain for the benefit of all mankind -
+ *  even the slimy ones who might try to proprietize my work and use it
+ *  to my detriment.
+ *
+ * Based in part on a single channel G.722 codec which is:
+ *
+ * Copyright (c) CMU 1993
+ * Computer Science, Speech Group
+ * Chengxiang Lu and Alex Hauptmann
+ *
+ * $Id: g722_decode.c 194722 2009-05-15 17:59:08Z russell $
+ */
+
+/*! \file */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "g722_typedefs.h"
+#include "g722_enc_dec.h"
+
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+#define PACKED_INPUT    (0)
+#define BITS_PER_SAMPLE (8)
+
+#ifndef BUILD_FEATURE_G722_USE_INTRINSIC_SAT
+static __inline int16_t __ssat16(int32_t amp)
+{
+    int16_t amp16;
+
+    /* Hopefully this is optimised for the common case - not clipping */
+    amp16 = (int16_t) amp;
+    if (amp == amp16)
+        return amp16;
+    if (amp > 0x7fff)
+        return  0x7fff;
+    return  0x8000;
+}
+/*- End of function --------------------------------------------------------*/
+#else
+static __inline int16_t __ssat16( int32_t val)
+{
+    register int32_t res;
+    __asm volatile (
+        "SSAT %0, #16, %1\n\t"
+        :"=r"(res)
+        :"r"(val)
+        :);
+    return (int16_t)res;
+}
+#endif
+
+/*- End of function --------------------------------------------------------*/
+
+static void block4(g722_band_t *band, int d);
+
+static void block4(g722_band_t *band, int d)
+{
+    int wd1;
+    int wd2;
+    int wd3;
+    int i;
+    int sg[7];
+    int ap1, ap2;
+    int sg0, sgi;
+    int sz;
+
+    /* Block 4, RECONS */
+    band->d[0] = d;
+    band->r[0] = __ssat16(band->s + d);
+
+    /* Block 4, PARREC */
+    band->p[0] = __ssat16(band->sz + d);
+
+    /* Block 4, UPPOL2 */
+    for (i = 0;  i < 3;  i++)
+    {
+        sg[i] = band->p[i] >> 15;
+    }
+    wd1 = __ssat16(band->a[1] << 2);
+
+    wd2 = (sg[0] == sg[1])  ?  -wd1  :  wd1;
+    if (wd2 > 32767)
+        wd2 = 32767;
+
+    ap2 = (sg[0] == sg[2])  ?  128  :  -128;
+    ap2 += (wd2 >> 7);
+    ap2 += (band->a[2]*32512) >> 15;
+    if (ap2 > 12288)
+        ap2 = 12288;
+    else if (ap2 < -12288)
+        ap2 = -12288;
+    band->ap[2] = ap2;
+
+    /* Block 4, UPPOL1 */
+    sg[0] = band->p[0] >> 15;
+    sg[1] = band->p[1] >> 15;
+    wd1 = (sg[0] == sg[1])  ?  192  :  -192;
+    wd2 = (band->a[1]*32640) >> 15;
+
+    ap1 = __ssat16(wd1 + wd2);
+    wd3 = __ssat16(15360 - band->ap[2]);
+    if (ap1 > wd3)
+        ap1 = wd3;
+    else if (ap1 < -wd3)
+        ap1 = -wd3;
+    band->ap[1] = ap1;
+
+    /* Block 4, UPZERO */
+    /* Block 4, FILTEZ */
+    wd1 = (d == 0)  ?  0  :  128;
+
+    sg0 = sg[0] = d >> 15;
+    for (i = 1;  i < 7;  i++)
+    {
+	sgi = band->d[i] >> 15;
+        wd2 = (sgi == sg0)  ?  wd1  :  -wd1;
+        wd3 = (band->b[i]*32640) >> 15;
+        band->bp[i] = __ssat16(wd2 + wd3);
+    }
+
+    /* Block 4, DELAYA */
+    sz = 0;
+    for (i = 6;  i > 0;  i--)
+    {
+	int bi;
+
+        band->d[i] = band->d[i - 1];
+	bi = band->b[i] = band->bp[i];
+	wd1 = __ssat16(band->d[i] + band->d[i]);
+	sz += (bi*wd1) >> 15;
+    }
+    band->sz = sz;
+    
+    for (i = 2;  i > 0;  i--)
+    {
+        band->r[i] = band->r[i - 1];
+        band->p[i] = band->p[i - 1];
+        band->a[i] = band->ap[i];
+    }
+
+    /* Block 4, FILTEP */
+    wd1 = __ssat16(band->r[1] + band->r[1]);
+    wd1 = (band->a[1]*wd1) >> 15;
+    wd2 = __ssat16(band->r[2] + band->r[2]);
+    wd2 = (band->a[2]*wd2) >> 15;
+    band->sp = __ssat16(wd1 + wd2);
+
+    /* Block 4, PREDIC */
+    band->s = __ssat16(band->sp + band->sz);
+}
+/*- End of function --------------------------------------------------------*/
+
+g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, unsigned int rate, int options)
+{
+    if (s == NULL)
+    {
+#ifdef G722_SUPPORT_MALLOC
+        if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL)
+#endif
+            return NULL;
+    }
+    memset(s, 0, sizeof(*s));
+    if (rate == 48000)
+        s->bits_per_sample = 6;
+    else if (rate == 56000)
+        s->bits_per_sample = 7;
+    else
+        s->bits_per_sample = 8;
+    s->dac_pcm = options & G722_FORMAT_DAC12;
+    s->band[0].det = 32;
+    s->band[1].det = 8;
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+int g722_decode_release(g722_decode_state_t *s)
+{
+    free(s);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int16_t wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042 };
+static int16_t rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3,  2, 1, 0 };
+static int16_t ilb[32] =
+{
+    2048, 2093, 2139, 2186, 2233, 2282, 2332,
+    2383, 2435, 2489, 2543, 2599, 2656, 2714,
+    2774, 2834, 2896, 2960, 3025, 3091, 3158,
+    3228, 3298, 3371, 3444, 3520, 3597, 3676,
+    3756, 3838, 3922, 4008
+};
+
+static int16_t wh[3] = {0, -214, 798};
+static int16_t rh2[4] = {2, 1, 2, 1};
+static int16_t qm2[4] = {-7408, -1616,  7408,   1616};
+static int16_t qm4[16] = 
+{
+        0, -20456, -12896,  -8968, 
+    -6288,  -4240,  -2584,  -1200,
+    20456,  12896,   8968,   6288,
+     4240,   2584,   1200,      0
+};
+#if 0
+static const int qm5[32] =
+{
+      -280,   -280, -23352, -17560,
+    -14120, -11664,  -9752,  -8184,
+     -6864,  -5712,  -4696,  -3784,
+     -2960,  -2208,  -1520,   -880,
+     23352,  17560,  14120,  11664,
+      9752,   8184,   6864,   5712,
+      4696,   3784,   2960,   2208,
+      1520,    880,    280,   -280
+};
+#endif
+static int16_t qm6[64] =
+{
+      -136,   -136,   -136,   -136,
+    -24808, -21904, -19008, -16704,
+    -14984, -13512, -12280, -11192,
+    -10232,  -9360,  -8576,  -7856,
+     -7192,  -6576,  -6000,  -5456,
+     -4944,  -4464,  -4008,  -3576,
+     -3168,  -2776,  -2400,  -2032,
+     -1688,  -1360,  -1040,   -728,
+     24808,  21904,  19008,  16704,
+     14984,  13512,  12280,  11192,
+     10232,   9360,   8576,   7856,
+      7192,   6576,   6000,   5456,
+      4944,   4464,   4008,   3576,
+      3168,   2776,   2400,   2032,
+      1688,   1360,   1040,    728,
+       432,    136,   -432,   -136
+};
+static int16_t qmf_coeffs_even[12] =
+{
+      3,  -11,   12,   32, -210,  951, 3876, -805,  362, -156,   53,  -11,
+};
+static int16_t qmf_coeffs_odd[12] =
+{
+    -11,   53, -156,  362, -805, 3876, 951,  -210,   32,   12,  -11,    3
+};
+
+uint32_t g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len, uint16_t gain)
+{
+
+    int dlowt;
+    int rlow;
+    int ihigh;
+    int dhigh;
+    int rhigh;
+    int xout1;
+    int xout2;
+    int wd1;
+    int wd2;
+    int wd3;
+    int code;
+    uint32_t outlen;
+    int i;
+    int j;
+
+    outlen = 0;
+    rhigh = 0;
+
+    for (j = 0;  j < len;  )
+    {
+#if PACKED_INPUT == 1
+        /* Unpack the code bits */
+        if (s->in_bits < s->bits_per_sample)
+        {
+            s->in_buffer |= (g722_data[j++] << s->in_bits);
+            s->in_bits += 8;
+        }
+        code = s->in_buffer & ((1 << s->bits_per_sample) - 1);
+        s->in_buffer >>= s->bits_per_sample;
+        s->in_bits -= s->bits_per_sample;
+#else
+        code = g722_data[j++];
+#endif
+
+#if BITS_PER_SAMPLE == 8
+        wd1 = code & 0x3F;
+        ihigh = (code >> 6) & 0x03;
+        wd2 = qm6[wd1];
+        wd1 >>= 2;
+#elif BITS_PER_SAMPLE == 7
+        wd1 = code & 0x1F;
+        ihigh = (code >> 5) & 0x03;
+        wd2 = qm5[wd1];
+        wd1 >>= 1;
+#elif BITS_PER_SAMPLE == 6
+       wd1 = code & 0x0F;
+       ihigh = (code >> 4) & 0x03;
+       wd2 = qm4[wd1];
+#endif
+        /* Block 5L, LOW BAND INVQBL */
+        wd2 = (s->band[0].det*wd2) >> 15;
+        /* Block 5L, RECONS */
+        rlow = s->band[0].s + wd2;
+        /* Block 6L, LIMIT */
+
+        // ANDREA
+        // rlow=ssat(rlow,2<<14)
+        if (rlow > 16383)
+        {
+            rlow = 16383;
+        }
+        else if (rlow < -16384)
+        {
+            rlow = -16384;
+        }
+
+        /* Block 2L, INVQAL */
+        wd2 = qm4[wd1];
+        dlowt = (s->band[0].det*wd2) >> 15;
+
+        /* Block 3L, LOGSCL */
+        wd2 = rl42[wd1];
+        wd1 = (s->band[0].nb*127) >> 7;
+        wd1 += wl[wd2];
+        if (wd1 < 0)
+        {
+            wd1 = 0;
+        }
+        else if (wd1 > 18432)
+        {
+            wd1 = 18432;
+        }
+        s->band[0].nb = wd1;
+            
+        /* Block 3L, SCALEL */
+        wd1 = (s->band[0].nb >> 6) & 31;
+        wd2 = 8 - (s->band[0].nb >> 11);
+        wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+        s->band[0].det = wd3 << 2;
+
+        block4(&s->band[0], dlowt);
+        
+        /* Block 2H, INVQAH */
+        wd2 = qm2[ihigh];
+        dhigh = (s->band[1].det*wd2) >> 15;
+        /* Block 5H, RECONS */
+        rhigh = dhigh + s->band[1].s;
+        /* Block 6H, LIMIT */
+
+        // ANDREA
+        // rhigh=ssat(rhigh,2<<14)
+
+        if (rhigh > 16383)
+            rhigh = 16383;
+        else if (rhigh < -16384)
+            rhigh = -16384;
+
+        /* Block 2H, INVQAH */
+        wd2 = rh2[ihigh];
+        wd1 = (s->band[1].nb*127) >> 7;
+        wd1 += wh[wd2];
+        if (wd1 < 0)
+            wd1 = 0;
+        else if (wd1 > 22528)
+            wd1 = 22528;
+        s->band[1].nb = wd1;
+            
+        /* Block 3H, SCALEH */
+        wd1 = (s->band[1].nb >> 6) & 31;
+        wd2 = 10 - (s->band[1].nb >> 11);
+        wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+        s->band[1].det = wd3 << 2;
+
+        block4(&s->band[1], dhigh);
+
+        /* Apply the receive QMF */
+        for (i = 0;  i < 22;  i++)
+            s->x[i] = s->x[i + 2];
+        s->x[22] = rlow + rhigh;
+        s->x[23] = rlow - rhigh;
+
+        // we should get PERF numbers for the following loop 
+        xout1 = 0;
+        xout2 = 0;
+        for (i = 0;  i < 12;  i++)
+        {
+            xout2 += s->x[2*i]   * qmf_coeffs_even[i];
+            xout1 += s->x[2*i+1] * qmf_coeffs_odd[i];
+        }
+        xout1 = NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN((int16_t) __ssat16(xout1 >> 11), gain);
+        xout2 = NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN((int16_t) __ssat16(xout2 >> 11), gain);
+        if (s->dac_pcm)
+        {
+            amp[outlen++] = ((int16_t) (xout1 >> 4) + 2048);
+            amp[outlen++] = ((int16_t) (xout2 >> 4) + 2048);
+        }
+        else
+        {
+            amp[outlen++] = xout1;
+            amp[outlen++] = xout2;
+        }
+    }
+    return outlen;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --git a/embdrv/g722/g722_enc_dec.h b/embdrv/g722/g722_enc_dec.h
new file mode 100644
index 0000000..f06cd20
--- /dev/null
+++ b/embdrv/g722/g722_enc_dec.h
@@ -0,0 +1,148 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g722.h - The ITU G.722 codec.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2005 Steve Underwood
+ *
+ *  Despite my general liking of the GPL, I place my own contributions 
+ *  to this code in the public domain for the benefit of all mankind -
+ *  even the slimy ones who might try to proprietize my work and use it
+ *  to my detriment.
+ *
+ * Based on a single channel G.722 codec which is:
+ *
+ *****    Copyright (c) CMU    1993      *****
+ * Computer Science, Speech Group
+ * Chengxiang Lu and Alex Hauptmann
+ *
+ * $Id: g722.h 48959 2006-12-25 06:42:15Z rizzo $
+ */
+
+
+/*! \file */
+
+#if !defined(_G722_H_)
+#define _G722_H_
+
+/*! \page g722_page G.722 encoding and decoding
+\section g722_page_sec_1 What does it do?
+The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
+specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
+
+To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
+support an option for the linear audio to be an 8k samples/second stream. In this mode the
+codec is considerably faster, and still fully compatible with wideband terminals using G.722.
+
+\section g722_page_sec_2 How does it work?
+???.
+*/
+
+/* Format DAC12 is added to decode directly into samples suitable for
+   a 12-bit DAC using offset binary representation. */
+
+enum
+{
+    G722_SAMPLE_RATE_8000 = 0x0001,
+    G722_PACKED = 0x0002,
+    G722_FORMAT_DAC12 = 0x0004,
+};
+
+#ifdef BUILD_FEATURE_DAC
+#define NLDECOMPRESS_APPLY_GAIN(s,g) (((s) * (int32_t)(g)) >> 16)
+// Equivalent to shift 16, add 0x8000, shift 4
+#define NLDECOMPRESS_APPLY_GAIN_CONVERTED_DAC(s,g) (uint16_t)((uint16_t)(((s) * (int32_t)(g)) >> 20) + 0x800)
+#else
+#define NLDECOMPRESS_APPLY_GAIN(s,g) (((int32_t)(s) * (int32_t)(g)) >> 16)
+#endif
+
+#ifdef BUILD_FEATURE_DAC
+#define NLDECOMPRESS_PREPROCESS_PCM_SAMPLE_WITH_GAIN(s,g) NLDECOMPRESS_APPLY_GAIN_CONVERTED_DAC((s),(g))
+#define NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN(s,g) ((int16_t)NLDECOMPRESS_APPLY_GAIN((s),(g)))
+#else
+#define NLDECOMPRESS_PREPROCESS_PCM_SAMPLE_WITH_GAIN NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN
+#define NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN(s,g) ((int16_t)(NLDECOMPRESS_APPLY_GAIN((s),(g))))
+#endif
+
+typedef struct {
+    int s;
+    int sp;
+    int sz;
+    int r[3];
+    int a[3];
+    int ap[3];
+    int p[3];
+    int d[7];
+    int b[7];
+    int bp[7];
+    int nb;
+    int det;
+} g722_band_t;
+
+typedef struct
+{
+    /*! TRUE if the operating in the special ITU test mode, with the band split filters
+             disabled. */
+    int itu_test_mode;
+    /*! TRUE if the G.722 data is packed */
+    int packed;
+    /*! TRUE if encode from 8k samples/second */
+    int eight_k;
+    /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
+    int bits_per_sample;
+
+    /*! Signal history for the QMF */
+    int x[24];
+
+    g722_band_t band[2];
+
+    unsigned int in_buffer;
+    int in_bits;
+    unsigned int out_buffer;
+    int out_bits;
+} g722_encode_state_t;
+
+typedef struct
+{
+    /*! TRUE if the operating in the special ITU test mode, with the band split filters
+             disabled. */
+    int itu_test_mode;
+    /*! TRUE if the G.722 data is packed */
+    int packed;
+    /*! TRUE if decode to 8k samples/second */
+    int eight_k;
+    /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
+    int bits_per_sample;
+    /*! TRUE if offset binary for a 12-bit DAC */
+    int dac_pcm;
+
+    /*! Signal history for the QMF */
+    int x[24];
+
+    g722_band_t band[2];
+    
+    unsigned int in_buffer;
+    int in_bits;
+    unsigned int out_buffer;
+    int out_bits;
+} g722_decode_state_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, unsigned int rate, int options);
+int g722_encode_release(g722_encode_state_t *s);
+int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
+
+g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, unsigned int rate, int options);
+int g722_decode_release(g722_decode_state_t *s);
+uint32_t g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len, uint16_t aGain);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/embdrv/g722/g722_encode.cc b/embdrv/g722/g722_encode.cc
new file mode 100644
index 0000000..817f5c0
--- /dev/null
+++ b/embdrv/g722/g722_encode.cc
@@ -0,0 +1,438 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g722_encode.c - The ITU G.722 codec, encode part.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2005 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ *  Despite my general liking of the GPL, I place my own contributions 
+ *  to this code in the public domain for the benefit of all mankind -
+ *  even the slimy ones who might try to proprietize my work and use it
+ *  to my detriment.
+ *
+ * Based on a single channel 64kbps only G.722 codec which is:
+ *
+ *****    Copyright (c) CMU    1993      *****
+ * Computer Science, Speech Group
+ * Chengxiang Lu and Alex Hauptmann
+ *
+ * $Id: g722_encode.c,v 1.14 2006/07/07 16:37:49 steveu Exp $
+ */
+
+/*! \file */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "g722_typedefs.h"
+#include "g722_enc_dec.h"
+
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+#define PACKED_OUTPUT   (0)
+#define BITS_PER_SAMPLE (8)
+
+#ifndef BUILD_FEATURE_G722_USE_INTRINSIC_SAT
+static __inline int16_t saturate(int32_t amp)
+{
+    int16_t amp16;
+
+    /* Hopefully this is optimised for the common case - not clipping */
+    amp16 = (int16_t) amp;
+    if (amp == amp16)
+        return amp16;
+    if (amp > 0x7FFF)
+        return  0x7FFF;
+    return  0x8000;
+}
+#else
+static __inline int16_t saturate(int32_t val)
+{
+    register int32_t res;
+    __asm volatile (
+        "SSAT %0, #16, %1\n\t"
+        :"=r"(res)
+        :"r"(val)
+        :);
+    return (int16_t)res;
+}
+#endif
+/*- End of function --------------------------------------------------------*/
+
+static void block4(g722_band_t *band, int d)
+{
+    int wd1;
+    int wd2;
+    int wd3;
+    int i;
+    int sg[7];
+    int ap1, ap2;
+    int sg0, sgi;
+    int sz;
+
+    /* Block 4, RECONS */
+    band->d[0] = d;
+    band->r[0] = saturate(band->s + d);
+
+    /* Block 4, PARREC */
+    band->p[0] = saturate(band->sz + d);
+
+    /* Block 4, UPPOL2 */
+    for (i = 0;  i < 3;  i++)
+        sg[i] = band->p[i] >> 15;
+    wd1 = saturate(band->a[1] << 2);
+
+    wd2 = (sg[0] == sg[1])  ?  -wd1  :  wd1;
+    if (wd2 > 32767)
+        wd2 = 32767;
+
+    ap2 = (wd2 >> 7) + ((sg[0] == sg[2])  ?  128  :  -128);
+    ap2 += (band->a[2]*32512) >> 15;
+    if (ap2 > 12288)
+        ap2 = 12288;
+    else if (ap2 < -12288)
+        ap2 = -12288;
+    band->ap[2] = ap2;
+
+    /* Block 4, UPPOL1 */
+    sg[0] = band->p[0] >> 15;
+    sg[1] = band->p[1] >> 15;
+    wd1 = (sg[0] == sg[1])  ?  192  :  -192;
+    wd2 = (band->a[1]*32640) >> 15;
+
+    ap1 = saturate(wd1 + wd2);
+    wd3 = saturate(15360 - band->ap[2]);
+    if (ap1 > wd3)
+        ap1 = wd3;
+    else if (ap1 < -wd3)
+        ap1 = -wd3;
+    band->ap[1] = ap1;
+
+    /* Block 4, UPZERO */
+    /* Block 4, FILTEZ */
+    wd1 = (d == 0)  ?  0  :  128;
+
+    sg0 = sg[0] = d >> 15;
+    for (i = 1;  i < 7;  i++)
+    {
+	sgi = band->d[i] >> 15;
+	wd2 = (sgi == sg0) ? wd1 : -wd1;
+        wd3 = (band->b[i]*32640) >> 15;
+        band->bp[i] = saturate(wd2 + wd3);
+    }
+
+    /* Block 4, DELAYA */
+    sz = 0;
+    for (i = 6;  i > 0;  i--)
+    {
+	int bi;
+
+        band->d[i] = band->d[i - 1];
+        bi = band->b[i] = band->bp[i];
+        wd1 = saturate(band->d[i] + band->d[i]);
+        sz += (bi*wd1) >> 15;
+    }
+    band->sz = sz;
+    
+    for (i = 2;  i > 0;  i--)
+    {
+        band->r[i] = band->r[i - 1];
+        band->p[i] = band->p[i - 1];
+        band->a[i] = band->ap[i];
+    }
+
+    /* Block 4, FILTEP */
+    wd1 = saturate(band->r[1] + band->r[1]);
+    wd1 = (band->a[1]*wd1) >> 15;
+    wd2 = saturate(band->r[2] + band->r[2]);
+    wd2 = (band->a[2]*wd2) >> 15;
+    band->sp = saturate(wd1 + wd2);
+
+    /* Block 4, PREDIC */
+    band->s = saturate(band->sp + band->sz);
+}
+/*- End of function --------------------------------------------------------*/
+
+g722_encode_state_t *g722_encode_init(g722_encode_state_t *s,
+                                             unsigned int rate, int options)
+{
+    if (s == NULL)
+    {
+#ifdef G722_SUPPORT_MALLOC
+        if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL)
+#endif
+            return NULL;
+    }
+    memset(s, 0, sizeof(*s));
+    if (rate == 48000)
+        s->bits_per_sample = 6;
+    else if (rate == 56000)
+        s->bits_per_sample = 7;
+    else
+        s->bits_per_sample = 8;
+    s->band[0].det = 32;
+    s->band[1].det = 8;
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+int g722_encode_release(g722_encode_state_t *s)
+{
+    free(s);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+/* WebRtc, tlegrand:
+ * Only define the following if bit-exactness with reference implementation
+ * is needed. Will only have any effect if input signal is saturated.
+ */
+//#define RUN_LIKE_REFERENCE_G722
+#ifdef RUN_LIKE_REFERENCE_G722
+int16_t limitValues (int16_t rl)
+{
+
+    int16_t yl;
+
+    yl = (rl > 16383) ? 16383 : ((rl < -16384) ? -16384 : rl);
+
+    return (yl);
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+static int16_t q6[32] =
+{
+       0,   35,   72,  110,  150,  190,  233,  276,
+     323,  370,  422,  473,  530,  587,  650,  714,
+     786,  858,  940, 1023, 1121, 1219, 1339, 1458,
+    1612, 1765, 1980, 2195, 2557, 2919,    0,    0
+};
+static int16_t iln[32] =
+{
+     0, 63, 62, 31, 30, 29, 28, 27,
+    26, 25, 24, 23, 22, 21, 20, 19,
+    18, 17, 16, 15, 14, 13, 12, 11,
+    10,  9,  8,  7,  6,  5,  4,  0
+};
+static int16_t ilp[32] =
+{
+     0, 61, 60, 59, 58, 57, 56, 55,
+    54, 53, 52, 51, 50, 49, 48, 47,
+    46, 45, 44, 43, 42, 41, 40, 39,
+    38, 37, 36, 35, 34, 33, 32,  0
+};
+static int16_t wl[8] =
+{
+    -60, -30, 58, 172, 334, 538, 1198, 3042
+};
+static int16_t rl42[16] =
+{
+    0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
+};
+static int16_t ilb[32] =
+{
+    2048, 2093, 2139, 2186, 2233, 2282, 2332,
+    2383, 2435, 2489, 2543, 2599, 2656, 2714,
+    2774, 2834, 2896, 2960, 3025, 3091, 3158,
+    3228, 3298, 3371, 3444, 3520, 3597, 3676,
+    3756, 3838, 3922, 4008
+};
+static int16_t qm4[16] =
+{
+         0, -20456, -12896, -8968,
+     -6288,  -4240,  -2584, -1200,
+     20456,  12896,   8968,  6288,
+      4240,   2584,   1200,     0
+};
+static int16_t qm2[4] =
+{
+    -7408,  -1616,   7408,   1616
+};
+static int16_t qmf_coeffs[12] =
+{
+       3,  -11,   12,   32, -210,  951, 3876, -805,  362, -156,   53,  -11,
+};
+static int16_t ihn[3] = {0, 1, 0};
+static int16_t ihp[3] = {0, 3, 2};
+static int16_t wh[3] = {0, -214, 798};
+static int16_t rh2[4] = {2, 1, 2, 1};
+
+int g722_encode(g722_encode_state_t *s, uint8_t g722_data[],
+                       const int16_t amp[], int len)
+{
+    int dlow;
+    int dhigh;
+    int el;
+    int wd;
+    int wd1;
+    int ril;
+    int wd2;
+    int il4;
+    int ih2;
+    int wd3;
+    int eh;
+    int mih;
+    int i;
+    int j;
+    /* Low and high band PCM from the QMF */
+    int xlow;
+    int xhigh;
+    int g722_bytes;
+    /* Even and odd tap accumulators */
+    int sumeven;
+    int sumodd;
+    int ihigh;
+    int ilow;
+    int code;
+
+    g722_bytes = 0;
+    xhigh = 0;
+    for (j = 0;  j < len;  )
+    {
+        if (s->itu_test_mode)
+        {
+            xlow =
+            xhigh = amp[j++] >> 1;
+        }
+        else
+        {
+            {
+                /* Apply the transmit QMF */
+                /* Shuffle the buffer down */
+                for (i = 0;  i < 22;  i++)
+                    s->x[i] = s->x[i + 2];
+                //TODO: if len is odd, then this can be a buffer overrun
+                s->x[22] = amp[j++];
+                s->x[23] = amp[j++];
+    
+                /* Discard every other QMF output */
+                sumeven = 0;
+                sumodd = 0;
+                for (i = 0;  i < 12;  i++)
+                {
+                    sumodd += s->x[2*i]*qmf_coeffs[i];
+                    sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i];
+                }
+                /* We shift by 12 to allow for the QMF filters (DC gain = 4096), plus 1
+                   to allow for us summing two filters, plus 1 to allow for the 15 bit
+                   input to the G.722 algorithm. */
+                xlow = (sumeven + sumodd) >> 14;
+                xhigh = (sumeven - sumodd) >> 14;
+
+#ifdef RUN_LIKE_REFERENCE_G722
+                /* The following lines are only used to verify bit-exactness
+                 * with reference implementation of G.722. Higher precision
+                 * is achieved without limiting the values.
+                 */
+                xlow = limitValues(xlow);
+                xhigh = limitValues(xhigh);
+#endif
+            }
+        }
+        /* Block 1L, SUBTRA */
+        el = saturate(xlow - s->band[0].s);
+
+        /* Block 1L, QUANTL */
+        wd = (el >= 0)  ?  el  :  -(el + 1);
+
+        for (i = 1;  i < 30;  i++)
+        {
+            wd1 = (q6[i]*s->band[0].det) >> 12;
+            if (wd < wd1)
+                break;
+        }
+        ilow = (el < 0)  ?  iln[i]  :  ilp[i];
+
+        /* Block 2L, INVQAL */
+        ril = ilow >> 2;
+        wd2 = qm4[ril];
+        dlow = (s->band[0].det*wd2) >> 15;
+
+        /* Block 3L, LOGSCL */
+        il4 = rl42[ril];
+        wd = (s->band[0].nb*127) >> 7;
+        s->band[0].nb = wd + wl[il4];
+        if (s->band[0].nb < 0)
+            s->band[0].nb = 0;
+        else if (s->band[0].nb > 18432)
+            s->band[0].nb = 18432;
+
+        /* Block 3L, SCALEL */
+        wd1 = (s->band[0].nb >> 6) & 31;
+        wd2 = 8 - (s->band[0].nb >> 11);
+        wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+        s->band[0].det = wd3 << 2;
+
+        block4(&s->band[0], dlow);
+        {
+	    int nb;
+
+            /* Block 1H, SUBTRA */
+            eh = saturate(xhigh - s->band[1].s);
+
+            /* Block 1H, QUANTH */
+            wd = (eh >= 0)  ?  eh  :  -(eh + 1);
+            wd1 = (564*s->band[1].det) >> 12;
+            mih = (wd >= wd1)  ?  2  :  1;
+            ihigh = (eh < 0)  ?  ihn[mih]  :  ihp[mih];
+
+            /* Block 2H, INVQAH */
+            wd2 = qm2[ihigh];
+            dhigh = (s->band[1].det*wd2) >> 15;
+
+            /* Block 3H, LOGSCH */
+            ih2 = rh2[ihigh];
+            wd = (s->band[1].nb*127) >> 7;
+
+            nb = wd + wh[ih2];
+            if (nb < 0)
+                nb = 0;
+            else if (nb > 22528)
+                nb = 22528;
+	    s->band[1].nb = nb;
+
+            /* Block 3H, SCALEH */
+            wd1 = (s->band[1].nb >> 6) & 31;
+            wd2 = 10 - (s->band[1].nb >> 11);
+            wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+            s->band[1].det = wd3 << 2;
+
+            block4(&s->band[1], dhigh);
+#if   BITS_PER_SAMPLE == 8
+            code = ((ihigh << 6) | ilow);
+#elif BITS_PER_SAMPLE == 7
+            code = ((ihigh << 6) | ilow) >> 1;
+#elif BITS_PER_SAMPLE == 6
+            code = ((ihigh << 6) | ilow) >> 2;
+#endif
+        }
+
+#if PACKED_OUTPUT == 1
+            /* Pack the code bits */
+            s->out_buffer |= (code << s->out_bits);
+            s->out_bits += s->bits_per_sample;
+            if (s->out_bits >= 8)
+            {
+                g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF);
+                s->out_bits -= 8;
+                s->out_buffer >>= 8;
+            }
+#else
+            g722_data[g722_bytes++] = (uint8_t) code;
+#endif
+    }
+    return g722_bytes;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --git a/embdrv/g722/g722_typedefs.h b/embdrv/g722/g722_typedefs.h
new file mode 100644
index 0000000..d8977ff
--- /dev/null
+++ b/embdrv/g722/g722_typedefs.h
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+// This file contains platform-specific typedefs and defines.
+// Much of it is derived from Chromium's build/build_config.h.
+
+#ifndef WEBRTC_TYPEDEFS_H_
+#define WEBRTC_TYPEDEFS_H_
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+//   or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define WEBRTC_ARCH_X86_FAMILY
+#define WEBRTC_ARCH_X86_64
+#define WEBRTC_ARCH_64_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__aarch64__)
+#define WEBRTC_ARCH_64_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(_M_IX86) || defined(__i386__)
+#define WEBRTC_ARCH_X86_FAMILY
+#define WEBRTC_ARCH_X86
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__ARMEL__)
+// TODO(ajm): We'd prefer to control platform defines here, but this is
+// currently provided by the Android makefiles. Commented to avoid duplicate
+// definition warnings.
+//#define WEBRTC_ARCH_ARM
+// TODO(ajm): Chromium uses the following two defines. Should we switch?
+//#define WEBRTC_ARCH_ARM_FAMILY
+//#define WEBRTC_ARCH_ARMEL
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__MIPSEL__)
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__pnacl__)
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#else
+#error Please add support for your architecture in typedefs.h
+#endif
+
+#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
+#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
+#endif
+
+#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)) ||  \
+    (defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON))
+#define WEBRTC_CPU_DETECTION
+#endif
+
+#if !defined(_MSC_VER)
+#include <stdint.h>
+#else
+// Define C99 equivalent types, since pre-2010 MSVC doesn't provide stdint.h.
+typedef signed char         int8_t;
+typedef signed short        int16_t;
+typedef signed int          int32_t;
+typedef __int64             int64_t;
+typedef unsigned char       uint8_t;
+typedef unsigned short      uint16_t;
+typedef unsigned int        uint32_t;
+typedef unsigned __int64    uint64_t;
+#endif
+
+// Borrowed from Chromium's base/compiler_specific.h.
+// Annotate a virtual method indicating it must be overriding a virtual
+// method in the parent class.
+// Use like:
+//   virtual void foo() OVERRIDE;
+#if defined(_MSC_VER)
+#define OVERRIDE override
+#elif defined(__clang__)
+// Clang defaults to C++03 and warns about using override. Squelch that.
+// Intentionally no push/pop here so all users of OVERRIDE ignore the warning
+// too. This is like passing -Wno-c++11-extensions, except that GCC won't die
+// (because it won't see this pragma).
+#pragma clang diagnostic ignored "-Wc++11-extensions"
+#define OVERRIDE override
+#elif defined(__GNUC__) && __cplusplus >= 201103 && \
+    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700
+// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled.
+#define OVERRIDE override
+#else
+#define OVERRIDE
+#endif
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
+// libjingle are merged.
+#if !defined(WARN_UNUSED_RESULT)
+#if defined(__GNUC__)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+#endif  // WARN_UNUSED_RESULT
+
+#endif  // WEBRTC_TYPEDEFS_H_
diff --git a/embdrv/sbc/BUILD.gn b/embdrv/sbc/BUILD.gn
index 7e75633..696080a 100644
--- a/embdrv/sbc/BUILD.gn
+++ b/embdrv/sbc/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@
 
   include_dirs = [
     "encoder/include",
-    "//include",
+    "//internal_include",
     "//stack/include",
   ]
 }
diff --git a/embdrv/sbc/decoder/include/oi_assert.h b/embdrv/sbc/decoder/include/oi_assert.h
index 1d18f12..4a429e1 100644
--- a/embdrv/sbc/decoder/include/oi_assert.h
+++ b/embdrv/sbc/decoder/include/oi_assert.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_bitstream.h b/embdrv/sbc/decoder/include/oi_bitstream.h
index 1fb075e..0d2aff2 100644
--- a/embdrv/sbc/decoder/include/oi_bitstream.h
+++ b/embdrv/sbc/decoder/include/oi_bitstream.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_bt_spec.h b/embdrv/sbc/decoder/include/oi_bt_spec.h
index 077befd..67d5217 100644
--- a/embdrv/sbc/decoder/include/oi_bt_spec.h
+++ b/embdrv/sbc/decoder/include/oi_bt_spec.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_codec_sbc.h b/embdrv/sbc/decoder/include/oi_codec_sbc.h
index 61fe510..ee761db 100644
--- a/embdrv/sbc/decoder/include/oi_codec_sbc.h
+++ b/embdrv/sbc/decoder/include/oi_codec_sbc.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_codec_sbc_private.h b/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
index 91d80f1..080fe5d 100644
--- a/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
+++ b/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_common.h b/embdrv/sbc/decoder/include/oi_common.h
index a4cf20b..67a69a5 100644
--- a/embdrv/sbc/decoder/include/oi_common.h
+++ b/embdrv/sbc/decoder/include/oi_common.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_cpu_dep.h b/embdrv/sbc/decoder/include/oi_cpu_dep.h
index 21faf5e..b628b4a 100644
--- a/embdrv/sbc/decoder/include/oi_cpu_dep.h
+++ b/embdrv/sbc/decoder/include/oi_cpu_dep.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_modules.h b/embdrv/sbc/decoder/include/oi_modules.h
index 3c20285..272a31a 100644
--- a/embdrv/sbc/decoder/include/oi_modules.h
+++ b/embdrv/sbc/decoder/include/oi_modules.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_osinterface.h b/embdrv/sbc/decoder/include/oi_osinterface.h
index c0a3ff1..8460ca7 100644
--- a/embdrv/sbc/decoder/include/oi_osinterface.h
+++ b/embdrv/sbc/decoder/include/oi_osinterface.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_status.h b/embdrv/sbc/decoder/include/oi_status.h
index 13a5815..8e6d20a 100644
--- a/embdrv/sbc/decoder/include/oi_status.h
+++ b/embdrv/sbc/decoder/include/oi_status.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_stddefs.h b/embdrv/sbc/decoder/include/oi_stddefs.h
index ade040d..e619635 100644
--- a/embdrv/sbc/decoder/include/oi_stddefs.h
+++ b/embdrv/sbc/decoder/include/oi_stddefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_string.h b/embdrv/sbc/decoder/include/oi_string.h
index fe1e4c1..0d53761 100644
--- a/embdrv/sbc/decoder/include/oi_string.h
+++ b/embdrv/sbc/decoder/include/oi_string.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_time.h b/embdrv/sbc/decoder/include/oi_time.h
index 9b189af..d183ccb 100644
--- a/embdrv/sbc/decoder/include/oi_time.h
+++ b/embdrv/sbc/decoder/include/oi_time.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/include/oi_utils.h b/embdrv/sbc/decoder/include/oi_utils.h
index 9579d78..269114f 100644
--- a/embdrv/sbc/decoder/include/oi_utils.h
+++ b/embdrv/sbc/decoder/include/oi_utils.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/alloc.c b/embdrv/sbc/decoder/srce/alloc.c
index db0d7f0..bc6e543 100644
--- a/embdrv/sbc/decoder/srce/alloc.c
+++ b/embdrv/sbc/decoder/srce/alloc.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/bitalloc-sbc.c b/embdrv/sbc/decoder/srce/bitalloc-sbc.c
index 3e7e6f4..caf6bdf 100644
--- a/embdrv/sbc/decoder/srce/bitalloc-sbc.c
+++ b/embdrv/sbc/decoder/srce/bitalloc-sbc.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/bitalloc.c b/embdrv/sbc/decoder/srce/bitalloc.c
index 75e914a..db8a3b5 100644
--- a/embdrv/sbc/decoder/srce/bitalloc.c
+++ b/embdrv/sbc/decoder/srce/bitalloc.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/bitstream-decode.c b/embdrv/sbc/decoder/srce/bitstream-decode.c
index 5c8b664..913c064 100644
--- a/embdrv/sbc/decoder/srce/bitstream-decode.c
+++ b/embdrv/sbc/decoder/srce/bitstream-decode.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/decoder-oina.c b/embdrv/sbc/decoder/srce/decoder-oina.c
index 5811584..3553d06 100644
--- a/embdrv/sbc/decoder/srce/decoder-oina.c
+++ b/embdrv/sbc/decoder/srce/decoder-oina.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2006 Open Interface North America, Inc. All rights reserved.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/embdrv/sbc/decoder/srce/decoder-private.c b/embdrv/sbc/decoder/srce/decoder-private.c
index 686dd6a..2b10cde 100644
--- a/embdrv/sbc/decoder/srce/decoder-private.c
+++ b/embdrv/sbc/decoder/srce/decoder-private.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/decoder-sbc.c b/embdrv/sbc/decoder/srce/decoder-sbc.c
index 85c37d6..20c5b67 100644
--- a/embdrv/sbc/decoder/srce/decoder-sbc.c
+++ b/embdrv/sbc/decoder/srce/decoder-sbc.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2006 Open Interface North America, Inc. All rights reserved.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/embdrv/sbc/decoder/srce/dequant.c b/embdrv/sbc/decoder/srce/dequant.c
index 5243477..e2bce9e 100644
--- a/embdrv/sbc/decoder/srce/dequant.c
+++ b/embdrv/sbc/decoder/srce/dequant.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/framing-sbc.c b/embdrv/sbc/decoder/srce/framing-sbc.c
index e3b1000..9aea461 100644
--- a/embdrv/sbc/decoder/srce/framing-sbc.c
+++ b/embdrv/sbc/decoder/srce/framing-sbc.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/framing.c b/embdrv/sbc/decoder/srce/framing.c
index f6f762c..f835b52 100644
--- a/embdrv/sbc/decoder/srce/framing.c
+++ b/embdrv/sbc/decoder/srce/framing.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/oi_codec_version.c b/embdrv/sbc/decoder/srce/oi_codec_version.c
index 4b69183..70c005f 100644
--- a/embdrv/sbc/decoder/srce/oi_codec_version.c
+++ b/embdrv/sbc/decoder/srce/oi_codec_version.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/readsamplesjoint.inc b/embdrv/sbc/decoder/srce/readsamplesjoint.inc
index 79151ff..5c9613e 100644
--- a/embdrv/sbc/decoder/srce/readsamplesjoint.inc
+++ b/embdrv/sbc/decoder/srce/readsamplesjoint.inc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/synthesis-8-generated.c b/embdrv/sbc/decoder/srce/synthesis-8-generated.c
index d852c74..1656dc4 100644
--- a/embdrv/sbc/decoder/srce/synthesis-8-generated.c
+++ b/embdrv/sbc/decoder/srce/synthesis-8-generated.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/synthesis-dct8.c b/embdrv/sbc/decoder/srce/synthesis-dct8.c
index 514c900..2dfe753 100644
--- a/embdrv/sbc/decoder/srce/synthesis-dct8.c
+++ b/embdrv/sbc/decoder/srce/synthesis-dct8.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/decoder/srce/synthesis-sbc.c b/embdrv/sbc/decoder/srce/synthesis-sbc.c
index 12950c3..a5111ae 100644
--- a/embdrv/sbc/decoder/srce/synthesis-sbc.c
+++ b/embdrv/sbc/decoder/srce/synthesis-sbc.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2014 The Android Open Source Project
  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights
  *                        reserved.
  *
diff --git a/embdrv/sbc/encoder/Android.bp b/embdrv/sbc/encoder/Android.bp
index 6e22f89..8ca44de 100644
--- a/embdrv/sbc/encoder/Android.bp
+++ b/embdrv/sbc/encoder/Android.bp
@@ -17,7 +17,7 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/stack/include",
     ],
 }
diff --git a/embdrv/sbc/encoder/include/sbc_dct.h b/embdrv/sbc/encoder/include/sbc_dct.h
index 10123e5..86130b7 100644
--- a/embdrv/sbc/encoder/include/sbc_dct.h
+++ b/embdrv/sbc/encoder/include/sbc_dct.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/include/sbc_enc_func_declare.h b/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
index 3fbe06a..081f8ab 100644
--- a/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
+++ b/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/include/sbc_encoder.h b/embdrv/sbc/encoder/include/sbc_encoder.h
index e53a08a..53a04a2 100644
--- a/embdrv/sbc/encoder/include/sbc_encoder.h
+++ b/embdrv/sbc/encoder/include/sbc_encoder.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -150,10 +150,6 @@
 /*#define ENC_VX_BUFFER_SIZE MINIMUM_ENC_VX_BUFFER_SIZE + 1024*/
 #endif
 
-#ifndef SBC_FOR_EMBEDDED_LINUX
-#define SBC_FOR_EMBEDDED_LINUX FALSE
-#endif
-
 /*constants used for index calculation*/
 #define SBC_BLK (SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS)
 
diff --git a/embdrv/sbc/encoder/include/sbc_if.h b/embdrv/sbc/encoder/include/sbc_if.h
index 19706d2..5679383 100644
--- a/embdrv/sbc/encoder/include/sbc_if.h
+++ b/embdrv/sbc/encoder/include/sbc_if.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/include/sbc_types.h b/embdrv/sbc/encoder/include/sbc_types.h
index 0069a2a..211c693 100644
--- a/embdrv/sbc/encoder/include/sbc_types.h
+++ b/embdrv/sbc/encoder/include/sbc_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_analysis.c b/embdrv/sbc/encoder/srce/sbc_analysis.c
index ddc9978..b9a9a5c 100644
--- a/embdrv/sbc/encoder/srce/sbc_analysis.c
+++ b/embdrv/sbc/encoder/srce/sbc_analysis.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_dct.c b/embdrv/sbc/encoder/srce/sbc_dct.c
index 4ef5572..9f0efe4 100644
--- a/embdrv/sbc/encoder/srce/sbc_dct.c
+++ b/embdrv/sbc/encoder/srce/sbc_dct.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c b/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
index 287ad4c..fd7e9cd 100644
--- a/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
+++ b/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c b/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
index f849340..868ce6f 100644
--- a/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
+++ b/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c b/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
index 4e205e2..00ee65b 100644
--- a/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
+++ b/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c b/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
index 2129fba..2536b79 100644
--- a/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
+++ b/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_encoder.c b/embdrv/sbc/encoder/srce/sbc_encoder.c
index 978fa71..54212ad 100644
--- a/embdrv/sbc/encoder/srce/sbc_encoder.c
+++ b/embdrv/sbc/encoder/srce/sbc_encoder.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/embdrv/sbc/encoder/srce/sbc_packing.c b/embdrv/sbc/encoder/srce/sbc_packing.c
index 5f36ab8..b478a80 100644
--- a/embdrv/sbc/encoder/srce/sbc_packing.c
+++ b/embdrv/sbc/encoder/srce/sbc_packing.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/Android.bp b/hci/Android.bp
index 4edcfee..635d939 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -31,7 +31,7 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/btcore/include",
         "system/bt/stack/include",
         "system/bt/utils/include",
@@ -51,7 +51,7 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/btcore/include",
         "system/bt/osi/test",
         "system/bt/stack/include",
@@ -73,6 +73,6 @@
         "libosi-AllocationTestHarness",
         "libcutils",
         "libbtcore",
-        "libbt-protos",
+        "libbt-protos-lite",
     ],
 }
diff --git a/hci/AndroidTest.xml b/hci/AndroidTest.xml
index b7c1e64..944b454 100644
--- a/hci/AndroidTest.xml
+++ b/hci/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright 2017 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.
diff --git a/hci/BUILD.gn b/hci/BUILD.gn
index ba38134..fc9c2ce 100644
--- a/hci/BUILD.gn
+++ b/hci/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
   include_dirs = [
     "include",
     "//",
-    "//include",
+    "//internal_include",
     "//bta/include",
     "//btcore/include",
     "//stack/include",
@@ -52,7 +52,7 @@
 
   include_dirs = [
     "//",
-    "//include",
+    "//internal_include",
     "//btcore/include",
     "//hci/include",
     "//osi/test",
diff --git a/hci/include/bt_hci_bdroid.h b/hci/include/bt_hci_bdroid.h
index aa193d0..cf2c113 100644
--- a/hci/include/bt_hci_bdroid.h
+++ b/hci/include/bt_hci_bdroid.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/bt_vendor_lib.h b/hci/include/bt_vendor_lib.h
index 3c056ab..a274af7 100644
--- a/hci/include/bt_vendor_lib.h
+++ b/hci/include/bt_vendor_lib.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/btsnoop.h b/hci/include/btsnoop.h
index 1cd35dc..e897a96 100644
--- a/hci/include/btsnoop.h
+++ b/hci/include/btsnoop.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/btsnoop_mem.h b/hci/include/btsnoop_mem.h
index cf42ff7..42c3229 100644
--- a/hci/include/btsnoop_mem.h
+++ b/hci/include/btsnoop_mem.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/buffer_allocator.h b/hci/include/buffer_allocator.h
index 63fb217..3bfa2e44 100644
--- a/hci/include/buffer_allocator.h
+++ b/hci/include/buffer_allocator.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/hci_hal.h b/hci/include/hci_hal.h
index 53595c0..f73e116 100644
--- a/hci/include/hci_hal.h
+++ b/hci/include/hci_hal.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/hci_inject.h b/hci/include/hci_inject.h
index 12870d5..62ec518 100644
--- a/hci/include/hci_inject.h
+++ b/hci/include/hci_inject.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/hci_internals.h b/hci/include/hci_internals.h
index 6b9fb01..8fe0041 100644
--- a/hci/include/hci_internals.h
+++ b/hci/include/hci_internals.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
index acb86de..59ee443 100644
--- a/hci/include/hci_layer.h
+++ b/hci/include/hci_layer.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/hci_packet_factory.h b/hci/include/hci_packet_factory.h
index ed189d6..e7cb47b 100644
--- a/hci/include/hci_packet_factory.h
+++ b/hci/include/hci_packet_factory.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@
   BT_HDR* (*make_ble_read_local_supported_features)(void);
   BT_HDR* (*make_ble_read_resolving_list_size)(void);
   BT_HDR* (*make_ble_read_suggested_default_data_length)(void);
+  BT_HDR* (*make_ble_read_maximum_data_length)(void);
   BT_HDR* (*make_ble_read_maximum_advertising_data_length)(void);
   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);
diff --git a/hci/include/hci_packet_parser.h b/hci/include/hci_packet_parser.h
index 0e74c29..8878cb9 100644
--- a/hci/include/hci_packet_parser.h
+++ b/hci/include/hci_packet_parser.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -67,6 +67,12 @@
   void (*parse_ble_read_suggested_default_data_length_response)(
       BT_HDR* response, uint16_t* ble_default_packet_length_ptr);
 
+  void (*parse_ble_read_maximum_data_length_response)(
+      BT_HDR* response, uint16_t* ble_supported_max_tx_octets,
+      uint16_t* ble_supported_max_tx_time,
+      uint16_t* ble_supported_max_rx_octets,
+      uint16_t* ble_supported_max_rx_time);
+
   void (*parse_ble_read_maximum_advertising_data_length)(
       BT_HDR* response, uint16_t* ble_maximum_advertising_data_length_ptr);
 
diff --git a/hci/include/low_power_manager.h b/hci/include/low_power_manager.h
index 47e3b6d..8b8bd8f 100644
--- a/hci/include/low_power_manager.h
+++ b/hci/include/low_power_manager.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/packet_fragmenter.h b/hci/include/packet_fragmenter.h
index 935ea94..9b252b8 100644
--- a/hci/include/packet_fragmenter.h
+++ b/hci/include/packet_fragmenter.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/userial.h b/hci/include/userial.h
index becb407..2d1424f 100644
--- a/hci/include/userial.h
+++ b/hci/include/userial.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/include/vendor.h b/hci/include/vendor.h
index 70a2cef..ca9f153 100644
--- a/hci/include/vendor.h
+++ b/hci/include/vendor.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/btsnoop.cc b/hci/src/btsnoop.cc
index a109ad0..9812b61 100644
--- a/hci/src/btsnoop.cc
+++ b/hci/src/btsnoop.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
 #include "bt_types.h"
@@ -199,7 +200,7 @@
   get_btsnoop_log_path(log_path);
   get_btsnoop_last_log_path(last_log_path, log_path);
 
-  if (!rename(log_path, last_log_path) && errno != ENOENT)
+  if (rename(log_path, last_log_path) != 0 && errno != ENOENT)
     LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
               log_path, last_log_path, strerror(errno));
 
diff --git a/hci/src/btsnoop_mem.cc b/hci/src/btsnoop_mem.cc
index ad135e0..17ce248 100644
--- a/hci/src/btsnoop_mem.cc
+++ b/hci/src/btsnoop_mem.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/btsnoop_net.cc b/hci/src/btsnoop_net.cc
index 1d49692..a549205 100644
--- a/hci/src/btsnoop_net.cc
+++ b/hci/src/btsnoop_net.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2013 Google, Inc.
+ *  Copyright 2013 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/buffer_allocator.cc b/hci/src/buffer_allocator.cc
index d231abe..19a3940 100644
--- a/hci/src/buffer_allocator.cc
+++ b/hci/src/buffer_allocator.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/hci_inject.cc b/hci/src/hci_inject.cc
index 70194a5..01b8cfd 100644
--- a/hci/src/hci_inject.cc
+++ b/hci/src/hci_inject.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index d1fa920..f1e0e7a 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -78,7 +78,9 @@
 
 // Abort if there is no response to an HCI command.
 static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;
-static const uint32_t COMMAND_TIMEOUT_RESTART_US = 5000000;
+static const uint32_t COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS = 500;
+static const uint32_t COMMAND_TIMEOUT_RESTART_MS = 5000;
+static const int HCI_UNKNOWN_COMMAND_TIMED_OUT = 0x00ffffff;
 
 // Our interface
 static bool interface_created;
@@ -105,7 +107,8 @@
 // Inbound-related
 static alarm_t* command_response_timer;
 static list_t* commands_pending_response;
-static std::recursive_mutex commands_pending_response_mutex;
+static std::recursive_timed_mutex commands_pending_response_mutex;
+static alarm_t* hci_timeout_abort_timer;
 
 // The hand-off point for data going to a higher layer, set by the higher layer
 static base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
@@ -254,7 +257,8 @@
 
   // Free the timers
   {
-    std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+    std::lock_guard<std::recursive_timed_mutex> lock(
+        commands_pending_response_mutex);
     alarm_free(command_response_timer);
     command_response_timer = NULL;
     alarm_free(startup_timer);
@@ -276,7 +280,8 @@
   hci_close();
 
   {
-    std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+    std::lock_guard<std::recursive_timed_mutex> lock(
+        commands_pending_response_mutex);
     list_free(commands_pending_response);
     commands_pending_response = NULL;
   }
@@ -286,6 +291,17 @@
   thread_free(thread);
   thread = NULL;
 
+  // Clean up abort timer, if it exists.
+  if (hci_timeout_abort_timer != NULL) {
+    alarm_free(hci_timeout_abort_timer);
+    hci_timeout_abort_timer = NULL;
+  }
+
+  if (hci_firmware_log_fd != INVALID_FD) {
+    hci_close_firmware_log_file(hci_firmware_log_fd);
+    hci_firmware_log_fd = INVALID_FD;
+  }
+
   return NULL;
 }
 
@@ -359,7 +375,8 @@
 
 static void event_finish_startup(UNUSED_ATTR void* context) {
   LOG_INFO(LOG_TAG, "%s", __func__);
-  std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+  std::lock_guard<std::recursive_timed_mutex> lock(
+      commands_pending_response_mutex);
   alarm_cancel(startup_timer);
   future_ready(startup_future, FUTURE_SUCCESS);
   startup_future = NULL;
@@ -368,9 +385,18 @@
 static void startup_timer_expired(UNUSED_ATTR void* context) {
   LOG_ERROR(LOG_TAG, "%s", __func__);
 
-  std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+  std::unique_lock<std::recursive_timed_mutex> lock(
+      commands_pending_response_mutex, std::defer_lock);
+  if (!lock.try_lock_for(std::chrono::milliseconds(
+          COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
+    LOG_ERROR(LOG_TAG, "%s: Cannot obtain the mutex", __func__);
+    // We cannot recover if the startup timer expired and we are deadlock,
+    // hence abort.
+    abort();
+  }
   future_ready(startup_future, FUTURE_FAIL);
   startup_future = NULL;
+  lock.unlock();
 }
 
 // Command/packet transmitting functions
@@ -394,11 +420,13 @@
 }
 
 static void event_command_ready(waiting_command_t* wait_entry) {
-  /// Move it to the list of commands awaiting response
-  std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
-  wait_entry->timestamp = std::chrono::steady_clock::now();
-  list_append(commands_pending_response, wait_entry);
-
+  {
+    /// Move it to the list of commands awaiting response
+    std::lock_guard<std::recursive_timed_mutex> lock(
+        commands_pending_response_mutex);
+    wait_entry->timestamp = std::chrono::steady_clock::now();
+    list_append(commands_pending_response, wait_entry);
+  }
   // Send it off
   packet_fragmenter->fragment_and_dispatch(wait_entry->command);
 
@@ -426,11 +454,17 @@
 static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) {
   btsnoop->capture(packet, false);
 
+  // HCI command packets are freed on a different thread when the matching
+  // event is received. Check packet->event before sending to avoid a race.
+  bool free_after_transmit =
+      (packet->event & MSG_EVT_MASK) != MSG_STACK_TO_HC_HCI_CMD &&
+      send_transmit_finished;
+
   hci_transmit(packet);
 
-  uint16_t event = packet->event & MSG_EVT_MASK;
-  if (event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished)
+  if (free_after_transmit) {
     buffer_allocator->free(packet);
+  }
 }
 
 static void fragmenter_transmit_finished(BT_HDR* packet,
@@ -446,10 +480,17 @@
   }
 }
 
-// Print debugging information and quit. Don't dereference original_wait_entry.
-static void command_timed_out(void* original_wait_entry) {
-  std::unique_lock<std::recursive_mutex> lock(commands_pending_response_mutex);
+// Abort.  The chip has had time to write any debugging information.
+static void hci_timeout_abort(void* unused_data) {
+  LOG_ERROR(LOG_TAG, "%s restarting the Bluetooth process.", __func__);
+  hci_close_firmware_log_file(hci_firmware_log_fd);
 
+  // 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();
+}
+
+static void command_timed_out_log_info(void* original_wait_entry) {
   LOG_ERROR(LOG_TAG, "%s: %d commands pending response", __func__,
             get_num_waiting_commands());
 
@@ -479,7 +520,26 @@
 
     LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
   }
-  lock.unlock();
+}
+
+// Print debugging information and quit. Don't dereference original_wait_entry.
+static void command_timed_out(void* original_wait_entry) {
+  LOG_ERROR(LOG_TAG, "%s", __func__);
+  std::unique_lock<std::recursive_timed_mutex> lock(
+      commands_pending_response_mutex, std::defer_lock);
+  if (!lock.try_lock_for(std::chrono::milliseconds(
+          COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
+    LOG_ERROR(LOG_TAG, "%s: Cannot obtain the mutex", __func__);
+    LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, HCI_UNKNOWN_COMMAND_TIMED_OUT);
+  } else {
+    command_timed_out_log_info(original_wait_entry);
+    lock.unlock();
+  }
+
+  // Don't request a firmware dump for multiple hci timeouts
+  if (hci_timeout_abort_timer != NULL || hci_firmware_log_fd != INVALID_FD) {
+    return;
+  }
 
   LOG_ERROR(LOG_TAG, "%s: requesting a firmware dump.", __func__);
 
@@ -502,14 +562,15 @@
   transmit_fragment(bt_hdr, true);
 
   osi_free(bt_hdr);
+  LOG_ERROR(LOG_TAG, "%s: Setting a timer to restart.", __func__);
 
-  LOG_ERROR(LOG_TAG, "%s restarting the Bluetooth process.", __func__);
-  usleep(COMMAND_TIMEOUT_RESTART_US);
-  hci_close_firmware_log_file(hci_firmware_log_fd);
-
-  // 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();
+  hci_timeout_abort_timer = alarm_new("hci.hci_timeout_aborter");
+  if (!hci_timeout_abort_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create an abort timer.", __func__);
+    abort();
+  }
+  alarm_set(hci_timeout_abort_timer, COMMAND_TIMEOUT_RESTART_MS,
+            hci_timeout_abort, nullptr);
 }
 
 // Event/packet receiving functions
@@ -640,7 +701,8 @@
 // Misc internal functions
 
 static waiting_command_t* get_waiting_command(command_opcode_t opcode) {
-  std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+  std::lock_guard<std::recursive_timed_mutex> lock(
+      commands_pending_response_mutex);
 
   for (const list_node_t* node = list_begin(commands_pending_response);
        node != list_end(commands_pending_response); node = list_next(node)) {
@@ -658,12 +720,14 @@
 }
 
 static int get_num_waiting_commands() {
-  std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+  std::lock_guard<std::recursive_timed_mutex> lock(
+      commands_pending_response_mutex);
   return list_length(commands_pending_response);
 }
 
 static void update_command_response_timer(void) {
-  std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+  std::lock_guard<std::recursive_timed_mutex> lock(
+      commands_pending_response_mutex);
 
   if (command_response_timer == NULL) return;
   if (list_is_empty(commands_pending_response)) {
diff --git a/hci/src/hci_layer_android.cc b/hci/src/hci_layer_android.cc
index 0598ca1..183b74e 100644
--- a/hci/src/hci_layer_android.cc
+++ b/hci/src/hci_layer_android.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 Google, Inc.
+ *  Copyright 2017 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/hci_layer_linux.cc b/hci/src/hci_layer_linux.cc
index aa37f78..e32b5ef 100644
--- a/hci/src/hci_layer_linux.cc
+++ b/hci/src/hci_layer_linux.cc
@@ -1,7 +1,7 @@
 /**********************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
- *  Copyright (C) 2015 Intel Corporation
+ *  Copyright 2017 The Android Open Source Project
+ *  Copyright 2015 Intel Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/hci/src/hci_packet_factory.cc b/hci/src/hci_packet_factory.cc
index c3c4a60..ca0fb5f 100644
--- a/hci/src/hci_packet_factory.cc
+++ b/hci/src/hci_packet_factory.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -142,6 +142,10 @@
   return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH);
 }
 
+static BT_HDR* make_ble_read_maximum_data_length(void) {
+  return make_command_no_params(HCI_BLE_READ_MAXIMUM_DATA_LENGTH);
+}
+
 static BT_HDR* make_ble_read_maximum_advertising_data_length(void) {
   return make_command_no_params(HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH);
 }
@@ -212,6 +216,7 @@
     make_ble_read_local_supported_features,
     make_ble_read_resolving_list_size,
     make_ble_read_suggested_default_data_length,
+    make_ble_read_maximum_data_length,
     make_ble_read_maximum_advertising_data_length,
     make_ble_read_number_of_supported_advertising_sets,
     make_ble_set_event_mask,
diff --git a/hci/src/hci_packet_parser.cc b/hci/src/hci_packet_parser.cc
index e7ace27..b1efd44 100644
--- a/hci/src/hci_packet_parser.cc
+++ b/hci/src/hci_packet_parser.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -184,7 +184,23 @@
     BT_HDR* response, uint16_t* ble_default_packet_length_ptr) {
   uint8_t* stream = read_command_complete_header(
       response, HCI_BLE_READ_DEFAULT_DATA_LENGTH, 2 /* bytes after */);
-  STREAM_TO_UINT8(*ble_default_packet_length_ptr, stream);
+  STREAM_TO_UINT16(*ble_default_packet_length_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_maximum_data_length_response(
+    BT_HDR* response, uint16_t* ble_supported_max_tx_octets,
+    uint16_t* ble_supported_max_tx_time, uint16_t* ble_supported_max_rx_octets,
+    uint16_t* ble_supported_max_rx_time) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_BLE_READ_MAXIMUM_DATA_LENGTH, 8 /* bytes after */);
+  STREAM_TO_UINT16(*ble_supported_max_tx_octets, stream);
+  STREAM_TO_UINT16(*ble_supported_max_tx_time, stream);
+  STREAM_TO_UINT16(*ble_supported_max_rx_octets, stream);
+  STREAM_TO_UINT16(*ble_supported_max_rx_time, stream);
+
+  buffer_allocator->free(response);
 }
 
 static void parse_ble_read_maximum_advertising_data_length(
@@ -262,6 +278,7 @@
     parse_ble_read_local_supported_features_response,
     parse_ble_read_resolving_list_size_response,
     parse_ble_read_suggested_default_data_length_response,
+    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};
diff --git a/hci/src/packet_fragmenter.cc b/hci/src/packet_fragmenter.cc
index 7ac4850..921ac82 100644
--- a/hci/src/packet_fragmenter.cc
+++ b/hci/src/packet_fragmenter.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,7 +39,9 @@
 #define HANDLE_MASK 0x0FFF
 #define START_PACKET_BOUNDARY 2
 #define CONTINUATION_PACKET_BOUNDARY 1
-#define L2CAP_HEADER_SIZE 4
+#define L2CAP_HEADER_PDU_LEN_SIZE 2
+#define L2CAP_HEADER_CID_SIZE 2
+#define L2CAP_HEADER_SIZE (L2CAP_HEADER_PDU_LEN_SIZE + L2CAP_HEADER_CID_SIZE)
 
 // Our interface and callbacks
 
@@ -146,9 +148,9 @@
         buffer_allocator->free(hdl);
       }
 
-      if (acl_length < L2CAP_HEADER_SIZE) {
+      if (acl_length < L2CAP_HEADER_PDU_LEN_SIZE) {
         LOG_WARN(LOG_TAG, "%s L2CAP packet too small (%d < %d). Dropping it.",
-                 __func__, packet->len, L2CAP_HEADER_SIZE);
+                 __func__, packet->len, L2CAP_HEADER_PDU_LEN_SIZE);
         buffer_allocator->free(packet);
         return;
       }
diff --git a/hci/test/packet_fragmenter_test.cc b/hci/test/packet_fragmenter_test.cc
index 29c130d..483a66d 100644
--- a/hci/test/packet_fragmenter_test.cc
+++ b/hci/test/packet_fragmenter_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/include/Android.bp b/include/Android.bp
new file mode 100644
index 0000000..01a01b5
--- /dev/null
+++ b/include/Android.bp
@@ -0,0 +1,31 @@
+cc_library_headers {
+    name: "avrcp_headers",
+    defaults: ["libchrome_support_defaults"],
+    include_dirs: ["system/bt/internal_include"],
+    export_include_dirs: ["./hardware/avrcp/"],
+    header_libs: ["internal_include_headers"],
+    export_header_lib_headers: ["internal_include_headers"],
+
+    // We need this in case some file outside of the Bluetooth project includes
+    // bluetooth.h but doesn't include libchrome which avrcp.h depends on.
+    export_shared_lib_headers: ["libchrome"],
+
+    vendor_available: true,
+    host_supported: true,
+}
+
+cc_library_headers {
+    name: "libbluetooth_headers",
+    defaults: ["libchrome_support_defaults"],
+    header_libs: [
+        "avrcp_headers",
+        "libbluetooth-types-header",
+    ],
+    export_header_lib_headers: [
+        "avrcp_headers",
+        "libbluetooth-types-header",
+    ],
+    export_include_dirs: ["./"],
+    vendor_available: true,
+    host_supported: true,
+}
diff --git a/include/hardware/avrcp/avrcp.h b/include/hardware/avrcp/avrcp.h
new file mode 100644
index 0000000..8adba47
--- /dev/null
+++ b/include/hardware/avrcp/avrcp.h
@@ -0,0 +1,187 @@
+/*
+ * 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 <set>
+#include <string>
+
+#include <base/bind.h>
+
+#include "avrcp_common.h"
+#include "raw_address.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+struct SongInfo {
+  std::string media_id;  // This gets converted to a UID in the native service
+  std::set<AttributeEntry> attributes;
+};
+
+enum PlayState : uint8_t {
+  STOPPED = 0x00,
+  PLAYING,
+  PAUSED,
+  FWD_SEEK,
+  REV_SEEK,
+  ERROR = 0xFF,
+};
+
+struct PlayStatus {
+  uint32_t position;
+  uint32_t duration;
+  PlayState state;
+};
+
+struct MediaPlayerInfo {
+  uint16_t id;
+  std::string name;
+  bool browsing_supported;
+};
+
+struct FolderInfo {
+  std::string media_id;
+  bool is_playable;
+  std::string name;
+};
+
+// TODO (apanicke): Convert this to a union
+struct ListItem {
+  enum : uint8_t {
+    FOLDER,
+    SONG,
+  } type;
+
+  FolderInfo folder;
+  SongInfo song;
+};
+
+class MediaCallbacks {
+ public:
+  virtual void SendMediaUpdate(bool track_changed, bool play_state, bool queue);
+  virtual void SendFolderUpdate(bool available_players, bool addressed_players,
+                                bool uids_changed);
+  virtual void SendActiveDeviceChanged(const RawAddress& address);
+  virtual ~MediaCallbacks() = default;
+};
+
+// The classes below are used by the JNI and are loaded dynamically with the
+// Bluetooth library. All classes must be pure virtual otherwise a compiler
+// error occurs when trying to link the function implementation.
+
+// MediaInterface defines the class that the AVRCP Service uses in order
+// communicate with the media layer. The media layer will define its own
+// implementation of this object and register it with the service using
+// Avrcp::ServiceInterface::Init(). At this point the AVRCP Service will
+// call RegisterUpdateCallbacks() to provide an handle to use to send
+// notifications about changes in the Media Interface.
+//
+// NOTES: The current implementation has the native service handle all the
+// thread switching. It will call the interface functions on the btif/jni
+// thread and the callback will post its results to the bta thread.
+// In the future the interface the JNI registered with the
+// service should post all its tasks to the JNI thread itself so that the native
+// service isn't aware of the thread the interface functions need to be called
+// on. It can then supply callbacks that post results to the correct thread
+// allowing the threading model to be totally encapsulated and allow correct
+// behavior in case the threading model changes on either side.
+class MediaInterface {
+ public:
+  virtual void SendKeyEvent(uint8_t key, KeyState state) = 0;
+
+  using SongInfoCallback = base::Callback<void(SongInfo)>;
+  virtual void GetSongInfo(SongInfoCallback info_cb) = 0;
+
+  using PlayStatusCallback = base::Callback<void(PlayStatus)>;
+  virtual void GetPlayStatus(PlayStatusCallback status_cb) = 0;
+
+  // Contains the current queue and the media ID of the currently playing item
+  // in the queue
+  using NowPlayingCallback =
+      base::Callback<void(std::string, std::vector<SongInfo>)>;
+  virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) = 0;
+
+  // TODO (apanicke): Use a map with the ID as the key instead of vector
+  // in follow up cleanup patches. This allows simplification of the
+  // MediaPlayerInfo object
+  using MediaListCallback =
+      base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
+  virtual void GetMediaPlayerList(MediaListCallback list_cb) = 0;
+
+  using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
+  virtual void GetFolderItems(uint16_t player_id, std::string media_id,
+                              FolderItemsCallback folder_cb) = 0;
+
+  using SetBrowsedPlayerCallback = base::Callback<void(
+      bool success, std::string root_id, uint32_t num_items)>;
+  virtual void SetBrowsedPlayer(uint16_t player_id,
+                                SetBrowsedPlayerCallback browse_cb) = 0;
+
+  virtual void PlayItem(uint16_t player_id, bool now_playing,
+                        std::string media_id) = 0;
+
+  virtual void SetActiveDevice(const RawAddress& address) = 0;
+
+  virtual void RegisterUpdateCallback(MediaCallbacks* callback) = 0;
+
+  virtual void UnregisterUpdateCallback(MediaCallbacks* callback) = 0;
+
+  MediaInterface() = default;
+  virtual ~MediaInterface() = default;
+};
+
+class VolumeInterface {
+ public:
+  // TODO (apanicke): Investigate the best value type for volume. Right now it
+  // is a value from 0-127 because thats what AVRCP uses.
+  using VolumeChangedCb = base::Callback<void(int8_t volume)>;
+
+  // Indicate that a device has been connected that does not support absolute
+  // volume.
+  virtual void DeviceConnected(const RawAddress& bdaddr) = 0;
+
+  // Indicate that a device has been connected that does support absolute
+  // volume. The callback will be immediately called with the current volume
+  // which will be sent to the device.
+  virtual void DeviceConnected(const RawAddress& bdaddr,
+                               VolumeChangedCb cb) = 0;
+
+  // Indicate that a device has been disconnected from AVRCP. Will unregister
+  // any callbacks if absolute volume is supported.
+  virtual void DeviceDisconnected(const RawAddress& bdaddr) = 0;
+
+  virtual void SetVolume(int8_t volume) = 0;
+
+  virtual ~VolumeInterface() = default;
+};
+
+class ServiceInterface {
+ public:
+  // mediaInterface can not be null. If volumeInterface is null then Absolute
+  // Volume is disabled.
+  virtual void Init(MediaInterface* mediaInterface,
+                    VolumeInterface* volumeInterface) = 0;
+  virtual bool ConnectDevice(const RawAddress& bdaddr) = 0;
+  virtual bool DisconnectDevice(const RawAddress& bdaddr) = 0;
+  virtual bool Cleanup() = 0;
+
+ protected:
+  virtual ~ServiceInterface() = default;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/include/hardware/avrcp/avrcp_common.h b/include/hardware/avrcp/avrcp_common.h
new file mode 100644
index 0000000..702f95d
--- /dev/null
+++ b/include/hardware/avrcp/avrcp_common.h
@@ -0,0 +1,355 @@
+/*
+ * 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 <set>
+
+#include <base/sys_byteorder.h>
+
+namespace bluetooth {
+namespace avrcp {
+
+constexpr uint32_t BLUETOOTH_COMPANY_ID = 0x001958;
+
+constexpr uint8_t MAX_TRANSACTION_LABEL = 0xF;
+
+enum class CType : uint8_t {
+  CONTROL = 0x0,
+  STATUS = 0x1,
+  NOTIFY = 0x3,
+  NOT_IMPLEMENTED = 0x8,
+  ACCEPTED = 0x9,
+  REJECTED = 0xa,
+  STABLE = 0xc,
+  CHANGED = 0xd,
+  INTERIM = 0xf,
+};
+
+enum class Opcode : uint8_t {
+  VENDOR = 0x00,
+  UNIT_INFO = 0x30,
+  SUBUNIT_INFO = 0x31,
+  PASS_THROUGH = 0x7c,
+};
+
+// Found in AVRCP_v1.6.1 Section 4.5 Table 4.5
+// Searching can be done in the spec by Camel Casing the constant name
+enum class CommandPdu : uint8_t {
+  GET_CAPABILITIES = 0x10,
+  LIST_APPLICATION_SETTING_ATTRIBUTES = 0x11,
+  GET_ELEMENT_ATTRIBUTES = 0x20,
+  GET_PLAY_STATUS = 0x30,
+  REGISTER_NOTIFICATION = 0x31,
+  SET_ABSOLUTE_VOLUME = 0x50,
+  SET_ADDRESSED_PLAYER = 0x60,
+  PLAY_ITEM = 0x74,
+};
+
+enum class PacketType : uint8_t {
+  SINGLE = 0x00,
+};
+
+enum class Capability : uint8_t {
+  COMPANY_ID = 0x02,
+  EVENTS_SUPPORTED = 0x03,
+};
+
+// Found in AVRCP_v1.6.1 Section 28 Appendix H
+enum class Event : uint8_t {
+  PLAYBACK_STATUS_CHANGED = 0x01,
+  TRACK_CHANGED = 0x02,
+  PLAYBACK_POS_CHANGED = 0x05,
+  PLAYER_APPLICATION_SETTING_CHANGED = 0x08,
+  NOW_PLAYING_CONTENT_CHANGED = 0x09,
+  AVAILABLE_PLAYERS_CHANGED = 0x0a,
+  ADDRESSED_PLAYER_CHANGED = 0x0b,
+  UIDS_CHANGED = 0x0c,
+  VOLUME_CHANGED = 0x0d,
+};
+
+enum class Attribute : uint32_t {
+  TITLE = 0x01,
+  ARTIST_NAME = 0x02,
+  ALBUM_NAME = 0x03,
+  TRACK_NUMBER = 0x04,
+  TOTAL_NUMBER_OF_TRACKS = 0x05,
+  GENRE = 0x06,
+  PLAYING_TIME = 0x07,
+  DEFAULT_COVER_ART = 0x08,
+};
+
+enum class Status : uint8_t {
+  INVALID_COMMAND = 0x00,
+  INVALID_PARAMETER = 0x01,
+  PARAMETER_CONTENT_ERROR = 0x02,
+  INTERNAL_ERROR = 0x03,
+  NO_ERROR = 0x04,
+  UIDS_CHANGED = 0x05,
+  RESERVED = 0x06,
+  INVALID_DIRECTION = 0x07,
+  NOT_A_DIRECTORY = 0x08,
+  DOES_NOT_EXIST = 0x09,
+  INVALID_SCOPE = 0x0a,
+  RANGE_OUT_OF_BOUNDS = 0xb,
+  FOLDER_ITEM_NOT_PLAYABLE = 0x0c,
+  MEDIA_IN_USE = 0x0d,
+  NOW_PLAYING_LIST_FULL = 0x0e,
+  SEARCH_NOT_SUPPORTED = 0x0f,
+  SEARCH_IN_PROGRESS = 0x10,
+  INVALID_PLAYER_ID = 0x11,
+  PLAYER_NOT_BROWSABLE = 0x12,
+  PLAYER_NOT_ADDRESSED = 0x13,
+  NO_VALID_SEARCH_RESULTS = 0x14,
+  NO_AVAILABLE_PLAYERS = 0x15,
+  ADDRESSED_PLAYER_CHANGED = 0x16,
+};
+
+enum class BrowsePdu : uint8_t {
+  SET_BROWSED_PLAYER = 0x70,
+  GET_FOLDER_ITEMS = 0x71,
+  CHANGE_PATH = 0x72,
+  GET_ITEM_ATTRIBUTES = 0x73,
+  GET_TOTAL_NUMBER_OF_ITEMS = 0x75,
+  GENERAL_REJECT = 0xa0,
+};
+
+enum class Scope : uint8_t {
+  MEDIA_PLAYER_LIST = 0x00,
+  VFS = 0x01,
+  SEARCH = 0x02,
+  NOW_PLAYING = 0x03,
+};
+
+enum class Direction : uint8_t {
+  UP = 0x00,
+  DOWN = 0x01,
+};
+
+enum class KeyState : uint8_t {
+  PUSHED = 0x00,
+  RELEASED = 0x01,
+};
+
+class AttributeEntry {
+ public:
+  AttributeEntry(const Attribute& attribute, const std::string& value)
+      : attribute_(attribute), value_(value) {}
+
+  AttributeEntry(const Attribute& attribute) : attribute_(attribute) {}
+
+  AttributeEntry(const AttributeEntry&) = default;
+
+  Attribute attribute() const { return attribute_; }
+
+  std::string value() const { return value_; }
+
+  static constexpr size_t kHeaderSize() {
+    size_t ret = 0;
+    ret += 4;  // Size of attribute field
+    ret += 2;  // Size of length field
+    ret += 2;  // Size of character encoding field
+    return ret;
+  }
+
+  size_t size() const { return kHeaderSize() + value_.size(); }
+
+  void resize(size_t new_size) {
+    new_size = new_size < kHeaderSize() ? 0 : new_size - kHeaderSize();
+    if (value_.size() > new_size) {
+      value_.resize(new_size);
+    }
+  }
+
+  bool empty() { return value_.empty(); }
+
+  bool operator<(const AttributeEntry& rhs) const {
+    return attribute_ < rhs.attribute_;
+  }
+
+ private:
+  Attribute attribute_;
+  std::string value_;
+};
+
+constexpr size_t MAX_FIELD_LEN = 100;
+
+struct MediaPlayerItem {
+  uint16_t id_;
+  std::string name_;
+  bool browsable_;
+
+  MediaPlayerItem(uint16_t id, const std::string& name, bool browsable)
+      : id_(id), name_(name), browsable_(browsable) {
+    if (name_.size() > MAX_FIELD_LEN) {
+      name_.resize(MAX_FIELD_LEN);
+    }
+  }
+
+  MediaPlayerItem(const MediaPlayerItem&) = default;
+
+  static constexpr size_t kHeaderSize() {
+    size_t ret = 0;
+    ret += 1;   // Media Player Type
+    ret += 2;   // Item Length
+    ret += 2;   // Player Id
+    ret += 1;   // Player Type
+    ret += 4;   // Player Subtype
+    ret += 1;   // Play Status
+    ret += 16;  // Features
+    ret += 2;   // UTF-8 character set
+    ret += 2;   // Name Length
+    return ret;
+  }
+
+  size_t size() const { return kHeaderSize() + name_.size(); }
+};
+
+struct FolderItem {
+  uint64_t uid_;
+  uint8_t folder_type_;
+  bool is_playable_;
+  std::string name_;
+
+  FolderItem(uint64_t uid, uint8_t folder_type, bool is_playable,
+             const std::string& name)
+      : uid_(uid),
+        folder_type_(folder_type),
+        is_playable_(is_playable),
+        name_(name) {
+    if (name_.size() > MAX_FIELD_LEN) {
+      name_.resize(MAX_FIELD_LEN);
+    }
+  }
+
+  FolderItem(const FolderItem&) = default;
+
+  static constexpr size_t kHeaderSize() {
+    size_t ret = 0;
+    ret += 1;  // Folder Item Type
+    ret += 2;  // Item Length
+    ret += 8;  // Folder UID
+    ret += 1;  // Folder Type
+    ret += 1;  // Is Playable byte
+    ret += 2;  // UTF-8 Character Set
+    ret += 2;  // Name Length
+    return ret;
+  }
+
+  size_t size() const { return kHeaderSize() + name_.size(); }
+};
+
+// NOTE: We never use media type field because we only support audio types
+struct MediaElementItem {
+  uint64_t uid_ = 0;
+  std::string name_;
+  std::set<AttributeEntry> attributes_;
+
+  // Truncate the name and attribute fields so that we don't have a single item
+  // that can exceed the Browsing MTU
+  MediaElementItem(uint64_t uid, const std::string& name,
+                   std::set<AttributeEntry> attributes)
+      : uid_(uid), name_(name) {
+    if (name_.size() > MAX_FIELD_LEN) {
+      name_.resize(MAX_FIELD_LEN);
+    }
+
+    for (AttributeEntry val : attributes) {
+      val.resize(MAX_FIELD_LEN);
+      attributes_.insert(val);
+    }
+  }
+
+  MediaElementItem(const MediaElementItem&) = default;
+
+  size_t size() const {
+    size_t ret = 0;
+    ret += 1;  // Media Element Item Type
+    ret += 2;  // Item Length
+    ret += 8;  // Item UID
+    ret += 1;  // Media Type
+    ret += 2;  // UTF-8 Character Set
+    ret += 2;  // Name Length
+    ret += name_.size();
+    ret += 1;  // Number of Attributes
+    for (const auto& entry : attributes_) {
+      ret += entry.size();
+    }
+
+    return ret;
+  }
+};
+
+struct MediaListItem {
+  enum : uint8_t { PLAYER = 0x01, FOLDER = 0x02, SONG = 0x03 } type_;
+
+  union {
+    MediaPlayerItem player_;
+    FolderItem folder_;
+    MediaElementItem song_;
+  };
+
+  MediaListItem(MediaPlayerItem item) : type_(PLAYER), player_(item) {}
+
+  MediaListItem(FolderItem item) : type_(FOLDER), folder_(item) {}
+
+  MediaListItem(MediaElementItem item) : type_(SONG), song_(item) {}
+
+  MediaListItem(const MediaListItem& item) {
+    type_ = item.type_;
+    switch (item.type_) {
+      case PLAYER:
+        new (&player_) MediaPlayerItem(item.player_);
+        return;
+      case FOLDER:
+        new (&folder_) FolderItem(item.folder_);
+        return;
+      case SONG:
+        new (&song_) MediaElementItem(item.song_);
+        return;
+    }
+  }
+
+  ~MediaListItem() {
+    switch (type_) {
+      case PLAYER:
+        player_.~MediaPlayerItem();
+        return;
+      case FOLDER:
+        folder_.~FolderItem();
+        return;
+      case SONG:
+        song_.~MediaElementItem();
+        return;
+    }
+  }
+
+  size_t size() const {
+    switch (type_) {
+      case PLAYER:
+        return player_.size();
+      case FOLDER:
+        return folder_.size();
+      case SONG:
+        return song_.size();
+    }
+  }
+};
+
+constexpr size_t AVCT_HDR_LEN = 3;
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/include/hardware/avrcp/avrcp_logging_helper.h b/include/hardware/avrcp/avrcp_logging_helper.h
new file mode 100644
index 0000000..ce95337
--- /dev/null
+++ b/include/hardware/avrcp/avrcp_logging_helper.h
@@ -0,0 +1,243 @@
+/*
+ * 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 <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "avrcp_common.h"
+#include "bt_trace.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+#define CASE_RETURN_TEXT(code) \
+  case code:                   \
+    return #code
+
+inline std::string CTypeText(const CType& type) {
+  switch (type) {
+    CASE_RETURN_TEXT(CType::CONTROL);
+    CASE_RETURN_TEXT(CType::STATUS);
+    CASE_RETURN_TEXT(CType::NOTIFY);
+    CASE_RETURN_TEXT(CType::ACCEPTED);
+    CASE_RETURN_TEXT(CType::REJECTED);
+    CASE_RETURN_TEXT(CType::STABLE);
+    CASE_RETURN_TEXT(CType::CHANGED);
+    CASE_RETURN_TEXT(CType::INTERIM);
+    default:
+      return "Unknown CType: " + loghex((uint8_t)type);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const CType& type) {
+  return os << CTypeText(type);
+}
+
+inline std::string OpcodeText(const Opcode& opcode) {
+  switch (opcode) {
+    CASE_RETURN_TEXT(Opcode::VENDOR);
+    CASE_RETURN_TEXT(Opcode::UNIT_INFO);
+    CASE_RETURN_TEXT(Opcode::SUBUNIT_INFO);
+    CASE_RETURN_TEXT(Opcode::PASS_THROUGH);
+    default:
+      return "Unknown Opcode: " + loghex((uint8_t)opcode);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Opcode& opcode) {
+  return os << OpcodeText(opcode);
+}
+
+inline std::string CommandPduText(const CommandPdu& pdu) {
+  switch (pdu) {
+    CASE_RETURN_TEXT(CommandPdu::GET_CAPABILITIES);
+    CASE_RETURN_TEXT(CommandPdu::LIST_APPLICATION_SETTING_ATTRIBUTES);
+    CASE_RETURN_TEXT(CommandPdu::GET_ELEMENT_ATTRIBUTES);
+    CASE_RETURN_TEXT(CommandPdu::GET_PLAY_STATUS);
+    CASE_RETURN_TEXT(CommandPdu::REGISTER_NOTIFICATION);
+    CASE_RETURN_TEXT(CommandPdu::SET_ABSOLUTE_VOLUME);
+    CASE_RETURN_TEXT(CommandPdu::SET_ADDRESSED_PLAYER);
+    CASE_RETURN_TEXT(CommandPdu::PLAY_ITEM);
+    default:
+      return "Unknown Command PDU: " + loghex((uint8_t)pdu);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const CommandPdu& pdu) {
+  return os << CommandPduText(pdu);
+}
+
+inline std::string PacketTypeText(const PacketType& type) {
+  switch (type) {
+    CASE_RETURN_TEXT(PacketType::SINGLE);
+    default:
+      return "Unknown Packet Type: " + loghex((uint8_t)type);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const PacketType& type) {
+  return os << PacketTypeText(type);
+}
+
+inline std::string CapabilityText(const Capability& cap) {
+  switch (cap) {
+    CASE_RETURN_TEXT(Capability::COMPANY_ID);
+    CASE_RETURN_TEXT(Capability::EVENTS_SUPPORTED);
+    default:
+      return "Unknown Capability: " + loghex((uint8_t)cap);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Capability& cap) {
+  return os << CapabilityText(cap);
+}
+
+inline std::string EventText(const Event& event) {
+  switch (event) {
+    CASE_RETURN_TEXT(Event::PLAYBACK_STATUS_CHANGED);
+    CASE_RETURN_TEXT(Event::TRACK_CHANGED);
+    CASE_RETURN_TEXT(Event::PLAYBACK_POS_CHANGED);
+    CASE_RETURN_TEXT(Event::PLAYER_APPLICATION_SETTING_CHANGED);
+    CASE_RETURN_TEXT(Event::NOW_PLAYING_CONTENT_CHANGED);
+    CASE_RETURN_TEXT(Event::AVAILABLE_PLAYERS_CHANGED);
+    CASE_RETURN_TEXT(Event::ADDRESSED_PLAYER_CHANGED);
+    CASE_RETURN_TEXT(Event::UIDS_CHANGED);
+    CASE_RETURN_TEXT(Event::VOLUME_CHANGED);
+    default:
+      return "Unknown Event: " + loghex((uint8_t)event);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Event& event) {
+  return os << EventText(event);
+}
+
+inline std::string AttributeText(const Attribute& attr) {
+  switch (attr) {
+    CASE_RETURN_TEXT(Attribute::TITLE);
+    CASE_RETURN_TEXT(Attribute::ARTIST_NAME);
+    CASE_RETURN_TEXT(Attribute::ALBUM_NAME);
+    CASE_RETURN_TEXT(Attribute::TRACK_NUMBER);
+    CASE_RETURN_TEXT(Attribute::TOTAL_NUMBER_OF_TRACKS);
+    CASE_RETURN_TEXT(Attribute::GENRE);
+    CASE_RETURN_TEXT(Attribute::PLAYING_TIME);
+    CASE_RETURN_TEXT(Attribute::DEFAULT_COVER_ART);
+    default:
+      return "Unknown Attribute Value: " + loghex((uint32_t)attr);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Attribute& attr) {
+  return os << AttributeText(attr);
+}
+
+inline std::string StatusText(const Status& status) {
+  switch (status) {
+    CASE_RETURN_TEXT(Status::INVALID_COMMAND);
+    CASE_RETURN_TEXT(Status::INVALID_PARAMETER);
+    CASE_RETURN_TEXT(Status::PARAMETER_CONTENT_ERROR);
+    CASE_RETURN_TEXT(Status::INTERNAL_ERROR);
+    CASE_RETURN_TEXT(Status::NO_ERROR);
+    CASE_RETURN_TEXT(Status::UIDS_CHANGED);
+    CASE_RETURN_TEXT(Status::RESERVED);
+    CASE_RETURN_TEXT(Status::INVALID_DIRECTION);
+    CASE_RETURN_TEXT(Status::NOT_A_DIRECTORY);
+    CASE_RETURN_TEXT(Status::DOES_NOT_EXIST);
+    CASE_RETURN_TEXT(Status::INVALID_SCOPE);
+    CASE_RETURN_TEXT(Status::RANGE_OUT_OF_BOUNDS);
+    CASE_RETURN_TEXT(Status::FOLDER_ITEM_NOT_PLAYABLE);
+    CASE_RETURN_TEXT(Status::MEDIA_IN_USE);
+    CASE_RETURN_TEXT(Status::NOW_PLAYING_LIST_FULL);
+    CASE_RETURN_TEXT(Status::SEARCH_NOT_SUPPORTED);
+    CASE_RETURN_TEXT(Status::SEARCH_IN_PROGRESS);
+    CASE_RETURN_TEXT(Status::INVALID_PLAYER_ID);
+    CASE_RETURN_TEXT(Status::PLAYER_NOT_BROWSABLE);
+    CASE_RETURN_TEXT(Status::PLAYER_NOT_ADDRESSED);
+    CASE_RETURN_TEXT(Status::NO_VALID_SEARCH_RESULTS);
+    CASE_RETURN_TEXT(Status::NO_AVAILABLE_PLAYERS);
+    CASE_RETURN_TEXT(Status::ADDRESSED_PLAYER_CHANGED);
+    default:
+      return "Unknown Status: " + loghex((uint8_t)status);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Status& status) {
+  return os << StatusText(status);
+}
+
+inline std::string BrowsePduText(const BrowsePdu& pdu) {
+  switch (pdu) {
+    CASE_RETURN_TEXT(BrowsePdu::SET_BROWSED_PLAYER);
+    CASE_RETURN_TEXT(BrowsePdu::GET_FOLDER_ITEMS);
+    CASE_RETURN_TEXT(BrowsePdu::CHANGE_PATH);
+    CASE_RETURN_TEXT(BrowsePdu::GET_ITEM_ATTRIBUTES);
+    default:
+      return "Unknown Browse PDU: " + loghex((uint8_t)pdu);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const BrowsePdu& pdu) {
+  return os << BrowsePduText(pdu);
+}
+
+inline std::string ScopeText(const Scope& scope) {
+  switch (scope) {
+    CASE_RETURN_TEXT(Scope::MEDIA_PLAYER_LIST);
+    CASE_RETURN_TEXT(Scope::VFS);
+    CASE_RETURN_TEXT(Scope::SEARCH);
+    CASE_RETURN_TEXT(Scope::NOW_PLAYING);
+    default:
+      return "Unknown Scope: " + loghex((uint8_t)scope);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Scope& pdu) {
+  return os << ScopeText(pdu);
+}
+
+inline std::string DirectionText(const Direction& dir) {
+  switch (dir) {
+    CASE_RETURN_TEXT(Direction::UP);
+    CASE_RETURN_TEXT(Direction::DOWN);
+    default:
+      return "Unknown Direction: " + loghex((uint8_t)dir);
+  }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Direction& dir) {
+  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/ble_advertiser.h b/include/hardware/ble_advertiser.h
new file mode 100644
index 0000000..6055d89
--- /dev/null
+++ b/include/hardware/ble_advertiser.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BLE_ADVERTISER_H
+#define ANDROID_INCLUDE_BLE_ADVERTISER_H
+
+#include <base/callback_forward.h>
+#include <stdint.h>
+#include <vector>
+#include "bt_common_types.h"
+#include "bt_gatt_types.h"
+
+struct AdvertiseParameters {
+  uint16_t advertising_event_properties;
+  uint32_t min_interval;
+  uint32_t max_interval;
+  uint8_t channel_map;
+  int8_t tx_power;
+  uint8_t primary_advertising_phy;
+  uint8_t secondary_advertising_phy;
+  uint8_t scan_request_notification_enable;
+};
+
+struct PeriodicAdvertisingParameters {
+  uint8_t enable;
+  uint16_t min_interval;
+  uint16_t max_interval;
+  uint16_t periodic_advertising_properties;
+};
+
+class BleAdvertiserInterface {
+ public:
+  virtual ~BleAdvertiserInterface() = default;
+
+  /** Callback invoked when multi-adv operation has completed */
+  using StatusCallback = base::Callback<void(uint8_t /* status */)>;
+  using IdStatusCallback =
+      base::Callback<void(uint8_t /* advertiser_id */, uint8_t /* status */)>;
+  using IdTxPowerStatusCallback =
+      base::Callback<void(uint8_t /* advertiser_id */, int8_t /* tx_power */,
+                          uint8_t /* status */)>;
+  using ParametersCallback =
+      base::Callback<void(uint8_t /* status */, int8_t /* tx_power */)>;
+
+  /** Registers an advertiser with the stack */
+  virtual void RegisterAdvertiser(IdStatusCallback) = 0;
+
+  using GetAddressCallback =
+      base::Callback<void(uint8_t /* address_type*/, RawAddress /*address*/)>;
+  virtual void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) = 0;
+
+  /* Set the parameters as per spec, user manual specified values */
+  virtual void SetParameters(uint8_t advertiser_id, AdvertiseParameters params,
+                             ParametersCallback cb) = 0;
+
+  /* Setup the data */
+  virtual void SetData(int advertiser_id, bool set_scan_rsp,
+                       std::vector<uint8_t> data, StatusCallback cb) = 0;
+
+  /* Enable the advertising instance */
+  virtual void Enable(uint8_t advertiser_id, bool enable, StatusCallback cb,
+                      uint16_t duration, uint8_t maxExtAdvEvents,
+                      StatusCallback timeout_cb) = 0;
+
+  /*  Unregisters an advertiser */
+  virtual void Unregister(uint8_t advertiser_id) = 0;
+
+  virtual void StartAdvertising(uint8_t advertiser_id, StatusCallback cb,
+                                AdvertiseParameters params,
+                                std::vector<uint8_t> advertise_data,
+                                std::vector<uint8_t> scan_response_data,
+                                int timeout_s, StatusCallback timeout_cb) = 0;
+
+  /** Start the advertising set. This include registering, setting all
+   * parameters and data, and enabling it. |register_cb| is called when the set
+   * is advertising. |timeout_cb| is called when the timeout_s have passed */
+  virtual void StartAdvertisingSet(
+      IdTxPowerStatusCallback register_cb, AdvertiseParameters params,
+      std::vector<uint8_t> advertise_data,
+      std::vector<uint8_t> scan_response_data,
+      PeriodicAdvertisingParameters periodic_params,
+      std::vector<uint8_t> periodic_data, uint16_t duration,
+      uint8_t maxExtAdvEvents, IdStatusCallback timeout_cb) = 0;
+
+  virtual void SetPeriodicAdvertisingParameters(
+      int advertiser_id, PeriodicAdvertisingParameters parameters,
+      StatusCallback cb) = 0;
+
+  virtual void SetPeriodicAdvertisingData(int advertiser_id,
+                                          std::vector<uint8_t> data,
+                                          StatusCallback cb) = 0;
+
+  virtual void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable,
+                                            StatusCallback cb) = 0;
+};
+
+#endif /* ANDROID_INCLUDE_BLE_ADVERTISER_H */
diff --git a/include/hardware/ble_scanner.h b/include/hardware/ble_scanner.h
new file mode 100644
index 0000000..efa9662
--- /dev/null
+++ b/include/hardware/ble_scanner.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BLE_SCANNER_H
+#define ANDROID_INCLUDE_BLE_SCANNER_H
+
+#include <stdint.h>
+#include <vector>
+#include "bt_common_types.h"
+#include "bt_gatt_client.h"
+#include "bt_gatt_types.h"
+
+/** Callback invoked when batchscan reports are obtained */
+typedef void (*batchscan_reports_callback)(int client_if, int status,
+                                           int report_format, int num_records,
+                                           std::vector<uint8_t> data);
+
+/** Callback invoked when batchscan storage threshold limit is crossed */
+typedef void (*batchscan_threshold_callback)(int client_if);
+
+/** Track ADV VSE callback invoked when tracked device is found or lost */
+typedef void (*track_adv_event_callback)(
+    btgatt_track_adv_info_t* p_track_adv_info);
+
+/** Callback for scan results */
+typedef void (*scan_result_callback)(uint16_t event_type, uint8_t addr_type,
+                                     RawAddress* bda, uint8_t primary_phy,
+                                     uint8_t secondary_phy,
+                                     uint8_t advertising_sid, int8_t tx_power,
+                                     int8_t rssi, uint16_t periodic_adv_int,
+                                     std::vector<uint8_t> adv_data);
+
+typedef struct {
+  scan_result_callback scan_result_cb;
+  batchscan_reports_callback batchscan_reports_cb;
+  batchscan_threshold_callback batchscan_threshold_cb;
+  track_adv_event_callback track_adv_event_cb;
+} btgatt_scanner_callbacks_t;
+
+class BleScannerInterface {
+ public:
+  virtual ~BleScannerInterface() = default;
+
+  using RegisterCallback =
+      base::Callback<void(uint8_t /* scanner_id */, uint8_t /* status */)>;
+
+  using Callback = base::Callback<void(uint8_t /* status */)>;
+
+  using EnableCallback =
+      base::Callback<void(uint8_t /* action */, uint8_t /* status */)>;
+
+  using FilterParamSetupCallback =
+      base::Callback<void(uint8_t /* avbl_space */, uint8_t /* action_type */,
+                          uint8_t /* status */)>;
+
+  using FilterConfigCallback =
+      base::Callback<void(uint8_t /* filt_type */, uint8_t /* avbl_space */,
+                          uint8_t /* action */, uint8_t /* status */)>;
+
+  /** Registers a scanner with the stack */
+  virtual void RegisterScanner(RegisterCallback) = 0;
+
+  /** Unregister a scanner from the stack */
+  virtual void Unregister(int scanner_id) = 0;
+
+  /** Start or stop LE device scanning */
+  virtual void Scan(bool start) = 0;
+
+  /** Setup scan filter params */
+  virtual void ScanFilterParamSetup(
+      uint8_t client_if, uint8_t action, uint8_t filt_index,
+      std::unique_ptr<btgatt_filt_param_setup_t> filt_param,
+      FilterParamSetupCallback cb) = 0;
+
+  /** Configure a scan filter condition  */
+  virtual void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
+                             FilterConfigCallback cb) = 0;
+
+  /** Clear all scan filter conditions for specific filter index*/
+  virtual void ScanFilterClear(int filt_index, FilterConfigCallback cb) = 0;
+
+  /** Enable / disable scan filter feature*/
+  virtual void ScanFilterEnable(bool enable, EnableCallback cb) = 0;
+
+  /** Sets the LE scan interval and window in units of N*0.625 msec */
+  virtual void SetScanParameters(int scan_interval, int scan_window,
+                                 Callback cb) = 0;
+
+  /* Configure the batchscan storage */
+  virtual void BatchscanConfigStorage(int client_if, int batch_scan_full_max,
+                                      int batch_scan_trunc_max,
+                                      int batch_scan_notify_threshold,
+                                      Callback cb) = 0;
+
+  /* Enable batchscan */
+  virtual void BatchscanEnable(int scan_mode, int scan_interval,
+                               int scan_window, int addr_type, int discard_rule,
+                               Callback cb) = 0;
+
+  /* Disable batchscan */
+  virtual void BatchscanDisable(Callback cb) = 0;
+
+  /* Read out batchscan reports */
+  virtual void BatchscanReadReports(int client_if, int scan_mode) = 0;
+
+  using StartSyncCb =
+      base::Callback<void(uint8_t status, uint16_t sync_handle,
+                          uint8_t advertising_sid, uint8_t address_type,
+                          RawAddress address, uint8_t phy, uint16_t interval)>;
+  using SyncReportCb =
+      base::Callback<void(uint16_t sync_handle, int8_t tx_power, int8_t rssi,
+                          uint8_t status, std::vector<uint8_t> data)>;
+  using SyncLostCb = base::Callback<void(uint16_t sync_handle)>;
+  virtual void StartSync(uint8_t sid, RawAddress address, uint16_t skip,
+                         uint16_t timeout, StartSyncCb start_cb,
+                         SyncReportCb report_cb, SyncLostCb lost_cb) = 0;
+  virtual void StopSync(uint16_t handle) = 0;
+};
+
+#endif /* ANDROID_INCLUDE_BLE_SCANNER_H */
\ No newline at end of file
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
new file mode 100644
index 0000000..36680bf
--- /dev/null
+++ b/include/hardware/bluetooth.h
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BLUETOOTH_H
+#define ANDROID_INCLUDE_BLUETOOTH_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "avrcp/avrcp.h"
+#include "bluetooth/uuid.h"
+#include "raw_address.h"
+
+/**
+ * The Bluetooth Hardware Module ID
+ */
+
+#define BT_HARDWARE_MODULE_ID "bluetooth"
+#define BT_STACK_MODULE_ID "bluetooth"
+
+/** Bluetooth profile interface IDs */
+#define BT_PROFILE_HANDSFREE_ID "handsfree"
+#define BT_PROFILE_HANDSFREE_CLIENT_ID "handsfree_client"
+#define BT_PROFILE_ADVANCED_AUDIO_ID "a2dp"
+#define BT_PROFILE_ADVANCED_AUDIO_SINK_ID "a2dp_sink"
+#define BT_PROFILE_HEALTH_ID "health"
+#define BT_PROFILE_SOCKETS_ID "socket"
+#define BT_PROFILE_HIDHOST_ID "hidhost"
+#define BT_PROFILE_HIDDEV_ID "hiddev"
+#define BT_PROFILE_PAN_ID "pan"
+#define BT_PROFILE_MAP_CLIENT_ID "map_client"
+#define BT_PROFILE_SDP_CLIENT_ID "sdp"
+#define BT_PROFILE_GATT_ID "gatt"
+#define BT_PROFILE_AV_RC_ID "avrcp"
+#define BT_PROFILE_AV_RC_CTRL_ID "avrcp_ctrl"
+#define BT_PROFILE_HEARING_AID_ID "hearing_aid"
+
+/** Bluetooth test interface IDs */
+#define BT_TEST_INTERFACE_MCAP_ID "mcap_test"
+
+/** Bluetooth Device Name */
+typedef struct { uint8_t name[249]; } __attribute__((packed)) bt_bdname_t;
+
+/** Bluetooth Adapter Visibility Modes*/
+typedef enum {
+  BT_SCAN_MODE_NONE,
+  BT_SCAN_MODE_CONNECTABLE,
+  BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
+} bt_scan_mode_t;
+
+/** Bluetooth Adapter State */
+typedef enum { BT_STATE_OFF, BT_STATE_ON } bt_state_t;
+
+/** Bluetooth Error Status */
+/** We need to build on this */
+
+typedef enum {
+  BT_STATUS_SUCCESS,
+  BT_STATUS_FAIL,
+  BT_STATUS_NOT_READY,
+  BT_STATUS_NOMEM,
+  BT_STATUS_BUSY,
+  BT_STATUS_DONE, /* request already completed */
+  BT_STATUS_UNSUPPORTED,
+  BT_STATUS_PARM_INVALID,
+  BT_STATUS_UNHANDLED,
+  BT_STATUS_AUTH_FAILURE,
+  BT_STATUS_RMT_DEV_DOWN,
+  BT_STATUS_AUTH_REJECTED,
+  BT_STATUS_JNI_ENVIRONMENT_ERROR,
+  BT_STATUS_JNI_THREAD_ATTACH_ERROR,
+  BT_STATUS_WAKELOCK_ERROR
+} bt_status_t;
+
+/** Bluetooth PinKey Code */
+typedef struct { uint8_t pin[16]; } __attribute__((packed)) bt_pin_code_t;
+
+typedef struct {
+  uint8_t status;
+  uint8_t ctrl_state;   /* stack reported state */
+  uint64_t tx_time;     /* in ms */
+  uint64_t rx_time;     /* in ms */
+  uint64_t idle_time;   /* in ms */
+  uint64_t energy_used; /* a product of mA, V and ms */
+} __attribute__((packed)) bt_activity_energy_info;
+
+typedef struct {
+  int32_t app_uid;
+  uint64_t tx_bytes;
+  uint64_t rx_bytes;
+} __attribute__((packed)) bt_uid_traffic_t;
+
+/** Bluetooth Adapter Discovery state */
+typedef enum {
+  BT_DISCOVERY_STOPPED,
+  BT_DISCOVERY_STARTED
+} bt_discovery_state_t;
+
+/** Bluetooth ACL connection state */
+typedef enum {
+  BT_ACL_STATE_CONNECTED,
+  BT_ACL_STATE_DISCONNECTED
+} bt_acl_state_t;
+
+/** Bluetooth SDP service record */
+typedef struct {
+  bluetooth::Uuid uuid;
+  uint16_t channel;
+  char name[256];  // what's the maximum length
+} bt_service_record_t;
+
+/** Bluetooth Remote Version info */
+typedef struct {
+  int version;
+  int sub_ver;
+  int manufacturer;
+} bt_remote_version_t;
+
+typedef struct {
+  uint16_t version_supported;
+  uint8_t local_privacy_enabled;
+  uint8_t max_adv_instance;
+  uint8_t rpa_offload_supported;
+  uint8_t max_irk_list_size;
+  uint8_t max_adv_filter_supported;
+  uint8_t activity_energy_info_supported;
+  uint16_t scan_result_storage_size;
+  uint16_t total_trackable_advertisers;
+  bool extended_scan_support;
+  bool debug_logging_supported;
+  bool le_2m_phy_supported;
+  bool le_coded_phy_supported;
+  bool le_extended_advertising_supported;
+  bool le_periodic_advertising_supported;
+  uint16_t le_maximum_advertising_data_length;
+} bt_local_le_features_t;
+
+/* Bluetooth Adapter and Remote Device property types */
+typedef enum {
+  /* Properties common to both adapter and remote device */
+  /**
+   * Description - Bluetooth Device Name
+   * Access mode - Adapter name can be GET/SET. Remote device can be GET
+   * Data type   - bt_bdname_t
+   */
+  BT_PROPERTY_BDNAME = 0x1,
+  /**
+   * Description - Bluetooth Device Address
+   * Access mode - Only GET.
+   * Data type   - RawAddress
+   */
+  BT_PROPERTY_BDADDR,
+  /**
+   * Description - Bluetooth Service 128-bit UUIDs
+   * Access mode - Only GET.
+   * Data type   - Array of bluetooth::Uuid (Array size inferred from property
+   *               length).
+   */
+  BT_PROPERTY_UUIDS,
+  /**
+   * Description - Bluetooth Class of Device as found in Assigned Numbers
+   * Access mode - Only GET.
+   * Data type   - uint32_t.
+   */
+  BT_PROPERTY_CLASS_OF_DEVICE,
+  /**
+   * Description - Device Type - BREDR, BLE or DUAL Mode
+   * Access mode - Only GET.
+   * Data type   - bt_device_type_t
+   */
+  BT_PROPERTY_TYPE_OF_DEVICE,
+  /**
+   * Description - Bluetooth Service Record
+   * Access mode - Only GET.
+   * Data type   - bt_service_record_t
+   */
+  BT_PROPERTY_SERVICE_RECORD,
+
+  /* Properties unique to adapter */
+  /**
+   * Description - Bluetooth Adapter scan mode
+   * Access mode - GET and SET
+   * Data type   - bt_scan_mode_t.
+   */
+  BT_PROPERTY_ADAPTER_SCAN_MODE,
+  /**
+   * Description - List of bonded devices
+   * Access mode - Only GET.
+   * Data type   - Array of RawAddress of the bonded remote devices
+   *               (Array size inferred from property length).
+   */
+  BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+  /**
+   * Description - Bluetooth Adapter Discovery timeout (in seconds)
+   * Access mode - GET and SET
+   * Data type   - uint32_t
+   */
+  BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+
+  /* Properties unique to remote device */
+  /**
+   * Description - User defined friendly name of the remote device
+   * Access mode - GET and SET
+   * Data type   - bt_bdname_t.
+   */
+  BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+  /**
+   * Description - RSSI value of the inquired remote device
+   * Access mode - Only GET.
+   * Data type   - int8_t.
+   */
+  BT_PROPERTY_REMOTE_RSSI,
+  /**
+   * Description - Remote version info
+   * Access mode - SET/GET.
+   * Data type   - bt_remote_version_t.
+   */
+
+  BT_PROPERTY_REMOTE_VERSION_INFO,
+
+  /**
+   * Description - Local LE features
+   * Access mode - GET.
+   * Data type   - bt_local_le_features_t.
+   */
+  BT_PROPERTY_LOCAL_LE_FEATURES,
+
+  BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
+} bt_property_type_t;
+
+/** Bluetooth Adapter Property data structure */
+typedef struct {
+  bt_property_type_t type;
+  int len;
+  void* val;
+} bt_property_t;
+
+/** Bluetooth Out Of Band data for bonding */
+typedef struct {
+  uint8_t le_bt_dev_addr[7]; /* LE Bluetooth Device Address */
+  uint8_t c192[16];          /* Simple Pairing Hash C-192 */
+  uint8_t r192[16];          /* Simple Pairing Randomizer R-192 */
+  uint8_t c256[16];          /* Simple Pairing Hash C-256 */
+  uint8_t r256[16];          /* Simple Pairing Randomizer R-256 */
+  uint8_t sm_tk[16];         /* Security Manager TK Value */
+  uint8_t le_sc_c[16];       /* LE Secure Connections Confirmation Value */
+  uint8_t le_sc_r[16];       /* LE Secure Connections Random Value */
+} bt_out_of_band_data_t;
+
+/** Bluetooth Device Type */
+typedef enum {
+  BT_DEVICE_DEVTYPE_BREDR = 0x1,
+  BT_DEVICE_DEVTYPE_BLE,
+  BT_DEVICE_DEVTYPE_DUAL
+} bt_device_type_t;
+/** Bluetooth Bond state */
+typedef enum {
+  BT_BOND_STATE_NONE,
+  BT_BOND_STATE_BONDING,
+  BT_BOND_STATE_BONDED
+} bt_bond_state_t;
+
+/** Bluetooth SSP Bonding Variant */
+typedef enum {
+  BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
+  BT_SSP_VARIANT_PASSKEY_ENTRY,
+  BT_SSP_VARIANT_CONSENT,
+  BT_SSP_VARIANT_PASSKEY_NOTIFICATION
+} bt_ssp_variant_t;
+
+#define BT_MAX_NUM_UUIDS 32
+
+/** Bluetooth Interface callbacks */
+
+/** Bluetooth Enable/Disable Callback. */
+typedef void (*adapter_state_changed_callback)(bt_state_t state);
+
+/** GET/SET Adapter Properties callback */
+/* TODO: For the GET/SET property APIs/callbacks, we may need a session
+ * identifier to associate the call with the callback. This would be needed
+ * whenever more than one simultaneous instance of the same adapter_type
+ * is get/set.
+ *
+ * If this is going to be handled in the Java framework, then we do not need
+ * to manage sessions here.
+ */
+typedef void (*adapter_properties_callback)(bt_status_t status,
+                                            int num_properties,
+                                            bt_property_t* properties);
+
+/** GET/SET Remote Device Properties callback */
+/** TODO: For remote device properties, do not see a need to get/set
+ * multiple properties - num_properties shall be 1
+ */
+typedef void (*remote_device_properties_callback)(bt_status_t status,
+                                                  RawAddress* bd_addr,
+                                                  int num_properties,
+                                                  bt_property_t* properties);
+
+/** New device discovered callback */
+/** If EIR data is not present, then BD_NAME and RSSI shall be NULL and -1
+ * respectively */
+typedef void (*device_found_callback)(int num_properties,
+                                      bt_property_t* properties);
+
+/** Discovery state changed callback */
+typedef void (*discovery_state_changed_callback)(bt_discovery_state_t state);
+
+/** Bluetooth Legacy PinKey Request callback */
+typedef void (*pin_request_callback)(RawAddress* remote_bd_addr,
+                                     bt_bdname_t* bd_name, uint32_t cod,
+                                     bool min_16_digit);
+
+/** Bluetooth SSP Request callback - Just Works & Numeric Comparison*/
+/** pass_key - Shall be 0 for BT_SSP_PAIRING_VARIANT_CONSENT &
+ *  BT_SSP_PAIRING_PASSKEY_ENTRY */
+/* TODO: Passkey request callback shall not be needed for devices with display
+ * capability. We still need support this in the stack for completeness */
+typedef void (*ssp_request_callback)(RawAddress* remote_bd_addr,
+                                     bt_bdname_t* bd_name, uint32_t cod,
+                                     bt_ssp_variant_t pairing_variant,
+                                     uint32_t pass_key);
+
+/** Bluetooth Bond state changed callback */
+/* Invoked in response to create_bond, cancel_bond or remove_bond */
+typedef void (*bond_state_changed_callback)(bt_status_t status,
+                                            RawAddress* remote_bd_addr,
+                                            bt_bond_state_t state);
+
+/** Bluetooth ACL connection state changed callback */
+typedef void (*acl_state_changed_callback)(bt_status_t status,
+                                           RawAddress* remote_bd_addr,
+                                           bt_acl_state_t state);
+
+typedef enum { ASSOCIATE_JVM, DISASSOCIATE_JVM } bt_cb_thread_evt;
+
+/** Thread Associate/Disassociate JVM Callback */
+/* Callback that is invoked by the callback thread to allow upper layer to
+ * attach/detach to/from the JVM */
+typedef void (*callback_thread_event)(bt_cb_thread_evt evt);
+
+/** Bluetooth Test Mode Callback */
+/* Receive any HCI event from controller. Must be in DUT Mode for this callback
+ * to be received */
+typedef void (*dut_mode_recv_callback)(uint16_t opcode, uint8_t* buf,
+                                       uint8_t len);
+
+/* LE Test mode callbacks
+ * This callback shall be invoked whenever the le_tx_test, le_rx_test or
+ * le_test_end is invoked The num_packets is valid only for le_test_end command
+ */
+typedef void (*le_test_mode_callback)(bt_status_t status, uint16_t num_packets);
+
+/** Callback invoked when energy details are obtained */
+/* Ctrl_state-Current controller state-Active-1,scan-2,or idle-3 state as
+ * defined by HCI spec. If the ctrl_state value is 0, it means the API call
+ * failed Time values-In milliseconds as returned by the controller Energy
+ * used-Value as returned by the controller Status-Provides the status of the
+ * read_energy_info API call uid_data provides an array of bt_uid_traffic_t,
+ * where the array is terminated by an element with app_uid set to -1.
+ */
+typedef void (*energy_info_callback)(bt_activity_energy_info* energy_info,
+                                     bt_uid_traffic_t* uid_data);
+
+/** TODO: Add callbacks for Link Up/Down and other generic
+ *  notifications/callbacks */
+
+/** Bluetooth DM callback structure. */
+typedef struct {
+  /** set to sizeof(bt_callbacks_t) */
+  size_t size;
+  adapter_state_changed_callback adapter_state_changed_cb;
+  adapter_properties_callback adapter_properties_cb;
+  remote_device_properties_callback remote_device_properties_cb;
+  device_found_callback device_found_cb;
+  discovery_state_changed_callback discovery_state_changed_cb;
+  pin_request_callback pin_request_cb;
+  ssp_request_callback ssp_request_cb;
+  bond_state_changed_callback bond_state_changed_cb;
+  acl_state_changed_callback acl_state_changed_cb;
+  callback_thread_event thread_evt_cb;
+  dut_mode_recv_callback dut_mode_recv_cb;
+  le_test_mode_callback le_test_mode_cb;
+  energy_info_callback energy_info_cb;
+} bt_callbacks_t;
+
+typedef void (*alarm_cb)(void* data);
+typedef bool (*set_wake_alarm_callout)(uint64_t delay_millis, bool should_wake,
+                                       alarm_cb cb, void* data);
+typedef int (*acquire_wake_lock_callout)(const char* lock_name);
+typedef int (*release_wake_lock_callout)(const char* lock_name);
+
+/** The set of functions required by bluedroid to set wake alarms and
+ * grab wake locks. This struct is passed into the stack through the
+ * |set_os_callouts| function on |bt_interface_t|.
+ */
+typedef struct {
+  /* set to sizeof(bt_os_callouts_t) */
+  size_t size;
+
+  set_wake_alarm_callout set_wake_alarm;
+  acquire_wake_lock_callout acquire_wake_lock;
+  release_wake_lock_callout release_wake_lock;
+} bt_os_callouts_t;
+
+/** NOTE: By default, no profiles are initialized at the time of init/enable.
+ *  Whenever the application invokes the 'init' API of a profile, then one of
+ *  the following shall occur:
+ *
+ *    1.) If Bluetooth is not enabled, then the Bluetooth core shall mark the
+ *        profile as enabled. Subsequently, when the application invokes the
+ *        Bluetooth 'enable', as part of the enable sequence the profile that
+ * were marked shall be enabled by calling appropriate stack APIs. The
+ *        'adapter_properties_cb' shall return the list of UUIDs of the
+ *        enabled profiles.
+ *
+ *    2.) If Bluetooth is enabled, then the Bluetooth core shall invoke the
+ * stack profile API to initialize the profile and trigger a
+ *        'adapter_properties_cb' with the current list of UUIDs including the
+ *        newly added profile's UUID.
+ *
+ *   The reverse shall occur whenever the profile 'cleanup' APIs are invoked
+ */
+
+/** Represents the standard Bluetooth DM interface. */
+typedef struct {
+  /** set to sizeof(bt_interface_t) */
+  size_t size;
+  /**
+   * Opens the interface and provides the callback routines
+   * to the implemenation of this interface.
+   */
+  int (*init)(bt_callbacks_t* callbacks);
+
+  /** Enable Bluetooth. */
+  int (*enable)(bool guest_mode);
+
+  /** Disable Bluetooth. */
+  int (*disable)(void);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+
+  /** Get all Bluetooth Adapter properties at init */
+  int (*get_adapter_properties)(void);
+
+  /** Get Bluetooth Adapter property of 'type' */
+  int (*get_adapter_property)(bt_property_type_t type);
+
+  /** Set Bluetooth Adapter property of 'type' */
+  /* Based on the type, val shall be one of
+   * RawAddress or bt_bdname_t or bt_scanmode_t etc
+   */
+  int (*set_adapter_property)(const bt_property_t* property);
+
+  /** Get all Remote Device properties */
+  int (*get_remote_device_properties)(RawAddress* remote_addr);
+
+  /** Get Remote Device property of 'type' */
+  int (*get_remote_device_property)(RawAddress* remote_addr,
+                                    bt_property_type_t type);
+
+  /** Set Remote Device property of 'type' */
+  int (*set_remote_device_property)(RawAddress* remote_addr,
+                                    const bt_property_t* property);
+
+  /** Get Remote Device's service record  for the given UUID */
+  int (*get_remote_service_record)(const RawAddress& remote_addr,
+                                   const bluetooth::Uuid& uuid);
+
+  /** Start SDP to get remote services */
+  int (*get_remote_services)(RawAddress* remote_addr);
+
+  /** Start Discovery */
+  int (*start_discovery)(void);
+
+  /** Cancel Discovery */
+  int (*cancel_discovery)(void);
+
+  /** Create Bluetooth Bonding */
+  int (*create_bond)(const RawAddress* bd_addr, int transport);
+
+  /** Create Bluetooth Bond using out of band data */
+  int (*create_bond_out_of_band)(const RawAddress* bd_addr, int transport,
+                                 const bt_out_of_band_data_t* oob_data);
+
+  /** Remove Bond */
+  int (*remove_bond)(const RawAddress* bd_addr);
+
+  /** Cancel Bond */
+  int (*cancel_bond)(const RawAddress* bd_addr);
+
+  /**
+   * Get the connection status for a given remote device.
+   * return value of 0 means the device is not connected,
+   * non-zero return status indicates an active connection.
+   */
+  int (*get_connection_state)(const RawAddress* bd_addr);
+
+  /** BT Legacy PinKey Reply */
+  /** If accept==FALSE, then pin_len and pin_code shall be 0x0 */
+  int (*pin_reply)(const RawAddress* bd_addr, uint8_t accept, uint8_t pin_len,
+                   bt_pin_code_t* pin_code);
+
+  /** BT SSP Reply - Just Works, Numeric Comparison and Passkey
+   * passkey shall be zero for BT_SSP_VARIANT_PASSKEY_COMPARISON &
+   * BT_SSP_VARIANT_CONSENT
+   * For BT_SSP_VARIANT_PASSKEY_ENTRY, if accept==FALSE, then passkey
+   * shall be zero */
+  int (*ssp_reply)(const RawAddress* bd_addr, bt_ssp_variant_t variant,
+                   uint8_t accept, uint32_t passkey);
+
+  /** Get Bluetooth profile interface */
+  const void* (*get_profile_interface)(const char* profile_id);
+
+  /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */
+  /* Configure DUT Mode - Use this mode to enter/exit DUT mode */
+  int (*dut_mode_configure)(uint8_t enable);
+
+  /* Send any test HCI (vendor-specific) command to the controller. Must be in
+   * DUT Mode */
+  int (*dut_mode_send)(uint16_t opcode, uint8_t* buf, uint8_t len);
+  /** BLE Test Mode APIs */
+  /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End
+   */
+  int (*le_test_mode)(uint16_t opcode, uint8_t* buf, uint8_t len);
+
+  /** Sets the OS call-out functions that bluedroid needs for alarms and wake
+   * locks. This should be called immediately after a successful |init|.
+   */
+  int (*set_os_callouts)(bt_os_callouts_t* callouts);
+
+  /** Read Energy info details - return value indicates BT_STATUS_SUCCESS or
+   * BT_STATUS_NOT_READY Success indicates that the VSC command was sent to
+   * controller
+   */
+  int (*read_energy_info)();
+
+  /**
+   * Native support for dumpsys function
+   * Function is synchronous and |fd| is owned by caller.
+   * |arguments| are arguments which may affect the output, encoded as
+   * UTF-8 strings.
+   */
+  void (*dump)(int fd, const char** arguments);
+
+  /**
+   * Native support for metrics protobuf dumping. The dumping format will be
+   * raw byte array
+   *
+   * @param output an externally allocated string to dump serialized protobuf
+   */
+  void (*dumpMetrics)(std::string* output);
+
+  /**
+   * Clear /data/misc/bt_config.conf and erase all stored connections
+   */
+  int (*config_clear)(void);
+
+  /**
+   * Clear (reset) the dynamic portion of the device interoperability database.
+   */
+  void (*interop_database_clear)(void);
+
+  /**
+   * Add a new device interoperability workaround for a remote device whose
+   * first |len| bytes of the its device address match |addr|.
+   * NOTE: |feature| has to match an item defined in interop_feature_t
+   * (interop.h).
+   */
+  void (*interop_database_add)(uint16_t feature, const RawAddress* addr,
+                               size_t len);
+
+  /**
+   * Get the AvrcpTarget Service interface to interact with the Avrcp Service
+   */
+  bluetooth::avrcp::ServiceInterface* (*get_avrcp_service)(void);
+} bt_interface_t;
+
+#define BLUETOOTH_INTERFACE_STRING "bluetoothInterface"
+
+#endif /* ANDROID_INCLUDE_BLUETOOTH_H */
diff --git a/include/hardware/bluetooth_headset_callbacks.h b/include/hardware/bluetooth_headset_callbacks.h
new file mode 100644
index 0000000..e115a15
--- /dev/null
+++ b/include/hardware/bluetooth_headset_callbacks.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2017 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_hf.h"
+
+namespace bluetooth {
+namespace headset {
+
+/**
+ * Headset related callbacks invoked from from the Bluetooth native stack
+ * All callbacks are invoked on the JNI thread
+ */
+class Callbacks {
+ public:
+  virtual ~Callbacks() = default;
+  /**
+   * Callback for connection state change.
+   *
+   * @param state one of the values from bthf_connection_state_t
+   * @param bd_addr remote device address
+   */
+  virtual void ConnectionStateCallback(bthf_connection_state_t state,
+                                       RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for audio connection state change.
+   *
+   * @param state one of the values from bthf_audio_state_t
+   * @param bd_addr remote device address
+   */
+  virtual void AudioStateCallback(bthf_audio_state_t state,
+                                  RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for VR connection state change.
+   *
+   * @param state one of the values from bthf_vr_state_t
+   * @param bd_addr
+   */
+  virtual void VoiceRecognitionCallback(bthf_vr_state_t state,
+                                        RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for answer incoming call (ATA)
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void AnswerCallCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for disconnect call (AT+CHUP)
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void HangupCallCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for disconnect call (AT+CHUP)
+   *
+   * @param type denote Speaker/Mic gain bthf_volume_type_t
+   * @param volume volume value 0 to 15, p69, HFP 1.7.1 spec
+   * @param bd_addr remote device address
+   */
+  virtual void VolumeControlCallback(bthf_volume_type_t type, int volume,
+                                     RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for dialing an outgoing call
+   *
+   * @param number intended phone number, if number is NULL, redial
+   * @param bd_addr remote device address
+   */
+  virtual void DialCallCallback(char* number, RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for sending DTMF tones
+   *
+   * @param tone contains the dtmf character to be sent
+   * @param bd_addr remote device address
+   */
+  virtual void DtmfCmdCallback(char tone, RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for enabling/disabling noise reduction/echo cancellation
+   *
+   * @param nrec 1 to enable, 0 to disable
+   * @param bd_addr remote device address
+   */
+  virtual void NoiseReductionCallback(bthf_nrec_t nrec,
+                                      RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for AT+BCS and event from BAC
+   *
+   * @param wbs WBS enable, WBS disable
+   * @param bd_addr remote device address
+   */
+  virtual void WbsCallback(bthf_wbs_config_t wbs, RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for call hold handling (AT+CHLD)
+   *
+   * @param chld the call hold command (0, 1, 2, 3)
+   * @param bd_addr remote device address
+   */
+  virtual void AtChldCallback(bthf_chld_type_t chld, RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for CNUM (subscriber number)
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void AtCnumCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for indicators (CIND)
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void AtCindCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for operator selection (COPS)
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void AtCopsCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for call list (AT+CLCC)
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void AtClccCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for unknown AT command recd from HF
+   *
+   * @param at_string he unparsed AT string
+   * @param bd_addr remote device address
+   */
+  virtual void UnknownAtCallback(char* at_string, RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for keypressed (HSP) event.
+   *
+   * @param bd_addr remote device address
+   */
+  virtual void KeyPressedCallback(RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for BIND. Pass the remote HF Indicators supported.
+   *
+   * @param at_string unparsed AT command string
+   * @param bd_addr remote device address
+   */
+  virtual void AtBindCallback(char* at_string, RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for BIEV. Pass the change in the Remote HF indicator values
+   *
+   * @param ind_id HF indicator id
+   * @param ind_value HF indicator value
+   * @param bd_addr remote device address
+   */
+  virtual void AtBievCallback(bthf_hf_ind_type_t ind_id, int ind_value,
+                              RawAddress* bd_addr) = 0;
+
+  /**
+   * Callback for BIA. Pass the change in AG indicator activation.
+   * NOTE: Call, Call Setup and Call Held indicators are mandatory and cannot
+   *       be disabled. Thus, they are not included here.
+   *
+   * @param service whether HF should receive network service state update
+   * @param roam whether HF should receive roaming state update
+   * @param signal whether HF should receive signal strength update
+   * @param battery whether HF should receive AG battery level update
+   * @param bd_addr remote HF device address
+   */
+  virtual void AtBiaCallback(bool service, bool roam, bool signal, bool battery,
+                             RawAddress* bd_addr) = 0;
+};
+
+}  // namespace headset
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/include/hardware/bluetooth_headset_interface.h b/include/hardware/bluetooth_headset_interface.h
new file mode 100644
index 0000000..a3e0e37
--- /dev/null
+++ b/include/hardware/bluetooth_headset_interface.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2017 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 "bluetooth_headset_callbacks.h"
+#include "bt_hf.h"
+
+namespace bluetooth {
+namespace headset {
+
+/**
+ * Programming interface for Headset profiles in the Fluoride stack
+ * Thread-safe
+ */
+class Interface {
+ public:
+  virtual ~Interface() = default;
+  /**
+   * Register the BtHf callbacks
+   *
+   * @param callbacks callbacks for the user of the native stack
+   * @param max_hf_clients maximum number of headset clients
+   * @param inband_ringing_enabled whether inband ringtone is enabled
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t Init(Callbacks* callbacks, int max_hf_clients,
+                           bool inband_ringing_enabled) = 0;
+
+  /**
+   * Connect to headset
+   *
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t Connect(RawAddress* bd_addr) = 0;
+
+  /**
+   * Disconnect from headset
+   *
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t Disconnect(RawAddress* bd_addr) = 0;
+
+  /**
+   * Create an audio connection
+   *
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t ConnectAudio(RawAddress* bd_addr) = 0;
+
+  /**
+   * Close the audio connection
+   *
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t DisconnectAudio(RawAddress* bd_addr) = 0;
+
+  /** start voice recognition */
+  /**
+   * Start voice recognition
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t StartVoiceRecognition(RawAddress* bd_addr) = 0;
+
+  /**
+   * Stop voice recognition
+   *
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t StopVoiceRecognition(RawAddress* bd_addr) = 0;
+
+  /**
+   * Change HFP related volume on remote headset
+   *
+   * @param type Speaker (+VGS) or Mic (+VGM)
+   * @param volume volume level on scale from 0 to 15, p69, HFP 1.7.1 spec
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t VolumeControl(bthf_volume_type_t type, int volume,
+                                    RawAddress* bd_addr) = 0;
+
+  /**
+   * Combined device status change notification
+   *
+   * @param ntk_state Network state, available or not available
+   * @param svc_type Service type, roaming or home
+   * @param signal Signal strength, 0 to 5, p86, HFP 1.7.1 spec
+   * @param batt_chg Battery level of the phone, 0 to 5, p87, HFP 1.7.1 spec
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t DeviceStatusNotification(bthf_network_state_t ntk_state,
+                                               bthf_service_type_t svc_type,
+                                               int signal, int batt_chg,
+                                               RawAddress* bd_addr) = 0;
+
+  /**
+   * Response for COPS (Query Operator Selection) command
+   *
+   * @param cops Operator Name, max length 16 char, p32 HFP 1.7.1 spec
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t CopsResponse(const char* cops, RawAddress* bd_addr) = 0;
+
+  /**
+   * Response for CIND (Stanford Indicator Update) command
+   *
+   * @param svc service availability, available or not available
+   * @param num_active number of active calls
+   * @param num_held number of held calls
+   * @param call_setup_state call setup state
+   * @param signal signal strength, 0 to 5, p86 HFP 1.7.1 spec
+   * @param roam roaming state, 1 for roaming, 0 for home, p86 HFP 1.7.1 spec
+   * @param batt_chg AG battery charge, 0 to 5, p87 HFP 1.7.1 spec
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t CindResponse(int svc, int num_active, int num_held,
+                                   bthf_call_state_t call_setup_state,
+                                   int signal, int roam, int batt_chg,
+                                   RawAddress* bd_addr) = 0;
+
+  /**
+   * Pre-formatted AT response, typically in response to unknown AT cmd
+   *
+   * @param rsp formatted AT response
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t FormattedAtResponse(const char* rsp,
+                                          RawAddress* bd_addr) = 0;
+
+  /**
+   * ok/error response to AT commands
+   *
+   * @param response_code OK or ERROR
+   * @param error_code actual error code depend on use case
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t AtResponse(bthf_at_response_t response_code,
+                                 int error_code, RawAddress* bd_addr) = 0;
+
+  /**
+   * Response for CLCC (Current List of Calls) command.
+   * Can be iteratively called for each call index
+   * Call index of 0 will be treated as NULL termination (Completes response)
+   *
+   * @param index index of the call
+   * @param dir direction of the call
+   * @param state state of the call
+   * @param mode mode of the call
+   * @param mpty whether the call is multi party
+   * @param number phone number of the call
+   * @param type type of the call
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t ClccResponse(
+      int index, bthf_call_direction_t dir, bthf_call_state_t state,
+      bthf_call_mode_t mode, bthf_call_mpty_type_t mpty, const char* number,
+      bthf_call_addrtype_t type, RawAddress* bd_addr) = 0;
+
+  /**
+   * Notify of a call state change
+   *  Each update notifies
+   *    1. Number of active/held/ringing calls
+   *    2. call_state: This denotes the state change that triggered this msg
+   *                   This will take one of the values from BtHfCallState
+   *    3. number & type: valid only for incoming & waiting call
+   *
+   * @param num_active number of active calls
+   * @param num_held number of held calls
+   * @param call_setup_state current call setup state
+   * @param number phone number of the call
+   * @param type type of the call
+   * @param bd_addr remote device address
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t PhoneStateChange(int num_active, int num_held,
+                                       bthf_call_state_t call_setup_state,
+                                       const char* number,
+                                       bthf_call_addrtype_t type,
+                                       RawAddress* bd_addr) = 0;
+
+  /**
+   * Closes the interface.
+   */
+  virtual void Cleanup() = 0;
+
+  /**
+   * Whether we are allowed to initiate SCO
+   *
+   * @param value true to allow, false to disallow
+   * @return BT_STATUS_SUCCESS on success
+   */
+  virtual bt_status_t SetScoAllowed(bool value) = 0;
+
+  /**
+   * Send +BSIR response code to enable/disable in-band ringtone in an active
+   * HFP service level connection
+   *
+   * @param value true for enabled, false for disable
+   * @param bd_addr remote device address
+   */
+  virtual bt_status_t SendBsir(bool value, RawAddress* bd_addr) = 0;
+
+  /**
+   * Set the current active headset device for SCO audio
+   *
+   * @param active_device_addr remote device address
+   */
+  virtual bt_status_t SetActiveDevice(RawAddress* active_device_addr) = 0;
+};
+
+}  // namespace headset
+}  // namespace bluetooth
diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h
new file mode 100644
index 0000000..bdb1285
--- /dev/null
+++ b/include/hardware/bt_av.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_AV_H
+#define ANDROID_INCLUDE_BT_AV_H
+
+#include <vector>
+
+#include <hardware/bluetooth.h>
+
+__BEGIN_DECLS
+
+/* Bluetooth AV connection states */
+typedef enum {
+  BTAV_CONNECTION_STATE_DISCONNECTED = 0,
+  BTAV_CONNECTION_STATE_CONNECTING,
+  BTAV_CONNECTION_STATE_CONNECTED,
+  BTAV_CONNECTION_STATE_DISCONNECTING
+} btav_connection_state_t;
+
+/* Bluetooth AV datapath states */
+typedef enum {
+  BTAV_AUDIO_STATE_REMOTE_SUSPEND = 0,
+  BTAV_AUDIO_STATE_STOPPED,
+  BTAV_AUDIO_STATE_STARTED,
+} btav_audio_state_t;
+
+/*
+ * Enum values for each A2DP supported codec.
+ * There should be a separate entry for each A2DP codec that is supported
+ * for encoding (SRC), and for decoding purpose (SINK).
+ */
+typedef enum {
+  BTAV_A2DP_CODEC_INDEX_SOURCE_MIN = 0,
+
+  // Add an entry for each source codec here.
+  // NOTE: The values should be same as those listed in the following file:
+  //   BluetoothCodecConfig.java
+  BTAV_A2DP_CODEC_INDEX_SOURCE_SBC = 0,
+  BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
+  BTAV_A2DP_CODEC_INDEX_SOURCE_APTX,
+  BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
+  BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC,
+
+  BTAV_A2DP_CODEC_INDEX_SOURCE_MAX,
+
+  BTAV_A2DP_CODEC_INDEX_SINK_MIN = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX,
+
+  // Add an entry for each sink codec here
+  BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
+  BTAV_A2DP_CODEC_INDEX_SINK_AAC,
+
+  BTAV_A2DP_CODEC_INDEX_SINK_MAX,
+
+  BTAV_A2DP_CODEC_INDEX_MIN = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN,
+  BTAV_A2DP_CODEC_INDEX_MAX = BTAV_A2DP_CODEC_INDEX_SINK_MAX
+} btav_a2dp_codec_index_t;
+
+typedef enum {
+  // Disable the codec.
+  // NOTE: This value can be used only during initialization when
+  // function btav_source_interface_t::init() is called.
+  BTAV_A2DP_CODEC_PRIORITY_DISABLED = -1,
+
+  // Reset the codec priority to its default value.
+  BTAV_A2DP_CODEC_PRIORITY_DEFAULT = 0,
+
+  // Highest codec priority.
+  BTAV_A2DP_CODEC_PRIORITY_HIGHEST = 1000 * 1000
+} btav_a2dp_codec_priority_t;
+
+typedef enum {
+  BTAV_A2DP_CODEC_SAMPLE_RATE_NONE = 0x0,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_44100 = 0x1 << 0,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_48000 = 0x1 << 1,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_88200 = 0x1 << 2,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_96000 = 0x1 << 3,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_176400 = 0x1 << 4,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_192000 = 0x1 << 5,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_16000 = 0x1 << 6,
+  BTAV_A2DP_CODEC_SAMPLE_RATE_24000 = 0x1 << 7
+} btav_a2dp_codec_sample_rate_t;
+
+typedef enum {
+  BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE = 0x0,
+  BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 = 0x1 << 0,
+  BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 = 0x1 << 1,
+  BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32 = 0x1 << 2
+} btav_a2dp_codec_bits_per_sample_t;
+
+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_t;
+
+/*
+ * Structure for representing codec capability or configuration.
+ * It is used for configuring A2DP codec preference, and for reporting back
+ * current configuration or codec capability.
+ * For codec capability, fields "sample_rate", "bits_per_sample" and
+ * "channel_mode" can contain bit-masks with all supported features.
+ */
+typedef struct {
+  btav_a2dp_codec_index_t codec_type;
+  btav_a2dp_codec_priority_t
+      codec_priority;  // Codec selection priority
+                       // relative to other codecs: larger value
+                       // means higher priority. If 0, reset to
+                       // default.
+  btav_a2dp_codec_sample_rate_t sample_rate;
+  btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+  btav_a2dp_codec_channel_mode_t channel_mode;
+  int64_t codec_specific_1;  // Codec-specific value 1
+  int64_t codec_specific_2;  // Codec-specific value 2
+  int64_t codec_specific_3;  // Codec-specific value 3
+  int64_t codec_specific_4;  // Codec-specific value 4
+
+  std::string ToString() const {
+    std::string codec_name_str;
+
+    switch (codec_type) {
+      case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+        codec_name_str = "SBC";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+        codec_name_str = "AAC";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+        codec_name_str = "aptX";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+        codec_name_str = "aptX HD";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+        codec_name_str = "LDAC";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+        codec_name_str = "SBC (Sink)";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+        codec_name_str = "AAC (Sink)";
+        break;
+      case BTAV_A2DP_CODEC_INDEX_MAX:
+        codec_name_str = "Unknown(CODEC_INDEX_MAX)";
+        break;
+    }
+
+    std::string sample_rate_str;
+    AppendCapability(sample_rate_str,
+                     (sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE), "NONE");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_44100),
+                     "44100");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_48000),
+                     "48000");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_88200),
+                     "88200");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_96000),
+                     "96000");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_176400),
+                     "176400");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_192000),
+                     "192000");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_16000),
+                     "16000");
+    AppendCapability(sample_rate_str,
+                     (sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_24000),
+                     "24000");
+
+    std::string bits_per_sample_str;
+    AppendCapability(bits_per_sample_str,
+                     (bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE),
+                     "NONE");
+    AppendCapability(bits_per_sample_str,
+                     (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16),
+                     "16");
+    AppendCapability(bits_per_sample_str,
+                     (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24),
+                     "24");
+    AppendCapability(bits_per_sample_str,
+                     (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32),
+                     "32");
+
+    std::string channel_mode_str;
+    AppendCapability(channel_mode_str,
+                     (channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE),
+                     "NONE");
+    AppendCapability(channel_mode_str,
+                     (channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_MONO),
+                     "MONO");
+    AppendCapability(channel_mode_str,
+                     (channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO),
+                     "STEREO");
+
+    return "codec: " + codec_name_str +
+           " priority: " + std::to_string(codec_priority) +
+           " sample_rate: " + sample_rate_str +
+           " bits_per_sample: " + bits_per_sample_str +
+           " channel_mode: " + channel_mode_str +
+           " codec_specific_1: " + std::to_string(codec_specific_1) +
+           " codec_specific_2: " + std::to_string(codec_specific_2) +
+           " codec_specific_3: " + std::to_string(codec_specific_3) +
+           " codec_specific_4: " + std::to_string(codec_specific_4);
+  }
+
+ private:
+  static std::string AppendCapability(std::string& result, bool append,
+                                      const std::string& name) {
+    if (!append) return result;
+    if (!result.empty()) result += "|";
+    result += name;
+    return result;
+  }
+} btav_a2dp_codec_config_t;
+
+/** Callback for connection state change.
+ *  state will have one of the values from btav_connection_state_t
+ */
+typedef void (*btav_connection_state_callback)(const RawAddress& bd_addr,
+                                               btav_connection_state_t state);
+
+/** Callback for audiopath state change.
+ *  state will have one of the values from btav_audio_state_t
+ */
+typedef void (*btav_audio_state_callback)(const RawAddress& bd_addr,
+                                          btav_audio_state_t state);
+
+/** Callback for audio configuration change.
+ *  Used only for the A2DP Source interface.
+ */
+typedef void (*btav_audio_source_config_callback)(
+    const RawAddress& bd_addr, btav_a2dp_codec_config_t codec_config,
+    std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
+    std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities);
+
+/** Callback for audio configuration change.
+ *  Used only for the A2DP Sink interface.
+ *  sample_rate: sample rate in Hz
+ *  channel_count: number of channels (1 for mono, 2 for stereo)
+ */
+typedef void (*btav_audio_sink_config_callback)(const RawAddress& bd_addr,
+                                                uint32_t sample_rate,
+                                                uint8_t channel_count);
+
+/** BT-AV A2DP Source callback structure. */
+typedef struct {
+  /** set to sizeof(btav_source_callbacks_t) */
+  size_t size;
+  btav_connection_state_callback connection_state_cb;
+  btav_audio_state_callback audio_state_cb;
+  btav_audio_source_config_callback audio_config_cb;
+} btav_source_callbacks_t;
+
+/** BT-AV A2DP Sink callback structure. */
+typedef struct {
+  /** set to sizeof(btav_sink_callbacks_t) */
+  size_t size;
+  btav_connection_state_callback connection_state_cb;
+  btav_audio_state_callback audio_state_cb;
+  btav_audio_sink_config_callback audio_config_cb;
+} btav_sink_callbacks_t;
+
+/**
+ * NOTE:
+ *
+ * 1. AVRCP 1.0 shall be supported initially. AVRCP passthrough commands
+ *    shall be handled internally via uinput
+ *
+ * 2. A2DP data path shall be handled via a socket pipe between the AudioFlinger
+ *    android_audio_hw library and the Bluetooth stack.
+ *
+ */
+
+/** Represents the standard BT-AV A2DP Source interface.
+ */
+typedef struct {
+  /** set to sizeof(btav_source_interface_t) */
+  size_t size;
+  /**
+   * Register the BtAv callbacks.
+   */
+  bt_status_t (*init)(btav_source_callbacks_t* callbacks,
+                      int max_connected_audio_devices,
+                      std::vector<btav_a2dp_codec_config_t> codec_priorities);
+
+  /** connect to headset */
+  bt_status_t (*connect)(const RawAddress& bd_addr);
+
+  /** dis-connect from headset */
+  bt_status_t (*disconnect)(const RawAddress& bd_addr);
+
+  /** sets the connected device as active */
+  bt_status_t (*set_active_device)(const RawAddress& bd_addr);
+
+  /** configure the codecs settings preferences */
+  bt_status_t (*config_codec)(
+      const RawAddress& bd_addr,
+      std::vector<btav_a2dp_codec_config_t> codec_preferences);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+
+} btav_source_interface_t;
+
+/** Represents the standard BT-AV A2DP Sink interface.
+ */
+typedef struct {
+  /** set to sizeof(btav_sink_interface_t) */
+  size_t size;
+  /**
+   * Register the BtAv callbacks
+   */
+  bt_status_t (*init)(btav_sink_callbacks_t* callbacks);
+
+  /** connect to headset */
+  bt_status_t (*connect)(const RawAddress& bd_addr);
+
+  /** dis-connect from headset */
+  bt_status_t (*disconnect)(const RawAddress& bd_addr);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+
+  /** Sends Audio Focus State. */
+  void (*set_audio_focus_state)(int focus_state);
+
+  /** Sets the audio track gain. */
+  void (*set_audio_track_gain)(float gain);
+} btav_sink_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_AV_H */
diff --git a/include/hardware/bt_common_types.h b/include/hardware/bt_common_types.h
new file mode 100644
index 0000000..0a315fe
--- /dev/null
+++ b/include/hardware/bt_common_types.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+/******************************************************************************
+ *
+ * This file contains constants and definitions that can be used commonly
+ * between JNI and stack layer
+ *
+ ******************************************************************************/
+#ifndef ANDROID_INCLUDE_BT_COMMON_TYPES_H
+#define ANDROID_INCLUDE_BT_COMMON_TYPES_H
+
+#include "bluetooth.h"
+
+#include <bluetooth/uuid.h>
+#include <vector>
+
+typedef struct {
+  uint8_t client_if;
+  uint8_t filt_index;
+  uint8_t advertiser_state;
+  uint8_t advertiser_info_present;
+  uint8_t addr_type;
+  uint8_t tx_power;
+  int8_t rssi_value;
+  uint16_t time_stamp;
+  RawAddress bd_addr;
+  uint8_t adv_pkt_len;
+  uint8_t* p_adv_pkt_data;
+  uint8_t scan_rsp_len;
+  uint8_t* p_scan_rsp_data;
+} btgatt_track_adv_info_t;
+
+typedef enum {
+  BTGATT_DB_PRIMARY_SERVICE,
+  BTGATT_DB_SECONDARY_SERVICE,
+  BTGATT_DB_INCLUDED_SERVICE,
+  BTGATT_DB_CHARACTERISTIC,
+  BTGATT_DB_DESCRIPTOR,
+} bt_gatt_db_attribute_type_t;
+
+typedef struct {
+  uint16_t id;
+  bluetooth::Uuid uuid;
+  bt_gatt_db_attribute_type_t type;
+  uint16_t attribute_handle;
+
+  /*
+   * If |type| is |BTGATT_DB_PRIMARY_SERVICE|, or
+   * |BTGATT_DB_SECONDARY_SERVICE|, this contains the start and end attribute
+   * handles.
+   */
+  uint16_t start_handle;
+  uint16_t end_handle;
+
+  /*
+   * If |type| is |BTGATT_DB_CHARACTERISTIC|, this contains the properties of
+   * the characteristic.
+   */
+  uint8_t properties;
+  uint16_t permissions;
+} btgatt_db_element_t;
+
+typedef struct {
+  uint16_t feat_seln;
+  uint16_t list_logic_type;
+  uint8_t filt_logic_type;
+  uint8_t rssi_high_thres;
+  uint8_t rssi_low_thres;
+  uint8_t dely_mode;
+  uint16_t found_timeout;
+  uint16_t lost_timeout;
+  uint8_t found_timeout_cnt;
+  uint16_t num_of_tracking_entries;
+} btgatt_filt_param_setup_t;
+
+// Advertising Packet Content Filter
+struct ApcfCommand {
+  uint8_t type;
+  RawAddress address;
+  uint8_t addr_type;
+  bluetooth::Uuid uuid;
+  bluetooth::Uuid uuid_mask;
+  std::vector<uint8_t> name;
+  uint16_t company;
+  uint16_t company_mask;
+  std::vector<uint8_t> data;
+  std::vector<uint8_t> data_mask;
+};
+
+#endif /* ANDROID_INCLUDE_BT_COMMON_TYPES_H */
diff --git a/include/hardware/bt_gatt.h b/include/hardware/bt_gatt.h
new file mode 100644
index 0000000..6f8c408
--- /dev/null
+++ b/include/hardware/bt_gatt.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_GATT_H
+#define ANDROID_INCLUDE_BT_GATT_H
+
+#include <stdint.h>
+#include "ble_advertiser.h"
+#include "ble_scanner.h"
+#include "bt_gatt_client.h"
+#include "bt_gatt_server.h"
+
+__BEGIN_DECLS
+
+/** BT-GATT callbacks */
+typedef struct {
+  /** Set to sizeof(btgatt_callbacks_t) */
+  size_t size;
+
+  /** GATT Client callbacks */
+  const btgatt_client_callbacks_t* client;
+
+  /** GATT Server callbacks */
+  const btgatt_server_callbacks_t* server;
+
+  /** LE scanner callbacks */
+  const btgatt_scanner_callbacks_t* scanner;
+} btgatt_callbacks_t;
+
+/** Represents the standard Bluetooth GATT interface. */
+typedef struct {
+  /** Set to sizeof(btgatt_interface_t) */
+  size_t size;
+
+  /**
+   * Initializes the interface and provides callback routines
+   */
+  bt_status_t (*init)(const btgatt_callbacks_t* callbacks);
+
+  /** Closes the interface */
+  void (*cleanup)(void);
+
+  /** Pointer to the GATT client interface methods.*/
+  const btgatt_client_interface_t* client;
+
+  /** Pointer to the GATT server interface methods.*/
+  const btgatt_server_interface_t* server;
+
+  /** Pointer to the LE scanner interface methods.*/
+  BleScannerInterface* scanner;
+
+  /** Pointer to the advertiser interface methods.*/
+  BleAdvertiserInterface* advertiser;
+} btgatt_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_H */
diff --git a/include/hardware/bt_gatt_client.h b/include/hardware/bt_gatt_client.h
new file mode 100644
index 0000000..6ea1c89
--- /dev/null
+++ b/include/hardware/bt_gatt_client.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_GATT_CLIENT_H
+#define ANDROID_INCLUDE_BT_GATT_CLIENT_H
+
+#include <stdint.h>
+#include <vector>
+#include "bt_common_types.h"
+#include "bt_gatt_types.h"
+
+#include <bluetooth/uuid.h>
+
+__BEGIN_DECLS
+
+/**
+ * Buffer sizes for maximum attribute length and maximum read/write
+ * operation buffer size.
+ */
+#define BTGATT_MAX_ATTR_LEN 600
+
+/** Buffer type for unformatted reads/writes */
+typedef struct {
+  uint8_t value[BTGATT_MAX_ATTR_LEN];
+  uint16_t len;
+} btgatt_unformatted_value_t;
+
+/** Parameters for GATT read operations */
+typedef struct {
+  uint16_t handle;
+  btgatt_unformatted_value_t value;
+  uint16_t value_type;
+  uint8_t status;
+} btgatt_read_params_t;
+
+/** Parameters for GATT write operations */
+typedef struct {
+  btgatt_srvc_id_t srvc_id;
+  btgatt_gatt_id_t char_id;
+  btgatt_gatt_id_t descr_id;
+  uint8_t status;
+} btgatt_write_params_t;
+
+/** Attribute change notification parameters */
+typedef struct {
+  uint8_t value[BTGATT_MAX_ATTR_LEN];
+  RawAddress bda;
+  uint16_t handle;
+  uint16_t len;
+  uint8_t is_notify;
+} btgatt_notify_params_t;
+
+typedef struct {
+  RawAddress* bda1;
+  bluetooth::Uuid* uuid1;
+  uint16_t u1;
+  uint16_t u2;
+  uint16_t u3;
+  uint16_t u4;
+  uint16_t u5;
+} btgatt_test_params_t;
+
+/* BT GATT client error codes */
+typedef enum {
+  BT_GATTC_COMMAND_SUCCESS = 0, /* 0  Command succeeded                 */
+  BT_GATTC_COMMAND_STARTED,     /* 1  Command started OK.               */
+  BT_GATTC_COMMAND_BUSY,        /* 2  Device busy with another command  */
+  BT_GATTC_COMMAND_STORED,      /* 3 request is stored in control block */
+  BT_GATTC_NO_RESOURCES,        /* 4  No resources to issue command     */
+  BT_GATTC_MODE_UNSUPPORTED,    /* 5  Request for 1 or more unsupported modes */
+  BT_GATTC_ILLEGAL_VALUE,       /* 6  Illegal command /parameter value  */
+  BT_GATTC_INCORRECT_STATE,     /* 7  Device in wrong state for request  */
+  BT_GATTC_UNKNOWN_ADDR,        /* 8  Unknown remote BD address         */
+  BT_GATTC_DEVICE_TIMEOUT,      /* 9  Device timeout                    */
+  BT_GATTC_INVALID_CONTROLLER_OUTPUT, /* 10  An incorrect value was received
+                                         from HCI */
+  BT_GATTC_SECURITY_ERROR, /* 11 Authorization or security failure or not
+                              authorized  */
+  BT_GATTC_DELAYED_ENCRYPTION_CHECK, /*12 Delayed encryption check */
+  BT_GATTC_ERR_PROCESSING            /* 12 Generic error                     */
+} btgattc_error_t;
+
+/** BT-GATT Client callback structure. */
+
+/** Callback invoked in response to register_client */
+typedef void (*register_client_callback)(int status, int client_if,
+                                         const bluetooth::Uuid& app_uuid);
+
+/** GATT open callback invoked in response to open */
+typedef void (*connect_callback)(int conn_id, int status, int client_if,
+                                 const RawAddress& bda);
+
+/** Callback invoked in response to close */
+typedef void (*disconnect_callback)(int conn_id, int status, int client_if,
+                                    const RawAddress& bda);
+
+/**
+ * Invoked in response to search_service when the GATT service search
+ * has been completed.
+ */
+typedef void (*search_complete_callback)(int conn_id, int status);
+
+/** Callback invoked in response to [de]register_for_notification */
+typedef void (*register_for_notification_callback)(int conn_id, int registered,
+                                                   int status, uint16_t handle);
+
+/**
+ * Remote device notification callback, invoked when a remote device sends
+ * a notification or indication that a client has registered for.
+ */
+typedef void (*notify_callback)(int conn_id,
+                                const btgatt_notify_params_t& p_data);
+
+/** Reports result of a GATT read operation */
+typedef void (*read_characteristic_callback)(int conn_id, int status,
+                                             btgatt_read_params_t* p_data);
+
+/** GATT write characteristic operation callback */
+typedef void (*write_characteristic_callback)(int conn_id, int status,
+                                              uint16_t handle);
+
+/** GATT execute prepared write callback */
+typedef void (*execute_write_callback)(int conn_id, int status);
+
+/** Callback invoked in response to read_descriptor */
+typedef void (*read_descriptor_callback)(int conn_id, int status,
+                                         const btgatt_read_params_t& p_data);
+
+/** Callback invoked in response to write_descriptor */
+typedef void (*write_descriptor_callback)(int conn_id, int status,
+                                          uint16_t handle);
+
+/** Callback triggered in response to read_remote_rssi */
+typedef void (*read_remote_rssi_callback)(int client_if, const RawAddress& bda,
+                                          int rssi, int status);
+
+/** Callback invoked when the MTU for a given connection changes */
+typedef void (*configure_mtu_callback)(int conn_id, int status, int mtu);
+
+/**
+ * Callback notifying an application that a remote device connection is
+ * currently congested and cannot receive any more data. An application should
+ * avoid sending more data until a further callback is received indicating the
+ * congestion status has been cleared.
+ */
+typedef void (*congestion_callback)(int conn_id, bool congested);
+
+/** GATT get database callback */
+typedef void (*get_gatt_db_callback)(int conn_id, const btgatt_db_element_t* db,
+                                     int count);
+
+/** GATT services between start_handle and end_handle were removed */
+typedef void (*services_removed_callback)(int conn_id, uint16_t start_handle,
+                                          uint16_t end_handle);
+
+/** GATT services were added */
+typedef void (*services_added_callback)(int conn_id,
+                                        const btgatt_db_element_t& added,
+                                        int added_count);
+
+/** Callback invoked when the PHY for a given connection changes */
+typedef void (*phy_updated_callback)(int conn_id, uint8_t tx_phy,
+                                     uint8_t rx_phy, uint8_t status);
+
+/** Callback invoked when the connection parameters for a given connection
+ * changes */
+typedef void (*conn_updated_callback)(int conn_id, uint16_t interval,
+                                      uint16_t latency, uint16_t timeout,
+                                      uint8_t status);
+
+typedef struct {
+  register_client_callback register_client_cb;
+  connect_callback open_cb;
+  disconnect_callback close_cb;
+  search_complete_callback search_complete_cb;
+  register_for_notification_callback register_for_notification_cb;
+  notify_callback notify_cb;
+  read_characteristic_callback read_characteristic_cb;
+  write_characteristic_callback write_characteristic_cb;
+  read_descriptor_callback read_descriptor_cb;
+  write_descriptor_callback write_descriptor_cb;
+  execute_write_callback execute_write_cb;
+  read_remote_rssi_callback read_remote_rssi_cb;
+  configure_mtu_callback configure_mtu_cb;
+  congestion_callback congestion_cb;
+  get_gatt_db_callback get_gatt_db_cb;
+  services_removed_callback services_removed_cb;
+  services_added_callback services_added_cb;
+  phy_updated_callback phy_updated_cb;
+  conn_updated_callback conn_updated_cb;
+} btgatt_client_callbacks_t;
+
+/** Represents the standard BT-GATT client interface. */
+
+typedef struct {
+  /** Registers a GATT client application with the stack */
+  bt_status_t (*register_client)(const bluetooth::Uuid& uuid);
+
+  /** Unregister a client application from the stack */
+  bt_status_t (*unregister_client)(int client_if);
+
+  /** Create a connection to a remote LE or dual-mode device */
+  bt_status_t (*connect)(int client_if, const RawAddress& bd_addr,
+                         bool is_direct, int transport, bool opportunistic,
+                         int initiating_phys);
+
+  /** Disconnect a remote device or cancel a pending connection */
+  bt_status_t (*disconnect)(int client_if, const RawAddress& bd_addr,
+                            int conn_id);
+
+  /** Clear the attribute cache for a given device */
+  bt_status_t (*refresh)(int client_if, const RawAddress& bd_addr);
+
+  /**
+   * Enumerate all GATT services on a connected device.
+   * Optionally, the results can be filtered for a given UUID.
+   */
+  bt_status_t (*search_service)(int conn_id,
+                                const bluetooth::Uuid* filter_uuid);
+
+  /**
+   * Sead "Find service by UUID" request. Used only for PTS tests.
+   */
+  void (*btif_gattc_discover_service_by_uuid)(int conn_id,
+                                              const bluetooth::Uuid& uuid);
+
+  /** Read a characteristic on a remote device */
+  bt_status_t (*read_characteristic)(int conn_id, uint16_t handle,
+                                     int auth_req);
+
+  /** Read a characteristic on a remote device */
+  bt_status_t (*read_using_characteristic_uuid)(int conn_id,
+                                                const bluetooth::Uuid& uuid,
+                                                uint16_t s_handle,
+                                                uint16_t e_handle,
+                                                int auth_req);
+
+  /** Write a remote characteristic */
+  bt_status_t (*write_characteristic)(int conn_id, uint16_t handle,
+                                      int write_type, int auth_req,
+                                      std::vector<uint8_t> value);
+
+  /** Read the descriptor for a given characteristic */
+  bt_status_t (*read_descriptor)(int conn_id, uint16_t handle, int auth_req);
+
+  /** Write a remote descriptor for a given characteristic */
+  bt_status_t (*write_descriptor)(int conn_id, uint16_t handle, int auth_req,
+                                  std::vector<uint8_t> value);
+
+  /** Execute a prepared write operation */
+  bt_status_t (*execute_write)(int conn_id, int execute);
+
+  /**
+   * Register to receive notifications or indications for a given
+   * characteristic
+   */
+  bt_status_t (*register_for_notification)(int client_if,
+                                           const RawAddress& bd_addr,
+                                           uint16_t handle);
+
+  /** Deregister a previous request for notifications/indications */
+  bt_status_t (*deregister_for_notification)(int client_if,
+                                             const RawAddress& bd_addr,
+                                             uint16_t handle);
+
+  /** Request RSSI for a given remote device */
+  bt_status_t (*read_remote_rssi)(int client_if, const RawAddress& bd_addr);
+
+  /** Determine the type of the remote device (LE, BR/EDR, Dual-mode) */
+  int (*get_device_type)(const RawAddress& bd_addr);
+
+  /** Configure the MTU for a given connection */
+  bt_status_t (*configure_mtu)(int conn_id, int mtu);
+
+  /** Request a connection parameter update */
+  bt_status_t (*conn_parameter_update)(const RawAddress& bd_addr,
+                                       int min_interval, int max_interval,
+                                       int latency, int timeout,
+                                       uint16_t min_ce_len,
+                                       uint16_t max_ce_len);
+
+  bt_status_t (*set_preferred_phy)(const RawAddress& bd_addr, uint8_t tx_phy,
+                                   uint8_t rx_phy, uint16_t phy_options);
+
+  bt_status_t (*read_phy)(
+      const RawAddress& bd_addr,
+      base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb);
+
+  /** Test mode interface */
+  bt_status_t (*test_command)(int command, const btgatt_test_params_t& params);
+
+  /** Get gatt db content */
+  bt_status_t (*get_gatt_db)(int conn_id);
+
+} btgatt_client_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_CLIENT_H */
diff --git a/include/hardware/bt_gatt_server.h b/include/hardware/bt_gatt_server.h
new file mode 100644
index 0000000..1b1db37
--- /dev/null
+++ b/include/hardware/bt_gatt_server.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_GATT_SERVER_H
+#define ANDROID_INCLUDE_BT_GATT_SERVER_H
+
+#include <stdint.h>
+#include <vector>
+
+#include "bt_gatt_types.h"
+
+__BEGIN_DECLS
+
+/** GATT value type used in response to remote read requests */
+typedef struct {
+  uint8_t value[BTGATT_MAX_ATTR_LEN];
+  uint16_t handle;
+  uint16_t offset;
+  uint16_t len;
+  uint8_t auth_req;
+} btgatt_value_t;
+
+/** GATT remote read request response type */
+typedef union {
+  btgatt_value_t attr_value;
+  uint16_t handle;
+} btgatt_response_t;
+
+/** BT-GATT Server callback structure. */
+
+/** Callback invoked in response to register_server */
+typedef void (*register_server_callback)(int status, int server_if,
+                                         const bluetooth::Uuid& app_uuid);
+
+/** Callback indicating that a remote device has connected or been disconnected
+ */
+typedef void (*connection_callback)(int conn_id, int server_if, int connected,
+                                    const RawAddress& bda);
+
+/** Callback invoked in response to create_service */
+typedef void (*service_added_callback)(
+    int status, int server_if, std::vector<btgatt_db_element_t> service);
+
+/** Callback invoked in response to stop_service */
+typedef void (*service_stopped_callback)(int status, int server_if,
+                                         int srvc_handle);
+
+/** Callback triggered when a service has been deleted */
+typedef void (*service_deleted_callback)(int status, int server_if,
+                                         int srvc_handle);
+
+/**
+ * Callback invoked when a remote device has requested to read a characteristic
+ * or descriptor. The application must respond by calling send_response
+ */
+typedef void (*request_read_callback)(int conn_id, int trans_id,
+                                      const RawAddress& bda, int attr_handle,
+                                      int offset, bool is_long);
+
+/**
+ * Callback invoked when a remote device has requested to write to a
+ * characteristic or descriptor.
+ */
+typedef void (*request_write_callback)(int conn_id, int trans_id,
+                                       const RawAddress& bda, int attr_handle,
+                                       int offset, bool need_rsp, bool is_prep,
+                                       std::vector<uint8_t> value);
+
+/** Callback invoked when a previously prepared write is to be executed */
+typedef void (*request_exec_write_callback)(int conn_id, int trans_id,
+                                            const RawAddress& bda,
+                                            int exec_write);
+
+/**
+ * Callback triggered in response to send_response if the remote device
+ * sends a confirmation.
+ */
+typedef void (*response_confirmation_callback)(int status, int handle);
+
+/**
+ * Callback confirming that a notification or indication has been sent
+ * to a remote device.
+ */
+typedef void (*indication_sent_callback)(int conn_id, int status);
+
+/**
+ * Callback notifying an application that a remote device connection is
+ * currently congested and cannot receive any more data. An application should
+ * avoid sending more data until a further callback is received indicating the
+ * congestion status has been cleared.
+ */
+typedef void (*congestion_callback)(int conn_id, bool congested);
+
+/** Callback invoked when the MTU for a given connection changes */
+typedef void (*mtu_changed_callback)(int conn_id, int mtu);
+
+/** Callback invoked when the PHY for a given connection changes */
+typedef void (*phy_updated_callback)(int conn_id, uint8_t tx_phy,
+                                     uint8_t rx_phy, uint8_t status);
+
+/** Callback invoked when the connection parameters for a given connection
+ * changes */
+typedef void (*conn_updated_callback)(int conn_id, uint16_t interval,
+                                      uint16_t latency, uint16_t timeout,
+                                      uint8_t status);
+typedef struct {
+  register_server_callback register_server_cb;
+  connection_callback connection_cb;
+  service_added_callback service_added_cb;
+  service_stopped_callback service_stopped_cb;
+  service_deleted_callback service_deleted_cb;
+  request_read_callback request_read_characteristic_cb;
+  request_read_callback request_read_descriptor_cb;
+  request_write_callback request_write_characteristic_cb;
+  request_write_callback request_write_descriptor_cb;
+  request_exec_write_callback request_exec_write_cb;
+  response_confirmation_callback response_confirmation_cb;
+  indication_sent_callback indication_sent_cb;
+  congestion_callback congestion_cb;
+  mtu_changed_callback mtu_changed_cb;
+  phy_updated_callback phy_updated_cb;
+  conn_updated_callback conn_updated_cb;
+} btgatt_server_callbacks_t;
+
+/** Represents the standard BT-GATT server interface. */
+typedef struct {
+  /** Registers a GATT server application with the stack */
+  bt_status_t (*register_server)(const bluetooth::Uuid& uuid);
+
+  /** Unregister a server application from the stack */
+  bt_status_t (*unregister_server)(int server_if);
+
+  /** Create a connection to a remote peripheral */
+  bt_status_t (*connect)(int server_if, const RawAddress& bd_addr,
+                         bool is_direct, int transport);
+
+  /** Disconnect an established connection or cancel a pending one */
+  bt_status_t (*disconnect)(int server_if, const RawAddress& bd_addr,
+                            int conn_id);
+
+  /** Create a new service */
+  bt_status_t (*add_service)(int server_if,
+                             std::vector<btgatt_db_element_t> service);
+
+  /** Stops a local service */
+  bt_status_t (*stop_service)(int server_if, int service_handle);
+
+  /** Delete a local service */
+  bt_status_t (*delete_service)(int server_if, int service_handle);
+
+  /** Send value indication to a remote device */
+  bt_status_t (*send_indication)(int server_if, int attribute_handle,
+                                 int conn_id, int confirm,
+                                 std::vector<uint8_t> value);
+
+  /** Send a response to a read/write operation */
+  bt_status_t (*send_response)(int conn_id, int trans_id, int status,
+                               const btgatt_response_t& response);
+
+  bt_status_t (*set_preferred_phy)(const RawAddress& bd_addr, uint8_t tx_phy,
+                                   uint8_t rx_phy, uint16_t phy_options);
+
+  bt_status_t (*read_phy)(
+      const RawAddress& bd_addr,
+      base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb);
+
+} btgatt_server_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_CLIENT_H */
diff --git a/include/hardware/bt_gatt_types.h b/include/hardware/bt_gatt_types.h
new file mode 100644
index 0000000..e41cca6
--- /dev/null
+++ b/include/hardware/bt_gatt_types.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_GATT_TYPES_H
+#define ANDROID_INCLUDE_BT_GATT_TYPES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <bluetooth/uuid.h>
+
+__BEGIN_DECLS
+
+/**
+ * GATT Service types
+ */
+#define BTGATT_SERVICE_TYPE_PRIMARY 0
+#define BTGATT_SERVICE_TYPE_SECONDARY 1
+
+/** GATT ID adding instance id tracking to the UUID */
+typedef struct {
+  bluetooth::Uuid uuid;
+  uint8_t inst_id;
+} btgatt_gatt_id_t;
+
+/** GATT Service ID also identifies the service type (primary/secondary) */
+typedef struct {
+  btgatt_gatt_id_t id;
+  uint8_t is_primary;
+} btgatt_srvc_id_t;
+
+/** Preferred physical Transport for GATT connection */
+typedef enum {
+  GATT_TRANSPORT_AUTO,
+  GATT_TRANSPORT_BREDR,
+  GATT_TRANSPORT_LE
+} btgatt_transport_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_GATT_TYPES_H */
diff --git a/include/hardware/bt_hd.h b/include/hardware/bt_hd.h
new file mode 100644
index 0000000..be93709
--- /dev/null
+++ b/include/hardware/bt_hd.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HD_H
+#define ANDROID_INCLUDE_BT_HD_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+typedef enum {
+  BTHD_REPORT_TYPE_OTHER = 0,
+  BTHD_REPORT_TYPE_INPUT,
+  BTHD_REPORT_TYPE_OUTPUT,
+  BTHD_REPORT_TYPE_FEATURE,
+  // special value for reports to be sent on INTR(INPUT is assumed)
+  BTHD_REPORT_TYPE_INTRDATA
+} bthd_report_type_t;
+
+typedef enum {
+  BTHD_APP_STATE_NOT_REGISTERED,
+  BTHD_APP_STATE_REGISTERED
+} bthd_application_state_t;
+
+typedef enum {
+  BTHD_CONN_STATE_CONNECTED,
+  BTHD_CONN_STATE_CONNECTING,
+  BTHD_CONN_STATE_DISCONNECTED,
+  BTHD_CONN_STATE_DISCONNECTING,
+  BTHD_CONN_STATE_UNKNOWN
+} bthd_connection_state_t;
+
+typedef struct {
+  const char* name;
+  const char* description;
+  const char* provider;
+  uint8_t subclass;
+  uint8_t* desc_list;
+  int desc_list_len;
+} bthd_app_param_t;
+
+typedef struct {
+  uint8_t service_type;
+  uint32_t token_rate;
+  uint32_t token_bucket_size;
+  uint32_t peak_bandwidth;
+  uint32_t access_latency;
+  uint32_t delay_variation;
+} bthd_qos_param_t;
+
+typedef void (*bthd_application_state_callback)(RawAddress* bd_addr,
+                                                bthd_application_state_t state);
+typedef void (*bthd_connection_state_callback)(RawAddress* bd_addr,
+                                               bthd_connection_state_t state);
+typedef void (*bthd_get_report_callback)(uint8_t type, uint8_t id,
+                                         uint16_t buffer_size);
+typedef void (*bthd_set_report_callback)(uint8_t type, uint8_t id, uint16_t len,
+                                         uint8_t* p_data);
+typedef void (*bthd_set_protocol_callback)(uint8_t protocol);
+typedef void (*bthd_intr_data_callback)(uint8_t report_id, uint16_t len,
+                                        uint8_t* p_data);
+typedef void (*bthd_vc_unplug_callback)(void);
+
+/** BT-HD callbacks */
+typedef struct {
+  size_t size;
+
+  bthd_application_state_callback application_state_cb;
+  bthd_connection_state_callback connection_state_cb;
+  bthd_get_report_callback get_report_cb;
+  bthd_set_report_callback set_report_cb;
+  bthd_set_protocol_callback set_protocol_cb;
+  bthd_intr_data_callback intr_data_cb;
+  bthd_vc_unplug_callback vc_unplug_cb;
+} bthd_callbacks_t;
+
+/** BT-HD interface */
+typedef struct {
+  size_t size;
+
+  /** init interface and register callbacks */
+  bt_status_t (*init)(bthd_callbacks_t* callbacks);
+
+  /** close interface */
+  void (*cleanup)(void);
+
+  /** register application */
+  bt_status_t (*register_app)(bthd_app_param_t* app_param,
+                              bthd_qos_param_t* in_qos,
+                              bthd_qos_param_t* out_qos);
+
+  /** unregister application */
+  bt_status_t (*unregister_app)(void);
+
+  /** connects to host with virtual cable */
+  bt_status_t (*connect)(RawAddress* bd_addr);
+
+  /** disconnects from currently connected host */
+  bt_status_t (*disconnect)(void);
+
+  /** send report */
+  bt_status_t (*send_report)(bthd_report_type_t type, uint8_t id, uint16_t len,
+                             uint8_t* p_data);
+
+  /** notifies error for invalid SET_REPORT */
+  bt_status_t (*report_error)(uint8_t error);
+
+  /** send Virtual Cable Unplug  */
+  bt_status_t (*virtual_cable_unplug)(void);
+
+} bthd_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HD_H */
diff --git a/include/hardware/bt_hearing_aid.h b/include/hardware/bt_hearing_aid.h
new file mode 100644
index 0000000..a54f82a
--- /dev/null
+++ b/include/hardware/bt_hearing_aid.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HEARING_AID_H
+#define ANDROID_INCLUDE_BT_HEARING_AID_H
+
+#include <hardware/bluetooth.h>
+
+namespace bluetooth {
+namespace hearing_aid {
+
+enum class ConnectionState {
+  DISCONNECTED = 0,
+  CONNECTING,
+  CONNECTED,
+  DISCONNECTING
+};
+
+class HearingAidCallbacks {
+ public:
+  virtual ~HearingAidCallbacks() = default;
+
+  /** Callback for profile connection state change */
+  virtual void OnConnectionState(ConnectionState state,
+                                 const RawAddress& address) = 0;
+
+  /** Callback for device being available. Is executed when devices are loaded
+   * from storage on stack bringup, and when new device is connected to profile.
+   * Main purpose of this callback is to keep its users informed of device
+   * capabilities and hiSyncId.
+   */
+  virtual void OnDeviceAvailable(uint8_t capabilities, uint64_t hiSyncId,
+                                 const RawAddress& address) = 0;
+};
+
+class HearingAidInterface {
+ public:
+  virtual ~HearingAidInterface() = default;
+
+  /** Register the Hearing Aid callbacks */
+  virtual void Init(HearingAidCallbacks* callbacks) = 0;
+
+  /** Connect to Hearing Aid */
+  virtual void Connect(const RawAddress& address) = 0;
+
+  /** Disconnect from Hearing Aid */
+  virtual void Disconnect(const RawAddress& address) = 0;
+
+  /** Set the volume */
+  virtual void SetVolume(int8_t volume) = 0;
+
+  /** Closes the interface. */
+  virtual void Cleanup(void) = 0;
+
+  /* Called when Hearing Aid is unbonded. */
+  virtual void RemoveDevice(const RawAddress& address) = 0;
+};
+
+}  // namespace hearing_aid
+}  // namespace bluetooth
+
+#endif /* ANDROID_INCLUDE_BT_HEARING_AID_H */
diff --git a/include/hardware/bt_hf.h b/include/hardware/bt_hf.h
new file mode 100644
index 0000000..ac2de4d
--- /dev/null
+++ b/include/hardware/bt_hf.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 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
+
+namespace bluetooth {
+namespace headset {
+
+/* AT response code - OK/Error */
+typedef enum {
+  BTHF_AT_RESPONSE_ERROR = 0,
+  BTHF_AT_RESPONSE_OK
+} bthf_at_response_t;
+
+typedef enum {
+  BTHF_CONNECTION_STATE_DISCONNECTED = 0,
+  BTHF_CONNECTION_STATE_CONNECTING,
+  BTHF_CONNECTION_STATE_CONNECTED,
+  BTHF_CONNECTION_STATE_SLC_CONNECTED,
+  BTHF_CONNECTION_STATE_DISCONNECTING
+} bthf_connection_state_t;
+
+typedef enum {
+  BTHF_AUDIO_STATE_DISCONNECTED = 0,
+  BTHF_AUDIO_STATE_CONNECTING,
+  BTHF_AUDIO_STATE_CONNECTED,
+  BTHF_AUDIO_STATE_DISCONNECTING
+} bthf_audio_state_t;
+
+typedef enum {
+  BTHF_VR_STATE_STOPPED = 0,
+  BTHF_VR_STATE_STARTED
+} bthf_vr_state_t;
+
+typedef enum {
+  BTHF_VOLUME_TYPE_SPK = 0,
+  BTHF_VOLUME_TYPE_MIC
+} bthf_volume_type_t;
+
+/* Noise Reduction and Echo Cancellation */
+typedef enum { BTHF_NREC_STOP, BTHF_NREC_START } bthf_nrec_t;
+
+/* WBS codec setting */
+typedef enum { BTHF_WBS_NONE, BTHF_WBS_NO, BTHF_WBS_YES } bthf_wbs_config_t;
+
+/* CHLD - Call held handling */
+typedef enum {
+  BTHF_CHLD_TYPE_RELEASEHELD,  // Terminate all held or set UDUB("busy") to a
+                               // waiting call
+  BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD,  // Terminate all active calls and
+                                            // accepts a waiting/held call
+  BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD,  // Hold all active calls and accepts a
+                                         // waiting/held call
+  BTHF_CHLD_TYPE_ADDHELDTOCONF,          // Add all held calls to a conference
+} bthf_chld_type_t;
+
+/* HF Indicators HFP 1.7 */
+typedef enum {
+  BTHF_HF_IND_ENHANCED_DRIVER_SAFETY = 1,
+  BTHF_HF_IND_BATTERY_LEVEL_STATUS = 2,
+} bthf_hf_ind_type_t;
+
+typedef enum {
+  BTHF_HF_IND_DISABLED = 0,
+  BTHF_HF_IND_ENABLED,
+} bthf_hf_ind_status_t;
+
+/** Network Status */
+typedef enum {
+  BTHF_NETWORK_STATE_NOT_AVAILABLE = 0,
+  BTHF_NETWORK_STATE_AVAILABLE
+} bthf_network_state_t;
+
+/** Service type */
+typedef enum {
+  BTHF_SERVICE_TYPE_HOME = 0,
+  BTHF_SERVICE_TYPE_ROAMING
+} bthf_service_type_t;
+
+typedef enum {
+  BTHF_CALL_STATE_ACTIVE = 0,
+  BTHF_CALL_STATE_HELD,
+  BTHF_CALL_STATE_DIALING,
+  BTHF_CALL_STATE_ALERTING,
+  BTHF_CALL_STATE_INCOMING,
+  BTHF_CALL_STATE_WAITING,
+  BTHF_CALL_STATE_IDLE,
+  BTHF_CALL_STATE_DISCONNECTED
+} bthf_call_state_t;
+
+typedef enum {
+  BTHF_CALL_DIRECTION_OUTGOING = 0,
+  BTHF_CALL_DIRECTION_INCOMING
+} bthf_call_direction_t;
+
+typedef enum {
+  BTHF_CALL_TYPE_VOICE = 0,
+  BTHF_CALL_TYPE_DATA,
+  BTHF_CALL_TYPE_FAX
+} bthf_call_mode_t;
+
+typedef enum {
+  BTHF_CALL_MPTY_TYPE_SINGLE = 0,
+  BTHF_CALL_MPTY_TYPE_MULTI
+} bthf_call_mpty_type_t;
+
+typedef enum {
+  BTHF_CALL_ADDRTYPE_UNKNOWN = 0x81,
+  BTHF_CALL_ADDRTYPE_INTERNATIONAL = 0x91
+} bthf_call_addrtype_t;
+
+}  // namespace headset
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/include/hardware/bt_hf_client.h b/include/hardware/bt_hf_client.h
new file mode 100644
index 0000000..a31de0f
--- /dev/null
+++ b/include/hardware/bt_hf_client.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2012-2014 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HF_CLIENT_H
+#define ANDROID_INCLUDE_BT_HF_CLIENT_H
+
+__BEGIN_DECLS
+
+typedef enum {
+  BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED = 0,
+  BTHF_CLIENT_CONNECTION_STATE_CONNECTING,
+  BTHF_CLIENT_CONNECTION_STATE_CONNECTED,
+  BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED,
+  BTHF_CLIENT_CONNECTION_STATE_DISCONNECTING
+} bthf_client_connection_state_t;
+
+typedef enum {
+  BTHF_CLIENT_AUDIO_STATE_DISCONNECTED = 0,
+  BTHF_CLIENT_AUDIO_STATE_CONNECTING,
+  BTHF_CLIENT_AUDIO_STATE_CONNECTED,
+  BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC,
+} bthf_client_audio_state_t;
+
+typedef enum {
+  BTHF_CLIENT_VR_STATE_STOPPED = 0,
+  BTHF_CLIENT_VR_STATE_STARTED
+} bthf_client_vr_state_t;
+
+typedef enum {
+  BTHF_CLIENT_VOLUME_TYPE_SPK = 0,
+  BTHF_CLIENT_VOLUME_TYPE_MIC
+} bthf_client_volume_type_t;
+
+typedef enum {
+  BTHF_CLIENT_NETWORK_STATE_NOT_AVAILABLE = 0,
+  BTHF_CLIENT_NETWORK_STATE_AVAILABLE
+} bthf_client_network_state_t;
+
+typedef enum {
+  BTHF_CLIENT_SERVICE_TYPE_HOME = 0,
+  BTHF_CLIENT_SERVICE_TYPE_ROAMING
+} bthf_client_service_type_t;
+
+typedef enum {
+  BTHF_CLIENT_CALL_STATE_ACTIVE = 0,
+  BTHF_CLIENT_CALL_STATE_HELD,
+  BTHF_CLIENT_CALL_STATE_DIALING,
+  BTHF_CLIENT_CALL_STATE_ALERTING,
+  BTHF_CLIENT_CALL_STATE_INCOMING,
+  BTHF_CLIENT_CALL_STATE_WAITING,
+  BTHF_CLIENT_CALL_STATE_HELD_BY_RESP_HOLD,
+} bthf_client_call_state_t;
+
+typedef enum {
+  BTHF_CLIENT_CALL_NO_CALLS_IN_PROGRESS = 0,
+  BTHF_CLIENT_CALL_CALLS_IN_PROGRESS
+} bthf_client_call_t;
+
+typedef enum {
+  BTHF_CLIENT_CALLSETUP_NONE = 0,
+  BTHF_CLIENT_CALLSETUP_INCOMING,
+  BTHF_CLIENT_CALLSETUP_OUTGOING,
+  BTHF_CLIENT_CALLSETUP_ALERTING
+
+} bthf_client_callsetup_t;
+
+typedef enum {
+  BTHF_CLIENT_CALLHELD_NONE = 0,
+  BTHF_CLIENT_CALLHELD_HOLD_AND_ACTIVE,
+  BTHF_CLIENT_CALLHELD_HOLD,
+} bthf_client_callheld_t;
+
+typedef enum {
+  BTHF_CLIENT_RESP_AND_HOLD_HELD = 0,
+  BTRH_CLIENT_RESP_AND_HOLD_ACCEPT,
+  BTRH_CLIENT_RESP_AND_HOLD_REJECT,
+} bthf_client_resp_and_hold_t;
+
+typedef enum {
+  BTHF_CLIENT_CALL_DIRECTION_OUTGOING = 0,
+  BTHF_CLIENT_CALL_DIRECTION_INCOMING
+} bthf_client_call_direction_t;
+
+typedef enum {
+  BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE = 0,
+  BTHF_CLIENT_CALL_MPTY_TYPE_MULTI
+} bthf_client_call_mpty_type_t;
+
+typedef enum {
+  BTHF_CLIENT_CMD_COMPLETE_OK = 0,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR_NO_CARRIER,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR_BUSY,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR_NO_ANSWER,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR_DELAYED,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR_BLACKLISTED,
+  BTHF_CLIENT_CMD_COMPLETE_ERROR_CME
+} bthf_client_cmd_complete_t;
+
+typedef enum {
+  BTHF_CLIENT_CALL_ACTION_CHLD_0 = 0,
+  BTHF_CLIENT_CALL_ACTION_CHLD_1,
+  BTHF_CLIENT_CALL_ACTION_CHLD_2,
+  BTHF_CLIENT_CALL_ACTION_CHLD_3,
+  BTHF_CLIENT_CALL_ACTION_CHLD_4,
+  BTHF_CLIENT_CALL_ACTION_CHLD_1x,
+  BTHF_CLIENT_CALL_ACTION_CHLD_2x,
+  BTHF_CLIENT_CALL_ACTION_ATA,
+  BTHF_CLIENT_CALL_ACTION_CHUP,
+  BTHF_CLIENT_CALL_ACTION_BTRH_0,
+  BTHF_CLIENT_CALL_ACTION_BTRH_1,
+  BTHF_CLIENT_CALL_ACTION_BTRH_2,
+} bthf_client_call_action_t;
+
+typedef enum {
+  BTHF_CLIENT_SERVICE_UNKNOWN = 0,
+  BTHF_CLIENT_SERVICE_VOICE,
+  BTHF_CLIENT_SERVICE_FAX
+} bthf_client_subscriber_service_type_t;
+
+typedef enum {
+  BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED = 0,
+  BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED,
+} bthf_client_in_band_ring_state_t;
+
+/* Peer features masks */
+#define BTHF_CLIENT_PEER_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTHF_CLIENT_PEER_FEAT_ECNR \
+  0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTHF_CLIENT_PEER_FEAT_VREC 0x00000004   /* Voice recognition */
+#define BTHF_CLIENT_PEER_FEAT_INBAND 0x00000008 /* In-band ring tone */
+#define BTHF_CLIENT_PEER_FEAT_VTAG \
+  0x00000010 /* Attach a phone number to a voice tag */
+#define BTHF_CLIENT_PEER_FEAT_REJECT \
+  0x00000020 /* Ability to reject incoming call */
+#define BTHF_CLIENT_PEER_FEAT_ECS 0x00000040    /* Enhanced Call Status */
+#define BTHF_CLIENT_PEER_FEAT_ECC 0x00000080    /* Enhanced Call Control */
+#define BTHF_CLIENT_PEER_FEAT_EXTERR 0x00000100 /* Extended error codes */
+#define BTHF_CLIENT_PEER_FEAT_CODEC 0x00000200  /* Codec Negotiation */
+
+/* Peer call handling features masks */
+#define BTHF_CLIENT_CHLD_FEAT_REL \
+  0x00000001 /* 0  Release waiting call or held calls */
+#define BTHF_CLIENT_CHLD_FEAT_REL_ACC                    \
+  0x00000002 /* 1  Release active calls and accept other \
+                   (waiting or held) cal */
+#define BTHF_CLIENT_CHLD_FEAT_REL_X \
+  0x00000004 /* 1x Release specified active call only */
+#define BTHF_CLIENT_CHLD_FEAT_HOLD_ACC                   \
+  0x00000008 /* 2  Active calls on hold and accept other \
+                   (waiting or held) call */
+#define BTHF_CLIENT_CHLD_FEAT_PRIV_X                   \
+  0x00000010 /* 2x Request private mode with specified \
+                   call (put the rest on hold) */
+#define BTHF_CLIENT_CHLD_FEAT_MERGE \
+  0x00000020 /* 3  Add held call to multiparty */
+#define BTHF_CLIENT_CHLD_FEAT_MERGE_DETACH     \
+  0x00000040 /* 4  Connect two calls and leave \
+                   (disconnect from) multiparty */
+
+/** Callback for connection state change.
+ *  state will have one of the values from BtHfConnectionState
+ *  peer/chld_features are valid only for
+ * BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED state
+ */
+typedef void (*bthf_client_connection_state_callback)(
+    const RawAddress* bd_addr, bthf_client_connection_state_t state,
+    unsigned int peer_feat, unsigned int chld_feat);
+
+/** Callback for audio connection state change.
+ *  state will have one of the values from BtHfAudioState
+ */
+typedef void (*bthf_client_audio_state_callback)(
+    const RawAddress* bd_addr, bthf_client_audio_state_t state);
+
+/** Callback for VR connection state change.
+ *  state will have one of the values from BtHfVRState
+ */
+typedef void (*bthf_client_vr_cmd_callback)(const RawAddress* bd_addr,
+                                            bthf_client_vr_state_t state);
+
+/** Callback for network state change
+ */
+typedef void (*bthf_client_network_state_callback)(
+    const RawAddress* bd_addr, bthf_client_network_state_t state);
+
+/** Callback for network roaming status change
+ */
+typedef void (*bthf_client_network_roaming_callback)(
+    const RawAddress* bd_addr, bthf_client_service_type_t type);
+
+/** Callback for signal strength indication
+ */
+typedef void (*bthf_client_network_signal_callback)(const RawAddress* bd_addr,
+                                                    int signal_strength);
+
+/** Callback for battery level indication
+ */
+typedef void (*bthf_client_battery_level_callback)(const RawAddress* bd_addr,
+                                                   int battery_level);
+
+/** Callback for current operator name
+ */
+typedef void (*bthf_client_current_operator_callback)(const RawAddress* bd_addr,
+                                                      const char* name);
+
+/** Callback for call indicator
+ */
+typedef void (*bthf_client_call_callback)(const RawAddress* bd_addr,
+                                          bthf_client_call_t call);
+
+/** Callback for callsetup indicator
+ */
+typedef void (*bthf_client_callsetup_callback)(
+    const RawAddress* bd_addr, bthf_client_callsetup_t callsetup);
+
+/** Callback for callheld indicator
+ */
+typedef void (*bthf_client_callheld_callback)(const RawAddress* bd_addr,
+                                              bthf_client_callheld_t callheld);
+
+/** Callback for response and hold
+ */
+typedef void (*bthf_client_resp_and_hold_callback)(
+    const RawAddress* bd_addr, bthf_client_resp_and_hold_t resp_and_hold);
+
+/** Callback for Calling Line Identification notification
+ *  Will be called only when there is an incoming call and number is provided.
+ */
+typedef void (*bthf_client_clip_callback)(const RawAddress* bd_addr,
+                                          const char* number);
+
+/**
+ * Callback for Call Waiting notification
+ */
+typedef void (*bthf_client_call_waiting_callback)(const RawAddress* bd_addr,
+                                                  const char* number);
+
+/**
+ *  Callback for listing current calls. Can be called multiple time.
+ *  If number is unknown NULL is passed.
+ */
+typedef void (*bthf_client_current_calls)(const RawAddress* bd_addr, int index,
+                                          bthf_client_call_direction_t dir,
+                                          bthf_client_call_state_t state,
+                                          bthf_client_call_mpty_type_t mpty,
+                                          const char* number);
+
+/** Callback for audio volume change
+ */
+typedef void (*bthf_client_volume_change_callback)(
+    const RawAddress* bd_addr, bthf_client_volume_type_t type, int volume);
+
+/** Callback for command complete event
+ *  cme is valid only for BTHF_CLIENT_CMD_COMPLETE_ERROR_CME type
+ */
+typedef void (*bthf_client_cmd_complete_callback)(
+    const RawAddress* bd_addr, bthf_client_cmd_complete_t type, int cme);
+
+/** Callback for subscriber information
+ */
+typedef void (*bthf_client_subscriber_info_callback)(
+    const RawAddress* bd_addr, const char* name,
+    bthf_client_subscriber_service_type_t type);
+
+/** Callback for in-band ring tone settings
+ */
+typedef void (*bthf_client_in_band_ring_tone_callback)(
+    const RawAddress* bd_addr, bthf_client_in_band_ring_state_t state);
+
+/**
+ * Callback for requested number from AG
+ */
+typedef void (*bthf_client_last_voice_tag_number_callback)(
+    const RawAddress* bd_addr, const char* number);
+
+/**
+ * Callback for sending ring indication to app
+ */
+typedef void (*bthf_client_ring_indication_callback)(const RawAddress* bd_addr);
+
+/** BT-HF callback structure. */
+typedef struct {
+  /** set to sizeof(BtHfClientCallbacks) */
+  size_t size;
+  bthf_client_connection_state_callback connection_state_cb;
+  bthf_client_audio_state_callback audio_state_cb;
+  bthf_client_vr_cmd_callback vr_cmd_cb;
+  bthf_client_network_state_callback network_state_cb;
+  bthf_client_network_roaming_callback network_roaming_cb;
+  bthf_client_network_signal_callback network_signal_cb;
+  bthf_client_battery_level_callback battery_level_cb;
+  bthf_client_current_operator_callback current_operator_cb;
+  bthf_client_call_callback call_cb;
+  bthf_client_callsetup_callback callsetup_cb;
+  bthf_client_callheld_callback callheld_cb;
+  bthf_client_resp_and_hold_callback resp_and_hold_cb;
+  bthf_client_clip_callback clip_cb;
+  bthf_client_call_waiting_callback call_waiting_cb;
+  bthf_client_current_calls current_calls_cb;
+  bthf_client_volume_change_callback volume_change_cb;
+  bthf_client_cmd_complete_callback cmd_complete_cb;
+  bthf_client_subscriber_info_callback subscriber_info_cb;
+  bthf_client_in_band_ring_tone_callback in_band_ring_tone_cb;
+  bthf_client_last_voice_tag_number_callback last_voice_tag_number_callback;
+  bthf_client_ring_indication_callback ring_indication_cb;
+} bthf_client_callbacks_t;
+
+/** Represents the standard BT-HF interface. */
+typedef struct {
+  /** set to sizeof(BtHfClientInterface) */
+  size_t size;
+  /**
+   * Register the BtHf callbacks
+   */
+  bt_status_t (*init)(bthf_client_callbacks_t* callbacks);
+
+  /** connect to audio gateway */
+  bt_status_t (*connect)(RawAddress* bd_addr);
+
+  /** disconnect from audio gateway */
+  bt_status_t (*disconnect)(const RawAddress* bd_addr);
+
+  /** create an audio connection */
+  bt_status_t (*connect_audio)(const RawAddress* bd_addr);
+
+  /** close the audio connection */
+  bt_status_t (*disconnect_audio)(const RawAddress* bd_addr);
+
+  /** start voice recognition */
+  bt_status_t (*start_voice_recognition)(const RawAddress* bd_addr);
+
+  /** stop voice recognition */
+  bt_status_t (*stop_voice_recognition)(const RawAddress* bd_addr);
+
+  /** volume control */
+  bt_status_t (*volume_control)(const RawAddress* bd_addr,
+                                bthf_client_volume_type_t type, int volume);
+
+  /** place a call with number a number
+   * if number is NULL last called number is called (aka re-dial)*/
+  bt_status_t (*dial)(const RawAddress* bd_addr, const char* number);
+
+  /** place a call with number specified by location (speed dial) */
+  bt_status_t (*dial_memory)(const RawAddress* bd_addr, int location);
+
+  /** perform specified call related action
+   * idx is limited only for enhanced call control related action
+   */
+  bt_status_t (*handle_call_action)(const RawAddress* bd_addr,
+                                    bthf_client_call_action_t action, int idx);
+
+  /** query list of current calls */
+  bt_status_t (*query_current_calls)(const RawAddress* bd_addr);
+
+  /** query name of current selected operator */
+  bt_status_t (*query_current_operator_name)(const RawAddress* bd_addr);
+
+  /** Retrieve subscriber information */
+  bt_status_t (*retrieve_subscriber_info)(const RawAddress* bd_addr);
+
+  /** Send DTMF code*/
+  bt_status_t (*send_dtmf)(const RawAddress* bd_addr, char code);
+
+  /** Request a phone number from AG corresponding to last voice tag recorded */
+  bt_status_t (*request_last_voice_tag_number)(const RawAddress* bd_addr);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+
+  /** Send AT Command. */
+  bt_status_t (*send_at_cmd)(const RawAddress* bd_addr, int cmd, int val1,
+                             int val2, const char* arg);
+} bthf_client_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HF_CLIENT_H */
diff --git a/include/hardware/bt_hh.h b/include/hardware/bt_hh.h
new file mode 100644
index 0000000..b87b129
--- /dev/null
+++ b/include/hardware/bt_hh.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HH_H
+#define ANDROID_INCLUDE_BT_HH_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+#define BTHH_MAX_DSC_LEN 884
+
+/* HH connection states */
+typedef enum {
+  BTHH_CONN_STATE_CONNECTED = 0,
+  BTHH_CONN_STATE_CONNECTING,
+  BTHH_CONN_STATE_DISCONNECTED,
+  BTHH_CONN_STATE_DISCONNECTING,
+  BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST,
+  BTHH_CONN_STATE_FAILED_KBD_FROM_HOST,
+  BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES,
+  BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER,
+  BTHH_CONN_STATE_FAILED_GENERIC,
+  BTHH_CONN_STATE_UNKNOWN
+} bthh_connection_state_t;
+
+typedef enum {
+  BTHH_OK = 0,
+  BTHH_HS_HID_NOT_READY,  /* handshake error : device not ready */
+  BTHH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */
+  BTHH_HS_TRANS_NOT_SPT,  /* handshake error : transaction not spt */
+  BTHH_HS_INVALID_PARAM,  /* handshake error : invalid paremter */
+  BTHH_HS_ERROR,          /* handshake error : unspecified HS error */
+  BTHH_ERR,               /* general BTA HH error */
+  BTHH_ERR_SDP,           /* SDP error */
+  BTHH_ERR_PROTO,         /* SET_Protocol error,
+                                                        only used in BTA_HH_OPEN_EVT
+                             callback */
+  BTHH_ERR_DB_FULL,       /* device database full error, used  */
+  BTHH_ERR_TOD_UNSPT,     /* type of device not supported */
+  BTHH_ERR_NO_RES,        /* out of system resources */
+  BTHH_ERR_AUTH_FAILED,   /* authentication fail */
+  BTHH_ERR_HDL
+} bthh_status_t;
+
+/* Protocol modes */
+typedef enum {
+  BTHH_REPORT_MODE = 0x00,
+  BTHH_BOOT_MODE = 0x01,
+  BTHH_UNSUPPORTED_MODE = 0xff
+} bthh_protocol_mode_t;
+
+/* Report types */
+typedef enum {
+  BTHH_INPUT_REPORT = 1,
+  BTHH_OUTPUT_REPORT,
+  BTHH_FEATURE_REPORT
+} bthh_report_type_t;
+
+typedef struct {
+  int attr_mask;
+  uint8_t sub_class;
+  uint8_t app_id;
+  int vendor_id;
+  int product_id;
+  int version;
+  uint8_t ctry_code;
+  int dl_len;
+  uint8_t dsc_list[BTHH_MAX_DSC_LEN];
+} bthh_hid_info_t;
+
+/** Callback for connection state change.
+ *  state will have one of the values from bthh_connection_state_t
+ */
+typedef void (*bthh_connection_state_callback)(RawAddress* bd_addr,
+                                               bthh_connection_state_t state);
+
+/** Callback for vitual unplug api.
+ *  the status of the vitual unplug
+ */
+typedef void (*bthh_virtual_unplug_callback)(RawAddress* bd_addr,
+                                             bthh_status_t hh_status);
+
+/** Callback for get hid info
+ *  hid_info will contain attr_mask, sub_class, app_id, vendor_id, product_id,
+ * version, ctry_code, len
+ */
+typedef void (*bthh_hid_info_callback)(RawAddress* bd_addr,
+                                       bthh_hid_info_t hid_info);
+
+/** Callback for get protocol api.
+ *  the protocol mode is one of the value from bthh_protocol_mode_t
+ */
+typedef void (*bthh_protocol_mode_callback)(RawAddress* bd_addr,
+                                            bthh_status_t hh_status,
+                                            bthh_protocol_mode_t mode);
+
+/** Callback for get/set_idle_time api.
+ */
+typedef void (*bthh_idle_time_callback)(RawAddress* bd_addr,
+                                        bthh_status_t hh_status, int idle_rate);
+
+/** Callback for get report api.
+ *  if staus is ok rpt_data contains the report data
+ */
+typedef void (*bthh_get_report_callback)(RawAddress* bd_addr,
+                                         bthh_status_t hh_status,
+                                         uint8_t* rpt_data, int rpt_size);
+
+/** Callback for set_report/set_protocol api and if error
+ *  occurs for get_report/get_protocol api.
+ */
+typedef void (*bthh_handshake_callback)(RawAddress* bd_addr,
+                                        bthh_status_t hh_status);
+
+/** BT-HH callback structure. */
+typedef struct {
+  /** set to sizeof(BtHfCallbacks) */
+  size_t size;
+  bthh_connection_state_callback connection_state_cb;
+  bthh_hid_info_callback hid_info_cb;
+  bthh_protocol_mode_callback protocol_mode_cb;
+  bthh_idle_time_callback idle_time_cb;
+  bthh_get_report_callback get_report_cb;
+  bthh_virtual_unplug_callback virtual_unplug_cb;
+  bthh_handshake_callback handshake_cb;
+
+} bthh_callbacks_t;
+
+/** Represents the standard BT-HH interface. */
+typedef struct {
+  /** set to sizeof(BtHhInterface) */
+  size_t size;
+
+  /**
+   * Register the BtHh callbacks
+   */
+  bt_status_t (*init)(bthh_callbacks_t* callbacks);
+
+  /** connect to hid device */
+  bt_status_t (*connect)(RawAddress* bd_addr);
+
+  /** dis-connect from hid device */
+  bt_status_t (*disconnect)(RawAddress* bd_addr);
+
+  /** Virtual UnPlug (VUP) the specified HID device */
+  bt_status_t (*virtual_unplug)(RawAddress* bd_addr);
+
+  /** Set the HID device descriptor for the specified HID device. */
+  bt_status_t (*set_info)(RawAddress* bd_addr, bthh_hid_info_t hid_info);
+
+  /** Get the HID proto mode. */
+  bt_status_t (*get_protocol)(RawAddress* bd_addr,
+                              bthh_protocol_mode_t protocolMode);
+
+  /** Set the HID proto mode. */
+  bt_status_t (*set_protocol)(RawAddress* bd_addr,
+                              bthh_protocol_mode_t protocolMode);
+
+  /** Get the HID Idle Time */
+  bt_status_t (*get_idle_time)(RawAddress* bd_addr);
+
+  /** Set the HID Idle Time */
+  bt_status_t (*set_idle_time)(RawAddress* bd_addr, uint8_t idleTime);
+
+  /** Send a GET_REPORT to HID device. */
+  bt_status_t (*get_report)(RawAddress* bd_addr, bthh_report_type_t reportType,
+                            uint8_t reportId, int bufferSize);
+
+  /** Send a SET_REPORT to HID device. */
+  bt_status_t (*set_report)(RawAddress* bd_addr, bthh_report_type_t reportType,
+                            char* report);
+
+  /** Send data to HID device. */
+  bt_status_t (*send_data)(RawAddress* bd_addr, char* data);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+
+} bthh_interface_t;
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HH_H */
diff --git a/include/hardware/bt_hl.h b/include/hardware/bt_hl.h
new file mode 100644
index 0000000..682605b
--- /dev/null
+++ b/include/hardware/bt_hl.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_HL_H
+#define ANDROID_INCLUDE_BT_HL_H
+
+__BEGIN_DECLS
+
+/* HL connection states */
+
+typedef enum { BTHL_MDEP_ROLE_SOURCE, BTHL_MDEP_ROLE_SINK } bthl_mdep_role_t;
+
+typedef enum {
+  BTHL_APP_REG_STATE_REG_SUCCESS,
+  BTHL_APP_REG_STATE_REG_FAILED,
+  BTHL_APP_REG_STATE_DEREG_SUCCESS,
+  BTHL_APP_REG_STATE_DEREG_FAILED
+} bthl_app_reg_state_t;
+
+typedef enum {
+  BTHL_CHANNEL_TYPE_RELIABLE,
+  BTHL_CHANNEL_TYPE_STREAMING,
+  BTHL_CHANNEL_TYPE_ANY
+} bthl_channel_type_t;
+
+/* HL connection states */
+typedef enum {
+  BTHL_CONN_STATE_CONNECTING,
+  BTHL_CONN_STATE_CONNECTED,
+  BTHL_CONN_STATE_DISCONNECTING,
+  BTHL_CONN_STATE_DISCONNECTED,
+  BTHL_CONN_STATE_DESTROYED
+} bthl_channel_state_t;
+
+typedef struct {
+  bthl_mdep_role_t mdep_role;
+  int data_type;
+  bthl_channel_type_t channel_type;
+  const char* mdep_description; /* MDEP description to be used in the SDP
+                                   (optional); null terminated */
+} bthl_mdep_cfg_t;
+
+typedef struct {
+  const char* application_name;
+  const char*
+      provider_name;    /* provider name to be used in the SDP (optional); null
+                           terminated */
+  const char* srv_name; /* service name to be used in the SDP (optional); null
+                           terminated*/
+  const char*
+      srv_desp; /* service description to be used in the SDP (optional); null
+                   terminated */
+  int number_of_mdeps;
+  bthl_mdep_cfg_t* mdep_cfg; /* Dynamic array */
+} bthl_reg_param_t;
+
+/** Callback for application registration status.
+ *  state will have one of the values from  bthl_app_reg_state_t
+ */
+typedef void (*bthl_app_reg_state_callback)(int app_id,
+                                            bthl_app_reg_state_t state);
+
+/** Callback for channel connection state change.
+ *  state will have one of the values from
+ *  bthl_connection_state_t and fd (file descriptor)
+ */
+typedef void (*bthl_channel_state_callback)(int app_id, RawAddress* bd_addr,
+                                            int mdep_cfg_index, int channel_id,
+                                            bthl_channel_state_t state, int fd);
+
+/** BT-HL callback structure. */
+typedef struct {
+  /** set to sizeof(bthl_callbacks_t) */
+  size_t size;
+  bthl_app_reg_state_callback app_reg_state_cb;
+  bthl_channel_state_callback channel_state_cb;
+} bthl_callbacks_t;
+
+/** Represents the standard BT-HL interface. */
+typedef struct {
+  /** set to sizeof(bthl_interface_t)  */
+  size_t size;
+
+  /**
+   * Register the Bthl callbacks
+   */
+  bt_status_t (*init)(bthl_callbacks_t* callbacks);
+
+  /** Register HL application */
+  bt_status_t (*register_application)(bthl_reg_param_t* p_reg_param,
+                                      int* app_id);
+
+  /** Unregister HL application */
+  bt_status_t (*unregister_application)(int app_id);
+
+  /** connect channel */
+  bt_status_t (*connect_channel)(int app_id, RawAddress* bd_addr,
+                                 int mdep_cfg_index, int* channel_id);
+
+  /** destroy channel */
+  bt_status_t (*destroy_channel)(int channel_id);
+
+  /** Close the  Bthl callback **/
+  void (*cleanup)(void);
+
+} bthl_interface_t;
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HL_H */
diff --git a/include/hardware/bt_mce.h b/include/hardware/bt_mce.h
new file mode 100644
index 0000000..0bb15d4
--- /dev/null
+++ b/include/hardware/bt_mce.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_MCE_H
+#define ANDROID_INCLUDE_BT_MCE_H
+
+__BEGIN_DECLS
+
+/** MAS instance description */
+typedef struct {
+  int id;
+  int scn;
+  int msg_types;
+  char* p_name;
+} btmce_mas_instance_t;
+
+/** callback for get_remote_mas_instances */
+typedef void (*btmce_remote_mas_instances_callback)(
+    bt_status_t status, RawAddress* bd_addr, int num_instances,
+    btmce_mas_instance_t* instances);
+
+typedef struct {
+  /** set to sizeof(btmce_callbacks_t) */
+  size_t size;
+  btmce_remote_mas_instances_callback remote_mas_instances_cb;
+} btmce_callbacks_t;
+
+typedef struct {
+  /** set to size of this struct */
+  size_t size;
+
+  /** register BT MCE callbacks */
+  bt_status_t (*init)(btmce_callbacks_t* callbacks);
+
+  /** search for MAS instances on remote device */
+  bt_status_t (*get_remote_mas_instances)(RawAddress* bd_addr);
+} btmce_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_MCE_H */
diff --git a/include/hardware/bt_pan.h b/include/hardware/bt_pan.h
new file mode 100644
index 0000000..90caa5d
--- /dev/null
+++ b/include/hardware/bt_pan.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_PAN_H
+#define ANDROID_INCLUDE_BT_PAN_H
+
+__BEGIN_DECLS
+
+#define BTPAN_ROLE_NONE 0
+#define BTPAN_ROLE_PANNAP 1
+#define BTPAN_ROLE_PANU 2
+
+typedef enum {
+  BTPAN_STATE_CONNECTED = 0,
+  BTPAN_STATE_CONNECTING = 1,
+  BTPAN_STATE_DISCONNECTED = 2,
+  BTPAN_STATE_DISCONNECTING = 3
+} btpan_connection_state_t;
+
+typedef enum {
+  BTPAN_STATE_ENABLED = 0,
+  BTPAN_STATE_DISABLED = 1
+} btpan_control_state_t;
+
+/**
+ * Callback for pan connection state
+ */
+typedef void (*btpan_connection_state_callback)(btpan_connection_state_t state,
+                                                bt_status_t error,
+                                                const RawAddress* bd_addr,
+                                                int local_role,
+                                                int remote_role);
+typedef void (*btpan_control_state_callback)(btpan_control_state_t state,
+                                             int local_role, bt_status_t error,
+                                             const char* ifname);
+
+typedef struct {
+  size_t size;
+  btpan_control_state_callback control_state_cb;
+  btpan_connection_state_callback connection_state_cb;
+} btpan_callbacks_t;
+typedef struct {
+  /** set to size of this struct*/
+  size_t size;
+  /**
+   * Initialize the pan interface and register the btpan callbacks
+   */
+  bt_status_t (*init)(const btpan_callbacks_t* callbacks);
+  /*
+   * enable the pan service by specified role. The result state of
+   * enabl will be returned by btpan_control_state_callback. when pan-nap is
+   * enabled, the state of connecting panu device will be notified by
+   * btpan_connection_state_callback
+   */
+  bt_status_t (*enable)(int local_role);
+  /*
+   * get current pan local role
+   */
+  int (*get_local_role)(void);
+  /**
+   * start bluetooth pan connection to the remote device by specified pan role.
+   * The result state will be returned by btpan_connection_state_callback
+   */
+  bt_status_t (*connect)(const RawAddress* bd_addr, int local_role,
+                         int remote_role);
+  /**
+   * stop bluetooth pan connection. The result state will be returned by
+   * btpan_connection_state_callback
+   */
+  bt_status_t (*disconnect)(const RawAddress* bd_addr);
+
+  /**
+   * Cleanup the pan interface
+   */
+  void (*cleanup)(void);
+
+} btpan_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_PAN_H */
diff --git a/include/hardware/bt_rc.h b/include/hardware/bt_rc.h
new file mode 100644
index 0000000..9349eed
--- /dev/null
+++ b/include/hardware/bt_rc.h
@@ -0,0 +1,709 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ANDROID_INCLUDE_BT_RC_H
+#define ANDROID_INCLUDE_BT_RC_H
+
+__BEGIN_DECLS
+
+/* Change this macro to use multiple RC */
+#define BT_RC_NUM_APP 6
+
+/* Macros */
+#define BTRC_MAX_ATTR_STR_LEN (1 << 16)
+#define BTRC_UID_SIZE 8
+#define BTRC_MAX_APP_SETTINGS 8
+#define BTRC_MAX_FOLDER_DEPTH 4
+#define BTRC_MAX_APP_ATTR_SIZE 16
+#define BTRC_MAX_ELEM_ATTR_SIZE 8
+#define BTRC_FEATURE_BIT_MASK_SIZE 16
+
+/* Macros for valid scopes in get_folder_items */
+#define BTRC_SCOPE_PLAYER_LIST 0x00 /* Media Player List */
+#define BTRC_SCOPE_FILE_SYSTEM 0x01 /* Virtual File System */
+#define BTRC_SCOPE_SEARCH 0x02      /* Search */
+#define BTRC_SCOPE_NOW_PLAYING 0x03 /* Now Playing */
+
+/* Macros for supported character encoding */
+#define BTRC_CHARSET_ID_UTF8 0x006A
+
+/* Macros for item types */
+#define BTRC_ITEM_PLAYER 0x01 /* Media Player */
+#define BTRC_ITEM_FOLDER 0x02 /* Folder */
+#define BTRC_ITEM_MEDIA 0x03  /* Media File */
+
+/* Macros for media attribute IDs */
+#define BTRC_MEDIA_ATTR_ID_INVALID -1
+#define BTRC_MEDIA_ATTR_ID_TITLE 0x00000001
+#define BTRC_MEDIA_ATTR_ID_ARTIST 0x00000002
+#define BTRC_MEDIA_ATTR_ID_ALBUM 0x00000003
+#define BTRC_MEDIA_ATTR_ID_TRACK_NUM 0x00000004
+#define BTRC_MEDIA_ATTR_ID_NUM_TRACKS 0x00000005
+#define BTRC_MEDIA_ATTR_ID_GENRE 0x00000006
+#define BTRC_MEDIA_ATTR_ID_PLAYING_TIME 0x00000007 /* in miliseconds */
+
+/* Macros for folder types */
+#define BTRC_FOLDER_TYPE_MIXED 0x00
+#define BTRC_FOLDER_TYPE_TITLES 0x01
+#define BTRC_FOLDER_TYPE_ALBUMS 0x02
+#define BTRC_FOLDER_TYPE_ARTISTS 0x03
+#define BTRC_FOLDER_TYPE_GENRES 0x04
+#define BTRC_FOLDER_TYPE_PLAYLISTS 0x05
+#define BTRC_FOLDER_TYPE_YEARS 0x06
+
+/* Macros for media types */
+#define BTRC_MEDIA_TYPE_AUDIO 0x00 /* audio */
+#define BTRC_MEDIA_TYPE_VIDEO 0x01 /* video */
+
+/* Macros for num attributes */
+#define BTRC_NUM_ATTR_NONE 0xFF /* No attributes required */
+#define BTRC_NUM_ATTR_ALL 0X00  /* All attributes required */
+
+#define BTRC_HANDLE_NONE 0xFF
+
+typedef uint8_t btrc_uid_t[BTRC_UID_SIZE];
+
+typedef enum {
+  BTRC_CONNECTION_STATE_DISCONNECTED = 0,
+  BTRC_CONNECTION_STATE_CONNECTED
+} btrc_connection_state_t;
+
+typedef enum {
+  BTRC_FEAT_NONE = 0x00,            /* AVRCP 1.0 */
+  BTRC_FEAT_METADATA = 0x01,        /* AVRCP 1.3 */
+  BTRC_FEAT_ABSOLUTE_VOLUME = 0x02, /* Supports TG role and volume sync */
+  BTRC_FEAT_BROWSE = 0x04, /* AVRCP 1.4 and up, with Browsing support */
+} btrc_remote_features_t;
+
+typedef enum {
+  BTRC_PLAYSTATE_STOPPED = 0x00,  /* Stopped */
+  BTRC_PLAYSTATE_PLAYING = 0x01,  /* Playing */
+  BTRC_PLAYSTATE_PAUSED = 0x02,   /* Paused  */
+  BTRC_PLAYSTATE_FWD_SEEK = 0x03, /* Fwd Seek*/
+  BTRC_PLAYSTATE_REV_SEEK = 0x04, /* Rev Seek*/
+  BTRC_PLAYSTATE_ERROR = 0xFF,    /* Error   */
+} btrc_play_status_t;
+
+typedef enum {
+  BTRC_EVT_PLAY_STATUS_CHANGED = 0x01,
+  BTRC_EVT_TRACK_CHANGE = 0x02,
+  BTRC_EVT_TRACK_REACHED_END = 0x03,
+  BTRC_EVT_TRACK_REACHED_START = 0x04,
+  BTRC_EVT_PLAY_POS_CHANGED = 0x05,
+  BTRC_EVT_APP_SETTINGS_CHANGED = 0x08,
+  BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED = 0x09,
+  BTRC_EVT_AVAL_PLAYER_CHANGE = 0x0a,
+  BTRC_EVT_ADDR_PLAYER_CHANGE = 0x0b,
+  BTRC_EVT_UIDS_CHANGED = 0x0c,
+  BTRC_EVT_VOL_CHANGED = 0x0d,
+} btrc_event_id_t;
+
+typedef enum {
+  BTRC_NOTIFICATION_TYPE_INTERIM = 0,
+  BTRC_NOTIFICATION_TYPE_CHANGED = 1,
+} btrc_notification_type_t;
+
+typedef enum {
+  BTRC_PLAYER_ATTR_EQUALIZER = 0x01,
+  BTRC_PLAYER_ATTR_REPEAT = 0x02,
+  BTRC_PLAYER_ATTR_SHUFFLE = 0x03,
+  BTRC_PLAYER_ATTR_SCAN = 0x04,
+} btrc_player_attr_t;
+
+typedef enum {
+  BTRC_MEDIA_ATTR_TITLE = 0x01,
+  BTRC_MEDIA_ATTR_ARTIST = 0x02,
+  BTRC_MEDIA_ATTR_ALBUM = 0x03,
+  BTRC_MEDIA_ATTR_TRACK_NUM = 0x04,
+  BTRC_MEDIA_ATTR_NUM_TRACKS = 0x05,
+  BTRC_MEDIA_ATTR_GENRE = 0x06,
+  BTRC_MEDIA_ATTR_PLAYING_TIME = 0x07,
+} btrc_media_attr_t;
+
+typedef enum {
+  BTRC_PLAYER_VAL_OFF_REPEAT = 0x01,
+  BTRC_PLAYER_VAL_SINGLE_REPEAT = 0x02,
+  BTRC_PLAYER_VAL_ALL_REPEAT = 0x03,
+  BTRC_PLAYER_VAL_GROUP_REPEAT = 0x04
+} btrc_player_repeat_val_t;
+
+typedef enum {
+  BTRC_PLAYER_VAL_OFF_SHUFFLE = 0x01,
+  BTRC_PLAYER_VAL_ALL_SHUFFLE = 0x02,
+  BTRC_PLAYER_VAL_GROUP_SHUFFLE = 0x03
+} btrc_player_shuffle_val_t;
+
+typedef enum {
+  BTRC_STS_BAD_CMD = 0x00,       /* Invalid command */
+  BTRC_STS_BAD_PARAM = 0x01,     /* Invalid parameter */
+  BTRC_STS_NOT_FOUND = 0x02,     /* Specified parameter is wrong or not found */
+  BTRC_STS_INTERNAL_ERR = 0x03,  /* Internal Error */
+  BTRC_STS_NO_ERROR = 0x04,      /* Operation Success */
+  BTRC_STS_UID_CHANGED = 0x05,   /* UIDs changed */
+  BTRC_STS_RESERVED = 0x06,      /* Reserved */
+  BTRC_STS_INV_DIRN = 0x07,      /* Invalid direction */
+  BTRC_STS_INV_DIRECTORY = 0x08, /* Invalid directory */
+  BTRC_STS_INV_ITEM = 0x09,      /* Invalid Item */
+  BTRC_STS_INV_SCOPE = 0x0a,     /* Invalid scope */
+  BTRC_STS_INV_RANGE = 0x0b,     /* Invalid range */
+  BTRC_STS_DIRECTORY = 0x0c,     /* UID is a directory */
+  BTRC_STS_MEDIA_IN_USE = 0x0d,  /* Media in use */
+  BTRC_STS_PLAY_LIST_FULL = 0x0e, /* Playing list full */
+  BTRC_STS_SRCH_NOT_SPRTD = 0x0f, /* Search not supported */
+  BTRC_STS_SRCH_IN_PROG = 0x10,   /* Search in progress */
+  BTRC_STS_INV_PLAYER = 0x11,     /* Invalid player */
+  BTRC_STS_PLAY_NOT_BROW = 0x12,  /* Player not browsable */
+  BTRC_STS_PLAY_NOT_ADDR = 0x13,  /* Player not addressed */
+  BTRC_STS_INV_RESULTS = 0x14,    /* Invalid results */
+  BTRC_STS_NO_AVBL_PLAY = 0x15,   /* No available players */
+  BTRC_STS_ADDR_PLAY_CHGD = 0x16, /* Addressed player changed */
+} btrc_status_t;
+
+typedef struct {
+  uint16_t player_id;
+  uint16_t uid_counter;
+} btrc_addr_player_changed_t;
+
+typedef struct {
+  uint8_t num_attr;
+  uint8_t attr_ids[BTRC_MAX_APP_SETTINGS];
+  uint8_t attr_values[BTRC_MAX_APP_SETTINGS];
+} btrc_player_settings_t;
+
+typedef struct {
+  uint8_t val;
+  uint16_t charset_id;
+  uint16_t str_len;
+  uint8_t* p_str;
+} btrc_player_app_ext_attr_val_t;
+
+typedef struct {
+  uint8_t attr_id;
+  uint16_t charset_id;
+  uint16_t str_len;
+  uint8_t* p_str;
+  uint8_t num_val;
+  btrc_player_app_ext_attr_val_t ext_attr_val[BTRC_MAX_APP_ATTR_SIZE];
+} btrc_player_app_ext_attr_t;
+
+typedef struct {
+  uint8_t attr_id;
+  uint8_t num_val;
+  uint8_t attr_val[BTRC_MAX_APP_ATTR_SIZE];
+} btrc_player_app_attr_t;
+
+typedef struct {
+  uint32_t start_item;
+  uint32_t end_item;
+  uint32_t size;
+  uint32_t attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+  uint8_t attr_count;
+} btrc_getfolderitem_t;
+
+typedef struct {
+  uint16_t type;
+  uint16_t uid_counter;
+} btrc_uids_changed_t;
+
+typedef struct { uint16_t type; } btrc_now_playing_changed_t;
+
+typedef union {
+  btrc_play_status_t play_status;
+  btrc_uid_t track; /* queue position in NowPlaying */
+  uint32_t song_pos;
+  uint16_t uid_counter;
+  btrc_player_settings_t player_setting;
+  btrc_addr_player_changed_t addr_player_changed;
+  btrc_uids_changed_t uids_changed;
+  btrc_now_playing_changed_t now_playing_changed;
+} btrc_register_notification_t;
+
+typedef struct {
+  uint8_t id; /* can be attr_id or value_id */
+  uint8_t text[BTRC_MAX_ATTR_STR_LEN];
+} btrc_player_setting_text_t;
+
+typedef struct {
+  uint32_t attr_id;
+  uint8_t text[BTRC_MAX_ATTR_STR_LEN];
+} btrc_element_attr_val_t;
+
+typedef struct {
+  uint16_t player_id;
+  uint8_t major_type;
+  uint32_t sub_type;
+  uint8_t play_status;
+  uint8_t features[BTRC_FEATURE_BIT_MASK_SIZE];
+  uint16_t charset_id;
+  uint8_t name[BTRC_MAX_ATTR_STR_LEN];
+} btrc_item_player_t;
+
+typedef struct {
+  uint8_t uid[BTRC_UID_SIZE];
+  uint8_t type;
+  uint8_t playable;
+  uint16_t charset_id;
+  uint8_t name[BTRC_MAX_ATTR_STR_LEN];
+} btrc_item_folder_t;
+
+typedef struct {
+  uint8_t uid[BTRC_UID_SIZE];
+  uint8_t type;
+  uint16_t charset_id;
+  uint8_t name[BTRC_MAX_ATTR_STR_LEN];
+  int num_attrs;
+  btrc_element_attr_val_t* p_attrs;
+} btrc_item_media_t;
+
+typedef struct {
+  uint8_t item_type;
+  union {
+    btrc_item_player_t player;
+    btrc_item_folder_t folder;
+    btrc_item_media_t media;
+  };
+} btrc_folder_items_t;
+
+typedef struct {
+  uint16_t str_len;
+  uint8_t p_str[BTRC_MAX_ATTR_STR_LEN];
+} btrc_br_folder_name_t;
+
+/** Callback for the controller's supported feautres */
+typedef void (*btrc_remote_features_callback)(const RawAddress& bd_addr,
+                                              btrc_remote_features_t features);
+
+/** Callback for play status request */
+typedef void (*btrc_get_play_status_callback)(const RawAddress& bd_addr);
+
+/** Callback for list player application attributes (Shuffle, Repeat,...) */
+typedef void (*btrc_list_player_app_attr_callback)(const RawAddress& bd_addr);
+
+/** Callback for list player application attributes (Shuffle, Repeat,...) */
+typedef void (*btrc_list_player_app_values_callback)(btrc_player_attr_t attr_id,
+                                                     const RawAddress& bd_addr);
+
+/** Callback for getting the current player application settings value
+**  num_attr: specifies the number of attribute ids contained in p_attrs
+*/
+typedef void (*btrc_get_player_app_value_callback)(uint8_t num_attr,
+                                                   btrc_player_attr_t* p_attrs,
+                                                   const RawAddress& bd_addr);
+
+/** Callback for getting the player application settings attributes' text
+**  num_attr: specifies the number of attribute ids contained in p_attrs
+*/
+typedef void (*btrc_get_player_app_attrs_text_callback)(
+    uint8_t num_attr, btrc_player_attr_t* p_attrs, const RawAddress& bd_addr);
+
+/** Callback for getting the player application settings values' text
+**  num_attr: specifies the number of value ids contained in p_vals
+*/
+typedef void (*btrc_get_player_app_values_text_callback)(
+    uint8_t attr_id, uint8_t num_val, uint8_t* p_vals,
+    const RawAddress& bd_addr);
+
+/** Callback for setting the player application settings values */
+typedef void (*btrc_set_player_app_value_callback)(
+    btrc_player_settings_t* p_vals, const RawAddress& bd_addr);
+
+/** Callback to fetch the get element attributes of the current song
+**  num_attr: specifies the number of attributes requested in p_attrs
+*/
+typedef void (*btrc_get_element_attr_callback)(uint8_t num_attr,
+                                               btrc_media_attr_t* p_attrs,
+                                               const RawAddress& bd_addr);
+
+/** Callback for register notification (Play state change/track change/...)
+**  param: Is only valid if event_id is BTRC_EVT_PLAY_POS_CHANGED
+*/
+typedef void (*btrc_register_notification_callback)(btrc_event_id_t event_id,
+                                                    uint32_t param,
+                                                    const RawAddress& bd_addr);
+
+/* AVRCP 1.4 Enhancements */
+/** Callback for volume change on CT
+**  volume: Current volume setting on the CT (0-127)
+*/
+typedef void (*btrc_volume_change_callback)(uint8_t volume, uint8_t ctype,
+                                            const RawAddress& bd_addr);
+
+/** Callback for passthrough commands */
+typedef void (*btrc_passthrough_cmd_callback)(int id, int key_state,
+                                              const RawAddress& bd_addr);
+
+/** Callback for set addressed player response on TG **/
+typedef void (*btrc_set_addressed_player_callback)(uint16_t player_id,
+                                                   const RawAddress& bd_addr);
+
+/** Callback for set browsed player response on TG **/
+typedef void (*btrc_set_browsed_player_callback)(uint16_t player_id,
+                                                 const RawAddress& bd_addr);
+
+/** Callback for get folder items on TG
+**  num_attr: specifies the number of attributes requested in p_attr_ids
+*/
+typedef void (*btrc_get_folder_items_callback)(
+    uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
+    uint32_t* p_attr_ids, const RawAddress& bd_addr);
+
+/** Callback for changing browsed path on TG **/
+typedef void (*btrc_change_path_callback)(uint8_t direction,
+                                          uint8_t* folder_uid,
+                                          const RawAddress& bd_addr);
+
+/** Callback to fetch the get item attributes of the media item
+**  num_attr: specifies the number of attributes requested in p_attrs
+*/
+typedef void (*btrc_get_item_attr_callback)(uint8_t scope, uint8_t* uid,
+                                            uint16_t uid_counter,
+                                            uint8_t num_attr,
+                                            btrc_media_attr_t* p_attrs,
+                                            const RawAddress& bd_addr);
+
+/** Callback for play request for the media item indicated by an identifier */
+typedef void (*btrc_play_item_callback)(uint8_t scope, uint16_t uid_counter,
+                                        uint8_t* uid,
+                                        const RawAddress& bd_addr);
+
+/** Callback to fetch total number of items from a folder **/
+typedef void (*btrc_get_total_num_of_items_callback)(uint8_t scope,
+                                                     const RawAddress& bd_addr);
+
+/** Callback for conducting recursive search on a current browsed path for a
+ * specified string */
+typedef void (*btrc_search_callback)(uint16_t charset_id, uint16_t str_len,
+                                     uint8_t* p_str, const RawAddress& bd_addr);
+
+/** Callback to add a specified media item indicated by an identifier to now
+ * playing queue. */
+typedef void (*btrc_add_to_now_playing_callback)(uint8_t scope, uint8_t* uid,
+                                                 uint16_t uid_counter,
+                                                 const RawAddress& bd_addr);
+
+/** BT-RC Target callback structure. */
+typedef struct {
+  /** set to sizeof(BtRcCallbacks) */
+  size_t size;
+  btrc_remote_features_callback remote_features_cb;
+  btrc_get_play_status_callback get_play_status_cb;
+  btrc_list_player_app_attr_callback list_player_app_attr_cb;
+  btrc_list_player_app_values_callback list_player_app_values_cb;
+  btrc_get_player_app_value_callback get_player_app_value_cb;
+  btrc_get_player_app_attrs_text_callback get_player_app_attrs_text_cb;
+  btrc_get_player_app_values_text_callback get_player_app_values_text_cb;
+  btrc_set_player_app_value_callback set_player_app_value_cb;
+  btrc_get_element_attr_callback get_element_attr_cb;
+  btrc_register_notification_callback register_notification_cb;
+  btrc_volume_change_callback volume_change_cb;
+  btrc_passthrough_cmd_callback passthrough_cmd_cb;
+  btrc_set_addressed_player_callback set_addressed_player_cb;
+  btrc_set_browsed_player_callback set_browsed_player_cb;
+  btrc_get_folder_items_callback get_folder_items_cb;
+  btrc_change_path_callback change_path_cb;
+  btrc_get_item_attr_callback get_item_attr_cb;
+  btrc_play_item_callback play_item_cb;
+  btrc_get_total_num_of_items_callback get_total_num_of_items_cb;
+  btrc_search_callback search_cb;
+  btrc_add_to_now_playing_callback add_to_now_playing_cb;
+} btrc_callbacks_t;
+
+/** Represents the standard BT-RC AVRCP Target interface. */
+typedef struct {
+  /** set to sizeof(BtRcInterface) */
+  size_t size;
+  /**
+   * Register the BtRc callbacks
+   */
+  bt_status_t (*init)(btrc_callbacks_t* callbacks);
+
+  /** Respose to GetPlayStatus request. Contains the current
+  **  1. Play status
+  **  2. Song duration/length
+  **  3. Song position
+  */
+  bt_status_t (*get_play_status_rsp)(const RawAddress& bd_addr,
+                                     btrc_play_status_t play_status,
+                                     uint32_t song_len, uint32_t song_pos);
+
+  /** Lists the support player application attributes (Shuffle/Repeat/...)
+  **  num_attr: Specifies the number of attributes contained in the pointer
+  *p_attrs
+  */
+  bt_status_t (*list_player_app_attr_rsp)(const RawAddress& bd_addr,
+                                          int num_attr,
+                                          btrc_player_attr_t* p_attrs);
+
+  /** Lists the support player application attributes (Shuffle Off/On/Group)
+  **  num_val: Specifies the number of values contained in the pointer p_vals
+  */
+  bt_status_t (*list_player_app_value_rsp)(const RawAddress& bd_addr,
+                                           int num_val, uint8_t* p_vals);
+
+  /** Returns the current application attribute values for each of the specified
+   * attr_id */
+  bt_status_t (*get_player_app_value_rsp)(const RawAddress& bd_addr,
+                                          btrc_player_settings_t* p_vals);
+
+  /** Returns the application attributes text ("Shuffle"/"Repeat"/...)
+  **  num_attr: Specifies the number of attributes' text contained in the
+  *pointer p_attrs
+  */
+  bt_status_t (*get_player_app_attr_text_rsp)(
+      const RawAddress& bd_addr, int num_attr,
+      btrc_player_setting_text_t* p_attrs);
+
+  /** Returns the application attributes text ("Shuffle"/"Repeat"/...)
+  **  num_attr: Specifies the number of attribute values' text contained in the
+  *pointer p_vals
+  */
+  bt_status_t (*get_player_app_value_text_rsp)(
+      const RawAddress& bd_addr, int num_val,
+      btrc_player_setting_text_t* p_vals);
+
+  /** Returns the current songs' element attributes text
+   *("Title"/"Album"/"Artist")
+   **  num_attr: Specifies the number of attributes' text contained in the
+   *pointer p_attrs
+   */
+  bt_status_t (*get_element_attr_rsp)(const RawAddress& bd_addr,
+                                      uint8_t num_attr,
+                                      btrc_element_attr_val_t* p_attrs);
+
+  /** Response to set player attribute request ("Shuffle"/"Repeat")
+  **  rsp_status: Status of setting the player attributes for the current media
+  *player
+  */
+  bt_status_t (*set_player_app_value_rsp)(const RawAddress& bd_addr,
+                                          btrc_status_t rsp_status);
+
+  /* Response to the register notification request (Play state change/track
+   *change/...).
+   ** event_id: Refers to the event_id this notification change corresponds too
+   ** type: Response type - interim/changed
+   ** p_params: Based on the event_id, this parameter should be populated
+   */
+  bt_status_t (*register_notification_rsp)(
+      btrc_event_id_t event_id, btrc_notification_type_t type,
+      btrc_register_notification_t* p_param);
+
+  /* AVRCP 1.4 enhancements */
+
+  /**Send current volume setting to remote side. Support limited to
+   *SetAbsoluteVolume
+   ** This can be enhanced to support Relative Volume (AVRCP 1.0).
+   ** With RelateVolume, we will send VOLUME_UP/VOLUME_DOWN opposed to absolute
+   *volume level
+   ** volume: Should be in the range 0-127. bit7 is reseved and cannot be set
+   */
+  bt_status_t (*set_volume)(uint8_t volume);
+
+  /* Set addressed player response from TG to CT */
+  bt_status_t (*set_addressed_player_rsp)(const RawAddress& bd_addr,
+                                          btrc_status_t rsp_status);
+
+  /* Set browsed player response from TG to CT */
+  bt_status_t (*set_browsed_player_rsp)(const RawAddress& bd_addr,
+                                        btrc_status_t rsp_status,
+                                        uint32_t num_items, uint16_t charset_id,
+                                        uint8_t folder_depth,
+                                        btrc_br_folder_name_t* p_folders);
+
+  /* Get folder item list response from TG to CT */
+  bt_status_t (*get_folder_items_list_rsp)(const RawAddress& bd_addr,
+                                           btrc_status_t rsp_status,
+                                           uint16_t uid_counter,
+                                           uint8_t num_items,
+                                           btrc_folder_items_t* p_items);
+
+  /* Change path response from TG to CT */
+  bt_status_t (*change_path_rsp)(const RawAddress& bd_addr,
+                                 btrc_status_t rsp_status, uint32_t num_items);
+
+  /** Returns the element's attributes num_attr: Specifies the number of
+   * attributes' text contained in the pointer p_attrs
+   */
+  bt_status_t (*get_item_attr_rsp)(const RawAddress& bd_addr,
+                                   btrc_status_t rsp_status, uint8_t num_attr,
+                                   btrc_element_attr_val_t* p_attrs);
+
+  /* play media item response from TG to CT */
+  bt_status_t (*play_item_rsp)(const RawAddress& bd_addr,
+                               btrc_status_t rsp_status);
+
+  /* get total number of items response from TG to CT*/
+  bt_status_t (*get_total_num_of_items_rsp)(const RawAddress& bd_addr,
+                                            btrc_status_t rsp_status,
+                                            uint32_t uid_counter,
+                                            uint32_t num_items);
+
+  /* Search VFS response from TG to CT */
+  bt_status_t (*search_rsp)(const RawAddress& bd_addr, btrc_status_t rsp_status,
+                            uint32_t uid_counter, uint32_t num_items);
+
+  /* add_to_now playing list response from TG to CT */
+  bt_status_t (*add_to_now_playing_rsp)(const RawAddress& bd_addr,
+                                        btrc_status_t rsp_status);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+} btrc_interface_t;
+
+typedef void (*btrc_passthrough_rsp_callback)(const RawAddress& bd_addr, int id,
+                                              int key_state);
+
+typedef void (*btrc_groupnavigation_rsp_callback)(int id, int key_state);
+
+typedef void (*btrc_connection_state_callback)(bool rc_connect, bool bt_connect,
+                                               const RawAddress& bd_addr);
+
+typedef void (*btrc_ctrl_getrcfeatures_callback)(const RawAddress& bd_addr,
+                                                 int features);
+
+typedef void (*btrc_ctrl_setabsvol_cmd_callback)(const RawAddress& bd_addr,
+                                                 uint8_t abs_vol,
+                                                 uint8_t label);
+
+typedef void (*btrc_ctrl_registernotification_abs_vol_callback)(
+    const RawAddress& bd_addr, uint8_t label);
+
+typedef void (*btrc_ctrl_setplayerapplicationsetting_rsp_callback)(
+    const RawAddress& bd_addr, uint8_t accepted);
+
+typedef void (*btrc_ctrl_playerapplicationsetting_callback)(
+    const RawAddress& bd_addr, uint8_t num_attr,
+    btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr,
+    btrc_player_app_ext_attr_t* ext_attrs);
+
+typedef void (*btrc_ctrl_playerapplicationsetting_changed_callback)(
+    const RawAddress& bd_addr, const btrc_player_settings_t& vals);
+
+typedef void (*btrc_ctrl_track_changed_callback)(
+    const RawAddress& bd_addr, uint8_t num_attr,
+    btrc_element_attr_val_t* p_attrs);
+
+typedef void (*btrc_ctrl_play_position_changed_callback)(
+    const RawAddress& bd_addr, uint32_t song_len, uint32_t song_pos);
+
+typedef void (*btrc_ctrl_play_status_changed_callback)(
+    const RawAddress& bd_addr, btrc_play_status_t play_status);
+
+typedef void (*btrc_ctrl_get_folder_items_callback)(
+    const RawAddress& bd_addr, btrc_status_t status,
+    const btrc_folder_items_t* folder_items, uint8_t count);
+
+typedef void (*btrc_ctrl_change_path_callback)(const RawAddress& bd_addr,
+                                               uint32_t count);
+
+typedef void (*btrc_ctrl_set_browsed_player_callback)(const RawAddress& bd_addr,
+                                                      uint8_t num_items,
+                                                      uint8_t depth);
+typedef void (*btrc_ctrl_set_addressed_player_callback)(
+    const RawAddress& bd_addr, uint8_t status);
+/** BT-RC Controller callback structure. */
+typedef struct {
+  /** set to sizeof(BtRcCallbacks) */
+  size_t size;
+  btrc_passthrough_rsp_callback passthrough_rsp_cb;
+  btrc_groupnavigation_rsp_callback groupnavigation_rsp_cb;
+  btrc_connection_state_callback connection_state_cb;
+  btrc_ctrl_getrcfeatures_callback getrcfeatures_cb;
+  btrc_ctrl_setplayerapplicationsetting_rsp_callback setplayerappsetting_rsp_cb;
+  btrc_ctrl_playerapplicationsetting_callback playerapplicationsetting_cb;
+  btrc_ctrl_playerapplicationsetting_changed_callback
+      playerapplicationsetting_changed_cb;
+  btrc_ctrl_setabsvol_cmd_callback setabsvol_cmd_cb;
+  btrc_ctrl_registernotification_abs_vol_callback
+      registernotification_absvol_cb;
+  btrc_ctrl_track_changed_callback track_changed_cb;
+  btrc_ctrl_play_position_changed_callback play_position_changed_cb;
+  btrc_ctrl_play_status_changed_callback play_status_changed_cb;
+  btrc_ctrl_get_folder_items_callback get_folder_items_cb;
+  btrc_ctrl_change_path_callback change_folder_path_cb;
+  btrc_ctrl_set_browsed_player_callback set_browsed_player_cb;
+  btrc_ctrl_set_addressed_player_callback set_addressed_player_cb;
+} btrc_ctrl_callbacks_t;
+
+/** Represents the standard BT-RC AVRCP Controller interface. */
+typedef struct {
+  /** set to sizeof(BtRcInterface) */
+  size_t size;
+  /**
+   * Register the BtRc callbacks
+   */
+  bt_status_t (*init)(btrc_ctrl_callbacks_t* callbacks);
+
+  /** send pass through command to target */
+  bt_status_t (*send_pass_through_cmd)(const RawAddress& bd_addr,
+                                       uint8_t key_code, uint8_t key_state);
+
+  /** send group navigation command to target */
+  bt_status_t (*send_group_navigation_cmd)(const RawAddress& bd_addr,
+                                           uint8_t key_code, uint8_t key_state);
+
+  /** send command to set player applicaiton setting attributes to target */
+  bt_status_t (*set_player_app_setting_cmd)(const RawAddress& bd_addr,
+                                            uint8_t num_attrib,
+                                            uint8_t* attrib_ids,
+                                            uint8_t* attrib_vals);
+
+  /** send command to play a particular item */
+  bt_status_t (*play_item_cmd)(const RawAddress& bd_addr, uint8_t scope,
+                               uint8_t* uid, uint16_t uid_counter);
+
+  /** get the playback state */
+  bt_status_t (*get_playback_state_cmd)(const RawAddress& bd_addr);
+
+  /** get the now playing list */
+  bt_status_t (*get_now_playing_list_cmd)(const RawAddress& bd_addr,
+                                          uint32_t start, uint32_t end);
+
+  /** get the folder list */
+  bt_status_t (*get_folder_list_cmd)(const RawAddress& bd_addr, uint32_t start,
+                                     uint32_t end);
+
+  /** get the player list */
+  bt_status_t (*get_player_list_cmd)(const RawAddress& bd_addr, uint32_t start,
+                                     uint32_t end);
+
+  /** change the folder path */
+  bt_status_t (*change_folder_path_cmd)(const RawAddress& bd_addr,
+                                        uint8_t direction, uint8_t* uid);
+
+  /** set browsed player */
+  bt_status_t (*set_browsed_player_cmd)(const RawAddress& bd_addr,
+                                        uint16_t player_id);
+
+  /** set addressed player */
+  bt_status_t (*set_addressed_player_cmd)(const RawAddress& bd_addr,
+                                          uint16_t player_id);
+
+  /** send rsp to set_abs_vol received from target */
+  bt_status_t (*set_volume_rsp)(const RawAddress& bd_addr, uint8_t abs_vol,
+                                uint8_t label);
+
+  /** send notificaiton rsp for abs vol to target */
+  bt_status_t (*register_abs_vol_rsp)(const RawAddress& bd_addr,
+                                      btrc_notification_type_t rsp_type,
+                                      uint8_t abs_vol, uint8_t label);
+
+  /** Closes the interface. */
+  void (*cleanup)(void);
+} btrc_ctrl_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_RC_H */
diff --git a/include/hardware/bt_sdp.h b/include/hardware/bt_sdp.h
new file mode 100644
index 0000000..024ee40
--- /dev/null
+++ b/include/hardware/bt_sdp.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015 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 "bluetooth.h"
+
+#define SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH 15
+
+__BEGIN_DECLS
+
+/**
+ * These events are handled by the state machine
+ */
+typedef enum {
+  SDP_TYPE_RAW,         // Used to carry raw SDP search data for unknown UUIDs
+  SDP_TYPE_MAP_MAS,     // Message Access Profile - Server
+  SDP_TYPE_MAP_MNS,     // Message Access Profile - Client (Notification Server)
+  SDP_TYPE_PBAP_PSE,    // Phone Book Profile - Server
+  SDP_TYPE_PBAP_PCE,    // Phone Book Profile - Client
+  SDP_TYPE_OPP_SERVER,  // Object Push Profile
+  SDP_TYPE_SAP_SERVER   // SIM Access Profile
+} bluetooth_sdp_types;
+
+typedef struct _bluetooth_sdp_hdr {
+  bluetooth_sdp_types type;
+  bluetooth::Uuid uuid;
+  uint32_t service_name_length;
+  char* service_name;
+  int32_t rfcomm_channel_number;
+  int32_t l2cap_psm;
+  int32_t profile_version;
+} bluetooth_sdp_hdr;
+
+/**
+ * Some signals need additional pointers, hence we introduce a
+ * generic way to handle these pointers.
+ */
+typedef struct _bluetooth_sdp_hdr_overlay {
+  bluetooth_sdp_types type;
+  bluetooth::Uuid uuid;
+  uint32_t service_name_length;
+  char* service_name;
+  int32_t rfcomm_channel_number;
+  int32_t l2cap_psm;
+  int32_t profile_version;
+
+  // User pointers, only used for some signals - see bluetooth_sdp_ops_record
+  int user1_ptr_len;
+  uint8_t* user1_ptr;
+  int user2_ptr_len;
+  uint8_t* user2_ptr;
+} bluetooth_sdp_hdr_overlay;
+
+typedef struct _bluetooth_sdp_mas_record {
+  bluetooth_sdp_hdr_overlay hdr;
+  uint32_t mas_instance_id;
+  uint32_t supported_features;
+  uint32_t supported_message_types;
+} bluetooth_sdp_mas_record;
+
+typedef struct _bluetooth_sdp_mns_record {
+  bluetooth_sdp_hdr_overlay hdr;
+  uint32_t supported_features;
+} bluetooth_sdp_mns_record;
+
+typedef struct _bluetooth_sdp_pse_record {
+  bluetooth_sdp_hdr_overlay hdr;
+  uint32_t supported_features;
+  uint32_t supported_repositories;
+} bluetooth_sdp_pse_record;
+
+typedef struct _bluetooth_sdp_pce_record {
+  bluetooth_sdp_hdr_overlay hdr;
+} bluetooth_sdp_pce_record;
+
+typedef struct _bluetooth_sdp_ops_record {
+  bluetooth_sdp_hdr_overlay hdr;
+  int supported_formats_list_len;
+  uint8_t supported_formats_list[SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH];
+} bluetooth_sdp_ops_record;
+
+typedef struct _bluetooth_sdp_sap_record {
+  bluetooth_sdp_hdr_overlay hdr;
+} bluetooth_sdp_sap_record;
+
+typedef union {
+  bluetooth_sdp_hdr_overlay hdr;
+  bluetooth_sdp_mas_record mas;
+  bluetooth_sdp_mns_record mns;
+  bluetooth_sdp_pse_record pse;
+  bluetooth_sdp_pce_record pce;
+  bluetooth_sdp_ops_record ops;
+  bluetooth_sdp_sap_record sap;
+} bluetooth_sdp_record;
+
+/** Callback for SDP search */
+typedef void (*btsdp_search_callback)(bt_status_t status,
+                                      const RawAddress& bd_addr,
+                                      const bluetooth::Uuid& uuid,
+                                      int num_records,
+                                      bluetooth_sdp_record* records);
+
+typedef struct {
+  /** Set to sizeof(btsdp_callbacks_t) */
+  size_t size;
+  btsdp_search_callback sdp_search_cb;
+} btsdp_callbacks_t;
+
+typedef struct {
+  /** Set to size of this struct */
+  size_t size;
+
+  /** Register BT SDP search callbacks */
+  bt_status_t (*init)(btsdp_callbacks_t* callbacks);
+
+  /** Unregister BT SDP */
+  bt_status_t (*deinit)();
+
+  /** Search for SDP records with specific uuid on remote device */
+  bt_status_t (*sdp_search)(RawAddress* bd_addr, const bluetooth::Uuid& uuid);
+
+  /**
+   * Use listen in the socket interface to create rfcomm and/or l2cap PSM
+   * channels, (without UUID and service_name and set the BTSOCK_FLAG_NO_SDP
+   * flag in flags). Then use createSdpRecord to create the SDP record
+   * associated with the rfcomm/l2cap channels.
+   *
+   * Returns a handle to the SDP record, which can be parsed to
+   * remove_sdp_record.
+   *
+   * record           (in) The SDP record to create
+   * record_handle    (out)The corresponding record handle will be written to
+   * this pointer.
+   */
+  bt_status_t (*create_sdp_record)(bluetooth_sdp_record* record,
+                                   int* record_handle);
+
+  /** Remove a SDP record created by createSdpRecord */
+  bt_status_t (*remove_sdp_record)(int sdp_handle);
+} btsdp_interface_t;
+
+__END_DECLS
diff --git a/include/hardware/bt_sock.h b/include/hardware/bt_sock.h
new file mode 100644
index 0000000..04827aa
--- /dev/null
+++ b/include/hardware/bt_sock.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 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
+
+__BEGIN_DECLS
+
+#define BTSOCK_FLAG_ENCRYPT 1
+#define BTSOCK_FLAG_AUTH (1 << 1)
+#define BTSOCK_FLAG_NO_SDP (1 << 2)
+#define BTSOCK_FLAG_AUTH_MITM (1 << 3)
+#define BTSOCK_FLAG_AUTH_16_DIGIT (1 << 4)
+#define BTSOCK_FLAG_LE_COC (1 << 5)
+
+typedef enum {
+  BTSOCK_RFCOMM = 1,
+  BTSOCK_SCO = 2,
+  BTSOCK_L2CAP = 3,
+  BTSOCK_L2CAP_LE = 4
+} btsock_type_t;
+
+/** Represents the standard BT SOCKET interface. */
+typedef struct {
+  short size;
+  RawAddress bd_addr;
+  int channel;
+  int status;
+
+  // The writer must make writes using a buffer of this maximum size
+  // to avoid loosing data. (L2CAP only)
+  unsigned short max_tx_packet_size;
+
+  // The reader must read using a buffer of at least this size to avoid
+  // loosing data. (L2CAP only)
+  unsigned short max_rx_packet_size;
+} __attribute__((packed)) sock_connect_signal_t;
+
+typedef struct {
+  /** set to size of this struct*/
+  size_t size;
+
+  /**
+   * Listen to a RFCOMM UUID or channel. It returns the socket fd from which
+   * btsock_connect_signal can be read out when a remote device connected.
+   * If neither a UUID nor a channel is provided, a channel will be allocated
+   * and a service record can be created providing the channel number to
+   * create_sdp_record(...) in bt_sdp.
+   * The callingUid is the UID of the application which is requesting the
+   * socket. This is used for traffic accounting purposes.
+   */
+  bt_status_t (*listen)(btsock_type_t type, const char* service_name,
+                        const bluetooth::Uuid* service_uuid, int channel,
+                        int* sock_fd, int flags, int callingUid);
+
+  /**
+   * Connect to a RFCOMM UUID channel of remote device, It returns the socket fd
+   * from which the btsock_connect_signal and a new socket fd to be accepted can
+   * be read out when connected. The callingUid is the UID of the application
+   * which is requesting the socket. This is used for traffic accounting
+   * purposes.
+   */
+  bt_status_t (*connect)(const RawAddress* bd_addr, btsock_type_t type,
+                         const bluetooth::Uuid* uuid, int channel, int* sock_fd,
+                         int flags, int callingUid);
+
+  /**
+   * Set the LE Data Length value to this connected peer to the
+   * maximum supported by this BT controller. This command
+   * suggests to the BT controller to set its maximum transmission
+   * packet size.
+   */
+  void (*request_max_tx_data_length)(const RawAddress& bd_addr);
+
+} btsock_interface_t;
+
+__END_DECLS
diff --git a/internal_include/Android.bp b/internal_include/Android.bp
new file mode 100644
index 0000000..3ef202b
--- /dev/null
+++ b/internal_include/Android.bp
@@ -0,0 +1,6 @@
+cc_library_headers {
+    name: "internal_include_headers",
+    export_include_dirs: ["./"],
+    vendor_available: true,
+    host_supported: true,
+}
\ No newline at end of file
diff --git a/include/bt_common.h b/internal_include/bt_common.h
similarity index 95%
rename from include/bt_common.h
rename to internal_include/bt_common.h
index 9680792..a15cb64 100644
--- a/include/bt_common.h
+++ b/internal_include/bt_common.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/include/bt_target.h b/internal_include/bt_target.h
similarity index 92%
rename from include/bt_target.h
rename to internal_include/bt_target.h
index eadfc92..cf09b15 100644
--- a/include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  *  Copyright (c) 2014 The Android Open Source Project
- *  Copyright (C) 1999-2016 Broadcom Corporation
+ *  Copyright 1999-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -51,10 +51,6 @@
   (L2CAP_MTU_SIZE - L2CAP_MIN_OFFSET - RFCOMM_DATA_OVERHEAD)
 #endif
 
-#ifndef BTA_INCLUDED
-#define BTA_INCLUDED TRUE
-#endif
-
 #ifndef BTA_PAN_INCLUDED
 #define BTA_PAN_INCLUDED TRUE
 #endif
@@ -87,22 +83,14 @@
 #define BTA_DISABLE_DELAY 200 /* in milliseconds */
 #endif
 
-#ifndef SBC_FOR_EMBEDDED_LINUX
-#define SBC_FOR_EMBEDDED_LINUX TRUE
-#endif
-
 #ifndef AVDT_VERSION
-#define AVDT_VERSION 0x0102
+#define AVDT_VERSION 0x0103
 #endif
 
 #ifndef BTA_AG_AT_MAX_LEN
 #define BTA_AG_AT_MAX_LEN 512
 #endif
 
-#ifndef BTA_AVRCP_FF_RW_SUPPORT
-#define BTA_AVRCP_FF_RW_SUPPORT TRUE
-#endif
-
 #ifndef BTA_AG_SCO_PKT_TYPES
 #define BTA_AG_SCO_PKT_TYPES                                     \
   (BTM_SCO_LINK_ONLY_MASK | ESCO_PKT_TYPES_MASK_EV3 |            \
@@ -119,11 +107,6 @@
 #define BTA_AV_CO_CP_SCMS_T FALSE
 #endif
 
-/* This feature is used to enable interleaved scan */
-#ifndef BTA_HOST_INTERLEAVE_SEARCH
-#define BTA_HOST_INTERLEAVE_SEARCH FALSE
-#endif
-
 #ifndef BTA_DM_SDP_DB_SIZE
 #define BTA_DM_SDP_DB_SIZE 8000
 #endif
@@ -141,11 +124,17 @@
 #endif
 
 // How long to wait before activating sniff mode after entering the
-// idle state for FTS, OPS connections
+// idle state for server FT/RFCOMM, OPS connections
 #ifndef BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS
 #define BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS 7000
 #endif
 
+// How long to wait before activating sniff mode after entering the
+// idle state for client FT/RFCOMM connections
+#ifndef BTA_FTC_IDLE_TO_SNIFF_DELAY_MS
+#define BTA_FTC_IDLE_TO_SNIFF_DELAY_MS 5000
+#endif
+
 //------------------End added from bdroid_buildcfg.h---------------------
 
 /******************************************************************************
@@ -270,11 +259,6 @@
 #define BTA_HL_LRG_DATA_BUF_SIZE (10240 + 24)
 #endif
 
-/* GATT Server Database buffer size */
-#ifndef GATT_DB_BUF_SIZE
-#define GATT_DB_BUF_SIZE 128
-#endif
-
 /* GATT Data sending buffer size */
 #ifndef GATT_DATA_BUF_SIZE
 #define GATT_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
@@ -296,11 +280,6 @@
 #define BTM_SCO_INCLUDED TRUE /* TRUE includes SCO code */
 #endif
 
-/* Includes SCO if TRUE */
-#ifndef BTM_SCO_HCI_INCLUDED
-#define BTM_SCO_HCI_INCLUDED FALSE /* TRUE includes SCO over HCI code */
-#endif
-
 /*  This is used to work around a controller bug that doesn't like Disconnect
  *  issued while there is a role switch in progress
 */
@@ -373,11 +352,6 @@
 #define BTM_MAX_SCO_LINKS 3
 #endif
 
-/* The preferred type of SCO links (2-eSCO, 0-SCO). */
-#ifndef BTM_DEFAULT_SCO_MODE
-#define BTM_DEFAULT_SCO_MODE 2
-#endif
-
 /* The number of security records for peer devices. */
 #ifndef BTM_SEC_MAX_DEVICE_RECORDS
 #define BTM_SEC_MAX_DEVICE_RECORDS 100
@@ -507,14 +481,14 @@
 
 /* The maximum number of simultaneous links that L2CAP can support. */
 #ifndef MAX_ACL_CONNECTIONS
-#define MAX_L2CAP_LINKS 7
+#define MAX_L2CAP_LINKS 13
 #else
 #define MAX_L2CAP_LINKS MAX_ACL_CONNECTIONS
 #endif
 
 /* The maximum number of simultaneous channels that L2CAP can support. */
 #ifndef MAX_L2CAP_CHANNELS
-#define MAX_L2CAP_CHANNELS 16
+#define MAX_L2CAP_CHANNELS 32
 #endif
 
 /* The maximum number of simultaneous applications that can register with L2CAP.
@@ -585,26 +559,6 @@
 #define L2CAP_HCI_FLOW_CONTROL_DEBUG TRUE
 #endif
 
-/* Unicast Connectionless Data */
-#ifndef L2CAP_UCD_INCLUDED
-#define L2CAP_UCD_INCLUDED FALSE
-#endif
-
-/* Unicast Connectionless Data MTU */
-#ifndef L2CAP_UCD_MTU
-#define L2CAP_UCD_MTU L2CAP_MTU_SIZE
-#endif
-
-/* Unicast Connectionless Data Idle Timeout */
-#ifndef L2CAP_UCD_IDLE_TIMEOUT
-#define L2CAP_UCD_IDLE_TIMEOUT 2
-#endif
-
-/* Unicast Connectionless Data Idle Timeout */
-#ifndef L2CAP_UCD_CH_PRIORITY
-#define L2CAP_UCD_CH_PRIORITY L2CAP_CHNL_PRIORITY_MEDIUM
-#endif
-
 /* Used for features using fixed channels; set to zero if no fixed channels
  * supported (BLE, etc.) */
 /* Excluding L2CAP signaling channel and UCD */
@@ -653,7 +607,7 @@
  *****************************************************************************/
 
 #ifndef LOCAL_BLE_CONTROLLER_ID
-#define LOCAL_BLE_CONTROLLER_ID (1)
+#define LOCAL_BLE_CONTROLLER_ID 1
 #endif
 
 /*
@@ -679,11 +633,6 @@
 #define BLE_VND_INCLUDED FALSE
 #endif
 
-#ifndef BTM_BLE_ADV_TX_POWER
-#define BTM_BLE_ADV_TX_POWER \
-  { -21, -15, -7, 1, 9 }
-#endif
-
 /* The maximum number of simultaneous applications that can register with LE
  * L2CAP. */
 #ifndef BLE_MAX_L2CAP_CLIENTS
@@ -699,28 +648,12 @@
 #define BLE_LLT_INCLUDED TRUE
 #endif
 
-#ifndef ATT_INCLUDED
-#define ATT_INCLUDED TRUE
-#endif
-
-#ifndef ATT_DEBUG
-#define ATT_DEBUG TRUE
-#endif
-
 #ifndef BLE_DELAY_REQUEST_ENC
 /* This flag is to work around IPHONE problem, We need to wait for iPhone ready
    before send encryption request to iPhone */
 #define BLE_DELAY_REQUEST_ENC FALSE
 #endif
 
-#ifndef GAP_TRANSPORT_SUPPORTED
-#define GAP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR
-#endif
-
-#ifndef GATTP_TRANSPORT_SUPPORTED
-#define GATTP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR
-#endif
-
 #ifndef GATT_MAX_SR_PROFILES
 #define GATT_MAX_SR_PROFILES 32 /* max is 32 */
 #endif
@@ -829,7 +762,7 @@
 
 /* The MTU size for the L2CAP configuration. */
 #ifndef SDP_MTU_SIZE
-#define SDP_MTU_SIZE 672
+#define SDP_MTU_SIZE 1024
 #endif
 
 /* The flush timeout for the L2CAP configuration. */
@@ -920,17 +853,6 @@
 #define PORT_FC_DEFAULT PORT_FC_CREDIT
 #endif
 
-/* The maximum number of credits receiver sends to peer when using credit-based
- * flow control. */
-#ifndef PORT_CREDIT_RX_MAX
-#define PORT_CREDIT_RX_MAX 16
-#endif
-
-/* The credit low watermark level. */
-#ifndef PORT_CREDIT_RX_LOW
-#define PORT_CREDIT_RX_LOW 8
-#endif
-
 /******************************************************************************
  *
  * OBEX
@@ -1072,18 +994,9 @@
  *
  *****************************************************************************/
 
-#ifndef AVDT_INCLUDED
-#define AVDT_INCLUDED TRUE
-#endif
-
-/* Include reporting capability in AVDTP */
-#ifndef AVDT_REPORTING
-#define AVDT_REPORTING TRUE
-#endif
-
 /* Number of simultaneous links to different peer devices. */
 #ifndef AVDT_NUM_LINKS
-#define AVDT_NUM_LINKS 2
+#define AVDT_NUM_LINKS 6
 #endif
 
 /* Number of simultaneous stream endpoints. */
@@ -1093,7 +1006,7 @@
 
 /* Number of transport channels setup by AVDT for all media streams */
 #ifndef AVDT_NUM_TC_TBL
-#define AVDT_NUM_TC_TBL 6
+#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS)
 #endif
 
 /* Maximum size in bytes of the content protection information element. */
@@ -1225,10 +1138,6 @@
 #define HID_DEV_INCLUDED TRUE
 #endif
 
-#ifndef HID_DEV_SUBCLASS
-#define HID_DEV_SUBCLASS COD_MINOR_POINTING
-#endif
-
 #ifndef HID_CONTROL_BUF_SIZE
 #define HID_CONTROL_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
 #endif
@@ -1280,18 +1189,11 @@
 #endif
 
 #ifndef HID_HOST_MAX_CONN_RETRY
-#define HID_HOST_MAX_CONN_RETRY (1)
+#define HID_HOST_MAX_CONN_RETRY 1
 #endif
 
 #ifndef HID_HOST_REPAGE_WIN
-#define HID_HOST_REPAGE_WIN (2)
-#endif
-
-/*************************************************************************
- * A2DP Definitions
- */
-#ifndef A2D_INCLUDED
-#define A2D_INCLUDED TRUE
+#define HID_HOST_REPAGE_WIN 2
 #endif
 
 /******************************************************************************
@@ -1302,12 +1204,12 @@
 
 /* Number of simultaneous ACL links to different peer devices. */
 #ifndef AVCT_NUM_LINKS
-#define AVCT_NUM_LINKS 2
+#define AVCT_NUM_LINKS 6
 #endif
 
 /* Number of simultaneous AVCTP connections. */
 #ifndef AVCT_NUM_CONN
-#define AVCT_NUM_CONN 3
+#define AVCT_NUM_CONN 14  // 2 * MaxDevices + 2
 #endif
 
 /******************************************************************************
@@ -1316,10 +1218,6 @@
  *
  *****************************************************************************/
 
-#ifndef AVRC_METADATA_INCLUDED
-#define AVRC_METADATA_INCLUDED TRUE
-#endif
-
 #ifndef AVRC_ADV_CTRL_INCLUDED
 #define AVRC_ADV_CTRL_INCLUDED TRUE
 #endif
diff --git a/include/bt_trace.h b/internal_include/bt_trace.h
similarity index 94%
rename from include/bt_trace.h
rename to internal_include/bt_trace.h
index 44ff2ff..97c761b 100644
--- a/include/bt_trace.h
+++ b/internal_include/bt_trace.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -478,27 +478,27 @@
 /* AVDTP */
 #define AVDT_TRACE_ERROR(...)                                     \
   {                                                               \
-    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
+    if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_ERROR)            \
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
   }
 #define AVDT_TRACE_WARNING(...)                                     \
   {                                                                 \
-    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING)              \
+    if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_WARNING)            \
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
   }
 #define AVDT_TRACE_EVENT(...)                                     \
   {                                                               \
-    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT)              \
+    if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_EVENT)            \
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
   }
 #define AVDT_TRACE_DEBUG(...)                                     \
   {                                                               \
-    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)              \
+    if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_DEBUG)            \
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 #define AVDT_TRACE_API(...)                                     \
   {                                                             \
-    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API)              \
+    if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_API)            \
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
   }
 
@@ -720,3 +720,55 @@
 #ifdef __cplusplus
 }
 #endif
+
+#ifdef __cplusplus
+
+#include <iomanip>
+#include <sstream>
+#include <type_traits>
+
+#include <base/logging.h>
+
+/* Prints intergral parameter x as hex string, with '0' fill */
+template <typename T>
+std::string loghex(T x) {
+  static_assert(std::is_integral<T>::value,
+                "loghex parameter must be integral.");
+  std::stringstream tmp;
+  tmp << std::showbase << std::internal << std::hex << std::setfill('0')
+      << std::setw((sizeof(T) * 2) + 2) << +x;
+  return tmp.str();
+}
+
+/**
+ * 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.
+ *
+ * @param p_result a pointer to the result string to add the field name to
+ * @param append if true the field name will be added
+ * @param name the field name to add
+ * @return the result string
+ */
+inline std::string& AppendField(std::string* p_result, bool append,
+                                const std::string& name) {
+  CHECK(p_result != nullptr);
+  if (!append) return *p_result;
+  if (!p_result->empty()) *p_result += "|";
+  *p_result += name;
+  return *p_result;
+}
+
+#endif
diff --git a/include/bte.h b/internal_include/bte.h
similarity index 98%
rename from include/bte.h
rename to internal_include/bte.h
index 90c9590..754cf53 100644
--- a/include/bte.h
+++ b/internal_include/bte.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/include/bte_appl.h b/internal_include/bte_appl.h
similarity index 95%
rename from include/bte_appl.h
rename to internal_include/bte_appl.h
index b2aaa02..84ab641 100644
--- a/include/bte_appl.h
+++ b/internal_include/bte_appl.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/include/stack_config.h b/internal_include/stack_config.h
similarity index 90%
rename from include/stack_config.h
rename to internal_include/stack_config.h
index 156f5be..d623fa4 100644
--- a/include/stack_config.h
+++ b/internal_include/stack_config.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,10 +27,11 @@
 
 typedef struct {
   bool (*get_trace_config_enabled)(void);
+  bool (*get_pts_avrcp_test)(void);
   bool (*get_pts_secure_only_mode)(void);
   bool (*get_pts_conn_updates_disabled)(void);
   bool (*get_pts_crosskey_sdp_disable)(void);
-  const char* (*get_pts_smp_options)(void);
+  const std::string* (*get_pts_smp_options)(void);
   int (*get_pts_smp_failure_case)(void);
   config_t* (*get_all)(void);
 } stack_config_t;
diff --git a/main/Android.bp b/main/Android.bp
index 9dc5a98..c07b849 100644
--- a/main/Android.bp
+++ b/main/Android.bp
@@ -1,9 +1,11 @@
+
 // Bluetooth main HW module / shared library for target
 // ========================================================
 cc_library_shared {
-    name: "bluetooth.default",
+    name: "libbluetooth",
     defaults: ["fluoride_defaults"],
-    relative_install_path: "hw",
+    header_libs: ["libbluetooth_headers"],
+    export_header_lib_headers: ["libbluetooth_headers"],
     srcs: [
         // platform specific
         "bte_conf.cc",
@@ -19,7 +21,7 @@
         "system/bt/bta/sys",
         "system/bt/bta/dm",
         "system/bt/btcore/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/stack/include",
         "system/bt/stack/l2cap",
         "system/bt/stack/a2dp",
@@ -37,6 +39,7 @@
     logtags: ["../EventLogTags.logtags"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth.a2dp@1.0",
         "libaudioclient",
         "libcutils",
         "libdl",
@@ -53,6 +56,7 @@
         "libbt-sbc-decoder",
         "libbt-sbc-encoder",
         "libFraunhoferAAC",
+        "libg722codec",
         "libudrv-uipc",
     ],
     whole_static_libs: [
@@ -60,11 +64,11 @@
         "libbtdevice",
         "libbtif",
         "libbt-hci",
-        "libbt-protos",
         "libbt-stack",
         "libbt-utils",
         "libbtcore",
         "libosi",
+        "libbt-protos-lite",
     ],
     // Shared library link options.
     // References to global symbols and functions should bind to the library
@@ -75,7 +79,6 @@
     required: [
         "bt_did.conf",
         "bt_stack.conf",
-        "libbt-hci",
         "libldacBT_enc",
         "libldacBT_abr",
     ],
@@ -83,3 +86,30 @@
         "-DBUILDCFG",
     ],
 }
+
+cc_library_static {
+    name: "libbluetooth-for-tests",
+    defaults: ["fluoride_defaults"],
+
+    srcs: [
+        "bte_conf.cc",
+        "bte_init.cc",
+        "bte_init_cpp_logging.cc",
+        "bte_logmsg.cc",
+        "bte_main.cc",
+        "stack_config.cc",
+    ],
+    include_dirs: [
+        "system/bt",
+        "system/bt/bta/include",
+        "system/bt/btcore/include",
+        "system/bt/btif/include",
+        "system/bt/hci/include",
+        "system/bt/internal_include",
+        "system/bt/stack/include",
+        "system/bt/utils/include",
+    ],
+    cflags: [
+        "-DBUILDCFG",
+    ],
+}
diff --git a/main/BUILD.gn b/main/BUILD.gn
index 957068c..2a07d7b 100644
--- a/main/BUILD.gn
+++ b/main/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -14,7 +14,14 @@
 #  limitations under the License.
 #
 
-shared_library("bluetooth.default") {
+config("libbluetooth_config") {
+  include_dirs = [
+    "../include",
+  ]
+}
+
+shared_library("bluetooth") {
+
   # HAL layer
   sources = [
     "//btif/src/bluetooth.cc",
@@ -30,13 +37,15 @@
     "stack_config.cc",
   ]
 
+  public_configs = [ ":libbluetooth_config" ]
+
   include_dirs = [
     "//",
     "//bta/include",
     "//bta/sys",
     "//bta/dm",
     "//btcore/include",
-    "//include",
+    "//internal_include",
     "//stack/include",
     "//stack/l2cap",
     "//stack/a2dp",
diff --git a/main/bte_conf.cc b/main/bte_conf.cc
index f765eb6..a60015a 100644
--- a/main/bte_conf.cc
+++ b/main/bte_conf.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
 void bte_load_did_conf(const char* p_path) {
   CHECK(p_path != NULL);
 
-  config_t* config = config_new(p_path);
+  std::unique_ptr<config_t> config = config_new(p_path);
   if (!config) {
     LOG_ERROR(LOG_TAG, "%s unable to load DID config '%s'.", __func__, p_path);
     return;
@@ -43,28 +43,34 @@
     char section_name[16] = {0};
     snprintf(section_name, sizeof(section_name), "DID%d", i);
 
-    if (!config_has_section(config, section_name)) {
+    if (!config_has_section(*config, section_name)) {
       LOG_DEBUG(LOG_TAG, "%s no section named %s.", __func__, section_name);
       break;
     }
 
     tBTA_DI_RECORD record;
     record.vendor =
-        config_get_int(config, section_name, "vendorId", LMP_COMPID_BROADCOM);
+        config_get_int(*config, section_name, "vendorId", LMP_COMPID_GOOGLE);
     record.vendor_id_source = config_get_int(
-        config, section_name, "vendorIdSource", DI_VENDOR_ID_SOURCE_BTSIG);
-    record.product = config_get_int(config, section_name, "productId", 0);
-    record.version = config_get_int(config, section_name, "version", 0);
+        *config, section_name, "vendorIdSource", DI_VENDOR_ID_SOURCE_BTSIG);
+    record.product = config_get_int(*config, section_name, "productId", 0);
+    record.version = config_get_int(*config, section_name, "version", 0);
     record.primary_record =
-        config_get_bool(config, section_name, "primaryRecord", false);
-    strlcpy(record.client_executable_url,
-            config_get_string(config, section_name, "clientExecutableURL", ""),
-            sizeof(record.client_executable_url));
-    strlcpy(record.service_description,
-            config_get_string(config, section_name, "serviceDescription", ""),
-            sizeof(record.service_description));
+        config_get_bool(*config, section_name, "primaryRecord", false);
+    std::string empty = "";
+    strlcpy(
+        record.client_executable_url,
+        config_get_string(*config, section_name, "clientExecutableURL", &empty)
+            ->c_str(),
+        sizeof(record.client_executable_url));
+    strlcpy(
+        record.service_description,
+        config_get_string(*config, section_name, "serviceDescription", &empty)
+            ->c_str(),
+        sizeof(record.service_description));
     strlcpy(record.documentation_url,
-            config_get_string(config, section_name, "documentationURL", ""),
+            config_get_string(*config, section_name, "documentationURL", &empty)
+                ->c_str(),
             sizeof(record.documentation_url));
 
     if (record.vendor_id_source != DI_VENDOR_ID_SOURCE_BTSIG &&
@@ -94,6 +100,4 @@
                 __func__, i, status);
     }
   }
-
-  config_free(config);
 }
diff --git a/main/bte_init.cc b/main/bte_init.cc
index 2aa8a97..afbd6bf 100644
--- a/main/bte_init.cc
+++ b/main/bte_init.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,10 +26,6 @@
 #include <string.h>
 #include "bt_target.h"
 
-#ifndef BTA_INCLUDED
-#define BTA_INCLUDED FALSE
-#endif
-
 #include "bte.h"
 
 /* Include initialization functions definitions */
@@ -46,10 +42,7 @@
 #endif
 
 #include "avrc_api.h"
-
-#if (A2D_INCLUDED == TRUE)
 #include "a2dp_api.h"
-#endif
 
 #if (HID_HOST_INCLUDED == TRUE)
 #include "hidh_api.h"
@@ -99,9 +92,7 @@
 /**************************
  * AVDT and its profiles **
  **************************/
-#if (A2D_INCLUDED == TRUE)
   A2DP_Init();
-#endif /* AADP */
 
   AVRC_Init();
 
diff --git a/main/bte_init_cpp_logging.cc b/main/bte_init_cpp_logging.cc
index f29500d..f7c10fe 100644
--- a/main/bte_init_cpp_logging.cc
+++ b/main/bte_init_cpp_logging.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Android Open Source Project
+ *  Copyright 2016 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.
@@ -24,21 +24,21 @@
   // configuring.
   if (base::CommandLine::InitializedForCurrentProcess()) return;
 
-  const char* loggingV =
-      config_get_string(config, CONFIG_DEFAULT_SECTION, "LoggingV", NULL);
-  const char* loggingVModule =
-      config_get_string(config, CONFIG_DEFAULT_SECTION, "LoggingVModule", NULL);
+  const std::string* loggingV =
+      config_get_string(*config, CONFIG_DEFAULT_SECTION, "LoggingV", NULL);
+  const std::string* loggingVModule = config_get_string(
+      *config, CONFIG_DEFAULT_SECTION, "LoggingVModule", NULL);
 
   int argc = 1;
   const char* argv[] = {"bt_stack", NULL, NULL};
 
   if (loggingV != NULL) {
-    argv[argc] = loggingV;
+    argv[argc] = loggingV->c_str();
     argc++;
   }
 
   if (loggingVModule != NULL) {
-    argv[argc] = loggingVModule;
+    argv[argc] = loggingVModule->c_str();
     argc++;
   }
 
diff --git a/main/bte_logmsg.cc b/main/bte_logmsg.cc
index 3be38fd..3ccb64d 100644
--- a/main/bte_logmsg.cc
+++ b/main/bte_logmsg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -40,12 +40,8 @@
 #include "sdp_api.h"
 #include "stack_config.h"
 
-#if (AVDT_INCLUDED == TRUE)
 #include "avdt_api.h"
-#endif
-#if (A2D_INCLUDED == TRUE)
 #include "a2dp_api.h"
-#endif
 #if (BNEP_INCLUDED == TRUE)
 #include "bnep_api.h"
 #endif
@@ -66,7 +62,7 @@
 #endif
 
 #ifndef BTE_LOG_BUF_SIZE
-#define BTE_LOG_BUF_SIZE 1024
+#define BTE_LOG_BUF_SIZE 256
 #endif
 
 #define BTE_LOG_MAX_SIZE (BTE_LOG_BUF_SIZE - 12)
@@ -97,20 +93,12 @@
      DEFAULT_CONF_TRACE_LEVEL},
     {BTTRC_ID_STK_RFCOMM, BTTRC_ID_STK_RFCOMM_DATA, PORT_SetTraceLevel,
      "TRC_RFCOMM", DEFAULT_CONF_TRACE_LEVEL},
-#if (AVDT_INCLUDED == TRUE)
     {BTTRC_ID_STK_AVDT, BTTRC_ID_STK_AVDT, AVDT_SetTraceLevel, "TRC_AVDT",
      DEFAULT_CONF_TRACE_LEVEL},
-#endif
     {BTTRC_ID_STK_AVRC, BTTRC_ID_STK_AVRC, AVRC_SetTraceLevel, "TRC_AVRC",
      DEFAULT_CONF_TRACE_LEVEL},
-#if (AVDT_INCLUDED == TRUE)
-//{BTTRC_ID_AVDT_SCB, BTTRC_ID_AVDT_CCB, NULL, "TRC_AVDT_SCB",
-// DEFAULT_CONF_TRACE_LEVEL},
-#endif
-#if (A2D_INCLUDED == TRUE)
     {BTTRC_ID_STK_A2DP, BTTRC_ID_STK_A2DP, A2DP_SetTraceLevel, "TRC_A2D",
      DEFAULT_CONF_TRACE_LEVEL},
-#endif
 #if (BNEP_INCLUDED == TRUE)
     {BTTRC_ID_STK_BNEP, BTTRC_ID_STK_BNEP, BNEP_SetTraceLevel, "TRC_BNEP",
      DEFAULT_CONF_TRACE_LEVEL},
@@ -144,7 +132,7 @@
     {0, 0, NULL, NULL, DEFAULT_CONF_TRACE_LEVEL}};
 
 void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {
-  static char buffer[BTE_LOG_BUF_SIZE];
+  char buffer[BTE_LOG_BUF_SIZE];
   int trace_layer = TRACE_GET_LAYER(trace_set_mask);
   if (trace_layer >= TRACE_LAYER_MAX_NUM) trace_layer = 0;
 
@@ -199,10 +187,11 @@
 
   for (tBTTRC_FUNC_MAP* functions = &bttrc_set_level_map[0];
        functions->trc_name; ++functions) {
-    int value =
-        config_get_int(config, CONFIG_DEFAULT_SECTION, functions->trc_name, -1);
+    int value = config_get_int(*config, CONFIG_DEFAULT_SECTION,
+                               functions->trc_name, -1);
     if (value != -1) functions->trace_level = value;
-
+    LOG_INFO(LOG_TAG, "BTE_InitTraceLevels -- %s : Level %d",
+             functions->trc_name, functions->trace_level);
     if (functions->p_f) functions->p_f(functions->trace_level);
   }
 }
diff --git a/main/bte_main.cc b/main/bte_main.cc
index 527d93e..7fdeef03 100644
--- a/main/bte_main.cc
+++ b/main/bte_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/main/main_int.h b/main/main_int.h
index 3ca01c9..5178713 100644
--- a/main/main_int.h
+++ b/main/main_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Android Open Source Project
+ *  Copyright 2016 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.
diff --git a/main/stack_config.cc b/main/stack_config.cc
index 1353073..0e56250 100644
--- a/main/stack_config.cc
+++ b/main/stack_config.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,14 +25,17 @@
 #include "osi/include/future.h"
 #include "osi/include/log.h"
 
+namespace {
 const char* TRACE_CONFIG_ENABLED_KEY = "TraceConf";
+const char* PTS_AVRCP_TEST = "PTS_AvrcpTest";
 const char* PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly";
 const char* PTS_LE_CONN_UPDATED_DISABLED = "PTS_DisableConnUpdates";
 const char* PTS_DISABLE_SDP_LE_PAIR = "PTS_DisableSDPOnLEPair";
 const char* PTS_SMP_PAIRING_OPTIONS_KEY = "PTS_SmpOptions";
 const char* PTS_SMP_FAILURE_CASE_KEY = "PTS_SmpFailureCase";
 
-static config_t* config;
+static std::unique_ptr<config_t> config;
+}  // namespace
 
 // Module lifecycle functions
 
@@ -57,8 +60,7 @@
 }
 
 static future_t* clean_up() {
-  config_free(config);
-  config = NULL;
+  config.reset();
   return future_new_immediate(FUTURE_SUCCESS);
 }
 
@@ -72,43 +74,46 @@
 
 // Interface functions
 static bool get_trace_config_enabled(void) {
-  return config_get_bool(config, CONFIG_DEFAULT_SECTION,
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
                          TRACE_CONFIG_ENABLED_KEY, false);
 }
 
+static bool get_pts_avrcp_test(void) {
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION, PTS_AVRCP_TEST,
+                         false);
+}
+
 static bool get_pts_secure_only_mode(void) {
-  return config_get_bool(config, CONFIG_DEFAULT_SECTION, PTS_SECURE_ONLY_MODE,
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION, PTS_SECURE_ONLY_MODE,
                          false);
 }
 
 static bool get_pts_conn_updates_disabled(void) {
-  return config_get_bool(config, CONFIG_DEFAULT_SECTION,
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
                          PTS_LE_CONN_UPDATED_DISABLED, false);
 }
 
 static bool get_pts_crosskey_sdp_disable(void) {
-  return config_get_bool(config, CONFIG_DEFAULT_SECTION,
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
                          PTS_DISABLE_SDP_LE_PAIR, false);
 }
 
-static const char* get_pts_smp_options(void) {
-  return config_get_string(config, CONFIG_DEFAULT_SECTION,
+static const std::string* get_pts_smp_options(void) {
+  return config_get_string(*config, CONFIG_DEFAULT_SECTION,
                            PTS_SMP_PAIRING_OPTIONS_KEY, NULL);
 }
 
 static int get_pts_smp_failure_case(void) {
-  return config_get_int(config, CONFIG_DEFAULT_SECTION,
+  return config_get_int(*config, CONFIG_DEFAULT_SECTION,
                         PTS_SMP_FAILURE_CASE_KEY, 0);
 }
 
-static config_t* get_all(void) { return config; }
+static config_t* get_all(void) { return config.get(); }
 
-const stack_config_t interface = {get_trace_config_enabled,
-                                  get_pts_secure_only_mode,
-                                  get_pts_conn_updates_disabled,
-                                  get_pts_crosskey_sdp_disable,
-                                  get_pts_smp_options,
-                                  get_pts_smp_failure_case,
-                                  get_all};
+const stack_config_t interface = {
+    get_trace_config_enabled,     get_pts_avrcp_test,
+    get_pts_secure_only_mode,     get_pts_conn_updates_disabled,
+    get_pts_crosskey_sdp_disable, get_pts_smp_options,
+    get_pts_smp_failure_case,     get_all};
 
 const stack_config_t* stack_config_get_interface(void) { return &interface; }
diff --git a/osi/Android.bp b/osi/Android.bp
index b93593c..ad2f44b 100644
--- a/osi/Android.bp
+++ b/osi/Android.bp
@@ -3,8 +3,7 @@
     defaults: ["fluoride_defaults"],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
-        "system/bt/osi/src/protos",
+        "system/bt/internal_include",
         "system/bt/utils/include",
         "system/bt/stack/include",
     ]
@@ -21,7 +20,7 @@
     host_supported: true,
     shared: {
         enabled: false
-    }
+    },
 }
 
 cc_test_library {
@@ -33,22 +32,9 @@
     host_supported: true,
     shared: {
         enabled: false
-    }
-}
-
-// Bluetooth Protobuf static library for target and host
-// ========================================================
-cc_library_static {
-    name: "libbt-protos",
-    defaults: ["fluoride_defaults"],
-    srcs: ["src/protos/bluetooth.proto"],
-    proto: {
-        export_proto_headers: true,
     },
-    host_supported: true
 }
 
-
 // libosi static library for target
 // ========================================================
 cc_library_static {
@@ -85,16 +71,13 @@
     shared_libs: [
         "liblog",
     ],
-    static_libs: ["libbt-protos"],
+    static_libs: ["libbt-protos-lite"],
     host_supported: true,
     // TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
     // should be compatible for a Linux host OS. We should figure out what to do for
     // a non-Linux host OS.
     target: {
-        darwin: {
-            enabled: false,
-        },
-        linux: {
+        linux_glibc: {
             cflags: [
                 "-D_GNU_SOURCE",
                 "-DOS_GENERIC",
@@ -139,20 +122,16 @@
         "libcutils",
     ],
     static_libs: [
-        "libbt-protos",
+        "libbt-protos-lite",
         "libgmock",
         "libosi",
     ],
     target: {
-        linux: {
+        linux_glibc: {
             cflags: ["-DOS_GENERIC"],
-            host_ldlibs: [
-                "-lrt",
-                "-lpthread",
-            ],
         },
-        darwin: {
-            enabled: false,
-        }
+    },
+    sanitize: {
+        cfi: false,
     },
 }
diff --git a/osi/AndroidTest.xml b/osi/AndroidTest.xml
index a64158c..aa723bb 100644
--- a/osi/AndroidTest.xml
+++ b/osi/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright 2017 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.
diff --git a/osi/BUILD.gn b/osi/BUILD.gn
index daecda4..93b74cc 100644
--- a/osi/BUILD.gn
+++ b/osi/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/osi/include/alarm.h b/osi/include/alarm.h
index a01e6d0..b7395ca 100644
--- a/osi/include/alarm.h
+++ b/osi/include/alarm.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/allocation_tracker.h b/osi/include/allocation_tracker.h
index 1e3fa07..a019693 100644
--- a/osi/include/allocation_tracker.h
+++ b/osi/include/allocation_tracker.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/allocator.h b/osi/include/allocator.h
index ef03f9a..3a4141f 100644
--- a/osi/include/allocator.h
+++ b/osi/include/allocator.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/array.h b/osi/include/array.h
index bdae2fa..4b49681 100644
--- a/osi/include/array.h
+++ b/osi/include/array.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/buffer.h b/osi/include/buffer.h
index b81c9e9..a7b3b57 100644
--- a/osi/include/buffer.h
+++ b/osi/include/buffer.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/config.h b/osi/include/config.h
index 0ca4b3a..55adecb 100644
--- a/osi/include/config.h
+++ b/osi/include/config.h
@@ -17,129 +17,114 @@
 // - All strings are case sensitive.
 
 #include <stdbool.h>
+#include <list>
+#include <memory>
+#include <string>
 
 // The default section name to use if a key/value pair is not defined within
 // a section.
 #define CONFIG_DEFAULT_SECTION "Global"
 
-typedef struct config_t config_t;
-typedef struct config_section_node_t config_section_node_t;
+struct entry_t {
+  std::string key;
+  std::string value;
+};
+
+struct section_t {
+  std::string name;
+  std::list<entry_t> entries;
+};
+
+struct config_t {
+  std::list<section_t> sections;
+};
 
 // Creates a new config object with no entries (i.e. not backed by a file).
-// This function returns a config object or NULL on error. Clients must call
-// |config_free| on the returned handle when it is no longer required.
-config_t* config_new_empty(void);
+// This function returns a unique pointer to config object.
+std::unique_ptr<config_t> config_new_empty(void);
 
 // Loads the specified file and returns a handle to the config file. If there
-// was a problem loading the file or allocating memory, this function returns
-// NULL. Clients must call |config_free| on the returned handle when it is no
-// longer required. |filename| must not be NULL and must point to a readable
+// was a problem loading the file, this function returns
+// NULL. |filename| must not be NULL and must point to a readable
 // file on the filesystem.
-config_t* config_new(const char* filename);
+std::unique_ptr<config_t> config_new(const char* filename);
 
 // Clones |src|, including all of it's sections, keys, and values.
 // Returns a new config which is a copy and separated from the original;
 // changes to the new config are not reflected in any way in the original.
 //
-// |src| must not be NULL
 // This function will not return NULL.
-// Clients must call config_free on the returned object.
-config_t* config_new_clone(const config_t* src);
-
-// Frees resources associated with the config file. No further operations may
-// be performed on the |config| object after calling this function. |config|
-// may be NULL.
-void config_free(config_t* config);
+std::unique_ptr<config_t> config_new_clone(const config_t& src);
 
 // Returns true if the config file contains a section named |section|. If
 // the section has no key/value pairs in it, this function will return false.
-// |config| and |section| must not be NULL.
-bool config_has_section(const config_t* config, const char* section);
+bool config_has_section(const config_t& config, const std::string& section);
 
 // Returns true if the config file has a key named |key| under |section|.
-// Returns false otherwise. |config|, |section|, and |key| must not be NULL.
-bool config_has_key(const config_t* config, const char* section,
-                    const char* key);
+// Returns false otherwise.
+bool config_has_key(const config_t& config, const std::string& section,
+                    const std::string& key);
 
 // Returns the integral value for a given |key| in |section|. If |section|
 // or |key| do not exist, or the value cannot be fully converted to an integer,
-// this function returns |def_value|. |config|, |section|, and |key| must not
-// be NULL.
-int config_get_int(const config_t* config, const char* section, const char* key,
-                   int def_value);
+// this function returns |def_value|.
+int config_get_int(const config_t& config, const std::string& section,
+                   const std::string& key, int def_value);
+
+// Returns the uint64_t value for a given |key| in |section|. If |section|
+// or |key| do not exist, or the value cannot be fully converted to an integer,
+// this function returns |def_value|.
+uint64_t config_get_uint64(const config_t& config, const std::string& section,
+                           const std::string& key, uint64_t def_value);
 
 // Returns the boolean value for a given |key| in |section|. If |section|
 // or |key| do not exist, or the value cannot be converted to a boolean, this
-// function returns |def_value|. |config|, |section|, and |key| must not be
-// NULL.
-bool config_get_bool(const config_t* config, const char* section,
-                     const char* key, bool def_value);
+// function returns |def_value|.
+bool config_get_bool(const config_t& config, const std::string& section,
+                     const std::string& key, bool def_value);
 
 // Returns the string value for a given |key| in |section|. If |section| or
 // |key| do not exist, this function returns |def_value|. The returned string
-// is owned by the config module and must not be freed. |config|, |section|,
-// and |key| must not be NULL. |def_value| may be NULL.
-const char* config_get_string(const config_t* config, const char* section,
-                              const char* key, const char* def_value);
+// is owned by the config module and must not be freed or modified. |def_value|
+// may be NULL.
+const std::string* config_get_string(const config_t& config,
+                                     const std::string& section,
+                                     const std::string& key,
+                                     const std::string* def_value);
 
 // Sets an integral value for the |key| in |section|. If |key| or |section| do
-// not already exist, this function creates them. |config|, |section|, and |key|
-// must not be NULL.
-void config_set_int(config_t* config, const char* section, const char* key,
-                    int value);
+// not already exist, this function creates them. |config| must not be NULL.
+void config_set_int(config_t* config, const std::string& section,
+                    const std::string& key, int value);
+
+// Sets a uint64_t value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config| must not be NULL.
+void config_set_uint64(config_t* config, const std::string& section,
+                       const std::string& key, uint64_t value);
 
 // Sets a boolean value for the |key| in |section|. If |key| or |section| do
-// not already exist, this function creates them. |config|, |section|, and |key|
-// must not be NULL.
-void config_set_bool(config_t* config, const char* section, const char* key,
-                     bool value);
+// not already exist, this function creates them. |config| must not be NULL.
+void config_set_bool(config_t* config, const std::string& section,
+                     const std::string& key, bool value);
 
 // Sets a string value for the |key| in |section|. If |key| or |section| do
-// not already exist, this function creates them. |config|, |section|, |key|,
-// and
-// |value| must not be NULL.
-void config_set_string(config_t* config, const char* section, const char* key,
-                       const char* value);
+// not already exist, this function creates them. |config| must not be NULL.
+void config_set_string(config_t* config, const std::string& section,
+                       const std::string& key, const std::string& value);
 
 // Removes |section| from the |config| (and, as a result, all keys in the
 // section).
 // Returns true if |section| was found and removed from |config|, false
 // otherwise.
-// Neither |config| nor |section| may be NULL.
-bool config_remove_section(config_t* config, const char* section);
+// |config| may be NULL.
+bool config_remove_section(config_t* config, const std::string& section);
 
 // Removes one specific |key| residing in |section| of the |config|. Returns
 // true
 // if the section and key were found and the key was removed, false otherwise.
-// None of |config|, |section|, or |key| may be NULL.
-bool config_remove_key(config_t* config, const char* section, const char* key);
-
-// Returns an iterator to the first section in the config file. If there are no
-// sections, the iterator will equal the return value of |config_section_end|.
-// The returned pointer must be treated as an opaque handle and must not be
-// freed.
-// The iterator is invalidated on any config mutating operation. |config| may
-// not be NULL.
-const config_section_node_t* config_section_begin(const config_t* config);
-
-// Returns an iterator to one past the last section in the config file. It does
-// not represent a valid section, but can be used to determine if all sections
-// have been iterated over. The returned pointer must be treated as an opaque
-// handle and must not be freed and must not be iterated on (must not call
-// |config_section_next| on it). |config| may not be NULL.
-const config_section_node_t* config_section_end(const config_t* config);
-
-// Moves |iter| to the next section. If there are no more sections, |iter| will
-// equal the value of |config_section_end|. |iter| may not be NULL and must be
-// a pointer returned by either |config_section_begin| or |config_section_next|.
-const config_section_node_t* config_section_next(
-    const config_section_node_t* iter);
-
-// Returns the name of the section referred to by |iter|. The returned pointer
-// is owned by the config module and must not be freed by the caller. The
-// pointer will remain valid until |config_free| is called. |iter| may not be
-// NULL and must not equal the value returned by |config_section_end|.
-const char* config_section_name(const config_section_node_t* iter);
+// |config|may not be NULL.
+bool config_remove_key(config_t* config, const std::string& section,
+                       const std::string& key);
 
 // Saves |config| to a file given by |filename|. Note that this could be a
 // destructive operation: if |filename| already exists, it will be overwritten.
@@ -147,4 +132,4 @@
 // file was opened with |config_new| and subsequently overwritten with
 // |config_save|, all comments and special formatting in the original file will
 // be lost. Neither |config| nor |filename| may be NULL.
-bool config_save(const config_t* config, const char* filename);
+bool config_save(const config_t& config, const std::string& filename);
diff --git a/osi/include/fixed_queue.h b/osi/include/fixed_queue.h
index 6b98f7e..adbc5be 100644
--- a/osi/include/fixed_queue.h
+++ b/osi/include/fixed_queue.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/future.h b/osi/include/future.h
index 3ed1a21..dc743e6 100644
--- a/osi/include/future.h
+++ b/osi/include/future.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/hash_map_utils.h b/osi/include/hash_map_utils.h
index 1ea3996..7bf8de2 100644
--- a/osi/include/hash_map_utils.h
+++ b/osi/include/hash_map_utils.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/leaky_bonded_queue.h b/osi/include/leaky_bonded_queue.h
index 8259cdc..6861e8b 100644
--- a/osi/include/leaky_bonded_queue.h
+++ b/osi/include/leaky_bonded_queue.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/list.h b/osi/include/list.h
index 50c3e2c..ae738f5 100644
--- a/osi/include/list.h
+++ b/osi/include/list.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/log.h b/osi/include/log.h
index d42ea62..1c2e96d 100644
--- a/osi/include/log.h
+++ b/osi/include/log.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/metrics.h b/osi/include/metrics.h
index dcd1a20..504a16a 100644
--- a/osi/include/metrics.h
+++ b/osi/include/metrics.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <bta/include/bta_api.h>
 #include <stdint.h>
 #include <memory>
 #include <string>
@@ -104,6 +105,8 @@
   int32_t buffer_overruns_total = -1;
   float buffer_underruns_average = -1;
   int32_t buffer_underruns_count = -1;
+  int64_t codec_index = -1;
+  bool is_a2dp_offload = false;
 };
 
 class BluetoothMetricsLogger {
@@ -209,13 +212,20 @@
    */
   void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
 
-  /*
-   * Writes the metrics, in base64 protobuf format, into the descriptor FD
-   * If CLEAR is true, metrics events are cleared afterwards.
+  /**
+   * Log Headset profile RFCOMM connection event
+   *
+   * @param service_id the BTA service ID for this headset connection
    */
-  void WriteBase64(int fd, bool clear);
-  void WriteBase64String(std::string* serialized, bool clear);
-  void WriteString(std::string* serialized, bool clear);
+  void LogHeadsetProfileRfcConnection(tBTA_SERVICE_ID service_id);
+
+  /*
+   * Writes the metrics, in base64 protobuf format, into the descriptor FD,
+   * metrics events are always cleared after dump
+   */
+  void WriteBase64(int fd);
+  void WriteBase64String(std::string* serialized);
+  void WriteString(std::string* serialized);
 
   /*
    * Reset the metrics logger by cleaning up its staging queues and existing
diff --git a/osi/include/mutex.h b/osi/include/mutex.h
index bf00983..0d9fe10 100644
--- a/osi/include/mutex.h
+++ b/osi/include/mutex.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/osi.h b/osi/include/osi.h
index 3359cbf..a39d56c 100644
--- a/osi/include/osi.h
+++ b/osi/include/osi.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,15 +35,6 @@
 #define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c)
 #define DUMMY_PTR DUMMY_COUNTER(__COUNTER__)
 
-// base/macros.h defines a COMPILE_ASSERT macro to the C++11 keyword
-// "static_assert" (it undef's COMPILE_ASSERT before redefining it).
-// C++ code that includes base and osi/include/osi.h can thus easily default to
-// the definition from libbase but we should check here to avoid compile errors.
-#ifndef COMPILE_ASSERT
-#define COMPILE_ASSERT(COND) \
-  typedef int failed_compile_assert[(COND) ? 1 : -1] __attribute__((unused))
-#endif  // COMPILE_ASSERT
-
 // Macros for safe integer to pointer conversion. In the C language, data is
 // commonly cast to opaque pointer containers and back for generic parameter
 // passing in callbacks. These macros should be used sparingly in new code
diff --git a/osi/include/properties.h b/osi/include/properties.h
index ececef5..b186f4f 100644
--- a/osi/include/properties.h
+++ b/osi/include/properties.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,11 +19,9 @@
 #pragma once
 
 #include <cstdint>
-#if defined(OS_GENERIC)
+
 #define PROPERTY_VALUE_MAX 92
-#else
-#include <cutils/properties.h>
-#endif  // defined(OS_GENERIC)
+#define BUILD_SANITY_PROPERTY_VALUE_MAX 92
 
 // Get value associated with key |key| into |value|.
 // Returns the length of the value which will never be greater than
@@ -43,3 +41,10 @@
 // returns the value of |key| truncated and coerced into an
 // int32_t. If the property is not set, then the |default_value| is used.
 int32_t osi_property_get_int32(const char* key, int32_t default_value);
+
+// Adapter function for property_get_bool in
+// libcutils/include/cutils/properties.h
+//
+// returns the value of |key| coerced into a bool. If the property is not set,
+// then the |default_value| is used.
+bool osi_property_get_bool(const char* key, bool default_value);
\ No newline at end of file
diff --git a/osi/include/reactor.h b/osi/include/reactor.h
index c868a01..211cdd8 100644
--- a/osi/include/reactor.h
+++ b/osi/include/reactor.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/ringbuffer.h b/osi/include/ringbuffer.h
index 6a3c3fa..db0d674 100644
--- a/osi/include/ringbuffer.h
+++ b/osi/include/ringbuffer.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/semaphore.h b/osi/include/semaphore.h
index 9c8f6fb..3ae5e0f 100644
--- a/osi/include/semaphore.h
+++ b/osi/include/semaphore.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/socket.h b/osi/include/socket.h
index 5cd8938..83a4f2d 100644
--- a/osi/include/socket.h
+++ b/osi/include/socket.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/socket_utils/socket_local.h b/osi/include/socket_utils/socket_local.h
index fd3b00c..9fcb9d5 100644
--- a/osi/include/socket_utils/socket_local.h
+++ b/osi/include/socket_utils/socket_local.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright 2006 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.
diff --git a/osi/include/socket_utils/sockets.h b/osi/include/socket_utils/sockets.h
index fc7514f..d2a05d3 100644
--- a/osi/include/socket_utils/sockets.h
+++ b/osi/include/socket_utils/sockets.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright 2006 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.
diff --git a/osi/include/thread.h b/osi/include/thread.h
index c8da381..f69fa34 100644
--- a/osi/include/thread.h
+++ b/osi/include/thread.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/time.h b/osi/include/time.h
index 0988c20..8f533d0 100644
--- a/osi/include/time.h
+++ b/osi/include/time.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/include/wakelock.h b/osi/include/wakelock.h
index 502f9fb..b1475ce 100644
--- a/osi/include/wakelock.h
+++ b/osi/include/wakelock.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/alarm.cc b/osi/src/alarm.cc
index 9bf9cc5..83a661d 100644
--- a/osi/src/alarm.cc
+++ b/osi/src/alarm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
  *
  ******************************************************************************/
 
-#include "include/bt_target.h"
+#include "internal_include/bt_target.h"
 
 #define LOG_TAG "bt_osi_alarm"
 
@@ -647,7 +647,8 @@
       }
 
       alarm->closure.i.Reset(Bind(alarm_ready_mloop, alarm));
-      get_message_loop()->PostTask(FROM_HERE, alarm->closure.i.callback());
+      get_message_loop()->task_runner()->PostTask(FROM_HERE,
+                                                  alarm->closure.i.callback());
     } else {
       fixed_queue_enqueue(alarm->queue, alarm);
     }
diff --git a/osi/src/allocation_tracker.cc b/osi/src/allocation_tracker.cc
index 2dee1dc..ba6b7f1 100644
--- a/osi/src/allocation_tracker.cc
+++ b/osi/src/allocation_tracker.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/allocator.cc b/osi/src/allocator.cc
index 4e4f9a7..1c0449e 100644
--- a/osi/src/allocator.cc
+++ b/osi/src/allocator.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/array.cc b/osi/src/array.cc
index 913b711..f28a70c 100644
--- a/osi/src/array.cc
+++ b/osi/src/array.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/buffer.cc b/osi/src/buffer.cc
index abfacdb..41eea00 100644
--- a/osi/src/buffer.cc
+++ b/osi/src/buffer.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/config.cc b/osi/src/config.cc
index fc64d47..d4ed2e6 100644
--- a/osi/src/config.cc
+++ b/osi/src/config.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2017 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.
@@ -16,10 +16,10 @@
  *
  ******************************************************************************/
 
-#define LOG_TAG "bt_osi_config"
-
 #include "osi/include/config.h"
+#include "log/log.h"
 
+#include <base/files/file_path.h>
 #include <base/logging.h>
 #include <ctype.h>
 #include <errno.h>
@@ -30,267 +30,195 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
-
-#include "osi/include/allocator.h"
-#include "osi/include/list.h"
-#include "osi/include/log.h"
-#include "log/log.h"
-
-typedef struct {
-  char* key;
-  char* value;
-} entry_t;
-
-typedef struct {
-  char* name;
-  list_t* entries;
-} section_t;
-
-struct config_t {
-  list_t* sections;
-};
+#include <sstream>
+#include <type_traits>
 
 // Empty definition; this type is aliased to list_node_t.
 struct config_section_iter_t {};
 
 static bool config_parse(FILE* fp, config_t* config);
 
-static section_t* section_new(const char* name);
-static void section_free(void* ptr);
-static section_t* section_find(const config_t* config, const char* section);
-
-static entry_t* entry_new(const char* key, const char* value);
-static void entry_free(void* ptr);
-static entry_t* entry_find(const config_t* config, const char* section,
-                           const char* key);
-
-config_t* config_new_empty(void) {
-  config_t* config = static_cast<config_t*>(osi_calloc(sizeof(config_t)));
-
-  config->sections = list_new(section_free);
-  if (!config->sections) {
-    LOG_ERROR(LOG_TAG, "%s unable to allocate list for sections.", __func__);
-    goto error;
-  }
-
-  return config;
-
-error:;
-  config_free(config);
-  return NULL;
+template <typename T,
+          class = typename std::enable_if<std::is_same<
+              config_t, typename std::remove_const<T>::type>::value>>
+static auto section_find(T& config, const std::string& section) {
+  return std::find_if(
+      config.sections.begin(), config.sections.end(),
+      [&section](const section_t& sec) { return sec.name == section; });
 }
 
-config_t* config_new(const char* filename) {
-  CHECK(filename != NULL);
+static const entry_t* entry_find(const config_t& config,
+                                 const std::string& section,
+                                 const std::string& key) {
+  auto sec = section_find(config, section);
+  if (sec == config.sections.end()) return nullptr;
 
-  config_t* config = config_new_empty();
-  if (!config) return NULL;
+  for (const entry_t& entry : sec->entries) {
+    if (entry.key == key) return &entry;
+  }
+
+  return nullptr;
+}
+
+std::unique_ptr<config_t> config_new_empty(void) {
+  return std::make_unique<config_t>();
+}
+
+std::unique_ptr<config_t> config_new(const char* filename) {
+  CHECK(filename != nullptr);
+
+  std::unique_ptr<config_t> config = config_new_empty();
 
   FILE* fp = fopen(filename, "rt");
   if (!fp) {
-    LOG_ERROR(LOG_TAG, "%s unable to open file '%s': %s", __func__, filename,
-              strerror(errno));
-    config_free(config);
-    return NULL;
+    LOG(ERROR) << __func__ << ": unable to open file '" << filename
+               << "': " << strerror(errno);
+    return nullptr;
   }
 
-  if (!config_parse(fp, config)) {
-    config_free(config);
-    config = NULL;
+  if (!config_parse(fp, config.get())) {
+    config.reset();
   }
 
   fclose(fp);
   return config;
 }
 
-config_t* config_new_clone(const config_t* src) {
-  CHECK(src != NULL);
+std::unique_ptr<config_t> config_new_clone(const config_t& src) {
+  std::unique_ptr<config_t> ret = config_new_empty();
 
-  config_t* ret = config_new_empty();
-
-  CHECK(ret != NULL);
-
-  for (const list_node_t* node = list_begin(src->sections);
-       node != list_end(src->sections); node = list_next(node)) {
-    section_t* sec = static_cast<section_t*>(list_node(node));
-
-    for (const list_node_t* node_entry = list_begin(sec->entries);
-         node_entry != list_end(sec->entries);
-         node_entry = list_next(node_entry)) {
-      entry_t* entry = static_cast<entry_t*>(list_node(node_entry));
-
-      config_set_string(ret, sec->name, entry->key, entry->value);
+  for (const section_t& sec : src.sections) {
+    for (const entry_t& entry : sec.entries) {
+      config_set_string(ret.get(), sec.name, entry.key, entry.value);
     }
   }
 
   return ret;
 }
 
-void config_free(config_t* config) {
-  if (!config) return;
-
-  list_free(config->sections);
-  osi_free(config);
+bool config_has_section(const config_t& config, const std::string& section) {
+  return (section_find(config, section) != config.sections.end());
 }
 
-bool config_has_section(const config_t* config, const char* section) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-
-  return (section_find(config, section) != NULL);
+bool config_has_key(const config_t& config, const std::string& section,
+                    const std::string& key) {
+  return (entry_find(config, section, key) != nullptr);
 }
 
-bool config_has_key(const config_t* config, const char* section,
-                    const char* key) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
-
-  return (entry_find(config, section, key) != NULL);
-}
-
-int config_get_int(const config_t* config, const char* section, const char* key,
-                   int def_value) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
-
-  entry_t* entry = entry_find(config, section, key);
+int config_get_int(const config_t& config, const std::string& section,
+                   const std::string& key, int def_value) {
+  const entry_t* entry = entry_find(config, section, key);
   if (!entry) return def_value;
 
   char* endptr;
-  int ret = strtol(entry->value, &endptr, 0);
+  int ret = strtol(entry->value.c_str(), &endptr, 0);
   return (*endptr == '\0') ? ret : def_value;
 }
 
-bool config_get_bool(const config_t* config, const char* section,
-                     const char* key, bool def_value) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
-
-  entry_t* entry = entry_find(config, section, key);
+uint64_t config_get_uint64(const config_t& config, const std::string& section,
+                           const std::string& key, uint64_t def_value) {
+  const entry_t* entry = entry_find(config, section, key);
   if (!entry) return def_value;
 
-  if (!strcmp(entry->value, "true")) return true;
-  if (!strcmp(entry->value, "false")) return false;
+  char* endptr;
+  uint64_t ret = strtoull(entry->value.c_str(), &endptr, 0);
+  return (*endptr == '\0') ? ret : def_value;
+}
+
+bool config_get_bool(const config_t& config, const std::string& section,
+                     const std::string& key, bool def_value) {
+  const entry_t* entry = entry_find(config, section, key);
+  if (!entry) return def_value;
+
+  if (entry->value == "true") return true;
+  if (entry->value == "false") return false;
 
   return def_value;
 }
 
-const char* config_get_string(const config_t* config, const char* section,
-                              const char* key, const char* def_value) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
-
-  entry_t* entry = entry_find(config, section, key);
+const std::string* config_get_string(const config_t& config,
+                                     const std::string& section,
+                                     const std::string& key,
+                                     const std::string* def_value) {
+  const entry_t* entry = entry_find(config, section, key);
   if (!entry) return def_value;
 
-  return entry->value;
+  return &entry->value;
 }
 
-void config_set_int(config_t* config, const char* section, const char* key,
-                    int value) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
-
-  char value_str[32] = {0};
-  snprintf(value_str, sizeof(value_str), "%d", value);
-  config_set_string(config, section, key, value_str);
+void config_set_int(config_t* config, const std::string& section,
+                    const std::string& key, int value) {
+  config_set_string(config, section, key, std::to_string(value));
 }
 
-void config_set_bool(config_t* config, const char* section, const char* key,
-                     bool value) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
+void config_set_uint64(config_t* config, const std::string& section,
+                       const std::string& key, uint64_t value) {
+  config_set_string(config, section, key, std::to_string(value));
+}
 
+void config_set_bool(config_t* config, const std::string& section,
+                     const std::string& key, bool value) {
   config_set_string(config, section, key, value ? "true" : "false");
 }
 
-void config_set_string(config_t* config, const char* section, const char* key,
-                       const char* value) {
-  section_t* sec = section_find(config, section);
-  if (!sec) {
-    sec = section_new(section);
-    list_append(config->sections, sec);
+void config_set_string(config_t* config, const std::string& section,
+                       const std::string& key, const std::string& value) {
+  CHECK(config);
+
+  auto sec = section_find(*config, section);
+  if (sec == config->sections.end()) {
+    config->sections.emplace_back(section_t{.name = section});
+    sec = std::prev(config->sections.end());
   }
 
-  std::string value_string = value;
   std::string value_no_newline;
-  size_t newline_position = value_string.find("\n");
+  size_t newline_position = value.find("\n");
   if (newline_position != std::string::npos) {
     android_errorWriteLog(0x534e4554, "70808273");
-    value_no_newline = value_string.substr(0, newline_position);
+    value_no_newline = value.substr(0, newline_position);
   } else {
-    value_no_newline = value_string;
+    value_no_newline = value;
   }
 
-  for (const list_node_t* node = list_begin(sec->entries);
-       node != list_end(sec->entries); node = list_next(node)) {
-    entry_t* entry = static_cast<entry_t*>(list_node(node));
-    if (!strcmp(entry->key, key)) {
-      osi_free(entry->value);
-      entry->value = osi_strdup(value_no_newline.c_str());
+  for (entry_t& entry : sec->entries) {
+    if (entry.key == key) {
+      entry.value = value_no_newline;
       return;
     }
   }
 
-  entry_t* entry = entry_new(key, value_no_newline.c_str());
-  list_append(sec->entries, entry);
+  sec->entries.emplace_back(entry_t{.key = key, .value = value_no_newline});
 }
 
-bool config_remove_section(config_t* config, const char* section) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
+bool config_remove_section(config_t* config, const std::string& section) {
+  CHECK(config);
 
-  section_t* sec = section_find(config, section);
-  if (!sec) return false;
+  auto sec = section_find(*config, section);
+  if (sec == config->sections.end()) return false;
 
-  return list_remove(config->sections, sec);
+  config->sections.erase(sec);
+  return true;
 }
 
-bool config_remove_key(config_t* config, const char* section, const char* key) {
-  CHECK(config != NULL);
-  CHECK(section != NULL);
-  CHECK(key != NULL);
+bool config_remove_key(config_t* config, const std::string& section,
+                       const std::string& key) {
+  CHECK(config);
+  auto sec = section_find(*config, section);
+  if (sec == config->sections.end()) return false;
 
-  section_t* sec = section_find(config, section);
-  entry_t* entry = entry_find(config, section, key);
-  if (!sec || !entry) return false;
+  for (auto entry = sec->entries.begin(); entry != sec->entries.end();
+       ++entry) {
+    if (entry->key == key) {
+      sec->entries.erase(entry);
+      return true;
+    }
+  }
 
-  return list_remove(sec->entries, entry);
+  return false;
 }
 
-const config_section_node_t* config_section_begin(const config_t* config) {
-  CHECK(config != NULL);
-  return (const config_section_node_t*)list_begin(config->sections);
-}
-
-const config_section_node_t* config_section_end(const config_t* config) {
-  CHECK(config != NULL);
-  return (const config_section_node_t*)list_end(config->sections);
-}
-
-const config_section_node_t* config_section_next(
-    const config_section_node_t* node) {
-  CHECK(node != NULL);
-  return (const config_section_node_t*)list_next((const list_node_t*)node);
-}
-
-const char* config_section_name(const config_section_node_t* node) {
-  CHECK(node != NULL);
-  const list_node_t* lnode = (const list_node_t*)node;
-  const section_t* section = (const section_t*)list_node(lnode);
-  return section->name;
-}
-
-bool config_save(const config_t* config, const char* filename) {
-  CHECK(config != NULL);
-  CHECK(filename != NULL);
-  CHECK(*filename != '\0');
+bool config_save(const config_t& config, const std::string& filename) {
+  CHECK(!filename.empty());
 
   // Steps to ensure content of config file gets to disk:
   //
@@ -301,119 +229,98 @@
   // 4) Sync directory that has the conf file with fsync().
   //    This ensures directory entries are up-to-date.
   int dir_fd = -1;
-  FILE* fp = NULL;
+  FILE* fp = nullptr;
+  std::stringstream serialized;
 
   // Build temp config file based on config file (e.g. bt_config.conf.new).
-  static const char* temp_file_ext = ".new";
-  const int filename_len = strlen(filename);
-  const int temp_filename_len = filename_len + strlen(temp_file_ext) + 1;
-  char* temp_filename = static_cast<char*>(osi_calloc(temp_filename_len));
-  snprintf(temp_filename, temp_filename_len, "%s%s", filename, temp_file_ext);
+  const std::string temp_filename = filename + ".new";
 
   // Extract directory from file path (e.g. /data/misc/bluedroid).
-  char* temp_dirname = osi_strdup(filename);
-  const char* directoryname = dirname(temp_dirname);
-  if (!directoryname) {
-    LOG_ERROR(LOG_TAG, "%s error extracting directory from '%s': %s", __func__,
-              filename, strerror(errno));
+  const std::string directoryname = base::FilePath(filename).DirName().value();
+  if (directoryname.empty()) {
+    LOG(ERROR) << __func__ << ": error extracting directory from '" << filename
+               << "': " << strerror(errno);
     goto error;
   }
 
-  dir_fd = open(directoryname, O_RDONLY);
+  dir_fd = open(directoryname.c_str(), O_RDONLY);
   if (dir_fd < 0) {
-    LOG_ERROR(LOG_TAG, "%s unable to open dir '%s': %s", __func__,
-              directoryname, strerror(errno));
+    LOG(ERROR) << __func__ << ": unable to open dir '" << directoryname
+               << "': " << strerror(errno);
     goto error;
   }
 
-  fp = fopen(temp_filename, "wt");
+  fp = fopen(temp_filename.c_str(), "wt");
   if (!fp) {
-    LOG_ERROR(LOG_TAG, "%s unable to write file '%s': %s", __func__,
-              temp_filename, strerror(errno));
+    LOG(ERROR) << __func__ << ": unable to write to file '" << temp_filename
+               << "': " << strerror(errno);
     goto error;
   }
 
-  for (const list_node_t* node = list_begin(config->sections);
-       node != list_end(config->sections); node = list_next(node)) {
-    const section_t* section = (const section_t*)list_node(node);
-    if (fprintf(fp, "[%s]\n", section->name) < 0) {
-      LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
-                temp_filename, strerror(errno));
-      goto error;
-    }
+  for (const section_t& section : config.sections) {
+    serialized << "[" << section.name << "]" << std::endl;
 
-    for (const list_node_t* enode = list_begin(section->entries);
-         enode != list_end(section->entries); enode = list_next(enode)) {
-      const entry_t* entry = (const entry_t*)list_node(enode);
-      if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) {
-        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
-                  temp_filename, strerror(errno));
-        goto error;
-      }
-    }
+    for (const entry_t& entry : section.entries)
+      serialized << entry.key << " = " << entry.value << std::endl;
 
-    // Only add a separating newline if there are more sections.
-    if (list_next(node) != list_end(config->sections)) {
-      if (fputc('\n', fp) == EOF) {
-        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
-                  temp_filename, strerror(errno));
-        goto error;
-      }
-    }
+    serialized << std::endl;
+  }
+
+  if (fprintf(fp, "%s", serialized.str().c_str()) < 0) {
+    LOG(ERROR) << __func__ << ": unable to write to file '" << temp_filename
+               << "': " << strerror(errno);
+    goto error;
   }
 
   // Sync written temp file out to disk. fsync() is blocking until data makes it
   // to disk.
   if (fsync(fileno(fp)) < 0) {
-    LOG_WARN(LOG_TAG, "%s unable to fsync file '%s': %s", __func__,
-             temp_filename, strerror(errno));
+    LOG(WARNING) << __func__ << ": unable to fsync file '" << temp_filename
+                 << "': " << strerror(errno);
   }
 
   if (fclose(fp) == EOF) {
-    LOG_ERROR(LOG_TAG, "%s unable to close file '%s': %s", __func__,
-              temp_filename, strerror(errno));
+    LOG(ERROR) << __func__ << ": unable to close file '" << temp_filename
+               << "': " << strerror(errno);
     goto error;
   }
-  fp = NULL;
+  fp = nullptr;
 
   // Change the file's permissions to Read/Write by User and Group
-  if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
-    LOG_ERROR(LOG_TAG, "%s unable to change file permissions '%s': %s",
-              __func__, filename, strerror(errno));
+  if (chmod(temp_filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) ==
+      -1) {
+    LOG(ERROR) << __func__ << ": unable to change file permissions '"
+               << filename << "': " << strerror(errno);
     goto error;
   }
 
   // Rename written temp file to the actual config file.
-  if (rename(temp_filename, filename) == -1) {
-    LOG_ERROR(LOG_TAG, "%s unable to commit file '%s': %s", __func__, filename,
-              strerror(errno));
+  if (rename(temp_filename.c_str(), filename.c_str()) == -1) {
+    LOG(ERROR) << __func__ << ": unable to commit file '" << filename
+               << "': " << strerror(errno);
     goto error;
   }
 
   // This should ensure the directory is updated as well.
   if (fsync(dir_fd) < 0) {
-    LOG_WARN(LOG_TAG, "%s unable to fsync dir '%s': %s", __func__,
-             directoryname, strerror(errno));
+    LOG(WARNING) << __func__ << ": unable to fsync dir '" << directoryname
+                 << "': " << strerror(errno);
   }
 
   if (close(dir_fd) < 0) {
-    LOG_ERROR(LOG_TAG, "%s unable to close dir '%s': %s", __func__,
-              directoryname, strerror(errno));
+    LOG(ERROR) << __func__ << ": unable to close dir '" << directoryname
+               << "': " << strerror(errno);
     goto error;
   }
 
-  osi_free(temp_filename);
-  osi_free(temp_dirname);
   return true;
 
 error:
   // This indicates there is a write issue.  Unlink as partial data is not
   // acceptable.
-  unlink(temp_filename);
+  unlink(temp_filename.c_str());
   if (fp) fclose(fp);
   if (dir_fd != -1) close(dir_fd);
-  osi_free(temp_filename);
-  osi_free(temp_dirname);
   return false;
 }
 
@@ -430,8 +337,8 @@
 }
 
 static bool config_parse(FILE* fp, config_t* config) {
-  CHECK(fp != NULL);
-  CHECK(config != NULL);
+  CHECK(fp != nullptr);
+  CHECK(config != nullptr);
 
   int line_num = 0;
   char line[1024];
@@ -448,17 +355,17 @@
     if (*line_ptr == '[') {
       size_t len = strlen(line_ptr);
       if (line_ptr[len - 1] != ']') {
-        LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__,
-                  line_num);
+        VLOG(1) << __func__ << ": unterminated section name on line "
+                << line_num;
         return false;
       }
-      strncpy(section, line_ptr + 1, len - 2);
+      strncpy(section, line_ptr + 1, len - 2);  // NOLINT (len < 1024)
       section[len - 2] = '\0';
     } else {
       char* split = strchr(line_ptr, '=');
       if (!split) {
-        LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.",
-                  __func__, line_num);
+        VLOG(1) << __func__ << ": no key/value separator found on line "
+                << line_num;
         return false;
       }
 
@@ -468,61 +375,3 @@
   }
   return true;
 }
-
-static section_t* section_new(const char* name) {
-  section_t* section = static_cast<section_t*>(osi_calloc(sizeof(section_t)));
-
-  section->name = osi_strdup(name);
-  section->entries = list_new(entry_free);
-  return section;
-}
-
-static void section_free(void* ptr) {
-  if (!ptr) return;
-
-  section_t* section = static_cast<section_t*>(ptr);
-  osi_free(section->name);
-  list_free(section->entries);
-  osi_free(section);
-}
-
-static section_t* section_find(const config_t* config, const char* section) {
-  for (const list_node_t* node = list_begin(config->sections);
-       node != list_end(config->sections); node = list_next(node)) {
-    section_t* sec = static_cast<section_t*>(list_node(node));
-    if (!strcmp(sec->name, section)) return sec;
-  }
-
-  return NULL;
-}
-
-static entry_t* entry_new(const char* key, const char* value) {
-  entry_t* entry = static_cast<entry_t*>(osi_calloc(sizeof(entry_t)));
-
-  entry->key = osi_strdup(key);
-  entry->value = osi_strdup(value);
-  return entry;
-}
-
-static void entry_free(void* ptr) {
-  if (!ptr) return;
-
-  entry_t* entry = static_cast<entry_t*>(ptr);
-  osi_free(entry->key);
-  osi_free(entry->value);
-  osi_free(entry);
-}
-
-static entry_t* entry_find(const config_t* config, const char* section,
-                           const char* key) {
-  section_t* sec = section_find(config, section);
-  if (!sec) return NULL;
-
-  for (const list_node_t* node = list_begin(sec->entries);
-       node != list_end(sec->entries); node = list_next(node)) {
-    entry_t* entry = static_cast<entry_t*>(list_node(node));
-    if (!strcmp(entry->key, key)) return entry;
-  }
-
-  return NULL;
-}
diff --git a/osi/src/fixed_queue.cc b/osi/src/fixed_queue.cc
index c384050..81bd66d 100644
--- a/osi/src/fixed_queue.cc
+++ b/osi/src/fixed_queue.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/future.cc b/osi/src/future.cc
index cbfd91a..e5347a4 100644
--- a/osi/src/future.cc
+++ b/osi/src/future.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/hash_map_utils.cc b/osi/src/hash_map_utils.cc
index c934cfb..6cd58de 100644
--- a/osi/src/hash_map_utils.cc
+++ b/osi/src/hash_map_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/metrics.cc b/osi/src/metrics.cc
index f31bf4e..73450b9 100644
--- a/osi/src/metrics.cc
+++ b/osi/src/metrics.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 
 #include <unistd.h>
 #include <algorithm>
+#include <array>
 #include <cerrno>
 #include <chrono>
 #include <cstdint>
@@ -28,33 +29,41 @@
 
 #include <base/base64.h>
 #include <base/logging.h>
+#include <include/hardware/bt_av.h>
 
+#include "bluetooth/metrics/bluetooth.pb.h"
 #include "osi/include/leaky_bonded_queue.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "osi/include/time.h"
 #include "stack/include/btm_api_types.h"
 
-#include "src/protos/bluetooth.pb.h"
-
 #include "osi/include/metrics.h"
 
 namespace system_bt_osi {
 
-using clearcut::connectivity::A2DPSession;
-using clearcut::connectivity::BluetoothLog;
-using clearcut::connectivity::BluetoothSession;
-using clearcut::connectivity::BluetoothSession_ConnectionTechnologyType;
-using clearcut::connectivity::BluetoothSession_DisconnectReasonType;
-using clearcut::connectivity::DeviceInfo;
-using clearcut::connectivity::DeviceInfo_DeviceType;
-using clearcut::connectivity::PairEvent;
-using clearcut::connectivity::ScanEvent;
-using clearcut::connectivity::ScanEvent_ScanTechnologyType;
-using clearcut::connectivity::ScanEvent_ScanEventType;
-using clearcut::connectivity::WakeEvent;
-using clearcut::connectivity::WakeEvent_WakeEventType;
-
+using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
+using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
+using bluetooth::metrics::BluetoothMetricsProto::
+    BluetoothSession_ConnectionTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::
+    BluetoothSession_DisconnectReasonType;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
+using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MIN;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MAX;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_ARRAYSIZE;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_IsValid;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
 /*
  * Get current OS boot time in millisecond
  */
@@ -133,6 +142,12 @@
       buffer_underruns_count += metrics.buffer_underruns_count;
     }
   }
+  if (codec_index < 0) {
+    codec_index = metrics.codec_index;
+  }
+  if (!is_a2dp_offload) {
+    is_a2dp_offload = metrics.is_a2dp_offload;
+  }
 }
 
 bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
@@ -144,7 +159,9 @@
          buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
          buffer_overruns_total == rhs.buffer_overruns_total &&
          buffer_underruns_average == rhs.buffer_underruns_average &&
-         buffer_underruns_count == rhs.buffer_underruns_count;
+         buffer_underruns_count == rhs.buffer_underruns_count &&
+         codec_index == rhs.codec_index &&
+         is_a2dp_offload == rhs.is_a2dp_offload;
 }
 
 static DeviceInfo_DeviceType get_device_type(device_type_t type) {
@@ -223,6 +240,23 @@
   }
 }
 
+static A2dpSourceCodec get_a2dp_source_codec(int64_t codec_index) {
+  switch (codec_index) {
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+      return A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      return A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+      return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+      return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX_HD;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+      return A2dpSourceCodec::A2DP_SOURCE_CODEC_LDAC;
+    default:
+      return A2dpSourceCodec::A2DP_SOURCE_CODEC_UNKNOWN;
+  }
+}
+
 struct BluetoothMetricsLogger::impl {
   impl(size_t max_bluetooth_session, size_t max_pair_event,
        size_t max_wake_event, size_t max_scan_event)
@@ -232,6 +266,7 @@
         wake_event_queue_(new LeakyBondedQueue<WakeEvent>(max_wake_event)),
         scan_event_queue_(new LeakyBondedQueue<ScanEvent>(max_scan_event)) {
     bluetooth_log_ = BluetoothLog::default_instance().New();
+    headset_profile_connection_counts_.fill(0);
     bluetooth_session_ = nullptr;
     bluetooth_session_start_time_ms_ = 0;
     a2dp_session_metrics_ = A2dpSessionMetrics();
@@ -239,6 +274,8 @@
 
   /* Bluetooth log lock protected */
   BluetoothLog* bluetooth_log_;
+  std::array<int, HeadsetProfileType_ARRAYSIZE>
+      headset_profile_connection_counts_;
   std::recursive_mutex bluetooth_log_lock_;
   /* End Bluetooth log lock protected */
   /* Bluetooth session lock protected */
@@ -346,6 +383,7 @@
       get_disconnect_reason_type(disconnect_reason));
   pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
   pimpl_->bluetooth_session_ = nullptr;
+  pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
   {
     std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
     pimpl_->bluetooth_log_->set_num_bluetooth_session(
@@ -394,31 +432,50 @@
       pimpl_->a2dp_session_metrics_.buffer_underruns_average);
   a2dp_session->set_buffer_underruns_count(
       pimpl_->a2dp_session_metrics_.buffer_underruns_count);
+  a2dp_session->set_source_codec(
+      get_a2dp_source_codec(pimpl_->a2dp_session_metrics_.codec_index));
+  a2dp_session->set_is_a2dp_offload(
+      pimpl_->a2dp_session_metrics_.is_a2dp_offload);
 }
 
-void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
+void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
+    tBTA_SERVICE_ID service_id) {
+  std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+  switch (service_id) {
+    case BTA_HSP_SERVICE_ID:
+      pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HSP]++;
+      break;
+    case BTA_HFP_SERVICE_ID:
+      pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HFP]++;
+      break;
+    default:
+      pimpl_->headset_profile_connection_counts_
+          [HeadsetProfileType::HEADSET_PROFILE_UNKNOWN]++;
+      break;
+  }
+  return;
+}
+
+void BluetoothMetricsLogger::WriteString(std::string* serialized) {
   std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
   LOG_DEBUG(LOG_TAG, "%s building metrics", __func__);
   Build();
   LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
   if (!pimpl_->bluetooth_log_->SerializeToString(serialized)) {
     LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
-    return;
   }
-  if (clear) {
-    pimpl_->bluetooth_log_->Clear();
-  }
+  // Always clean up log objects
+  pimpl_->bluetooth_log_->Clear();
 }
 
-void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
-                                               bool clear) {
-  this->WriteString(serialized, clear);
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized) {
+  this->WriteString(serialized);
   base::Base64Encode(*serialized, serialized);
 }
 
-void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
+void BluetoothMetricsLogger::WriteBase64(int fd) {
   std::string protoBase64;
-  this->WriteBase64String(&protoBase64, clear);
+  this->WriteBase64String(&protoBase64);
   ssize_t ret;
   OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
   if (ret == -1) {
@@ -475,6 +532,19 @@
     bluetooth_log->mutable_wake_event()->AddAllocated(
         pimpl_->wake_event_queue_->Dequeue());
   }
+  for (size_t i = 0; i < HeadsetProfileType_ARRAYSIZE; ++i) {
+    int num_times_connected = pimpl_->headset_profile_connection_counts_[i];
+    if (HeadsetProfileType_IsValid(i) && num_times_connected > 0) {
+      HeadsetProfileConnectionStats* headset_profile_connection_stats =
+          bluetooth_log->add_headset_profile_connection_stats();
+      // Able to static_cast because HeadsetProfileType_IsValid(i) is true
+      headset_profile_connection_stats->set_headset_profile_type(
+          static_cast<HeadsetProfileType>(i));
+      headset_profile_connection_stats->set_num_times_connected(
+          num_times_connected);
+    }
+  }
+  pimpl_->headset_profile_connection_counts_.fill(0);
 }
 
 void BluetoothMetricsLogger::ResetSession() {
diff --git a/osi/src/metrics_linux.cc b/osi/src/metrics_linux.cc
index 3169131..162f4ca 100644
--- a/osi/src/metrics_linux.cc
+++ b/osi/src/metrics_linux.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/mutex.cc b/osi/src/mutex.cc
index fbbef40..0634f09 100644
--- a/osi/src/mutex.cc
+++ b/osi/src/mutex.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/osi.cc b/osi/src/osi.cc
index 0109a95..73d6c1a 100644
--- a/osi/src/osi.cc
+++ b/osi/src/osi.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/properties.cc b/osi/src/properties.cc
index 7392953..c20b39f 100644
--- a/osi/src/properties.cc
+++ b/osi/src/properties.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,6 +20,14 @@
 
 #include "osi/include/properties.h"
 
+#if !defined(OS_GENERIC)
+#undef PROPERTY_VALUE_MAX
+#include <cutils/properties.h>
+#if BUILD_SANITY_PROPERTY_VALUE_MAX != PROPERTY_VALUE_MAX
+#error "PROPERTY_VALUE_MAX from osi/include/properties.h != the Android value"
+#endif  // GENERIC_PROPERTY_VALUE_MAX != PROPERTY_VALUE_MAX
+#endif  // !defined(OS_GENERIC)
+
 int osi_property_get(const char* key, char* value, const char* default_value) {
 #if defined(OS_GENERIC)
   /* For linux right now just return default value, if present */
@@ -52,3 +60,11 @@
   return property_get_int32(key, default_value);
 #endif  // defined(OS_GENERIC)
 }
+
+bool osi_property_get_bool(const char* key, bool default_value) {
+#if defined(OS_GENERIC)
+  return default_value;
+#else
+  return property_get_bool(key, default_value);
+#endif  // defined(OS_GENERIC)
+}
\ No newline at end of file
diff --git a/osi/src/reactor.cc b/osi/src/reactor.cc
index 7f88df9..ce1251c 100644
--- a/osi/src/reactor.cc
+++ b/osi/src/reactor.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/ringbuffer.cc b/osi/src/ringbuffer.cc
index 5c7874d..4f7988a 100644
--- a/osi/src/ringbuffer.cc
+++ b/osi/src/ringbuffer.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google Inc.
+ *  Copyright 2015 Google Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/semaphore.cc b/osi/src/semaphore.cc
index 097f32e..a943aa7 100644
--- a/osi/src/semaphore.cc
+++ b/osi/src/semaphore.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/socket.cc b/osi/src/socket.cc
index 201f976..3f9366f 100644
--- a/osi/src/socket.cc
+++ b/osi/src/socket.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/socket_utils/README b/osi/src/socket_utils/README
index 9ed210a..ac744fd 100644
--- a/osi/src/socket_utils/README
+++ b/osi/src/socket_utils/README
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright 2015 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.
diff --git a/osi/src/socket_utils/socket_local_client.cc b/osi/src/socket_utils/socket_local_client.cc
index 7338407..14f8b83 100644
--- a/osi/src/socket_utils/socket_local_client.cc
+++ b/osi/src/socket_utils/socket_local_client.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright 2006 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.
diff --git a/osi/src/socket_utils/socket_local_server.cc b/osi/src/socket_utils/socket_local_server.cc
index 9bfdf54..9710ab2 100644
--- a/osi/src/socket_utils/socket_local_server.cc
+++ b/osi/src/socket_utils/socket_local_server.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, The Android Open Source Project
+ * Copyright 2006, 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.
diff --git a/osi/src/thread.cc b/osi/src/thread.cc
index 61b44f2..e164083 100644
--- a/osi/src/thread.cc
+++ b/osi/src/thread.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/time.cc b/osi/src/time.cc
index 0b7f3a1..1a47504 100644
--- a/osi/src/time.cc
+++ b/osi/src/time.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/src/wakelock.cc b/osi/src/wakelock.cc
index 565735f..46c462c 100644
--- a/osi/src/wakelock.cc
+++ b/osi/src/wakelock.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/AlarmTestHarness.cc b/osi/test/AlarmTestHarness.cc
index ee6aaa3..ad890c4 100644
--- a/osi/test/AlarmTestHarness.cc
+++ b/osi/test/AlarmTestHarness.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/AlarmTestHarness.h b/osi/test/AlarmTestHarness.h
index 39dd218..38be959 100644
--- a/osi/test/AlarmTestHarness.h
+++ b/osi/test/AlarmTestHarness.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/AllocationTestHarness.cc b/osi/test/AllocationTestHarness.cc
index 8df097f..a8582424 100644
--- a/osi/test/AllocationTestHarness.cc
+++ b/osi/test/AllocationTestHarness.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/AllocationTestHarness.h b/osi/test/AllocationTestHarness.h
index cbf29d8..0c6b98e 100644
--- a/osi/test/AllocationTestHarness.h
+++ b/osi/test/AllocationTestHarness.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/alarm_test.cc b/osi/test/alarm_test.cc
index 2eed78f..f7f473d 100644
--- a/osi/test/alarm_test.cc
+++ b/osi/test/alarm_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -347,7 +347,8 @@
 
   for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
 
-  message_loop_->PostTask(FROM_HERE, run_loop_->QuitWhenIdleClosure());
+  message_loop_->task_runner()->PostTask(FROM_HERE,
+                                         run_loop_->QuitWhenIdleClosure());
   thread_free(message_loop_thread_);
   EXPECT_FALSE(WakeLockHeld());
 }
diff --git a/osi/test/allocation_tracker_test.cc b/osi/test/allocation_tracker_test.cc
index cf979cb..6ce0e69 100644
--- a/osi/test/allocation_tracker_test.cc
+++ b/osi/test/allocation_tracker_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/allocator_test.cc b/osi/test/allocator_test.cc
index 9dc6302..1e09f71 100644
--- a/osi/test/allocator_test.cc
+++ b/osi/test/allocator_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/config_test.cc b/osi/test/config_test.cc
index 6712222..58ce818 100644
--- a/osi/test/config_test.cc
+++ b/osi/test/config_test.cc
@@ -44,6 +44,9 @@
 [DID]                                                                                \n\
 [DID]                                                                                \n\
 version = 0x1436                                                                     \n\
+                                                                                     \n\
+HiSyncId = 18446744073709551615                                                      \n\
+HiSyncId2 = 15001900                                                                 \n\
 ";
 
 class ConfigTest : public AllocationTestHarness {
@@ -57,146 +60,116 @@
 };
 
 TEST_F(ConfigTest, config_new_empty) {
-  config_t* config = config_new_empty();
-  EXPECT_TRUE(config != NULL);
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new_empty();
+  EXPECT_TRUE(config.get() != NULL);
 }
 
 TEST_F(ConfigTest, config_new_no_file) {
-  config_t* config = config_new("/meow");
-  EXPECT_TRUE(config == NULL);
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new("/meow");
+  EXPECT_TRUE(config.get() == NULL);
 }
 
 TEST_F(ConfigTest, config_new) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_TRUE(config != NULL);
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config.get() != NULL);
 }
 
-TEST_F(ConfigTest, config_free_null) { config_free(NULL); }
-
 TEST_F(ConfigTest, config_new_clone) {
-  config_t* config = config_new(CONFIG_FILE);
-  config_t* clone = config_new_clone(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  std::unique_ptr<config_t> clone = config_new_clone(*config);
 
-  config_set_string(clone, CONFIG_DEFAULT_SECTION, "first_key", "not_value");
+  config_set_string(clone.get(), CONFIG_DEFAULT_SECTION, "first_key",
+                    "not_value");
 
+  std::string one = std::string("one");
   EXPECT_STRNE(
-      config_get_string(config, CONFIG_DEFAULT_SECTION, "first_key", "one"),
-      config_get_string(clone, CONFIG_DEFAULT_SECTION, "first_key", "one"));
-
-  config_free(config);
-  config_free(clone);
+      config_get_string(*config, CONFIG_DEFAULT_SECTION, "first_key", &one)
+          ->c_str(),
+      config_get_string(*clone, CONFIG_DEFAULT_SECTION, "first_key", &one)
+          ->c_str());
 }
 
 TEST_F(ConfigTest, config_has_section) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_TRUE(config_has_section(config, "DID"));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_has_section(*config, "DID"));
 }
 
 TEST_F(ConfigTest, config_has_key_in_default_section) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_TRUE(config_has_key(config, CONFIG_DEFAULT_SECTION, "first_key"));
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_has_key(*config, CONFIG_DEFAULT_SECTION, "first_key"));
   EXPECT_STREQ(
-      config_get_string(config, CONFIG_DEFAULT_SECTION, "first_key", "meow"),
+      config_get_string(*config, CONFIG_DEFAULT_SECTION, "first_key", nullptr)
+          ->c_str(),
       "value");
-  config_free(config);
 }
 
 TEST_F(ConfigTest, config_has_keys) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_TRUE(config_has_key(config, "DID", "recordNumber"));
-  EXPECT_TRUE(config_has_key(config, "DID", "primaryRecord"));
-  EXPECT_TRUE(config_has_key(config, "DID", "productId"));
-  EXPECT_TRUE(config_has_key(config, "DID", "version"));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_has_key(*config, "DID", "recordNumber"));
+  EXPECT_TRUE(config_has_key(*config, "DID", "primaryRecord"));
+  EXPECT_TRUE(config_has_key(*config, "DID", "productId"));
+  EXPECT_TRUE(config_has_key(*config, "DID", "version"));
 }
 
 TEST_F(ConfigTest, config_no_bad_keys) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_FALSE(config_has_key(config, "DID_BAD", "primaryRecord"));
-  EXPECT_FALSE(config_has_key(config, "DID", "primaryRecord_BAD"));
-  EXPECT_FALSE(config_has_key(config, CONFIG_DEFAULT_SECTION, "primaryRecord"));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_FALSE(config_has_key(*config, "DID_BAD", "primaryRecord"));
+  EXPECT_FALSE(config_has_key(*config, "DID", "primaryRecord_BAD"));
+  EXPECT_FALSE(
+      config_has_key(*config, CONFIG_DEFAULT_SECTION, "primaryRecord"));
 }
 
 TEST_F(ConfigTest, config_get_int_version) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_EQ(config_get_int(config, "DID", "version", 0), 0x1436);
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(*config, "DID", "version", 0), 0x1436);
 }
 
 TEST_F(ConfigTest, config_get_int_default) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_EQ(config_get_int(config, "DID", "primaryRecord", 123), 123);
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(*config, "DID", "primaryRecord", 123), 123);
+}
+
+TEST_F(ConfigTest, config_get_uint64) {
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_uint64(*config, "DID", "HiSyncId", 0),
+            0xFFFFFFFFFFFFFFFF);
+  EXPECT_EQ(config_get_uint64(*config, "DID", "HiSyncId2", 0),
+            uint64_t(15001900));
+}
+
+TEST_F(ConfigTest, config_get_uint64_default) {
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_uint64(*config, "DID", "primaryRecord", 123),
+            uint64_t(123));
 }
 
 TEST_F(ConfigTest, config_remove_section) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_TRUE(config_remove_section(config, "DID"));
-  EXPECT_FALSE(config_has_section(config, "DID"));
-  EXPECT_FALSE(config_has_key(config, "DID", "productId"));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_remove_section(config.get(), "DID"));
+  EXPECT_FALSE(config_has_section(*config, "DID"));
+  EXPECT_FALSE(config_has_key(*config, "DID", "productId"));
 }
 
 TEST_F(ConfigTest, config_remove_section_missing) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_FALSE(config_remove_section(config, "not a section"));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_FALSE(config_remove_section(config.get(), "not a section"));
 }
 
 TEST_F(ConfigTest, config_remove_key) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 0x1200);
-  EXPECT_TRUE(config_remove_key(config, "DID", "productId"));
-  EXPECT_FALSE(config_has_key(config, "DID", "productId"));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(*config, "DID", "productId", 999), 0x1200);
+  EXPECT_TRUE(config_remove_key(config.get(), "DID", "productId"));
+  EXPECT_FALSE(config_has_key(*config, "DID", "productId"));
 }
 
 TEST_F(ConfigTest, config_remove_key_missing) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 0x1200);
-  EXPECT_TRUE(config_remove_key(config, "DID", "productId"));
-  EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 999);
-  config_free(config);
-}
-
-TEST_F(ConfigTest, config_section_begin) {
-  config_t* config = config_new(CONFIG_FILE);
-  const config_section_node_t* section = config_section_begin(config);
-  EXPECT_TRUE(section != NULL);
-  const char* section_name = config_section_name(section);
-  EXPECT_TRUE(section != NULL);
-  EXPECT_TRUE(!strcmp(section_name, CONFIG_DEFAULT_SECTION));
-  config_free(config);
-}
-
-TEST_F(ConfigTest, config_section_next) {
-  config_t* config = config_new(CONFIG_FILE);
-  const config_section_node_t* section = config_section_begin(config);
-  EXPECT_TRUE(section != NULL);
-  section = config_section_next(section);
-  EXPECT_TRUE(section != NULL);
-  const char* section_name = config_section_name(section);
-  EXPECT_TRUE(section != NULL);
-  EXPECT_TRUE(!strcmp(section_name, "DID"));
-  config_free(config);
-}
-
-TEST_F(ConfigTest, config_section_end) {
-  config_t* config = config_new(CONFIG_FILE);
-  const config_section_node_t* section = config_section_begin(config);
-  section = config_section_next(section);
-  section = config_section_next(section);
-  EXPECT_EQ(section, config_section_end(config));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(*config, "DID", "productId", 999), 0x1200);
+  EXPECT_TRUE(config_remove_key(config.get(), "DID", "productId"));
+  EXPECT_EQ(config_get_int(*config, "DID", "productId", 999), 999);
 }
 
 TEST_F(ConfigTest, config_save_basic) {
-  config_t* config = config_new(CONFIG_FILE);
-  EXPECT_TRUE(config_save(config, CONFIG_FILE));
-  config_free(config);
+  std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_save(*config, CONFIG_FILE));
 }
diff --git a/osi/test/future_test.cc b/osi/test/future_test.cc
index fe5e7fd..26d319a 100644
--- a/osi/test/future_test.cc
+++ b/osi/test/future_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/hash_map_utils_test.cc b/osi/test/hash_map_utils_test.cc
index 0e483e5..1e312d4 100644
--- a/osi/test/hash_map_utils_test.cc
+++ b/osi/test/hash_map_utils_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/leaky_bonded_queue_test.cc b/osi/test/leaky_bonded_queue_test.cc
index c538101..116676b 100644
--- a/osi/test/leaky_bonded_queue_test.cc
+++ b/osi/test/leaky_bonded_queue_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,10 +26,10 @@
 
 using system_bt_osi::LeakyBondedQueue;
 
-#define ITEM_EQ(a, b)              \
-  do {                             \
-    EXPECT_EQ(a, b);               \
-    EXPECT_EQ(a->index, b->index); \
+#define ITEM_EQ(a, b)                  \
+  do {                                 \
+    EXPECT_EQ(a, b);                   \
+    EXPECT_EQ((a)->index, (b)->index); \
   } while (0)
 
 class Item {
diff --git a/osi/test/metrics_test.cc b/osi/test/metrics_test.cc
index a8de2fc..bfb548f 100644
--- a/osi/test/metrics_test.cc
+++ b/osi/test/metrics_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,29 +25,35 @@
 #include <gtest/gtest.h>
 
 #include <base/logging.h>
+#include <include/hardware/bt_av.h>
 
+#include "bluetooth/metrics/bluetooth.pb.h"
 #include "osi/include/metrics.h"
 #include "osi/include/time.h"
-#include "src/protos/bluetooth.pb.h"
 
 #define BTM_COD_MAJOR_AUDIO_TEST 0x04
 
 namespace testing {
 
-using clearcut::connectivity::A2DPSession;
-using clearcut::connectivity::BluetoothLog;
-using clearcut::connectivity::BluetoothSession;
-using clearcut::connectivity::BluetoothSession_ConnectionTechnologyType;
-using clearcut::connectivity::BluetoothSession_DisconnectReasonType;
-using clearcut::connectivity::DeviceInfo;
-using clearcut::connectivity::DeviceInfo_DeviceType;
-using clearcut::connectivity::PairEvent;
-using clearcut::connectivity::RFCommSession;
-using clearcut::connectivity::ScanEvent;
-using clearcut::connectivity::ScanEvent_ScanTechnologyType;
-using clearcut::connectivity::ScanEvent_ScanEventType;
-using clearcut::connectivity::WakeEvent;
-using clearcut::connectivity::WakeEvent_WakeEventType;
+using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
+using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
+using bluetooth::metrics::BluetoothMetricsProto::
+    BluetoothSession_ConnectionTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::
+    BluetoothSession_DisconnectReasonType;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
+using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
+using bluetooth::metrics::BluetoothMetricsProto::RFCommSession;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
 using system_bt_osi::BluetoothMetricsLogger;
 using system_bt_osi::A2dpSessionMetrics;
 
@@ -107,7 +113,8 @@
   return event;
 }
 
-A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics) {
+A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics,
+                             A2dpSourceCodec source_codec) {
   A2DPSession* session = new A2DPSession();
   session->set_media_timer_min_millis(metrics.media_timer_min_ms);
   session->set_media_timer_max_millis(metrics.media_timer_max_ms);
@@ -117,6 +124,8 @@
   session->set_buffer_underruns_average(metrics.buffer_underruns_average);
   session->set_buffer_underruns_count(metrics.buffer_underruns_count);
   session->set_audio_duration_millis(metrics.audio_duration_ms);
+  session->set_source_codec(source_codec);
+  session->set_is_a2dp_offload(metrics.is_a2dp_offload);
   return session;
 }
 
@@ -170,19 +179,21 @@
   }
 }
 
-#define COMPARE_A2DP_METRICS(a, b)                                       \
-  do {                                                                   \
-    EXPECT_EQ(a.audio_duration_ms, b.audio_duration_ms);                 \
-    EXPECT_EQ(a.media_timer_min_ms, b.media_timer_min_ms);               \
-    EXPECT_EQ(a.media_timer_max_ms, b.media_timer_max_ms);               \
-    EXPECT_EQ(a.media_timer_avg_ms, b.media_timer_avg_ms);               \
-    EXPECT_EQ(a.total_scheduling_count, b.total_scheduling_count);       \
-    EXPECT_EQ(a.buffer_overruns_max_count, b.buffer_overruns_max_count); \
-    EXPECT_EQ(a.buffer_overruns_total, b.buffer_overruns_total);         \
-    EXPECT_THAT(a.buffer_underruns_average,                              \
-                FloatNear(b.buffer_underruns_average, 0.01));            \
-    a.buffer_underruns_average = b.buffer_underruns_average;             \
-    EXPECT_EQ(a.buffer_underruns_count, b.buffer_underruns_count);       \
+#define COMPARE_A2DP_METRICS(a, b)                                           \
+  do {                                                                       \
+    EXPECT_EQ((a).audio_duration_ms, (b).audio_duration_ms);                 \
+    EXPECT_EQ((a).media_timer_min_ms, (b).media_timer_min_ms);               \
+    EXPECT_EQ((a).media_timer_max_ms, (b).media_timer_max_ms);               \
+    EXPECT_EQ((a).media_timer_avg_ms, (b).media_timer_avg_ms);               \
+    EXPECT_EQ((a).total_scheduling_count, (b).total_scheduling_count);       \
+    EXPECT_EQ((a).buffer_overruns_max_count, (b).buffer_overruns_max_count); \
+    EXPECT_EQ((a).buffer_overruns_total, (b).buffer_overruns_total);         \
+    EXPECT_THAT((a).buffer_underruns_average,                                \
+                FloatNear((b).buffer_underruns_average, 0.01));              \
+    (a).buffer_underruns_average = (b).buffer_underruns_average;             \
+    EXPECT_EQ((a).buffer_underruns_count, (b).buffer_underruns_count);       \
+    EXPECT_EQ((a).codec_index, (b).codec_index);                             \
+    EXPECT_EQ((a).is_a2dp_offload, (b).is_a2dp_offload);                     \
   } while (0)
 
 /*
@@ -216,6 +227,12 @@
   metrics2.buffer_underruns_count = 2400;
   metrics_sum.buffer_underruns_average = 113.33333333;
   metrics_sum.buffer_underruns_count = 3600;
+  metrics1.codec_index = -1;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  metrics1.is_a2dp_offload = false;
+  metrics2.is_a2dp_offload = true;
+  metrics_sum.is_a2dp_offload = true;
   metrics1.Update(metrics2);
   COMPARE_A2DP_METRICS(metrics1, metrics_sum);
   EXPECT_TRUE(metrics1 == metrics_sum);
@@ -242,6 +259,10 @@
   metrics2.buffer_underruns_count = 2400;
   metrics_sum.buffer_underruns_average = 130;
   metrics_sum.buffer_underruns_count = 2400;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+  metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+  metrics2.is_a2dp_offload = true;
+  metrics_sum.is_a2dp_offload = true;
   metrics1.Update(metrics2);
   COMPARE_A2DP_METRICS(metrics1, metrics_sum);
   EXPECT_TRUE(metrics1 == metrics_sum);
@@ -268,6 +289,10 @@
   metrics2.buffer_underruns_count = 2400;
   metrics_sum.buffer_underruns_average = 130;
   metrics_sum.buffer_underruns_count = 2400;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+  metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+  metrics2.is_a2dp_offload = true;
+  metrics_sum.is_a2dp_offload = true;
   metrics2.Update(metrics1);
   COMPARE_A2DP_METRICS(metrics2, metrics_sum);
   EXPECT_TRUE(metrics2 == metrics_sum);
@@ -406,7 +431,7 @@
   BluetoothMetricsLogger::GetInstance()->LogPairEvent(
       35, 12345, 42, system_bt_osi::DEVICE_TYPE_BREDR);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -418,7 +443,7 @@
   BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
       system_bt_osi::WAKE_EVENT_ACQUIRED, "TEST_REQ", "TEST_NAME", 12345);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -435,7 +460,7 @@
         "TEST_REQ", "TEST_NAME", i);
   }
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -449,7 +474,7 @@
   BluetoothMetricsLogger::GetInstance()->LogScanEvent(
       false, "TEST_INITIATOR", system_bt_osi::SCAN_TECH_TYPE_BREDR, 42, 123456);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -467,7 +492,7 @@
   BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
       system_bt_osi::DISCONNECT_REASON_UNKNOWN, 133456);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -484,7 +509,7 @@
       system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, time_get_os_boottime_ms());
   sleep_ms(1000);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -511,7 +536,7 @@
       system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, 0);
   sleep_ms(2000);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -556,10 +581,17 @@
   metrics2.buffer_underruns_count = 2400;
   metrics_sum.buffer_underruns_average = 113.33333333;
   metrics_sum.buffer_underruns_count = 3600;
+  metrics1.codec_index = -1;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  metrics1.is_a2dp_offload = false;
+  metrics2.is_a2dp_offload = true;
+  metrics_sum.is_a2dp_offload = true;
   DeviceInfo* info = MakeDeviceInfo(
       BTM_COD_MAJOR_AUDIO_TEST,
       DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
-  A2DPSession* session = MakeA2DPSession(metrics_sum);
+  A2DPSession* session =
+      MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
   bt_sessions_.push_back(MakeBluetoothSession(
       10,
       BluetoothSession_ConnectionTechnologyType::
@@ -577,7 +609,7 @@
   BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
       system_bt_osi::DISCONNECT_REASON_UNKNOWN, 133456);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -614,10 +646,13 @@
   metrics1.buffer_underruns_count = 1200;
   metrics2.buffer_underruns_average = 130;
   metrics2.buffer_underruns_count = 2400;
+  metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
   DeviceInfo* info = MakeDeviceInfo(
       BTM_COD_MAJOR_AUDIO_TEST,
       DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
-  A2DPSession* session = MakeA2DPSession(metrics1);
+  A2DPSession* session =
+      MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
   bt_sessions_.push_back(MakeBluetoothSession(
       1,
       BluetoothSession_ConnectionTechnologyType::
@@ -633,13 +668,13 @@
   BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
   sleep_ms(1000);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
   ClearLog();
   info = MakeDeviceInfo(
       BTM_COD_MAJOR_AUDIO_TEST,
       DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
-  session = MakeA2DPSession(metrics2);
+  session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
   bt_sessions_.push_back(MakeBluetoothSession(
       1,
       BluetoothSession_ConnectionTechnologyType::
@@ -653,7 +688,87 @@
   BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
       system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
   msg_str.clear();
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+  EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesSeparatedbyEndTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogA2dpSession
+ * 4. LogBluetoothSessionEnd
+ * 5. LogBluetoothSessionStart
+ * 6. LogA2dpSession
+ * 7. LogBluetoothSessionEnd
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyEndTest) {
+  /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+  A2dpSessionMetrics metrics1;
+  metrics1.audio_duration_ms = 10;
+  metrics1.media_timer_min_ms = 10;
+  metrics1.media_timer_max_ms = 100;
+  metrics1.media_timer_avg_ms = 50;
+  metrics1.total_scheduling_count = 50;
+  metrics1.buffer_overruns_max_count = 70;
+  metrics1.buffer_underruns_average = 80;
+  metrics1.buffer_underruns_count = 1200;
+  metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+  DeviceInfo* info = MakeDeviceInfo(
+      BTM_COD_MAJOR_AUDIO_TEST,
+      DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+  A2DPSession* session =
+      MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
+  bt_sessions_.push_back(MakeBluetoothSession(
+      1,
+      BluetoothSession_ConnectionTechnologyType::
+          BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+      BluetoothSession_DisconnectReasonType::
+          BluetoothSession_DisconnectReasonType_UNKNOWN,
+      info, nullptr, session));
+  UpdateLog();
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+      system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+      BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
+  BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+  sleep_ms(1000);
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+      system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+  std::string msg_str;
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+  EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+  ClearLog();
+  A2dpSessionMetrics metrics2;
+  metrics2.audio_duration_ms = 25;
+  metrics2.media_timer_min_ms = 25;
+  metrics2.media_timer_max_ms = 200;
+  metrics2.media_timer_avg_ms = 100;
+  metrics2.total_scheduling_count = 50;
+  metrics2.buffer_overruns_max_count = 80;
+  metrics2.buffer_underruns_average = 130;
+  metrics2.buffer_underruns_count = 2400;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
+  bt_sessions_.push_back(MakeBluetoothSession(
+      1,
+      BluetoothSession_ConnectionTechnologyType::
+          BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+      BluetoothSession_DisconnectReasonType::
+          BluetoothSession_DisconnectReasonType_UNKNOWN,
+      nullptr, nullptr, session));
+  UpdateLog();
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+      system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+  sleep_ms(1000);
+  BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+  BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+      system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+  msg_str.clear();
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -696,10 +811,14 @@
   metrics2.buffer_underruns_count = 2400;
   metrics_sum.buffer_underruns_average = 113.33333333;
   metrics_sum.buffer_underruns_count = 3600;
+  metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
   DeviceInfo* info = MakeDeviceInfo(
       BTM_COD_MAJOR_AUDIO_TEST,
       DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
-  A2DPSession* session = MakeA2DPSession(metrics_sum);
+  A2DPSession* session =
+      MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
   bt_sessions_.push_back(MakeBluetoothSession(
       1,
       BluetoothSession_ConnectionTechnologyType::
@@ -712,7 +831,7 @@
   BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
   sleep_ms(1000);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
 
@@ -758,6 +877,9 @@
   metrics2.buffer_underruns_count = 2400;
   metrics_sum.buffer_underruns_average = 113.33333333;
   metrics_sum.buffer_underruns_count = 3600;
+  metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+  metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+  metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
   DeviceInfo* info = MakeDeviceInfo(
       BTM_COD_MAJOR_AUDIO_TEST,
       DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
@@ -775,13 +897,14 @@
       BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
   sleep_ms(1000);
   std::string msg_str;
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
   ClearLog();
   info = MakeDeviceInfo(
       BTM_COD_MAJOR_AUDIO_TEST,
       DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
-  A2DPSession* session = MakeA2DPSession(metrics_sum);
+  A2DPSession* session =
+      MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
   bt_sessions_.push_back(MakeBluetoothSession(
       1,
       BluetoothSession_ConnectionTechnologyType::
@@ -796,7 +919,94 @@
   BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
       system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
   msg_str.clear();
-  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
   EXPECT_THAT(msg_str, StrEq(bt_log_str_));
 }
+
+TEST_F(BluetoothMetricsLoggerTest, LogHeadsetProfileRfcConnectionTest) {
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_HSP_SERVICE_ID);
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_HFP_SERVICE_ID);
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_HFP_SERVICE_ID);
+  std::string msg_str;
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+  BluetoothLog* metrics = BluetoothLog::default_instance().New();
+  metrics->ParseFromString(msg_str);
+  EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 2);
+  bool hfp_correct = false;
+  bool hsp_correct = false;
+  for (const HeadsetProfileConnectionStats& headset_profile_connection_stats :
+       metrics->headset_profile_connection_stats()) {
+    switch (headset_profile_connection_stats.headset_profile_type()) {
+      case HeadsetProfileType::HFP:
+        EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 2);
+        hfp_correct = true;
+        break;
+      case HeadsetProfileType::HSP:
+        EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
+        hsp_correct = true;
+        break;
+      default:
+        FAIL();
+    }
+  }
+  EXPECT_TRUE(hfp_correct);
+  EXPECT_TRUE(hsp_correct);
+  metrics->clear_headset_profile_connection_stats();
+  EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+  msg_str.clear();
+  // Verify that dump after clean up result in an empty list
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+  metrics->ParseFromString(msg_str);
+  EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+  delete metrics;
+}
+
+TEST_F(BluetoothMetricsLoggerTest, LogHeadsetProfileRfcConnectionErrorTest) {
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_HSP_SERVICE_ID);
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_HFP_SERVICE_ID);
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_BIP_SERVICE_ID);
+  BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+      BTA_HSP_SERVICE_ID);
+  std::string msg_str;
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+  BluetoothLog* metrics = BluetoothLog::default_instance().New();
+  metrics->ParseFromString(msg_str);
+  EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 3);
+  bool hfp_correct = false;
+  bool hsp_correct = false;
+  bool unknown_correct = false;
+  for (const HeadsetProfileConnectionStats& headset_profile_connection_stats :
+       metrics->headset_profile_connection_stats()) {
+    switch (headset_profile_connection_stats.headset_profile_type()) {
+      case HeadsetProfileType::HFP:
+        EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
+        hfp_correct = true;
+        break;
+      case HeadsetProfileType::HSP:
+        EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 2);
+        hsp_correct = true;
+        break;
+      default:
+        EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
+        unknown_correct = true;
+        break;
+    }
+  }
+  EXPECT_TRUE(hfp_correct);
+  EXPECT_TRUE(hsp_correct);
+  EXPECT_TRUE(unknown_correct);
+  metrics->clear_headset_profile_connection_stats();
+  EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+  // Verify that dump after clean up result in an empty list
+  BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+  metrics->ParseFromString(msg_str);
+  EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+  delete metrics;
+}
 }
diff --git a/osi/test/properties_test.cc b/osi/test/properties_test.cc
index f8c503a..499f6f3 100644
--- a/osi/test/properties_test.cc
+++ b/osi/test/properties_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -53,4 +53,4 @@
 
   int32_t received = osi_property_get_int32("very.useful.set.test", 84);
   ASSERT_EQ(received, 42);
-}
+}
\ No newline at end of file
diff --git a/osi/test/test_stubs.h b/osi/test/test_stubs.h
index cbaa967..043fd37 100644
--- a/osi/test/test_stubs.h
+++ b/osi/test/test_stubs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/time_test.cc b/osi/test/time_test.cc
index 6b35c17..f14842d 100644
--- a/osi/test/time_test.cc
+++ b/osi/test/time_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/osi/test/wakelock_test.cc b/osi/test/wakelock_test.cc
index d1ff0a2..0e027be 100644
--- a/osi/test/wakelock_test.cc
+++ b/osi/test/wakelock_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/packet/Android.bp b/packet/Android.bp
new file mode 100644
index 0000000..8338c2d
--- /dev/null
+++ b/packet/Android.bp
@@ -0,0 +1,50 @@
+cc_library_static {
+    name: "lib-bt-packets",
+    defaults: ["libchrome_support_defaults"],
+    host_supported: true,
+    export_include_dirs: [
+        "./include",
+        "./",
+    ],
+    whole_static_libs: [
+        "lib-bt-packets-base",
+        "lib-bt-packets-avrcp",
+    ],
+}
+
+cc_test {
+    name: "net_test_btpackets",
+    defaults: ["fluoride_defaults"],
+    host_supported: true,
+    local_include_dirs: ["tests"],
+    srcs: [
+        "tests/avrcp/avrcp_browse_packet_test.cc",
+        "tests/avrcp/avrcp_packet_test.cc",
+        "tests/avrcp/avrcp_reject_packet_test.cc",
+        "tests/avrcp/change_path_packet_test.cc",
+        "tests/avrcp/general_reject_packet_test.cc",
+        "tests/avrcp/get_capabilities_packet_test.cc",
+        "tests/avrcp/get_element_attributes_packet_test.cc",
+        "tests/avrcp/get_folder_items_packet_test.cc",
+        "tests/avrcp/get_item_attributes_packet_test.cc",
+        "tests/avrcp/get_play_status_packet_test.cc",
+        "tests/avrcp/get_total_number_of_items_packet_test.cc",
+        "tests/avrcp/pass_through_packet_test.cc",
+        "tests/avrcp/play_item_packet_test.cc",
+        "tests/avrcp/register_notification_packet_test.cc",
+        "tests/avrcp/set_absolute_volume_packet_test.cc",
+        "tests/avrcp/set_addressed_player_packet_test.cc",
+        "tests/avrcp/set_browsed_player_packet_test.cc",
+        "tests/avrcp/vendor_packet_test.cc",
+        "tests/base/iterator_test.cc",
+        "tests/base/packet_builder_test.cc",
+        "tests/base/packet_test.cc",
+    ],
+    static_libs: [
+        "libgmock",
+        "lib-bt-packets",
+    ],
+    cflags: [
+        "-DBUILDCFG",
+    ],
+}
diff --git a/packet/avrcp/Android.bp b/packet/avrcp/Android.bp
new file mode 100644
index 0000000..80e93e8
--- /dev/null
+++ b/packet/avrcp/Android.bp
@@ -0,0 +1,31 @@
+cc_library_static {
+    name: "lib-bt-packets-avrcp",
+    defaults: ["libchrome_support_defaults"],
+    header_libs: ["avrcp_headers"],
+    export_header_lib_headers: ["avrcp_headers"],
+    export_include_dirs: ["."],
+    host_supported: true,
+    srcs: [
+        "avrcp_browse_packet.cc",
+        "avrcp_packet.cc",
+        "avrcp_reject_packet.cc",
+        "capabilities_packet.cc",
+        "change_path.cc",
+        "general_reject_packet.cc",
+        "get_element_attributes_packet.cc",
+        "get_folder_items.cc",
+        "get_item_attributes.cc",
+        "get_play_status_packet.cc",
+        "get_total_number_of_items.cc",
+        "pass_through_packet.cc",
+        "play_item.cc",
+        "register_notification_packet.cc",
+        "set_absolute_volume.cc",
+        "set_addressed_player.cc",
+        "set_browsed_player.cc",
+        "vendor_packet.cc",
+    ],
+    static_libs: [
+        "lib-bt-packets-base",
+    ],
+}
diff --git a/packet/avrcp/avrcp_browse_packet.cc b/packet/avrcp/avrcp_browse_packet.cc
new file mode 100644
index 0000000..f4a7691
--- /dev/null
+++ b/packet/avrcp/avrcp_browse_packet.cc
@@ -0,0 +1,91 @@
+/*
+ * 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 "avrcp_browse_packet.h"
+
+#include <base/logging.h>
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<BrowsePacketBuilder> BrowsePacketBuilder::MakeBuilder(
+    BrowsePdu pdu, std::unique_ptr<::bluetooth::PacketBuilder> payload) {
+  std::unique_ptr<BrowsePacketBuilder> builder =
+      std::unique_ptr<BrowsePacketBuilder>(new BrowsePacketBuilder(pdu));
+
+  builder->payload_ = std::move(payload);
+
+  return builder;
+}
+
+size_t BrowsePacketBuilder::size() const {
+  return BrowsePacket::kMinSize() + payload_->size();
+}
+
+bool BrowsePacketBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PushHeader(pkt, payload_->size());
+
+  return payload_->Serialize(pkt);
+}
+
+void BrowsePacketBuilder::PushHeader(
+    const std::shared_ptr<::bluetooth::Packet>& pkt, uint16_t length) {
+  AddPayloadOctets1(pkt, (uint8_t)pdu_);
+  AddPayloadOctets2(pkt, base::ByteSwap(length));
+}
+
+std::shared_ptr<BrowsePacket> BrowsePacket::Parse(
+    std::shared_ptr<::bluetooth::Packet> pkt) {
+  return std::shared_ptr<BrowsePacket>(new BrowsePacket(pkt));
+}
+
+BrowsePdu BrowsePacket::GetPdu() const {
+  return static_cast<BrowsePdu>(*begin());
+}
+
+uint16_t BrowsePacket::GetLength() const {
+  auto it = begin() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool BrowsePacket::IsValid() const {
+  if (size() < kMinSize()) return false;
+  return size() == GetLength() + kMinSize();
+}
+
+std::string BrowsePacket::ToString() const {
+  std::stringstream ss;
+  ss << "AvrcpBrowsePacket: " << std::endl;
+  ss << "  â”” PDU = " << GetPdu() << std::endl;
+  ss << "  â”” Length = " << GetLength() << std::endl;
+  ss << "  â”” Payload =";
+  for (auto it = begin() + static_cast<size_t>(3); it != end(); it++) {
+    ss << " " << loghex(*it);
+  }
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::pair<size_t, size_t> BrowsePacket::GetPayloadIndecies() const {
+  return std::pair<size_t, size_t>(packet_start_index_ + 3, packet_end_index_);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/avrcp_browse_packet.h b/packet/avrcp/avrcp_browse_packet.h
new file mode 100644
index 0000000..d62f0e2
--- /dev/null
+++ b/packet/avrcp/avrcp_browse_packet.h
@@ -0,0 +1,83 @@
+/*
+ * 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 <base/logging.h>
+#include <base/macros.h>
+#include <iostream>
+
+#include "avrcp_common.h"
+#include "avrcp_logging_helper.h"
+#include "iterator.h"
+#include "packet.h"
+#include "packet_builder.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class BrowsePacketBuilder : public ::bluetooth::PacketBuilder {
+ public:
+  virtual ~BrowsePacketBuilder() = default;
+
+  static std::unique_ptr<BrowsePacketBuilder> MakeBuilder(
+      BrowsePdu pdu, std::unique_ptr<::bluetooth::PacketBuilder> payload);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  BrowsePdu pdu_;
+  std::unique_ptr<::bluetooth::PacketBuilder> payload_;
+
+  void PushHeader(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                  uint16_t length);
+
+  BrowsePacketBuilder(BrowsePdu pdu) : pdu_(pdu){};
+};
+
+class BrowsePacket : public ::bluetooth::Packet {
+ public:
+  virtual ~BrowsePacket() = default;
+
+  static std::shared_ptr<BrowsePacket> Parse(
+      std::shared_ptr<::bluetooth::Packet> pkt);
+
+  /**
+   * Avrcp Browse Packet Layout
+   *   uint8_t pdu_;
+   *   uint16_t length_;
+   *   uint8_t[] payload_;
+   */
+  static constexpr size_t kMinSize() { return 3; }
+
+  BrowsePdu GetPdu() const;
+  uint16_t GetLength() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using ::bluetooth::Packet::Packet;
+
+ private:
+  virtual std::pair<size_t, size_t> GetPayloadIndecies() const;
+  DISALLOW_COPY_AND_ASSIGN(BrowsePacket);
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/avrcp_packet.cc b/packet/avrcp/avrcp_packet.cc
new file mode 100644
index 0000000..635759a
--- /dev/null
+++ b/packet/avrcp/avrcp_packet.cc
@@ -0,0 +1,117 @@
+/*
+ * 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 <iomanip>
+#include <sstream>
+#include <type_traits>
+
+#include "avrcp_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<PacketBuilder> PacketBuilder::MakeBuilder(
+    CType type, uint8_t subunit_type, uint8_t subunit_id, Opcode opcode,
+    std::unique_ptr<::bluetooth::PacketBuilder> payload) {
+  std::unique_ptr<PacketBuilder> builder = std::unique_ptr<PacketBuilder>(
+      new PacketBuilder(type, subunit_type, subunit_id, opcode));
+
+  builder->payload_ = std::move(payload);
+
+  return builder;
+}
+
+size_t PacketBuilder::size() const {
+  // The size of the header for an Packet is 3
+  return payload_->size() + Packet::kMinSize();
+}
+
+bool PacketBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  // Push the header for the packet
+  PushHeader(pkt);
+
+  // Push the payload for the packet
+  return payload_->Serialize(pkt);
+}
+
+void PacketBuilder::PushHeader(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(c_type_));
+  AddPayloadOctets1(pkt, (subunit_type_ << 3) | subunit_id_);
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(opcode_));
+}
+
+bool PacketBuilder::PushCompanyId(
+    const std::shared_ptr<::bluetooth::Packet>& pkt, uint32_t company_id) {
+  company_id = base::ByteSwap(company_id);
+  for (int i = 0; i < 3; i++) {
+    company_id >>= 8;
+    AddPayloadOctets1(pkt, company_id & 0xFF);
+  }
+
+  return true;
+}
+
+std::shared_ptr<Packet> Packet::Parse(
+    std::shared_ptr<::bluetooth::Packet> pkt) {
+  return std::shared_ptr<Packet>(new Packet(pkt));
+}
+
+CType Packet::GetCType() const {
+  auto value = *begin() & 0x0F;
+  return static_cast<CType>(value);
+}
+
+uint8_t Packet::GetSubunitType() const {
+  return *(begin() + static_cast<size_t>(1)) >> 3;
+}
+
+uint8_t Packet::GetSubunitId() const {
+  return *(begin() + static_cast<size_t>(1)) & 0b00000111;
+}
+
+Opcode Packet::GetOpcode() const {
+  auto value = *(begin() + static_cast<size_t>(2));
+  return static_cast<Opcode>(value);
+}
+
+bool Packet::IsValid() const { return size() >= kMinSize(); }
+
+std::string Packet::ToString() const {
+  std::stringstream ss;
+  ss << "avrcp::Packet: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Payload =";
+  for (auto it = begin() + static_cast<size_t>(3); it != end(); it++) {
+    ss << " " << loghex(*it);
+  }
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::pair<size_t, size_t> Packet::GetPayloadIndecies() const {
+  return std::pair<size_t, size_t>(packet_start_index_ + 3, packet_end_index_);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/avrcp_packet.h b/packet/avrcp/avrcp_packet.h
new file mode 100644
index 0000000..1e56186
--- /dev/null
+++ b/packet/avrcp/avrcp_packet.h
@@ -0,0 +1,111 @@
+/*
+ * 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 <base/logging.h>
+#include <base/macros.h>
+#include <iostream>
+
+#include "avrcp_common.h"
+#include "avrcp_logging_helper.h"
+#include "iterator.h"
+#include "packet.h"
+#include "packet_builder.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class PacketBuilder : public ::bluetooth::PacketBuilder {
+ public:
+  virtual ~PacketBuilder() = default;
+
+  static std::unique_ptr<PacketBuilder> MakeBuilder(
+      CType cType, uint8_t subunit_type, uint8_t subunit_id, Opcode opcode,
+      std::unique_ptr<::bluetooth::PacketBuilder> packet);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  CType c_type_;
+  uint8_t subunit_type_ : 5;
+  uint8_t subunit_id_ : 3;
+  Opcode opcode_;
+  std::unique_ptr<::bluetooth::PacketBuilder> payload_;
+
+  void PushHeader(const std::shared_ptr<::bluetooth::Packet>& pkt);
+  bool PushCompanyId(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                     uint32_t company_id);
+
+  PacketBuilder(CType type, uint8_t subunit_type, uint8_t subunit_id,
+                Opcode opcode)
+      : c_type_(type),
+        subunit_type_(subunit_type),
+        subunit_id_(subunit_id),
+        opcode_(opcode){};
+};
+
+class Packet : public ::bluetooth::Packet {
+ public:
+  virtual ~Packet() = default;
+
+  // TODO (apanicke): Right now we can use this to build an AvrcpPacket from
+  // another packet type. In the future, we can remove this in favor of
+  // getting an AVRCP Packet directly from an AVCTP Packet
+  static std::shared_ptr<Packet> Parse(
+      std::shared_ptr<::bluetooth::Packet> pkt);
+
+  /**
+   * Avrcp Packet Layout
+   *   CType c_type_;
+   *   uint8_t subunit_type_ : 5;
+   *   uint8_t subunit_id_ : 3;
+   *   Opcode opcode_;
+   *   uint8_t[] payload_;
+   */
+  static constexpr size_t kMinSize() { return 3; };
+
+  // Getter Functions
+  CType GetCType() const;
+  uint8_t GetSubunitType() const;
+  uint8_t GetSubunitId() const;
+  Opcode GetOpcode() const;
+
+  // Overloaded Functions
+  virtual bool IsValid() const;
+  virtual std::string ToString() const override;
+
+ protected:
+  using ::bluetooth::Packet::Packet;
+
+  static inline uint32_t PullCompanyId(Iterator it) {
+    uint32_t value = 0;
+    for (int i = 0; i < 3; i++) {
+      value <<= 8;
+      value |= *it++;
+    }
+    return value;
+  }
+
+ private:
+  virtual std::pair<size_t, size_t> GetPayloadIndecies() const;
+  DISALLOW_COPY_AND_ASSIGN(Packet);
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/avrcp_reject_packet.cc b/packet/avrcp/avrcp_reject_packet.cc
new file mode 100644
index 0000000..d4ad7ad
--- /dev/null
+++ b/packet/avrcp/avrcp_reject_packet.cc
@@ -0,0 +1,47 @@
+/*
+ * 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 "avrcp_reject_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<RejectBuilder> RejectBuilder::MakeBuilder(CommandPdu pdu,
+                                                          Status reason) {
+  std::unique_ptr<RejectBuilder> builder =
+      std::unique_ptr<RejectBuilder>(new RejectBuilder(pdu, reason));
+
+  return builder;
+}
+
+size_t RejectBuilder::size() const { return VendorPacket::kMinSize() + 1; }
+
+bool RejectBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  // Push the standard avrcp headers
+  PacketBuilder::PushHeader(pkt);
+
+  // Push the avrcp vendor command headers
+  VendorPacketBuilder::PushHeader(pkt, 1);
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(reason_));
+
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/avrcp_reject_packet.h b/packet/avrcp/avrcp_reject_packet.h
new file mode 100644
index 0000000..9b7f3a9
--- /dev/null
+++ b/packet/avrcp/avrcp_reject_packet.h
@@ -0,0 +1,44 @@
+/*
+ * 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 "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class RejectBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~RejectBuilder() = default;
+
+  static std::unique_ptr<RejectBuilder> MakeBuilder(CommandPdu pdu,
+                                                    Status reason);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status reason_;
+
+  RejectBuilder(CommandPdu pdu, Status reason)
+      : VendorPacketBuilder(CType::REJECTED, pdu, PacketType::SINGLE),
+        reason_(reason){};
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/capabilities_packet.cc b/packet/avrcp/capabilities_packet.cc
new file mode 100644
index 0000000..459b47d
--- /dev/null
+++ b/packet/avrcp/capabilities_packet.cc
@@ -0,0 +1,152 @@
+/*
+ * 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 "capabilities_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetCapabilitiesRequestBuilder>
+GetCapabilitiesRequestBuilder::MakeBuilder(Capability capability) {
+  std::unique_ptr<GetCapabilitiesRequestBuilder> builder(
+      new GetCapabilitiesRequestBuilder(capability));
+
+  return builder;
+}
+
+size_t GetCapabilitiesRequestBuilder::size() const {
+  return GetCapabilitiesRequest::kMinSize();
+}
+
+bool GetCapabilitiesRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  // Push the standard avrcp headers
+  PacketBuilder::PushHeader(pkt);
+
+  // Push the avrcp vendor command headers, the parameter length is always 1
+  VendorPacketBuilder::PushHeader(pkt, 1);
+
+  // Push the capability
+  return AddPayloadOctets1(pkt, static_cast<uint8_t>(capability_));
+}
+
+Capability GetCapabilitiesRequest::GetCapabilityRequested() const {
+  auto value = *(begin() + VendorPacket::kMinSize());
+  return static_cast<Capability>(value);
+}
+
+bool GetCapabilitiesRequest::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  return (size() == VendorPacket::kMinSize() + 1);
+}
+
+std::string GetCapabilitiesRequest::ToString() const {
+  std::stringstream ss;
+  ss << "AvrcpCapabilityReqPacket: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Capabilities Request = " << GetCapabilityRequested() << std::endl;
+  return ss.str();
+}
+
+std::unique_ptr<GetCapabilitiesResponseBuilder>
+GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(
+    uint32_t company_id_element) {
+  std::unique_ptr<GetCapabilitiesResponseBuilder> builder(
+      new GetCapabilitiesResponseBuilder(Capability::COMPANY_ID));
+
+  company_id_element &= 0x00FFFFFF;
+  builder->elements_.insert(company_id_element);
+
+  return builder;
+}
+
+std::unique_ptr<GetCapabilitiesResponseBuilder>
+GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(Event event) {
+  std::unique_ptr<GetCapabilitiesResponseBuilder> builder(
+      new GetCapabilitiesResponseBuilder(Capability::EVENTS_SUPPORTED));
+
+  builder->elements_.insert(static_cast<uint8_t>(event));
+
+  return builder;
+}
+
+GetCapabilitiesResponseBuilder* GetCapabilitiesResponseBuilder::AddCompanyId(
+    uint32_t company_id) {
+  CHECK_EQ(capability_, Capability::COMPANY_ID);
+  CHECK_LT(elements_.size(), size_t(0xFF))
+      << __func__ << ": maximum capability count reached";
+
+  company_id &= 0x00FFFFFF;
+  elements_.insert(company_id);
+
+  return this;
+}
+
+GetCapabilitiesResponseBuilder* GetCapabilitiesResponseBuilder::AddEvent(
+    Event event) {
+  CHECK_EQ(capability_, Capability::EVENTS_SUPPORTED);
+  CHECK_LT(elements_.size(), size_t(0xFF))
+      << __func__ << ": maximum capability count reached";
+
+  elements_.insert(static_cast<uint8_t>(event));
+
+  return this;
+}
+
+size_t GetCapabilitiesResponseBuilder::size() const {
+  // Company ID's have a size of 3 while Events have a size of 1
+  size_t capability_count = elements_.size();
+  size_t capability_size = capability_ == Capability::COMPANY_ID ? 3 : 1;
+
+  return GetCapabilitiesResponse::kMinSize() +
+         (capability_count * capability_size);
+}
+
+bool GetCapabilitiesResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  // Push the standard avrcp headers
+  PacketBuilder::PushHeader(pkt);
+
+  // Push the avrcp vendor command headers
+  uint16_t parameter_count = size() - VendorPacket::kMinSize();
+  VendorPacketBuilder::PushHeader(pkt, parameter_count);
+
+  // Push the capability, capability count, and elements
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(capability_));
+  AddPayloadOctets1(pkt, elements_.size());
+  for (auto it = elements_.begin(); it != elements_.end(); it++) {
+    if (capability_ == Capability::COMPANY_ID)
+      PushCompanyId(pkt, *it);
+    else
+      AddPayloadOctets1(pkt, *it);
+  }
+
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/capabilities_packet.h b/packet/avrcp/capabilities_packet.h
new file mode 100644
index 0000000..3a4607f
--- /dev/null
+++ b/packet/avrcp/capabilities_packet.h
@@ -0,0 +1,139 @@
+/*
+ * 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 <set>
+
+#include "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetCapabilitiesRequestBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~GetCapabilitiesRequestBuilder() = default;
+
+  static std::unique_ptr<GetCapabilitiesRequestBuilder> MakeBuilder(
+      Capability capability);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Capability capability_;
+
+  GetCapabilitiesRequestBuilder(Capability capability)
+      : VendorPacketBuilder(CType::STATUS, CommandPdu::GET_CAPABILITIES,
+                            PacketType::SINGLE),
+        capability_(capability){};
+};
+
+class GetCapabilitiesRequest : public VendorPacket {
+ public:
+  virtual ~GetCapabilitiesRequest() = default;
+
+  /**
+   *  Get Capabilities Response Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   GetCapabilitiesRequestPacket:
+   *     uint8_t capability_requested:
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; };
+
+  // Getter Functions
+  Capability GetCapabilityRequested() const;
+
+  // Overloaded Functions
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+class GetCapabilitiesResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~GetCapabilitiesResponseBuilder() = default;
+
+  static std::unique_ptr<GetCapabilitiesResponseBuilder> MakeCompanyIdBuilder(
+      uint32_t company_id_element);
+
+  static std::unique_ptr<GetCapabilitiesResponseBuilder>
+  MakeEventsSupportedBuilder(Event event);
+
+  GetCapabilitiesResponseBuilder* AddCompanyId(uint32_t company_id);
+  GetCapabilitiesResponseBuilder* AddEvent(Event event);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  Capability capability_;
+  std::set<uint32_t> elements_;
+
+  GetCapabilitiesResponseBuilder(Capability capability)
+      : VendorPacketBuilder(CType::STABLE, CommandPdu::GET_CAPABILITIES,
+                            PacketType::SINGLE),
+        capability_(capability){};
+};
+
+class GetCapabilitiesResponse : public VendorPacket {
+ public:
+  /**
+   * Get Capabilities Response Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   GetCapabilitiesRequestPacket;
+   *     uint8_t capability_requested;
+   *     uint16_t capability_count;
+   *     union {
+   *        uint8_t event_supported;
+   *        uint8_t company_id[3];
+   *     } capability_array[];
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 2; };
+
+  // TODO: Implement these for AVRCP Controller
+  // virtual uint8_t GetCapabilityReturned() const;
+  // virtual uint8_t GetCapabilityCount() const;
+  // virtual std::vector<Event> GetEventsSupported() const;
+  // virtual std::vector<uint32_t> GetCompanyIds() const;
+
+  virtual std::string ToString() const override;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/change_path.cc b/packet/avrcp/change_path.cc
new file mode 100644
index 0000000..3c69903
--- /dev/null
+++ b/packet/avrcp/change_path.cc
@@ -0,0 +1,112 @@
+/*
+ * 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 "change_path.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<ChangePathResponseBuilder>
+ChangePathResponseBuilder::MakeBuilder(Status status,
+                                       uint32_t num_items_in_folder) {
+  std::unique_ptr<ChangePathResponseBuilder> builder(
+      new ChangePathResponseBuilder(status, num_items_in_folder));
+
+  return builder;
+}
+
+size_t ChangePathResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 4;  // Number of items in folder
+  return len;
+}
+
+bool ChangePathResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+  if (status_ != Status::NO_ERROR) return true;
+
+  AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+  return true;
+}
+
+uint16_t ChangePathRequest::GetUidCounter() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+Direction ChangePathRequest::GetDirection() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(2);
+  return static_cast<Direction>(*it);
+}
+
+uint64_t ChangePathRequest::GetUid() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(3);
+  return base::ByteSwap(it.extract<uint64_t>());
+}
+
+bool ChangePathRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  // Change path request packets are always the same size
+  return size() == kMinSize();
+}
+
+std::string ChangePathRequest::ToString() const {
+  std::stringstream ss;
+  ss << "ChangePathRequestPacket: " << std::endl;
+  ss << "  â”” PDU = " << GetPdu() << std::endl;
+  ss << "  â”” Length = " << GetLength() << std::endl;
+  ss << "  â”” UID Counter = " << loghex(GetUidCounter()) << std::endl;
+  ss << "  â”” Direction = " << GetDirection() << std::endl;
+  ss << "  â”” UID Requested = " << loghex(GetUid()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::unique_ptr<ChangePathRequestBuilder> ChangePathRequestBuilder::MakeBuilder(
+    uint16_t uid_counter, Direction direction, uint64_t folder_uid) {
+  std::unique_ptr<ChangePathRequestBuilder> builder(
+      new ChangePathRequestBuilder(uid_counter, direction, folder_uid));
+
+  return builder;
+}
+
+size_t ChangePathRequestBuilder::size() const {
+  return ChangePathRequest::kMinSize();
+}
+
+bool ChangePathRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(direction_));
+  AddPayloadOctets8(pkt, base::ByteSwap(folder_uid_));
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/change_path.h b/packet/avrcp/change_path.h
new file mode 100644
index 0000000..a033aa8
--- /dev/null
+++ b/packet/avrcp/change_path.h
@@ -0,0 +1,97 @@
+/*
+ * 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 "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class ChangePathResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~ChangePathResponseBuilder() = default;
+
+  static std::unique_ptr<ChangePathResponseBuilder> MakeBuilder(
+      Status status, uint32_t num_items_in_folder);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  Status status_;
+  uint32_t num_items_in_folder_;
+
+  ChangePathResponseBuilder(Status status, uint32_t num_items_in_folder)
+      : BrowsePacketBuilder(BrowsePdu::CHANGE_PATH),
+        status_(status),
+        num_items_in_folder_(num_items_in_folder) {}
+};
+
+class ChangePathRequest : public BrowsePacket {
+ public:
+  virtual ~ChangePathRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   ChangePathRequest:
+   *     uint16_t uid_counter_;
+   *     uint8_t direction_;
+   *     uint64_t folder_uid_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 11; }
+
+  uint16_t GetUidCounter() const;
+  Direction GetDirection() const;
+  uint64_t GetUid() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+class ChangePathRequestBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~ChangePathRequestBuilder() = default;
+
+  static std::unique_ptr<ChangePathRequestBuilder> MakeBuilder(
+      uint16_t uid_counter, Direction direction, uint64_t folder_uid);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  ChangePathRequestBuilder(uint16_t uid_counter, Direction direction,
+                           uint64_t folder_uid)
+      : BrowsePacketBuilder(BrowsePdu::CHANGE_PATH),
+        uid_counter_(uid_counter),
+        direction_(direction),
+        folder_uid_(folder_uid){};
+
+  uint16_t uid_counter_;
+  Direction direction_;
+  uint64_t folder_uid_;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/general_reject_packet.cc b/packet/avrcp/general_reject_packet.cc
new file mode 100644
index 0000000..cde0031
--- /dev/null
+++ b/packet/avrcp/general_reject_packet.cc
@@ -0,0 +1,47 @@
+/*
+ * 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 "general_reject_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GeneralRejectBuilder> GeneralRejectBuilder::MakeBuilder(
+    BrowsePdu pdu, Status reason) {
+  std::unique_ptr<GeneralRejectBuilder> builder =
+      std::unique_ptr<GeneralRejectBuilder>(
+          new GeneralRejectBuilder(pdu, reason));
+
+  return builder;
+}
+
+size_t GeneralRejectBuilder::size() const {
+  return BrowsePacket::kMinSize() + 1;
+}
+
+bool GeneralRejectBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(reason_));
+
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/avrcp/general_reject_packet.h b/packet/avrcp/general_reject_packet.h
new file mode 100644
index 0000000..4058fd4
--- /dev/null
+++ b/packet/avrcp/general_reject_packet.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GeneralRejectBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GeneralRejectBuilder() = default;
+
+  static std::unique_ptr<GeneralRejectBuilder> MakeBuilder(BrowsePdu pdu,
+                                                           Status reason);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status reason_;
+
+  GeneralRejectBuilder(BrowsePdu pdu, Status reason)
+      : BrowsePacketBuilder(pdu), reason_(reason){};
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/avrcp/get_element_attributes_packet.cc b/packet/avrcp/get_element_attributes_packet.cc
new file mode 100644
index 0000000..c26207e
--- /dev/null
+++ b/packet/avrcp/get_element_attributes_packet.cc
@@ -0,0 +1,143 @@
+/*
+ * 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 <algorithm>
+
+#include "get_element_attributes_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+uint64_t GetElementAttributesRequest::GetIdentifier() const {
+  auto it = begin() + VendorPacket::kMinSize();
+  return it.extract<uint64_t>();
+}
+
+uint8_t GetElementAttributesRequest::GetNumAttributes() const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
+  return it.extract<uint8_t>();
+}
+
+std::vector<Attribute> GetElementAttributesRequest::GetAttributesRequested()
+    const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
+
+  size_t number_of_attributes = it.extract<uint8_t>();
+
+  std::vector<Attribute> attribute_list;
+
+  for (size_t i = 0; i < number_of_attributes; i++) {
+    attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+  }
+
+  return attribute_list;
+}
+
+bool GetElementAttributesRequest::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  if (size() < kMinSize()) return false;
+
+  size_t num_attributes = GetNumAttributes();
+  auto attr_start = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
+
+  // Casting the int returned from end - attr_start should be fine. If an
+  // overflow occurs we can definitly say the packet is invalid
+  return (num_attributes * sizeof(Attribute)) == (size_t)(end() - attr_start);
+}
+
+std::string GetElementAttributesRequest::ToString() const {
+  std::stringstream ss;
+  ss << "RegisterNotificationPacket: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << GetParameterLength() << std::endl;
+  ss << "  â”” Identifier = " << loghex(GetIdentifier()) << std::endl;
+
+  auto attr_list = GetAttributesRequested();
+
+  ss << "  â”” Attribute List: Size: " << attr_list.size() << std::endl;
+  for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
+    ss << "      â”” " << loghex((uint32_t)(*it)) << std::endl;
+  }
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::unique_ptr<GetElementAttributesResponseBuilder>
+GetElementAttributesResponseBuilder::MakeBuilder(size_t mtu) {
+  std::unique_ptr<GetElementAttributesResponseBuilder> builder(
+      new GetElementAttributesResponseBuilder(mtu));
+
+  return builder;
+}
+
+bool GetElementAttributesResponseBuilder::AddAttributeEntry(
+    AttributeEntry entry) {
+  CHECK_LT(entries_.size(), size_t(0xFF))
+      << __func__ << ": attribute entry overflow";
+
+  size_t remaining_space = mtu_ - size();
+  if (entry.size() > remaining_space) {
+    entry.resize(remaining_space);
+  }
+
+  if (entry.empty()) {
+    return false;
+  }
+
+  entries_.insert(entry);
+  return true;
+}
+
+bool GetElementAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
+                                                            std::string value) {
+  return AddAttributeEntry(AttributeEntry(attribute, value));
+}
+
+size_t GetElementAttributesResponseBuilder::size() const {
+  size_t attr_list_size = 0;
+
+  for (auto& attribute_entry : entries_) {
+    attr_list_size += attribute_entry.size();
+  }
+
+  return VendorPacket::kMinSize() + 1 + attr_list_size;
+}
+
+bool GetElementAttributesResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, entries_.size());
+  for (auto attribute_entry : entries_) {
+    PushAttributeValue(pkt, attribute_entry);
+  }
+
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_element_attributes_packet.h b/packet/avrcp/get_element_attributes_packet.h
new file mode 100644
index 0000000..03fa8d1
--- /dev/null
+++ b/packet/avrcp/get_element_attributes_packet.h
@@ -0,0 +1,86 @@
+/*
+ * 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 <set>
+#include "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetElementAttributesRequest : public VendorPacket {
+ public:
+  virtual ~GetElementAttributesRequest() = default;
+
+  /**
+   *  Register Notificaiton Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   RegisterNotificationRequestPacket:
+   *     uint64_t identifier;
+   *     uint8_t number_of_attributes;
+   *     uint32_t attributes_requested[];
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 9; }
+
+  // Getter Functions
+  uint64_t GetIdentifier() const;
+  uint8_t GetNumAttributes() const;
+  std::vector<Attribute> GetAttributesRequested() const;
+
+  // Overloaded Functions
+  virtual bool IsValid() const;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+class GetElementAttributesResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~GetElementAttributesResponseBuilder() = default;
+
+  static std::unique_ptr<GetElementAttributesResponseBuilder> MakeBuilder(
+      size_t mtu);
+
+  bool AddAttributeEntry(AttributeEntry entry);
+  bool AddAttributeEntry(Attribute attribute, std::string value);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  std::set<AttributeEntry> entries_;
+  size_t mtu_;
+
+  GetElementAttributesResponseBuilder(size_t mtu)
+      : VendorPacketBuilder(CType::STABLE, CommandPdu::GET_ELEMENT_ATTRIBUTES,
+                            PacketType::SINGLE),
+        mtu_(mtu){};
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_folder_items.cc b/packet/avrcp/get_folder_items.cc
new file mode 100644
index 0000000..c95bb4a
--- /dev/null
+++ b/packet/avrcp/get_folder_items.cc
@@ -0,0 +1,345 @@
+/*
+ * 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 "get_folder_items.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status status,
+                                                     uint16_t uid_counter,
+                                                     size_t mtu) {
+  std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+      new GetFolderItemsResponseBuilder(Scope::MEDIA_PLAYER_LIST, status,
+                                        uid_counter, mtu));
+
+  return builder;
+}
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakeVFSBuilder(Status status,
+                                              uint16_t uid_counter,
+                                              size_t mtu) {
+  std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+      new GetFolderItemsResponseBuilder(Scope::VFS, status, uid_counter, mtu));
+
+  return builder;
+}
+
+std::unique_ptr<GetFolderItemsResponseBuilder>
+GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(Status status,
+                                                     uint16_t uid_counter,
+                                                     size_t mtu) {
+  std::unique_ptr<GetFolderItemsResponseBuilder> builder(
+      new GetFolderItemsResponseBuilder(Scope::NOW_PLAYING, status, uid_counter,
+                                        mtu));
+
+  return builder;
+}
+
+size_t GetFolderItemsResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+
+  // There is nothing other than the status in the packet if the status isn't
+  // NO_ERROR
+  if (status_ != Status::NO_ERROR || items_.size() == 0) return len;
+
+  len += 2;  // UID Counter
+  len += 2;  // Number of Items;
+  for (const auto& item : items_) {
+    len += item.size();
+  }
+
+  return len;
+}
+
+bool GetFolderItemsResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  if (status_ == Status::NO_ERROR && items_.size() == 0) {
+    // Return range out of bounds if there are zero items in the folder
+    status_ = Status::RANGE_OUT_OF_BOUNDS;
+  }
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);  // Status
+  if (status_ != Status::NO_ERROR) return true;
+
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  uint16_t num_items = items_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(num_items));
+
+  for (const auto& item : items_) {
+    PushMediaListItem(pkt, item);
+  }
+
+  return true;
+}
+
+bool GetFolderItemsResponseBuilder::AddMediaPlayer(MediaPlayerItem item) {
+  CHECK(scope_ == Scope::MEDIA_PLAYER_LIST);
+
+  if (size() + item.size() > mtu_) return false;
+
+  items_.push_back(MediaListItem(item));
+  return true;
+}
+
+bool GetFolderItemsResponseBuilder::AddSong(MediaElementItem item) {
+  CHECK(scope_ == Scope::VFS || scope_ == Scope::NOW_PLAYING);
+
+  if (size() + item.size() > mtu_) return false;
+
+  items_.push_back(MediaListItem(item));
+  return true;
+}
+
+bool GetFolderItemsResponseBuilder::AddFolder(FolderItem item) {
+  CHECK(scope_ == Scope::VFS);
+
+  if (size() + item.size() > mtu_) return false;
+
+  items_.push_back(MediaListItem(item));
+  return true;
+}
+
+void GetFolderItemsResponseBuilder::PushMediaListItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const MediaListItem& item) {
+  switch (item.type_) {
+    case MediaListItem::PLAYER:
+      PushMediaPlayerItem(pkt, item.player_);
+      break;
+    case MediaListItem::FOLDER:
+      PushFolderItem(pkt, item.folder_);
+      break;
+    case MediaListItem::SONG:
+      PushMediaElementItem(pkt, item.song_);
+      break;
+  }
+}
+
+void GetFolderItemsResponseBuilder::PushMediaPlayerItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const MediaPlayerItem& item) {
+  AddPayloadOctets1(pkt, 0x01);  // Media Player Item
+  uint16_t item_len = item.size() - 3;
+  AddPayloadOctets2(pkt, base::ByteSwap(item_len));  // Item length
+  AddPayloadOctets2(pkt, base::ByteSwap(item.id_));  // Player ID
+  AddPayloadOctets1(pkt, 0x01);                      // Player Type
+  AddPayloadOctets4(pkt, 0x00000000);                // Player Subtype
+  AddPayloadOctets1(
+      pkt, 0x02);  // Player Play Status // TODO: Add this as a passed field
+
+  // Features
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0xb7);
+  AddPayloadOctets1(pkt, 0x01);
+  if (item.browsable_) {
+    AddPayloadOctets1(pkt, 0x0C);
+    AddPayloadOctets1(pkt, 0x0a);
+  } else {
+    AddPayloadOctets1(pkt, 0x04);
+    AddPayloadOctets1(pkt, 0x00);
+  }
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+  AddPayloadOctets1(pkt, 0x00);
+
+  AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a));
+  uint16_t name_len = item.name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(name_len));
+
+  for (const uint8_t& byte : item.name_) {
+    AddPayloadOctets1(pkt, byte);
+  }
+}
+
+void GetFolderItemsResponseBuilder::PushFolderItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt, const FolderItem& item) {
+  AddPayloadOctets1(pkt, 0x02);  // Folder Item
+  uint16_t item_len = item.size() - 3;
+  AddPayloadOctets2(pkt, base::ByteSwap(item_len));
+  AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
+  AddPayloadOctets1(pkt, item.folder_type_);
+  AddPayloadOctets1(pkt, item.is_playable_ ? 0x01 : 0x00);
+  AddPayloadOctets2(pkt,
+                    base::ByteSwap((uint16_t)0x006a));  // UTF-8 Character Set
+  uint16_t name_len = item.name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(name_len));
+  for (const uint8_t& byte : item.name_) {
+    AddPayloadOctets1(pkt, byte);
+  }
+}
+
+void GetFolderItemsResponseBuilder::PushMediaElementItem(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const MediaElementItem& item) {
+  AddPayloadOctets1(pkt, 0x03);  // Media Element Item
+  uint16_t item_len = item.size() - 3;
+  AddPayloadOctets2(pkt, base::ByteSwap(item_len));
+  AddPayloadOctets8(pkt, base::ByteSwap(item.uid_));
+  AddPayloadOctets1(pkt, 0x00);  // Media Type Audio
+  AddPayloadOctets2(pkt,
+                    base::ByteSwap((uint16_t)0x006a));  // UTF-8 Character Set
+  uint16_t name_len = item.name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(name_len));
+  for (const uint8_t& byte : item.name_) {
+    AddPayloadOctets1(pkt, byte);
+  }
+
+  AddPayloadOctets1(pkt, (uint8_t)item.attributes_.size());
+  for (const auto& entry : item.attributes_) {
+    AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
+    AddPayloadOctets2(pkt,
+                      base::ByteSwap((uint16_t)0x006a));  // UTF-8 Character Set
+
+    std::string attr_val = entry.value();
+    uint16_t attr_len = attr_val.size();
+
+    AddPayloadOctets2(pkt, base::ByteSwap(attr_len));
+    for (const uint8_t& byte : attr_val) {
+      AddPayloadOctets1(pkt, byte);
+    }
+  }
+}
+
+Scope GetFolderItemsRequest::GetScope() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+uint32_t GetFolderItemsRequest::GetStartItem() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint32_t>());
+}
+
+uint32_t GetFolderItemsRequest::GetEndItem() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(5);
+  return base::ByteSwap(it.extract<uint32_t>());
+}
+
+uint8_t GetFolderItemsRequest::GetNumAttributes() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+  return *it;
+}
+
+std::vector<Attribute> GetFolderItemsRequest::GetAttributesRequested() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+
+  size_t number_of_attributes = it.extract<uint8_t>();
+  std::vector<Attribute> attribute_list;
+
+  // No attributes requested
+  if (number_of_attributes == 0xFF) return attribute_list;
+
+  // TODO: If the number of attributes equals 0, then all attributes are
+  // requested right now thats handled in the service itself, but it'd be nice
+  // to have this function return a vector with all the attributes
+
+  for (size_t i = 0; i < number_of_attributes; i++) {
+    attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+  }
+
+  return attribute_list;
+}
+
+bool GetFolderItemsRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  // The minimum size required to be valid
+  if (size() < kMinSize()) return false;
+
+  auto attr_count = GetNumAttributes();
+
+  // No items requested
+  if (attr_count == 0xFF) return true;
+
+  auto attr_start = begin() + kMinSize();
+
+  // Casting the int returned from end - attr_start should be fine. If an
+  // overflow occurs we can definitly say the packet is invalid
+  return (attr_count * sizeof(Attribute)) == (size_t)(end() - attr_start);
+}
+
+std::string GetFolderItemsRequest::ToString() const {
+  std::stringstream ss;
+  ss << "GetFolderItemsRequestPacket: " << std::endl;
+  ss << "  â”” PDU = " << GetPdu() << std::endl;
+  ss << "  â”” Length = " << GetLength() << std::endl;
+  ss << "  â”” Scope = " << GetScope() << std::endl;
+  ss << "  â”” Start Item = " << loghex(GetStartItem()) << std::endl;
+  ss << "  â”” End Item = " << loghex(GetEndItem()) << std::endl;
+  ss << "  â”” Attribute Count = " << loghex(GetNumAttributes()) << std::endl;
+
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::unique_ptr<GetFolderItemsRequestBuilder>
+GetFolderItemsRequestBuilder::MakeBuilder(
+    Scope scope, uint32_t start_item, uint32_t end_item,
+    const std::set<Attribute>& requested_attrs) {
+  std::unique_ptr<GetFolderItemsRequestBuilder> builder(
+      new GetFolderItemsRequestBuilder(scope, start_item, end_item,
+                                       requested_attrs));
+
+  return builder;
+}
+
+size_t GetFolderItemsRequestBuilder::size() const {
+  size_t len = GetFolderItemsRequest::kMinSize();
+  len += requested_attrs_.size() * sizeof(Attribute);
+  return len;
+}
+
+bool GetFolderItemsRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(scope_));
+  AddPayloadOctets4(pkt, base::ByteSwap(start_item_));
+  AddPayloadOctets4(pkt, base::ByteSwap(end_item_));
+
+  if (requested_attrs_.size() == 0) {
+    // 0xFF is the value to signify that there are no attributes requested.
+    AddPayloadOctets1(pkt, 0xFF);
+    return true;
+  }
+
+  AddPayloadOctets1(pkt, requested_attrs_.size());
+  for (const auto& attr : requested_attrs_) {
+    AddPayloadOctets4(pkt, base::ByteSwap(static_cast<uint32_t>(attr)));
+  }
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_folder_items.h b/packet/avrcp/get_folder_items.h
new file mode 100644
index 0000000..f5291af
--- /dev/null
+++ b/packet/avrcp/get_folder_items.h
@@ -0,0 +1,129 @@
+/*
+ * 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 "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetFolderItemsResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetFolderItemsResponseBuilder() = default;
+  static std::unique_ptr<GetFolderItemsResponseBuilder> MakePlayerListBuilder(
+      Status status, uint16_t uid_counter, size_t mtu);
+  static std::unique_ptr<GetFolderItemsResponseBuilder> MakeVFSBuilder(
+      Status status, uint16_t uid_counter, size_t mtu);
+  static std::unique_ptr<GetFolderItemsResponseBuilder> MakeNowPlayingBuilder(
+      Status status, uint16_t uid_counter, size_t mtu);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+  // Returns false if adding an item would exceed the MTU
+  bool AddMediaPlayer(MediaPlayerItem item);
+  bool AddSong(MediaElementItem item);
+  bool AddFolder(FolderItem item);
+
+ protected:
+  Scope scope_;
+  std::vector<MediaListItem> items_;
+  Status status_;
+  uint16_t uid_counter_;
+  size_t mtu_;
+
+  GetFolderItemsResponseBuilder(Scope scope, Status status,
+                                uint16_t uid_counter, size_t mtu)
+      : BrowsePacketBuilder(BrowsePdu::GET_FOLDER_ITEMS),
+        scope_(scope),
+        status_(status),
+        uid_counter_(uid_counter),
+        mtu_(mtu){};
+
+ private:
+  void PushMediaListItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                         const MediaListItem& item);
+  void PushMediaPlayerItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                           const MediaPlayerItem& item);
+  void PushMediaElementItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                            const MediaElementItem& item);
+  void PushFolderItem(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                      const FolderItem& item);
+};
+
+class GetFolderItemsRequest : public BrowsePacket {
+ public:
+  virtual ~GetFolderItemsRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetFolderItemsRequest:
+   *     uint8_t scope_;
+   *     uint32_t start_item_;
+   *     uint32_t end_item_;
+   *     uint8_t attr_count_;
+   *     uint32_t[] attr_requested_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 10; }
+
+  Scope GetScope() const;
+  uint32_t GetStartItem() const;
+  uint32_t GetEndItem() const;
+  uint8_t GetNumAttributes() const;
+  std::vector<Attribute> GetAttributesRequested() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+class GetFolderItemsRequestBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetFolderItemsRequestBuilder() = default;
+
+  static std::unique_ptr<GetFolderItemsRequestBuilder> MakeBuilder(
+      Scope scope, uint32_t start_item, uint32_t end_item,
+      const std::set<Attribute>& requested_attrs);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  GetFolderItemsRequestBuilder(Scope scope, uint32_t start_item,
+                               uint32_t end_item,
+                               const std::set<Attribute>& requested_attrs)
+      : BrowsePacketBuilder(BrowsePdu::GET_FOLDER_ITEMS),
+        scope_(scope),
+        start_item_(start_item),
+        end_item_(end_item),
+        requested_attrs_(requested_attrs){};
+
+  Scope scope_;
+  uint32_t start_item_;
+  uint32_t end_item_;
+  std::set<Attribute> requested_attrs_;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_item_attributes.cc b/packet/avrcp/get_item_attributes.cc
new file mode 100644
index 0000000..3430474
--- /dev/null
+++ b/packet/avrcp/get_item_attributes.cc
@@ -0,0 +1,150 @@
+/*
+ * 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 "get_item_attributes.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetItemAttributesResponseBuilder>
+GetItemAttributesResponseBuilder::MakeBuilder(Status status, size_t mtu) {
+  std::unique_ptr<GetItemAttributesResponseBuilder> builder(
+      new GetItemAttributesResponseBuilder(status, mtu));
+
+  return builder;
+}
+
+bool GetItemAttributesResponseBuilder::AddAttributeEntry(AttributeEntry entry) {
+  CHECK(entries_.size() < 0xFF);
+
+  size_t remaining_space = mtu_ - size();
+  if (entry.size() > remaining_space) {
+    entry.resize(remaining_space);
+  }
+
+  if (entry.empty()) {
+    return false;
+  }
+
+  entries_.insert(entry);
+  return true;
+}
+
+bool GetItemAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
+                                                         std::string value) {
+  return AddAttributeEntry(AttributeEntry(attribute, value));
+}
+
+size_t GetItemAttributesResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 1;  // Number of attributes
+  for (const auto& entry : entries_) {
+    len += entry.size();
+  }
+  return len;
+}
+
+bool GetItemAttributesResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+  if (status_ != Status::NO_ERROR) return true;
+
+  AddPayloadOctets1(pkt, entries_.size());
+  for (auto entry : entries_) {
+    AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
+    uint16_t character_set = 0x006a;  // UTF-8
+    AddPayloadOctets2(pkt, base::ByteSwap(character_set));
+    uint16_t value_length = entry.value().length();
+    AddPayloadOctets2(pkt, base::ByteSwap(value_length));
+    for (const uint8_t& byte : entry.value()) {
+      AddPayloadOctets1(pkt, byte);
+    }
+  }
+
+  return true;
+}
+
+Scope GetItemAttributesRequest::GetScope() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+uint64_t GetItemAttributesRequest::GetUid() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint64_t>());
+}
+
+uint16_t GetItemAttributesRequest::GetUidCounter() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+uint8_t GetItemAttributesRequest::GetNumAttributes() const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
+  return *it;
+}
+
+std::vector<Attribute> GetItemAttributesRequest::GetAttributesRequested()
+    const {
+  auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
+  size_t number_of_attributes = it.extract<uint8_t>();
+
+  std::vector<Attribute> attribute_list;
+  for (size_t i = 0; i < number_of_attributes; i++) {
+    attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+  }
+
+  return attribute_list;
+}
+
+bool GetItemAttributesRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  if (size() < kMinSize()) return false;
+
+  // Casting the int returned from end - attr_start should be fine. If an
+  // overflow occurs we can definitly say the packet is invalid
+  return (GetNumAttributes() * sizeof(Attribute)) == (size() - kMinSize());
+}
+
+std::string GetItemAttributesRequest::ToString() const {
+  std::stringstream ss;
+  ss << "GetItemAttributesRequestPacket: " << std::endl;
+  ss << "  â”” PDU = " << GetPdu() << std::endl;
+  ss << "  â”” Length = " << GetLength() << std::endl;
+  ss << "  â”” Scope = " << GetScope() << std::endl;
+  ss << "  â”” UID Requested = " << loghex(GetUid()) << std::endl;
+  ss << "  â”” UID Counter = " << loghex(GetUidCounter()) << std::endl;
+  ss << "  â”” Num Attributes = " << loghex(GetNumAttributes()) << std::endl;
+
+  auto attr_list = GetAttributesRequested();
+  ss << "  â”” Attribute List: Size: " << attr_list.size() << std::endl;
+  for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
+    ss << "      â”” " << loghex((uint32_t)(*it)) << std::endl;
+  }
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_item_attributes.h b/packet/avrcp/get_item_attributes.h
new file mode 100644
index 0000000..aa1db71
--- /dev/null
+++ b/packet/avrcp/get_item_attributes.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <set>
+
+#include "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetItemAttributesResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetItemAttributesResponseBuilder() = default;
+
+  static std::unique_ptr<GetItemAttributesResponseBuilder> MakeBuilder(
+      Status status, size_t mtu);
+
+  bool AddAttributeEntry(AttributeEntry entry);
+  bool AddAttributeEntry(Attribute, std::string);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  Status status_;
+  size_t mtu_;
+  std::set<AttributeEntry> entries_;
+
+  GetItemAttributesResponseBuilder(Status status, size_t mtu)
+      : BrowsePacketBuilder(BrowsePdu::GET_ITEM_ATTRIBUTES),
+        status_(status),
+        mtu_(mtu) {}
+};
+
+class GetItemAttributesRequest : public BrowsePacket {
+ public:
+  virtual ~GetItemAttributesRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetItemAttributesRequest:
+   *     uint8_t scope_;
+   *     uint64_t uid_;
+   *     uint16_t uid_counter_;
+   *     uint8_t attr_count_;
+   *     uint32_t[] attr_requested_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 12; }
+
+  Scope GetScope() const;
+  uint64_t GetUid() const;
+  uint16_t GetUidCounter() const;
+  uint8_t GetNumAttributes()
+      const;  // If this value is zero, then all attributes are requested
+  std::vector<Attribute> GetAttributesRequested() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_play_status_packet.cc b/packet/avrcp/get_play_status_packet.cc
new file mode 100644
index 0000000..8a40de9
--- /dev/null
+++ b/packet/avrcp/get_play_status_packet.cc
@@ -0,0 +1,60 @@
+/*
+ * 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 "get_play_status_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::string GetPlayStatusRequest::ToString() const {
+  return "GetPlayStatusRequest";
+}
+
+std::unique_ptr<GetPlayStatusResponseBuilder>
+GetPlayStatusResponseBuilder::MakeBuilder(uint32_t song_length,
+                                          uint32_t song_position,
+                                          uint8_t play_status) {
+  std::unique_ptr<GetPlayStatusResponseBuilder> builder(
+      new GetPlayStatusResponseBuilder(song_length, song_position,
+                                       play_status));
+
+  return builder;
+}
+
+size_t GetPlayStatusResponseBuilder::size() const {
+  return VendorPacket::kMinSize() + 4 + 4 + 1;
+}
+
+bool GetPlayStatusResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  // Push the standard avrcp headers
+  PacketBuilder::PushHeader(pkt);
+
+  // Push the avrcp vendor command headers
+  uint16_t parameter_count = size() - VendorPacket::kMinSize();
+  VendorPacketBuilder::PushHeader(pkt, parameter_count);
+
+  AddPayloadOctets4(pkt, base::ByteSwap(song_length_));
+  AddPayloadOctets4(pkt, base::ByteSwap(song_position_));
+  AddPayloadOctets1(pkt, play_status_);
+
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_play_status_packet.h b/packet/avrcp/get_play_status_packet.h
new file mode 100644
index 0000000..5714c26
--- /dev/null
+++ b/packet/avrcp/get_play_status_packet.h
@@ -0,0 +1,80 @@
+/*
+ * 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 "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+// TODO (apanicke): This packet doesn't really need to exist as it provides
+// zero extra information other than it is a strong type and provides a
+// validator
+class GetPlayStatusRequest : public VendorPacket {
+ public:
+  virtual ~GetPlayStatusRequest() = default;
+
+  /**
+   *  Get Capabilities Response Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length = 0;
+   */
+  static constexpr size_t kMinSize() { return Packet::kMinSize() + 7; }
+
+  // Overloaded Functions
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+class GetPlayStatusResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~GetPlayStatusResponseBuilder() = default;
+
+  static std::unique_ptr<GetPlayStatusResponseBuilder> MakeBuilder(
+      uint32_t song_length, uint32_t song_position, uint8_t play_status);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  uint32_t song_length_;
+  uint32_t song_position_;
+  uint8_t play_status_;
+
+  GetPlayStatusResponseBuilder(uint32_t song_length, uint32_t song_position,
+                               uint8_t play_status)
+      : VendorPacketBuilder(CType::STABLE, CommandPdu::GET_PLAY_STATUS,
+                            PacketType::SINGLE),
+        song_length_(song_length),
+        song_position_(song_position),
+        play_status_(play_status){};
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/get_total_number_of_items.cc b/packet/avrcp/get_total_number_of_items.cc
new file mode 100644
index 0000000..ab601ea
--- /dev/null
+++ b/packet/avrcp/get_total_number_of_items.cc
@@ -0,0 +1,79 @@
+/*
+ * 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 "get_total_number_of_items.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<GetTotalNumberOfItemsResponseBuilder>
+GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+    Status status, uint16_t uid_counter, uint32_t num_items_in_folder) {
+  std::unique_ptr<GetTotalNumberOfItemsResponseBuilder> builder(
+      new GetTotalNumberOfItemsResponseBuilder(status, uid_counter,
+                                               num_items_in_folder));
+
+  return builder;
+}
+
+size_t GetTotalNumberOfItemsResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 2;  // UID Counter
+  len += 4;  // Number of items in folder
+  return len;
+}
+
+bool GetTotalNumberOfItemsResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  if (status_ != Status::NO_ERROR) return true;
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+  return true;
+}
+
+Scope GetTotalNumberOfItemsRequest::GetScope() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+bool GetTotalNumberOfItemsRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string GetTotalNumberOfItemsRequest::ToString() const {
+  std::stringstream ss;
+  ss << "GetTotalNumberOfItemsRequest: " << std::endl;
+  ss << "  â”” PDU = " << GetPdu() << std::endl;
+  ss << "  â”” Length = " << GetLength() << std::endl;
+  ss << "  â”” Scope = " << GetScope() << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/avrcp/get_total_number_of_items.h b/packet/avrcp/get_total_number_of_items.h
new file mode 100644
index 0000000..51842c9
--- /dev/null
+++ b/packet/avrcp/get_total_number_of_items.h
@@ -0,0 +1,72 @@
+/*
+ * 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 "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class GetTotalNumberOfItemsResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetTotalNumberOfItemsResponseBuilder() = default;
+
+  static std::unique_ptr<GetTotalNumberOfItemsResponseBuilder> MakeBuilder(
+      Status status, uint16_t uid_counter, uint32_t num_items_in_folder);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+  uint16_t uid_counter_;
+  uint32_t num_items_in_folder_;
+
+  GetTotalNumberOfItemsResponseBuilder(Status status, uint16_t uid_counter,
+                                       uint32_t num_items_in_folder)
+      : BrowsePacketBuilder(BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS),
+        status_(status),
+        uid_counter_(uid_counter),
+        num_items_in_folder_(num_items_in_folder){};
+};
+
+class GetTotalNumberOfItemsRequest : public BrowsePacket {
+ public:
+  virtual ~GetTotalNumberOfItemsRequest() = default;
+
+  /**
+   * AVRCP Get Total Number Of Items Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetTotalNumberOfItemsRequest:
+   *     uint8_t scope_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 1; }
+
+  Scope GetScope() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/pass_through_packet.cc b/packet/avrcp/pass_through_packet.cc
new file mode 100644
index 0000000..67b8d16
--- /dev/null
+++ b/packet/avrcp/pass_through_packet.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 "pass_through_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<PassThroughPacketBuilder> PassThroughPacketBuilder::MakeBuilder(
+    bool response, bool pushed, uint8_t opperation_id) {
+  auto builder = std::unique_ptr<PassThroughPacketBuilder>(
+      new PassThroughPacketBuilder(response, pushed, opperation_id));
+
+  return builder;
+}
+
+size_t PassThroughPacketBuilder::size() const {
+  return PassThroughPacket::kMinSize();
+}
+
+bool PassThroughPacketBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  uint8_t byte = opperation_id_ & 0b01111111;
+  if (!pushed_) byte |= 0b10000000;
+  AddPayloadOctets1(pkt, byte);
+  // Data length, for this packet it's always 0;
+  AddPayloadOctets1(pkt, 0x00);
+
+  return true;
+}
+
+KeyState PassThroughPacket::GetKeyState() const {
+  auto it = begin() + Packet::kMinSize();
+  return static_cast<KeyState>(((*it) & 0b10000000) >> 7);
+}
+
+uint8_t PassThroughPacket::GetOperationId() const {
+  return *(begin() + Packet::kMinSize()) & 0b01111111;
+}
+
+bool PassThroughPacket::IsValid() const { return size() == kMinSize(); }
+
+std::string PassThroughPacket::ToString() const {
+  std::stringstream ss;
+  ss << "Avrcp::AvrcpPacket: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Pushed = " << GetKeyState() << std::endl;
+  ss << "  â”” Opperation ID = " << loghex(GetOperationId()) << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/pass_through_packet.h b/packet/avrcp/pass_through_packet.h
new file mode 100644
index 0000000..903b3d8
--- /dev/null
+++ b/packet/avrcp/pass_through_packet.h
@@ -0,0 +1,77 @@
+/*
+ * 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 "avrcp_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class PassThroughPacketBuilder : public PacketBuilder {
+ public:
+  virtual ~PassThroughPacketBuilder() = default;
+
+  static std::unique_ptr<PassThroughPacketBuilder> MakeBuilder(
+      bool response, bool pushed, uint8_t operation_id);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  bool pushed_;
+  uint8_t opperation_id_;
+
+  PassThroughPacketBuilder(bool response, bool pushed, uint8_t opperation_id)
+      : PacketBuilder(response ? CType::ACCEPTED : CType::CONTROL, 0x09, 0x00,
+                      Opcode::PASS_THROUGH),
+        pushed_(pushed),
+        opperation_id_(opperation_id){};
+};
+
+class PassThroughPacket : public Packet {
+ public:
+  virtual ~PassThroughPacket() = default;
+
+  /**
+   * Pass Through Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   PassThroughPacket:
+   *     uint8_t state : 1;
+   *     uint8_t opperation_id : 7;
+   *     uint8_t data_length;
+   */
+  static constexpr size_t kMinSize() { return Packet::kMinSize() + 2; }
+
+  // Getter Functions
+  KeyState GetKeyState() const;
+  uint8_t GetOperationId() const;
+
+  // Overloaded Functions
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using Packet::Packet;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/play_item.cc b/packet/avrcp/play_item.cc
new file mode 100644
index 0000000..27b242b
--- /dev/null
+++ b/packet/avrcp/play_item.cc
@@ -0,0 +1,89 @@
+/*
+ * 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 "play_item.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<PlayItemResponseBuilder> PlayItemResponseBuilder::MakeBuilder(
+    Status status) {
+  std::unique_ptr<PlayItemResponseBuilder> builder(
+      new PlayItemResponseBuilder(status));
+
+  return builder;
+}
+
+size_t PlayItemResponseBuilder::size() const {
+  size_t len = VendorPacket::kMinSize();
+  len += 1;  // Status
+  return len;
+}
+
+bool PlayItemResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  return true;
+}
+
+Scope PlayItemRequest::GetScope() const {
+  auto it = begin() + VendorPacket::kMinSize();
+  return static_cast<Scope>(*it);
+}
+
+uint64_t PlayItemRequest::GetUid() const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint64_t>());
+}
+
+uint16_t PlayItemRequest::GetUidCounter() const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool PlayItemRequest::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string PlayItemRequest::ToString() const {
+  std::stringstream ss;
+  ss << "PlayItemRequest: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Scope = " << GetScope() << std::endl;
+  ss << "  â”” UID = " << loghex(GetUid()) << std::endl;
+  ss << "  â”” UID Counter = " << loghex(GetUidCounter()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/play_item.h b/packet/avrcp/play_item.h
new file mode 100644
index 0000000..e1c2d48
--- /dev/null
+++ b/packet/avrcp/play_item.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 "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class PlayItemResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~PlayItemResponseBuilder() = default;
+
+  static std::unique_ptr<PlayItemResponseBuilder> MakeBuilder(Status status);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+
+  PlayItemResponseBuilder(Status status)
+      : VendorPacketBuilder(CType::ACCEPTED, CommandPdu::PLAY_ITEM,
+                            PacketType::SINGLE),
+        status_(status){};
+};
+
+class PlayItemRequest : public VendorPacket {
+ public:
+  virtual ~PlayItemRequest() = default;
+
+  /**
+   * AVRCP Play Item Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t parameter_length;
+   *   PlayItemRequest:
+   *     uint8_t scope_;
+   *     uint64_t uid_;
+   *     uint16_t uid_counter_;
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 11; }
+
+  Scope GetScope() const;
+  uint64_t GetUid() const;
+  uint16_t GetUidCounter() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/register_notification_packet.cc b/packet/avrcp/register_notification_packet.cc
new file mode 100644
index 0000000..86115e1
--- /dev/null
+++ b/packet/avrcp/register_notification_packet.cc
@@ -0,0 +1,291 @@
+/*
+ * 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 "register_notification_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+bool RegisterNotificationResponse::IsInterim() const {
+  return GetCType() == CType::INTERIM;
+}
+
+Event RegisterNotificationResponse::GetEvent() const {
+  auto value = *(begin() + VendorPacket::kMinSize());
+  return static_cast<Event>(value);
+}
+
+uint8_t RegisterNotificationResponse::GetVolume() const {
+  CHECK(GetEvent() == Event::VOLUME_CHANGED);
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
+  return *it;
+}
+
+bool RegisterNotificationResponse::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  if (size() < kMinSize()) return false;
+  if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED)
+    return false;
+
+  switch (GetEvent()) {
+    case Event::VOLUME_CHANGED:
+      return size() == (kMinSize() + 1);
+    default:
+      // TODO (apanicke): Add the remaining events when implementing AVRCP
+      // Controller
+      return false;
+  }
+}
+
+std::string RegisterNotificationResponse::ToString() const {
+  std::stringstream ss;
+  ss << "RegisterNotificationResponse: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Event Registered = " << GetEvent() << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+    bool interim, uint8_t play_status) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(interim,
+                                              Event::PLAYBACK_STATUS_CHANGED));
+
+  builder->data_ = play_status;
+  return builder;
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
+    bool interim, uint64_t track_uid) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(interim, Event::TRACK_CHANGED));
+
+  builder->data_ = track_uid;
+  return builder;
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
+    bool interim, uint32_t playback_pos) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(interim,
+                                              Event::PLAYBACK_POS_CHANGED));
+
+  builder->data_ = playback_pos;
+  return builder;
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(bool interim) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(
+          interim, Event::NOW_PLAYING_CONTENT_CHANGED));
+  return builder;
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(bool interim) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(
+          interim, Event::AVAILABLE_PLAYERS_CHANGED));
+  return builder;
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
+    bool interim, uint16_t player_id, uint16_t uid_counter) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(interim,
+                                              Event::ADDRESSED_PLAYER_CHANGED));
+  builder->data_ = ((uint32_t)player_id) << 16;
+  builder->data_ |= uid_counter;
+  return builder;
+}
+
+std::unique_ptr<RegisterNotificationResponseBuilder>
+RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(
+    bool interim, uint16_t uid_counter) {
+  std::unique_ptr<RegisterNotificationResponseBuilder> builder(
+      new RegisterNotificationResponseBuilder(interim, Event::UIDS_CHANGED));
+
+  builder->data_ = uid_counter;
+  return builder;
+}
+
+size_t RegisterNotificationResponseBuilder::size() const {
+  size_t data_size = 0;
+
+  // We specifically avoid having a default case here in order to ensure that
+  // there is an error in case an event isn't handled.
+  switch (event_) {
+    case Event::PLAYBACK_STATUS_CHANGED:
+      data_size = 1;
+      break;
+    case Event::TRACK_CHANGED:
+      data_size = 8;
+      break;
+    case Event::PLAYBACK_POS_CHANGED:
+      data_size = 4;
+      break;
+    case Event::PLAYER_APPLICATION_SETTING_CHANGED:
+      LOG(FATAL) << "Player Application Notification Not Implemented";
+      break;
+    case Event::NOW_PLAYING_CONTENT_CHANGED:
+      data_size = 0;
+      break;
+    case Event::AVAILABLE_PLAYERS_CHANGED:
+      data_size = 0;
+      break;
+    case Event::ADDRESSED_PLAYER_CHANGED:
+      data_size = 4;
+      break;
+    case Event::UIDS_CHANGED:
+      data_size = 2;
+      break;
+    case Event::VOLUME_CHANGED:
+      LOG(FATAL) << "Volume Changed Notification Not Implemented";
+      break;
+  }
+
+  return VendorPacket::kMinSize() + 1 + data_size;
+}
+
+bool RegisterNotificationResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
+  switch (event_) {
+    case Event::PLAYBACK_STATUS_CHANGED: {
+      uint8_t playback_status = data_ & 0xFF;
+      AddPayloadOctets1(pkt, playback_status);
+      break;
+    }
+    case Event::TRACK_CHANGED: {
+      AddPayloadOctets8(pkt, base::ByteSwap(data_));
+      break;
+    }
+    case Event::PLAYBACK_POS_CHANGED: {
+      uint32_t playback_pos = data_ & 0xFFFFFFFF;
+      AddPayloadOctets4(pkt, base::ByteSwap(playback_pos));
+      break;
+    }
+    case Event::PLAYER_APPLICATION_SETTING_CHANGED:
+      break;  // No additional data
+    case Event::NOW_PLAYING_CONTENT_CHANGED:
+      break;  // No additional data
+    case Event::AVAILABLE_PLAYERS_CHANGED:
+      break;  // No additional data
+    case Event::ADDRESSED_PLAYER_CHANGED: {
+      uint16_t uid_counter = data_ & 0xFFFF;
+      uint16_t player_id = (data_ >> 16) & 0xFFFF;
+      AddPayloadOctets2(pkt, base::ByteSwap(player_id));
+      AddPayloadOctets2(pkt, base::ByteSwap(uid_counter));
+      break;
+    }
+    case Event::UIDS_CHANGED: {
+      uint16_t uid_counter = data_ & 0xFFFF;
+      AddPayloadOctets2(pkt, base::ByteSwap(uid_counter));
+      break;
+    }
+    case Event::VOLUME_CHANGED:
+      // TODO (apanicke): Add Volume Changed builder for when we are controller.
+      LOG(FATAL) << "Volume Changed Notification Not Implemented";
+      break;
+  }
+
+  return true;
+}
+
+Event RegisterNotificationRequest::GetEventRegistered() const {
+  auto value = *(begin() + VendorPacket::kMinSize());
+  return static_cast<Event>(value);
+}
+
+uint32_t RegisterNotificationRequest::GetInterval() const {
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
+  return base::ByteSwap(it.extract<uint32_t>());
+}
+
+bool RegisterNotificationRequest::IsValid() const {
+  return (size() == kMinSize());
+}
+
+std::string RegisterNotificationRequest::ToString() const {
+  std::stringstream ss;
+  ss << "RegisterNotificationPacket: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Event Registered = " << GetEventRegistered() << std::endl;
+  ss << "  â”” Interval = " << loghex(GetInterval()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+std::unique_ptr<RegisterNotificationRequestBuilder>
+RegisterNotificationRequestBuilder::MakeBuilder(Event event,
+                                                uint32_t interval) {
+  std::unique_ptr<RegisterNotificationRequestBuilder> builder(
+      new RegisterNotificationRequestBuilder(event, interval));
+
+  return builder;
+}
+
+size_t RegisterNotificationRequestBuilder::size() const {
+  return RegisterNotificationRequest::kMinSize();
+}
+
+bool RegisterNotificationRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
+
+  AddPayloadOctets4(pkt, base::ByteSwap(interval_));
+
+  return true;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/register_notification_packet.h b/packet/avrcp/register_notification_packet.h
new file mode 100644
index 0000000..53286c4
--- /dev/null
+++ b/packet/avrcp/register_notification_packet.h
@@ -0,0 +1,156 @@
+/*
+ * 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 "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class RegisterNotificationResponse : public VendorPacket {
+ public:
+  virtual ~RegisterNotificationResponse() = default;
+
+  /**
+   *  Register Notificaiton Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   RegisterNotificationRequestPacket:
+   *     uint8_t event_id;
+   *     uint8_t[] data;  // Length changes based on the event_id
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; }
+
+  // TODO (apanicke): Add other getters when implementing AVRCP Controller
+  bool IsInterim() const;
+  Event GetEvent() const;
+  uint8_t GetVolume() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+class RegisterNotificationResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~RegisterNotificationResponseBuilder() = default;
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakePlaybackStatusBuilder(bool interim, uint8_t play_status);
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakeTrackChangedBuilder(bool interim, uint64_t track_uid);
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakePlaybackPositionBuilder(bool interim, uint32_t playback_pos);
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakeNowPlayingBuilder(bool interim);
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakeAvailablePlayersBuilder(bool interim);
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakeAddressedPlayerBuilder(bool interim, uint16_t player_id,
+                             uint16_t uid_counter);
+
+  static std::unique_ptr<RegisterNotificationResponseBuilder>
+  MakeUidsChangedBuilder(bool interim, uint16_t uid_counter);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Event event_;
+  uint64_t data_;
+
+  RegisterNotificationResponseBuilder(bool interim, Event event)
+      : VendorPacketBuilder(interim ? CType::INTERIM : CType::CHANGED,
+                            CommandPdu::REGISTER_NOTIFICATION,
+                            PacketType::SINGLE),
+        event_(event){};
+};
+
+class RegisterNotificationRequest : public VendorPacket {
+ public:
+  virtual ~RegisterNotificationRequest() = default;
+
+  /**
+   *  Register Notificaiton Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   RegisterNotificationRequestPacket:
+   *     uint8_t event_id;
+   *     uint32_t interval;  // Only used for PLAYBACK_POS_CHANGED
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 5; }
+
+  // Getter Functions
+  Event GetEventRegistered() const;
+  uint32_t GetInterval() const;
+
+  // Overloaded Functions
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+class RegisterNotificationRequestBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~RegisterNotificationRequestBuilder() = default;
+
+  static std::unique_ptr<RegisterNotificationRequestBuilder> MakeBuilder(
+      Event event, uint32_t interval);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Event event_;
+  uint32_t interval_;
+
+  RegisterNotificationRequestBuilder(Event event, uint32_t interval)
+      : VendorPacketBuilder(CType::NOTIFY, CommandPdu::REGISTER_NOTIFICATION,
+                            PacketType::SINGLE),
+        event_(event),
+        interval_(interval){};
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_absolute_volume.cc b/packet/avrcp/set_absolute_volume.cc
new file mode 100644
index 0000000..ff6b7ac
--- /dev/null
+++ b/packet/avrcp/set_absolute_volume.cc
@@ -0,0 +1,76 @@
+/*
+ * 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 "set_absolute_volume.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<SetAbsoluteVolumeRequestBuilder>
+SetAbsoluteVolumeRequestBuilder::MakeBuilder(uint8_t volume) {
+  std::unique_ptr<SetAbsoluteVolumeRequestBuilder> builder(
+      new SetAbsoluteVolumeRequestBuilder(volume & 0x7F));
+
+  return builder;
+}
+
+size_t SetAbsoluteVolumeRequestBuilder::size() const {
+  return VendorPacket::kMinSize() + 1;
+}
+
+bool SetAbsoluteVolumeRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, volume_);
+
+  return true;
+}
+
+uint8_t SetAbsoluteVolumeResponse::GetVolume() const {
+  auto it = begin() + VendorPacket::kMinSize();
+  return *it;
+}
+
+bool SetAbsoluteVolumeResponse::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  if (GetCType() != CType::ACCEPTED) return false;
+  return size() == kMinSize();
+}
+
+std::string SetAbsoluteVolumeResponse::ToString() const {
+  std::stringstream ss;
+  ss << "SetAbsoluteVolumeResponse: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Volume = " << GetVolume() << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_absolute_volume.h b/packet/avrcp/set_absolute_volume.h
new file mode 100644
index 0000000..48cd388
--- /dev/null
+++ b/packet/avrcp/set_absolute_volume.h
@@ -0,0 +1,81 @@
+/*
+ * 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 "vendor_packet.h"
+
+// TODO (apanicke): Set Absolute Volume request vs response have the same
+// packet structure, the only difference between the two is the CType.
+// Adding a passed flag as a parameter would be possible but I feel that
+// this would break the design pattern of request vs response. Look into
+// this for the future.
+
+namespace bluetooth {
+namespace avrcp {
+
+class SetAbsoluteVolumeRequestBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~SetAbsoluteVolumeRequestBuilder() = default;
+
+  static std::unique_ptr<SetAbsoluteVolumeRequestBuilder> MakeBuilder(
+      uint8_t volume);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  uint8_t volume_;
+
+  SetAbsoluteVolumeRequestBuilder(uint8_t volume)
+      : VendorPacketBuilder(CType::CONTROL, CommandPdu::SET_ABSOLUTE_VOLUME,
+                            PacketType::SINGLE),
+        volume_(volume){};
+};
+
+class SetAbsoluteVolumeResponse : public VendorPacket {
+ public:
+  virtual ~SetAbsoluteVolumeResponse() = default;
+
+  /**
+   * AVRCP Play Item Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t parameter_length;
+   *   SetAbsoluteVolumeResponse:
+   *     uint8_t volume;
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; }
+
+  uint8_t GetVolume() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_addressed_player.cc b/packet/avrcp/set_addressed_player.cc
new file mode 100644
index 0000000..f4b4ddd
--- /dev/null
+++ b/packet/avrcp/set_addressed_player.cc
@@ -0,0 +1,77 @@
+/*
+ * 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 "set_addressed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<SetAddressedPlayerResponseBuilder>
+SetAddressedPlayerResponseBuilder::MakeBuilder(Status status) {
+  std::unique_ptr<SetAddressedPlayerResponseBuilder> builder(
+      new SetAddressedPlayerResponseBuilder(status));
+
+  return builder;
+}
+
+size_t SetAddressedPlayerResponseBuilder::size() const {
+  size_t len = VendorPacket::kMinSize();
+  len += 1;  // Status
+  return len;
+}
+
+bool SetAddressedPlayerResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  return true;
+}
+
+uint16_t SetAddressedPlayerRequest::GetPlayerId() const {
+  auto it = begin() + VendorPacket::kMinSize();
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool SetAddressedPlayerRequest::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string SetAddressedPlayerRequest::ToString() const {
+  std::stringstream ss;
+  ss << "SetAddressedPlayerRequest: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Player ID = " << loghex(GetPlayerId()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_addressed_player.h b/packet/avrcp/set_addressed_player.h
new file mode 100644
index 0000000..8234116
--- /dev/null
+++ b/packet/avrcp/set_addressed_player.h
@@ -0,0 +1,75 @@
+/*
+ * 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 "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class SetAddressedPlayerResponseBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~SetAddressedPlayerResponseBuilder() = default;
+
+  static std::unique_ptr<SetAddressedPlayerResponseBuilder> MakeBuilder(
+      Status status);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+
+  SetAddressedPlayerResponseBuilder(Status status)
+      : VendorPacketBuilder(CType::ACCEPTED, CommandPdu::SET_ADDRESSED_PLAYER,
+                            PacketType::SINGLE),
+        status_(status){};
+};
+
+class SetAddressedPlayerRequest : public VendorPacket {
+ public:
+  virtual ~SetAddressedPlayerRequest() = default;
+
+  /**
+   *  Register Notificaiton Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   SetAddressedPlayerRequest:
+   *     uint16_t player_id;
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 2; }
+
+  uint16_t GetPlayerId() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_browsed_player.cc b/packet/avrcp/set_browsed_player.cc
new file mode 100644
index 0000000..b8463fa
--- /dev/null
+++ b/packet/avrcp/set_browsed_player.cc
@@ -0,0 +1,103 @@
+/*
+ * 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 "set_browsed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<SetBrowsedPlayerResponseBuilder>
+SetBrowsedPlayerResponseBuilder::MakeBuilder(Status status,
+                                             uint16_t uid_counter,
+                                             uint32_t num_items_in_folder,
+                                             uint8_t folder_depth,
+                                             std::string folder_name) {
+  std::unique_ptr<SetBrowsedPlayerResponseBuilder> builder(
+      new SetBrowsedPlayerResponseBuilder(
+          status, uid_counter, num_items_in_folder, folder_depth, folder_name));
+
+  return builder;
+}
+
+size_t SetBrowsedPlayerResponseBuilder::size() const {
+  size_t len = BrowsePacket::kMinSize();
+  len += 1;  // Status
+
+  // If the status isn't success the rest of the fields are ommited
+  if (status_ != Status::NO_ERROR) return len;
+
+  len += 2;  // UID Counter
+  len += 4;  // Number of items in folder
+  len += 2;  // UTF-8 Character Set
+  len += 1;  // Folder Depth
+
+  // This is only included if the folder returned isn't the root folder
+  if (folder_depth_ != 0) {
+    len += 2;                    // Folder Name Size;
+    len += folder_name_.size();  // Folder Name
+  }
+
+  return len;
+}
+
+bool SetBrowsedPlayerResponseBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, (uint8_t)status_);
+
+  if (status_ != Status::NO_ERROR) return true;
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  AddPayloadOctets4(pkt, base::ByteSwap(num_items_in_folder_));
+  AddPayloadOctets2(pkt, base::ByteSwap((uint16_t)0x006a));  // UTF-8
+  AddPayloadOctets1(pkt, folder_depth_);
+
+  // Skip adding the folder name if the folder depth is 0
+  if (folder_depth_ == 0) return true;
+  uint16_t folder_name_len = folder_name_.size();
+  AddPayloadOctets2(pkt, base::ByteSwap(folder_name_len));
+  for (auto it = folder_name_.begin(); it != folder_name_.end(); it++) {
+    AddPayloadOctets1(pkt, *it);
+  }
+
+  return true;
+}
+
+uint16_t SetBrowsedPlayerRequest::GetPlayerId() const {
+  auto it = begin() + BrowsePacket::kMinSize();
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool SetBrowsedPlayerRequest::IsValid() const {
+  if (!BrowsePacket::IsValid()) return false;
+  return size() == kMinSize();
+}
+
+std::string SetBrowsedPlayerRequest::ToString() const {
+  std::stringstream ss;
+  ss << "SetBrowsedPlayerRequestPacket: " << std::endl;
+  ss << "  â”” PDU = " << GetPdu() << std::endl;
+  ss << "  â”” Length = " << GetLength() << std::endl;
+  ss << "  â”” Player ID = " << loghex(GetPlayerId()) << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_browsed_player.h b/packet/avrcp/set_browsed_player.h
new file mode 100644
index 0000000..336c4e1
--- /dev/null
+++ b/packet/avrcp/set_browsed_player.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 "avrcp_browse_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class SetBrowsedPlayerResponseBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~SetBrowsedPlayerResponseBuilder() = default;
+
+  static std::unique_ptr<SetBrowsedPlayerResponseBuilder> MakeBuilder(
+      Status status, uint16_t uid_counter, uint32_t num_items_in_folder,
+      uint8_t folder_depth, std::string folder_name);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Status status_;
+  uint16_t uid_counter_;
+  uint32_t num_items_in_folder_;
+  uint8_t folder_depth_;
+  std::string folder_name_;
+
+  SetBrowsedPlayerResponseBuilder(Status status, uint16_t uid_counter,
+                                  uint32_t num_items_in_folder,
+                                  uint8_t folder_depth, std::string folder_name)
+      : BrowsePacketBuilder(BrowsePdu::SET_BROWSED_PLAYER),
+        status_(status),
+        uid_counter_(uid_counter),
+        num_items_in_folder_(num_items_in_folder),
+        folder_depth_(folder_depth),
+        folder_name_(folder_name) {}
+};
+
+class SetBrowsedPlayerRequest : public BrowsePacket {
+ public:
+  virtual ~SetBrowsedPlayerRequest() = default;
+
+  /**
+   * Avrcp Change Path Packet Layout
+   *   BrowsePacket:
+   *     uint8_t pdu_;
+   *     uint16_t length_;
+   *   GetFolderItemsRequest:
+   *     uint16_t player_id_;
+   */
+  static constexpr size_t kMinSize() { return BrowsePacket::kMinSize() + 2; }
+
+  uint16_t GetPlayerId() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using BrowsePacket::BrowsePacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/vendor_packet.cc b/packet/avrcp/vendor_packet.cc
new file mode 100644
index 0000000..982cf81
--- /dev/null
+++ b/packet/avrcp/vendor_packet.cc
@@ -0,0 +1,131 @@
+/*
+ * 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 "vendor_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<VendorPacketBuilder> VendorPacketBuilder::MakeBuilder(
+    CType ctype, CommandPdu pdu, PacketType packet_type,
+    std::unique_ptr<::bluetooth::PacketBuilder> payload) {
+  // If the payload size is greater than max uint16_t
+  // the packet should be fragmented
+  CHECK_LE(payload->size(), size_t(0xFFFF))
+      << __func__ << ": payload size bigger than uint16_t";
+
+  std::unique_ptr<VendorPacketBuilder> builder(
+      new VendorPacketBuilder(ctype, pdu, packet_type));
+  builder->payload_ = std::move(payload);
+
+  return builder;
+}
+
+size_t VendorPacketBuilder::size() const {
+  return VendorPacket::kMinSize() + payload_->size();
+}
+
+bool VendorPacketBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  // Push the standard avrcp headers
+  PacketBuilder::PushHeader(pkt);
+
+  // Push the avrcp vendor command headers
+  CHECK_LT(payload_->size(), size_t(0xFFFF))
+      << __func__ << ": payload size bigger than uint16_t";
+  PushHeader(pkt, payload_->size());
+
+  // Push the payload for the packet
+  return payload_->Serialize(pkt);
+}
+
+void VendorPacketBuilder::PushHeader(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    uint16_t parameter_length) {
+  PushCompanyId(pkt, BLUETOOTH_COMPANY_ID);
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(pdu_));
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(packet_type_));
+  AddPayloadOctets2(pkt, base::ByteSwap(parameter_length));
+}
+
+bool VendorPacketBuilder::PushAttributeValue(
+    const std::shared_ptr<::bluetooth::Packet>& pkt,
+    const AttributeEntry& entry) {
+  AddPayloadOctets4(pkt,
+                    base::ByteSwap(static_cast<uint32_t>(entry.attribute())));
+  uint16_t character_set = 0x006a;  // UTF-8
+  AddPayloadOctets2(pkt, base::ByteSwap(character_set));
+  uint16_t value_length = entry.value().length();
+  AddPayloadOctets2(pkt, base::ByteSwap(value_length));
+  for (int i = 0; i < value_length; i++) {
+    AddPayloadOctets1(pkt, entry.value()[i]);
+  }
+
+  return true;
+}
+
+uint32_t VendorPacket::GetCompanyId() const {
+  return PullCompanyId(begin() + Packet::kMinSize());
+}
+
+CommandPdu VendorPacket::GetCommandPdu() const {
+  auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(3));
+  return static_cast<CommandPdu>(value);
+}
+
+PacketType VendorPacket::GetPacketType() const {
+  auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(4));
+  return static_cast<PacketType>(value);
+}
+
+uint16_t VendorPacket::GetParameterLength() const {
+  auto it = begin() + Packet::kMinSize() + static_cast<size_t>(5);
+  // Swap to little endian
+  return base::ByteSwap(it.extract<uint16_t>());
+}
+
+bool VendorPacket::IsValid() const {
+  if (size() < VendorPacket::kMinSize()) return false;
+
+  auto start = begin() + VendorPacket::kMinSize();
+  // Even if end is less than start and a sign extension occurs, thats fine as
+  // its pretty definitive proof that the packet is poorly formated
+  return GetParameterLength() == (end() - start);
+}
+
+std::string VendorPacket::ToString() const {
+  std::stringstream ss;
+  ss << "VendorPacket: " << std::endl;
+  ss << "  â”” cType = " << GetCType() << std::endl;
+  ss << "  â”” Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  â”” Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  â”” OpCode = " << GetOpcode() << std::endl;
+  ss << "  â”” Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  â”” Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  â”” PacketType = " << GetPacketType() << std::endl;
+  ss << "  â”” Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  â”” Payload =";
+  for (auto it = begin(); it != end(); it++) {
+    ss << " " << loghex(*it);
+  }
+  ss << std::endl;
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/vendor_packet.h b/packet/avrcp/vendor_packet.h
new file mode 100644
index 0000000..b9e1f10
--- /dev/null
+++ b/packet/avrcp/vendor_packet.h
@@ -0,0 +1,89 @@
+/*
+ * 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 "avrcp_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+class VendorPacketBuilder : public avrcp::PacketBuilder {
+ public:
+  virtual ~VendorPacketBuilder() = default;
+
+  static std::unique_ptr<VendorPacketBuilder> MakeBuilder(
+      CType ctype, CommandPdu pdu, PacketType packet_type,
+      std::unique_ptr<::bluetooth::PacketBuilder> payload);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  CommandPdu pdu_;
+  PacketType packet_type_;
+  uint16_t param_length_;
+
+  void PushHeader(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                  uint16_t parameter_length);
+
+  // Helper function used a couple other AVRCP packet builders
+  bool PushAttributeValue(const std::shared_ptr<::bluetooth::Packet>& pkt,
+                          const AttributeEntry& entry);
+
+  VendorPacketBuilder(CType ctype, CommandPdu pdu, PacketType packet_type)
+      : PacketBuilder(ctype, 0x09, 0x00, Opcode::VENDOR),
+        pdu_(pdu),
+        packet_type_(packet_type){};
+};
+
+class VendorPacket : public avrcp::Packet {
+ public:
+  virtual ~VendorPacket() = default;
+
+  /**
+   * Avrcp Vendor Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t parameter_length;
+   *   uint8_t[] payload;
+   */
+  static constexpr size_t kMinSize() { return Packet::kMinSize() + 7; };
+
+  // Getter Functions
+  uint32_t GetCompanyId() const;
+  CommandPdu GetCommandPdu() const;
+  PacketType GetPacketType() const;
+  uint16_t GetParameterLength() const;
+
+  // Overloaded functions
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using Packet::Packet;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/base/Android.bp b/packet/base/Android.bp
new file mode 100644
index 0000000..67f77d6
--- /dev/null
+++ b/packet/base/Android.bp
@@ -0,0 +1,11 @@
+cc_library_static {
+    name: "lib-bt-packets-base",
+    defaults: ["libchrome_support_defaults"],
+    export_include_dirs: ["./"],
+    host_supported: true,
+    srcs: [
+        "packet.cc",
+        "iterator.cc",
+        "packet_builder.cc",
+    ],
+}
diff --git a/packet/base/iterator.cc b/packet/base/iterator.cc
new file mode 100644
index 0000000..b2c1c23
--- /dev/null
+++ b/packet/base/iterator.cc
@@ -0,0 +1,129 @@
+/*
+ * 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 "iterator.h"
+
+#include <base/logging.h>
+
+#include "packet.h"
+
+namespace bluetooth {
+
+Iterator::Iterator(std::shared_ptr<const Packet> packet, size_t i) {
+  packet_ = packet;
+  index_ = i;
+
+  CHECK_GE(index_, packet->packet_start_index_);
+  CHECK_LE(index_, packet->packet_end_index_);
+}
+
+Iterator::Iterator(const Iterator& itr) { *this = itr; }
+
+Iterator Iterator::operator+(size_t offset) {
+  auto itr(*this);
+
+  return itr += offset;
+}
+
+Iterator& Iterator::operator+=(size_t offset) {
+  size_t new_offset = index_ + offset;
+  index_ = new_offset > packet_->packet_end_index_ ? packet_->packet_end_index_
+                                                   : new_offset;
+  return *this;
+}
+
+Iterator Iterator::operator++(int) {
+  auto itr(*this);
+  index_++;
+
+  if (index_ > packet_->packet_end_index_) index_ = packet_->packet_end_index_;
+
+  return itr;
+}
+
+Iterator& Iterator::operator++() {
+  index_++;
+
+  if (index_ > packet_->packet_end_index_) index_ = packet_->packet_end_index_;
+
+  return *this;
+}
+
+Iterator Iterator::operator-(size_t offset) {
+  auto itr(*this);
+
+  return itr -= offset;
+}
+
+int Iterator::operator-(const Iterator& itr) { return index_ - itr.index_; }
+
+Iterator& Iterator::operator-=(size_t offset) {
+  index_ = (index_ < offset || index_ - offset < packet_->packet_start_index_)
+               ? packet_->packet_start_index_
+               : index_ - offset;
+
+  return *this;
+}
+
+Iterator Iterator::operator--(int) {
+  auto itr(*this);
+  if (index_ != packet_->packet_start_index_) index_--;
+
+  return itr;
+}
+
+Iterator& Iterator::operator--() {
+  if (index_ != packet_->packet_start_index_) index_--;
+
+  return *this;
+}
+
+Iterator& Iterator::operator=(const Iterator& itr) {
+  packet_ = itr.packet_;
+  index_ = itr.index_;
+
+  return *this;
+}
+
+bool Iterator::operator==(const Iterator& itr) const {
+  return ((packet_ == itr.packet_) && (index_ == itr.index_));
+}
+
+bool Iterator::operator!=(const Iterator& itr) const { return !(*this == itr); }
+
+bool Iterator::operator<(const Iterator& itr) const {
+  return ((packet_ == itr.packet_) && (index_ < itr.index_));
+}
+
+bool Iterator::operator>(const Iterator& itr) const {
+  return ((packet_ == itr.packet_) && (index_ > itr.index_));
+}
+
+bool Iterator::operator<=(const Iterator& itr) const {
+  return ((packet_ == itr.packet_) && (index_ <= itr.index_));
+}
+
+bool Iterator::operator>=(const Iterator& itr) const {
+  return ((packet_ == itr.packet_) && (index_ >= itr.index_));
+}
+
+uint8_t Iterator::operator*() const {
+  CHECK_NE(index_, packet_->packet_end_index_);
+
+  return packet_->get_at_index(index_);
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/base/iterator.h b/packet/base/iterator.h
new file mode 100644
index 0000000..c4ad32c
--- /dev/null
+++ b/packet/base/iterator.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <iterator>
+#include <memory>
+
+namespace bluetooth {
+
+// Forward declare Packet class
+class Packet;
+
+// Iterator is a custom iterator class for Packets.
+class Iterator
+    : public std::iterator<std::random_access_iterator_tag, uint8_t> {
+ public:
+  Iterator(std::shared_ptr<const Packet> packet, size_t i);
+  Iterator(const Iterator& itr);
+
+  // All addition and subtraction operators are bounded from 0 to the length of
+  // the packet.
+  Iterator operator+(size_t offset);
+  Iterator& operator+=(size_t offset);
+  Iterator operator++(int);
+  Iterator& operator++();
+
+  Iterator operator-(size_t offset);
+  int operator-(const Iterator& itr);
+  Iterator& operator-=(size_t offset);
+  Iterator operator--(int);
+  Iterator& operator--();
+
+  Iterator& operator=(const Iterator& itr);
+
+  bool operator!=(const Iterator& itr) const;
+  bool operator==(const Iterator& itr) const;
+
+  bool operator<(const Iterator& itr) const;
+  bool operator>(const Iterator& itr) const;
+
+  bool operator<=(const Iterator& itr) const;
+  bool operator>=(const Iterator& itr) const;
+
+  uint8_t operator*() const;
+
+  template <typename FixedWidthIntegerType>
+  FixedWidthIntegerType extract() {
+    static_assert(std::is_integral<FixedWidthIntegerType>::value,
+                  "Iterator::extract requires an integral type.");
+
+    FixedWidthIntegerType extracted_value = 0;
+    for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
+      extracted_value |= static_cast<FixedWidthIntegerType>(**this) << i * 8;
+      (*this)++;
+    }
+
+    return extracted_value;
+  }
+
+  uint8_t extract8() { return extract<uint8_t>(); }
+  uint16_t extract16() { return extract<uint16_t>(); }
+  uint32_t extract32() { return extract<uint32_t>(); }
+  uint64_t extract64() { return extract<uint64_t>(); }
+
+ private:
+  std::shared_ptr<const Packet> packet_;
+  size_t index_;
+};  // Iterator
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/base/packet.cc b/packet/base/packet.cc
new file mode 100644
index 0000000..e17691c
--- /dev/null
+++ b/packet/base/packet.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "packet.h"
+
+#include <base/logging.h>
+#include <algorithm>
+
+#include "iterator.h"
+
+namespace bluetooth {
+
+size_t Packet::size() const { return packet_end_index_ - packet_start_index_; }
+
+Iterator Packet::begin() const {
+  return Iterator(shared_from_this(), packet_start_index_);
+}
+
+Iterator Packet::end() const {
+  return Iterator(shared_from_this(), packet_end_index_);
+}
+
+// For the Array operator, treat index 0 as the relative start of the packet
+uint8_t Packet::operator[](size_t i) {
+  return get_at_index(i + packet_start_index_);
+}
+
+size_t Packet::get_length() const { return data_->size(); }
+
+// Iterators use the absolute index to access data.
+uint8_t Packet::get_at_index(size_t index) const {
+  CHECK_GE(index, packet_start_index_);
+  CHECK_LT(index, packet_end_index_);
+  return data_->at(index);
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/base/packet.h b/packet/base/packet.h
new file mode 100644
index 0000000..8c8f229
--- /dev/null
+++ b/packet/base/packet.h
@@ -0,0 +1,99 @@
+/*
+ * 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 <cstdint>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace bluetooth {
+
+// Abstract base class that is subclassed to provide type-specifc accessors on
+// data. Manages said data's memory and guarantees the data's persistence. Once
+// created the underlying data is immutable.
+class Packet : public std::enable_shared_from_this<Packet> {
+  friend class Iterator;
+  friend class PacketBuilder;
+
+ public:
+  virtual ~Packet() = default;
+
+ protected:
+  Packet()
+      : packet_start_index_(0),
+        packet_end_index_(0),
+        data_(std::make_shared<std::vector<uint8_t>>(0)){};
+  Packet(std::shared_ptr<const Packet> pkt, size_t start, size_t end)
+      : packet_start_index_(start), packet_end_index_(end), data_(pkt->data_){};
+  Packet(std::shared_ptr<const Packet> pkt) : data_(pkt->data_) {
+    auto indices = pkt->GetPayloadIndecies();
+    packet_start_index_ = indices.first;
+    packet_end_index_ = indices.second;
+  };
+
+ public:
+  size_t size() const;
+  class Iterator begin() const;
+  class Iterator end() const;
+
+  uint8_t operator[](size_t i);
+
+  // Check to see if the packet is structured correctly and have the correct
+  // lengths. Data access on an invalid packet may cause a crash.
+  virtual bool IsValid() const = 0;
+
+  // Debug string representation of the packet
+  virtual std::string ToString() const = 0;
+
+  // Convert a packet horizontally in a layer, you may only specialize
+  // into a more specific type and doing otherwise will cause a compiler error
+  //
+  // Example:
+  // std::shared_ptr<AvrcpPacket> base;
+  // std::shared_ptr<AvrcpVendorPacket> p =
+  //    Packet::Specialize<AvrcpVendorPacket>(base);
+  template <class T, class U>
+  static std::shared_ptr<T> Specialize(const std::shared_ptr<U>& pkt) {
+    static_assert(std::is_convertible<U*, Packet*>::value,
+                  "Unable to specialize a non-packet object.");
+    static_assert(std::is_convertible<T*, Packet*>::value,
+                  "Unable to specialize to something that isn't a packet");
+    static_assert(std::is_convertible<T*, U*>::value,
+                  "Can not convert between the two packet types.");
+    return std::shared_ptr<T>(
+        new T(pkt, pkt->packet_start_index_, pkt->packet_end_index_));
+  };
+
+ protected:
+  // Packet should be immutable other than when building
+  size_t packet_start_index_;
+  size_t packet_end_index_;
+  std::shared_ptr<std::vector<uint8_t>> data_;
+
+ private:
+  // Only Available to the iterators
+  virtual size_t get_length() const;
+  virtual uint8_t get_at_index(size_t index) const;
+
+  // Returns the begining and end indicies of the payload of the packet.
+  // Used when constructing a packet from another packet when moving
+  // between layers.
+  virtual std::pair<size_t, size_t> GetPayloadIndecies() const = 0;
+};
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/base/packet_builder.cc b/packet/base/packet_builder.cc
new file mode 100644
index 0000000..ea3f3d2
--- /dev/null
+++ b/packet/base/packet_builder.cc
@@ -0,0 +1,43 @@
+/*
+ * 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 "packet_builder.h"
+
+#include <base/logging.h>
+
+#include "packet.h"
+
+namespace bluetooth {
+
+void PacketBuilder::ReserveSpace(const std::shared_ptr<Packet>& pkt,
+                                 size_t size) {
+  pkt->data_->reserve(size);
+}
+
+bool PacketBuilder::AddPayloadOctets(const std::shared_ptr<Packet>& pkt,
+                                     size_t octets, uint64_t value) {
+  CHECK_LE(octets, sizeof(uint64_t));
+
+  for (size_t i = 0; i < octets; i++) {
+    pkt->data_->push_back(value & 0xff);
+    pkt->packet_end_index_++;
+    value = value >> 8;
+  }
+
+  return true;
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/base/packet_builder.h b/packet/base/packet_builder.h
new file mode 100644
index 0000000..eb71708
--- /dev/null
+++ b/packet/base/packet_builder.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <memory>
+
+namespace bluetooth {
+
+class Packet;
+
+class PacketBuilder {
+ public:
+  virtual size_t size() const = 0;
+  virtual bool Serialize(const std::shared_ptr<Packet>& pkt) = 0;
+
+  virtual ~PacketBuilder() = default;
+
+ protected:
+  // Only Builders should be able to call these
+  void ReserveSpace(const std::shared_ptr<Packet>& pkt, size_t size);
+  bool AddPayloadOctets1(const std::shared_ptr<Packet>& pkt, uint8_t value) {
+    return AddPayloadOctets(pkt, 1, value);
+  }
+  bool AddPayloadOctets2(const std::shared_ptr<Packet>& pkt, uint16_t value) {
+    return AddPayloadOctets(pkt, 2, value);
+  }
+  bool AddPayloadOctets3(const std::shared_ptr<Packet>& pkt, uint32_t value) {
+    return AddPayloadOctets(pkt, 3, value);
+  }
+  bool AddPayloadOctets4(const std::shared_ptr<Packet>& pkt, uint32_t value) {
+    return AddPayloadOctets(pkt, 4, value);
+  }
+  bool AddPayloadOctets6(const std::shared_ptr<Packet>& pkt, uint64_t value) {
+    return AddPayloadOctets(pkt, 6, value);
+  }
+  bool AddPayloadOctets8(const std::shared_ptr<Packet>& pkt, uint64_t value) {
+    return AddPayloadOctets(pkt, 8, value);
+  }
+
+ private:
+  // Add |octets| bytes to the payload.  Return true if:
+  // - the value of |value| fits in |octets| bytes and
+  // - the new size of the payload is still < |kMaxPayloadOctets|
+  bool AddPayloadOctets(const std::shared_ptr<Packet>& pkt, size_t octets,
+                        uint64_t value);
+};
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/include/avrcp_packet.h b/packet/include/avrcp_packet.h
new file mode 100644
index 0000000..e086c7d
--- /dev/null
+++ b/packet/include/avrcp_packet.h
@@ -0,0 +1,37 @@
+/*
+ * 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 "avrcp/avrcp_packet.h"
+#include "avrcp/avrcp_reject_packet.h"
+#include "avrcp/capabilities_packet.h"
+#include "avrcp/get_element_attributes_packet.h"
+#include "avrcp/get_play_status_packet.h"
+#include "avrcp/pass_through_packet.h"
+#include "avrcp/register_notification_packet.h"
+#include "avrcp/vendor_packet.h"
+
+#include "avrcp/avrcp_browse_packet.h"
+#include "avrcp/change_path.h"
+#include "avrcp/general_reject_packet.h"
+#include "avrcp/get_folder_items.h"
+#include "avrcp/get_item_attributes.h"
+#include "avrcp/get_total_number_of_items.h"
+#include "avrcp/play_item.h"
+#include "avrcp/set_absolute_volume.h"
+#include "avrcp/set_addressed_player.h"
+#include "avrcp/set_browsed_player.h"
\ No newline at end of file
diff --git a/packet/include/packet.h b/packet/include/packet.h
new file mode 100644
index 0000000..01368af
--- /dev/null
+++ b/packet/include/packet.h
@@ -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.
+ */
+
+#pragma once
+
+#include "base/iterator.h"
+#include "base/packet.h"
+#include "base/packet_builder.h"
\ No newline at end of file
diff --git a/packet/tests/avrcp/avrcp_browse_packet_test.cc b/packet/tests/avrcp/avrcp_browse_packet_test.cc
new file mode 100644
index 0000000..cde0867
--- /dev/null
+++ b/packet/tests/avrcp/avrcp_browse_packet_test.cc
@@ -0,0 +1,119 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_browse_packet.h"
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+
+// A helper class that has public accessors to protected methods
+class TestPacketBuilder : public PacketBuilder {
+ public:
+  static std::unique_ptr<TestPacketBuilder> MakeBuilder(
+      std::vector<uint8_t> data) {
+    std::unique_ptr<TestPacketBuilder> builder(new TestPacketBuilder(data));
+    return builder;
+  };
+
+  // Make all the utility functions public
+  using PacketBuilder::ReserveSpace;
+  using PacketBuilder::AddPayloadOctets1;
+  using PacketBuilder::AddPayloadOctets2;
+  using PacketBuilder::AddPayloadOctets3;
+  using PacketBuilder::AddPayloadOctets4;
+  using PacketBuilder::AddPayloadOctets6;
+  using PacketBuilder::AddPayloadOctets8;
+
+  size_t size() const override { return data_.size(); };
+
+  bool Serialize(const std::shared_ptr<Packet>& pkt) override {
+    ReserveSpace(pkt, size());
+
+    for (uint8_t byte : data_) {
+      AddPayloadOctets1(pkt, byte);
+    }
+
+    return true;
+  }
+
+  TestPacketBuilder(std::vector<uint8_t> data) : data_(data){};
+
+  std::vector<uint8_t> data_;
+};
+
+namespace avrcp {
+
+using TestBrowsePacket = TestPacketType<BrowsePacket>;
+
+TEST(AvrcpBrowsePacketBuilderTest, buildPacketTest) {
+  std::vector<uint8_t> get_folder_items_request_payload = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00};
+  auto payload_builder =
+      TestPacketBuilder::MakeBuilder(get_folder_items_request_payload);
+
+  auto builder = BrowsePacketBuilder::MakeBuilder(BrowsePdu::GET_FOLDER_ITEMS,
+                                                  std::move(payload_builder));
+
+  ASSERT_EQ(builder->size(), get_folder_items_request.size());
+
+  auto test_packet = TestBrowsePacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_request);
+}
+
+TEST(AvrcpBrowsePacketTest, gettersTest) {
+  auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+
+  ASSERT_EQ(test_browse_packet->GetPdu(), BrowsePdu::GET_FOLDER_ITEMS);
+  ASSERT_EQ(test_browse_packet->GetLength(), 10u);
+}
+
+TEST(AvrcpBrowsePacketTest, payloadBoundsTest) {
+  auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+  std::vector<uint8_t> get_folder_items_request_payload = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00};
+
+  // Make a folder items payload packet out of the payload of the browse packet
+  auto get_folder_items_payload = TestBrowsePacket::Make(test_browse_packet);
+
+  for (size_t i = 0; i < get_folder_items_request_payload.size(); i++) {
+    ASSERT_EQ((*get_folder_items_payload)[i],
+              get_folder_items_request_payload[i]);
+  }
+}
+
+TEST(AvrcpBrowsePacketTest, validTest) {
+  auto test_browse_packet = TestBrowsePacket::Make(get_folder_items_request);
+
+  ASSERT_TRUE(test_browse_packet->IsValid());
+}
+
+TEST(AvrcpBrowsePacketTest, invalidTest) {
+  auto packet_copy = get_folder_items_request;
+  packet_copy.push_back(0x00);
+  auto test_browse_packet = TestBrowsePacket::Make(packet_copy);
+  ASSERT_FALSE(test_browse_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01};
+  test_browse_packet = TestBrowsePacket::Make(short_packet);
+  ASSERT_FALSE(test_browse_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/avrcp_packet_test.cc b/packet/tests/avrcp/avrcp_packet_test.cc
new file mode 100644
index 0000000..8a438b3
--- /dev/null
+++ b/packet/tests/avrcp/avrcp_packet_test.cc
@@ -0,0 +1,117 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_packet.h"
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+
+// A helper class that has public accessors to protected methods
+class TestPacketBuilder : public PacketBuilder {
+ public:
+  static std::unique_ptr<TestPacketBuilder> MakeBuilder(
+      std::vector<uint8_t> data) {
+    std::unique_ptr<TestPacketBuilder> builder(new TestPacketBuilder(data));
+    return builder;
+  };
+
+  // Make all the utility functions public
+  using PacketBuilder::ReserveSpace;
+  using PacketBuilder::AddPayloadOctets1;
+  using PacketBuilder::AddPayloadOctets2;
+  using PacketBuilder::AddPayloadOctets3;
+  using PacketBuilder::AddPayloadOctets4;
+  using PacketBuilder::AddPayloadOctets6;
+  using PacketBuilder::AddPayloadOctets8;
+
+  size_t size() const override { return data_.size(); };
+
+  bool Serialize(const std::shared_ptr<Packet>& pkt) override {
+    ReserveSpace(pkt, size());
+
+    for (uint8_t byte : data_) {
+      AddPayloadOctets1(pkt, byte);
+    }
+
+    return true;
+  }
+
+  TestPacketBuilder(std::vector<uint8_t> data) : data_(data){};
+
+  std::vector<uint8_t> data_;
+};
+
+namespace avrcp {
+
+using TestAvrcpPacket = TestPacketType<Packet>;
+
+TEST(AvrcpPacketBuilderTest, buildPacketTest) {
+  std::vector<uint8_t> get_capabilities_request_payload = {
+      0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x03};
+  auto cap_req_builder =
+      TestPacketBuilder::MakeBuilder(get_capabilities_request_payload);
+
+  auto builder = PacketBuilder::MakeBuilder(
+      CType::STATUS, 0x09, 0x00, Opcode::VENDOR, std::move(cap_req_builder));
+
+  ASSERT_EQ(builder->size(), get_capabilities_request.size());
+
+  auto test_packet = TestAvrcpPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_capabilities_request);
+}
+
+TEST(AvrcpPacketTest, getterTests) {
+  auto test_avrcp_packet = TestAvrcpPacket::Make(get_capabilities_request);
+
+  ASSERT_EQ(test_avrcp_packet->GetCType(), CType::STATUS);
+  ASSERT_EQ(test_avrcp_packet->GetSubunitType(), 0x09);
+  ASSERT_EQ(test_avrcp_packet->GetSubunitId(), 0x00);
+  ASSERT_EQ(test_avrcp_packet->GetOpcode(), Opcode::VENDOR);
+}
+
+TEST(AvrcpPacketTest, getterMaskTests) {
+  auto bad_get_cap_data = get_capabilities_request;
+  bad_get_cap_data[0] = 0xFF;  // CType
+  bad_get_cap_data[1] = 0xFF;  // Subunit Type & ID
+
+  auto test_avrcp_packet = TestAvrcpPacket::Make(bad_get_cap_data);
+
+  ASSERT_EQ(test_avrcp_packet->GetCType(), CType::INTERIM);
+  ASSERT_EQ(test_avrcp_packet->GetSubunitType(), 0b00011111);
+  ASSERT_EQ(test_avrcp_packet->GetSubunitId(), 0b00000111);
+}
+
+TEST(AvrcpPacketTest, payloadBoundsTest) {
+  auto test_avrcp_packet = TestAvrcpPacket::Make(get_capabilities_request);
+
+  std::vector<uint8_t> get_cap_payload_data = {0x00, 0x19, 0x58, 0x10,
+                                               0x00, 0x00, 0x01, 0x03};
+
+  auto get_cap_payload_packet = TestAvrcpPacket::Make(test_avrcp_packet);
+
+  // We are unable to do a direct vector compare here as one of the packets is
+  // a larger vector that only has a segment of data currently visible.
+  for (size_t i = 0; i < get_cap_payload_data.size(); i++) {
+    ASSERT_EQ(get_cap_payload_data[i], (*get_cap_payload_packet)[i]);
+  }
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/avrcp_reject_packet_test.cc b/packet/tests/avrcp/avrcp_reject_packet_test.cc
new file mode 100644
index 0000000..ebaa9a6
--- /dev/null
+++ b/packet/tests/avrcp/avrcp_reject_packet_test.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_reject_packet.h"
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestAvrcpPacket = TestPacketType<Packet>;
+
+TEST(RejectPacketBuilderTest, buildPacketTest) {
+  auto builder = RejectBuilder::MakeBuilder(
+      CommandPdu::LIST_APPLICATION_SETTING_ATTRIBUTES, Status::INVALID_COMMAND);
+
+  ASSERT_EQ(builder->size(), reject_player_app_settings_response.size());
+
+  auto test_packet = TestAvrcpPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), reject_player_app_settings_response);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/avrcp_test_packets.h b/packet/tests/avrcp/avrcp_test_packets.h
new file mode 100644
index 0000000..13994d0
--- /dev/null
+++ b/packet/tests/avrcp/avrcp_test_packets.h
@@ -0,0 +1,359 @@
+/*
+ * 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>
+
+// AVRCP packets pulled from wireshark
+namespace {
+
+// AVRCP Get Capabilities Request packet
+std::vector<uint8_t> get_capabilities_request = {
+    0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x03};
+
+// AVRCP Get Capabilities Request packet with Company ID
+std::vector<uint8_t> get_capabilities_request_company_id = {
+    0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x02};
+
+// AVRCP Get Capabilities Request packet with Unknown
+std::vector<uint8_t> get_capabilities_request_unknown = {
+    0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01, 0x7f};
+
+// AVRCP Get Capabilities Response to Company ID request
+std::vector<uint8_t> get_capabilities_response_company_id = {
+    0x0c, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00,
+    0x08, 0x02, 0x02, 0x00, 0x19, 0x58, 0x00, 0x23, 0x45};
+
+// AVRCP Get Capabilities Response to Events Supported request
+std::vector<uint8_t> get_capabilities_response_events_supported = {
+    0x0c, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00,
+    0x00, 0x05, 0x03, 0x03, 0x01, 0x02, 0x05};
+
+// AVRCP Get Element Attributes request for current playing song and attribute
+// Title
+std::vector<uint8_t> get_element_attributes_request_partial = {
+    0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x20, 0x00, 0x00, 0x0d, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01};
+
+// AVRCP Get Element Attributes request for current playing song and attributes
+// Title, Artist, Album, Media Number, Playing Time, Total Number of Media, and
+// Genre
+std::vector<uint8_t> get_element_attributes_request_full = {
+    0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x20, 0x00, 0x00, 0x25, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00,
+    0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06};
+
+// AVRCP Get Element Attributes response with attribute values as follows
+// Title: "Test Song"
+// Artist: "Test Artist"
+// Album: "Test Album"
+// Track Number: "1"
+// Number of Tracks: "2"
+// Genre: "Test Genre"
+// Duration: "1000"
+std::vector<uint8_t> get_elements_attributes_response_full = {
+    0x0c, 0x48, 0x00, 0x00, 0x19, 0x58, 0x20, 0x00, 0x00, 0x67, 0x07, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x6a, 0x00, 0x09, 0x54, 0x65, 0x73, 0x74, 0x20,
+    0x53, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6a, 0x00, 0x0b,
+    0x54, 0x65, 0x73, 0x74, 0x20, 0x41, 0x72, 0x74, 0x69, 0x73, 0x74, 0x00,
+    0x00, 0x00, 0x03, 0x00, 0x6a, 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x20,
+    0x41, 0x6c, 0x62, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00,
+    0x01, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x6a, 0x00, 0x01, 0x32, 0x00,
+    0x00, 0x00, 0x06, 0x00, 0x6a, 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x20,
+    0x47, 0x65, 0x6e, 0x72, 0x65, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6a, 0x00,
+    0x04, 0x31, 0x30, 0x30, 0x30};
+
+// AVRCP Get Play Status Request
+std::vector<uint8_t> get_play_status_request = {0x01, 0x48, 0x00, 0x00, 0x19,
+                                                0x58, 0x30, 0x00, 0x00, 0x00};
+
+// AVRCP Get Play Status Response
+std::vector<uint8_t> get_play_status_response = {
+    0x0c, 0x48, 0x00, 0x00, 0x19, 0x58, 0x30, 0x00, 0x00, 0x09,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00};
+
+// AVRCP Pass Through Command Play Pushed Request
+std::vector<uint8_t> pass_through_command_play_pushed = {0x00, 0x48, 0x7c, 0x44,
+                                                         0x00};
+
+// AVRCP Pass Through Command Play Pushed Response
+std::vector<uint8_t> pass_through_command_play_released = {0x09, 0x48, 0x7c,
+                                                           0xc4, 0x00};
+
+// AVRCP Register Playback Status Notification
+std::vector<uint8_t> register_play_status_notification = {
+    0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
+    0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x05};
+
+// AVRCP Register Volume Changed Notification
+std::vector<uint8_t> register_volume_changed_notification = {
+    0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
+    0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x00};
+
+// AVRCP Register Notification without any parameter
+std::vector<uint8_t> register_notification_invalid = {
+    0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x05};
+
+// AVRCP Interim Playback Status Notification
+std::vector<uint8_t> interim_play_status_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x01, 0x00};
+
+// AVRCP Interim Track Changed Notification
+std::vector<uint8_t> interim_track_changed_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x09,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+// AVRCP Changed Playback Position Notification
+std::vector<uint8_t> changed_play_pos_notification = {
+    0x0d, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
+    0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00};
+
+// AVRCP Interim Now Playing Changed Notification
+std::vector<uint8_t> interim_now_playing_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x01, 0x09};
+
+// AVRCP Interim Available Players Changed Notification
+std::vector<uint8_t> interim_available_players_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x01, 0x0a};
+
+// AVRCP Interim Addressed Player Changed Notification with active
+// player ID 1
+std::vector<uint8_t> interim_addressed_player_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
+    0x00, 0x05, 0x0b, 0x00, 0x01, 0x00, 0x00};
+
+// AVRCP Interim UIDs Changed Notification
+std::vector<uint8_t> interim_uids_notificaiton = {0x0f, 0x48, 0x00, 0x00, 0x19,
+                                                  0x58, 0x31, 0x00, 0x00, 0x03,
+                                                  0x0c, 0x00, 0x00};
+
+// AVRCP Interim Volume Changed Notification with volume at 55% (0x47)
+std::vector<uint8_t> interim_volume_changed_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x0d, 0x47};
+
+// AVRCP Rejected Volume Changed Notification with volume at 0%
+std::vector<uint8_t> rejected_volume_changed_notification = {
+    0x0a, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x0d, 0x00};
+
+// AVRCP Changed Volume Changed Notification with volume at 55% (0x47)
+std::vector<uint8_t> changed_volume_changed_notification = {
+    0x0d, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x0d, 0x47};
+
+// AVRCP Reject List Player Application Settings Response
+std::vector<uint8_t> reject_player_app_settings_response = {
+    0x0a, 0x48, 0x00, 0x00, 0x19, 0x58, 0x11, 0x00, 0x00, 0x01, 0x00};
+
+// AVRCP Browse General Reject packet for invalid PDU ID
+std::vector<uint8_t> general_reject_invalid_command_packet = {0xa0, 0x00, 0x01,
+                                                              0x00};
+
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+//    scope = 0x00 (Media Player List)
+//    start_item = 0x00
+//    end_item = 0x03
+//    attributes_requested: all
+std::vector<uint8_t> get_folder_items_request = {0x71, 0x00, 0x0a, 0x00, 0x00,
+                                                 0x00, 0x00, 0x00, 0x00, 0x00,
+                                                 0x00, 0x03, 0x00};
+
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+//    scope = 0x01 (VFS)
+//    start_item = 0x00
+//    end_item = 0x09
+//    attributes_requested: none
+std::vector<uint8_t> get_folder_items_request_no_attrs = {
+    0x71, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x09, 0xff};
+
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+//    scope = 0x01 (VFS)
+//    start_item = 0x00
+//    end_item = 0x09
+//    attributes_requested: Title
+std::vector<uint8_t> get_folder_items_request_title = {
+    0x71, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x1};
+
+// AVRCP Browse Get Folder Items Request packet for vfs with
+// the following data:
+//    scope = 0x01 (VFS)
+//    start_item = 0x00
+//    end_item = 0x05
+//    attributes_requested: TITLE
+std::vector<uint8_t> get_folder_items_request_vfs = {
+    0x71, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01};
+
+// AVRCP Browse Get Folder Items Request packet for now playing with
+// the following data:
+//    scope = 0x03 (Now Playing)
+//    start_item = 0x00
+//    end_item = 0x05
+//    attributes_requested: All Items
+std::vector<uint8_t> get_folder_items_request_now_playing = {
+    0x71, 0x00, 0x0e, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x05, 0x00};
+
+// AVRCP Browse Get Folder Items Response packet with range out of bounds error
+std::vector<uint8_t> get_folder_items_error_response = {0x71, 0x00, 0x01, 0x0b};
+
+// AVRCP Browse Get Folder Items Response packet for media players
+// Contains one media player with the following fields:
+//    id = 0x0001
+//    name = "com.google.android.music"
+//    browsing_supported = true
+std::vector<uint8_t> get_folder_items_media_player_response = {
+    0x71, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x34,
+    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xb7, 0x01, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x6a, 0x00, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67,
+    0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+    0x69, 0x64, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63};
+
+// AVRCP Browse Get Folder Items Response packet with one folder
+// with the following fields:
+//    uid = 0x0000000000000001
+//    type = 0x00 (Mixed);
+//    name = "Test Folder"
+//    is_playable = true
+std::vector<uint8_t> get_folder_items_folder_response = {
+    0x71, 0x00, 0x21, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x19, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x6a, 0x00,
+    0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72};
+
+// AVRCP Browse Get Folder Items Response packet with one song
+// with the following fields:
+//    uid = 0x0000000000000002
+//    name = "Test Title"
+//    attribute[TITLE] = "Test Title"
+std::vector<uint8_t> get_folder_items_song_response = {
+    0x71, 0x00, 0x32, 0x04, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x2a,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x6a,
+    0x00, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x54, 0x69, 0x74, 0x6c,
+    0x65, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00, 0x0a, 0x54,
+    0x65, 0x73, 0x74, 0x20, 0x54, 0x69, 0x74, 0x6c, 0x65};
+
+// AVRCP Browse Change Path Request down to folder with UID 0x0000000000000002
+std::vector<uint8_t> change_path_request = {0x72, 0x00, 0x0b, 0x00, 0x00,
+                                            0x01, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x02};
+
+// AVRCP Browse Change Path Request up
+std::vector<uint8_t> change_path_up_request = {0x72, 0x00, 0x0b, 0x00, 0x00,
+                                               0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+                                               0xFF, 0xFF, 0xFF, 0xFF};
+
+// AVRCP Browse Change Path Response with two items in current folder
+std::vector<uint8_t> change_path_response = {0x72, 0x00, 0x05, 0x04,
+                                             0x00, 0x00, 0x00, 0x02};
+
+// AVRCP Browse Change Path Response with an error of invalid direction
+std::vector<uint8_t> change_path_error_response = {0x72, 0x00, 0x01, 0x07};
+
+// AVRCP Get Item Attributes request with all attributes requested
+// with the following fields:
+//    scope = 0x03 (Now Playing List)
+//    uid_counter = 0x0000
+//    uid = 0x0000000000000001
+std::vector<uint8_t> get_item_attributes_request_all_attributes = {
+    0x73, 0x00, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07};
+
+// AVRCP Get Item Attributes request with all attributes requested
+// with the following fields:
+//    scope = 0x03 (Now Playing List)
+//    uid_counter = 0x0001
+//    uid = 0x0000000000000001
+std::vector<uint8_t> get_item_attributes_request_all_attributes_invalid = {
+    0x73, 0x00, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x01, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07};
+
+// AVRCP Get Item Attributes Response with the following attributes:
+//    title = "Test Song"
+//    artist = "Test Artist"
+//    album = "Test Album"
+std::vector<uint8_t> get_item_attributes_song_response = {
+    0x73, 0x00, 0x38, 0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00,
+    0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6e, 0x67, 0x00, 0x00,
+    0x00, 0x02, 0x00, 0x6a, 0x00, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41,
+    0x72, 0x74, 0x69, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, 0x00,
+    0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41, 0x6c, 0x62, 0x75, 0x6d};
+
+// AVRCP Set Addressed Player Request with player_id = 0
+std::vector<uint8_t> set_addressed_player_request = {
+    0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x02, 0x00, 0x00};
+
+// AVRCP Set Addressed Player Request with player_id = 1
+std::vector<uint8_t> set_addressed_player_id_1_request = {
+    0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x02, 0x00, 0x01};
+
+// AVRCP Set Addressed Player Response with status success
+std::vector<uint8_t> set_addressed_player_response = {
+    0x09, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x01, 0x04};
+
+// AVRCP Set Browsed Player Request with player_id = 2
+std::vector<uint8_t> set_browsed_player_request = {0x70, 0x00, 0x02, 0x00,
+                                                   0x02};
+
+// AVRCP Set Browsed Player Response with num items = 4 and depth = 0
+std::vector<uint8_t> set_browsed_player_response = {
+    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_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 = {
+    0x75, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05};
+
+// AVRCP Play Item Request with scope = Now Playing and
+// UID = 0x0000000000000003
+std::vector<uint8_t> play_item_request = {
+    0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x74, 0x00, 0x00, 0x0b, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00};
+
+// AVRCP Play Item Response
+std::vector<uint8_t> play_item_response = {0x09, 0x48, 0x00, 0x00, 0x19, 0x58,
+                                           0x74, 0x00, 0x00, 0x01, 0x04};
+
+// AVRCP Set Absolute Volume Request with volume at 56% (0x48)
+std::vector<uint8_t> set_absolute_volume_request = {
+    0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x50, 0x00, 0x00, 0x01, 0x48};
+
+// AVRCP Set Absolute Volume Response with voume at 52% (0x43)
+std::vector<uint8_t> set_absolute_volume_response = {
+    0x09, 0x48, 0x00, 0x00, 0x19, 0x58, 0x50, 0x00, 0x00, 0x01, 0x43};
+
+}  // namespace
diff --git a/packet/tests/avrcp/change_path_packet_test.cc b/packet/tests/avrcp/change_path_packet_test.cc
new file mode 100644
index 0000000..b14d577
--- /dev/null
+++ b/packet/tests/avrcp/change_path_packet_test.cc
@@ -0,0 +1,85 @@
+/*
+ * 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 "avrcp_test_packets.h"
+#include "change_path.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestChangePathReqPacket = TestPacketType<ChangePathRequest>;
+
+TEST(ChangePathResponseBuilderTest, builderTest) {
+  auto builder = ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, 2);
+  ASSERT_EQ(builder->size(), change_path_response.size());
+
+  auto test_packet = TestChangePathReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), change_path_response);
+}
+
+TEST(ChangePathResponseBuilderTest, builderErrorStatusTest) {
+  // NOTE: The num items in folder field doesn't matter when the status is
+  // not NO_ERROR
+  auto builder =
+      ChangePathResponseBuilder::MakeBuilder(Status::INVALID_DIRECTION, 2);
+  ASSERT_EQ(builder->size(), change_path_error_response.size());
+
+  auto test_packet = TestChangePathReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), change_path_error_response);
+}
+
+TEST(ChangePathRequestTest, getterTest) {
+  auto test_packet = TestChangePathReqPacket::Make(change_path_request);
+
+  ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+  ASSERT_EQ(test_packet->GetDirection(), Direction::DOWN);
+  ASSERT_EQ(test_packet->GetUid(), 0x0000000000000002u);
+}
+
+TEST(ChangePathRequestTest, validTest) {
+  auto test_packet = TestChangePathReqPacket::Make(change_path_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(ChangePathRequestTest, invalidTest) {
+  auto packet_copy = change_path_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestChangePathReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestChangePathReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+TEST(ChangePathRequestBuilder, builderTest) {
+  auto builder = ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 2);
+  ASSERT_EQ(builder->size(), change_path_request.size());
+
+  auto test_packet = TestChangePathReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), change_path_request);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/general_reject_packet_test.cc b/packet/tests/avrcp/general_reject_packet_test.cc
new file mode 100644
index 0000000..e27d0b7
--- /dev/null
+++ b/packet/tests/avrcp/general_reject_packet_test.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "general_reject_packet.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGeneralRejectPacket = TestPacketType<BrowsePacket>;
+
+TEST(GeneralRejectPacketBuilderTest, buildPacketTest) {
+  auto builder = GeneralRejectBuilder::MakeBuilder(BrowsePdu::GENERAL_REJECT,
+                                                   Status::INVALID_COMMAND);
+
+  ASSERT_EQ(builder->size(), general_reject_invalid_command_packet.size());
+
+  auto test_packet = TestGeneralRejectPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), general_reject_invalid_command_packet);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/tests/avrcp/get_capabilities_packet_test.cc b/packet/tests/avrcp/get_capabilities_packet_test.cc
new file mode 100644
index 0000000..267c62b
--- /dev/null
+++ b/packet/tests/avrcp/get_capabilities_packet_test.cc
@@ -0,0 +1,122 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "capabilities_packet.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using GetCapRequestTestPacket = TestPacketType<GetCapabilitiesRequest>;
+
+// Test parsing a GetCapabilities Request
+TEST(GetCapabilitiesRequestPacketTest, getterTest) {
+  auto test_packet = GetCapRequestTestPacket::Make(get_capabilities_request);
+
+  ASSERT_EQ(test_packet->GetCapabilityRequested(),
+            Capability::EVENTS_SUPPORTED);
+}
+
+TEST(GetCapabilitiesRequestPacketTest, validTest) {
+  auto test_packet = GetCapRequestTestPacket::Make(get_capabilities_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetCapabilitiesRequestPacketTest, invalidTest) {
+  std::vector<uint8_t> packet_copy = get_capabilities_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = GetCapRequestTestPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {
+      0, 1, 2, 3, 4, 5, 6,
+  };
+  test_packet = GetCapRequestTestPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+// Test that the length returned by the builder grows correctlyas fields are
+// added
+TEST(GetCapabilityResponseBuilder, builderLengthTest) {
+  auto builder = GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x000000);
+  ASSERT_EQ(builder->size(), 15u);
+  builder->AddCompanyId(0x000001);
+  ASSERT_EQ(builder->size(), 18u);
+  builder->AddCompanyId(0x000002);
+  ASSERT_EQ(builder->size(), 21u);
+
+  builder = GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
+      Event::PLAYBACK_STATUS_CHANGED);
+  ASSERT_EQ(builder->size(), 13u);
+  builder->AddEvent(Event::TRACK_CHANGED);
+  ASSERT_EQ(builder->size(), 14u);
+  builder->AddEvent(Event::PLAYBACK_POS_CHANGED);
+  ASSERT_EQ(builder->size(), 15u);
+}
+
+// Check to see that adding the same value multiple times does nothing
+TEST(GetCapabilityResponseBuilder, duplicateAddTest) {
+  auto builder = GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x000000);
+  ASSERT_EQ(builder->size(), 15u);
+  builder->AddCompanyId(0x000000);
+  ASSERT_EQ(builder->size(), 15u);
+
+  builder = GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
+      Event::PLAYBACK_STATUS_CHANGED);
+  ASSERT_EQ(builder->size(), 13u);
+  builder->AddEvent(Event::PLAYBACK_STATUS_CHANGED);
+  ASSERT_EQ(builder->size(), 13u);
+}
+
+// Test that trying to to add the wrong type of field to a builder causes death
+TEST(GetCapabilityResponseBuilder, mismatchAddDeathTest) {
+  auto builder = GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x000000);
+  ASSERT_DEATH(builder->AddEvent(Event::PLAYBACK_STATUS_CHANGED),
+               "capability_ == Capability::EVENTS_SUPPORTED");
+
+  builder = GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
+      Event::PLAYBACK_STATUS_CHANGED);
+  ASSERT_DEATH(builder->AddCompanyId(0x000000),
+               "capability_ == Capability::COMPANY_ID");
+}
+
+// Test building a GetCapabilities Response to a Company ID request
+TEST(GetCapabilityResponseBuilder, comanyIdBuilderTest) {
+  auto builder = GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x002345);
+  builder->AddCompanyId(BLUETOOTH_COMPANY_ID);
+
+  auto test_packet = GetCapRequestTestPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_capabilities_response_company_id);
+}
+
+// Test building a GetCapabilities Response to an Events Supported request
+TEST(GetCapabilityResponseBuilder, eventsSupportedBuilderTest) {
+  auto builder = GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
+      Event::PLAYBACK_STATUS_CHANGED);
+  builder->AddEvent(Event::TRACK_CHANGED);
+  builder->AddEvent(Event::PLAYBACK_POS_CHANGED);
+
+  auto test_packet = GetCapRequestTestPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_capabilities_response_events_supported);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/get_element_attributes_packet_test.cc b/packet/tests/avrcp/get_element_attributes_packet_test.cc
new file mode 100644
index 0000000..8a05487
--- /dev/null
+++ b/packet/tests/avrcp/get_element_attributes_packet_test.cc
@@ -0,0 +1,133 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_element_attributes_packet.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetElemAttrReqPacket = TestPacketType<GetElementAttributesRequest>;
+
+TEST(GetElementAttributesRequestPacketTest, getterTest) {
+  // Only Title is requested
+  auto test_packet =
+      TestGetElemAttrReqPacket::Make(get_element_attributes_request_partial);
+
+  ASSERT_EQ(test_packet->GetIdentifier(), 0u);
+
+  auto attribute_list = test_packet->GetAttributesRequested();
+  ASSERT_EQ(attribute_list.size(), 1u);
+  ASSERT_EQ(attribute_list[0], Attribute::TITLE);
+
+  // Title, Artist, Album, Media Numer, Playing Time, Total Number of Media,
+  // and Genre requested
+  test_packet =
+      TestGetElemAttrReqPacket::Make(get_element_attributes_request_full);
+
+  ASSERT_EQ(test_packet->GetIdentifier(), 0u);
+
+  attribute_list = test_packet->GetAttributesRequested();
+  ASSERT_EQ(attribute_list.size(), 7u);
+  ASSERT_EQ(attribute_list[0], Attribute::TITLE);
+  ASSERT_EQ(attribute_list[1], Attribute::ARTIST_NAME);
+  ASSERT_EQ(attribute_list[2], Attribute::ALBUM_NAME);
+  ASSERT_EQ(attribute_list[3], Attribute::TRACK_NUMBER);
+  ASSERT_EQ(attribute_list[4], Attribute::PLAYING_TIME);
+  ASSERT_EQ(attribute_list[5], Attribute::TOTAL_NUMBER_OF_TRACKS);
+  ASSERT_EQ(attribute_list[6], Attribute::GENRE);
+}
+
+TEST(GetElementAttributesRequestPacketTest, validTest) {
+  auto test_packet =
+      TestGetElemAttrReqPacket::Make(get_element_attributes_request_partial);
+  ASSERT_TRUE(test_packet->IsValid());
+
+  test_packet =
+      TestGetElemAttrReqPacket::Make(get_element_attributes_request_full);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetElementAttributesRequestPacketTest, invalidTest) {
+  std::vector<uint8_t> packet_copy = get_element_attributes_request_partial;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestGetElemAttrReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00};
+  test_packet = TestGetElemAttrReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+TEST(GetElementAttributesResponseBuilderTest, builderLengthTest) {
+  // Attributes have a size of 8 + string length
+  auto builder = GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF);
+  ASSERT_EQ(builder->size(), 11u);
+  builder->AddAttributeEntry(Attribute::TITLE, "test");
+  ASSERT_EQ(builder->size(), 23u);
+  builder->AddAttributeEntry(Attribute::ARTIST_NAME, "test");
+  ASSERT_EQ(builder->size(), 35u);
+}
+
+TEST(GetElementAttributesResponseBuilderTest, builderTest) {
+  auto builder = GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF);
+  builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+  builder->AddAttributeEntry(Attribute::TRACK_NUMBER, "1");
+  builder->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2");
+  builder->AddAttributeEntry(Attribute::GENRE, "Test Genre");
+  builder->AddAttributeEntry(Attribute::PLAYING_TIME, "1000");
+
+  ASSERT_EQ(builder->size(), get_elements_attributes_response_full.size());
+
+  auto test_packet = TestGetElemAttrReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_elements_attributes_response_full);
+}
+
+TEST(GetElementAttributesResponseBuilderTest, truncateBuilderTest) {
+  auto attribute = AttributeEntry(Attribute::TITLE, "1234");
+  size_t truncated_size = VendorPacket::kMinSize();
+  truncated_size += 1;                 // Number of attributes
+  truncated_size += attribute.size();  // Attribute size
+
+  auto truncated_builder =
+      GetElementAttributesResponseBuilder::MakeBuilder(truncated_size);
+  ASSERT_TRUE(
+      truncated_builder->AddAttributeEntry(Attribute::TITLE, "1234truncated"));
+  ASSERT_EQ(truncated_builder->size(), truncated_size);
+
+  ASSERT_FALSE(truncated_builder->AddAttributeEntry(Attribute::ARTIST_NAME,
+                                                    "Can not add"));
+
+  auto truncated_packet = TestGetElemAttrReqPacket::Make();
+  truncated_builder->Serialize(truncated_packet);
+
+  auto builder = GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF);
+  builder->AddAttributeEntry(attribute);
+  auto test_packet = TestGetElemAttrReqPacket::Make();
+  builder->Serialize(test_packet);
+
+  ASSERT_EQ(truncated_packet->GetData(), test_packet->GetData());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/get_folder_items_packet_test.cc b/packet/tests/avrcp/get_folder_items_packet_test.cc
new file mode 100644
index 0000000..ec2d733
--- /dev/null
+++ b/packet/tests/avrcp/get_folder_items_packet_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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_folder_items.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetFolderItemsReqPacket = TestPacketType<GetFolderItemsRequest>;
+
+TEST(GetFolderItemsResponseBuilderTest, builderMediaPlayerSizeTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  // If there are no items, then the only data in the packet is the status
+  ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  builder->AddMediaPlayer(player);
+  ASSERT_EQ(builder->size(), get_folder_items_media_player_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderMediaPlayerAddTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  builder->AddMediaPlayer(player);
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_media_player_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderPlayerAddMtuTest) {
+  MediaPlayerItem player1(1, "Player 1 that fits", true);
+  MediaPlayerItem player2(2, "Player 2 that doesn't fit", true);
+  MediaPlayerItem player3(3, "Player 3 that fits", true);
+
+  // Browsing Header + Status field + UID Counter field + Number of Items field
+  auto packet_size = BrowsePacket::kMinSize() + 5;
+  packet_size += player1.size() + player3.size();
+
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, packet_size);
+
+  ASSERT_TRUE(builder->AddMediaPlayer(player1));
+  ASSERT_FALSE(builder->AddMediaPlayer(player2));
+  ASSERT_TRUE(builder->AddMediaPlayer(player3));
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderSizeTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR,
+                                                               0x0000, 0xFFFF);
+  ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+  auto folder = FolderItem(0x0000000000000001, 0x00, true, "Test Folder");
+  builder->AddFolder(folder);
+  ASSERT_EQ(builder->size(), get_folder_items_folder_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderAddTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR,
+                                                               0x0000, 0xFFFF);
+  auto folder = FolderItem(0x0000000000000001, 0x00, true, "Test Folder");
+  builder->AddFolder(folder);
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_folder_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderFolderAddMtuTest) {
+  FolderItem folder1(0x01, 0x00, true, "Folder 1 that fits");
+  FolderItem folder2(0x02, 0x00, true, "Folder 2 that doesn't fit");
+  FolderItem folder3(0x03, 0x00, true, "Folder 3 that fits");
+
+  // Browsing Header + Status field + UID Counter field + Number of Items field
+  auto packet_size = BrowsePacket::kMinSize() + 5;
+  packet_size += folder1.size() + folder3.size();
+
+  auto builder = GetFolderItemsResponseBuilder::MakeVFSBuilder(
+      Status::NO_ERROR, 0x0000, packet_size);
+
+  ASSERT_TRUE(builder->AddFolder(folder1));
+  ASSERT_FALSE(builder->AddFolder(folder2));
+  ASSERT_TRUE(builder->AddFolder(folder3));
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongSizeTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  ASSERT_EQ(builder->size(), get_folder_items_error_response.size());
+
+  std::set<AttributeEntry> attributes;
+  attributes.insert(AttributeEntry(Attribute::TITLE, "Test Title"));
+  auto song = MediaElementItem(0x02, "Test Title", attributes);
+  builder->AddSong(song);
+  ASSERT_EQ(builder->size(), get_folder_items_song_response.size());
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongAddTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  std::set<AttributeEntry> attributes;
+  attributes.insert(AttributeEntry(Attribute::TITLE, "Test Title"));
+  auto song = MediaElementItem(0x02, "Test Title", attributes);
+  builder->AddSong(song);
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_song_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderSongAddMtuTest) {
+  MediaElementItem song1(0x01, "Song 1 that fits", std::set<AttributeEntry>());
+  MediaElementItem song2(0x02, "Song 2 that doesn't fit",
+                         std::set<AttributeEntry>());
+  MediaElementItem song3(0x03, "Song 3 that fits", std::set<AttributeEntry>());
+
+  auto packet_size = BrowsePacket::kMinSize() + 5;
+  packet_size += song1.size() + song3.size();
+
+  auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, packet_size);
+
+  ASSERT_TRUE(builder->AddSong(song1));
+  ASSERT_FALSE(builder->AddSong(song2));
+  ASSERT_TRUE(builder->AddSong(song3));
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderNoItemsTest) {
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+
+  builder = GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR,
+                                                          0x0000, 0xFFFF);
+  test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+
+  builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_error_response);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderErrorStatusTest) {
+  std::vector<uint8_t> get_folder_items_inv_scope = {0x71, 0x00, 0x01, 0x0a};
+
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::INVALID_SCOPE, 0x0000, 0xFFFF);
+
+  // Check that the status remains INVALID_SCOPE even though there are zero
+  // items
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_inv_scope);
+
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  builder->AddMediaPlayer(player);
+
+  // Check to make sure that even though we added an item, it doesn't get
+  // written to the packet
+  test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_inv_scope);
+}
+
+TEST(GetFolderItemsResponseBuilderTest, builderDeathTest) {
+  auto player = MediaPlayerItem(0x0001, "com.google.android.music", true);
+  auto folder = FolderItem(0x01, 0x00, true, "test folder");
+  auto song = MediaElementItem(0x01, "test song", std::set<AttributeEntry>());
+
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  ASSERT_DEATH(builder->AddFolder(folder), "scope_ == Scope::VFS");
+  ASSERT_DEATH(builder->AddSong(song),
+               "scope_ == Scope::VFS \\|\\| scope_ == Scope::NOW_PLAYING");
+
+  builder = GetFolderItemsResponseBuilder::MakeVFSBuilder(Status::NO_ERROR,
+                                                          0x0000, 0xFFFF);
+  ASSERT_DEATH(builder->AddMediaPlayer(player),
+               "scope_ == Scope::MEDIA_PLAYER_LIST");
+
+  builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  ASSERT_DEATH(builder->AddMediaPlayer(player),
+               "scope_ == Scope::MEDIA_PLAYER_LIST");
+  ASSERT_DEATH(builder->AddFolder(folder), "scope_ == Scope::VFS");
+}
+
+TEST(GetFolderItemsRequestTest, getterTest) {
+  auto test_packet =
+      TestGetFolderItemsReqPacket::Make(get_folder_items_request_vfs);
+
+  ASSERT_EQ(test_packet->GetScope(), Scope::VFS);
+  ASSERT_EQ(test_packet->GetStartItem(), 0x00000000u);
+  ASSERT_EQ(test_packet->GetEndItem(), 0x00000005u);
+  ASSERT_EQ(test_packet->GetNumAttributes(), 1);
+
+  std::vector<Attribute> attribute_list = {Attribute::TITLE};
+  ASSERT_EQ(test_packet->GetAttributesRequested(), attribute_list);
+}
+
+TEST(GetFolderItemsRequestBuilderTest, builderZeroAttrsTest) {
+  auto builder =
+      GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 9, {});
+  ASSERT_EQ(builder->size(), get_folder_items_request_no_attrs.size());
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_request_no_attrs);
+}
+
+TEST(GetFolderItemsRequestBuilderTest, builderTest) {
+  auto builder = GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 9,
+                                                           {Attribute::TITLE});
+  ASSERT_EQ(builder->size(), get_folder_items_request_title.size());
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_request_title);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/get_item_attributes_packet_test.cc b/packet/tests/avrcp/get_item_attributes_packet_test.cc
new file mode 100644
index 0000000..3d6f691
--- /dev/null
+++ b/packet/tests/avrcp/get_item_attributes_packet_test.cc
@@ -0,0 +1,130 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_item_attributes.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetItemAttrsReqPacket = TestPacketType<GetItemAttributesRequest>;
+
+TEST(GetItemAttributesResponseBuilderTest, builderSizeTest) {
+  auto builder =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF);
+  ASSERT_EQ(builder->size(), 5u);
+
+  builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  ASSERT_EQ(builder->size(), 22u);
+
+  builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  ASSERT_EQ(builder->size(), 41u);
+
+  builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+  ASSERT_EQ(builder->size(), get_item_attributes_song_response.size());
+}
+
+TEST(GetItemAttributesResponseBuilderTest, builderTest) {
+  auto builder =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF);
+  builder->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  builder->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  builder->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+
+  auto test_packet = TestGetItemAttrsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_item_attributes_song_response);
+}
+
+TEST(GetItemAttributesResponseBuilderTest, truncateBuilderTest) {
+  auto attribute = AttributeEntry(Attribute::TITLE, "1234");
+  size_t truncated_size = BrowsePacket::kMinSize();
+  truncated_size += 2;  // Status field  + Number of attributes field
+  truncated_size += attribute.size();  // Attribute size
+
+  auto truncated_builder = GetItemAttributesResponseBuilder::MakeBuilder(
+      Status::NO_ERROR, truncated_size);
+  ASSERT_TRUE(
+      truncated_builder->AddAttributeEntry(Attribute::TITLE, "1234truncated"));
+  ASSERT_EQ(truncated_builder->size(), truncated_size);
+
+  ASSERT_FALSE(truncated_builder->AddAttributeEntry(Attribute::ARTIST_NAME,
+                                                    "Can not add"));
+
+  auto truncated_packet = TestGetItemAttrsReqPacket::Make();
+  truncated_builder->Serialize(truncated_packet);
+
+  auto builder =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF);
+  builder->AddAttributeEntry(attribute);
+  auto test_packet = TestGetItemAttrsReqPacket::Make();
+  builder->Serialize(test_packet);
+
+  ASSERT_EQ(truncated_packet->GetData(), test_packet->GetData());
+}
+
+TEST(GetItemAttributesResponseBuilderTest, errorStatusTest) {
+  std::vector<uint8_t> does_not_exist_status = {0x73, 0x00, 0x01, 0x09};
+  auto builder = GetItemAttributesResponseBuilder::MakeBuilder(
+      Status::DOES_NOT_EXIST, 0xFFFF);
+  ASSERT_EQ(builder->size(), does_not_exist_status.size());
+
+  auto test_packet = TestGetItemAttrsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), does_not_exist_status);
+}
+
+TEST(GetItemAttributesRequestTest, getterTest) {
+  auto test_packet = TestGetItemAttrsReqPacket::Make(
+      get_item_attributes_request_all_attributes);
+
+  ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+  ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+  ASSERT_EQ(test_packet->GetUid(), 0x0000000000000001u);
+  ASSERT_EQ(test_packet->GetNumAttributes(), 7);
+  std::vector<Attribute> attrs_requested = {Attribute::TITLE,
+                                            Attribute::ARTIST_NAME,
+                                            Attribute::ALBUM_NAME,
+                                            Attribute::TRACK_NUMBER,
+                                            Attribute::TOTAL_NUMBER_OF_TRACKS,
+                                            Attribute::GENRE,
+                                            Attribute::PLAYING_TIME};
+  ASSERT_EQ(test_packet->GetAttributesRequested(), attrs_requested);
+}
+
+TEST(GetItemAttributesRequestTest, validTest) {
+  auto test_packet = TestGetItemAttrsReqPacket::Make(
+      get_item_attributes_request_all_attributes);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetItemAttributesRequestTest, invalidTest) {
+  auto packet_copy = get_item_attributes_request_all_attributes;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestGetItemAttrsReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03,
+                                       0x04, 0x05, 0x06, 0x07};
+  test_packet = TestGetItemAttrsReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/get_play_status_packet_test.cc b/packet/tests/avrcp/get_play_status_packet_test.cc
new file mode 100644
index 0000000..c15147d
--- /dev/null
+++ b/packet/tests/avrcp/get_play_status_packet_test.cc
@@ -0,0 +1,39 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_play_status_packet.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetPlayStatusRspPacket = TestPacketType<Packet>;
+
+TEST(GetPlayStatusResponseBuilderTest, builderTest) {
+  auto builder = GetPlayStatusResponseBuilder::MakeBuilder(0, 0xFFFFFFFF, 0);
+
+  ASSERT_EQ(builder->size(), get_play_status_response.size());
+
+  auto test_packet = TestGetPlayStatusRspPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_play_status_response);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
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
new file mode 100644
index 0000000..eb7efc2
--- /dev/null
+++ b/packet/tests/avrcp/get_total_number_of_items_packet_test.cc
@@ -0,0 +1,73 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "get_total_number_of_items.h"
+#include "packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestGetTotalNumItemsReqPacket =
+    TestPacketType<GetTotalNumberOfItemsRequest>;
+
+TEST(GetTotalNumberOfItemsResponseBuilderTest, builderTest) {
+  auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+      Status::NO_ERROR, 0x0000u, 0x00000005u);
+  ASSERT_EQ(builder->size(), get_total_number_of_items_response.size());
+
+  auto test_packet = TestGetTotalNumItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_total_number_of_items_response);
+}
+
+TEST(GetTotalNumberOfItemsResponseBuilderTest, errorStatusTest) {
+  std::vector<uint8_t> inv_scope_status_packet = {0x75, 0x00, 0x01, 0x0a};
+  auto builder = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(
+      Status::INVALID_SCOPE, 0x1234u, 0x56789abcu);
+  ASSERT_EQ(builder->size(), inv_scope_status_packet.size());
+
+  auto test_packet = TestGetTotalNumItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), inv_scope_status_packet);
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, getterTest) {
+  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_now_playing);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(GetTotalNumberOfItemsRequestTest, invalidTest) {
+  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());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03};
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/pass_through_packet_test.cc b/packet/tests/avrcp/pass_through_packet_test.cc
new file mode 100644
index 0000000..5ea749f
--- /dev/null
+++ b/packet/tests/avrcp/pass_through_packet_test.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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "pass_through_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestPassThroughPacket = TestPacketType<PassThroughPacket>;
+
+TEST(PassThroughPacketBuilderTest, builderTest) {
+  auto builder = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44);
+  ASSERT_EQ(builder->size(), pass_through_command_play_pushed.size());
+  auto test_packet = TestPassThroughPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), pass_through_command_play_pushed);
+
+  builder = PassThroughPacketBuilder::MakeBuilder(true, false, 0x44);
+  ASSERT_EQ(builder->size(), pass_through_command_play_released.size());
+  test_packet = TestPassThroughPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), pass_through_command_play_released);
+}
+
+TEST(PassThroughPacketTest, getterTest) {
+  auto test_packet =
+      TestPassThroughPacket::Make(pass_through_command_play_pushed);
+  ASSERT_EQ(test_packet->GetKeyState(), KeyState::PUSHED);
+  ASSERT_EQ(test_packet->GetOperationId(), 0x44);
+
+  test_packet = TestPassThroughPacket::Make(pass_through_command_play_released);
+  ASSERT_EQ(test_packet->GetKeyState(), KeyState::RELEASED);
+  ASSERT_EQ(test_packet->GetOperationId(), 0x44);
+}
+
+TEST(PassThroughPacketTest, validTest) {
+  auto test_packet =
+      TestPassThroughPacket::Make(pass_through_command_play_pushed);
+  ASSERT_TRUE(test_packet->IsValid());
+
+  test_packet = TestPassThroughPacket::Make(pass_through_command_play_released);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(PassThroughPacketTest, invalidTest) {
+  std::vector<uint8_t> packet_copy = pass_through_command_play_pushed;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestPassThroughPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0, 1, 2, 3, 4, 5};
+  test_packet = TestPassThroughPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/play_item_packet_test.cc b/packet/tests/avrcp/play_item_packet_test.cc
new file mode 100644
index 0000000..f2e48aa
--- /dev/null
+++ b/packet/tests/avrcp/play_item_packet_test.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "play_item.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestPlayItemReqPacket = TestPacketType<PlayItemRequest>;
+
+TEST(PlayItemResponseBuilderTest, builderTest) {
+  auto builder = PlayItemResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  ASSERT_EQ(builder->size(), play_item_response.size());
+
+  auto test_packet = TestPlayItemReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), play_item_response);
+}
+
+TEST(PlayItemResponseTest, getterTest) {
+  auto test_packet = TestPlayItemReqPacket::Make(play_item_request);
+
+  ASSERT_EQ(test_packet->GetScope(), Scope::NOW_PLAYING);
+  ASSERT_EQ(test_packet->GetUid(), 0x0000000000000003u);
+  ASSERT_EQ(test_packet->GetUidCounter(), 0x0000u);
+}
+
+TEST(PlayItemResponseTest, validTest) {
+  auto test_packet = TestPlayItemReqPacket::Make(play_item_request);
+
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(PlayItemResponseTest, invalidTest) {
+  auto packet_copy = play_item_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestPlayItemReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestPlayItemReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/tests/avrcp/register_notification_packet_test.cc b/packet/tests/avrcp/register_notification_packet_test.cc
new file mode 100644
index 0000000..abc0951
--- /dev/null
+++ b/packet/tests/avrcp/register_notification_packet_test.cc
@@ -0,0 +1,171 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "register_notification_packet.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestRegNotifReqPacket = TestPacketType<RegisterNotificationRequest>;
+using TestRegNotifRspPacket = TestPacketType<RegisterNotificationResponse>;
+
+TEST(RegisterNotificationRequestTest, getterTest) {
+  auto test_packet =
+      TestRegNotifReqPacket::Make(register_play_status_notification);
+
+  ASSERT_EQ(test_packet->GetEventRegistered(), Event::PLAYBACK_STATUS_CHANGED);
+  ASSERT_EQ(test_packet->GetInterval(), 5u);
+}
+
+TEST(RegisterNotificationRequestTest, validTest) {
+  auto test_packet =
+      TestRegNotifReqPacket::Make(register_play_status_notification);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(RegisterNotificationRequestTest, invalidTest) {
+  std::vector<uint8_t> packet_copy = register_play_status_notification;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestRegNotifReqPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0, 1, 2, 3, 4};
+  test_packet = TestRegNotifReqPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+TEST(RegisterNotificationRequestBuilderTest, builderTest) {
+  auto builder =
+      RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
+  ASSERT_EQ(builder->size(), register_volume_changed_notification.size());
+
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), register_volume_changed_notification);
+}
+
+TEST(RegisterNotificationResponseTest, volumeGetterTest) {
+  auto test_packet =
+      TestRegNotifRspPacket::Make(interim_volume_changed_notification);
+
+  ASSERT_TRUE(test_packet->IsInterim());
+  ASSERT_EQ(test_packet->GetEvent(), Event::VOLUME_CHANGED);
+  ASSERT_EQ(test_packet->GetVolume(), 0x47);
+}
+
+TEST(RegisterNotificationResponseTest, validTest) {
+  auto test_packet =
+      TestRegNotifRspPacket::Make(interim_volume_changed_notification);
+
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(RegisterNotificationResponseTest, invalidTest) {
+  std::vector<uint8_t> packet_copy = interim_volume_changed_notification;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestRegNotifRspPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0, 1, 2, 3, 4};
+  test_packet = TestRegNotifRspPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  auto wrong_ctype = interim_volume_changed_notification;
+  wrong_ctype[0] = 0x00;
+  test_packet = TestRegNotifRspPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+TEST(RegisterNotificationResponseTest, wrongEventDeathTest) {
+  auto wrong_event = interim_volume_changed_notification;
+  wrong_event[10] = 0x00;
+  auto test_packet = TestRegNotifRspPacket::Make(wrong_event);
+
+  ASSERT_DEATH(test_packet->GetVolume(),
+               "GetEvent\\(\\) == Event::VOLUME_CHANGED");
+}
+
+TEST(RegisterNotificationResponseBuilderTest, playStatusBuilderTest) {
+  auto builder = RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+      true, 0x00);
+  ASSERT_EQ(builder->size(), interim_play_status_notification.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), interim_play_status_notification);
+}
+
+TEST(RegisterNotificationResponseBuilderTest, trackChangedBuilderTest) {
+  auto builder = RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
+      true, 0x0000000000000000);
+  ASSERT_EQ(builder->size(), interim_track_changed_notification.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), interim_track_changed_notification);
+}
+
+TEST(RegisterNotificationResponseBuilderTest, playPositionBuilderTest) {
+  auto builder =
+      RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
+          false, 0x00000000);
+  ASSERT_EQ(builder->size(), changed_play_pos_notification.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), changed_play_pos_notification);
+}
+
+TEST(RegisterNotificationResponseBuilderTest, nowPlayingBuilderTest) {
+  auto builder =
+      RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(true);
+  ASSERT_EQ(builder->size(), interim_now_playing_notification.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), interim_now_playing_notification);
+}
+
+TEST(RegisterNotificationResponseBuilderTest, availablePlayersBuilderTest) {
+  auto builder =
+      RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(true);
+  ASSERT_EQ(builder->size(), interim_available_players_notification.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), interim_available_players_notification);
+}
+
+TEST(RegisterNotificationResponseBuilderTest, addressedPlayerBuilderTest) {
+  auto builder =
+      RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(true, 1,
+                                                                      0x0000);
+  ASSERT_EQ(builder->size(), interim_addressed_player_notification.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), interim_addressed_player_notification);
+}
+
+TEST(RegisterNotificationResponseBuilderTest, uidsChangedBuilderTest) {
+  auto builder =
+      RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(true, 0x0000);
+  ASSERT_EQ(builder->size(), interim_uids_notificaiton.size());
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), interim_uids_notificaiton);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/tests/avrcp/set_absolute_volume_packet_test.cc b/packet/tests/avrcp/set_absolute_volume_packet_test.cc
new file mode 100644
index 0000000..8be462e
--- /dev/null
+++ b/packet/tests/avrcp/set_absolute_volume_packet_test.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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "set_absolute_volume.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestSetVolumeRspPacket = TestPacketType<SetAbsoluteVolumeResponse>;
+
+TEST(SetAbsoluteVolumeRequestBuilderTest, builderTest) {
+  auto builder = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x48);
+  ASSERT_EQ(builder->size(), set_absolute_volume_request.size());
+
+  auto test_packet = TestSetVolumeRspPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_absolute_volume_request);
+}
+
+// Test whether the volume field has the highest bit masked
+TEST(SetAbsoluteVolumeRequestBuilderTest, volumeMaskTest) {
+  auto builder = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0xc8);
+  auto test_packet = TestSetVolumeRspPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_absolute_volume_request);
+}
+
+TEST(SetAbsoluteVolumeResponseTest, getterTest) {
+  auto test_packet = TestSetVolumeRspPacket::Make(set_absolute_volume_response);
+
+  ASSERT_EQ(test_packet->GetVolume(), 0x43);
+}
+
+TEST(SetAbsoluteVolumeResponseTest, validTest) {
+  auto test_packet = TestSetVolumeRspPacket::Make(set_absolute_volume_response);
+
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(SetAbsoluteVolumeResponseTest, invalidTest) {
+  auto packet_copy = set_absolute_volume_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestSetVolumeRspPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestSetVolumeRspPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  auto wrong_ctype = set_absolute_volume_request;
+  wrong_ctype[0] = 0x00;
+  test_packet = TestSetVolumeRspPacket::Make(wrong_ctype);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/set_addressed_player_packet_test.cc b/packet/tests/avrcp/set_addressed_player_packet_test.cc
new file mode 100644
index 0000000..a6ced9e
--- /dev/null
+++ b/packet/tests/avrcp/set_addressed_player_packet_test.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "set_addressed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestSetAddrPlayerPacket = TestPacketType<SetAddressedPlayerRequest>;
+
+TEST(SetAddressedPlayerResponseBuilderTest, builderTest) {
+  auto builder =
+      SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  ASSERT_EQ(builder->size(), set_addressed_player_response.size());
+
+  auto test_packet = TestSetAddrPlayerPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_addressed_player_response);
+}
+
+TEST(SetAddressedPlayerRequestTest, getterTest) {
+  auto test_packet =
+      TestSetAddrPlayerPacket::Make(set_addressed_player_request);
+
+  ASSERT_EQ(test_packet->GetPlayerId(), 0x0000u);
+}
+
+TEST(SetAddressedPlayerRequestTest, validTest) {
+  auto test_packet =
+      TestSetAddrPlayerPacket::Make(set_addressed_player_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(SetAddressedPlayerRequestTest, invalidTest) {
+  auto packet_copy = set_addressed_player_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestSetAddrPlayerPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestSetAddrPlayerPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/packet/tests/avrcp/set_browsed_player_packet_test.cc b/packet/tests/avrcp/set_browsed_player_packet_test.cc
new file mode 100644
index 0000000..828df18
--- /dev/null
+++ b/packet/tests/avrcp/set_browsed_player_packet_test.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 <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "set_browsed_player.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestSetBrowsedPlayerPacket = TestPacketType<SetBrowsedPlayerRequest>;
+
+TEST(SetBrowsedPlayerResponseBuilder, builderTest) {
+  auto builder = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR,
+                                                              0x0000, 4, 0, "");
+  ASSERT_EQ(builder->size(), set_browsed_player_response.size());
+
+  auto test_packet = TestSetBrowsedPlayerPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_browsed_player_response);
+}
+
+TEST(SetBrowsedPlayerResponseBuilder, errorStatusTest) {
+  std::vector<uint8_t> player_not_browsable_status = {0x70, 0x00, 0x01, 0x12};
+  auto builder = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+      Status::PLAYER_NOT_BROWSABLE, 0x1234, 5, 6, "Field Not Used");
+  ASSERT_EQ(builder->size(), player_not_browsable_status.size());
+
+  auto test_packet = TestSetBrowsedPlayerPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), player_not_browsable_status);
+}
+
+TEST(SetBrowsedPlayerRequestTest, getterTest) {
+  auto test_packet =
+      TestSetBrowsedPlayerPacket::Make(set_browsed_player_request);
+
+  ASSERT_EQ(test_packet->GetPlayerId(), 0x0002u);
+}
+
+TEST(SetBrowsedPlayerRequestTest, validTest) {
+  auto test_packet =
+      TestSetBrowsedPlayerPacket::Make(set_browsed_player_request);
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(SetBrowsedPlayerRequestTest, invalidTest) {
+  auto packet_copy = set_browsed_player_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestSetBrowsedPlayerPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestSetBrowsedPlayerPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/avrcp/vendor_packet_test.cc b/packet/tests/avrcp/vendor_packet_test.cc
new file mode 100644
index 0000000..e933824
--- /dev/null
+++ b/packet/tests/avrcp/vendor_packet_test.cc
@@ -0,0 +1,140 @@
+/*
+ * 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 <tuple>
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "vendor_packet.h"
+
+namespace bluetooth {
+
+// A helper class that has public accessors to protected methods
+class TestPacketBuilder : public PacketBuilder {
+ public:
+  static std::unique_ptr<TestPacketBuilder> MakeBuilder(
+      std::vector<uint8_t> data) {
+    std::unique_ptr<TestPacketBuilder> builder(new TestPacketBuilder(data));
+    return builder;
+  };
+
+  // Make all the utility functions public
+  using PacketBuilder::ReserveSpace;
+  using PacketBuilder::AddPayloadOctets1;
+  using PacketBuilder::AddPayloadOctets2;
+  using PacketBuilder::AddPayloadOctets3;
+  using PacketBuilder::AddPayloadOctets4;
+  using PacketBuilder::AddPayloadOctets6;
+  using PacketBuilder::AddPayloadOctets8;
+
+  size_t size() const override { return data_.size(); };
+
+  bool Serialize(const std::shared_ptr<Packet>& pkt) override {
+    ReserveSpace(pkt, size());
+
+    for (uint8_t byte : data_) {
+      AddPayloadOctets1(pkt, byte);
+    }
+
+    return true;
+  }
+
+  TestPacketBuilder(std::vector<uint8_t> data) : data_(data){};
+
+  std::vector<uint8_t> data_;
+};
+
+namespace avrcp {
+
+using TestVendorPacket = TestPacketType<VendorPacket>;
+
+TEST(VendorPacketBuilderTest, builderTest) {
+  std::vector<uint8_t> get_cap_payload_data = {0x03};
+
+  auto get_cap_payload = TestPacketBuilder::MakeBuilder(get_cap_payload_data);
+
+  auto builder = VendorPacketBuilder::MakeBuilder(
+      CType::STATUS, CommandPdu::GET_CAPABILITIES, PacketType::SINGLE,
+      std::move(get_cap_payload));
+
+  ASSERT_EQ(builder->size(), get_capabilities_request.size());
+
+  auto test_packet = TestVendorPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_capabilities_request);
+}
+
+using TestParam = std::tuple<std::vector<uint8_t>, CommandPdu>;
+class VendorPacketTest : public ::testing::TestWithParam<TestParam> {
+ public:
+  std::vector<uint8_t> GetPacketData() { return std::get<0>(GetParam()); }
+  CommandPdu GetCommandPdu() { return std::get<1>(GetParam()); }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    VendorPacketParameterTest, VendorPacketTest,
+    ::testing::Values(
+        std::make_tuple(get_capabilities_request, CommandPdu::GET_CAPABILITIES),
+        std::make_tuple(get_capabilities_response_company_id,
+                        CommandPdu::GET_CAPABILITIES),
+        std::make_tuple(get_capabilities_response_events_supported,
+                        CommandPdu::GET_CAPABILITIES),
+        std::make_tuple(get_element_attributes_request_partial,
+                        CommandPdu::GET_ELEMENT_ATTRIBUTES),
+        std::make_tuple(get_element_attributes_request_full,
+                        CommandPdu::GET_ELEMENT_ATTRIBUTES),
+        std::make_tuple(get_elements_attributes_response_full,
+                        CommandPdu::GET_ELEMENT_ATTRIBUTES),
+        std::make_tuple(get_play_status_request, CommandPdu::GET_PLAY_STATUS),
+        std::make_tuple(get_play_status_response, CommandPdu::GET_PLAY_STATUS),
+        std::make_tuple(register_play_status_notification,
+                        CommandPdu::REGISTER_NOTIFICATION),
+        std::make_tuple(interim_play_status_notification,
+                        CommandPdu::REGISTER_NOTIFICATION),
+        std::make_tuple(interim_track_changed_notification,
+                        CommandPdu::REGISTER_NOTIFICATION),
+        std::make_tuple(changed_play_pos_notification,
+                        CommandPdu::REGISTER_NOTIFICATION)));
+
+TEST_P(VendorPacketTest, getterTest) {
+  auto test_packet = TestVendorPacket::Make(GetPacketData());
+
+  ASSERT_EQ(test_packet->GetCompanyId(), BLUETOOTH_COMPANY_ID);
+  ASSERT_EQ(test_packet->GetCommandPdu(), GetCommandPdu());
+  ASSERT_EQ(test_packet->GetPacketType(), PacketType::SINGLE);
+  // ASSERT_EQ(test_packet->GetParameterLength(), 0x01);
+}
+
+TEST_P(VendorPacketTest, validTest) {
+  auto test_packet = TestVendorPacket::Make(GetPacketData());
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST_F(VendorPacketTest, invalidTest) {
+  auto get_capabilities_request_copy = get_capabilities_request;
+  get_capabilities_request_copy.push_back(0x00);
+  auto test_packet = TestVendorPacket::Make(get_capabilities_request_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x01, 0x02, 0x03, 0x04, 0x05};
+  test_packet = TestVendorPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/base/iterator_test.cc b/packet/tests/base/iterator_test.cc
new file mode 100644
index 0000000..5794686
--- /dev/null
+++ b/packet/tests/base/iterator_test.cc
@@ -0,0 +1,276 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <memory>
+
+#include "packet.h"
+#include "packet_test_common.h"
+#include "test_packets.h"
+
+namespace bluetooth {
+
+using pair = std::pair<size_t, size_t>;
+
+class IteratorTest
+    : public ::testing::TestWithParam<std::pair<size_t, size_t>> {
+ public:
+  std::shared_ptr<TestPacket> GetTestPacket() {
+    auto bounds = GetParam();
+    auto lower_bound = bounds.first;
+    auto upper_bound = bounds.second;
+
+    return TestPacket::Make(test_l2cap_data, lower_bound, upper_bound);
+  }
+
+  size_t GetTestPacketLength() { return GetParam().second - GetParam().first; }
+
+  size_t GetLowerBound() { return GetParam().first; }
+
+  size_t GetUpperBound() { return GetParam().second; }
+};
+
+INSTANTIATE_TEST_CASE_P(IteratorParameterTest, IteratorTest,
+                        ::testing::Values(pair(0, test_l2cap_data.size()),
+                                          pair(3, test_l2cap_data.size() - 2)));
+
+TEST_F(IteratorTest, iteratorCreateDeathTest) {
+  auto packet =
+      TestPacket::Make(test_l2cap_data, 3, test_l2cap_data.size() - 2);
+  ASSERT_DEATH(Iterator(packet, 0), "index_ >= packet->packet_start_index_");
+  ASSERT_DEATH(Iterator(packet, test_l2cap_data.size()),
+               "index_ <= packet->packet_end_index_");
+}
+
+TEST_F(IteratorTest, extractTest) {
+  auto packet = TestPacket::Make(test_l2cap_data);
+  Iterator general_case = packet->begin();
+
+  ASSERT_EQ(0x02u, general_case.extract<uint8_t>());
+  ASSERT_EQ(0x2edcu, general_case.extract<uint16_t>());
+  ASSERT_EQ(0x00620066u, general_case.extract<uint32_t>());
+  ASSERT_EQ(0x00010000000a0013u, general_case.extract<uint64_t>());
+}
+
+TEST_P(IteratorTest, payloadBoundsTest) {
+  auto packet = GetTestPacket();
+  ASSERT_EQ(static_cast<size_t>(packet->end() - packet->begin()),
+            GetTestPacketLength());
+
+  auto it = packet->begin();
+  for (size_t i = 0; i < GetTestPacketLength(); i++) {
+    ASSERT_EQ(test_l2cap_data[i + GetLowerBound()], *it++);
+  }
+}
+
+TEST_P(IteratorTest, extractBoundsDeathTest) {
+  auto packet = GetTestPacket();
+  Iterator bounds_test = packet->end();
+  ASSERT_DEATH(bounds_test.extract<uint8_t>(),
+               "index_ != packet_->packet_end_index_");
+  ASSERT_DEATH(bounds_test.extract<uint16_t>(),
+               "index_ != packet_->packet_end_index_");
+  ASSERT_DEATH(bounds_test.extract<uint32_t>(),
+               "index_ != packet_->packet_end_index_");
+  ASSERT_DEATH(bounds_test.extract<uint64_t>(),
+               "index_ != packet_->packet_end_index_");
+}
+
+TEST_P(IteratorTest, dereferenceDeathTest) {
+  auto packet = GetTestPacket();
+  Iterator dereference_test = packet->end();
+
+  ASSERT_EQ((*packet)[GetTestPacketLength() - 1],
+            *(dereference_test - static_cast<size_t>(1)));
+  ASSERT_DEATH(*dereference_test, "index_ != packet_->packet_end_index_");
+}
+
+TEST_P(IteratorTest, plusEqTest) {
+  auto packet = GetTestPacket();
+  Iterator plus_eq = packet->begin();
+  for (size_t i = 0; i < GetTestPacketLength(); i += 2) {
+    ASSERT_EQ(test_l2cap_data[i + GetLowerBound()], *plus_eq)
+        << "+= test: Dereferenced iterator does not equal expected at index "
+        << i;
+    plus_eq += 2;
+  }
+
+  ASSERT_EQ(plus_eq, packet->end());
+}
+
+TEST_P(IteratorTest, preIncrementTest) {
+  auto packet = GetTestPacket();
+  Iterator plus_plus = packet->begin();
+  for (size_t i = 0; i < GetTestPacketLength() - 1; i++) {
+    ASSERT_EQ(test_l2cap_data[i + GetLowerBound() + 1], *(++plus_plus))
+        << "Pre-increment test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_P(IteratorTest, postIncrementTest) {
+  auto packet = GetTestPacket();
+  Iterator plus_plus = packet->begin();
+  for (size_t i = 0; i < GetTestPacketLength(); i++) {
+    ASSERT_EQ(test_l2cap_data[i + GetLowerBound()], *(plus_plus++))
+        << "Post-increment test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_P(IteratorTest, additionTest) {
+  auto packet = GetTestPacket();
+  Iterator plus = packet->begin();
+  for (size_t i = 0; i < GetTestPacketLength(); i++) {
+    ASSERT_EQ(test_l2cap_data[i + GetLowerBound()], *plus)
+        << "+ test: Dereferenced iterator does not equal expected at index "
+        << i;
+    plus = plus + static_cast<size_t>(1);
+  }
+}
+
+TEST_P(IteratorTest, minusEqTest) {
+  auto packet = GetTestPacket();
+  Iterator minus_eq = packet->end();
+  minus_eq -= 1;
+  for (int i = GetTestPacketLength() - 1; i > 0; i -= 2) {
+    ASSERT_EQ(test_l2cap_data[static_cast<size_t>(i) + GetLowerBound()],
+              *minus_eq)
+        << "-= test: Dereferenced iterator does not equal expected at index "
+        << i;
+    minus_eq -= 2;
+  }
+}
+
+TEST_P(IteratorTest, preDecrementTest) {
+  auto packet = GetTestPacket();
+  Iterator minus_minus = packet->end();
+  for (int i = GetTestPacketLength(); i > 0; i--) {
+    ASSERT_EQ(test_l2cap_data[static_cast<size_t>(i) + GetLowerBound() - 1],
+              *(--minus_minus))
+        << "Pre-decrement test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_P(IteratorTest, postDecrementTest) {
+  auto packet = GetTestPacket();
+  Iterator minus_minus = packet->end();
+  minus_minus--;
+  for (int i = GetTestPacketLength() - 1; i > 0; i--) {
+    ASSERT_EQ(test_l2cap_data[static_cast<size_t>(i) + GetLowerBound()],
+              *(minus_minus--))
+        << "Post-decrement test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_P(IteratorTest, subtractionTest) {
+  auto packet = GetTestPacket();
+  Iterator minus = packet->end();
+  minus = minus - static_cast<size_t>(1);
+  for (int i = GetTestPacketLength() - 1; i > 0; i--) {
+    ASSERT_EQ(test_l2cap_data[static_cast<size_t>(i) + GetLowerBound()], *minus)
+        << "- test: Dereferenced iterator does not equal expected at index "
+        << i;
+    minus = minus - static_cast<size_t>(1);
+  }
+}
+
+TEST_P(IteratorTest, plusEqBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator plus_eq = packet->end();
+  for (size_t i = 0; i < 100; i++) {
+    plus_eq += i;
+    ASSERT_EQ(packet->end(), plus_eq)
+        << "+= test: Iterator exceeded the upper bound set by get_length()";
+  }
+}
+
+TEST_P(IteratorTest, preIncrementBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator plus_plus = packet->end();
+  plus_plus--;
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(packet->end(), ++plus_plus)
+        << "Pre-increment test: Iterator exceeded the upper bound set "
+           "by get_length()";
+  }
+}
+
+TEST_P(IteratorTest, postIncrementBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator plus_plus = packet->end();
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(packet->end(), plus_plus++)
+        << "Post-increment test: Iterator exceeded the upper bound set "
+           "by get_length()";
+  }
+}
+
+TEST_P(IteratorTest, additionBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator plus = packet->end();
+  for (size_t i = 0; i < 100; i++) {
+    plus = plus + static_cast<size_t>(i);
+    ASSERT_EQ(packet->end(), plus)
+        << "+ test: Iterator exceeded the upper bound set by get_length()";
+  }
+}
+
+TEST_P(IteratorTest, minusEqBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator minus_eq = packet->begin();
+  for (size_t i = 0; i < 100; i++) {
+    minus_eq -= i;
+    ASSERT_EQ(test_l2cap_data[GetLowerBound()], *minus_eq)
+        << "-= test: Iterator is less than the lower bound set by "
+           "packet->begin()";
+  }
+}
+
+TEST_P(IteratorTest, preDecrementBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator minus_minus = packet->begin();
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(test_l2cap_data[GetLowerBound()], *(--minus_minus))
+        << "Pre-decrement test: Iterator is less than the lower bound set by "
+           "packet->begin()";
+  }
+}
+
+TEST_P(IteratorTest, postDecrementBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator minus_minus = packet->begin();
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(test_l2cap_data[GetLowerBound()], *(minus_minus--))
+        << "Post-decrement test: Iterator is less than the lower bound set by "
+           "packet->begin()";
+  }
+}
+
+TEST_P(IteratorTest, subtractionBoundsTest) {
+  auto packet = GetTestPacket();
+  Iterator minus = packet->begin();
+  for (size_t i = 0; i < 100; i++) {
+    minus = minus - static_cast<size_t>(i);
+    ASSERT_EQ(test_l2cap_data[GetLowerBound()], *minus)
+        << "- test: Iterator is less than the lower bound set "
+           "by packet->begin()";
+  }
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/base/packet_builder_test.cc b/packet/tests/base/packet_builder_test.cc
new file mode 100644
index 0000000..c057606
--- /dev/null
+++ b/packet/tests/base/packet_builder_test.cc
@@ -0,0 +1,71 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <memory>
+
+#include "packet.h"
+#include "packet_test_common.h"
+#include "test_packets.h"
+
+using std::vector;
+
+namespace bluetooth {
+
+TEST(PacketBuilderTest, serializeTest) {
+  auto builder = TestPacketBuilder::MakeBuilder(test_l2cap_data);
+  auto packet = TestPacket::Make();
+
+  builder->Serialize(packet);
+
+  for (size_t i = 0; i < test_l2cap_data.size(); i++) {
+    ASSERT_EQ(test_l2cap_data[i], (*packet)[i]);
+  }
+}
+
+TEST(PacketBuilderTest, sizeTest) {
+  auto builder = TestPacketBuilder::MakeBuilder(test_l2cap_data);
+
+  ASSERT_EQ(builder->size(), test_l2cap_data.size());
+}
+
+TEST(PacketBuilderTest, reserveSpaceTest) {
+  auto packet = TestPacket::Make();
+  ASSERT_EQ(packet->GetData().capacity(), 0u);
+
+  auto builder = TestPacketBuilder::MakeBuilder(test_l2cap_data);
+  builder->ReserveSpace(packet, test_l2cap_data.size());
+
+  ASSERT_GE(packet->GetData().capacity(), test_l2cap_data.size());
+}
+
+TEST(PacketBuilderTest, addPayloadOctetsTest) {
+  auto builder = TestPacketBuilder::MakeBuilder(test_l2cap_data);
+  auto packet = TestPacket::Make();
+
+  builder->AddPayloadOctets1(packet, 0x01u);
+  builder->AddPayloadOctets2(packet, 0x0302u);
+  builder->AddPayloadOctets3(packet, 0x060504u);
+  builder->AddPayloadOctets4(packet, 0x0A090807u);
+  builder->AddPayloadOctets6(packet, 0x100F0E0D0C0Bu);
+  builder->AddPayloadOctets8(packet, 0x1817161514131211u);
+
+  for (size_t i = 0; i < 0x18; i++) {
+    ASSERT_EQ((*packet)[i], i + 1);
+  }
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/base/packet_test.cc b/packet/tests/base/packet_test.cc
new file mode 100644
index 0000000..2c4c147
--- /dev/null
+++ b/packet/tests/base/packet_test.cc
@@ -0,0 +1,122 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "packet.h"
+#include "packet_test_common.h"
+#include "test_packets.h"
+
+namespace bluetooth {
+
+// Test making a packet from another packet. The new packet should have the
+// same payload bounds as the old packet.
+TEST(PacketTest, newPacketFromPacketTest) {
+  // Create a packet with payload bounds
+  auto packet = TestPacket::Make(
+      test_avctp_data, test_avctp_data_payload_offset, test_avctp_data.size());
+
+  // Create packet from bounded packet
+  auto new_packet = TestPacket::Make(packet);
+
+  // Check to see if the new packet is bounded by the payload of the old packet
+  auto it = new_packet->begin();
+  for (size_t i = 0; i < test_avrcp_data.size(); i++) {
+    ASSERT_EQ(test_avrcp_data[i], *it++);
+  }
+}
+
+// Test that the correct payload length is returned
+TEST(PacketTest, sizeTest) {
+  auto packet = TestPacket::Make(test_avctp_data);
+  ASSERT_EQ(packet->size(), test_avctp_data.size());
+
+  packet = TestPacket::Make(test_avctp_data, test_avctp_data_payload_offset,
+                            test_avctp_data.size());
+  ASSERT_EQ(packet->size(), test_avrcp_data.size());
+}
+
+// Test the array access operator
+TEST(PacketTest, arrayAccessTest) {
+  auto packet = TestPacket::Make(test_l2cap_data);
+  for (size_t i = 0; i < test_l2cap_data.size(); i++) {
+    ASSERT_EQ(test_l2cap_data[i], (*packet)[i]);
+  }
+
+  packet = TestPacket::Make(test_avctp_data, test_avctp_data_payload_offset,
+                            test_avctp_data.size());
+  for (size_t i = 0; i < test_avrcp_data.size(); i++) {
+    ASSERT_EQ(test_avrcp_data[i], (*packet)[i]);
+  }
+}
+
+// Test that accessing past the end of the defined payload dies
+TEST(PacketTest, arrayAccessDeathTest) {
+  auto packet =
+      TestPacket::Make(test_l2cap_data, 3, test_l2cap_data.size() - 2);
+  ASSERT_DEATH((*packet)[test_l2cap_data.size()], "");
+}
+
+// Test that the iterator and array access operator return the same data
+TEST(PacketTest, iteratorTest) {
+  auto packet = TestPacket::Make(
+      test_avctp_data, test_avctp_data_payload_offset, test_avctp_data.size());
+
+  // Check to see if the data matches
+  auto it = packet->begin();
+  for (size_t i = 0; i < packet->size(); i++) {
+    ASSERT_EQ((*packet)[i], *it++);
+  }
+
+  // Check to see if the iterator points to the end of the data
+  ASSERT_EQ(it, packet->end());
+}
+
+class ChildTestPacket : public TestPacket {
+ public:
+  using TestPacket::TestPacket;
+
+  std::string ToString() const override { return "ChildTestPacket"; };
+};
+
+// Test specializing a packet to another packet type
+TEST(PacketTest, specializeTest) {
+  auto packet = TestPacket::Make(test_l2cap_data);
+
+  std::shared_ptr<ChildTestPacket> specialized_packet =
+      Packet::Specialize<ChildTestPacket>(packet);
+
+  // Test that the new packet is an instance of ChildTestPacket
+  ASSERT_EQ(specialized_packet->ToString(), "ChildTestPacket");
+
+  // Test that the underlying data is the same and no copy took place
+  ASSERT_EQ(&specialized_packet->GetData(), &packet->GetData());
+}
+
+// Test that when the packet goes out of scope, that the underlying memory is
+// freed
+TEST(PacketTest, memoryFreeTest) {
+  auto packet = TestPacket::Make(test_l2cap_data);
+  std::weak_ptr<std::vector<uint8_t>> data_ptr(packet->GetDataPointer());
+
+  ASSERT_FALSE(data_ptr.expired());
+
+  packet.reset();
+
+  ASSERT_TRUE(data_ptr.expired());
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/base/packet_test_common.h b/packet/tests/base/packet_test_common.h
new file mode 100644
index 0000000..26302ef
--- /dev/null
+++ b/packet/tests/base/packet_test_common.h
@@ -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.
+ */
+
+#pragma once
+
+#include "packet.h"
+#include "packet_test_helper.h"
+
+// We have our own definition of loghex to avoid dependencies
+namespace {
+template <typename T>
+std::string loghex(T x) {
+  std::stringstream tmp;
+  tmp << "0x" << std::internal << std::hex << std::setfill('0')
+      << std::setw(sizeof(T) * 2) << (unsigned int)x;
+  return tmp.str();
+}
+}  // namespace
+
+namespace bluetooth {
+
+class PacketImpl : public Packet {
+ public:
+  using Packet::Packet;  // Inherit constructors
+
+  virtual bool IsValid() const { return true; }
+
+  virtual std::string ToString() const {
+    std::stringstream ss;
+    ss << "TestPacket: Start = " << packet_start_index_
+       << " : End = " << packet_end_index_ << std::endl;
+    ss << "  â”” Payload =";
+    for (auto it = begin(); it != end(); it++) {
+      ss << " " << loghex(*it);
+    }
+    ss << std::endl;
+
+    return ss.str();
+  };
+
+  virtual std::pair<size_t, size_t> GetPayloadIndecies() const {
+    return std::pair<size_t, size_t>(packet_start_index_, packet_end_index_);
+  }
+};
+
+using TestPacket = TestPacketType<PacketImpl>;
+
+// A helper class that has public accessors to protected methods
+class TestPacketBuilder : public PacketBuilder {
+ public:
+  static std::unique_ptr<TestPacketBuilder> MakeBuilder(
+      std::vector<uint8_t> data) {
+    std::unique_ptr<TestPacketBuilder> builder(new TestPacketBuilder(data));
+    return builder;
+  };
+
+  // Make all the utility functions public
+  using PacketBuilder::ReserveSpace;
+  using PacketBuilder::AddPayloadOctets1;
+  using PacketBuilder::AddPayloadOctets2;
+  using PacketBuilder::AddPayloadOctets3;
+  using PacketBuilder::AddPayloadOctets4;
+  using PacketBuilder::AddPayloadOctets6;
+  using PacketBuilder::AddPayloadOctets8;
+
+  size_t size() const override { return data_.size(); };
+
+  bool Serialize(const std::shared_ptr<Packet>& pkt) override {
+    ReserveSpace(pkt, size());
+
+    for (uint8_t byte : data_) {
+      AddPayloadOctets1(pkt, byte);
+    }
+
+    return true;
+  }
+
+  TestPacketBuilder(std::vector<uint8_t> data) : data_(data){};
+
+  std::vector<uint8_t> data_;
+};
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/packet_test_helper.h b/packet/tests/packet_test_helper.h
new file mode 100644
index 0000000..ad3db2c
--- /dev/null
+++ b/packet/tests/packet_test_helper.h
@@ -0,0 +1,66 @@
+/*
+ * 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 <memory>
+
+#include "packet.h"
+
+namespace bluetooth {
+
+// A helper templated class to access the protected members of Packet to make
+// testing easier
+template <class PacketType>
+class TestPacketType : public PacketType {
+ public:
+  using PacketType::PacketType;
+
+  static std::shared_ptr<TestPacketType<PacketType>> Make() {
+    return std::shared_ptr<TestPacketType<PacketType>>(
+        new TestPacketType<PacketType>());
+  }
+
+  static std::shared_ptr<TestPacketType<PacketType>> Make(
+      std::shared_ptr<Packet> packet) {
+    return std::shared_ptr<TestPacketType<PacketType>>(
+        new TestPacketType<PacketType>(packet));
+  }
+
+  static std::shared_ptr<TestPacketType<PacketType>> Make(
+      std::vector<uint8_t> payload) {
+    size_t end = payload.size();
+    return Make(std::move(payload), 0, end);
+  }
+
+  static std::shared_ptr<TestPacketType<PacketType>> Make(
+      std::vector<uint8_t> payload, size_t start, size_t end) {
+    auto pkt = std::shared_ptr<TestPacketType<PacketType>>(
+        new TestPacketType<PacketType>());
+    pkt->packet_start_index_ = start;
+    pkt->packet_end_index_ = end;
+    pkt->data_ = std::make_shared<std::vector<uint8_t>>(std::move(payload));
+    return pkt;
+  }
+
+  const std::vector<uint8_t>& GetData() { return *PacketType::data_; }
+
+  std::shared_ptr<std::vector<uint8_t>> GetDataPointer() {
+    return PacketType::data_;
+  }
+};
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/tests/test_packets.h b/packet/tests/test_packets.h
new file mode 100644
index 0000000..0e0db42
--- /dev/null
+++ b/packet/tests/test_packets.h
@@ -0,0 +1,50 @@
+#pragma once
+
+namespace {
+
+// L2CAP packet pulled from Wireshark
+std::vector<uint8_t> test_l2cap_data = {
+    0x02, 0xdc, 0x2e, 0x66, 0x00, 0x62, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x00,
+    0x00, 0x01, 0x00, 0xb8, 0x9c, 0x00, 0x80, 0x56, 0x00, 0x43, 0xc4, 0x9a,
+    0x86, 0x36, 0x10, 0x00, 0x26, 0x43, 0x1c, 0x9b, 0x88, 0x1d, 0x06, 0x03,
+    0x26, 0x86, 0x36, 0x10, 0x00, 0x26, 0x43, 0xb4, 0x9b, 0x88, 0x1d, 0x06,
+    0x03, 0x26, 0x86, 0x36, 0x10, 0x00, 0x26, 0x43, 0xe4, 0x9b, 0x88, 0x1d,
+    0x06, 0x03, 0x26, 0x86, 0x36, 0x10, 0x00, 0x26, 0x43, 0xf8, 0x9b, 0x88,
+    0x1d, 0x06, 0x03, 0x26, 0x86, 0x36, 0x10, 0x00, 0x26, 0x43, 0x08, 0x9c,
+    0x88, 0x1d, 0x06, 0x03, 0x26, 0x86, 0x36, 0x10, 0x00, 0x26, 0x43, 0xa8,
+    0x9c, 0x88, 0x1d, 0x06, 0x03, 0x26, 0x86, 0x36, 0x10, 0x00, 0x26};
+
+// AVCTP packet pulled from Wireshark
+std::vector<uint8_t> test_avctp_data = {
+    0xf2, 0x11, 0x0e, 0x0c, 0x48, 0x00, 0x00, 0x19, 0x58, 0x20, 0x00, 0x00,
+    0x85, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x00, 0x22, 0x57, 0x61,
+    0x72, 0x20, 0x50, 0x69, 0x67, 0x73, 0x20, 0x28, 0x32, 0x30, 0x30, 0x39,
+    0x20, 0x52, 0x65, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20,
+    0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x6a, 0x00, 0x0d, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x20, 0x53, 0x61,
+    0x62, 0x62, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, 0x00,
+    0x17, 0x54, 0x68, 0x65, 0x20, 0x55, 0x6c, 0x74, 0x69, 0x6d, 0x61, 0x74,
+    0x65, 0x20, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+    0x00, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+    0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6a, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x07, 0x00, 0x6a, 0x00, 0x06, 0x34, 0x37, 0x33, 0x30,
+    0x30, 0x30};
+
+// An avrcp packet pulled from wireshark. This data is the payload of
+// test_avctp_packet
+size_t test_avctp_data_payload_offset = 3;
+std::vector<uint8_t> test_avrcp_data = {
+    0x0c, 0x48, 0x00, 0x00, 0x19, 0x58, 0x20, 0x00, 0x00, 0x85, 0x07, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x6a, 0x00, 0x22, 0x57, 0x61, 0x72, 0x20, 0x50,
+    0x69, 0x67, 0x73, 0x20, 0x28, 0x32, 0x30, 0x30, 0x39, 0x20, 0x52, 0x65,
+    0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x56, 0x65, 0x72,
+    0x73, 0x69, 0x6f, 0x6e, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6a, 0x00,
+    0x0d, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x20, 0x53, 0x61, 0x62, 0x62, 0x61,
+    0x74, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, 0x00, 0x17, 0x54, 0x68,
+    0x65, 0x20, 0x55, 0x6c, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x20, 0x43,
+    0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x6a, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x6a, 0x00, 0x06, 0x34, 0x37, 0x33, 0x30, 0x30, 0x30};
+
+}  // namespace
\ No newline at end of file
diff --git a/profile/avrcp/Android.bp b/profile/avrcp/Android.bp
new file mode 100644
index 0000000..1e27861
--- /dev/null
+++ b/profile/avrcp/Android.bp
@@ -0,0 +1,48 @@
+cc_library_static {
+    name: "avrcp-target-service",
+    defaults: ["fluoride_defaults"],
+    host_supported: true,
+    include_dirs: [
+        "system/bt",
+        "system/bt/btcore/include",
+        "system/bt/internal_include",
+        "system/bt/stack/include",
+    ],
+    export_include_dirs: ["./"],
+    srcs: [
+        "connection_handler.cc",
+        "device.cc",
+    ],
+    static_libs: [
+        "lib-bt-packets",
+        "libbluetooth-types",
+        "libosi",
+    ],
+}
+
+cc_test {
+    name: "net_test_avrcp",
+    defaults: ["fluoride_defaults"],
+    host_supported: true,
+    include_dirs: [
+        "system/bt",
+        "system/bt/btcore/include",
+        "system/bt/internal_include",
+        "system/bt/stack/include",
+    ],
+    srcs: [
+        "tests/avrcp_connection_handler_test.cc",
+        "tests/avrcp_device_test.cc",
+    ],
+    static_libs: [
+        "libgmock",
+        "lib-bt-packets",
+        "libosi",
+        "avrcp-target-service",
+    ],
+    sanitize: {
+        cfi: false,
+    },
+
+    cflags: ["-DBUILDCFG"],
+}
diff --git a/profile/avrcp/avrcp_internal.h b/profile/avrcp/avrcp_internal.h
new file mode 100644
index 0000000..c2e6549
--- /dev/null
+++ b/profile/avrcp/avrcp_internal.h
@@ -0,0 +1,87 @@
+/*
+ * 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 "stack/include/avrc_api.h"
+#include "stack/include/sdp_api.h"
+
+/**
+ * Wrapper classes for the API functions currently defined in "system/bt/stack".
+ * ConnectionHandler and AvrcpDevice both use this interface to manage AVRCP
+ * SDP, connections, and packets. We use these intermediate interfaces instead
+ * of calling the functions directly in order to make mocking and testing
+ * easier.
+ */
+// TODO (apanicke): Update the api's in "system/bt/stack" so that no wrapper is
+// required
+class AvrcpInterface {
+ public:
+  virtual uint16_t AddRecord(uint16_t service_uuid, const char* p_service_name,
+                             const char* p_provider_name, uint16_t categories,
+                             uint32_t sdp_handle, bool browse_supported,
+                             uint16_t profile_version) = 0;
+
+  virtual uint16_t FindService(uint16_t service_uuid, const RawAddress& bd_addr,
+                               tAVRC_SDP_DB_PARAMS* p_db,
+                               tAVRC_FIND_CBACK p_cback) = 0;
+
+  virtual uint16_t Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb,
+                        const RawAddress& bd_addr) = 0;
+
+  virtual uint16_t OpenBrowse(uint8_t handle, uint8_t conn_role) = 0;
+
+  virtual uint16_t GetPeerMtu(uint8_t handle) = 0;
+
+  virtual uint16_t GetBrowseMtu(uint8_t handle) = 0;
+
+  virtual uint16_t Close(uint8_t handle) = 0;
+
+  virtual uint16_t CloseBrowse(uint8_t handle) = 0;
+
+  virtual uint16_t MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
+                          BT_HDR* p_pkt) = 0;
+
+  virtual ~AvrcpInterface() = default;
+};
+
+class SdpInterface {
+ public:
+  virtual bool InitDiscoveryDb(tSDP_DISCOVERY_DB* a, uint32_t b, uint16_t c,
+                               const bluetooth::Uuid* d, uint16_t e,
+                               uint16_t* f) = 0;
+
+  virtual bool ServiceSearchAttributeRequest(const RawAddress& a,
+                                             tSDP_DISCOVERY_DB* b,
+                                             tSDP_DISC_CMPL_CB* c) = 0;
+
+  virtual tSDP_DISC_REC* FindServiceInDb(tSDP_DISCOVERY_DB* a, uint16_t b,
+                                         t_sdp_disc_rec* c) = 0;
+
+  virtual tSDP_DISC_ATTR* FindAttributeInRec(t_sdp_disc_rec* a, uint16_t b) = 0;
+
+  virtual bool FindProfileVersionInRec(t_sdp_disc_rec* a, uint16_t b,
+                                       uint16_t* c) = 0;
+
+  virtual ~SdpInterface() = default;
+};
+
+class A2dpInterface {
+ public:
+  virtual RawAddress active_peer() = 0;
+
+  virtual ~A2dpInterface() = default;
+};
\ No newline at end of file
diff --git a/profile/avrcp/avrcp_message_converter.h b/profile/avrcp/avrcp_message_converter.h
new file mode 100644
index 0000000..389a497
--- /dev/null
+++ b/profile/avrcp/avrcp_message_converter.h
@@ -0,0 +1,106 @@
+/*
+ * 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 <iostream>
+#include <vector>
+
+#include "avrcp_packet.h"
+
+// These classes are temporary placeholders to easily switch between BT_HDR and
+// packets.
+class VectorPacket : public ::bluetooth::Packet {
+ public:
+  using Packet::Packet;  // Inherit constructors
+
+  static std::shared_ptr<VectorPacket> Make() {
+    return std::shared_ptr<VectorPacket>(new VectorPacket());
+  };
+
+  static std::shared_ptr<VectorPacket> Make(std::vector<uint8_t> payload) {
+    auto pkt = VectorPacket::Make();
+    pkt->packet_start_index_ = 0;
+    pkt->packet_end_index_ = payload.size();
+    pkt->data_ = std::make_shared<std::vector<uint8_t>>(std::move(payload));
+    return pkt;
+  };
+
+  const std::vector<uint8_t>& GetData() { return *data_; };
+
+  virtual std::string ToString() const {
+    std::stringstream ss;
+    ss << "VectorPacket:" << std::endl;
+    ss << "  â”” Payload =";
+    for (auto it = begin(); it != end(); it++) {
+      ss << " " << loghex(*it);
+    }
+    ss << std::endl;
+
+    return ss.str();
+  };
+
+  virtual std::pair<size_t, size_t> GetPayloadIndecies() const override {
+    return std::pair<size_t, size_t>(packet_start_index_, packet_end_index_);
+  }
+
+  virtual bool IsValid() const override { return true; }
+};
+
+// TODO (apanicke): When deleting the old AVRCP Stack, remove this class and
+// instead create a BT_HDR Parsing packet.
+class AvrcpMessageConverter {
+ public:
+  static std::shared_ptr<::bluetooth::Packet> Parse(tAVRC_MSG* m) {
+    std::vector<uint8_t> data;
+
+    switch (m->hdr.opcode) {
+      case AVRC_OP_VENDOR: {
+        tAVRC_MSG_VENDOR* msg = (tAVRC_MSG_VENDOR*)m;
+        data.push_back(m->hdr.ctype);
+        data.push_back((m->hdr.subunit_type << 3) | m->hdr.subunit_id);
+        data.push_back(m->hdr.opcode);
+        for (int i = 2; i >= 0; i--) {
+          data.push_back((uint8_t)((msg->company_id >> i * 8) & 0xff));
+        }
+        for (uint8_t i = 0; i < msg->vendor_len; i++) {
+          data.push_back(msg->p_vendor_data[i]);
+        }
+      } break;
+      case AVRC_OP_PASS_THRU: {
+        tAVRC_MSG_PASS* msg = (tAVRC_MSG_PASS*)m;
+        data.push_back(m->hdr.ctype);
+        data.push_back((m->hdr.subunit_type << 3) | m->hdr.subunit_id);
+        data.push_back(m->hdr.opcode);
+        data.push_back((msg->state << 7) | msg->op_id);
+        data.push_back(0x00);
+      } break;
+      case AVRC_OP_BROWSE: {
+        tAVRC_MSG_BROWSE* msg = (tAVRC_MSG_BROWSE*)m;
+        // The first 3 bytes are header bytes that aren't actually in AVRCP
+        // packets
+        for (int i = 0; i < msg->browse_len; i++) {
+          data.push_back(msg->p_browse_data[i]);
+        }
+      } break;
+      default:
+        LOG(ERROR) << "Unknown opcode for AVRCP message";
+        break;
+    }
+
+    return VectorPacket::Make(data);
+  }
+};
\ No newline at end of file
diff --git a/profile/avrcp/connection_handler.cc b/profile/avrcp/connection_handler.cc
new file mode 100644
index 0000000..874bf77
--- /dev/null
+++ b/profile/avrcp/connection_handler.cc
@@ -0,0 +1,522 @@
+/*
+ * 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 "connection_handler.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <map>
+
+#include "avrc_defs.h"
+#include "avrcp_message_converter.h"
+#include "avrcp_packet.h"
+#include "bt_types.h"
+#include "btu.h"
+// TODO (apanicke): Remove dependency on this header once we cleanup feature
+// handling.
+#include "bta/include/bta_av_api.h"
+#include "osi/include/allocator.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+ConnectionHandler* ConnectionHandler::instance_ = nullptr;
+
+ConnectionHandler* ConnectionHandler::Get() {
+  CHECK(instance_);
+
+  return instance_;
+}
+
+bool ConnectionHandler::Initialize(const ConnectionCallback& callback,
+                                   AvrcpInterface* avrcp, SdpInterface* sdp,
+                                   VolumeInterface* vol) {
+  CHECK(instance_ == nullptr);
+  CHECK(avrcp != nullptr);
+  CHECK(sdp != nullptr);
+
+  // TODO (apanicke): When transitioning to using this service, implement
+  // SDP Initialization for AVRCP Here.
+  instance_ = new ConnectionHandler();
+  instance_->connection_cb_ = callback;
+  instance_->avrc_ = avrcp;
+  instance_->sdp_ = sdp;
+  instance_->vol_ = vol;
+
+  // Set up the AVRCP acceptor connection
+  if (!instance_->AvrcpConnect(false, RawAddress::kAny)) {
+    instance_->CleanUp();
+    return false;
+  }
+
+  return true;
+}
+
+bool ConnectionHandler::CleanUp() {
+  CHECK(instance_ != nullptr);
+
+  // TODO (apanicke): Cleanup the SDP Entries here
+  for (const auto& entry : instance_->device_map_) {
+    entry.second->DeviceDisconnected();
+    instance_->avrc_->Close(entry.first);
+  }
+  instance_->device_map_.clear();
+  instance_->feature_map_.clear();
+
+  instance_->weak_ptr_factory_.InvalidateWeakPtrs();
+
+  delete instance_;
+  instance_ = nullptr;
+
+  return true;
+}
+
+void ConnectionHandler::InitForTesting(ConnectionHandler* handler) {
+  CHECK(instance_ == nullptr);
+  instance_ = handler;
+}
+
+bool ConnectionHandler::ConnectDevice(const RawAddress& bdaddr) {
+  LOG(INFO) << "Attempting to connect to device " << bdaddr;
+
+  for (const auto& pair : device_map_) {
+    if (bdaddr == pair.second->GetAddress()) {
+      LOG(WARNING) << "Already connected to device with address " << bdaddr;
+      return false;
+    }
+  }
+
+  auto connection_lambda = [](ConnectionHandler* instance_,
+                              const RawAddress& bdaddr, uint16_t status,
+                              uint16_t version, uint16_t features) {
+    LOG(INFO) << __PRETTY_FUNCTION__
+              << " SDP Completed features=" << loghex(features);
+    if (status != AVRC_SUCCESS || !(features & BTA_AV_FEAT_RCCT)) {
+      LOG(ERROR) << "Failed to do SDP: status=" << loghex(status)
+                 << " features=" << loghex(features)
+                 << " supports controller: " << (features & BTA_AV_FEAT_RCCT);
+      instance_->connection_cb_.Run(std::shared_ptr<Device>());
+    }
+
+    instance_->feature_map_.emplace(bdaddr, features);
+    instance_->AvrcpConnect(true, bdaddr);
+    return;
+  };
+
+  return SdpLookup(bdaddr, base::Bind(connection_lambda, this, bdaddr));
+}
+
+bool ConnectionHandler::DisconnectDevice(const RawAddress& bdaddr) {
+  for (auto it = device_map_.begin(); it != device_map_.end(); it++) {
+    if (bdaddr == it->second->GetAddress()) {
+      it->second->DeviceDisconnected();
+      uint8_t handle = it->first;
+      device_map_.erase(handle);
+      return avrc_->Close(handle) == AVRC_SUCCESS;
+    }
+  }
+
+  return false;
+}
+
+std::vector<std::shared_ptr<Device>> ConnectionHandler::GetListOfDevices()
+    const {
+  std::vector<std::shared_ptr<Device>> list;
+  for (auto device : device_map_) {
+    list.push_back(device.second);
+  }
+  return list;
+}
+
+bool ConnectionHandler::SdpLookup(const RawAddress& bdaddr, SdpCallback cb) {
+  LOG(INFO) << __PRETTY_FUNCTION__;
+
+  tAVRC_SDP_DB_PARAMS db_params;
+  // TODO (apanicke): This needs to be replaced with smarter memory management.
+  tSDP_DISCOVERY_DB* disc_db =
+      (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+  uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+                          ATTR_ID_BT_PROFILE_DESC_LIST,
+                          ATTR_ID_SUPPORTED_FEATURES};
+
+  db_params.db_len =
+      BT_DEFAULT_BUFFER_SIZE;  // Some magic number found in the AVRCP code
+  db_params.num_attr = sizeof(attr_list) / sizeof(attr_list[0]);
+  db_params.p_db = disc_db;
+  db_params.p_attrs = attr_list;
+
+  return avrc_->FindService(
+             UUID_SERVCLASS_AV_REMOTE_CONTROL, bdaddr, &db_params,
+             base::Bind(&ConnectionHandler::SdpCb, base::Unretained(this),
+                        bdaddr, cb, disc_db)) == AVRC_SUCCESS;
+}
+
+bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) {
+  LOG(INFO) << "Connect to device " << bdaddr.ToString();
+
+  tAVRC_CONN_CB open_cb;
+  if (initiator) {
+    open_cb.ctrl_cback = base::Bind(&ConnectionHandler::InitiatorControlCb,
+                                    weak_ptr_factory_.GetWeakPtr());
+  } else {
+    open_cb.ctrl_cback = base::Bind(&ConnectionHandler::AcceptorControlCb,
+                                    weak_ptr_factory_.GetWeakPtr());
+  }
+  open_cb.msg_cback =
+      base::Bind(&ConnectionHandler::MessageCb, base::Unretained(this));
+  open_cb.company_id = AVRC_CO_GOOGLE;
+  open_cb.conn = initiator ? AVRC_CONN_INT
+                           : AVRC_CONN_ACP;  // 0 if initiator, 1 if acceptor
+  // TODO (apanicke): We shouldn't need RCCT to do absolute volume. The current
+  // AVRC_API requires it though.
+  open_cb.control = BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA;
+
+  uint8_t handle = 0;
+  uint16_t status = avrc_->Open(&handle, &open_cb, bdaddr);
+  LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
+            << " status= " << loghex(status);
+  return status == AVRC_SUCCESS;
+}
+
+void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event,
+                                           uint16_t result,
+                                           const RawAddress* peer_addr) {
+  DCHECK(!connection_cb_.is_null());
+
+  LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
+            << " result=" << loghex(result)
+            << " addr=" << (peer_addr ? peer_addr->ToString() : "none");
+
+  switch (event) {
+    case AVRC_OPEN_IND_EVT: {
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
+
+      const auto& feature_iter = feature_map_.find(*peer_addr);
+      if (feature_iter == feature_map_.end()) {
+        LOG(ERROR) << "Features do not exist even though SDP should have been "
+                      "done first";
+        return;
+      }
+
+      bool supports_browsing = feature_iter->second & BTA_AV_FEAT_BROWSE;
+
+      if (supports_browsing) {
+        avrc_->OpenBrowse(handle, AVCT_INT);
+      }
+
+      // TODO (apanicke): Implement a system to cache SDP entries. For most
+      // devices SDP is completed after the device connects AVRCP so that
+      // information isn't very useful when trying to control our
+      // capabilities. For now always use AVRCP 1.6.
+      auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
+                                   base::Unretained(this), 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>(
+          *peer_addr, !supports_browsing, callback, ctrl_mtu, browse_mtu);
+
+      device_map_[handle] = newDevice;
+      // TODO (apanicke): Create the device with all of the interfaces it
+      // needs. Return the new device where the service will register the
+      // interfaces it needs.
+      connection_cb_.Run(newDevice);
+
+      if (feature_iter->second & BTA_AV_FEAT_ADV_CTRL) {
+        newDevice->RegisterVolumeChanged();
+      } else if (instance_->vol_ != nullptr) {
+        instance_->vol_->DeviceConnected(newDevice->GetAddress());
+      }
+
+    } break;
+
+    case AVRC_CLOSE_IND_EVT: {
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Closed Event";
+
+      if (device_map_.find(handle) == device_map_.end()) {
+        LOG(WARNING)
+            << "Connection Close received from device that doesn't exist";
+        return;
+      }
+      avrc_->Close(handle);
+      feature_map_.erase(device_map_[handle]->GetAddress());
+      device_map_[handle]->DeviceDisconnected();
+      device_map_.erase(handle);
+    } break;
+
+    case AVRC_BROWSE_OPEN_IND_EVT:
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
+      // NOTE (apanicke): We don't need to explicitly handle this message
+      // since the AVCTP Layer will still send us browsing messages
+      // regardless. It would be useful to note this though for future
+      // compatibility issues.
+      break;
+    case AVRC_BROWSE_CLOSE_IND_EVT:
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
+      break;
+    default:
+      LOG(ERROR) << "Unknown AVRCP Control event";
+      break;
+  }
+}
+
+void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event,
+                                          uint16_t result,
+                                          const RawAddress* peer_addr) {
+  DCHECK(!connection_cb_.is_null());
+
+  LOG(INFO) << __PRETTY_FUNCTION__ << ": handle=" << loghex(handle)
+            << " result=" << loghex(result)
+            << " addr=" << (peer_addr ? peer_addr->ToString() : "none");
+
+  switch (event) {
+    case AVRC_OPEN_IND_EVT: {
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
+
+      auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
+                                   base::Unretained(this), 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>(
+          *peer_addr, false, callback, ctrl_mtu, browse_mtu);
+
+      device_map_[handle] = newDevice;
+      connection_cb_.Run(newDevice);
+
+      LOG(INFO) << __PRETTY_FUNCTION__
+                << ": Performing SDP on connected device. address="
+                << peer_addr->ToString();
+      auto sdp_lambda = [](ConnectionHandler* instance_, uint8_t handle,
+                           uint16_t status, uint16_t version,
+                           uint16_t features) {
+        if (instance_->device_map_.find(handle) ==
+            instance_->device_map_.end()) {
+          LOG(WARNING) << __PRETTY_FUNCTION__
+                       << ": No device found for handle: " << loghex(handle);
+          return;
+        }
+
+        auto device = instance_->device_map_[handle];
+        instance_->feature_map_.emplace(device->GetAddress(), features);
+
+        // TODO (apanicke): Report to the VolumeInterface that a new Device is
+        // connected that doesn't support absolute volume.
+        if (features & BTA_AV_FEAT_ADV_CTRL) {
+          device->RegisterVolumeChanged();
+        } else if (instance_->vol_ != nullptr) {
+          instance_->vol_->DeviceConnected(device->GetAddress());
+        }
+      };
+
+      SdpLookup(*peer_addr, base::Bind(sdp_lambda, this, handle));
+
+      avrc_->OpenBrowse(handle, AVCT_ACP);
+      AvrcpConnect(false, RawAddress::kAny);
+    } break;
+
+    case AVRC_CLOSE_IND_EVT: {
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Closed Event";
+
+      if (device_map_.find(handle) == device_map_.end()) {
+        LOG(WARNING)
+            << "Connection Close received from device that doesn't exist";
+        return;
+      }
+      avrc_->Close(handle);
+      feature_map_.erase(device_map_[handle]->GetAddress());
+      device_map_[handle]->DeviceDisconnected();
+      device_map_.erase(handle);
+    } break;
+
+    case AVRC_BROWSE_OPEN_IND_EVT:
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
+      // NOTE (apanicke): We don't need to explicitly handle this message
+      // since the AVCTP Layer will still send us browsing messages
+      // regardless. It would be useful to note this though for future
+      // compatibility issues.
+      break;
+    case AVRC_BROWSE_CLOSE_IND_EVT:
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
+      break;
+    default:
+      LOG(ERROR) << "Unknown AVRCP Control event";
+      break;
+  }
+}
+
+void ConnectionHandler::MessageCb(uint8_t handle, uint8_t label, uint8_t opcode,
+                                  tAVRC_MSG* p_msg) {
+  if (device_map_[handle] == nullptr) {
+    LOG(ERROR) << "Message received for unconnected device: handle="
+               << loghex(handle);
+    return;
+  }
+
+  auto pkt = AvrcpMessageConverter::Parse(p_msg);
+
+  if (opcode == AVRC_OP_BROWSE) {
+    VLOG(4) << "Browse Message received on handle " << (unsigned int)handle;
+    device_map_[handle]->BrowseMessageReceived(label, BrowsePacket::Parse(pkt));
+    return;
+  }
+
+  VLOG(4) << "Message received on handle " << (unsigned int)handle;
+  device_map_[handle]->MessageReceived(label, Packet::Parse(pkt));
+}
+
+void ConnectionHandler::SdpCb(const RawAddress& bdaddr, SdpCallback cb,
+                              tSDP_DISCOVERY_DB* disc_db, uint16_t status) {
+  LOG(INFO) << __PRETTY_FUNCTION__ << ": SDP lookup callback received";
+
+  if (status != AVRC_SUCCESS) {
+    LOG(ERROR) << __PRETTY_FUNCTION__
+               << ": SDP Failure: status = " << (unsigned int)status;
+    cb.Run(status, 0, 0);
+    osi_free(disc_db);
+    return;
+  }
+
+  // Check the peer features
+  tSDP_DISC_REC* sdp_record = nullptr;
+  uint16_t peer_features = 0;
+  uint16_t peer_avrcp_version = 0;
+
+  // TODO (apanicke): Replace this in favor of our own supported features.
+  sdp_record =
+      sdp_->FindServiceInDb(disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, nullptr);
+  if (sdp_record != nullptr) {
+    LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+              << " supports remote control";
+    peer_features |= BTA_AV_FEAT_RCCT;
+
+    if ((sdp_->FindAttributeInRec(sdp_record, ATTR_ID_BT_PROFILE_DESC_LIST)) !=
+        NULL) {
+      /* get profile version (if failure, version parameter is not updated) */
+      sdp_->FindProfileVersionInRec(
+          sdp_record, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_avrcp_version);
+      LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+                << " peer avrcp version=" << loghex(peer_avrcp_version);
+
+      if (peer_avrcp_version >= AVRC_REV_1_3) {
+        // These are the standard features, another way to check this is to
+        // search for CAT1 on the remote device
+        LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+                  << " supports metadata";
+        peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+      }
+      if (peer_avrcp_version >= AVRC_REV_1_4) {
+        /* get supported categories */
+        LOG(INFO) << __PRETTY_FUNCTION__ << " Get Supported categories";
+        tSDP_DISC_ATTR* sdp_attribute =
+            sdp_->FindAttributeInRec(sdp_record, ATTR_ID_SUPPORTED_FEATURES);
+        if (sdp_attribute != NULL) {
+          LOG(INFO) << __PRETTY_FUNCTION__
+                    << "Get Supported categories SDP ATTRIBUTES != null";
+          uint16_t categories = sdp_attribute->attr_value.v.u16;
+          if (categories & AVRC_SUPF_CT_CAT2) {
+            LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+                      << " supports advanced control";
+            peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+          }
+          if (categories & AVRC_SUPF_CT_BROWSE) {
+            LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+                      << " supports browsing";
+            peer_features |= (BTA_AV_FEAT_BROWSE);
+          }
+        }
+      }
+    }
+  }
+
+  sdp_record = sdp_->FindServiceInDb(disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+                                     nullptr);
+  if (sdp_record != nullptr) {
+    LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+              << " supports remote control target";
+
+    uint16_t peer_avrcp_target_version = 0;
+    sdp_->FindProfileVersionInRec(sdp_record, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+                                  &peer_avrcp_target_version);
+    LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+              << " peer avrcp target version="
+              << loghex(peer_avrcp_target_version);
+
+    if ((sdp_->FindAttributeInRec(sdp_record, ATTR_ID_BT_PROFILE_DESC_LIST)) !=
+        NULL) {
+      if (peer_avrcp_target_version >= AVRC_REV_1_4) {
+        /* get supported categories */
+        LOG(INFO) << __PRETTY_FUNCTION__ << " Get Supported categories";
+        tSDP_DISC_ATTR* sdp_attribute =
+            sdp_->FindAttributeInRec(sdp_record, ATTR_ID_SUPPORTED_FEATURES);
+        if (sdp_attribute != NULL) {
+          LOG(INFO) << __PRETTY_FUNCTION__
+                    << "Get Supported categories SDP ATTRIBUTES != null";
+          uint16_t categories = sdp_attribute->attr_value.v.u16;
+          if (categories & AVRC_SUPF_CT_CAT2) {
+            LOG(INFO) << __PRETTY_FUNCTION__ << ": Device " << bdaddr.ToString()
+                      << " supports advanced control";
+            peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+          }
+        }
+      }
+    }
+  }
+
+  osi_free(disc_db);
+
+  cb.Run(status, peer_avrcp_version, peer_features);
+}
+
+void ConnectionHandler::SendMessage(
+    uint8_t handle, uint8_t label, bool browse,
+    std::unique_ptr<::bluetooth::PacketBuilder> message) {
+  std::shared_ptr<::bluetooth::Packet> packet = VectorPacket::Make();
+  message->Serialize(packet);
+
+  uint8_t ctype = AVRC_RSP_ACCEPT;
+  if (!browse) {
+    ctype =
+        (uint8_t)(::bluetooth::Packet::Specialize<Packet>(packet)->GetCType());
+  }
+
+  DLOG(INFO) << "SendMessage to handle=" << loghex(handle);
+
+  BT_HDR* pkt = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+
+  pkt->offset = AVCT_MSG_OFFSET;
+  // TODO (apanicke): Update this constant. Currently this is a unique event
+  // used to tell the AVRCP API layer that the data is properly formatted and
+  // doesn't need to be processed. In the future, this is the only place sending
+  // the packet so none of these layer specific fields will be used.
+  pkt->event = 0xFFFF;
+
+  // TODO (apanicke): This layer specific stuff can go away once we move over
+  // to the new service.
+  pkt->layer_specific = AVCT_DATA_CTRL;
+  if (browse) {
+    pkt->layer_specific = AVCT_DATA_BROWSE;
+  }
+
+  pkt->len = packet->size();
+  uint8_t* p_data = (uint8_t*)(pkt + 1) + pkt->offset;
+  for (auto it = packet->begin(); it != packet->end(); it++) {
+    *p_data++ = *it;
+  }
+
+  avrc_->MsgReq(handle, label, ctype, pkt);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/profile/avrcp/connection_handler.h b/profile/avrcp/connection_handler.h
new file mode 100644
index 0000000..63bc8a0
--- /dev/null
+++ b/profile/avrcp/connection_handler.h
@@ -0,0 +1,164 @@
+/*
+ * 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 <base/bind.h>
+#include <base/memory/weak_ptr.h>
+#include <map>
+#include <memory>
+
+#include "avrcp_internal.h"
+#include "avrcp_packet.h"
+#include "device.h"
+#include "packet.h"
+#include "raw_address.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+// TODO: Remove the singleton design structure for this class.
+// AvrcpTargetService is already a singleton and can manage the lifetime of this
+// object. multiple singleton objects can lead to code that is hard to test and
+// have hard to debug lifetimes.
+
+// TODO (apanicke): Use a device factory instead of just the constructor in
+// order to create device objects. This will allow us to create specific device
+// classes that can provide interop fixes for certain badly behaving devices.
+
+/**
+ * ConnectionHandler handles SDP, connecting to remote AVRCP devices
+ * and multiplexing/delivering messages to devices.
+ */
+class ConnectionHandler {
+ public:
+  /**
+   * This callback is used to return a new device after a connection attempt.
+   * A reference to the new Avrcp device is located in the shared_ptr.
+   * If there was an issue during connection the pointer value will be null.
+   */
+  using ConnectionCallback = base::Callback<void(std::shared_ptr<Device>)>;
+
+  /**
+   * Initializes the singleton instance and sets up SDP. Also Opens the
+   * AVRCP Acceptor to receive connection requests from a remote device.
+   *
+   * Params:
+   * callback - A callback that gets called any time a new AVRCP Device
+   *            is connected. Will return nullpointer if a device fails
+   *            to connect via ConnectDevice();
+   *
+   * TODO: Add message loop to determine which thread events are posted to
+   */
+  static bool Initialize(const ConnectionCallback& callback,
+                         AvrcpInterface* avrcp, SdpInterface* sdp,
+                         VolumeInterface* vol);
+
+  /**
+   * Clears the singleton and tears down SDP
+   */
+  static bool CleanUp();
+
+  /**
+   * Get the singleton instance of Connection Handler
+   */
+  static ConnectionHandler* Get();
+
+  /**
+   * Attempt to connect AVRCP on a device. The callback will be called with
+   * either a smart pointer pointing to the connected AVRCP device or null
+   * if the connection failed.
+   *
+   * The order of operations for this function is as follows.
+   *   1. Perform SDP on remote device
+   *   2. Connect the AVCTP Channel
+   *   2. (Optional) If supported connect the AVCTP Browse channel
+   *   4. Call the provided callback with the new
+   *
+   * Params:
+   * bdaddr - Bluetooth address of device to connect to
+   * callback - The function that gets called when a connection succeeds or
+   *            fails. The pointer being cleared implies that the connection
+   *            failed.
+   *
+   * Returns:
+   * true if the connection attempt starts, false if there are no resources to
+   * connect AVRCP
+   */
+  virtual bool ConnectDevice(const RawAddress& bdaddr);
+
+  /**
+   * Disconnects AVRCP from a device that was successfully connected too using
+   * ConnectionHandler::ConnectDevice
+   *
+   * Returns:
+   * true if the AVRCP was successfully disconnected for the device or false
+   * if the device was already disconnected or in an invalid state
+   */
+  virtual bool DisconnectDevice(const RawAddress& bdaddr);
+
+  virtual std::vector<std::shared_ptr<Device>> GetListOfDevices() const;
+
+  /**
+   * Provide a custom ConnectionHandler that will be returned by Get().
+   * Initialize and CleanUp should not be called as the owner of the handler
+   * determines its lifetime.
+   */
+  static void InitForTesting(ConnectionHandler* handler);
+
+ private:
+  AvrcpInterface* avrc_;
+  SdpInterface* sdp_;
+  VolumeInterface* vol_;
+
+  ConnectionCallback connection_cb_;
+
+  std::map<uint8_t, std::shared_ptr<Device>> device_map_;
+  // TODO (apanicke): Replace the features with a class that has individual
+  // fields.
+  std::map<RawAddress, uint16_t> feature_map_;
+
+  static ConnectionHandler* instance_;
+
+  using SdpCallback = base::Callback<void(uint16_t status, uint16_t version,
+                                          uint16_t features)>;
+  virtual bool SdpLookup(const RawAddress& bdaddr, SdpCallback cb);
+  void SdpCb(const RawAddress& bdaddr, SdpCallback cb,
+             tSDP_DISCOVERY_DB* disc_db, uint16_t status);
+
+  virtual bool AvrcpConnect(bool initiator, const RawAddress& bdaddr);
+
+  // Callbacks when connecting to a device
+  void InitiatorControlCb(uint8_t handle, uint8_t event, uint16_t result,
+                          const RawAddress* peer_addr);
+  void AcceptorControlCb(uint8_t handle, uint8_t event, uint16_t result,
+                         const RawAddress* peer_addr);
+  void MessageCb(uint8_t handle, uint8_t label, uint8_t opcode,
+                 tAVRC_MSG* p_msg);
+
+  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
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
new file mode 100644
index 0000000..9a31ef3
--- /dev/null
+++ b/profile/avrcp/device.cc
@@ -0,0 +1,1308 @@
+/*
+ * 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>
+
+#include "connection_handler.h"
+#include "device.h"
+#include "stack_config.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+#define DEVICE_LOG(LEVEL) LOG(LEVEL) << address_.ToString() << " : "
+#define DEVICE_VLOG(LEVEL) VLOG(LEVEL) << address_.ToString() << " : "
+
+#define VOL_NOT_SUPPORTED -1
+#define VOL_REGISTRATION_FAILED -2
+
+Device::Device(
+    const RawAddress& bdaddr, bool avrcp13_compatibility,
+    base::Callback<void(uint8_t label, bool browse,
+                        std::unique_ptr<::bluetooth::PacketBuilder> message)>
+        send_msg_cb,
+    uint16_t ctrl_mtu, uint16_t browse_mtu)
+    : weak_ptr_factory_(this),
+      address_(bdaddr),
+      avrcp13_compatibility_(avrcp13_compatibility),
+      send_message_cb_(send_msg_cb),
+      ctrl_mtu_(ctrl_mtu),
+      browse_mtu_(browse_mtu) {}
+
+void Device::RegisterInterfaces(MediaInterface* media_interface,
+                                A2dpInterface* a2dp_interface,
+                                VolumeInterface* volume_interface) {
+  CHECK(media_interface);
+  CHECK(a2dp_interface);
+  a2dp_interface_ = a2dp_interface;
+  media_interface_ = media_interface;
+  volume_interface_ = volume_interface;
+}
+
+bool Device::IsActive() const {
+  return address_ == a2dp_interface_->active_peer();
+}
+
+void Device::VendorPacketHandler(uint8_t label,
+                                 std::shared_ptr<VendorPacket> pkt) {
+  CHECK(media_interface_);
+  DEVICE_VLOG(3) << __func__ << ": pdu=" << pkt->GetCommandPdu();
+
+  // All CTypes at and above NOT_IMPLEMENTED are all response types.
+  if (pkt->GetCType() == CType::NOT_IMPLEMENTED) {
+    return;
+  }
+
+  if (pkt->GetCType() >= CType::ACCEPTED) {
+    switch (pkt->GetCommandPdu()) {
+      // VOLUME_CHANGED is the only notification we register for while target.
+      case CommandPdu::REGISTER_NOTIFICATION: {
+        auto register_notification =
+            Packet::Specialize<RegisterNotificationResponse>(pkt);
+        if (register_notification->GetEvent() != Event::VOLUME_CHANGED) {
+          DEVICE_LOG(WARNING)
+              << __func__ << ": Unhandled register notification received: "
+              << register_notification->GetEvent();
+          return;
+        }
+        HandleVolumeChanged(label, register_notification);
+        break;
+      }
+      case CommandPdu::SET_ABSOLUTE_VOLUME:
+        // TODO (apanicke): Add a retry mechanism if the response has a
+        // different volume than the one we set. For now, we don't care
+        // about the response to this message.
+        break;
+      default:
+        DEVICE_LOG(WARNING)
+            << __func__ << ": Unhandled Response: pdu=" << pkt->GetCommandPdu();
+        break;
+    }
+    return;
+  }
+
+  switch (pkt->GetCommandPdu()) {
+    case CommandPdu::GET_CAPABILITIES: {
+      HandleGetCapabilities(label,
+                            Packet::Specialize<GetCapabilitiesRequest>(pkt));
+    } break;
+
+    case CommandPdu::REGISTER_NOTIFICATION: {
+      HandleNotification(label,
+                         Packet::Specialize<RegisterNotificationRequest>(pkt));
+    } break;
+
+    case CommandPdu::GET_ELEMENT_ATTRIBUTES: {
+      media_interface_->GetSongInfo(base::Bind(
+          &Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(),
+          label, Packet::Specialize<GetElementAttributesRequest>(pkt)));
+    } break;
+
+    case CommandPdu::GET_PLAY_STATUS: {
+      media_interface_->GetPlayStatus(base::Bind(&Device::GetPlayStatusResponse,
+                                                 weak_ptr_factory_.GetWeakPtr(),
+                                                 label));
+    } break;
+
+    case CommandPdu::PLAY_ITEM: {
+      HandlePlayItem(label, Packet::Specialize<PlayItemRequest>(pkt));
+    } break;
+
+    case CommandPdu::SET_ADDRESSED_PLAYER: {
+      // TODO (apanicke): Implement set addressed player. We don't need
+      // this currently since the current implementation only has one
+      // player and the player will never change, but we need it for a
+      // more complete implementation.
+      media_interface_->GetMediaPlayerList(base::Bind(
+          &Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(),
+          label, Packet::Specialize<SetAddressedPlayerRequest>(pkt)));
+    } break;
+
+    default: {
+      DEVICE_LOG(ERROR) << "Unhandled Vendor Packet: " << pkt->ToString();
+      auto response = RejectBuilder::MakeBuilder(
+          (CommandPdu)pkt->GetCommandPdu(), Status::INVALID_COMMAND);
+      send_message(label, false, std::move(response));
+    } break;
+  }
+}
+
+void Device::HandleGetCapabilities(
+    uint8_t label, const std::shared_ptr<GetCapabilitiesRequest>& pkt) {
+  DEVICE_VLOG(4) << __func__
+                 << ": capability=" << pkt->GetCapabilityRequested();
+
+  switch (pkt->GetCapabilityRequested()) {
+    case Capability::COMPANY_ID: {
+      auto response =
+          GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x001958);
+      response->AddCompanyId(0x002345);
+      send_message_cb_.Run(label, false, std::move(response));
+    } break;
+
+    case Capability::EVENTS_SUPPORTED: {
+      auto response =
+          GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
+              Event::PLAYBACK_STATUS_CHANGED);
+      response->AddEvent(Event::TRACK_CHANGED);
+      response->AddEvent(Event::PLAYBACK_POS_CHANGED);
+
+      if (!avrcp13_compatibility_) {
+        response->AddEvent(Event::AVAILABLE_PLAYERS_CHANGED);
+        response->AddEvent(Event::ADDRESSED_PLAYER_CHANGED);
+        response->AddEvent(Event::UIDS_CHANGED);
+        response->AddEvent(Event::NOW_PLAYING_CONTENT_CHANGED);
+      }
+
+      send_message(label, false, std::move(response));
+    } break;
+
+    default: {
+      DEVICE_LOG(WARNING) << "Unhandled Capability: "
+                          << pkt->GetCapabilityRequested();
+      auto response = RejectBuilder::MakeBuilder(CommandPdu::GET_CAPABILITIES,
+                                                 Status::INVALID_PARAMETER);
+      send_message(label, false, std::move(response));
+    } break;
+  }
+}
+
+void Device::HandleNotification(
+    uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(ERROR) << __func__ << ": Request packet is not valid";
+    auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
+                                               Status::INVALID_PARAMETER);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
+  DEVICE_VLOG(4) << __func__ << ": event=" << pkt->GetEventRegistered();
+
+  switch (pkt->GetEventRegistered()) {
+    case Event::TRACK_CHANGED: {
+      track_changed_ = Notification(true, label);
+      media_interface_->GetNowPlayingList(
+          base::Bind(&Device::TrackChangedNotificationResponse,
+                     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,
+                     weak_ptr_factory_.GetWeakPtr(), label, true));
+    } break;
+
+    case Event::PLAYBACK_POS_CHANGED: {
+      play_pos_changed_ = Notification(true, label);
+      play_pos_interval_ = pkt->GetInterval();
+      media_interface_->GetPlayStatus(
+          base::Bind(&Device::PlaybackPosNotificationResponse,
+                     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,
+          weak_ptr_factory_.GetWeakPtr(), now_playing_changed_.second, true));
+    } break;
+
+    case Event::AVAILABLE_PLAYERS_CHANGED: {
+      // Respond immediately since this notification doesn't require any info
+      avail_players_changed_ = Notification(true, label);
+      auto response =
+          RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(
+              true);
+      send_message(label, false, std::move(response));
+    } break;
+
+    case Event::ADDRESSED_PLAYER_CHANGED: {
+      addr_player_changed_ = Notification(true, label);
+      media_interface_->GetMediaPlayerList(
+          base::Bind(&Device::AddressedPlayerNotificationResponse,
+                     weak_ptr_factory_.GetWeakPtr(), label, true));
+    } break;
+
+    case Event::UIDS_CHANGED: {
+      // Respond immediately since this notification doesn't require any info
+      uids_changed_ = Notification(true, label);
+      auto response =
+          RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(true, 0);
+      send_message(label, false, std::move(response));
+    } break;
+
+    default: {
+      DEVICE_LOG(ERROR) << __func__ << " : Unknown event registered. Event ID="
+                        << pkt->GetEventRegistered();
+      auto response = RejectBuilder::MakeBuilder(
+          (CommandPdu)pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
+      send_message(label, false, std::move(response));
+    } break;
+  }
+}
+
+void Device::RegisterVolumeChanged() {
+  DEVICE_VLOG(2) << __func__;
+  if (volume_interface_ == nullptr) return;
+
+  auto request =
+      RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
+
+  // Find an open transaction label to prevent conflicts with other commands
+  // that are in flight. We can not use the reserved label while the
+  // notification hasn't been completed.
+  uint8_t label = MAX_TRANSACTION_LABEL;
+  for (uint8_t i = 0; i < MAX_TRANSACTION_LABEL; i++) {
+    if (active_labels_.find(i) == active_labels_.end()) {
+      active_labels_.insert(i);
+      label = i;
+      break;
+    }
+  }
+
+  if (label == MAX_TRANSACTION_LABEL) {
+    DEVICE_LOG(FATAL)
+        << __func__
+        << ": Abandon all hope, something went catastrophically wrong";
+  }
+
+  send_message_cb_.Run(label, false, std::move(request));
+}
+
+void Device::HandleVolumeChanged(
+    uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt) {
+  DEVICE_VLOG(1) << __func__ << ": interim=" << pkt->IsInterim();
+  if (volume_interface_ == nullptr) return;
+
+  if (pkt->GetCType() == CType::REJECTED) {
+    // Disable Absolute Volume
+    active_labels_.erase(label);
+    volume_interface_ = nullptr;
+    volume_ = VOL_REGISTRATION_FAILED;
+    return;
+  }
+
+  // We only update on interim and just re-register on changes.
+  if (!pkt->IsInterim()) {
+    active_labels_.erase(label);
+    RegisterVolumeChanged();
+    return;
+  }
+
+  // Handle the first volume update.
+  if (volume_ == VOL_NOT_SUPPORTED) {
+    volume_ = pkt->GetVolume();
+    volume_interface_->DeviceConnected(
+        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_);
+}
+
+void Device::SetVolume(int8_t volume) {
+  // TODO (apanicke): Implement logic for Multi-AVRCP
+  DEVICE_VLOG(1) << __func__ << ": volume=" << (int)volume;
+  auto request = SetAbsoluteVolumeRequestBuilder::MakeBuilder(volume);
+
+  uint8_t label = MAX_TRANSACTION_LABEL;
+  for (uint8_t i = 0; i < MAX_TRANSACTION_LABEL; i++) {
+    if (active_labels_.find(i) == active_labels_.end()) {
+      active_labels_.insert(i);
+      label = i;
+      break;
+    }
+  }
+
+  volume_ = volume;
+  send_message_cb_.Run(label, false, std::move(request));
+}
+
+void Device::TrackChangedNotificationResponse(uint8_t label, bool interim,
+                                              std::string curr_song_id,
+                                              std::vector<SongInfo> song_list) {
+  DEVICE_VLOG(1) << __func__;
+  uint64_t uid = 0;
+
+  if (!track_changed_.first) {
+    DEVICE_VLOG(0) << __func__ << ": Device not registered for update";
+    return;
+  }
+
+  // Anytime we use the now playing list, update our map so that its always
+  // current
+  now_playing_ids_.clear();
+  for (const SongInfo& song : song_list) {
+    now_playing_ids_.insert(song.media_id);
+    if (curr_song_id == song.media_id) {
+      DEVICE_VLOG(3) << __func__ << ": Found media ID match for "
+                     << song.media_id;
+      uid = now_playing_ids_.get_uid(curr_song_id);
+    }
+  }
+
+  if (curr_song_id == "") {
+    DEVICE_LOG(WARNING) << "Empty media ID";
+    uid = 0;
+    if (stack_config_get_interface()->get_pts_avrcp_test()) {
+      DEVICE_LOG(WARNING) << __func__ << ": pts test mode";
+      uid = 0xffffffffffffffff;
+    }
+  }
+
+  auto response = RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
+      interim, uid);
+  send_message_cb_.Run(label, false, std::move(response));
+  if (!interim) {
+    active_labels_.erase(label);
+    track_changed_ = Notification(false, 0);
+  }
+}
+
+void Device::PlaybackStatusNotificationResponse(uint8_t label, bool interim,
+                                                PlayStatus status) {
+  DEVICE_VLOG(1) << __func__;
+  if (status.state == PlayState::PAUSED) play_pos_update_cb_.Cancel();
+
+  if (!play_status_changed_.first) {
+    DEVICE_VLOG(0) << __func__ << ": Device not registered for update";
+    return;
+  }
+
+  auto state_to_send = status.state;
+  if (!IsActive()) state_to_send = PlayState::PAUSED;
+  if (!interim && state_to_send == last_play_status_.state) {
+    DEVICE_VLOG(0) << __func__
+                   << ": Not sending notification due to no state update "
+                   << address_.ToString();
+    return;
+  }
+
+  last_play_status_.state = state_to_send;
+
+  auto response =
+      RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+          interim, IsActive() ? status.state : PlayState::PAUSED);
+  send_message_cb_.Run(label, false, std::move(response));
+
+  if (!interim) {
+    active_labels_.erase(label);
+    play_status_changed_ = Notification(false, 0);
+  }
+}
+
+void Device::PlaybackPosNotificationResponse(uint8_t label, bool interim,
+                                             PlayStatus status) {
+  DEVICE_VLOG(4) << __func__;
+
+  if (!play_pos_changed_.first) {
+    DEVICE_VLOG(3) << __func__ << ": Device not registered for update";
+    return;
+  }
+
+  if (!interim && last_play_status_.position == status.position) {
+    DEVICE_LOG(WARNING) << address_.ToString()
+                        << ": No update to play position";
+    return;
+  }
+
+  auto response =
+      RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
+          interim, status.position);
+  send_message_cb_.Run(label, false, std::move(response));
+
+  last_play_status_.position = status.position;
+
+  if (!interim) {
+    active_labels_.erase(label);
+    play_pos_changed_ = Notification(false, 0);
+  }
+
+  // We still try to send updates while music is playing to the non active
+  // device even though the device thinks the music is paused. This makes
+  // 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,
+                                         weak_ptr_factory_.GetWeakPtr()));
+    base::MessageLoop::current()->task_runner()->PostDelayedTask(
+        FROM_HERE, play_pos_update_cb_.callback(),
+        base::TimeDelta::FromSeconds(play_pos_interval_));
+  }
+}
+
+// TODO (apanicke): Finish implementing when we add support for more than one
+// player
+void Device::AddressedPlayerNotificationResponse(
+    uint8_t label, bool interim, uint16_t curr_player,
+    std::vector<MediaPlayerInfo> /* unused */) {
+  DEVICE_VLOG(1) << __func__
+                 << ": curr_player_id=" << (unsigned int)curr_player;
+  // If there is no set browsed player, use the current addressed player as the
+  // default NOTE: Using any browsing commands before the browsed player is set
+  // is a violation of the AVRCP Spec but there are some carkits that try too
+  // anyways
+  if (curr_browsed_player_id_ == -1) curr_browsed_player_id_ = curr_player;
+
+  auto response =
+      RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
+          interim, curr_player, 0x0000);
+  send_message_cb_.Run(label, false, std::move(response));
+
+  if (!interim) {
+    active_labels_.erase(label);
+    addr_player_changed_ = Notification(false, 0);
+    RejectNotification();
+  }
+}
+
+void Device::RejectNotification() {
+  DEVICE_VLOG(1) << __func__;
+  Notification* rejectNotification[] = {&play_status_changed_, &track_changed_,
+                                        &play_pos_changed_,
+                                        &now_playing_changed_};
+  for (int i = 0; i < 4; i++) {
+    uint8_t label = rejectNotification[i]->second;
+    auto response = RejectBuilder::MakeBuilder(
+        CommandPdu::REGISTER_NOTIFICATION, Status::ADDRESSED_PLAYER_CHANGED);
+    send_message_cb_.Run(label, false, std::move(response));
+    active_labels_.erase(label);
+    rejectNotification[i] = new Notification(false, 0);
+  }
+}
+
+void Device::GetPlayStatusResponse(uint8_t label, PlayStatus status) {
+  DEVICE_VLOG(2) << __func__ << ": position=" << status.position
+                 << " duration=" << status.duration
+                 << " state=" << status.state;
+  auto response = GetPlayStatusResponseBuilder::MakeBuilder(
+      status.duration, status.position,
+      IsActive() ? status.state : PlayState::PAUSED);
+  send_message(label, false, std::move(response));
+}
+
+void Device::GetElementAttributesResponse(
+    uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
+    SongInfo info) {
+  DEVICE_VLOG(2) << __func__;
+  auto get_element_attributes_pkt = pkt;
+  auto attributes_requested =
+      get_element_attributes_pkt->GetAttributesRequested();
+
+  auto response = GetElementAttributesResponseBuilder::MakeBuilder(ctrl_mtu_);
+
+  last_song_info_ = info;
+
+  if (attributes_requested.size() != 0) {
+    for (const auto& attribute : attributes_requested) {
+      if (info.attributes.find(attribute) != info.attributes.end()) {
+        response->AddAttributeEntry(*info.attributes.find(attribute));
+      }
+    }
+  } else {  // zero attributes requested which means all attributes requested
+    for (const auto& attribute : info.attributes) {
+      response->AddAttributeEntry(attribute);
+    }
+  }
+
+  send_message(label, false, std::move(response));
+}
+
+void Device::MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt) {
+  DEVICE_VLOG(4) << __func__ << ": opcode=" << pkt->GetOpcode();
+
+  active_labels_.insert(label);
+
+  switch (pkt->GetOpcode()) {
+    // TODO (apanicke): Remove handling of UNIT_INFO and SUBUNIT_INFO from
+    // the AVRC_API and instead handle it here to reduce fragmentation.
+    case Opcode::UNIT_INFO: {
+    } break;
+    case Opcode::SUBUNIT_INFO: {
+    } break;
+    case Opcode::PASS_THROUGH: {
+      auto pass_through_packet = Packet::Specialize<PassThroughPacket>(pkt);
+      auto response = PassThroughPacketBuilder::MakeBuilder(
+          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
+      if (pass_through_packet->GetOperationId() == 0x44 &&
+          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(
+            [](base::WeakPtr<Device> d, PlayStatus s) {
+              if (!d) return;
+
+              if (!d->IsActive()) {
+                LOG(INFO) << "Setting " << d->address_.ToString()
+                          << " to be the active device";
+                d->media_interface_->SetActiveDevice(d->address_);
+
+                if (s.state == PlayState::PLAYING) {
+                  LOG(INFO)
+                      << "Skipping sendKeyEvent since music is already playing";
+                  return;
+                }
+              }
+
+              d->media_interface_->SendKeyEvent(0x44, KeyState::PUSHED);
+            },
+            weak_ptr_factory_.GetWeakPtr()));
+        return;
+      }
+
+      if (IsActive()) {
+        media_interface_->SendKeyEvent(pass_through_packet->GetOperationId(),
+                                       pass_through_packet->GetKeyState());
+      }
+    } break;
+    case Opcode::VENDOR: {
+      auto vendor_pkt = Packet::Specialize<VendorPacket>(pkt);
+      VendorPacketHandler(label, vendor_pkt);
+    } break;
+  }
+}
+
+void Device::HandlePlayItem(uint8_t label,
+                            std::shared_ptr<PlayItemRequest> pkt) {
+  DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope()
+                 << " uid=" << pkt->GetUid();
+
+  std::string media_id = "";
+  switch (pkt->GetScope()) {
+    case Scope::NOW_PLAYING:
+      media_id = now_playing_ids_.get_media_id(pkt->GetUid());
+      break;
+    case Scope::VFS:
+      media_id = vfs_ids_.get_media_id(pkt->GetUid());
+      break;
+    default:
+      DEVICE_LOG(WARNING) << __func__ << ": Unknown scope for play item";
+  }
+
+  if (media_id == "") {
+    DEVICE_VLOG(2) << "Could not find item";
+    auto response = RejectBuilder::MakeBuilder(CommandPdu::PLAY_ITEM,
+                                               Status::DOES_NOT_EXIST);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
+  media_interface_->PlayItem(curr_browsed_player_id_,
+                             pkt->GetScope() == Scope::NOW_PLAYING, media_id);
+
+  auto response = PlayItemResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  send_message(label, false, std::move(response));
+}
+
+void Device::HandleSetAddressedPlayer(
+    uint8_t label, std::shared_ptr<SetAddressedPlayerRequest> pkt,
+    uint16_t curr_player, std::vector<MediaPlayerInfo> players) {
+  DEVICE_VLOG(2) << __func__ << ": PlayerId=" << pkt->GetPlayerId();
+
+  if (curr_player != pkt->GetPlayerId()) {
+    DEVICE_VLOG(2) << "Reject invalid addressed player ID";
+    auto response = RejectBuilder::MakeBuilder(CommandPdu::SET_ADDRESSED_PLAYER,
+                                               Status::INVALID_PLAYER_ID);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
+  auto response =
+      SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
+  send_message(label, false, std::move(response));
+}
+
+void Device::BrowseMessageReceived(uint8_t label,
+                                   std::shared_ptr<BrowsePacket> pkt) {
+  DEVICE_VLOG(1) << __func__ << ": pdu=" << pkt->GetPdu();
+
+  switch (pkt->GetPdu()) {
+    case BrowsePdu::SET_BROWSED_PLAYER:
+      HandleSetBrowsedPlayer(label,
+                             Packet::Specialize<SetBrowsedPlayerRequest>(pkt));
+      break;
+    case BrowsePdu::GET_FOLDER_ITEMS:
+      HandleGetFolderItems(label,
+                           Packet::Specialize<GetFolderItemsRequest>(pkt));
+      break;
+    case BrowsePdu::CHANGE_PATH:
+      HandleChangePath(label, Packet::Specialize<ChangePathRequest>(pkt));
+      break;
+    case BrowsePdu::GET_ITEM_ATTRIBUTES:
+      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();
+      auto response = GeneralRejectBuilder::MakeBuilder(
+          BrowsePdu::GENERAL_REJECT, Status::INVALID_COMMAND);
+      send_message(label, true, std::move(response));
+
+      break;
+  }
+}
+
+void Device::HandleGetFolderItems(uint8_t label,
+                                  std::shared_ptr<GetFolderItemsRequest> pkt) {
+  DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope();
+
+  switch (pkt->GetScope()) {
+    case Scope::MEDIA_PLAYER_LIST:
+      media_interface_->GetMediaPlayerList(
+          base::Bind(&Device::GetMediaPlayerListResponse,
+                     weak_ptr_factory_.GetWeakPtr(), label, pkt));
+      break;
+    case Scope::VFS:
+      media_interface_->GetFolderItems(
+          curr_browsed_player_id_, CurrentFolder(),
+          base::Bind(&Device::GetVFSListResponse,
+                     weak_ptr_factory_.GetWeakPtr(), label, pkt));
+      break;
+    case Scope::NOW_PLAYING:
+      media_interface_->GetNowPlayingList(
+          base::Bind(&Device::GetNowPlayingListResponse,
+                     weak_ptr_factory_.GetWeakPtr(), label, pkt));
+      break;
+    default:
+      DEVICE_LOG(ERROR) << __func__ << ": " << pkt->GetScope();
+      break;
+  }
+}
+
+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()
+                 << " uid=" << loghex(pkt->GetUid());
+
+  if (pkt->GetDirection() == Direction::DOWN &&
+      vfs_ids_.get_media_id(pkt->GetUid()) == "") {
+    DEVICE_LOG(ERROR) << __func__
+                      << ": No item found for UID=" << pkt->GetUid();
+    auto builder =
+        ChangePathResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST, 0);
+    send_message(label, true, std::move(builder));
+    return;
+  }
+
+  if (pkt->GetDirection() == Direction::DOWN) {
+    current_path_.push(vfs_ids_.get_media_id(pkt->GetUid()));
+    DEVICE_VLOG(2) << "Pushing Path to stack: \"" << CurrentFolder() << "\"";
+  } else {
+    // Don't pop the root id off the stack
+    if (current_path_.size() > 1) {
+      current_path_.pop();
+    } else {
+      DEVICE_LOG(ERROR) << "Trying to change directory up past root.";
+      auto builder =
+          ChangePathResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST, 0);
+      send_message(label, true, std::move(builder));
+      return;
+    }
+
+    DEVICE_VLOG(2) << "Popping Path from stack: new path=\"" << CurrentFolder()
+                   << "\"";
+  }
+
+  media_interface_->GetFolderItems(
+      curr_browsed_player_id_, CurrentFolder(),
+      base::Bind(&Device::ChangePathResponse, weak_ptr_factory_.GetWeakPtr(),
+                 label, pkt));
+}
+
+void Device::ChangePathResponse(uint8_t label,
+                                std::shared_ptr<ChangePathRequest> pkt,
+                                std::vector<ListItem> list) {
+  // TODO (apanicke): Reconstruct the VFS ID's here. Right now it gets
+  // reconstructed in GetFolderItemsVFS
+  auto builder =
+      ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list.size());
+  send_message(label, true, std::move(builder));
+}
+
+void Device::HandleGetItemAttributes(
+    uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt) {
+  DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope()
+                 << " uid=" << loghex(pkt->GetUid())
+                 << " uid counter=" << loghex(pkt->GetUidCounter());
+  if (pkt->GetUidCounter() != 0x0000) {  // For database unaware player, use 0
+    DEVICE_LOG(WARNING) << "UidCounter is invalid";
+    auto builder = GetItemAttributesResponseBuilder::MakeBuilder(
+        Status::UIDS_CHANGED, browse_mtu_);
+    send_message(label, true, std::move(builder));
+    return;
+  }
+  switch (pkt->GetScope()) {
+    case Scope::NOW_PLAYING: {
+      media_interface_->GetNowPlayingList(
+          base::Bind(&Device::GetItemAttributesNowPlayingResponse,
+                     weak_ptr_factory_.GetWeakPtr(), label, pkt));
+    } break;
+    case Scope::VFS:
+      // TODO (apanicke): Check the vfs_ids_ here. If the item doesn't exist
+      // then we can auto send the error without calling up. We do this check
+      // later right now though in order to prevent race conditions with updates
+      // on the media layer.
+      media_interface_->GetFolderItems(
+          curr_browsed_player_id_, CurrentFolder(),
+          base::Bind(&Device::GetItemAttributesVFSResponse,
+                     weak_ptr_factory_.GetWeakPtr(), label, pkt));
+      break;
+    default:
+      DEVICE_LOG(ERROR) << "UNKNOWN SCOPE FOR HANDLE GET ITEM ATTRIBUTES";
+      break;
+  }
+}
+
+void Device::GetItemAttributesNowPlayingResponse(
+    uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
+    std::string curr_media_id, std::vector<SongInfo> song_list) {
+  DEVICE_VLOG(2) << __func__ << ": uid=" << loghex(pkt->GetUid());
+  auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR,
+                                                               browse_mtu_);
+
+  auto media_id = now_playing_ids_.get_media_id(pkt->GetUid());
+  if (media_id == "") {
+    media_id = curr_media_id;
+  }
+
+  DEVICE_VLOG(2) << __func__ << ": media_id=\"" << media_id << "\"";
+
+  SongInfo info;
+  for (const auto& temp : song_list) {
+    if (temp.media_id == media_id) {
+      info = temp;
+    }
+  }
+
+  auto attributes_requested = pkt->GetAttributesRequested();
+  if (attributes_requested.size() != 0) {
+    for (const auto& attribute : attributes_requested) {
+      if (info.attributes.find(attribute) != info.attributes.end()) {
+        builder->AddAttributeEntry(*info.attributes.find(attribute));
+      }
+    }
+  } else {
+    // If zero attributes were requested, that means all attributes were
+    // requested
+    for (const auto& attribute : info.attributes) {
+      builder->AddAttributeEntry(attribute);
+    }
+  }
+
+  send_message(label, true, std::move(builder));
+}
+
+void Device::GetItemAttributesVFSResponse(
+    uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
+    std::vector<ListItem> item_list) {
+  DEVICE_VLOG(2) << __func__ << ": uid=" << loghex(pkt->GetUid());
+
+  auto media_id = vfs_ids_.get_media_id(pkt->GetUid());
+  if (media_id == "") {
+    LOG(WARNING) << __func__ << ": Item not found";
+    auto builder = GetItemAttributesResponseBuilder::MakeBuilder(
+        Status::DOES_NOT_EXIST, browse_mtu_);
+    send_message(label, true, std::move(builder));
+    return;
+  }
+
+  auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR,
+                                                               browse_mtu_);
+
+  ListItem item_requested;
+  for (const auto& temp : item_list) {
+    if ((temp.type == ListItem::FOLDER && temp.folder.media_id == media_id) ||
+        (temp.type == ListItem::SONG && temp.song.media_id == media_id)) {
+      item_requested = temp;
+    }
+  }
+
+  // TODO (apanicke): Add a helper function or allow adding a map
+  // of attributes to GetItemAttributesResponseBuilder
+  auto attributes_requested = pkt->GetAttributesRequested();
+  if (item_requested.type == ListItem::FOLDER) {
+    if (attributes_requested.size() == 0) {
+      builder->AddAttributeEntry(Attribute::TITLE, item_requested.folder.name);
+    } else {
+      for (auto& attr : attributes_requested) {
+        if (attr == Attribute::TITLE) {
+          builder->AddAttributeEntry(Attribute::TITLE,
+                                     item_requested.folder.name);
+        }
+      }
+    }
+  } else {
+    if (attributes_requested.size() != 0) {
+      for (const auto& attribute : attributes_requested) {
+        if (item_requested.song.attributes.find(attribute) !=
+            item_requested.song.attributes.end()) {
+          builder->AddAttributeEntry(
+              *item_requested.song.attributes.find(attribute));
+        }
+      }
+    } else {
+      // If zero attributes were requested, that means all attributes were
+      // requested
+      for (const auto& attribute : item_requested.song.attributes) {
+        builder->AddAttributeEntry(attribute);
+      }
+    }
+  }
+
+  send_message(label, true, std::move(builder));
+}
+
+void Device::GetMediaPlayerListResponse(
+    uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
+    uint16_t curr_player, std::vector<MediaPlayerInfo> players) {
+  DEVICE_VLOG(2) << __func__;
+
+  if (players.size() == 0) {
+    auto no_items_rsp = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+        Status::RANGE_OUT_OF_BOUNDS, 0x0000, browse_mtu_);
+    send_message(label, true, std::move(no_items_rsp));
+  }
+
+  auto builder = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, browse_mtu_);
+
+  // Move the current player to the first slot due to some carkits always
+  // connecting to the first listed player rather than using the ID
+  // returned by Addressed Player Changed
+  for (auto it = players.begin(); it != players.end(); it++) {
+    if (it->id == curr_player) {
+      DEVICE_VLOG(1) << " Adding player to first spot: " << it->name;
+      auto temp_player = *it;
+      players.erase(it);
+      players.insert(players.begin(), temp_player);
+      break;
+    }
+  }
+
+  for (size_t i = pkt->GetStartItem();
+       i <= pkt->GetEndItem() && i < players.size(); i++) {
+    MediaPlayerItem item(players[i].id, players[i].name,
+                         players[i].browsing_supported);
+    builder->AddMediaPlayer(item);
+  }
+
+  send_message(label, true, std::move(builder));
+}
+
+std::set<AttributeEntry> filter_attributes_requested(
+    const SongInfo& song, const std::vector<Attribute>& attrs) {
+  std::set<AttributeEntry> result;
+  for (const auto& attr : attrs) {
+    if (song.attributes.find(attr) != song.attributes.end()) {
+      result.insert(*song.attributes.find(attr));
+    }
+  }
+
+  return result;
+}
+
+void Device::GetVFSListResponse(uint8_t label,
+                                std::shared_ptr<GetFolderItemsRequest> pkt,
+                                std::vector<ListItem> items) {
+  DEVICE_VLOG(2) << __func__ << ": start_item=" << pkt->GetStartItem()
+                 << " end_item=" << pkt->GetEndItem();
+
+  // The builder will automatically correct the status if there are zero items
+  auto builder = GetFolderItemsResponseBuilder::MakeVFSBuilder(
+      Status::NO_ERROR, 0x0000, browse_mtu_);
+
+  // TODO (apanicke): Add test that checks if vfs_ids_ is the correct size after
+  // an operation.
+  for (const auto& item : items) {
+    if (item.type == ListItem::FOLDER) {
+      vfs_ids_.insert(item.folder.media_id);
+    } else if (item.type == ListItem::SONG) {
+      vfs_ids_.insert(item.song.media_id);
+    }
+  }
+
+  // Add the elements retrieved in the last get folder items request and map
+  // them to UIDs The maps will be cleared every time a directory change
+  // happens. These items do not need to correspond with the now playing list as
+  // the UID's only need to be unique in the context of the current scope and
+  // the current folder
+  for (auto i = pkt->GetStartItem(); i <= pkt->GetEndItem() && i < items.size();
+       i++) {
+    if (items[i].type == ListItem::FOLDER) {
+      auto folder = items[i].folder;
+      // right now we always use folders of mixed type
+      FolderItem folder_item(vfs_ids_.get_uid(folder.media_id), 0x00,
+                             folder.is_playable, folder.name);
+      builder->AddFolder(folder_item);
+    } else if (items[i].type == ListItem::SONG) {
+      auto song = items[i].song;
+      auto title =
+          song.attributes.find(Attribute::TITLE) != song.attributes.end()
+              ? song.attributes.find(Attribute::TITLE)->value()
+              : "No Song Info";
+      MediaElementItem song_item(vfs_ids_.get_uid(song.media_id), title,
+                                 std::set<AttributeEntry>());
+
+      if (pkt->GetNumAttributes() == 0x00) {  // All attributes requested
+        song_item.attributes_ = std::move(song.attributes);
+      } else {
+        song_item.attributes_ =
+            filter_attributes_requested(song, pkt->GetAttributesRequested());
+      }
+
+      builder->AddSong(song_item);
+    }
+  }
+
+  send_message(label, true, std::move(builder));
+}
+
+void Device::GetNowPlayingListResponse(
+    uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
+    std::string /* unused curr_song_id */, std::vector<SongInfo> song_list) {
+  DEVICE_VLOG(2) << __func__;
+  auto builder = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, browse_mtu_);
+
+  now_playing_ids_.clear();
+  for (const SongInfo& song : song_list) {
+    now_playing_ids_.insert(song.media_id);
+  }
+
+  for (size_t i = pkt->GetStartItem();
+       i <= pkt->GetEndItem() && i < song_list.size(); i++) {
+    auto song = song_list[i];
+    auto title = song.attributes.find(Attribute::TITLE) != song.attributes.end()
+                     ? song.attributes.find(Attribute::TITLE)->value()
+                     : "No Song Info";
+
+    MediaElementItem item(i + 1, title, std::set<AttributeEntry>());
+    if (pkt->GetNumAttributes() == 0x00) {
+      item.attributes_ = std::move(song.attributes);
+    } else {
+      item.attributes_ =
+          filter_attributes_requested(song, pkt->GetAttributesRequested());
+    }
+    builder->AddSong(item);
+  }
+
+  send_message(label, true, std::move(builder));
+}
+
+void Device::HandleSetBrowsedPlayer(
+    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,
+                 weak_ptr_factory_.GetWeakPtr(), label, pkt));
+}
+
+void Device::SetBrowsedPlayerResponse(
+    uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt, bool success,
+    std::string root_id, uint32_t num_items) {
+  DEVICE_VLOG(2) << __func__ << ": success=" << success << " root_id=\""
+                 << root_id << "\" num_items=" << num_items;
+
+  if (!success) {
+    auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+        Status::INVALID_PLAYER_ID, 0x0000, num_items, 0, "");
+    send_message(label, true, std::move(response));
+    return;
+  }
+
+  curr_browsed_player_id_ = pkt->GetPlayerId();
+
+  // Clear the path and push the new root.
+  current_path_ = std::stack<std::string>();
+  current_path_.push(root_id);
+
+  auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(
+      Status::NO_ERROR, 0x0000, num_items, 0, "");
+  send_message(label, true, std::move(response));
+}
+
+void Device::SendMediaUpdate(bool metadata, bool play_status, bool queue) {
+  CHECK(media_interface_);
+  DEVICE_VLOG(4) << __func__ << ": Metadata=" << metadata
+                 << " : play_status= " << play_status << " : queue=" << queue;
+
+  if (queue) {
+    HandleNowPlayingUpdate();
+  }
+
+  if (play_status) {
+    HandlePlayStatusUpdate();
+    HandlePlayPosUpdate();
+  }
+
+  if (metadata) HandleTrackUpdate();
+}
+
+void Device::SendFolderUpdate(bool available_players, bool addressed_player,
+                              bool uids) {
+  CHECK(media_interface_);
+  DEVICE_VLOG(4) << __func__;
+
+  if (available_players) {
+    HandleAvailablePlayerUpdate();
+  }
+
+  if (addressed_player) {
+    HandleAddressedPlayerUpdate();
+  }
+}
+
+void Device::HandleTrackUpdate() {
+  DEVICE_VLOG(2) << __func__;
+  if (!track_changed_.first) {
+    LOG(WARNING) << "Device is not registered for track changed updates";
+    return;
+  }
+
+  media_interface_->GetNowPlayingList(
+      base::Bind(&Device::TrackChangedNotificationResponse,
+                 weak_ptr_factory_.GetWeakPtr(), track_changed_.second, false));
+}
+
+void Device::HandlePlayStatusUpdate() {
+  DEVICE_VLOG(2) << __func__;
+  if (!play_status_changed_.first) {
+    LOG(WARNING) << "Device is not registered for play status updates";
+    return;
+  }
+
+  media_interface_->GetPlayStatus(base::Bind(
+      &Device::PlaybackStatusNotificationResponse,
+      weak_ptr_factory_.GetWeakPtr(), play_status_changed_.second, false));
+}
+
+void Device::HandleNowPlayingUpdate() {
+  DEVICE_VLOG(2) << __func__;
+
+  if (!now_playing_changed_.first) {
+    LOG(WARNING) << "Device is not registered for now playing updates";
+    return;
+  }
+
+  media_interface_->GetNowPlayingList(base::Bind(
+      &Device::HandleNowPlayingNotificationResponse,
+      weak_ptr_factory_.GetWeakPtr(), now_playing_changed_.second, false));
+}
+
+void Device::HandleNowPlayingNotificationResponse(
+    uint8_t label, bool interim, std::string curr_song_id,
+    std::vector<SongInfo> song_list) {
+  if (!now_playing_changed_.first) {
+    LOG(WARNING) << "Device is not registered for now playing updates";
+    return;
+  }
+
+  now_playing_ids_.clear();
+  for (const SongInfo& song : song_list) {
+    now_playing_ids_.insert(song.media_id);
+  }
+
+  auto response =
+      RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(interim);
+  send_message(now_playing_changed_.second, false, std::move(response));
+
+  if (!interim) {
+    active_labels_.erase(label);
+    now_playing_changed_ = Notification(false, 0);
+  }
+}
+
+void Device::HandlePlayPosUpdate() {
+  DEVICE_VLOG(0) << __func__;
+  if (!play_pos_changed_.first) {
+    LOG(WARNING) << "Device is not registered for play position updates";
+    return;
+  }
+
+  media_interface_->GetPlayStatus(base::Bind(
+      &Device::PlaybackPosNotificationResponse, weak_ptr_factory_.GetWeakPtr(),
+      play_pos_changed_.second, false));
+}
+
+void Device::HandleAvailablePlayerUpdate() {
+  DEVICE_VLOG(1) << __func__;
+
+  if (!avail_players_changed_.first) {
+    LOG(WARNING) << "Device is not registered for available player updates";
+    return;
+  }
+
+  auto response =
+      RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(false);
+  send_message_cb_.Run(avail_players_changed_.second, false,
+                       std::move(response));
+
+  if (!avail_players_changed_.first) {
+    active_labels_.erase(avail_players_changed_.second);
+    avail_players_changed_ = Notification(false, 0);
+  }
+}
+
+void Device::HandleAddressedPlayerUpdate() {
+  DEVICE_VLOG(1) << __func__;
+  if (!addr_player_changed_.first) {
+    DEVICE_LOG(WARNING)
+        << "Device is not registered for addressed player updates";
+    return;
+  }
+  media_interface_->GetMediaPlayerList(base::Bind(
+      &Device::AddressedPlayerNotificationResponse,
+      weak_ptr_factory_.GetWeakPtr(), addr_player_changed_.second, false));
+}
+
+void Device::DeviceDisconnected() {
+  DEVICE_LOG(INFO) << "Device was disconnected";
+  play_pos_update_cb_.Cancel();
+
+  // TODO (apanicke): Once the interfaces are set in the Device construction,
+  // remove these conditionals.
+  if (volume_interface_ != nullptr)
+    volume_interface_->DeviceDisconnected(GetAddress());
+}
+
+static std::string volumeToStr(int8_t volume) {
+  if (volume == VOL_NOT_SUPPORTED) return "Absolute Volume not supported";
+  if (volume == VOL_REGISTRATION_FAILED)
+    return "Volume changed notification was rejected";
+  return std::to_string(volume);
+}
+
+std::ostream& operator<<(std::ostream& out, const Device& d) {
+  out << "  " << d.address_.ToString();
+  if (d.IsActive()) out << " <Active>";
+  out << std::endl;
+  out << "    Current Volume: " << volumeToStr(d.volume_) << std::endl;
+  out << "    Current Browsed Player ID: " << d.curr_browsed_player_id_
+      << std::endl;
+  out << "    Registered Notifications: " << std::endl;
+  if (d.track_changed_.first) {
+    out << "      Track Changed" << std::endl;
+  }
+  if (d.play_status_changed_.first) {
+    out << "      Play Status" << std::endl;
+  }
+  if (d.play_pos_changed_.first) {
+    out << "      Play Position" << std::endl;
+  }
+  if (d.now_playing_changed_.first) {
+    out << "      Now Playing" << std::endl;
+  }
+  if (d.addr_player_changed_.first) {
+    out << "      Addressed Player" << std::endl;
+  }
+  if (d.avail_players_changed_.first) {
+    out << "      Available Players" << std::endl;
+  }
+  if (d.uids_changed_.first) {
+    out << "      UIDs Changed" << std::endl;
+  }
+
+  out << "    Last Play State: " << d.last_play_status_.state << std::endl;
+  out << "    Last Song Sent ID: \"" << d.last_song_info_.media_id << "\""
+      << std::endl;
+  out << "    Current Folder: \"" << d.CurrentFolder() << "\"" << std::endl;
+  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;
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/profile/avrcp/device.h b/profile/avrcp/device.h
new file mode 100644
index 0000000..5ef886d
--- /dev/null
+++ b/profile/avrcp/device.h
@@ -0,0 +1,306 @@
+/*
+ * 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 <iostream>
+#include <memory>
+#include <stack>
+
+#include <base/bind.h>
+#include <base/cancelable_callback.h>
+
+#include "avrcp.h"
+#include "avrcp_internal.h"
+#include "avrcp_packet.h"
+#include "media_id_map.h"
+#include "raw_address.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+/**
+ * A class representing a connection with a remote AVRCP device. It holds all
+ * the state and message handling for the device that it represents.
+ */
+// TODO (apanicke): Once we move over to having the individual message
+// responders for Browse and Classic AVRCP Messages move the device around via a
+// weak pointer.
+class Device {
+ public:
+  /**
+   * Device is friends with Avrcp::ConnectionHandler so that ConnectionHandler
+   * can deliver messages to individual devices.
+   */
+  friend class ConnectionHandler;
+
+  Device(
+      const RawAddress& bdaddr, bool avrcp13_compatibility,
+      base::Callback<void(uint8_t label, bool browse,
+                          std::unique_ptr<::bluetooth::PacketBuilder> message)>
+          send_msg_cb,
+      uint16_t ctrl_mtu, uint16_t browse_mtu);
+  virtual ~Device() = default;
+
+  const RawAddress& GetAddress() const { return address_; };
+
+  /**
+   * Disconnects the AVRCP connection that this device represents.
+   */
+  bool Disconnect();
+
+  /**
+   * Returns true if the current device is active.
+   */
+  bool IsActive() const;
+
+  /**
+   * Register the interfaces that the device uses to get information. If the
+   * Volume Interface is null, then absolute volume is disabled.
+   * TODO (apanicke): Add these to the constructor/factory so that each device
+   * is created valid and can't be accidentally interacted with when no
+   * interfaces are registered.
+   */
+  void RegisterInterfaces(MediaInterface* interface,
+                          A2dpInterface* a2dp_interface,
+                          VolumeInterface* volume_interface);
+
+  /**
+   * Notify the device that metadata, play_status, and/or queue have updated
+   * via a boolean. Each boolean represents whether its respective content has
+   * updated.
+   */
+  virtual void SendMediaUpdate(bool metadata, bool play_status, bool queue);
+
+  /**
+   * Notify the device that the available_player, addressed_player, or UIDs
+   * have updated via a boolean. Each boolean represents whether its respective
+   * content has updated.
+   */
+  virtual void SendFolderUpdate(bool available_player, bool addressed_player,
+                                bool uids);
+
+  // TODO (apanicke): Split the message handlers into two files. One
+  // for handling Browse Messages and the other for handling all other
+  // messages. This prevents the .cc file from getting bloated like it is
+  // now. The Device class will then become a state holder for each message
+  // and all the functions in these handler classes can be static since the
+  // device will be passed in. The extensions of the Device class can contain
+  // any interop handling for specific messages on specific devices.
+
+  void MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt);
+  void BrowseMessageReceived(uint8_t label, std::shared_ptr<BrowsePacket> pkt);
+  void VendorPacketHandler(uint8_t label, std::shared_ptr<VendorPacket> pkt);
+
+  /********************
+   * MESSAGE RESPONSES
+   ********************/
+  // CURRENT TRACK CHANGED
+  virtual void HandleTrackUpdate();
+  virtual void TrackChangedNotificationResponse(
+      uint8_t label, bool interim, std::string curr_song_id,
+      std::vector<SongInfo> song_list);
+
+  // GET CAPABILITY
+  virtual void HandleGetCapabilities(
+      uint8_t label, const std::shared_ptr<GetCapabilitiesRequest>& pkt);
+
+  // REGISTER NOTIFICATION
+  virtual void HandleNotification(
+      uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt);
+
+  // PLAY STATUS CHANGED
+  virtual void HandlePlayStatusUpdate();
+
+  // NOW PLAYING LIST CHANGED
+  virtual void HandleNowPlayingUpdate();
+  virtual void HandleNowPlayingNotificationResponse(
+      uint8_t label, bool interim, std::string curr_song_id,
+      std::vector<SongInfo> song_list);
+
+  // PLAY POSITION CHANGED
+  virtual void HandlePlayPosUpdate();
+  virtual void PlaybackPosNotificationResponse(uint8_t label, bool interim,
+                                               PlayStatus status);
+
+  // GET PLAY STATUS
+  virtual void GetPlayStatusResponse(uint8_t label, PlayStatus status);
+  virtual void PlaybackStatusNotificationResponse(uint8_t label, bool interim,
+                                                  PlayStatus status);
+
+  // GET ELEMENT ATTRIBUTE
+  // TODO (apanicke): Add a Handler function for this so if a specific device
+  // needs to implement an interop fix, you only need to overload the one
+  // function.
+  virtual void GetElementAttributesResponse(
+      uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
+      SongInfo info);
+
+  // AVAILABLE PLAYER CHANGED
+  virtual void HandleAvailablePlayerUpdate();
+
+  // ADDRESSED PLAYER CHANGED
+  virtual void HandleAddressedPlayerUpdate();
+  virtual void RejectNotification();
+  virtual void AddressedPlayerNotificationResponse(
+      uint8_t label, bool interim, uint16_t curr_player,
+      std::vector<MediaPlayerInfo> /* unused */);
+
+  // GET FOLDER ITEMS
+  virtual void HandleGetFolderItems(
+      uint8_t label, std::shared_ptr<GetFolderItemsRequest> request);
+  virtual void GetMediaPlayerListResponse(
+      uint8_t label, std::shared_ptr<GetFolderItemsRequest> pkt,
+      uint16_t curr_player, std::vector<MediaPlayerInfo> players);
+  virtual void GetVFSListResponse(uint8_t label,
+                                  std::shared_ptr<GetFolderItemsRequest> pkt,
+                                  std::vector<ListItem> items);
+  virtual void GetNowPlayingListResponse(
+      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);
+  virtual void GetItemAttributesNowPlayingResponse(
+      uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
+      std::string curr_media_id, std::vector<SongInfo> song_list);
+  virtual void GetItemAttributesVFSResponse(
+      uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt,
+      std::vector<ListItem> item_list);
+
+  // SET BROWSED PLAYER
+  virtual void HandleSetBrowsedPlayer(
+      uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> request);
+  virtual void SetBrowsedPlayerResponse(
+      uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt, bool success,
+      std::string root_id, uint32_t num_items);
+
+  // CHANGE PATH
+  virtual void HandleChangePath(uint8_t label,
+                                std::shared_ptr<ChangePathRequest> request);
+  virtual void ChangePathResponse(uint8_t label,
+                                  std::shared_ptr<ChangePathRequest> request,
+                                  std::vector<ListItem> list);
+
+  // PLAY ITEM
+  virtual void HandlePlayItem(uint8_t label,
+                              std::shared_ptr<PlayItemRequest> request);
+
+  // SET ADDRESSED PLAYER
+  virtual void HandleSetAddressedPlayer(
+      uint8_t label, std::shared_ptr<SetAddressedPlayerRequest> request,
+      uint16_t curr_player, std::vector<MediaPlayerInfo> players);
+
+  /********************
+   * MESSAGE REQUESTS
+   ********************/
+  // VOLUME CHANGED NOTIFICATION
+  virtual void RegisterVolumeChanged();
+  virtual void HandleVolumeChanged(
+      uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt);
+
+  // SET VOLUME
+  virtual void SetVolume(int8_t volume);
+
+  /**
+   * This function is called by Avrcp::ConnectionHandler to signify that
+   * the remote device was disconnected.
+   *
+   * TODO (apanicke): Prevent allowing responses to messages while the device is
+   * disconnected by using a weak pointer handle to the device when we separate
+   * out the message handling. Also separate the logic in the future when
+   * disconnecting only browsing (Though this shouldn't matter as if we are
+   * disconnecting browsing then we should be fully disconnecting the device).
+   */
+  void DeviceDisconnected();
+
+  friend std::ostream& operator<<(std::ostream& out, const Device& c);
+
+ private:
+  // This should always contain one item which represents the root id on the
+  // current player.
+  std::string CurrentFolder() const {
+    if (current_path_.empty()) return "";
+    return current_path_.top();
+  }
+
+  void send_message(uint8_t label, bool browse,
+                    std::unique_ptr<::bluetooth::PacketBuilder> message) {
+    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_;
+
+  // Enables AVRCP 1.3 Compatibility mode. This disables any AVRCP 1.4+ features
+  // such as browsing and playlists but has the highest chance of working.
+  bool avrcp13_compatibility_ = false;
+  base::Callback<void(uint8_t label, bool browse,
+                      std::unique_ptr<::bluetooth::PacketBuilder> message)>
+      send_message_cb_;
+  uint16_t ctrl_mtu_;
+  uint16_t browse_mtu_;
+
+  int curr_browsed_player_id_ = -1;
+
+  std::stack<std::string> current_path_;
+
+  // Notification Trackers
+  using Notification = std::pair<bool, uint8_t>;
+  Notification track_changed_ = Notification(false, 0);
+  Notification play_status_changed_ = Notification(false, 0);
+  Notification play_pos_changed_ = Notification(false, 0);
+  Notification now_playing_changed_ = Notification(false, 0);
+  Notification addr_player_changed_ = Notification(false, 0);
+  Notification avail_players_changed_ = Notification(false, 0);
+  Notification uids_changed_ = Notification(false, 0);
+
+  MediaIdMap vfs_ids_;
+  MediaIdMap now_playing_ids_;
+
+  uint32_t play_pos_interval_ = 0;
+
+  SongInfo last_song_info_;
+  PlayStatus last_play_status_;
+
+  base::CancelableClosure play_pos_update_cb_;
+
+  MediaInterface* media_interface_ = nullptr;
+  A2dpInterface* a2dp_interface_ = nullptr;
+  VolumeInterface* volume_interface_ = nullptr;
+
+  // Labels used for messages currently in flight.
+  std::set<uint8_t> active_labels_;
+
+  int8_t volume_ = -1;
+  DISALLOW_COPY_AND_ASSIGN(Device);
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/profile/avrcp/media_id_map.h b/profile/avrcp/media_id_map.h
new file mode 100644
index 0000000..f282f20
--- /dev/null
+++ b/profile/avrcp/media_id_map.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <map>
+
+namespace bluetooth {
+namespace avrcp {
+
+// A helper class to convert Media ID's (represented as strings) that are
+// received from the AVRCP Media Interface layer into UID's to be used
+// with connected devices.
+class MediaIdMap {
+ public:
+  void clear() {
+    media_id_to_uid_.clear();
+    uid_to_media_id_.clear();
+  }
+
+  std::string get_media_id(uint64_t uid) {
+    const auto& uid_it = uid_to_media_id_.find(uid);
+    if (uid_it == uid_to_media_id_.end()) return "";
+    return uid_it->second;
+  }
+
+  uint64_t get_uid(std::string media_id) {
+    const auto& media_id_it = media_id_to_uid_.find(media_id);
+    if (media_id_it == media_id_to_uid_.end()) return 0;
+    return media_id_it->second;
+  }
+
+  uint64_t insert(std::string media_id) {
+    if (media_id_to_uid_.find(media_id) != media_id_to_uid_.end()) {
+      return media_id_to_uid_[media_id];
+    }
+
+    uint64_t uid = media_id_to_uid_.size() + 1;
+    media_id_to_uid_.insert(std::pair<std::string, uint64_t>(media_id, uid));
+    uid_to_media_id_.insert(std::pair<uint64_t, std::string>(uid, media_id));
+    return uid;
+  }
+
+ private:
+  std::map<std::string, uint64_t> media_id_to_uid_;
+  std::map<uint64_t, std::string> uid_to_media_id_;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/profile/avrcp/tests/avrcp_connection_handler_test.cc b/profile/avrcp/tests/avrcp_connection_handler_test.cc
new file mode 100644
index 0000000..4f542f6
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_connection_handler_test.cc
@@ -0,0 +1,529 @@
+/*
+ * 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/bind.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "avrcp_internal.h"
+#include "avrcp_test_helper.h"
+#include "connection_handler.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SaveArgPointee;
+using ::testing::SetArgPointee;
+using ::testing::MockFunction;
+using ::testing::NiceMock;
+using ::testing::StrictMock;
+
+namespace bluetooth {
+namespace avrcp {
+
+using device_ptr = std::shared_ptr<Device>;
+
+class AvrcpConnectionHandlerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    ON_CALL(mock_avrcp_, Close(_)).WillByDefault(Return(0));
+  }
+
+  void SetUpSdp(tAVRC_FIND_CBACK* sdp_cb, bool browsing, bool absolute_volume) {
+    EXPECT_CALL(mock_avrcp_, FindService(_, _, _, _))
+        .Times(1)
+        .WillOnce(DoAll(SaveArg<3>(sdp_cb), Return(0)));
+
+    static tSDP_DISC_ATTR fake_features;
+
+    fake_features = {
+        .p_next_attr = nullptr,
+        .attr_id = 0,
+        .attr_len_type = 0,
+        .attr_value.v.u16 = 0,
+    };
+
+    if (browsing) fake_features.attr_value.v.u16 |= AVRC_SUPF_CT_BROWSE;
+    if (absolute_volume) fake_features.attr_value.v.u16 |= AVRC_SUPF_CT_CAT2;
+
+    EXPECT_CALL(mock_sdp_, FindAttributeInRec(_, _))
+        .Times(4)
+        .WillRepeatedly(Return(&fake_features));
+
+    EXPECT_CALL(mock_sdp_, FindServiceInDb(_, _, _))
+        .Times(2)
+        .WillOnce(Return((tSDP_DISC_REC*)0x01))   // Return any non null pointer
+        .WillOnce(Return((tSDP_DISC_REC*)0x01));  // Return any non null pointer
+
+    EXPECT_CALL(mock_sdp_, FindProfileVersionInRec(_, _, _))
+        .Times(2)
+        .WillRepeatedly(DoAll(SetArgPointee<2>(AVRC_REV_1_6), Return(true)));
+  }
+
+ protected:
+  ConnectionHandler* connection_handler_ = nullptr;
+
+  // We use NiceMock's here because each function of this code does quite a few
+  // operations. This way it is much easier to write a higher number of smaller
+  // tests without having a large amount of warnings.
+  NiceMock<MockFunction<void(device_ptr)>> device_cb;
+  NiceMock<MockAvrcpInterface> mock_avrcp_;
+  NiceMock<MockSdpInterface> mock_sdp_;
+  NiceMock<MockVolumeInterface> mock_volume_;
+};
+
+TEST_F(AvrcpConnectionHandlerTest, initializeTest) {
+  // Set an Expectation that Open will be called 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)));
+
+  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();
+
+  // Check that the callback was sent with us as the acceptor
+  ASSERT_EQ(conn_cb.conn, 1);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+// Check that disconnecting without an active connection
+TEST_F(AvrcpConnectionHandlerTest, notConnectedDisconnectTest) {
+  // 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();
+
+  // Call the callback with a message saying the connection has closed
+  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+};
+
+// Test calling the connection callback after the handler is cleaned up
+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) {
+  // 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(2)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(2), 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();
+
+  // Check that the callback was sent with us as the acceptor
+  ASSERT_EQ(conn_cb.conn, 1);
+
+  // Set an Expectations that SDP will be performed
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, false, false);
+
+  // Set an expectation that a device will be created
+  EXPECT_CALL(device_cb, Call(_)).Times(1);
+
+  // Set an Expectation that OpenBrowse will be called in acceptor mode when the
+  // device connects.
+  EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ACP)).Times(1);
+
+  // Call the callback with a message saying that a remote device has connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+
+  // Run the SDP callback with status success
+  sdp_cb.Run(0);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+// Check that when a device does not support absolute volume, that the
+// handler reports that via the volume interface.
+TEST_F(AvrcpConnectionHandlerTest, noAbsoluteVolumeTest) {
+  // 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(2)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(2), 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();
+
+  // Set an Expectations that SDP will be performed
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, false, false);
+
+  EXPECT_CALL(mock_volume_, DeviceConnected(RawAddress::kAny)).Times(1);
+
+  // Call the callback with a message saying that a remote device has connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+
+  // Run the SDP callback with status success
+  sdp_cb.Run(0);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+// Check that when a device does support absolute volume, that the handler
+// doesn't report it. Instead that will be left up to the device.
+TEST_F(AvrcpConnectionHandlerTest, absoluteVolumeTest) {
+  // 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(2)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)));
+
+  // Initialize the interface
+  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
+                                   base::Unretained(&device_cb));
+
+  StrictMock<MockVolumeInterface> strict_volume;
+  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
+                                            &mock_sdp_, &strict_volume));
+  connection_handler_ = ConnectionHandler::Get();
+
+  // Set an Expectations that SDP will be performed with absolute volume
+  // supported
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, false, true);
+
+  // Call the callback with a message saying that a remote device has connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+
+  // Run the SDP callback with status success
+  sdp_cb.Run(0);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+TEST_F(AvrcpConnectionHandlerTest, disconnectTest) {
+  // 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(2)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(DoAll(SetArgPointee<0>(2), 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();
+
+  // Call the callback with a message saying that a remote device has connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+
+  // Set up the expectation that Close will be called
+  EXPECT_CALL(mock_avrcp_, Close(1)).Times(1);
+
+  // Call the callback with a message saying that a remote device has
+  // disconnected
+  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+// Check that we can handle having a remote device connect to us, start SDP, and
+// open another acceptor connection
+TEST_F(AvrcpConnectionHandlerTest, multipleRemoteDeviceConnectionTest) {
+  // Set an Expectation that Open will be called three times 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(3)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(3), 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();
+
+  // Check that the callback was sent with us as the acceptor
+  ASSERT_EQ(conn_cb.conn, 1);
+
+  // Set an Expectations that SDP will be performed
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, false, false);
+
+  // Set an expectation that a device will be created
+  EXPECT_CALL(device_cb, Call(_)).Times(1);
+
+  // Set an Expectation that OpenBrowse will be called in acceptor mode when the
+  // device connects on handle 1
+  EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ACP)).Times(1);
+
+  // Call the callback with a message saying that a remote device has connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+
+  // Run the SDP callback with status success
+  sdp_cb.Run(0);
+
+  // Set an Expectations that SDP will be performed again
+  SetUpSdp(&sdp_cb, false, false);
+
+  // Set an expectation that a device will be created again
+  EXPECT_CALL(device_cb, Call(_)).Times(1);
+
+  // Set an Expectation that OpenBrowse will be called in acceptor mode when the
+  // device connects on handle 2
+  EXPECT_CALL(mock_avrcp_, OpenBrowse(2, AVCT_ACP)).Times(1);
+
+  // Call the callback with a message saying that a remote device has connected
+  // with a different address
+  conn_cb.ctrl_cback.Run(2, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);
+
+  // Run the SDP callback with status success
+  sdp_cb.Run(0);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+TEST_F(AvrcpConnectionHandlerTest, cleanupTest) {
+  // Set Up Expectations for Initialize
+  tAVRC_CONN_CB conn_cb;
+  EXPECT_CALL(mock_avrcp_, Open(_, _, _))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(3), 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();
+
+  // Call the callback twice with a message saying that a remote device has
+  // connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+  conn_cb.ctrl_cback.Run(2, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);
+
+  // Set an Expectation that Close will be called twice with handles 1 and 2
+  EXPECT_CALL(mock_avrcp_, Close(1));
+  EXPECT_CALL(mock_avrcp_, Close(2));
+
+  // Cleanup the object causing all open connections to be closed
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+TEST_F(AvrcpConnectionHandlerTest, connectToRemoteDeviceTest) {
+  // 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();
+
+  // Set an Expectation that SDP will be performed
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, false, false);
+
+  // Connect to the device which starts SDP
+  connection_handler_->ConnectDevice(RawAddress::kEmpty);
+
+  // Set an expectation that the handler will try to open an AVRCP connection
+  // after doing SDP
+  tAVRC_CONN_CB conn_cb;
+  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kEmpty))
+      .Times(1)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));
+
+  // Complete SDP
+  sdp_cb.Run(0);
+
+  // Check that the callback was sent with us as the initiator
+  ASSERT_EQ(conn_cb.conn, 0);
+
+  // Set an expectation that a device will be created
+  EXPECT_CALL(device_cb, Call(_)).Times(1);
+
+  // Set an Expectation that OpenBrowse will NOT be called since the SDP entry
+  // didn't list browsing as a feature
+  EXPECT_CALL(mock_avrcp_, OpenBrowse(_, _)).Times(0);
+
+  // Call the callback with a message saying that a remote device has connected
+  // with a different address
+  conn_cb.ctrl_cback.Run(2, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);
+
+  // Cleanup the object causing all open connections to be closed
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+TEST_F(AvrcpConnectionHandlerTest, connectToBrowsableRemoteDeviceTest) {
+  // 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();
+
+  // Set an Expectation that SDP will be performed
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, true, false);
+
+  // Connect to the device which starts SDP
+  connection_handler_->ConnectDevice(RawAddress::kEmpty);
+
+  // Set an expectation that the handler will try to open an AVRCP connection
+  // after doing SDP
+  tAVRC_CONN_CB conn_cb;
+  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kEmpty))
+      .Times(1)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));
+
+  // Complete SDP
+  sdp_cb.Run(0);
+
+  // Check that the callback was sent with us as the initiator
+  ASSERT_EQ(conn_cb.conn, 0);
+
+  // Set an expectation that a device will be created
+  EXPECT_CALL(device_cb, Call(_)).Times(1);
+
+  // Set an Expectation that OpenBrowse will be called since browsing is listed
+  // as supported in SDP
+  EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_INT)).Times(1);
+
+  // Call the callback with a message saying that a remote device has connected
+  // with a different address
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);
+
+  // Cleanup the object causing all open connections to be closed
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+TEST_F(AvrcpConnectionHandlerTest, disconnectWhileDoingSdpTest) {
+  // 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(2)
+      .WillOnce(
+          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
+      .WillOnce(DoAll(SetArgPointee<0>(2), 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();
+
+  // Set an Expectation that SDP will be performed
+  tAVRC_FIND_CBACK sdp_cb;
+  SetUpSdp(&sdp_cb, true, false);
+
+  // Call the callback with a message saying that a remote device has connected
+  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
+
+  // Call the callback with a message saying that a remote device has
+  // disconnected
+  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);
+
+  // Signal that SDP has completed
+  sdp_cb.Run(0);
+
+  connection_handler_ = nullptr;
+  ConnectionHandler::CleanUp();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/profile/avrcp/tests/avrcp_device_test.cc b/profile/avrcp/tests/avrcp_device_test.cc
new file mode 100644
index 0000000..56f03e4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_test.cc
@@ -0,0 +1,1072 @@
+/*
+ * 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 <algorithm>
+#include <iostream>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/threading/thread.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "avrcp_packet.h"
+#include "avrcp_test_helper.h"
+#include "device.h"
+#include "stack_config.h"
+#include "tests/avrcp/avrcp_test_packets.h"
+#include "tests/packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+// TODO (apanicke): All the tests below are just basic positive unit tests.
+// Add more tests to increase code coverage.
+
+using AvrcpResponse = std::unique_ptr<::bluetooth::PacketBuilder>;
+using TestAvrcpPacket = TestPacketType<Packet>;
+using TestBrowsePacket = TestPacketType<BrowsePacket>;
+
+using ::testing::_;
+using ::testing::MockFunction;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+bool get_pts_avrcp_test(void) { return false; }
+
+const stack_config_t interface = {
+    nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr,
+    nullptr};
+
+// TODO (apanicke): All the tests below are just basic positive unit tests.
+// Add more tests to increase code coverage.
+class AvrcpDeviceTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    // NOTE: We use a wrapper lambda for the MockFunction in order to
+    // add a const qualifier to the response. Otherwise the MockFunction
+    // type doesn't match the callback type and a compiler error occurs.
+    base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = base::Bind(
+        [](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a,
+           uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); },
+        &response_cb);
+
+    // TODO (apanicke): Test setting avrc13 to false once we have full
+    // functionality.
+    test_device = new Device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF);
+  }
+
+  virtual void TearDown() override {
+    delete test_device;
+    Mock::VerifyAndClear(&response_cb);
+  }
+
+  void SendMessage(uint8_t label, std::shared_ptr<Packet> message) {
+    test_device->MessageReceived(label, message);
+  }
+
+  void SendBrowseMessage(uint8_t label, std::shared_ptr<BrowsePacket> message) {
+    test_device->BrowseMessageReceived(label, message);
+  }
+
+  MockFunction<void(uint8_t, bool, const AvrcpResponse&)> response_cb;
+  Device* test_device;
+};
+
+TEST_F(AvrcpDeviceTest, addressTest) {
+  base::Callback<void(uint8_t, bool, AvrcpResponse)> cb =
+      base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a,
+                    uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); },
+                 &response_cb);
+
+  Device device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF);
+  ASSERT_EQ(device.GetAddress(), RawAddress::kAny);
+}
+
+TEST_F(AvrcpDeviceTest, trackChangedTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {// The attribute map
+                    AttributeEntry(Attribute::TITLE, "Test Song"),
+                    AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"),
+                    AttributeEntry(Attribute::ALBUM_NAME, "Test Album"),
+                    AttributeEntry(Attribute::TRACK_NUMBER, "1"),
+                    AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"),
+                    AttributeEntry(Attribute::GENRE, "Test Genre"),
+                    AttributeEntry(Attribute::PLAYING_TIME, "1000")}};
+  std::vector<SongInfo> list = {info};
+
+  EXPECT_CALL(interface, GetNowPlayingList(_))
+      .Times(2)
+      .WillRepeatedly(InvokeCb<0>("test_id", list));
+
+  // Test the interim response for track changed
+  auto interim_response =
+      RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(true, 0x01);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(interim_response))))
+      .Times(1);
+
+  auto request =
+      RegisterNotificationRequestBuilder::MakeBuilder(Event::TRACK_CHANGED, 0);
+  auto pkt = TestAvrcpPacket::Make();
+  request->Serialize(pkt);
+  SendMessage(1, pkt);
+
+  // Test the changed response for track changed
+  auto changed_response =
+      RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(false, 0x01);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(changed_response))))
+      .Times(1);
+
+  test_device->HandleTrackUpdate();
+}
+
+TEST_F(AvrcpDeviceTest, playStatusTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING};
+  PlayStatus status2 = {0x1234, 0x5678, PlayState::STOPPED};
+
+  EXPECT_CALL(interface, GetPlayStatus(_))
+      .Times(2)
+      .WillOnce(InvokeCb<0>(status1))
+      .WillOnce(InvokeCb<0>(status2));
+
+  // Pretend the device is active
+  EXPECT_CALL(a2dp_interface, active_peer())
+      .WillRepeatedly(Return(test_device->GetAddress()));
+
+  // Test the interim response for play status changed
+  auto interim_response =
+      RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+          true, PlayState::PLAYING);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(interim_response))))
+      .Times(1);
+
+  auto request = RegisterNotificationRequestBuilder::MakeBuilder(
+      Event::PLAYBACK_STATUS_CHANGED, 0);
+  auto pkt = TestAvrcpPacket::Make();
+  request->Serialize(pkt);
+  SendMessage(1, pkt);
+
+  // Test the changed response for play status changed
+  auto changed_response =
+      RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+          false, PlayState::STOPPED);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(changed_response))))
+      .Times(1);
+  test_device->HandlePlayStatusUpdate();
+}
+
+TEST_F(AvrcpDeviceTest, playPositionTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING};
+  PlayStatus status2 = {0x5678, 0x9ABC, PlayState::STOPPED};
+
+  EXPECT_CALL(interface, GetPlayStatus(_))
+      .Times(2)
+      .WillOnce(InvokeCb<0>(status1))
+      .WillOnce(InvokeCb<0>(status2));
+
+  // Pretend the device is active
+  EXPECT_CALL(a2dp_interface, active_peer())
+      .WillRepeatedly(Return(test_device->GetAddress()));
+
+  // Test the interim response for play status changed
+  auto interim_response =
+      RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+          true, PlayState::PLAYING);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(interim_response))))
+      .Times(1);
+
+  auto request = RegisterNotificationRequestBuilder::MakeBuilder(
+      Event::PLAYBACK_STATUS_CHANGED, 0);
+  auto pkt = TestAvrcpPacket::Make();
+  request->Serialize(pkt);
+  SendMessage(1, pkt);
+
+  // Test the changed response for play status changed
+  auto changed_response =
+      RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
+          false, PlayState::STOPPED);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(changed_response))))
+      .Times(1);
+  test_device->HandlePlayStatusUpdate();
+}
+
+TEST_F(AvrcpDeviceTest, nowPlayingTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {// The attribute map
+                    AttributeEntry(Attribute::TITLE, "Test Song"),
+                    AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"),
+                    AttributeEntry(Attribute::ALBUM_NAME, "Test Album"),
+                    AttributeEntry(Attribute::TRACK_NUMBER, "1"),
+                    AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"),
+                    AttributeEntry(Attribute::GENRE, "Test Genre"),
+                    AttributeEntry(Attribute::PLAYING_TIME, "1000")}};
+  std::vector<SongInfo> list = {info};
+  EXPECT_CALL(interface, GetNowPlayingList(_))
+      .Times(2)
+      .WillRepeatedly(InvokeCb<0>("test_id", list));
+
+  // Test the interim response for now playing list changed
+  auto interim_response =
+      RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(true);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(interim_response))))
+      .Times(1);
+
+  auto request = RegisterNotificationRequestBuilder::MakeBuilder(
+      Event::NOW_PLAYING_CONTENT_CHANGED, 0);
+  auto pkt = TestAvrcpPacket::Make();
+  request->Serialize(pkt);
+  SendMessage(1, pkt);
+
+  // Test the changed response for now playing list changed
+  auto changed_response =
+      RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(false);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(changed_response))))
+      .Times(1);
+  test_device->HandleNowPlayingUpdate();
+}
+
+TEST_F(AvrcpDeviceTest, getPlayStatusTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING};
+
+  EXPECT_CALL(interface, GetPlayStatus(_))
+      .Times(1)
+      .WillOnce(InvokeCb<0>(status));
+
+  // Pretend the device is active
+  EXPECT_CALL(a2dp_interface, active_peer())
+      .WillRepeatedly(Return(test_device->GetAddress()));
+
+  auto expected_response = GetPlayStatusResponseBuilder::MakeBuilder(
+      0x5678, 0x1234, PlayState::PLAYING);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(expected_response))))
+      .Times(1);
+
+  auto request = TestAvrcpPacket::Make(get_play_status_request);
+  SendMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, getElementAttributesTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {// The attribute map
+                    AttributeEntry(Attribute::TITLE, "Test Song"),
+                    AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"),
+                    AttributeEntry(Attribute::ALBUM_NAME, "Test Album"),
+                    AttributeEntry(Attribute::TRACK_NUMBER, "1"),
+                    AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"),
+                    AttributeEntry(Attribute::GENRE, "Test Genre"),
+                    AttributeEntry(Attribute::PLAYING_TIME, "1000")}};
+
+  EXPECT_CALL(interface, GetSongInfo(_)).WillRepeatedly(InvokeCb<0>(info));
+
+  auto compare_to_partial =
+      GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF);
+  compare_to_partial->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  EXPECT_CALL(response_cb,
+              Call(2, false, matchPacket(std::move(compare_to_partial))))
+      .Times(1);
+  SendMessage(2, TestAvrcpPacket::Make(get_element_attributes_request_partial));
+
+  auto compare_to_full =
+      GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF);
+  compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+  compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1");
+  compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2");
+  compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre");
+  compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000");
+  EXPECT_CALL(response_cb,
+              Call(3, false, matchPacket(std::move(compare_to_full))))
+      .Times(1);
+  SendMessage(3, TestAvrcpPacket::Make(get_element_attributes_request_full));
+}
+
+TEST_F(AvrcpDeviceTest, getElementAttributesMtuTest) {
+  auto truncated_packet =
+      GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF);
+  truncated_packet->AddAttributeEntry(Attribute::TITLE, "1234");
+
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  base::Callback<void(uint8_t, bool, AvrcpResponse)> cb =
+      base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a,
+                    uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); },
+                 &response_cb);
+  Device device(RawAddress::kAny, true, cb, truncated_packet->size(), 0xFFFF);
+
+  device.RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {AttributeEntry(Attribute::TITLE, "1234truncated")}};
+  EXPECT_CALL(interface, GetSongInfo(_)).WillRepeatedly(InvokeCb<0>(info));
+
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(truncated_packet))))
+      .Times(1);
+
+  device.MessageReceived(
+      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;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  MediaPlayerInfo info = {0, "Test Player", true};
+  std::vector<MediaPlayerInfo> list = {info};
+
+  EXPECT_CALL(interface, GetMediaPlayerList(_))
+      .Times(1)
+      .WillOnce(InvokeCb<0>(0, list));
+
+  auto expected_response = GetFolderItemsResponseBuilder::MakePlayerListBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  expected_response->AddMediaPlayer(MediaPlayerItem(0, "Test Player", true));
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(expected_response))))
+      .Times(1);
+
+  auto request = TestBrowsePacket::Make(get_folder_items_request);
+  SendBrowseMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, getNowPlayingListTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {// The attribute map
+                    AttributeEntry(Attribute::TITLE, "Test Song"),
+                    AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"),
+                    AttributeEntry(Attribute::ALBUM_NAME, "Test Album"),
+                    AttributeEntry(Attribute::TRACK_NUMBER, "1"),
+                    AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"),
+                    AttributeEntry(Attribute::GENRE, "Test Genre"),
+                    AttributeEntry(Attribute::PLAYING_TIME, "1000")}};
+  std::vector<SongInfo> list = {info};
+
+  EXPECT_CALL(interface, GetNowPlayingList(_))
+      .WillRepeatedly(InvokeCb<0>("test_id", list));
+
+  auto expected_response = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  expected_response->AddSong(MediaElementItem(1, "Test Song", info.attributes));
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(expected_response))))
+      .Times(1);
+
+  auto request = TestBrowsePacket::Make(get_folder_items_request_now_playing);
+  SendBrowseMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, getVFSFolderTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  FolderInfo info = {"test_id", true, "Test Folder"};
+  ListItem item = {ListItem::FOLDER, info, SongInfo()};
+  std::vector<ListItem> list = {item};
+
+  EXPECT_CALL(interface, GetFolderItems(_, "", _))
+      .Times(1)
+      .WillOnce(InvokeCb<2>(list));
+
+  auto expected_response = GetFolderItemsResponseBuilder::MakeVFSBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  expected_response->AddFolder(FolderItem(1, 0, true, "Test Folder"));
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(expected_response))))
+      .Times(1);
+
+  auto request = TestBrowsePacket::Make(get_folder_items_request_vfs);
+  SendBrowseMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, getFolderItemsMtuTest) {
+  auto truncated_packet = GetFolderItemsResponseBuilder::MakeVFSBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  truncated_packet->AddFolder(FolderItem(1, 0, true, "Test Folder0"));
+  truncated_packet->AddFolder(FolderItem(2, 0, true, "Test Folder1"));
+
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+  base::Callback<void(uint8_t, bool, AvrcpResponse)> cb =
+      base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a,
+                    uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); },
+                 &response_cb);
+  Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size());
+  device.RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  FolderInfo info0 = {"test_id0", true, "Test Folder0"};
+  FolderInfo info1 = {"test_id1", true, "Test Folder1"};
+  FolderInfo info2 = {"test_id1", true, "Truncated folder"};
+  ListItem item0 = {ListItem::FOLDER, info0, SongInfo()};
+  ListItem item1 = {ListItem::FOLDER, info1, SongInfo()};
+  ListItem item2 = {ListItem::FOLDER, info1, SongInfo()};
+  std::vector<ListItem> list0 = {item0, item1, item2};
+  EXPECT_CALL(interface, GetFolderItems(_, "", _))
+      .WillRepeatedly(InvokeCb<2>(list0));
+
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(truncated_packet))))
+      .Times(1);
+  device.BrowseMessageReceived(
+      1, TestBrowsePacket::Make(get_folder_items_request_vfs));
+}
+
+TEST_F(AvrcpDeviceTest, changePathTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  FolderInfo info0 = {"test_id0", true, "Test Folder0"};
+  FolderInfo info1 = {"test_id1", true, "Test Folder1"};
+  ListItem item0 = {ListItem::FOLDER, info0, SongInfo()};
+  ListItem item1 = {ListItem::FOLDER, info1, SongInfo()};
+  std::vector<ListItem> list0 = {item0, item1};
+  EXPECT_CALL(interface, GetFolderItems(_, "", _))
+      .Times(1)
+      .WillRepeatedly(InvokeCb<2>(list0));
+
+  FolderInfo info2 = {"test_id2", true, "Test Folder2"};
+  FolderInfo info3 = {"test_id3", true, "Test Folder3"};
+  FolderInfo info4 = {"test_id4", true, "Test Folder4"};
+  ListItem item2 = {ListItem::FOLDER, info2, SongInfo()};
+  ListItem item3 = {ListItem::FOLDER, info3, SongInfo()};
+  ListItem item4 = {ListItem::FOLDER, info4, SongInfo()};
+  std::vector<ListItem> list1 = {item2, item3, item4};
+  EXPECT_CALL(interface, GetFolderItems(_, "test_id1", _))
+      .Times(3)
+      .WillRepeatedly(InvokeCb<2>(list1));
+
+  std::vector<ListItem> list2 = {};
+  EXPECT_CALL(interface, GetFolderItems(_, "test_id3", _))
+      .Times(1)
+      .WillOnce(InvokeCb<2>(list2));
+
+  // Populate the VFS ID map
+  auto folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  folder_items_response->AddFolder(FolderItem(1, 0, true, "Test Folder0"));
+  folder_items_response->AddFolder(FolderItem(2, 0, true, "Test Folder1"));
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(folder_items_response))))
+      .Times(1);
+
+  auto folder_request_builder =
+      GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {});
+  auto request = TestBrowsePacket::Make();
+  folder_request_builder->Serialize(request);
+  SendBrowseMessage(1, request);
+
+  // Change path down into Test Folder1
+  auto change_path_response =
+      ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size());
+  EXPECT_CALL(response_cb,
+              Call(2, true, matchPacket(std::move(change_path_response))));
+  auto path_request_builder =
+      ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 2);
+  request = TestBrowsePacket::Make();
+  path_request_builder->Serialize(request);
+  SendBrowseMessage(2, request);
+
+  // Populate the new VFS ID
+  folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder(
+      Status::NO_ERROR, 0x0000, 0xFFFF);
+  folder_items_response->AddFolder(FolderItem(3, 0, true, "Test Folder2"));
+  folder_items_response->AddFolder(FolderItem(4, 0, true, "Test Folder3"));
+  folder_items_response->AddFolder(FolderItem(5, 0, true, "Test Folder4"));
+  EXPECT_CALL(response_cb,
+              Call(3, true, matchPacket(std::move(folder_items_response))))
+      .Times(1);
+  folder_request_builder =
+      GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {});
+  request = TestBrowsePacket::Make();
+  folder_request_builder->Serialize(request);
+  SendBrowseMessage(3, request);
+
+  // Change path down into Test Folder3
+  change_path_response =
+      ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list2.size());
+  EXPECT_CALL(response_cb,
+              Call(4, true, matchPacket(std::move(change_path_response))));
+  path_request_builder =
+      ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 4);
+  request = TestBrowsePacket::Make();
+  path_request_builder->Serialize(request);
+  SendBrowseMessage(4, request);
+
+  // Change path up back into Test Folder1
+  change_path_response =
+      ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size());
+  EXPECT_CALL(response_cb,
+              Call(5, true, matchPacket(std::move(change_path_response))));
+  path_request_builder =
+      ChangePathRequestBuilder::MakeBuilder(0, Direction::UP, 0);
+  request = TestBrowsePacket::Make();
+  path_request_builder->Serialize(request);
+  SendBrowseMessage(5, request);
+}
+
+TEST_F(AvrcpDeviceTest, getItemAttributesNowPlayingTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {// The attribute map
+                    AttributeEntry(Attribute::TITLE, "Test Song"),
+                    AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"),
+                    AttributeEntry(Attribute::ALBUM_NAME, "Test Album"),
+                    AttributeEntry(Attribute::TRACK_NUMBER, "1"),
+                    AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"),
+                    AttributeEntry(Attribute::GENRE, "Test Genre"),
+                    AttributeEntry(Attribute::PLAYING_TIME, "1000")}};
+  std::vector<SongInfo> list = {info};
+
+  EXPECT_CALL(interface, GetNowPlayingList(_))
+      .WillRepeatedly(InvokeCb<0>("test_id", list));
+
+  auto compare_to_full =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF);
+  compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+  compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1");
+  compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2");
+  compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre");
+  compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000");
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(compare_to_full))))
+      .Times(1);
+
+  auto request =
+      TestBrowsePacket::Make(get_item_attributes_request_all_attributes);
+  SendBrowseMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, geItemAttributesMtuTest) {
+  auto truncated_packet =
+      GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF);
+  truncated_packet->AddAttributeEntry(Attribute::TITLE, "1234");
+
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+  base::Callback<void(uint8_t, bool, AvrcpResponse)> cb =
+      base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a,
+                    uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); },
+                 &response_cb);
+  Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size());
+  device.RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {AttributeEntry(Attribute::TITLE, "1234truncated")}};
+  std::vector<SongInfo> list = {info};
+  EXPECT_CALL(interface, GetNowPlayingList(_))
+      .WillRepeatedly(InvokeCb<0>("test_id", list));
+
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(truncated_packet))))
+      .Times(1);
+  device.BrowseMessageReceived(
+      1, TestBrowsePacket::Make(get_item_attributes_request_all_attributes));
+}
+
+TEST_F(AvrcpDeviceTest, setAddressedPlayerTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  MediaPlayerInfo info = {0, "Test Player", true};
+  std::vector<MediaPlayerInfo> list = {info};
+
+  EXPECT_CALL(interface, GetMediaPlayerList(_))
+      .WillRepeatedly(InvokeCb<0>(0, list));
+
+  auto set_addr_player_rej_rsp = RejectBuilder::MakeBuilder(
+      CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PLAYER_ID);
+
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(set_addr_player_rej_rsp))))
+      .Times(1);
+
+  auto player_id_1_request =
+      TestAvrcpPacket::Make(set_addressed_player_id_1_request);
+  SendMessage(1, player_id_1_request);
+
+  auto set_addr_player_rsp =
+      SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
+
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(set_addr_player_rsp))))
+      .Times(1);
+
+  auto request = TestAvrcpPacket::Make(set_addressed_player_request);
+  SendMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, volumeChangedTest) {
+  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 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);
+
+  EXPECT_CALL(vol_interface, SetVolume(0x47)).Times(1);
+  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, 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;
+  MockVolumeInterface vol_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface);
+
+  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();
+
+  auto response = TestAvrcpPacket::Make(rejected_volume_changed_notification);
+  SendMessage(1, response);
+
+  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);
+}
+
+TEST_F(AvrcpDeviceTest, getCapabilitiesTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  // GetCapabilities with CapabilityID COMPANY_ID
+  auto request_company_id_response =
+      GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x001958);
+  request_company_id_response->AddCompanyId(0x002345);
+  EXPECT_CALL(
+      response_cb,
+      Call(1, false, matchPacket(std::move(request_company_id_response))))
+      .Times(1);
+
+  auto request_company_id =
+      TestAvrcpPacket::Make(get_capabilities_request_company_id);
+  SendMessage(1, request_company_id);
+
+  // GetCapabilities with CapabilityID EVENTS_SUPPORTED
+  auto request_events_supported_response =
+      GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
+          Event::PLAYBACK_STATUS_CHANGED);
+  request_events_supported_response->AddEvent(Event::TRACK_CHANGED);
+  request_events_supported_response->AddEvent(Event::PLAYBACK_POS_CHANGED);
+
+  EXPECT_CALL(
+      response_cb,
+      Call(2, false, matchPacket(std::move(request_events_supported_response))))
+      .Times(1);
+
+  auto request_events_supported =
+      TestAvrcpPacket::Make(get_capabilities_request);
+  SendMessage(2, request_events_supported);
+
+  // GetCapabilities with CapabilityID UNKNOWN
+  auto request_unknown_response = RejectBuilder::MakeBuilder(
+      CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER);
+
+  EXPECT_CALL(response_cb,
+              Call(3, false, matchPacket(std::move(request_unknown_response))))
+      .Times(1);
+
+  auto request_unknown =
+      TestAvrcpPacket::Make(get_capabilities_request_unknown);
+  SendMessage(3, request_unknown);
+}
+
+TEST_F(AvrcpDeviceTest, getInvalidItemAttributesTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  SongInfo info = {"test_id",
+                   {// The attribute map
+                    AttributeEntry(Attribute::TITLE, "Test Song"),
+                    AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"),
+                    AttributeEntry(Attribute::ALBUM_NAME, "Test Album"),
+                    AttributeEntry(Attribute::TRACK_NUMBER, "1"),
+                    AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"),
+                    AttributeEntry(Attribute::GENRE, "Test Genre"),
+                    AttributeEntry(Attribute::PLAYING_TIME, "1000")}};
+  std::vector<SongInfo> list = {info};
+
+  EXPECT_CALL(interface, GetNowPlayingList(_))
+      .WillRepeatedly(InvokeCb<0>("test_id", list));
+
+  auto compare_to_full = GetItemAttributesResponseBuilder::MakeBuilder(
+      Status::UIDS_CHANGED, 0xFFFF);
+  compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song");
+  compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist");
+  compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album");
+  compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1");
+  compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2");
+  compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre");
+  compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000");
+  EXPECT_CALL(response_cb,
+              Call(1, true, matchPacket(std::move(compare_to_full))))
+      .Times(1);
+
+  auto request = TestBrowsePacket::Make(
+      get_item_attributes_request_all_attributes_invalid);
+  SendBrowseMessage(1, request);
+}
+
+TEST_F(AvrcpDeviceTest, invalidRegisterNotificationTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto reg_notif_rej_rsp = RejectBuilder::MakeBuilder(
+      CommandPdu::REGISTER_NOTIFICATION, Status::INVALID_PARAMETER);
+  EXPECT_CALL(response_cb,
+              Call(1, false, matchPacket(std::move(reg_notif_rej_rsp))))
+      .Times(1);
+
+  auto reg_notif_request = TestAvrcpPacket::Make(register_notification_invalid);
+  SendMessage(1, reg_notif_request);
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
+
+const stack_config_t* stack_config_get_interface(void) {
+  return &bluetooth::avrcp::interface;
+}
diff --git a/profile/avrcp/tests/avrcp_test_helper.h b/profile/avrcp/tests/avrcp_test_helper.h
new file mode 100644
index 0000000..16fc31f
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_test_helper.h
@@ -0,0 +1,150 @@
+/*
+ * 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 <type_traits>
+
+#include "avrcp.h"
+#include "avrcp_internal.h"
+#include "avrcp_packet.h"
+#include "tests/packet_test_helper.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using AvrcpResponse = std::unique_ptr<::bluetooth::PacketBuilder>;
+using TestAvrcpPacket = TestPacketType<Packet>;
+using TestBrowsePacket = TestPacketType<BrowsePacket>;
+
+class MockMediaInterface : public MediaInterface {
+ public:
+  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));
+  MOCK_METHOD1(GetMediaPlayerList, void(MediaInterface::MediaListCallback));
+  MOCK_METHOD3(GetFolderItems, void(uint16_t, std::string,
+                                    MediaInterface::FolderItemsCallback));
+  MOCK_METHOD2(SetBrowsedPlayer,
+               void(uint16_t, MediaInterface::SetBrowsedPlayerCallback));
+  MOCK_METHOD3(PlayItem, void(uint16_t, bool, std::string));
+  MOCK_METHOD1(SetActiveDevice, void(const RawAddress&));
+  MOCK_METHOD1(RegisterUpdateCallback, void(MediaCallbacks*));
+  MOCK_METHOD1(UnregisterUpdateCallback, void(MediaCallbacks*));
+};
+
+class MockVolumeInterface : public VolumeInterface {
+ public:
+  MOCK_METHOD1(DeviceConnected, void(const RawAddress&));
+  MOCK_METHOD2(DeviceConnected, void(const RawAddress&, VolumeChangedCb));
+  MOCK_METHOD1(DeviceDisconnected, void(const RawAddress&));
+  MOCK_METHOD1(SetVolume, void(int8_t));
+};
+
+class MockAvrcpInterface : public AvrcpInterface {
+ public:
+  MOCK_METHOD7(AddRecord, uint16_t(uint16_t, const char*, const char*, uint16_t,
+                                   uint32_t, bool, uint16_t));
+  MOCK_METHOD4(FindService, uint16_t(uint16_t, const RawAddress&,
+                                     tAVRC_SDP_DB_PARAMS*, tAVRC_FIND_CBACK));
+  MOCK_METHOD3(Open, uint16_t(uint8_t*, tAVRC_CONN_CB*, const RawAddress&));
+  MOCK_METHOD2(OpenBrowse, uint16_t(uint8_t, uint8_t));
+  MOCK_METHOD1(GetPeerMtu, uint16_t(uint8_t));
+  MOCK_METHOD1(GetBrowseMtu, uint16_t(uint8_t));
+  MOCK_METHOD1(Close, uint16_t(uint8_t));
+  MOCK_METHOD1(CloseBrowse, uint16_t(uint8_t));
+  MOCK_METHOD4(MsgReq, uint16_t(uint8_t, uint8_t, uint8_t, BT_HDR*));
+};
+
+class MockA2dpInterface : public A2dpInterface {
+ public:
+  MOCK_METHOD1(event_open, void(const RawAddress&));
+  MOCK_METHOD1(event_close, void(const RawAddress&));
+  MOCK_METHOD0(active_peer, RawAddress());
+};
+
+class MockSdpInterface : public SdpInterface {
+ public:
+  MOCK_METHOD6(InitDiscoveryDb,
+               bool(tSDP_DISCOVERY_DB*, uint32_t, uint16_t,
+                    const bluetooth::Uuid*, uint16_t, uint16_t*));
+  MOCK_METHOD3(ServiceSearchAttributeRequest,
+               bool(const RawAddress&, tSDP_DISCOVERY_DB*, tSDP_DISC_CMPL_CB*));
+  MOCK_METHOD3(FindServiceInDb,
+               tSDP_DISC_REC*(tSDP_DISCOVERY_DB*, uint16_t, t_sdp_disc_rec*));
+  MOCK_METHOD2(FindAttributeInRec, tSDP_DISC_ATTR*(t_sdp_disc_rec*, uint16_t));
+  MOCK_METHOD3(FindProfileVersionInRec,
+               bool(t_sdp_disc_rec*, uint16_t, uint16_t*));
+};
+
+ACTION_TEMPLATE(InvokeCb, HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(input)) {
+  ::testing::get<k>(args).Run(input);
+}
+
+ACTION_TEMPLATE(InvokeCb, HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_2_VALUE_PARAMS(a, b)) {
+  ::testing::get<k>(args).Run(a, b);
+}
+
+ACTION_TEMPLATE(InvokeCb, HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_3_VALUE_PARAMS(a, b, c)) {
+  ::testing::get<k>(args).Run(a, b, c);
+}
+
+template <class PacketType>
+class PacketMatcher : public ::testing::MatcherInterface<const AvrcpResponse&> {
+ public:
+  AvrcpResponse pkt_to_compare_to_;
+
+  PacketMatcher(AvrcpResponse&& pkt) { pkt_to_compare_to_ = std::move(pkt); }
+
+  bool MatchAndExplain(
+      const AvrcpResponse& r,
+      ::testing::MatchResultListener* listener) const override {
+    auto packet1 = TestPacketType<PacketType>::Make();
+    r->Serialize(packet1);
+
+    auto packet2 = TestPacketType<PacketType>::Make();
+    pkt_to_compare_to_->Serialize(packet2);
+
+    if (packet1->GetData() != packet2->GetData()) {
+      *listener << "\nPacket to compare to: \n";
+      *listener << packet2->ToString();
+      *listener << "\nActual packet: \n";
+      *listener << packet1->ToString();
+    }
+
+    return packet1->GetData() == packet2->GetData();
+  }
+
+  void DescribeTo(::std::ostream* os) const override { *os << "Packets match"; }
+};
+
+inline ::testing::Matcher<const AvrcpResponse&> matchPacket(
+    std::unique_ptr<PacketBuilder>&& arg) {
+  return MakeMatcher(new PacketMatcher<Packet>(std::move(arg)));
+}
+
+inline ::testing::Matcher<const AvrcpResponse&> matchPacket(
+    std::unique_ptr<BrowsePacketBuilder>&& arg) {
+  return MakeMatcher(new PacketMatcher<BrowsePacket>(std::move(arg)));
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
diff --git a/proto/Android.bp b/proto/Android.bp
new file mode 100644
index 0000000..0f97c72
--- /dev/null
+++ b/proto/Android.bp
@@ -0,0 +1,19 @@
+java_library_static {
+    name: "bluetooth-protos-lite",
+    host_supported: true,
+    proto: {
+        type: "lite",
+    },
+    srcs: ["bluetooth/metrics/bluetooth.proto"],
+}
+
+cc_library_static {
+    name: "libbt-protos-lite",
+    host_supported: true,
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    srcs: ["bluetooth/metrics/bluetooth.proto"],
+}
+
diff --git a/osi/src/protos/bluetooth.proto b/proto/bluetooth/metrics/bluetooth.proto
similarity index 65%
rename from osi/src/protos/bluetooth.proto
rename to proto/bluetooth/metrics/bluetooth.proto
index f6f1d0b..b1e28c3 100644
--- a/osi/src/protos/bluetooth.proto
+++ b/proto/bluetooth/metrics/bluetooth.proto
@@ -1,16 +1,28 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-// Author: pkanwar@google.com (Pankaj Kanwar)
-// Protos for uploading bluetooth metrics.
+/*
+ * Copyright (C) 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.
+ */
 
 syntax = "proto2";
+
 option optimize_for = LITE_RUNTIME;
 
-package clearcut.connectivity;
+// C++ namespace: bluetooth::metrics::BluetoothMetricsProto
+package bluetooth.metrics.BluetoothMetricsProto;
 
-option java_package = "com.google.wireless.android.play.playlog.connectivity";
-// option (datapol.file_vetting_status) = "latest";
-
-// import "storage/datapol/annotations/proto/semantic_annotations.proto";
+option java_package = "com.android.bluetooth";
+option java_outer_classname = "BluetoothMetricsProto";
 
 message BluetoothLog {
   // Session information that gets logged for every BT connection.
@@ -39,6 +51,12 @@
 
   // Number of ScanEvent including discarded ones beyond capacity
   optional int64 num_scan_event = 9;
+
+  // Statistics about Bluetooth profile connections
+  repeated ProfileConnectionStats profile_connection_stats = 10;
+
+  // Statistics about Headset profile connections
+  repeated HeadsetProfileConnectionStats headset_profile_connection_stats = 11;
 }
 
 // The information about the device.
@@ -115,6 +133,15 @@
   optional int32 tx_bytes = 2;
 }
 
+enum A2dpSourceCodec {
+  A2DP_SOURCE_CODEC_UNKNOWN = 0;
+  A2DP_SOURCE_CODEC_SBC = 1;
+  A2DP_SOURCE_CODEC_AAC = 2;
+  A2DP_SOURCE_CODEC_APTX = 3;
+  A2DP_SOURCE_CODEC_APTX_HD = 4;
+  A2DP_SOURCE_CODEC_LDAC = 5;
+}
+
 // Session information that gets logged for A2DP session.
 message A2DPSession {
   // Media timer in milliseconds.
@@ -140,11 +167,17 @@
 
   // Total audio time in this A2DP session
   optional int64 audio_duration_millis = 8;
+
+  // Audio codec used in this A2DP session in A2DP source role
+  optional A2dpSourceCodec source_codec = 9;
+
+  // Whether A2DP offload is enabled in this A2DP session
+  optional bool is_a2dp_offload = 10;
 }
 
 message PairEvent {
   // The reason for disconnecting
-  // https://cs.corp.google.com/#android/system/bt/stack/include/hcidefs.h&q=failed_establish.
+  // See: system/bt/stack/include/hcidefs.h, HCI_ERR_CONN_FAILED_ESTABLISHMENT
   optional int32 disconnect_reason = 1;
 
   // Pair event time
@@ -158,12 +191,9 @@
 message WakeEvent {
   // Information about the wake event type.
   enum WakeEventType {
-    // Type is unknown.
     UNKNOWN = 0;
-
     // WakeLock was acquired.
     ACQUIRED = 1;
-
     // WakeLock was released.
     RELEASED = 2;
   }
@@ -172,7 +202,7 @@
   optional WakeEventType wake_event_type = 1;
 
   // Initiator of the scan. Only the first three names will be stored.
-  // e.g. com.google.gms.
+  // e.g. com.company.app
   optional string requestor = 2;
 
   // Name of the wakelock (e.g. bluedroid_timer).
@@ -186,7 +216,6 @@
 message ScanEvent {
   // Scan type.
   enum ScanTechnologyType {
-    // Scan Type is unknown.
     SCAN_TYPE_UNKNOWN = 0;
 
     SCAN_TECH_TYPE_LE = 1;
@@ -200,7 +229,6 @@
   enum ScanEventType {
     // Scan started.
     SCAN_EVENT_START = 0;
-
     // Scan stopped.
     SCAN_EVENT_STOP = 1;
   }
@@ -209,7 +237,7 @@
   optional ScanEventType scan_event_type = 1;
 
   // Initiator of the scan. Only the first three names will be stored.
-  // e.g. com.google.gms.
+  // e.g. com.company.app
   optional string initiator = 2;
 
   // Technology used for scanning.
@@ -222,3 +250,52 @@
   optional int64 event_time_millis =
       5;  // [(datapol.semantic_type) = ST_TIMESTAMP];
 }
+
+// Profile IDs defined in BluetoothProfile API class
+// Values must match API class values
+enum ProfileId {
+  PROFILE_UNKNOWN = 0;
+  HEADSET = 1;
+  A2DP = 2;
+  HEALTH = 3;
+  HID_HOST = 4;
+  PAN = 5;
+  PBAP = 6;
+  GATT = 7;
+  GATT_SERVER = 8;
+  MAP = 9;
+  SAP = 10;
+  A2DP_SINK = 11;
+  AVRCP_CONTROLLER = 12;
+  AVRCP = 13;
+  HEADSET_CLIENT = 16;
+  PBAP_CLIENT = 17;
+  MAP_CLIENT = 18;
+  HID_DEVICE = 19;
+  OPP = 20;
+  HEARING_AID = 21;
+}
+
+// Statistics about Bluetooth profile connections
+message ProfileConnectionStats {
+  // Profile id defined in BluetoothProfile.java
+  optional ProfileId profile_id = 1;
+
+  // Number of times that this profile is connected since last metrics dump
+  optional int32 num_times_connected = 2;
+}
+
+enum HeadsetProfileType {
+  HEADSET_PROFILE_UNKNOWN = 0;
+  HSP = 1;
+  HFP = 2;
+}
+
+// Statistics about headset profile connections
+message HeadsetProfileConnectionStats {
+  // Type of headset profile connected
+  optional HeadsetProfileType headset_profile_type = 1;
+
+  // Number of times this type of headset profile is connected
+  optional int32 num_times_connected = 2;
+}
\ No newline at end of file
diff --git a/service/Android.bp b/service/Android.bp
index 5c8cb6c..d24e0fa 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -8,6 +8,7 @@
     include_dirs: [
         "system/bt",
     ],
+    header_libs: [ "libbluetooth_headers" ],
 }
 
 // Source variables
@@ -59,7 +60,6 @@
     "test/low_energy_client_unittest.cc",
     "test/low_energy_scanner_unittest.cc",
     "test/settings_unittest.cc",
-    "test/uuid_unittest.cc",
 ]
 
 // Native system service for target
@@ -71,15 +71,16 @@
     btserviceLinuxSrc +
     btserviceDaemonSrc +
     ["main.cc"],
-    required: ["bluetooth.default"],
     static_libs: [
         "libbluetooth-binder-common",
         "libbtcore",
+        "libbluetooth-types",
+        "libosi",
     ],
+
     shared_libs: [
         "libbinder",
         "libcutils",
-        "libhardware",
         "liblog",
         "libutils",
     ],
@@ -107,6 +108,7 @@
         "libbluetooth-common",
         "libgmock",
         "liblog",
+        "libbluetooth-types",
     ],
     host_supported: true,
     target: {
@@ -130,19 +132,16 @@
                 "test/stub_ipc_handler_binder.cc",
             ],
         },
-        darwin: {
-            srcs: [
-                "test/stub_ipc_handler_linux.cc",
-            ],
-        },
-        linux: {
+        linux_glibc: {
             srcs: btserviceLinuxSrc + [
                 // TODO(bcf): Fix this test.
                 //"test/ipc_linux_unittest.cc",
             ],
-            host_ldlibs: ["-lrt"],
         },
     },
+    sanitize: {
+        cfi: false,
+    },
 }
 
 // Native system service CLI for target
@@ -183,6 +182,7 @@
     name: "libbluetoothtbd_hal",
     defaults: ["fluoride_defaults"],
     include_dirs: ["system/bt"],
+    header_libs: ["libbluetooth_headers"],
     srcs: [
         "hal/bluetooth_gatt_interface.cc",
         "hal/bluetooth_interface.cc",
diff --git a/service/AndroidTest.xml b/service/AndroidTest.xml
index d16e371..0beba75 100644
--- a/service/AndroidTest.xml
+++ b/service/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright 2017 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.
diff --git a/service/BUILD.gn b/service/BUILD.gn
index 2ad2982..2fb94b5 100644
--- a/service/BUILD.gn
+++ b/service/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google
+#  Copyright 2015 Google
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@
     "common/bluetooth/scan_settings.cc",
     "common/bluetooth/service.cc",
     "common/bluetooth/util/atomic_string.cc",
-    "common/bluetooth/uuid.cc",
     "daemon.cc",
     "gatt_client.cc",
     "gatt_server.cc",
@@ -51,9 +50,9 @@
 
   include_dirs = [
     "//",
+    "//include",
     "//service/common",
     "//third_party/modp_b64/modp64",
-    "//third_party/libhardware/include",
   ]
 
   deps = [
@@ -88,7 +87,6 @@
   sources = [
     "test/fake_hal_util.cc",
     "test/settings_unittest.cc",
-    "test/uuid_unittest.cc",
   ]
 
   include_dirs = [ "//" ]
diff --git a/service/adapter.cc b/service/adapter.cc
index e059c80..853ffdf 100644
--- a/service/adapter.cc
+++ b/service/adapter.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -330,9 +330,9 @@
     }
 
     lock_guard<mutex> lock(observers_lock_);
-    FOR_EACH_OBSERVER(
-        Adapter::Observer, observers_,
-        OnDeviceConnectionStateChanged(this, device_address, connected));
+    for (auto& observer : observers_) {
+      observer.OnDeviceConnectionStateChanged(this, device_address, connected);
+    }
   }
 
   // Sends a request to set the given HAL adapter property type and value.
@@ -362,8 +362,9 @@
     if (prev_state == new_state) return;
 
     lock_guard<mutex> lock(observers_lock_);
-    FOR_EACH_OBSERVER(Adapter::Observer, observers_,
-                      OnAdapterStateChanged(this, prev_state, new_state));
+    for (auto& observer : observers_) {
+      observer.OnAdapterStateChanged(this, prev_state, new_state);
+    }
   }
 
  private:
diff --git a/service/adapter.h b/service/adapter.h
index 37275db..3becaae 100644
--- a/service/adapter.h
+++ b/service/adapter.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/bluetooth_instance.h b/service/bluetooth_instance.h
index 868f425..d0146c5 100644
--- a/service/bluetooth_instance.h
+++ b/service/bluetooth_instance.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -20,21 +20,21 @@
 #include <memory>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/common/bluetooth/low_energy_constants.h"
-#include "service/common/bluetooth/uuid.h"
 
 namespace bluetooth {
 
 // A BluetoothInstance represents an application's handle to an instance
-// that is registered with the underlying Bluetooth stack using a UUID and has a
+// that is registered with the underlying Bluetooth stack using a Uuid and has a
 // stack-assigned integer "instance_id" ID associated with it.
 class BluetoothInstance {
  public:
   virtual ~BluetoothInstance() = default;
 
   // Returns the app-specific unique ID used while registering this instance.
-  virtual const UUID& GetAppIdentifier() const = 0;
+  virtual const Uuid& GetAppIdentifier() const = 0;
 
   // Returns the HAL "interface ID" assigned to this instance by the stack.
   virtual int GetInstanceId() const = 0;
@@ -58,14 +58,14 @@
 
   // Callback invoked as a result of a call to RegisterInstance.
   using RegisterCallback =
-      std::function<void(BLEStatus status, const UUID& app_uuid,
+      std::function<void(BLEStatus status, const Uuid& app_uuid,
                          std::unique_ptr<BluetoothInstance> instance)>;
 
   // Registers an instance for the given unique identifier |app_uuid|.
   // On success, this asynchronously invokes |callback| with a unique pointer
   // to a BluetoothInstance whose ownership can be taken by the caller. In
   // the case of an error, the pointer will contain nullptr.
-  virtual bool RegisterInstance(const UUID& app_uuid,
+  virtual bool RegisterInstance(const Uuid& app_uuid,
                                 const RegisterCallback& callback) = 0;
 
  private:
diff --git a/service/client/main.cc b/service/client/main.cc
index be6b15e..e3b4c92 100644
--- a/service/client/main.cc
+++ b/service/client/main.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -593,7 +593,7 @@
   bool connectable = false;
   bool set_manufacturer_data = false;
   bool set_uuid = false;
-  bluetooth::UUID uuid;
+  bluetooth::Uuid uuid;
 
   for (auto iter = args.begin(); iter != args.end(); ++iter) {
     const std::string& arg = *iter;
@@ -609,14 +609,15 @@
       // This flag has a single argument.
       ++iter;
       if (iter == args.end()) {
-        PrintError("Expected a UUID after -u");
+        PrintError("Expected a Uuid after -u");
         return;
       }
 
       std::string uuid_str = *iter;
-      uuid = bluetooth::UUID(uuid_str);
-      if (!uuid.is_valid()) {
-        PrintError("Invalid UUID: " + uuid_str);
+      bool is_valid = false;
+      uuid = bluetooth::Uuid::FromString(uuid_str, &is_valid);
+      if (!is_valid) {
+        PrintError("Invalid Uuid: " + uuid_str);
         return;
       }
 
@@ -661,19 +662,19 @@
     // Determine the type and length bytes.
     int uuid_size = uuid.GetShortestRepresentationSize();
     uint8_t type;
-    if (uuid_size == bluetooth::UUID::kNumBytes128)
-      type = bluetooth::kEIRTypeComplete128BitUUIDs;
-    else if (uuid_size == bluetooth::UUID::kNumBytes32)
-      type = bluetooth::kEIRTypeComplete32BitUUIDs;
-    else if (uuid_size == bluetooth::UUID::kNumBytes16)
-      type = bluetooth::kEIRTypeComplete16BitUUIDs;
+    if (uuid_size == bluetooth::Uuid::kNumBytes128)
+      type = bluetooth::kEIRTypeComplete128BitUuids;
+    else if (uuid_size == bluetooth::Uuid::kNumBytes32)
+      type = bluetooth::kEIRTypeComplete32BitUuids;
+    else if (uuid_size == bluetooth::Uuid::kNumBytes16)
+      type = bluetooth::kEIRTypeComplete16BitUuids;
     else
       NOTREACHED() << "Unexpected size: " << uuid_size;
 
     data.push_back(uuid_size + 1);
     data.push_back(type);
 
-    auto uuid_bytes = uuid.GetFullLittleEndian();
+    auto uuid_bytes = uuid.To128BitLE();
     int index = (uuid_size == 16) ? 0 : 12;
     data.insert(data.end(), uuid_bytes.data() + index,
                 uuid_bytes.data() + index + uuid_size);
diff --git a/service/common/Android.bp b/service/common/Android.bp
index e85d353..b3fbfc4 100644
--- a/service/common/Android.bp
+++ b/service/common/Android.bp
@@ -7,6 +7,7 @@
         "-fvisibility=default",
     ],
     host_supported: true,
+    header_libs: [ "libbluetooth_headers" ],
     srcs: [
         "bluetooth/adapter_state.cc",
         "bluetooth/advertise_data.cc",
@@ -18,7 +19,6 @@
         "bluetooth/scan_settings.cc",
         "bluetooth/service.cc",
         "bluetooth/util/atomic_string.cc",
-        "bluetooth/uuid.cc",
     ],
     export_include_dirs: ["./"],
     include_dirs: ["system/bt"],
@@ -35,6 +35,7 @@
         /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
         "-fvisibility=default",
     ],
+    header_libs: [ "libbluetooth_headers" ],
     srcs: [
         "android/bluetooth/IBluetooth.aidl",
         "android/bluetooth/IBluetoothCallback.aidl",
@@ -72,4 +73,7 @@
         "libbase",
         "libbinder",
     ],
+    static_libs: [
+        "libbluetooth-types",
+    ]
 }
diff --git a/service/common/android/bluetooth/AdvertiseData.aidl b/service/common/android/bluetooth/AdvertiseData.aidl
index 3005670..9250f56 100644
--- a/service/common/android/bluetooth/AdvertiseData.aidl
+++ b/service/common/android/bluetooth/AdvertiseData.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/AdvertiseSettings.aidl b/service/common/android/bluetooth/AdvertiseSettings.aidl
index f479e5a..cc801ec 100644
--- a/service/common/android/bluetooth/AdvertiseSettings.aidl
+++ b/service/common/android/bluetooth/AdvertiseSettings.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl b/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
index 5f3f729..6c6922e 100644
--- a/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
+++ b/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/BluetoothGattDescriptor.aidl b/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
index 51af33e..5f6ed27 100644
--- a/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
+++ b/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/BluetoothGattIncludedService.aidl b/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
index 0ee3f63..44fded0 100644
--- a/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
+++ b/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/BluetoothGattService.aidl b/service/common/android/bluetooth/BluetoothGattService.aidl
index 92bdfe0..04dba09 100644
--- a/service/common/android/bluetooth/BluetoothGattService.aidl
+++ b/service/common/android/bluetooth/BluetoothGattService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetooth.aidl b/service/common/android/bluetooth/IBluetooth.aidl
index 1e96952..cc1e015 100644
--- a/service/common/android/bluetooth/IBluetooth.aidl
+++ b/service/common/android/bluetooth/IBluetooth.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothCallback.aidl b/service/common/android/bluetooth/IBluetoothCallback.aidl
index 24ac89b..96b7cdc 100644
--- a/service/common/android/bluetooth/IBluetoothCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothGattClient.aidl b/service/common/android/bluetooth/IBluetoothGattClient.aidl
index ccd05b0..3af3831 100644
--- a/service/common/android/bluetooth/IBluetoothGattClient.aidl
+++ b/service/common/android/bluetooth/IBluetoothGattClient.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl b/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
index 94dec9d..c4f4633 100644
--- a/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothGattServer.aidl b/service/common/android/bluetooth/IBluetoothGattServer.aidl
index 50d0a82..e48fd86 100644
--- a/service/common/android/bluetooth/IBluetoothGattServer.aidl
+++ b/service/common/android/bluetooth/IBluetoothGattServer.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl b/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
index 06340d0..9c91770 100644
--- a/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl b/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
index 5435af3..d5e4fca 100644
--- a/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
+++ b/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl b/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
index d51657e..d9032e2 100644
--- a/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothLeScanner.aidl b/service/common/android/bluetooth/IBluetoothLeScanner.aidl
index 2f9506d..7d300e2 100644
--- a/service/common/android/bluetooth/IBluetoothLeScanner.aidl
+++ b/service/common/android/bluetooth/IBluetoothLeScanner.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl b/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
index 4ee6be3..868b9cb 100644
--- a/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothLowEnergy.aidl b/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
index 4d49430..63470d0 100644
--- a/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
+++ b/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl b/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
index 858506a..ed9803b 100644
--- a/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/ScanFilter.aidl b/service/common/android/bluetooth/ScanFilter.aidl
index 2787a99..27d1ad8 100644
--- a/service/common/android/bluetooth/ScanFilter.aidl
+++ b/service/common/android/bluetooth/ScanFilter.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/ScanResult.aidl b/service/common/android/bluetooth/ScanResult.aidl
index 7ba2df5..3eac01b 100644
--- a/service/common/android/bluetooth/ScanResult.aidl
+++ b/service/common/android/bluetooth/ScanResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/ScanSettings.aidl b/service/common/android/bluetooth/ScanSettings.aidl
index 3b11b247..19b24c9 100644
--- a/service/common/android/bluetooth/ScanSettings.aidl
+++ b/service/common/android/bluetooth/ScanSettings.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/UUID.aidl b/service/common/android/bluetooth/UUID.aidl
index 54f993f..be09aaa 100644
--- a/service/common/android/bluetooth/UUID.aidl
+++ b/service/common/android/bluetooth/UUID.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/service/common/android/bluetooth/advertise_data.cc b/service/common/android/bluetooth/advertise_data.cc
index 7fe3601..75e5c59 100644
--- a/service/common/android/bluetooth/advertise_data.cc
+++ b/service/common/android/bluetooth/advertise_data.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/advertise_data.h b/service/common/android/bluetooth/advertise_data.h
index cde0eac..7543f05 100644
--- a/service/common/android/bluetooth/advertise_data.h
+++ b/service/common/android/bluetooth/advertise_data.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/advertise_settings.cc b/service/common/android/bluetooth/advertise_settings.cc
index b8fb1d1..c812abf 100644
--- a/service/common/android/bluetooth/advertise_settings.cc
+++ b/service/common/android/bluetooth/advertise_settings.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/advertise_settings.h b/service/common/android/bluetooth/advertise_settings.h
index afca233..9ee71b2 100644
--- a/service/common/android/bluetooth/advertise_settings.h
+++ b/service/common/android/bluetooth/advertise_settings.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc b/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
index 6ed9e1a..9dbc076 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
+++ b/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@
   UUID uuid;
   status = parcel->readParcelable(&uuid);
   if (status != OK) return status;
-  uuid_ = uuid;
+  uuid_ = uuid.uuid;
 
   status = parcel->readInt32(&tmp);
   if (status != OK) return status;
diff --git a/service/common/android/bluetooth/bluetooth_gatt_characteristic.h b/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
index 9884d99..954fe95 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
+++ b/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc b/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
index ecec0e0..e3ec03d 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
+++ b/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@
   UUID uuid;
   status_t status = parcel->readParcelable(&uuid);
   if (status != OK) return status;
-  uuid_ = (bluetooth::UUID)uuid;
+  uuid_ = uuid.uuid;
 
   int32_t tmp;
   status = parcel->readInt32(&tmp);
diff --git a/service/common/android/bluetooth/bluetooth_gatt_descriptor.h b/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
index 955c645..4321f9d 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
+++ b/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/bluetooth_gatt_included_service.cc b/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
index c66e0d2..21cf19a 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
+++ b/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
   UUID uuid;
   status_t status = parcel->readParcelable(&uuid);
   if (status != OK) return status;
-  uuid_ = uuid;
+  uuid_ = uuid.uuid;
 
   int32_t tmp;
   status = parcel->readInt32(&tmp);
diff --git a/service/common/android/bluetooth/bluetooth_gatt_included_service.h b/service/common/android/bluetooth/bluetooth_gatt_included_service.h
index 3a00a19..b011532 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_included_service.h
+++ b/service/common/android/bluetooth/bluetooth_gatt_included_service.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
 using android::Parcelable;
 using android::status_t;
 
-using ::bluetooth::UUID;
+using ::bluetooth::Uuid;
 
 namespace android {
 namespace bluetooth {
@@ -56,11 +56,11 @@
 
   uint16_t handle() const { return handle_; }
   bool primary() const { return primary_; }
-  UUID uuid() const { return uuid_; }
+  Uuid uuid() const { return uuid_; }
 
  protected:
   uint16_t handle_;
-  UUID uuid_;
+  Uuid uuid_;
   bool primary_;
 };
 }  // namespace bluetooth
diff --git a/service/common/android/bluetooth/bluetooth_gatt_service.cc b/service/common/android/bluetooth/bluetooth_gatt_service.cc
index 0c0daeb..820ef43 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_service.cc
+++ b/service/common/android/bluetooth/bluetooth_gatt_service.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -64,7 +64,7 @@
   UUID uuid;
   status = parcel->readParcelable(&uuid);
   if (status != OK) return status;
-  uuid_ = uuid;
+  uuid_ = uuid.uuid;
 
   std::vector<BluetoothGattCharacteristic> characteristics;
   status = parcel->readParcelableVector(&characteristics);
diff --git a/service/common/android/bluetooth/bluetooth_gatt_service.h b/service/common/android/bluetooth/bluetooth_gatt_service.h
index 932d4fb..a17b6da 100644
--- a/service/common/android/bluetooth/bluetooth_gatt_service.h
+++ b/service/common/android/bluetooth/bluetooth_gatt_service.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/scan_filter.cc b/service/common/android/bluetooth/scan_filter.cc
index 6bb6119..12d248a 100644
--- a/service/common/android/bluetooth/scan_filter.cc
+++ b/service/common/android/bluetooth/scan_filter.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -77,14 +77,14 @@
   if (status != OK) return status;
   device_address_ = std::string(String8(addr).string());
 
-  std::unique_ptr<UUID> uuid;
+  UUID uuid;
   status = parcel->readParcelable(&uuid);
   if (status != OK) return status;
-  service_uuid_ = std::move(uuid);
+  service_uuid_.reset(new ::bluetooth::Uuid(uuid.uuid));
 
   status = parcel->readParcelable(&uuid);
   if (status != OK) return status;
-  service_uuid_mask_ = std::move(uuid);
+  service_uuid_mask_.reset(new ::bluetooth::Uuid(uuid.uuid));
 
   return status;
 }
diff --git a/service/common/android/bluetooth/scan_filter.h b/service/common/android/bluetooth/scan_filter.h
index c14f392..ebf34a4 100644
--- a/service/common/android/bluetooth/scan_filter.h
+++ b/service/common/android/bluetooth/scan_filter.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/scan_result.cc b/service/common/android/bluetooth/scan_result.cc
index 32acae3..5693ead 100644
--- a/service/common/android/bluetooth/scan_result.cc
+++ b/service/common/android/bluetooth/scan_result.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/scan_result.h b/service/common/android/bluetooth/scan_result.h
index 732ef0cc5..1a58b3e 100644
--- a/service/common/android/bluetooth/scan_result.h
+++ b/service/common/android/bluetooth/scan_result.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/scan_settings.cc b/service/common/android/bluetooth/scan_settings.cc
index 8c79cea..ca46c43 100644
--- a/service/common/android/bluetooth/scan_settings.cc
+++ b/service/common/android/bluetooth/scan_settings.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/scan_settings.h b/service/common/android/bluetooth/scan_settings.h
index 14b8bd5..53af9ee 100644
--- a/service/common/android/bluetooth/scan_settings.h
+++ b/service/common/android/bluetooth/scan_settings.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/android/bluetooth/uuid.cc b/service/common/android/bluetooth/uuid.cc
index 6cfc6db..077dd2b 100644
--- a/service/common/android/bluetooth/uuid.cc
+++ b/service/common/android/bluetooth/uuid.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
   // a second 64-bit integer. This is the same as writing the raw-bytes in
   // sequence, but we don't want to assume any host-endianness here. So follow
   // the same scheme and use the same Parcel APIs.
-  UUID::UUID128Bit bytes = GetFullBigEndian();
+  ::bluetooth::Uuid::UUID128Bit bytes = uuid.To128BitBE();
 
   uint64_t most_sig_bits =
       ((((uint64_t)bytes[0]) << 56) | (((uint64_t)bytes[1]) << 48) |
@@ -55,7 +55,7 @@
 }
 
 status_t UUID::readFromParcel(const Parcel* parcel) {
-  UUID::UUID128Bit bytes;
+  ::bluetooth::Uuid::UUID128Bit bytes;
 
   uint64_t most_sig_bits, least_sig_bits;
   status_t status = parcel->readUint64(&most_sig_bits);
@@ -82,8 +82,7 @@
   bytes[14] = (least_sig_bits >> 8) & 0xFF;
   bytes[15] = least_sig_bits & 0xFF;
 
-  id_ = bytes;
-  is_valid_ = true;
+  uuid = ::bluetooth::Uuid::From128BitBE(bytes);
   return status;
 }
 
diff --git a/service/common/android/bluetooth/uuid.h b/service/common/android/bluetooth/uuid.h
index c0a09e0..1e84d19 100644
--- a/service/common/android/bluetooth/uuid.h
+++ b/service/common/android/bluetooth/uuid.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -28,11 +28,11 @@
 namespace android {
 namespace bluetooth {
 
-class UUID : public Parcelable, public ::bluetooth::UUID {
+class UUID : public Parcelable {
  public:
   UUID() = default;
   // NOLINT, implicit converter
-  UUID(const ::bluetooth::UUID& uuid) : ::bluetooth::UUID(uuid){};  // NOLINT
+  UUID(const ::bluetooth::Uuid& uuid) : uuid(uuid){};  // NOLINT
   ~UUID() = default;
 
   // Write |this| parcelable to the given |parcel|.  Keep in mind that
@@ -48,6 +48,15 @@
   //
   // Returns android::OK on success and an appropriate error otherwise.
   status_t readFromParcel(const Parcel* parcel) override;
+
+  bool operator==(::bluetooth::Uuid rhs) const { return uuid == rhs; }
+
+  ::bluetooth::Uuid uuid;
 };
 }  // namespace bluetooth
 }  // namespace android
+
+inline bool operator==(const ::bluetooth::Uuid& lhs,
+                       const android::bluetooth::UUID& rhs) {
+  return lhs == rhs.uuid;
+}
diff --git a/service/common/bluetooth/adapter_state.cc b/service/common/bluetooth/adapter_state.cc
index 47c07af..a8866d3 100644
--- a/service/common/bluetooth/adapter_state.cc
+++ b/service/common/bluetooth/adapter_state.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/adapter_state.h b/service/common/bluetooth/adapter_state.h
index 1b2fbe4..42897ad 100644
--- a/service/common/bluetooth/adapter_state.h
+++ b/service/common/bluetooth/adapter_state.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/advertise_data.cc b/service/common/bluetooth/advertise_data.cc
index d9cac21..83b3c2f 100644
--- a/service/common/bluetooth/advertise_data.cc
+++ b/service/common/bluetooth/advertise_data.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/advertise_data.h b/service/common/bluetooth/advertise_data.h
index 0eb2bc1..bae83ee 100644
--- a/service/common/bluetooth/advertise_data.h
+++ b/service/common/bluetooth/advertise_data.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
 class AdvertiseData {
  public:
   // Constructs an AdvertiseData with the given parameters. |data| can only
-  // contain the "Service UUIDs", "Service Data", "Manufacturer Data",
+  // contain the "Service Uuids", "Service Data", "Manufacturer Data",
   // "Tx Power" and "Device name" fields as specified in the Core Specification
   //  Supplement. |data| must be properly formatted according to the supplement
   // and contains the data as it will be sent over the wire.
diff --git a/service/common/bluetooth/advertise_settings.cc b/service/common/bluetooth/advertise_settings.cc
index 4d2605b..5ecc7b4 100644
--- a/service/common/bluetooth/advertise_settings.cc
+++ b/service/common/bluetooth/advertise_settings.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/advertise_settings.h b/service/common/bluetooth/advertise_settings.h
index 6a533dd..4aff4c9 100644
--- a/service/common/bluetooth/advertise_settings.h
+++ b/service/common/bluetooth/advertise_settings.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/characteristic.cc b/service/common/bluetooth/characteristic.cc
index 492a63a..28d02bc 100644
--- a/service/common/bluetooth/characteristic.cc
+++ b/service/common/bluetooth/characteristic.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/characteristic.h b/service/common/bluetooth/characteristic.h
index ba7328a..e6221b3 100644
--- a/service/common/bluetooth/characteristic.h
+++ b/service/common/bluetooth/characteristic.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
  public:
   Characteristic() = default;
   Characteristic(const Characteristic& other);
-  Characteristic(uint16_t handle, const UUID& uuid, uint8_t properties,
+  Characteristic(uint16_t handle, const Uuid& uuid, uint8_t properties,
                  uint16_t permissions,
                  const std::vector<Descriptor>& descriptors)
       : handle_(handle),
@@ -43,7 +43,7 @@
   bool operator!=(const Characteristic& rhs) const;
 
   uint16_t handle() const { return handle_; }
-  const UUID& uuid() const { return uuid_; }
+  const Uuid& uuid() const { return uuid_; }
   uint8_t properties() const { return properties_; }
   uint16_t permissions() const { return permissions_; }
   const std::vector<Descriptor>& descriptors() const { return descriptors_; }
@@ -51,7 +51,7 @@
 
  protected:
   uint16_t handle_;
-  UUID uuid_;
+  Uuid uuid_;
   uint8_t properties_;
   uint16_t permissions_;
   std::vector<Descriptor> descriptors_;
diff --git a/service/common/bluetooth/descriptor.cc b/service/common/bluetooth/descriptor.cc
index 7e37596..b437cc3 100644
--- a/service/common/bluetooth/descriptor.cc
+++ b/service/common/bluetooth/descriptor.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/descriptor.h b/service/common/bluetooth/descriptor.h
index 35fe53e..2633820 100644
--- a/service/common/bluetooth/descriptor.h
+++ b/service/common/bluetooth/descriptor.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
   Descriptor() = default;
   Descriptor(const Descriptor& other);
   Descriptor& operator=(const Descriptor& other);
-  Descriptor(uint16_t handle, const UUID& uuid, uint16_t permissions)
+  Descriptor(uint16_t handle, const Uuid& uuid, uint16_t permissions)
       : handle_(handle), uuid_(uuid), permissions_(permissions){};
   virtual ~Descriptor() = default;
 
@@ -35,11 +35,11 @@
 
   uint16_t handle() const { return handle_; }
   uint16_t permissions() const { return permissions_; }
-  const UUID& uuid() const { return uuid_; }
+  const Uuid& uuid() const { return uuid_; }
 
  protected:
   uint16_t handle_;
-  UUID uuid_;
+  Uuid uuid_;
   uint16_t permissions_;
 };
 }
diff --git a/service/common/bluetooth/low_energy_constants.h b/service/common/bluetooth/low_energy_constants.h
index 348fa60..9ec0aee 100644
--- a/service/common/bluetooth/low_energy_constants.h
+++ b/service/common/bluetooth/low_energy_constants.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -110,12 +110,12 @@
 // Various Extended Inquiry Response fields types that are used for advertising
 // data fields as defined in the Core Specification Supplement.
 const uint8_t kEIRTypeFlags = 0x01;
-const uint8_t kEIRTypeIncomplete16BitUUIDs = 0x02;
-const uint8_t kEIRTypeComplete16BitUUIDs = 0x03;
-const uint8_t kEIRTypeIncomplete32BitUUIDs = 0x04;
-const uint8_t kEIRTypeComplete32BitUUIDs = 0x05;
-const uint8_t kEIRTypeIncomplete128BitUUIDs = 0x06;
-const uint8_t kEIRTypeComplete128BitUUIDs = 0x07;
+const uint8_t kEIRTypeIncomplete16BitUuids = 0x02;
+const uint8_t kEIRTypeComplete16BitUuids = 0x03;
+const uint8_t kEIRTypeIncomplete32BitUuids = 0x04;
+const uint8_t kEIRTypeComplete32BitUuids = 0x05;
+const uint8_t kEIRTypeIncomplete128BitUuids = 0x06;
+const uint8_t kEIRTypeComplete128BitUuids = 0x07;
 const uint8_t kEIRTypeShortenedLocalName = 0x08;
 const uint8_t kEIRTypeCompleteLocalName = 0x09;
 const uint8_t kEIRTypeTxPower = 0x0A;
diff --git a/service/common/bluetooth/scan_filter.cc b/service/common/bluetooth/scan_filter.cc
index 3226c50..5aa4e9c 100644
--- a/service/common/bluetooth/scan_filter.cc
+++ b/service/common/bluetooth/scan_filter.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -16,16 +16,18 @@
 
 #include "bluetooth/scan_filter.h"
 
+#include <raw_address.h>
+
 namespace bluetooth {
 
 ScanFilter::ScanFilter(const ScanFilter& other) {
   device_name_ = other.device_name_;
   device_address_ = other.device_address_;
 
-  if (other.service_uuid_) service_uuid_.reset(new UUID(*other.service_uuid_));
+  if (other.service_uuid_) service_uuid_.reset(new Uuid(*other.service_uuid_));
 
   if (other.service_uuid_mask_)
-    service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+    service_uuid_mask_.reset(new Uuid(*other.service_uuid_mask_));
 }
 
 ScanFilter& ScanFilter::operator=(const ScanFilter& other) {
@@ -33,12 +35,12 @@
   device_address_ = other.device_address_;
 
   if (other.service_uuid_)
-    service_uuid_.reset(new UUID(*other.service_uuid_));
+    service_uuid_.reset(new Uuid(*other.service_uuid_));
   else
     service_uuid_ = nullptr;
 
   if (other.service_uuid_mask_)
-    service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+    service_uuid_mask_.reset(new Uuid(*other.service_uuid_mask_));
   else
     service_uuid_mask_ = nullptr;
 
@@ -52,15 +54,15 @@
   return true;
 }
 
-void ScanFilter::SetServiceUuid(const UUID& service_uuid) {
-  service_uuid_.reset(new UUID(service_uuid));
+void ScanFilter::SetServiceUuid(const Uuid& service_uuid) {
+  service_uuid_.reset(new Uuid(service_uuid));
   service_uuid_mask_.reset();
 }
 
-void ScanFilter::SetServiceUuidWithMask(const UUID& service_uuid,
-                                        const UUID& mask) {
-  service_uuid_.reset(new UUID(service_uuid));
-  service_uuid_mask_.reset(new UUID(mask));
+void ScanFilter::SetServiceUuidWithMask(const Uuid& service_uuid,
+                                        const Uuid& mask) {
+  service_uuid_.reset(new Uuid(service_uuid));
+  service_uuid_mask_.reset(new Uuid(mask));
 }
 
 bool ScanFilter::operator==(const ScanFilter& rhs) const {
diff --git a/service/common/bluetooth/scan_filter.h b/service/common/bluetooth/scan_filter.h
index a8c30ee..e0afaa7 100644
--- a/service/common/bluetooth/scan_filter.h
+++ b/service/common/bluetooth/scan_filter.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -45,21 +45,21 @@
   // |device_address| is in an illegal format.
   bool SetDeviceAddress(const std::string& device_address);
 
-  // The service UUID and its mask used while filtering scan results. See
+  // The service Uuid and its mask used while filtering scan results. See
   // SetServiceUuidWithMask for what this mask does. The raw pointer returned
   // from these getters belongs to the ScanFilter object. nullptr will be
   // returned if these fields have not been set on this filter.
-  const UUID* service_uuid() const { return service_uuid_.get(); }
-  const UUID* service_uuid_mask() const { return service_uuid_mask_.get(); }
+  const Uuid* service_uuid() const { return service_uuid_.get(); }
+  const Uuid* service_uuid_mask() const { return service_uuid_mask_.get(); }
 
-  // Sets the service UUID for this filter.
-  void SetServiceUuid(const UUID& service_uuid);
+  // Sets the service Uuid for this filter.
+  void SetServiceUuid(const Uuid& service_uuid);
 
-  // Sets the service UUID for this filter with a 128-bit mask. The mask allows
-  // the caller to partially filter scanned service UUIDs. For any of the
-  // 128-bits of a UUID, set the corresponding bit in the mask to 1 to match the
+  // Sets the service Uuid for this filter with a 128-bit mask. The mask allows
+  // the caller to partially filter scanned service Uuids. For any of the
+  // 128-bits of a Uuid, set the corresponding bit in the mask to 1 to match the
   // advertised value, and 0 to ignore that bit.
-  void SetServiceUuidWithMask(const UUID& service_uuid, const UUID& mask);
+  void SetServiceUuidWithMask(const Uuid& service_uuid, const Uuid& mask);
 
   // Comparison operator.
   bool operator==(const ScanFilter& rhs) const;
@@ -68,8 +68,8 @@
   std::string device_name_;
   std::string device_address_;
 
-  std::unique_ptr<UUID> service_uuid_;
-  std::unique_ptr<UUID> service_uuid_mask_;
+  std::unique_ptr<Uuid> service_uuid_;
+  std::unique_ptr<Uuid> service_uuid_mask_;
 
   // TODO(armansito): Add service and manufacturer data filter fields.
 };
diff --git a/service/common/bluetooth/scan_result.cc b/service/common/bluetooth/scan_result.cc
index 007019e..5258897 100644
--- a/service/common/bluetooth/scan_result.cc
+++ b/service/common/bluetooth/scan_result.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/scan_result.h b/service/common/bluetooth/scan_result.h
index 150ad4e..7fc62ef 100644
--- a/service/common/bluetooth/scan_result.h
+++ b/service/common/bluetooth/scan_result.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/scan_settings.cc b/service/common/bluetooth/scan_settings.cc
index dac0391..7f9aa90 100644
--- a/service/common/bluetooth/scan_settings.cc
+++ b/service/common/bluetooth/scan_settings.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/scan_settings.h b/service/common/bluetooth/scan_settings.h
index da907b5..30f98ba 100644
--- a/service/common/bluetooth/scan_settings.h
+++ b/service/common/bluetooth/scan_settings.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/service.cc b/service/common/bluetooth/service.cc
index 6a8a0c3..e9b3091 100644
--- a/service/common/bluetooth/service.cc
+++ b/service/common/bluetooth/service.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/service.h b/service/common/bluetooth/service.h
index b3ce0ea..9143d6d 100644
--- a/service/common/bluetooth/service.h
+++ b/service/common/bluetooth/service.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
  public:
   Service() = default;
   Service(const Service& other);
-  Service(uint16_t handle, bool primary, const UUID& uuid,
+  Service(uint16_t handle, bool primary, const Uuid& uuid,
           const std::vector<Characteristic>& characteristics,
           const std::vector<Service>& included_services)
       : handle_(handle),
@@ -44,7 +44,7 @@
 
   uint16_t handle() const { return handle_; }
   bool primary() const { return primary_; }
-  const UUID& uuid() const { return uuid_; }
+  const Uuid& uuid() const { return uuid_; }
   const std::vector<Characteristic>& characteristics() const {
     return characteristics_;
   }
@@ -56,7 +56,7 @@
  protected:
   uint16_t handle_;
   bool primary_;
-  UUID uuid_;
+  Uuid uuid_;
   std::vector<Characteristic> characteristics_;
   std::vector<Service> included_services_;
 };
diff --git a/service/common/bluetooth/util/atomic_string.cc b/service/common/bluetooth/util/atomic_string.cc
index fd71a5b..e431b40 100644
--- a/service/common/bluetooth/util/atomic_string.cc
+++ b/service/common/bluetooth/util/atomic_string.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/util/atomic_string.h b/service/common/bluetooth/util/atomic_string.h
index 68d37ad..46d4588 100644
--- a/service/common/bluetooth/util/atomic_string.h
+++ b/service/common/bluetooth/util/atomic_string.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/common/bluetooth/uuid.cc b/service/common/bluetooth/uuid.cc
deleted file mode 100644
index 16547ae..0000000
--- a/service/common/bluetooth/uuid.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-//
-//  Copyright (C) 2015 Google, Inc.
-//
-//  Licensed under the Apache License, Version 2.0 (the "License");
-//  you may not use this file except in compliance with the License.
-//  You may obtain a copy of the License at:
-//
-//  http://www.apache.org/licenses/LICENSE-2.0
-//
-//  Unless required by applicable law or agreed to in writing, software
-//  distributed under the License is distributed on an "AS IS" BASIS,
-//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//  See the License for the specific language governing permissions and
-//  limitations under the License.
-//
-
-#include "bluetooth/uuid.h"
-
-#include <algorithm>
-#include <array>
-#include <stack>
-#include <string>
-
-#include <base/rand_util.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-
-namespace bluetooth {
-
-namespace {
-
-const UUID::UUID128Bit kSigBaseUUID = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                        0x5f, 0x9b, 0x34, 0xfb}};
-
-}  // namespace
-
-// static
-UUID UUID::GetRandom() {
-  UUID128Bit bytes;
-  base::RandBytes(bytes.data(), bytes.size());
-  return UUID(bytes);
-}
-
-// static
-UUID UUID::GetNil() {
-  UUID128Bit bytes;
-  bytes.fill(0);
-  return UUID(bytes);
-}
-
-// static
-UUID UUID::GetMax() {
-  UUID128Bit bytes;
-  bytes.fill(1);
-  return UUID(bytes);
-}
-
-void UUID::InitializeDefault() {
-  // Initialize to Bluetooth SIG base UUID.
-  id_ = kSigBaseUUID;
-  is_valid_ = true;
-}
-
-UUID::UUID() { InitializeDefault(); }
-
-UUID::UUID(std::string uuid) {
-  InitializeDefault();
-  is_valid_ = false;
-
-  if (uuid.empty()) return;
-
-  if (uuid.size() < 11 && uuid.find("0x") == 0) uuid = uuid.substr(2);
-
-  if (uuid.size() != 4 && uuid.size() != 8 && uuid.size() != 36) return;
-
-  if (uuid.size() == 36) {
-    if (uuid[8] != '-') return;
-    if (uuid[13] != '-') return;
-    if (uuid[18] != '-') return;
-    if (uuid[23] != '-') return;
-
-    std::vector<std::string> tokens = base::SplitString(
-        uuid, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
-    if (tokens.size() != 5) return;
-
-    uuid = base::JoinString(tokens, "");
-  }
-
-  const int start_index = uuid.size() == 4 ? 2 : 0;
-  const size_t copy_size = std::min(id_.size(), uuid.size() / 2);
-  for (size_t i = 0; i < copy_size; ++i) {
-    std::string octet_text(uuid, i * 2, 2);
-    char* temp = nullptr;
-    id_[start_index + i] = strtol(octet_text.c_str(), &temp, 16);
-    if (*temp != '\0') return;
-  }
-
-  is_valid_ = true;
-}
-
-UUID::UUID(const bt_uuid_t& uuid) {
-  std::reverse_copy(uuid.uu, uuid.uu + sizeof(uuid.uu), id_.begin());
-  is_valid_ = true;
-}
-
-UUID::UUID(const UUID16Bit& uuid) {
-  InitializeDefault();
-  std::copy(uuid.begin(), uuid.end(), id_.begin() + kNumBytes16);
-}
-
-UUID::UUID(const UUID32Bit& uuid) {
-  InitializeDefault();
-  std::copy(uuid.begin(), uuid.end(), id_.begin());
-}
-
-UUID::UUID(const UUID128Bit& uuid) : id_(uuid), is_valid_(true) {}
-
-UUID::UUID128Bit UUID::GetFullBigEndian() const { return id_; }
-
-UUID::UUID128Bit UUID::GetFullLittleEndian() const {
-  UUID::UUID128Bit ret;
-  std::reverse_copy(id_.begin(), id_.end(), ret.begin());
-  return ret;
-}
-
-bt_uuid_t UUID::GetBlueDroid() const {
-  bt_uuid_t ret;
-  std::reverse_copy(id_.begin(), id_.end(), ret.uu);
-  return ret;
-}
-
-std::string UUID::ToString() const {
-  return base::StringPrintf(
-      "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-      id_[0], id_[1], id_[2], id_[3], id_[4], id_[5], id_[6], id_[7], id_[8],
-      id_[9], id_[10], id_[11], id_[12], id_[13], id_[14], id_[15]);
-}
-
-size_t UUID::GetShortestRepresentationSize() const {
-  if (memcmp(id_.data() + 4, kSigBaseUUID.data() + 4, id_.size() - 4) != 0)
-    return kNumBytes128;
-
-  if (id_[0] == 0 && id_[1] == 0) return kNumBytes16;
-
-  return kNumBytes32;
-}
-
-bool UUID::operator<(const UUID& rhs) const {
-  return std::lexicographical_compare(id_.begin(), id_.end(), rhs.id_.begin(),
-                                      rhs.id_.end());
-}
-
-bool UUID::operator==(const UUID& rhs) const {
-  return std::equal(id_.begin(), id_.end(), rhs.id_.begin());
-}
-
-}  // namespace bluetooth
diff --git a/service/common/bluetooth/uuid.h b/service/common/bluetooth/uuid.h
deleted file mode 100644
index 034654c..0000000
--- a/service/common/bluetooth/uuid.h
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-//  Copyright (C) 2015 Google, Inc.
-//
-//  Licensed under the Apache License, Version 2.0 (the "License");
-//  you may not use this file except in compliance with the License.
-//  You may obtain a copy of the License at:
-//
-//  http://www.apache.org/licenses/LICENSE-2.0
-//
-//  Unless required by applicable law or agreed to in writing, software
-//  distributed under the License is distributed on an "AS IS" BASIS,
-//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//  See the License for the specific language governing permissions and
-//  limitations under the License.
-//
-
-#pragma once
-
-#include <array>
-#include <string>
-
-// TODO: Find places that break include what you use and remove this.
-#include <base/logging.h>
-#include <hardware/bluetooth.h>
-
-namespace bluetooth {
-
-class UUID {
- public:
-  static constexpr size_t kNumBytes128 = 16;
-  static constexpr size_t kNumBytes32 = 4;
-  static constexpr size_t kNumBytes16 = 2;
-
-  typedef std::array<uint8_t, kNumBytes16> UUID16Bit;
-  typedef std::array<uint8_t, kNumBytes32> UUID32Bit;
-  typedef std::array<uint8_t, kNumBytes128> UUID128Bit;
-
-  // Creates and returns a random 128-bit UUID.
-  static UUID GetRandom();
-
-  // Creates and returns a UUID in which all 128 bits are equal to 0.
-  static UUID GetNil();
-
-  // Creates and returns a UUID in which all 128 bits are equal to 1.
-  static UUID GetMax();
-
-  // Construct a Bluetooth 'base' UUID.
-  UUID();
-  virtual ~UUID() = default;
-
-  // BlueDroid constructor.
-  explicit UUID(const bt_uuid_t& uuid);
-
-  // String constructor. Only hex ASCII accepted.
-  explicit UUID(std::string uuid);
-
-  // std::array variants constructors.
-  explicit UUID(const UUID16Bit& uuid);
-  explicit UUID(const UUID32Bit& uuid);
-  explicit UUID(const UUID128Bit& uuid);
-
-  // Provide the full network-byte-ordered blob.
-  UUID128Bit GetFullBigEndian() const;
-
-  // Provide blob in Little endian (BlueDroid expects this).
-  UUID128Bit GetFullLittleEndian() const;
-
-  // Helper for bluedroid LE type.
-  bt_uuid_t GetBlueDroid() const;
-
-  // Returns a string representation for the UUID.
-  std::string ToString() const;
-
-  // Returns whether or not this UUID was initialized correctly.
-  bool is_valid() const { return is_valid_; }
-
-  // Returns the shortest possible representation of this UUID in bytes.
-  size_t GetShortestRepresentationSize() const;
-
-  bool operator<(const UUID& rhs) const;
-  bool operator==(const UUID& rhs) const;
-  inline bool operator!=(const UUID& rhs) const { return !(*this == rhs); }
-
- protected:
-  void InitializeDefault();
-
-  // Network-byte-ordered ID.
-  UUID128Bit id_;
-
-  // True if this UUID was initialized with a correct representation.
-  bool is_valid_;
-};
-
-}  // namespace bluetooth
-
-// Custom std::hash specialization so that bluetooth::UUID can be used as a key
-// in std::unordered_map.
-namespace std {
-
-template <>
-struct hash<bluetooth::UUID> {
-  std::size_t operator()(const bluetooth::UUID& key) const {
-    const auto& uuid_bytes = key.GetFullBigEndian();
-    std::hash<std::string> hash_fn;
-    return hash_fn(std::string((char*)uuid_bytes.data(), uuid_bytes.size()));
-  }
-};
-
-}  // namespace std
diff --git a/service/daemon.cc b/service/daemon.cc
index 7fd9b2b..86a3b5a 100644
--- a/service/daemon.cc
+++ b/service/daemon.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 #include <memory>
 
 #include <base/logging.h>
+#include <base/run_loop.h>
 
 #include "service/adapter.h"
 #include "service/hal/bluetooth_gatt_interface.h"
@@ -44,7 +45,7 @@
     CleanUpBluetoothStack();
   }
 
-  void StartMainLoop() override { message_loop_->Run(); }
+  void StartMainLoop() override { base::RunLoop().Run(); }
 
   Settings* GetSettings() const override { return settings_.get(); }
 
diff --git a/service/daemon.h b/service/daemon.h
index 0afefa9..0d6474b 100644
--- a/service/daemon.h
+++ b/service/daemon.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/doc/IBluetooth.txt b/service/doc/IBluetooth.txt
index 54695e6..6560daa 100644
--- a/service/doc/IBluetooth.txt
+++ b/service/doc/IBluetooth.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothCallback.txt b/service/doc/IBluetoothCallback.txt
index 612ecca..93dcdef 100644
--- a/service/doc/IBluetoothCallback.txt
+++ b/service/doc/IBluetoothCallback.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothGattClient.txt b/service/doc/IBluetoothGattClient.txt
index 8e55005..b0fc905 100644
--- a/service/doc/IBluetoothGattClient.txt
+++ b/service/doc/IBluetoothGattClient.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothGattClientCallback.txt b/service/doc/IBluetoothGattClientCallback.txt
index d3ec6ed..455fcac 100644
--- a/service/doc/IBluetoothGattClientCallback.txt
+++ b/service/doc/IBluetoothGattClientCallback.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothGattServer.txt b/service/doc/IBluetoothGattServer.txt
index 0efecab..848109a 100644
--- a/service/doc/IBluetoothGattServer.txt
+++ b/service/doc/IBluetoothGattServer.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothGattServerCallback.txt b/service/doc/IBluetoothGattServerCallback.txt
index 3744ff1..e3eefba 100644
--- a/service/doc/IBluetoothGattServerCallback.txt
+++ b/service/doc/IBluetoothGattServerCallback.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothLowEnergy.txt b/service/doc/IBluetoothLowEnergy.txt
index b7218cb..ac7a6cb 100644
--- a/service/doc/IBluetoothLowEnergy.txt
+++ b/service/doc/IBluetoothLowEnergy.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/doc/IBluetoothLowEnergyCallback.txt b/service/doc/IBluetoothLowEnergyCallback.txt
index 1ced0aa..7867379 100644
--- a/service/doc/IBluetoothLowEnergyCallback.txt
+++ b/service/doc/IBluetoothLowEnergyCallback.txt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright 2015, 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.
diff --git a/service/example/heart_rate/constants.h b/service/example/heart_rate/constants.h
index 6159997..884d5ed 100644
--- a/service/example/heart_rate/constants.h
+++ b/service/example/heart_rate/constants.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -28,11 +28,12 @@
 const uint16_t kHRSensorContactDetected = (3 << 1);
 const uint8_t kHREnergyExpendedPresent = (1 << 3);
 
-const bluetooth::UUID kCCCDescriptorUUID("2902");
-const bluetooth::UUID kHRServiceUUID("180D");
-const bluetooth::UUID kHRMeasurementUUID("2A37");
-const bluetooth::UUID kBodySensorLocationUUID("2A38");
-const bluetooth::UUID kHRControlPointUUID("2A39");
+const bluetooth::Uuid kCCCDescriptorUuid = bluetooth::Uuid::FromString("2902");
+const bluetooth::Uuid kHRServiceUuid = bluetooth::Uuid::FromString("180D");
+const bluetooth::Uuid kHRMeasurementUuid = bluetooth::Uuid::FromString("2A37");
+const bluetooth::Uuid kBodySensorLocationUuid =
+    bluetooth::Uuid::FromString("2A38");
+const bluetooth::Uuid kHRControlPointUuid = bluetooth::Uuid::FromString("2A39");
 
 const uint8_t kHRBodyLocationOther = 0;
 const uint8_t kHRBodyLocationChest = 1;
diff --git a/service/example/heart_rate/heart_rate_server.cc b/service/example/heart_rate/heart_rate_server.cc
index a7bfe52..8b8e879 100644
--- a/service/example/heart_rate/heart_rate_server.cc
+++ b/service/example/heart_rate/heart_rate_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -55,8 +55,8 @@
     bt_->GetName(&name_param);
     std::string name(String8(name_param).string());
 
-    /* Advertising data: 16-bit Service UUID: Heart Rate Service, Tx power*/
-    std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUUIDs,
+    /* Advertising data: 16-bit Service Uuid: Heart Rate Service, Tx power*/
+    std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUuids,
                               0x0D, 0x18,
                               0x02, bluetooth::kEIRTypeTxPower,
                               0x00};
@@ -239,25 +239,25 @@
 
   LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
 
-  bluetooth::Service hrService(
-      0, true, kHRServiceUUID,
-      {{0,
-        kHRMeasurementUUID,
-        bluetooth::kCharacteristicPropertyNotify,
-        0,
-        {{0, kCCCDescriptorUUID, (bluetooth::kAttributePermissionRead |
-                                  bluetooth::kAttributePermissionWrite)}}},
-       {0,
-        kBodySensorLocationUUID,
-        bluetooth::kCharacteristicPropertyRead,
-        bluetooth::kAttributePermissionRead,
-        {}},
-       {0,
-        kHRControlPointUUID,
-        bluetooth::kCharacteristicPropertyWrite,
-        bluetooth::kAttributePermissionWrite,
-        {}}},
-      {});
+  bluetooth::Service hrService(0, true, kHRServiceUuid,
+                               {{0,
+                                 kHRMeasurementUuid,
+                                 bluetooth::kCharacteristicPropertyNotify,
+                                 0,
+                                 {{0, kCCCDescriptorUuid,
+                                   (bluetooth::kAttributePermissionRead |
+                                    bluetooth::kAttributePermissionWrite)}}},
+                                {0,
+                                 kBodySensorLocationUuid,
+                                 bluetooth::kCharacteristicPropertyRead,
+                                 bluetooth::kAttributePermissionRead,
+                                 {}},
+                                {0,
+                                 kHRControlPointUuid,
+                                 bluetooth::kCharacteristicPropertyWrite,
+                                 bluetooth::kAttributePermissionWrite,
+                                 {}}},
+                               {});
 
   bool op_status = true;
 
diff --git a/service/example/heart_rate/heart_rate_server.h b/service/example/heart_rate/heart_rate_server.h
index 5f64d85..0246652 100644
--- a/service/example/heart_rate/heart_rate_server.h
+++ b/service/example/heart_rate/heart_rate_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/example/heart_rate/server_main.cc b/service/example/heart_rate/server_main.cc
index 76e7741..8ffded6 100644
--- a/service/example/heart_rate/server_main.cc
+++ b/service/example/heart_rate/server_main.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -153,7 +153,7 @@
   // received in dedicated threads set up by the ProcessState::startThreadPool
   // call above but we use this main loop for sending out heart rate
   // notifications.
-  main_loop.Run();
+  base::RunLoop().Run();
 
   LOG(INFO) << "Exiting";
   return EXIT_SUCCESS;
diff --git a/service/gatt_client.cc b/service/gatt_client.cc
index 80f5ebf..629b82a 100644
--- a/service/gatt_client.cc
+++ b/service/gatt_client.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
 // GattClient implementation
 // ========================================================
 
-GattClient::GattClient(const UUID& uuid, int client_id)
+GattClient::GattClient(const Uuid& uuid, int client_id)
     : app_identifier_(uuid), client_id_(client_id) {}
 
 GattClient::~GattClient() {
@@ -38,7 +38,7 @@
       ->unregister_client(client_id_);
 }
 
-const UUID& GattClient::GetAppIdentifier() const { return app_identifier_; }
+const Uuid& GattClient::GetAppIdentifier() const { return app_identifier_; }
 
 int GattClient::GetInstanceId() const { return client_id_; }
 
@@ -53,22 +53,21 @@
   hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
 }
 
-bool GattClientFactory::RegisterInstance(const UUID& uuid,
+bool GattClientFactory::RegisterInstance(const Uuid& uuid,
                                          const RegisterCallback& callback) {
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   if (pending_calls_.find(uuid) != pending_calls_.end()) {
-    LOG(ERROR) << "GATT client with given UUID already registered - "
-               << "UUID: " << uuid.ToString();
+    LOG(ERROR) << "GATT client with given Uuid already registered - "
+               << "Uuid: " << uuid.ToString();
     return false;
   }
 
   const btgatt_client_interface_t* hal_iface =
       hal::BluetoothGattInterface::Get()->GetClientHALInterface();
-  bt_uuid_t app_uuid = uuid.GetBlueDroid();
 
-  if (hal_iface->register_client(app_uuid) != BT_STATUS_SUCCESS) return false;
+  if (hal_iface->register_client(uuid) != BT_STATUS_SUCCESS) return false;
 
   pending_calls_[uuid] = callback;
 
@@ -77,8 +76,8 @@
 
 void GattClientFactory::RegisterClientCallback(
     hal::BluetoothGattInterface* /* gatt_iface */, int status, int client_id,
-    const bt_uuid_t& app_uuid) {
-  UUID uuid(app_uuid);
+    const Uuid& app_uuid) {
+  Uuid uuid(app_uuid);
 
   auto iter = pending_calls_.find(uuid);
   if (iter == pending_calls_.end()) {
diff --git a/service/gatt_client.h b/service/gatt_client.h
index fd83ffe..5a0322d 100644
--- a/service/gatt_client.h
+++ b/service/gatt_client.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@
 #include <unordered_map>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/bluetooth_instance.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/hal/bluetooth_gatt_interface.h"
 
 namespace bluetooth {
@@ -35,7 +35,7 @@
   ~GattClient() override;
 
   // BluetoothClientInstace overrides:
-  const UUID& GetAppIdentifier() const override;
+  const Uuid& GetAppIdentifier() const override;
   int GetInstanceId() const override;
 
  private:
@@ -43,10 +43,10 @@
 
   // Constructor shouldn't be called directly as instances are meant to be
   // obtained from the factory.
-  GattClient(const UUID& uuid, int client_id);
+  GattClient(const Uuid& uuid, int client_id);
 
   // See getters above for documentation.
-  UUID app_identifier_;
+  Uuid app_identifier_;
   int client_id_;
 
   DISALLOW_COPY_AND_ASSIGN(GattClient);
@@ -64,18 +64,18 @@
   ~GattClientFactory() override;
 
   // BluetoothInstanceFactory override:
-  bool RegisterInstance(const UUID& uuid,
+  bool RegisterInstance(const Uuid& uuid,
                         const RegisterCallback& callback) override;
 
  private:
   // hal::BluetoothGattInterface::ClientObserver override:
   void RegisterClientCallback(hal::BluetoothGattInterface* gatt_iface,
                               int status, int client_id,
-                              const bt_uuid_t& app_uuid) override;
+                              const Uuid& app_uuid) override;
 
   // Map of pending calls to register.
   std::mutex pending_calls_lock_;
-  std::unordered_map<UUID, RegisterCallback> pending_calls_;
+  std::unordered_map<Uuid, RegisterCallback> pending_calls_;
 
   DISALLOW_COPY_AND_ASSIGN(GattClientFactory);
 };
diff --git a/service/gatt_server.cc b/service/gatt_server.cc
index 63bacbb..52fd1ed 100644
--- a/service/gatt_server.cc
+++ b/service/gatt_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
 
 #include "service/gatt_server.h"
 
+#include <base/logging.h>
+
 #include "service/logging_helpers.h"
 #include "stack/include/bt_types.h"
 
@@ -27,7 +29,7 @@
 // GattServer implementation
 // ========================================================
 
-GattServer::GattServer(const UUID& uuid, int server_id)
+GattServer::GattServer(const Uuid& uuid, int server_id)
     : app_identifier_(uuid), server_id_(server_id), delegate_(nullptr) {}
 
 GattServer::~GattServer() {
@@ -50,7 +52,7 @@
   delegate_ = delegate;
 }
 
-const UUID& GattServer::GetAppIdentifier() const { return app_identifier_; }
+const Uuid& GattServer::GetAppIdentifier() const { return app_identifier_; }
 
 int GattServer::GetInstanceId() const { return server_id_; }
 
@@ -68,16 +70,16 @@
 
   svc.push_back({.type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
                                             : BTGATT_DB_SECONDARY_SERVICE),
-                 .uuid = service.uuid().GetBlueDroid()});
+                 .uuid = service.uuid()});
 
   for (const auto& characteristic : service.characteristics()) {
     svc.push_back({.type = BTGATT_DB_CHARACTERISTIC,
-                   .uuid = characteristic.uuid().GetBlueDroid(),
+                   .uuid = characteristic.uuid(),
                    .properties = characteristic.properties(),
                    .permissions = characteristic.permissions()});
     for (const auto& descriptor : characteristic.descriptors())
       svc.push_back({.type = BTGATT_DB_DESCRIPTOR,
-                     .uuid = descriptor.uuid().GetBlueDroid(),
+                     .uuid = descriptor.uuid(),
                      .permissions = descriptor.permissions()});
   }
 
@@ -292,10 +294,10 @@
 
   VLOG(1) << __func__ << " - status: " << status << " server_id: " << server_id
           << " first handle: " << svc[0].attribute_handle
-          << " service UUID: " << UUID(svc[0].uuid).ToString()
+          << " service Uuid: " << Uuid(svc[0].uuid).ToString()
           << " count: " << svc.size();
 
-  Service service(svc[0].attribute_handle, true, UUID(svc[0].uuid), {}, {});
+  Service service(svc[0].attribute_handle, true, Uuid(svc[0].uuid), {}, {});
 
   for (size_t i = 1; i < svc.size(); i++) {
     const btgatt_db_element_t& curr = svc[i];
@@ -303,13 +305,13 @@
             << " handle: " << curr.attribute_handle;
     if (curr.type == BTGATT_DB_CHARACTERISTIC) {
       service.characteristics().push_back({curr.attribute_handle,
-                                           UUID(curr.uuid),
+                                           Uuid(curr.uuid),
                                            curr.properties,
                                            curr.permissions,
                                            {}});
     } else if (curr.type == BTGATT_DB_DESCRIPTOR) {
       service.characteristics().back().descriptors().push_back(
-          {curr.attribute_handle, UUID(curr.uuid), curr.permissions});
+          {curr.attribute_handle, Uuid(curr.uuid), curr.permissions});
     } else if (svc[i].type == BTGATT_DB_INCLUDED_SERVICE) {
     }
   }
@@ -567,22 +569,21 @@
   hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
 }
 
-bool GattServerFactory::RegisterInstance(const UUID& uuid,
+bool GattServerFactory::RegisterInstance(const Uuid& uuid,
                                          const RegisterCallback& callback) {
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   if (pending_calls_.find(uuid) != pending_calls_.end()) {
-    LOG(ERROR) << "GATT-server client with given UUID already being registered "
-               << " - UUID: " << uuid.ToString();
+    LOG(ERROR) << "GATT-server client with given Uuid already being registered "
+               << " - Uuid: " << uuid.ToString();
     return false;
   }
 
   const btgatt_server_interface_t* hal_iface =
       hal::BluetoothGattInterface::Get()->GetServerHALInterface();
-  bt_uuid_t app_uuid = uuid.GetBlueDroid();
 
-  if (hal_iface->register_server(app_uuid) != BT_STATUS_SUCCESS) return false;
+  if (hal_iface->register_server(uuid) != BT_STATUS_SUCCESS) return false;
 
   pending_calls_[uuid] = callback;
 
@@ -591,10 +592,10 @@
 
 void GattServerFactory::RegisterServerCallback(
     hal::BluetoothGattInterface* gatt_iface, int status, int server_id,
-    const bt_uuid_t& app_uuid) {
-  UUID uuid(app_uuid);
+    const Uuid& app_uuid) {
+  Uuid uuid(app_uuid);
 
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   auto iter = pending_calls_.find(uuid);
diff --git a/service/gatt_server.h b/service/gatt_server.h
index e17e862..ee3970b 100644
--- a/service/gatt_server.h
+++ b/service/gatt_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -25,10 +25,10 @@
 #include <vector>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/bluetooth_instance.h"
 #include "service/common/bluetooth/service.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/hal/bluetooth_gatt_interface.h"
 
 namespace bluetooth {
@@ -116,7 +116,7 @@
   void SetDelegate(Delegate* delegate);
 
   // BluetoothClientInstace overrides:
-  const UUID& GetAppIdentifier() const override;
+  const Uuid& GetAppIdentifier() const override;
   int GetInstanceId() const override;
 
   // Callback type used to report the status of an asynchronous GATT server
@@ -134,7 +134,7 @@
   // we can add other services to this server instance? Do we need to clean up
   // all the entries or does the upper-layer need to remove the service? Or are
   // we in a stuck-state where the service declaration hasn't ended?
-  bool AddService(const bluetooth::Service&, const ResultCallback& callback);
+  bool AddService(const Service&, const ResultCallback& callback);
 
   // Sends a response for a pending notification. |request_id| and
   // |device_address| should match those that were received through one of the
@@ -189,7 +189,7 @@
 
   // Constructor shouldn't be called directly as instances are meant to be
   // obtained from the factory.
-  GattServer(const UUID& uuid, int server_id);
+  GattServer(const Uuid& uuid, int server_id);
 
   // hal::BluetoothGattInterface::ServerObserver overrides:
   void ConnectionCallback(hal::BluetoothGattInterface* gatt_iface, int conn_id,
@@ -237,7 +237,7 @@
                                             int request_id);
 
   // See getters for documentation.
-  UUID app_identifier_;
+  Uuid app_identifier_;
   int server_id_;
 
   // Mutex that synchronizes access to the entries below.
@@ -277,18 +277,18 @@
   ~GattServerFactory() override;
 
   // BluetoothInstanceFactory override:
-  bool RegisterInstance(const UUID& uuid,
+  bool RegisterInstance(const Uuid& uuid,
                         const RegisterCallback& callback) override;
 
  private:
   // hal::BluetoothGattInterface::ServerObserver override:
   void RegisterServerCallback(hal::BluetoothGattInterface* gatt_iface,
                               int status, int server_id,
-                              const bt_uuid_t& app_uuid) override;
+                              const Uuid& app_uuid) override;
 
   // Map of pending calls to register.
   std::mutex pending_calls_lock_;
-  std::unordered_map<UUID, RegisterCallback> pending_calls_;
+  std::unordered_map<Uuid, RegisterCallback> pending_calls_;
 
   DISALLOW_COPY_AND_ASSIGN(GattServerFactory);
 };
diff --git a/service/gatt_server_old.cc b/service/gatt_server_old.cc
index f6099ef..e97a6c5 100644
--- a/service/gatt_server_old.cc
+++ b/service/gatt_server_old.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -83,7 +83,7 @@
 namespace gatt {
 
 struct Characteristic {
-  UUID uuid;
+  Uuid uuid;
   int blob_section;
   std::vector<uint8_t> blob;
 
@@ -97,11 +97,11 @@
   ServerInternals();
   ~ServerInternals();
   int Initialize();
-  bt_status_t AddCharacteristic(const UUID& uuid, uint8_t properties,
+  bt_status_t AddCharacteristic(const Uuid& uuid, uint8_t properties,
                                 uint16_t permissions);
 
-  // This maps API attribute UUIDs to BlueDroid handles.
-  std::map<UUID, int> uuid_to_attribute;
+  // This maps API attribute Uuids to BlueDroid handles.
+  std::map<Uuid, int> uuid_to_attribute;
 
   // The attribute cache, indexed by BlueDroid handles.
   std::unordered_map<int, Characteristic> characteristics;
@@ -111,7 +111,7 @@
 
   ScanResults scan_results;
 
-  UUID last_write;
+  Uuid last_write;
   const btgatt_interface_t* gatt;
   int server_if;
   int client_if;
@@ -130,11 +130,12 @@
 
 /** Callback invoked in response to register_server */
 void RegisterServerCallback(int status, int server_if,
-                            const bt_uuid_t& app_uuid) {
+                            const bluetooth::Uuid& app_uuid) {
   LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
            server_if, &app_uuid);
 
   g_internal->server_if = server_if;
+
   pending_svc_decl.push_back(
       {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = app_uuid});
 }
@@ -157,7 +158,7 @@
     if (el.type == BTGATT_DB_DESCRIPTOR) {
       LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle);
     } else if (el.type == BTGATT_DB_CHARACTERISTIC) {
-      bluetooth::UUID id(el.uuid);
+      bluetooth::Uuid id(el.uuid);
       uint16_t char_handle = el.attribute_handle;
 
       LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle);
@@ -192,11 +193,10 @@
   pending_svc_decl.clear();
   blob_index.clear();
 
-  // The UUID provided here is unimportant, and is only used to satisfy
+  // The Uuid provided here is unimportant, and is only used to satisfy
   // BlueDroid.
-  // It must be different than any other registered UUID.
-  bt_uuid_t client_id = service[0].uuid;
-  ++client_id.uu[15];
+  // It must be different than any other registered Uuid.
+  bluetooth::Uuid client_id = bluetooth::Uuid::GetRandom();
 
   bt_status_t btstat = g_internal->gatt->client->register_client(client_id);
   if (btstat != BT_STATUS_SUCCESS) {
@@ -277,7 +277,7 @@
   } else if (!is_prep) {
     // This is a single frame characteristic write.
     // Notify upwards because we're done now.
-    const bluetooth::UUID::UUID128Bit& attr_uuid = ch.uuid.GetFullBigEndian();
+    const bluetooth::Uuid::UUID128Bit& attr_uuid = ch.uuid.To128BitBE();
     ssize_t status;
     OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd],
                                attr_uuid.data(), attr_uuid.size()));
@@ -317,9 +317,8 @@
   if (!exec_write) return;
 
   std::lock_guard<std::mutex> lock(g_internal->lock);
-  // Communicate the attribute UUID as notification of a write update.
-  const bluetooth::UUID::UUID128Bit uuid =
-      g_internal->last_write.GetFullBigEndian();
+  // Communicate the attribute Uuid as notification of a write update.
+  const bluetooth::Uuid::UUID128Bit uuid = g_internal->last_write.To128BitBE();
   ssize_t status;
   OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(),
                              uuid.size()));
@@ -347,9 +346,9 @@
 }
 
 void RegisterClientCallback(int status, int client_if,
-                            const bt_uuid_t& app_uuid) {
-  LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
-           client_if, app_uuid.uu[0]);
+                            const bluetooth::Uuid& app_uuid) {
+  LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%s", __func__, status,
+           client_if, app_uuid.ToString().c_str());
   g_internal->client_if = client_if;
 
   // Setup our advertisement. This has no callback.
@@ -500,13 +499,11 @@
   return 0;
 }
 
-bt_status_t ServerInternals::AddCharacteristic(const UUID& uuid,
+bt_status_t ServerInternals::AddCharacteristic(const Uuid& uuid,
                                                uint8_t properties,
                                                uint16_t permissions) {
-  bt_uuid_t c_uuid = uuid.GetBlueDroid();
-
   pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC,
-                              .uuid = c_uuid,
+                              .uuid = uuid,
                               .properties = properties,
                               .permissions = permissions});
   return BT_STATUS_SUCCESS;
@@ -532,7 +529,7 @@
 
 Server::~Server() {}
 
-bool Server::Initialize(const UUID& service_id, int* gatt_pipe) {
+bool Server::Initialize(const Uuid& service_id, int* gatt_pipe) {
   internal_.reset(new ServerInternals);
   if (!internal_) {
     LOG_ERROR(LOG_TAG, "Error creating internals");
@@ -547,9 +544,7 @@
     return false;
   }
 
-  bt_uuid_t uuid = service_id.GetBlueDroid();
-
-  bt_status_t btstat = internal_->gatt->server->register_server(uuid);
+  bt_status_t btstat = internal_->gatt->server->register_server(service_id);
   if (btstat != BT_STATUS_SUCCESS) {
     LOG_ERROR(LOG_TAG, "Failed to register server");
     return false;
@@ -567,7 +562,7 @@
   return true;
 }
 
-bool Server::SetAdvertisement(const std::vector<UUID>& ids,
+bool Server::SetAdvertisement(const std::vector<Uuid>& ids,
                               const std::vector<uint8_t>& service_data,
                               const std::vector<uint8_t>& manufacturer_data,
                               bool transmit_name) {
@@ -575,8 +570,8 @@
   // const auto& mutable_manufacturer_data = manufacturer_data;
   // const auto& mutable_service_data = service_data;
 
-  // for (const UUID &id : ids) {
-  //   const auto le_id = id.GetFullLittleEndian();
+  // for (const Uuid &id : ids) {
+  //   const auto le_id = id.To128BitLE();
   //   id_data.insert(id_data.end(), le_id.begin(), le_id.end());
   // }
 
@@ -593,7 +588,7 @@
   return true;
 }
 
-bool Server::SetScanResponse(const std::vector<UUID>& ids,
+bool Server::SetScanResponse(const std::vector<Uuid>& ids,
                              const std::vector<uint8_t>& service_data,
                              const std::vector<uint8_t>& manufacturer_data,
                              bool transmit_name) {
@@ -601,8 +596,8 @@
   // const auto& mutable_manufacturer_data = manufacturer_data;
   // const auto& mutable_service_data = service_data;
 
-  // for (const UUID &id : ids) {
-  //   const auto le_id = id.GetFullLittleEndian();
+  // for (const Uuid &id : ids) {
+  //   const auto le_id = id.To128BitLE();
   //   id_data.insert(id_data.end(), le_id.begin(), le_id.end());
   // }
 
@@ -621,7 +616,7 @@
   return true;
 }
 
-bool Server::AddCharacteristic(const UUID& id, int properties,
+bool Server::AddCharacteristic(const Uuid& id, int properties,
                                int permissions) {
   std::unique_lock<std::mutex> lock(internal_->lock);
   bt_status_t btstat =
@@ -637,7 +632,7 @@
   return true;
 }
 
-bool Server::AddBlob(const UUID& id, const UUID& control_id, int properties,
+bool Server::AddBlob(const Uuid& id, const Uuid& control_id, int properties,
                      int permissions) {
   std::unique_lock<std::mutex> lock(internal_->lock);
 
@@ -702,7 +697,7 @@
   return true;
 }
 
-bool Server::SetCharacteristicValue(const UUID& id,
+bool Server::SetCharacteristicValue(const Uuid& id,
                                     const std::vector<uint8_t>& value) {
   std::lock_guard<std::mutex> lock(internal_->lock);
   const int attribute_id = internal_->uuid_to_attribute[id];
@@ -719,7 +714,7 @@
   return true;
 }
 
-bool Server::GetCharacteristicValue(const UUID& id,
+bool Server::GetCharacteristicValue(const Uuid& id,
                                     std::vector<uint8_t>* value) {
   std::lock_guard<std::mutex> lock(internal_->lock);
   const int attribute_id = internal_->uuid_to_attribute[id];
diff --git a/service/gatt_server_old.h b/service/gatt_server_old.h
index a16bdfc..546f164 100644
--- a/service/gatt_server_old.h
+++ b/service/gatt_server_old.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
 //
 #pragma once
 
+#include <bluetooth/uuid.h>
 #include <array>
 #include <memory>
 #include <unordered_map>
@@ -22,7 +23,6 @@
 
 #include "hardware/bluetooth.h"
 #include "hardware/bt_gatt.h"
-#include "service/common/bluetooth/uuid.h"
 
 namespace bluetooth {
 namespace gatt {
@@ -71,35 +71,35 @@
 
   // Register GATT interface, initialize internal state,
   // and open a pipe for characteristic write notification.
-  bool Initialize(const UUID& service_id, int* gatt_pipe);
+  bool Initialize(const Uuid& service_id, int* gatt_pipe);
 
   // Control the content of service advertisement.
-  bool SetAdvertisement(const std::vector<UUID>& ids,
+  bool SetAdvertisement(const std::vector<Uuid>& ids,
                         const std::vector<uint8_t>& service_data,
                         const std::vector<uint8_t>& manufacturer_data,
                         bool transmit_name);
 
   // Control the content of service scan response.
-  bool SetScanResponse(const std::vector<UUID>& ids,
+  bool SetScanResponse(const std::vector<Uuid>& ids,
                        const std::vector<uint8_t>& service_data,
                        const std::vector<uint8_t>& manufacturer_data,
                        bool transmit_name);
 
   // Add an ordinary characteristic for reading and/or writing.
-  bool AddCharacteristic(const UUID& id, int properties, int permissions);
+  bool AddCharacteristic(const Uuid& id, int properties, int permissions);
 
   // Add a special 'blob' characteristic with a corresponding control
   // attribute to manipulate which part of the blob the attribute represents.
-  bool AddBlob(const UUID& id, const UUID& control_id, int properties,
+  bool AddBlob(const Uuid& id, const Uuid& control_id, int properties,
                int permissions);
 
   // Put a new value into a characeteristic.
   // It will be read from a client starting at the next 0-offset read.
-  bool SetCharacteristicValue(const UUID& id,
+  bool SetCharacteristicValue(const Uuid& id,
                               const std::vector<uint8_t>& value);
 
   // Get the current value of a characteristic.
-  bool GetCharacteristicValue(const UUID& id, std::vector<uint8_t>* value);
+  bool GetCharacteristicValue(const Uuid& id, std::vector<uint8_t>* value);
 
   // Start this service. Activate advertisements, allow connections.
   // Characteristics should all be created before this.
diff --git a/service/hal/bluetooth_gatt_interface.cc b/service/hal/bluetooth_gatt_interface.cc
index f33fdbc..35b295b 100644
--- a/service/hal/bluetooth_gatt_interface.cc
+++ b/service/hal/bluetooth_gatt_interface.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -58,17 +58,20 @@
 base::ObserverList<BluetoothGattInterface::ServerObserver>*
 GetServerObservers();
 
-#define FOR_EACH_SCANNER_OBSERVER(func)                      \
-  FOR_EACH_OBSERVER(BluetoothGattInterface::ScannerObserver, \
-                    *GetScannerObservers(), func)
+#define FOR_EACH_SCANNER_OBSERVER(func)           \
+  for (auto& observer : *GetScannerObservers()) { \
+    observer.func;                                \
+  }
 
-#define FOR_EACH_CLIENT_OBSERVER(func)                      \
-  FOR_EACH_OBSERVER(BluetoothGattInterface::ClientObserver, \
-                    *GetClientObservers(), func)
+#define FOR_EACH_CLIENT_OBSERVER(func)           \
+  for (auto& observer : *GetClientObservers()) { \
+    observer.func;                               \
+  }
 
-#define FOR_EACH_SERVER_OBSERVER(func)                      \
-  FOR_EACH_OBSERVER(BluetoothGattInterface::ServerObserver, \
-                    *GetServerObservers(), func)
+#define FOR_EACH_SERVER_OBSERVER(func)           \
+  for (auto& observer : *GetServerObservers()) { \
+    observer.func;                               \
+  }
 
 #define VERIFY_INTERFACE_OR_RETURN()                                   \
   do {                                                                 \
@@ -79,7 +82,7 @@
   } while (0)
 
 void RegisterClientCallback(int status, int client_if,
-                            const bt_uuid_t& app_uuid) {
+                            const bluetooth::Uuid& app_uuid) {
   shared_lock<shared_mutex_impl> lock(g_instance_lock);
   VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
   VERIFY_INTERFACE_OR_RETURN();
@@ -222,7 +225,7 @@
 }
 
 void RegisterServerCallback(int status, int server_if,
-                            const bt_uuid_t& app_uuid) {
+                            const bluetooth::Uuid& app_uuid) {
   shared_lock<shared_mutex_impl> lock(g_instance_lock);
   VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if;
   VERIFY_INTERFACE_OR_RETURN();
@@ -567,7 +570,7 @@
 
 void BluetoothGattInterface::ClientObserver::RegisterClientCallback(
     BluetoothGattInterface* /* gatt_iface */, int /* status */,
-    int /* client_if */, const bt_uuid_t& /* app_uuid */) {
+    int /* client_if */, const bluetooth::Uuid& /* app_uuid */) {
   // Do nothing.
 }
 
@@ -639,7 +642,7 @@
 
 void BluetoothGattInterface::ServerObserver::RegisterServerCallback(
     BluetoothGattInterface* /* gatt_iface */, int /* status */,
-    int /* server_if */, const bt_uuid_t& /* app_uuid */) {
+    int /* server_if */, const bluetooth::Uuid& /* app_uuid */) {
   // Do nothing.
 }
 
diff --git a/service/hal/bluetooth_gatt_interface.h b/service/hal/bluetooth_gatt_interface.h
index 345ed88..08b0e9b 100644
--- a/service/hal/bluetooth_gatt_interface.h
+++ b/service/hal/bluetooth_gatt_interface.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@
 
     virtual void RegisterClientCallback(BluetoothGattInterface* gatt_iface,
                                         int status, int client_if,
-                                        const bt_uuid_t& app_uuid);
+                                        const bluetooth::Uuid& app_uuid);
 
     virtual void ConnectCallback(BluetoothGattInterface* gatt_iface,
                                  int conn_id, int status, int client_if,
@@ -120,7 +120,7 @@
 
     virtual void RegisterServerCallback(BluetoothGattInterface* gatt_iface,
                                         int status, int server_if,
-                                        const bt_uuid_t& app_uuid);
+                                        const bluetooth::Uuid& app_uuid);
 
     virtual void ConnectionCallback(BluetoothGattInterface* gatt_iface,
                                     int conn_id, int server_if, int connected,
diff --git a/service/hal/bluetooth_interface.cc b/service/hal/bluetooth_interface.cc
index 39816ef..9296966 100644
--- a/service/hal/bluetooth_interface.cc
+++ b/service/hal/bluetooth_interface.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -54,8 +54,10 @@
 // defined below since it depends on BluetoothInterfaceImpl.
 base::ObserverList<BluetoothInterface::Observer>* GetObservers();
 
-#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
-  FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)
+#define FOR_EACH_BLUETOOTH_OBSERVER(func)  \
+  for (auto& observer : *GetObservers()) { \
+    observer.func;                         \
+  }
 
 #define VERIFY_INTERFACE_OR_RETURN()                                   \
   do {                                                                 \
@@ -209,7 +211,7 @@
 // BluetoothInterface implementation for production.
 class BluetoothInterfaceImpl : public BluetoothInterface {
  public:
-  BluetoothInterfaceImpl() : hal_iface_(nullptr), hal_adapter_(nullptr) {}
+  BluetoothInterfaceImpl() : hal_iface_(nullptr) {}
 
   ~BluetoothInterfaceImpl() override {
     if (hal_iface_) hal_iface_->cleanup();
@@ -230,31 +232,18 @@
 
   bt_callbacks_t* GetHALCallbacks() const override { return &bt_callbacks; }
 
-  const bluetooth_device_t* GetHALAdapter() const override {
-    return hal_adapter_;
-  }
-
   // Initialize the interface. This loads the shared Bluetooth library and sets
   // up the callbacks.
   bool Initialize() {
     // Load the Bluetooth shared library module.
-    const hw_module_t* module;
-    int status = hal_util_load_bt_library(&module);
-    if (status) {
-      LOG(ERROR) << "Failed to load Bluetooth library: " << status;
-      return false;
-    }
-
-    // Open the Bluetooth adapter.
-    hw_device_t* device;
-    status = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+    const bt_interface_t* interface;
+    int status = hal_util_load_bt_library(&interface);
     if (status) {
       LOG(ERROR) << "Failed to open the Bluetooth module";
       return false;
     }
 
-    hal_adapter_ = reinterpret_cast<bluetooth_device_t*>(device);
-    hal_iface_ = hal_adapter_->get_bluetooth_interface();
+    hal_iface_ = interface;
 
     // Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
     // callbacks.
@@ -286,11 +275,6 @@
   // to this since the actual data resides in the shared Bluetooth library.
   const bt_interface_t* hal_iface_;
 
-  // The HAL handle that represents the underlying Bluetooth adapter. We hold a
-  // weak reference to this since the actual data resides in the shared
-  // Bluetooth library.
-  const bluetooth_device_t* hal_adapter_;
-
   DISALLOW_COPY_AND_ASSIGN(BluetoothInterfaceImpl);
 };
 
diff --git a/service/hal/bluetooth_interface.h b/service/hal/bluetooth_interface.h
index 49d621c..897835f 100644
--- a/service/hal/bluetooth_interface.h
+++ b/service/hal/bluetooth_interface.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -111,11 +111,6 @@
   // Returns the HAL callbacks that have been initialized previously.
   virtual bt_callbacks_t* GetHALCallbacks() const = 0;
 
-  // The HAL module pointer that represents the underlying Bluetooth adapter.
-  // This is implemented in and provided by the shared Bluetooth library, so
-  // this isn't owned by us.
-  virtual const bluetooth_device_t* GetHALAdapter() const = 0;
-
  protected:
   BluetoothInterface() = default;
   virtual ~BluetoothInterface() = default;
diff --git a/service/hal/fake_bluetooth_gatt_interface.cc b/service/hal/fake_bluetooth_gatt_interface.cc
index 42ccb51..dbbbcaa 100644
--- a/service/hal/fake_bluetooth_gatt_interface.cc
+++ b/service/hal/fake_bluetooth_gatt_interface.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
 std::shared_ptr<FakeBluetoothGattInterface::TestClientHandler> g_client_handler;
 std::shared_ptr<FakeBluetoothGattInterface::TestServerHandler> g_server_handler;
 
-bt_status_t FakeRegisterClient(const bt_uuid_t& app_uuid) {
+bt_status_t FakeRegisterClient(const bluetooth::Uuid& app_uuid) {
   if (g_client_handler) return g_client_handler->RegisterClient(app_uuid);
 
   return BT_STATUS_FAIL;
@@ -57,7 +57,7 @@
   return BT_STATUS_FAIL;
 }
 
-bt_status_t FakeRegisterServer(const bt_uuid_t& app_uuid) {
+bt_status_t FakeRegisterServer(const bluetooth::Uuid& app_uuid) {
   if (g_server_handler) return g_server_handler->RegisterServer(app_uuid);
 
   return BT_STATUS_FAIL;
@@ -178,95 +178,104 @@
 // given parameters.
 void FakeBluetoothGattInterface::NotifyScanResultCallback(
     const RawAddress& bda, int rssi, std::vector<uint8_t> adv_data) {
-  FOR_EACH_OBSERVER(ScannerObserver, scanner_observers_,
-                    ScanResultCallback(this, bda, rssi, adv_data));
+  for (auto& observer : scanner_observers_) {
+    observer.ScanResultCallback(this, bda, rssi, adv_data);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRegisterClientCallback(
-    int status, int client_if, const bt_uuid_t& app_uuid) {
-  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
-                    RegisterClientCallback(this, status, client_if, app_uuid));
+    int status, int client_if, const bluetooth::Uuid& app_uuid) {
+  for (auto& observer : client_observers_) {
+    observer.RegisterClientCallback(this, status, client_if, app_uuid);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyConnectCallback(int conn_id, int status,
                                                        int client_if,
                                                        const RawAddress& bda) {
-  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
-                    ConnectCallback(this, conn_id, status, client_if, bda));
+  for (auto& observer : client_observers_) {
+    observer.ConnectCallback(this, conn_id, status, client_if, bda);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyDisconnectCallback(
     int conn_id, int status, int client_if, const RawAddress& bda) {
-  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
-                    DisconnectCallback(this, conn_id, status, client_if, bda));
+  for (auto& observer : client_observers_) {
+    observer.DisconnectCallback(this, conn_id, status, client_if, bda);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRegisterServerCallback(
-    int status, int server_if, const bt_uuid_t& app_uuid) {
-  FOR_EACH_OBSERVER(ServerObserver, server_observers_,
-                    RegisterServerCallback(this, status, server_if, app_uuid));
+    int status, int server_if, const Uuid& app_uuid) {
+  for (auto& observer : server_observers_) {
+    observer.RegisterServerCallback(this, status, server_if, app_uuid);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyServerConnectionCallback(
     int conn_id, int server_if, int connected, const RawAddress& bda) {
-  FOR_EACH_OBSERVER(
-      ServerObserver, server_observers_,
-      ConnectionCallback(this, conn_id, server_if, connected, bda));
+  for (auto& observer : server_observers_) {
+    observer.ConnectionCallback(this, conn_id, server_if, connected, bda);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyServiceAddedCallback(
     int status, int server_if, std::vector<btgatt_db_element_t> service) {
-  FOR_EACH_OBSERVER(ServerObserver, server_observers_,
-                    ServiceAddedCallback(this, status, server_if, service));
+  for (auto& observer : server_observers_) {
+    observer.ServiceAddedCallback(this, status, server_if, service);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRequestReadCharacteristicCallback(
     int conn_id, int trans_id, const RawAddress& bda, int attr_handle,
     int offset, bool is_long) {
-  FOR_EACH_OBSERVER(
-      ServerObserver, server_observers_,
-      RequestReadCharacteristicCallback(this, conn_id, trans_id, bda,
-                                        attr_handle, offset, is_long));
+  for (auto& observer : server_observers_) {
+    observer.RequestReadCharacteristicCallback(this, conn_id, trans_id, bda,
+                                               attr_handle, offset, is_long);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRequestReadDescriptorCallback(
     int conn_id, int trans_id, const RawAddress& bda, int attr_handle,
     int offset, bool is_long) {
-  FOR_EACH_OBSERVER(
-      ServerObserver, server_observers_,
-      RequestReadDescriptorCallback(this, conn_id, trans_id, bda, attr_handle,
-                                    offset, is_long));
+  for (auto& observer : server_observers_) {
+    observer.RequestReadDescriptorCallback(this, conn_id, trans_id, bda,
+                                           attr_handle, offset, is_long);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRequestWriteCharacteristicCallback(
     int conn_id, int trans_id, const RawAddress& bda, int attr_handle,
     int offset, bool need_rsp, bool is_prep, std::vector<uint8_t> value) {
-  FOR_EACH_OBSERVER(ServerObserver, server_observers_,
-                    RequestWriteCharacteristicCallback(
-                        this, conn_id, trans_id, bda, attr_handle, offset,
-                        need_rsp, is_prep, value));
+  for (auto& observer : server_observers_) {
+    observer.RequestWriteCharacteristicCallback(this, conn_id, trans_id, bda,
+                                                attr_handle, offset, need_rsp,
+                                                is_prep, value);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRequestWriteDescriptorCallback(
     int conn_id, int trans_id, const RawAddress& bda, int attr_handle,
     int offset, bool need_rsp, bool is_prep, std::vector<uint8_t> value) {
-  FOR_EACH_OBSERVER(
-      ServerObserver, server_observers_,
-      RequestWriteDescriptorCallback(this, conn_id, trans_id, bda, attr_handle,
-                                     offset, need_rsp, is_prep, value));
+  for (auto& observer : server_observers_) {
+    observer.RequestWriteDescriptorCallback(this, conn_id, trans_id, bda,
+                                            attr_handle, offset, need_rsp,
+                                            is_prep, value);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyRequestExecWriteCallback(
     int conn_id, int trans_id, const RawAddress& bda, int exec_write) {
-  FOR_EACH_OBSERVER(
-      ServerObserver, server_observers_,
-      RequestExecWriteCallback(this, conn_id, trans_id, bda, exec_write));
+  for (auto& observer : server_observers_) {
+    observer.RequestExecWriteCallback(this, conn_id, trans_id, bda, exec_write);
+  }
 }
 
 void FakeBluetoothGattInterface::NotifyIndicationSentCallback(int conn_id,
                                                               int status) {
-  FOR_EACH_OBSERVER(ServerObserver, server_observers_,
-                    IndicationSentCallback(this, conn_id, status));
+  for (auto& observer : server_observers_) {
+    observer.IndicationSentCallback(this, conn_id, status);
+  }
 }
 
 void FakeBluetoothGattInterface::AddScannerObserver(ScannerObserver* observer) {
diff --git a/service/hal/fake_bluetooth_gatt_interface.h b/service/hal/fake_bluetooth_gatt_interface.h
index 7ad3c89..a991a21 100644
--- a/service/hal/fake_bluetooth_gatt_interface.h
+++ b/service/hal/fake_bluetooth_gatt_interface.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
    public:
     virtual ~TestClientHandler() = default;
 
-    virtual bt_status_t RegisterClient(const bt_uuid_t& app_uuid) = 0;
+    virtual bt_status_t RegisterClient(const bluetooth::Uuid& app_uuid) = 0;
     virtual bt_status_t UnregisterClient(int client_if) = 0;
 
     virtual bt_status_t Connect(int client_if, const RawAddress& bd_addr,
@@ -51,7 +51,7 @@
    public:
     virtual ~TestServerHandler() = default;
 
-    virtual bt_status_t RegisterServer(const bt_uuid_t& app_uuid) = 0;
+    virtual bt_status_t RegisterServer(const bluetooth::Uuid& app_uuid) = 0;
     virtual bt_status_t UnregisterServer(int server_if) = 0;
     virtual bt_status_t AddService(
         int server_if, std::vector<btgatt_db_element_t> service) = 0;
@@ -77,13 +77,13 @@
   // given parameters.
 
   void NotifyRegisterScannerCallback(int status, int client_if,
-                                     const bt_uuid_t& app_uuid);
+                                     const bluetooth::Uuid& app_uuid);
   void NotifyScanResultCallback(const RawAddress& bda, int rssi,
                                 std::vector<uint8_t> adv_data);
 
   // Client callbacks:
   void NotifyRegisterClientCallback(int status, int client_if,
-                                    const bt_uuid_t& app_uuid);
+                                    const bluetooth::Uuid& app_uuid);
   void NotifyConnectCallback(int conn_id, int status, int client_if,
                              const RawAddress& bda);
   void NotifyDisconnectCallback(int conn_id, int status, int client_if,
@@ -91,17 +91,17 @@
 
   // Server callbacks:
   void NotifyRegisterServerCallback(int status, int server_if,
-                                    const bt_uuid_t& app_uuid);
+                                    const bluetooth::Uuid& app_uuid);
   void NotifyServerConnectionCallback(int conn_id, int server_if, int connected,
                                       const RawAddress& bda);
   void NotifyServiceAddedCallback(int status, int server_if,
                                   std::vector<btgatt_db_element_t> srvc);
   void NotifyCharacteristicAddedCallback(int status, int server_if,
-                                         const bt_uuid_t& uuid, int srvc_handle,
-                                         int char_handle);
+                                         const bluetooth::Uuid& uuid,
+                                         int srvc_handle, int char_handle);
   void NotifyDescriptorAddedCallback(int status, int server_if,
-                                     const bt_uuid_t& uuid, int srvc_handle,
-                                     int desc_handle);
+                                     const bluetooth::Uuid& uuid,
+                                     int srvc_handle, int desc_handle);
   void NotifyServiceStartedCallback(int status, int server_if, int srvc_handle);
   void NotifyRequestReadCharacteristicCallback(int conn_id, int trans_id,
                                                const RawAddress& bda,
diff --git a/service/hal/fake_bluetooth_interface.cc b/service/hal/fake_bluetooth_interface.cc
index 45fdca0..eb550e7 100644
--- a/service/hal/fake_bluetooth_interface.cc
+++ b/service/hal/fake_bluetooth_interface.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -69,9 +69,11 @@
     nullptr, /* set_os_callouts */
     nullptr, /* read_energy_info */
     nullptr, /* dump */
+    nullptr, /* dumpMetrics */
     nullptr, /* config clear */
     nullptr, /* interop_database_clear */
-    nullptr  /* interop_database_add */
+    nullptr, /* interop_database_add */
+    nullptr, /* get_avrcp_service */
 };
 
 }  // namespace
@@ -87,14 +89,17 @@
       set_property_succeed(false) {}
 
 void FakeBluetoothInterface::NotifyAdapterStateChanged(bt_state_t state) {
-  FOR_EACH_OBSERVER(Observer, observers_, AdapterStateChangedCallback(state));
+  for (auto& observer : observers_) {
+    observer.AdapterStateChangedCallback(state);
+  }
 }
 
 void FakeBluetoothInterface::NotifyAdapterPropertiesChanged(
     int num_properties, bt_property_t* properties) {
-  FOR_EACH_OBSERVER(
-      Observer, observers_,
-      AdapterPropertiesCallback(BT_STATUS_SUCCESS, num_properties, properties));
+  for (auto& observer : observers_) {
+    observer.AdapterPropertiesCallback(BT_STATUS_SUCCESS, num_properties,
+                                       properties);
+  }
 }
 
 void FakeBluetoothInterface::NotifyAdapterNamePropertyChanged(
@@ -134,8 +139,9 @@
 
 void FakeBluetoothInterface::NotifyAclStateChangedCallback(
     bt_status_t status, const RawAddress& remote_bdaddr, bt_acl_state_t state) {
-  FOR_EACH_OBSERVER(Observer, observers_,
-                    AclStateChangedCallback(status, remote_bdaddr, state));
+  for (auto& observer : observers_) {
+    observer.AclStateChangedCallback(status, remote_bdaddr, state);
+  }
 }
 
 void FakeBluetoothInterface::AddObserver(Observer* observer) {
@@ -154,10 +160,5 @@
   return nullptr;
 }
 
-const bluetooth_device_t* FakeBluetoothInterface::GetHALAdapter() const {
-  // TODO(armansito): Do something meaningful here to simulate test behavior.
-  return nullptr;
-}
-
 }  // namespace hal
 }  // namespace bluetooth
diff --git a/service/hal/fake_bluetooth_interface.h b/service/hal/fake_bluetooth_interface.h
index b0fd657..b7dc832 100644
--- a/service/hal/fake_bluetooth_interface.h
+++ b/service/hal/fake_bluetooth_interface.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -63,7 +63,6 @@
   void RemoveObserver(Observer* observer) override;
   const bt_interface_t* GetHALInterface() const override;
   bt_callbacks_t* GetHALCallbacks() const override;
-  const bluetooth_device_t* GetHALAdapter() const override;
 
  private:
   base::ObserverList<Observer> observers_;
diff --git a/service/ipc/binder/bluetooth_binder_server.cc b/service/ipc/binder/bluetooth_binder_server.cc
index ea2d2c2..2d32cee 100644
--- a/service/ipc/binder/bluetooth_binder_server.cc
+++ b/service/ipc/binder/bluetooth_binder_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_binder_server.h b/service/ipc/binder/bluetooth_binder_server.h
index 55a3300..b03a815 100644
--- a/service/ipc/binder/bluetooth_binder_server.h
+++ b/service/ipc/binder/bluetooth_binder_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -30,9 +30,9 @@
 #include <android/bluetooth/IBluetoothLeAdvertiser.h>
 #include <android/bluetooth/IBluetoothLeScanner.h>
 #include <android/bluetooth/IBluetoothLowEnergy.h>
+#include <bluetooth/uuid.h>
 
 #include "service/adapter.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/ipc/binder/remote_callback_list.h"
 
 using android::String16;
diff --git a/service/ipc/binder/bluetooth_gatt_client_binder_server.cc b/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
index 77a5f75..f72767f 100644
--- a/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
+++ b/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_gatt_client_binder_server.h b/service/ipc/binder/bluetooth_gatt_client_binder_server.h
index 390b0ad..65b8b60 100644
--- a/service/ipc/binder/bluetooth_gatt_client_binder_server.h
+++ b/service/ipc/binder/bluetooth_gatt_client_binder_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_gatt_server_binder_server.cc b/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
index f0f0717..8dffef7 100644
--- a/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
+++ b/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_gatt_server_binder_server.h b/service/ipc/binder/bluetooth_gatt_server_binder_server.h
index 8a6dc02..925339a 100644
--- a/service/ipc/binder/bluetooth_gatt_server_binder_server.h
+++ b/service/ipc/binder/bluetooth_gatt_server_binder_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc b/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
index 170e94c..91f70d4 100644
--- a/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
+++ b/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_le_advertiser_binder_server.h b/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
index fc00db5..6602f5a 100644
--- a/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
+++ b/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_le_scanner_binder_server.cc b/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
index 0c20a46..b6072be 100644
--- a/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
+++ b/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
diff --git a/service/ipc/binder/bluetooth_le_scanner_binder_server.h b/service/ipc/binder/bluetooth_le_scanner_binder_server.h
index ef9a900..0cc3ae9 100644
--- a/service/ipc/binder/bluetooth_le_scanner_binder_server.h
+++ b/service/ipc/binder/bluetooth_le_scanner_binder_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
diff --git a/service/ipc/binder/bluetooth_low_energy_binder_server.cc b/service/ipc/binder/bluetooth_low_energy_binder_server.cc
index 9b8a863..2520d6d 100644
--- a/service/ipc/binder/bluetooth_low_energy_binder_server.cc
+++ b/service/ipc/binder/bluetooth_low_energy_binder_server.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/bluetooth_low_energy_binder_server.h b/service/ipc/binder/bluetooth_low_energy_binder_server.h
index d393c7d..4508b34 100644
--- a/service/ipc/binder/bluetooth_low_energy_binder_server.h
+++ b/service/ipc/binder/bluetooth_low_energy_binder_server.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/interface_with_instances_base.cc b/service/ipc/binder/interface_with_instances_base.cc
index 18b1eae..ba24657 100644
--- a/service/ipc/binder/interface_with_instances_base.cc
+++ b/service/ipc/binder/interface_with_instances_base.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
 
   // Store the callback in the pending list. It will get removed later when the
   // stack notifies us asynchronously.
-  bluetooth::UUID app_uuid = bluetooth::UUID::GetRandom();
+  bluetooth::Uuid app_uuid = bluetooth::Uuid::GetRandom();
   if (!pending_callbacks_.Register(app_uuid, callback)) {
     LOG(ERROR) << "Failed to store |callback| to map";
     return false;
@@ -45,21 +45,22 @@
   // (sp) we are using a wp here rather than std::weak_ptr.
   android::wp<InterfaceWithInstancesBase> weak_ptr_to_this(this);
 
-  bluetooth::BluetoothInstanceFactory::RegisterCallback cb = [weak_ptr_to_this](
-      bluetooth::BLEStatus status, const bluetooth::UUID& in_uuid,
-      std::unique_ptr<bluetooth::BluetoothInstance> instance) {
-    // If the weak pointer was invalidated then there is nothing we can do.
-    android::sp<InterfaceWithInstancesBase> strong_ptr_to_this =
-        weak_ptr_to_this.promote();
-    if (!strong_ptr_to_this.get()) {
-      VLOG(2) << "InterfaceWithInstancesBase was deleted while instance was"
-              << " being registered";
-      return;
-    }
+  bluetooth::BluetoothInstanceFactory::RegisterCallback cb =
+      [weak_ptr_to_this](
+          bluetooth::BLEStatus status, const bluetooth::Uuid& in_uuid,
+          std::unique_ptr<bluetooth::BluetoothInstance> instance) {
+        // If the weak pointer was invalidated then there is nothing we can do.
+        android::sp<InterfaceWithInstancesBase> strong_ptr_to_this =
+            weak_ptr_to_this.promote();
+        if (!strong_ptr_to_this.get()) {
+          VLOG(2) << "InterfaceWithInstancesBase was deleted while instance was"
+                  << " being registered";
+          return;
+        }
 
-    strong_ptr_to_this->OnRegisterInstance(status, in_uuid,
-                                           std::move(instance));
-  };
+        strong_ptr_to_this->OnRegisterInstance(status, in_uuid,
+                                               std::move(instance));
+      };
 
   if (factory->RegisterInstance(app_uuid, cb)) return true;
 
@@ -99,7 +100,7 @@
 }
 
 void InterfaceWithInstancesBase::OnRegisterInstance(
-    bluetooth::BLEStatus status, const bluetooth::UUID& uuid,
+    bluetooth::BLEStatus status, const bluetooth::Uuid& uuid,
     std::unique_ptr<bluetooth::BluetoothInstance> instance) {
   VLOG(2) << __func__ << " - status: " << status;
 
diff --git a/service/ipc/binder/interface_with_instances_base.h b/service/ipc/binder/interface_with_instances_base.h
index f0aa762..90224b6 100644
--- a/service/ipc/binder/interface_with_instances_base.h
+++ b/service/ipc/binder/interface_with_instances_base.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@
 #include <unordered_map>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/bluetooth_instance.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/ipc/binder/remote_callback_map.h"
 
 namespace ipc {
@@ -44,7 +44,7 @@
 
  protected:
   // The initial entry point for registering a instance. Invoke this from the
-  // registration API to add a instance/UUID pair to the pending list and set up
+  // registration API to add a instance/Uuid pair to the pending list and set up
   // the generic asynchronous callback handler and initiate the process with the
   // given |factory| instance. Returns false, if there were any errors that
   // could be synchronously reported.
@@ -74,7 +74,7 @@
  private:
   // Base implementation of the register callback.
   void OnRegisterInstance(
-      bluetooth::BLEStatus status, const bluetooth::UUID& uuid,
+      bluetooth::BLEStatus status, const bluetooth::Uuid& uuid,
       std::unique_ptr<bluetooth::BluetoothInstance> instance);
 
   // Called when the callback registration has completed. |instance| is owned by
@@ -89,7 +89,7 @@
 
   // Instances that are pending registration. Once their registration is
   // complete, the entry will be removed from this map.
-  RemoteCallbackMap<bluetooth::UUID, android::IInterface> pending_callbacks_;
+  RemoteCallbackMap<bluetooth::Uuid, android::IInterface> pending_callbacks_;
 
   // We keep two maps here: one from instance_id IDs to callback Binders and one
   // from instance_id IDs to the BluetoothInstance structures themselves.
diff --git a/service/ipc/binder/ipc_handler_binder.cc b/service/ipc/binder/ipc_handler_binder.cc
index 5b92120..becd6e8 100644
--- a/service/ipc/binder/ipc_handler_binder.cc
+++ b/service/ipc/binder/ipc_handler_binder.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/ipc_handler_binder.h b/service/ipc/binder/ipc_handler_binder.h
index 060548b..2edd323 100644
--- a/service/ipc/binder/ipc_handler_binder.h
+++ b/service/ipc/binder/ipc_handler_binder.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/remote_callback_list.h b/service/ipc/binder/remote_callback_list.h
index e62b7ef..8c1f6ac 100644
--- a/service/ipc/binder/remote_callback_list.h
+++ b/service/ipc/binder/remote_callback_list.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/binder/remote_callback_map.h b/service/ipc/binder/remote_callback_map.h
index b3422ac..b07de44 100644
--- a/service/ipc/binder/remote_callback_map.h
+++ b/service/ipc/binder/remote_callback_map.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/dbus/bluetooth_adapter.cc b/service/ipc/dbus/bluetooth_adapter.cc
index 8619a35..fd6688a 100644
--- a/service/ipc/dbus/bluetooth_adapter.cc
+++ b/service/ipc/dbus/bluetooth_adapter.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
diff --git a/service/ipc/dbus/bluetooth_adapter.h b/service/ipc/dbus/bluetooth_adapter.h
index 1d8dd8f..484ac11 100644
--- a/service/ipc/dbus/bluetooth_adapter.h
+++ b/service/ipc/dbus/bluetooth_adapter.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
diff --git a/service/ipc/dbus/ipc_handler_dbus.cc b/service/ipc/dbus/ipc_handler_dbus.cc
index ff7ff43..c8922d3 100644
--- a/service/ipc/dbus/ipc_handler_dbus.cc
+++ b/service/ipc/dbus/ipc_handler_dbus.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
diff --git a/service/ipc/dbus/ipc_handler_dbus.h b/service/ipc/dbus/ipc_handler_dbus.h
index 03f7720..2a83369 100644
--- a/service/ipc/dbus/ipc_handler_dbus.h
+++ b/service/ipc/dbus/ipc_handler_dbus.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
diff --git a/service/ipc/ipc_handler.cc b/service/ipc/ipc_handler.cc
index 66d9c03..11c1a50 100644
--- a/service/ipc/ipc_handler.cc
+++ b/service/ipc/ipc_handler.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/ipc_handler.h b/service/ipc/ipc_handler.h
index b1029ca..9b7994c 100644
--- a/service/ipc/ipc_handler.h
+++ b/service/ipc/ipc_handler.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/ipc_handler_linux.cc b/service/ipc/ipc_handler_linux.cc
index bcd21aa..7fe724e 100644
--- a/service/ipc/ipc_handler_linux.cc
+++ b/service/ipc/ipc_handler_linux.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/ipc_handler_linux.h b/service/ipc/ipc_handler_linux.h
index b00eb27..21c71d2 100644
--- a/service/ipc/ipc_handler_linux.h
+++ b/service/ipc/ipc_handler_linux.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/ipc_manager.cc b/service/ipc/ipc_manager.cc
index 71dc6c7..04870b4 100644
--- a/service/ipc/ipc_manager.cc
+++ b/service/ipc/ipc_manager.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/ipc_manager.h b/service/ipc/ipc_manager.h
index bf0967c..ee960ba 100644
--- a/service/ipc/ipc_manager.h
+++ b/service/ipc/ipc_manager.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/ipc/linux_ipc_host.cc b/service/ipc/linux_ipc_host.cc
index 7b328cf..705748f 100644
--- a/service/ipc/linux_ipc_host.cc
+++ b/service/ipc/linux_ipc_host.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@
 #include "service/adapter.h"
 
 using bluetooth::Adapter;
-using bluetooth::UUID;
+using bluetooth::Uuid;
 
 using namespace bluetooth::gatt;
 
@@ -108,8 +108,8 @@
   gatt_servers_[service_uuid] = std::unique_ptr<Server>(new Server);
 
   int gattfd;
-  bool status =
-      gatt_servers_[service_uuid]->Initialize(UUID(service_uuid), &gattfd);
+  bool status = gatt_servers_[service_uuid]->Initialize(
+      Uuid::FromString(service_uuid), &gattfd);
   if (!status) {
     LOG_ERROR(LOG_TAG, "Failed to initialize bluetooth");
     return false;
@@ -155,11 +155,12 @@
 
   if (control_uuid.empty()) {
     gatt_servers_[service_uuid]->AddCharacteristic(
-        UUID(characteristic_uuid), properties_mask, permissions_mask);
+        Uuid::FromString(characteristic_uuid), properties_mask,
+        permissions_mask);
   } else {
-    gatt_servers_[service_uuid]->AddBlob(UUID(characteristic_uuid),
-                                         UUID(control_uuid), properties_mask,
-                                         permissions_mask);
+    gatt_servers_[service_uuid]->AddBlob(Uuid::FromString(characteristic_uuid),
+                                         Uuid::FromString(control_uuid),
+                                         properties_mask, permissions_mask);
   }
   return true;
 }
@@ -170,8 +171,8 @@
   std::string decoded_data;
   base::Base64Decode(value, &decoded_data);
   std::vector<uint8_t> blob_data(decoded_data.begin(), decoded_data.end());
-  gatt_servers_[service_uuid]->SetCharacteristicValue(UUID(characteristic_uuid),
-                                                      blob_data);
+  gatt_servers_[service_uuid]->SetCharacteristicValue(
+      Uuid::FromString(characteristic_uuid), blob_data);
   return true;
 }
 
@@ -187,10 +188,10 @@
   std::vector<std::string> advertise_uuid_tokens = base::SplitString(
       advertise_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
-  // string -> vector<UUID>
-  std::vector<UUID> ids;
+  // string -> vector<Uuid>
+  std::vector<Uuid> ids;
   for (const auto& uuid_token : advertise_uuid_tokens)
-    ids.emplace_back(uuid_token);
+    ids.emplace_back(Uuid::FromString(uuid_token));
 
   std::string decoded_data;
   base::Base64Decode(advertise_data, &decoded_data);
@@ -215,10 +216,10 @@
   std::vector<std::string> scan_response_uuid_tokens = base::SplitString(
       scan_response_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
-  // string -> vector<UUID>
-  std::vector<UUID> ids;
+  // string -> vector<Uuid>
+  std::vector<Uuid> ids;
   for (const auto& uuid_token : scan_response_uuid_tokens)
-    ids.emplace_back(uuid_token);
+    ids.emplace_back(Uuid::FromString(uuid_token));
 
   std::string decoded_data;
   base::Base64Decode(scan_response_data, &decoded_data);
@@ -304,7 +305,7 @@
 }
 
 bool LinuxIPCHost::OnGattWrite() {
-  UUID::UUID128Bit id;
+  Uuid::UUID128Bit id;
   ssize_t r;
 
   OSI_NO_INTR(r = read(pfds_[kFdGatt].fd, id.data(), id.size()));
@@ -316,7 +317,7 @@
   std::vector<uint8_t> value;
   // TODO(icoolidge): Generalize this for multiple clients.
   auto server = gatt_servers_.begin();
-  server->second->GetCharacteristicValue(UUID(id), &value);
+  server->second->GetCharacteristicValue(Uuid::From128BitBE(id), &value);
   const std::string value_string(value.begin(), value.end());
   std::string encoded_value;
   base::Base64Encode(value_string, &encoded_value);
diff --git a/service/ipc/linux_ipc_host.h b/service/ipc/linux_ipc_host.h
index a51a966..012f70e 100644
--- a/service/ipc/linux_ipc_host.h
+++ b/service/ipc/linux_ipc_host.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -17,11 +17,11 @@
 
 #include <poll.h>
 
+#include <bluetooth/uuid.h>
 #include <memory>
 #include <string>
 #include <unordered_map>
 
-#include "service/common/bluetooth/uuid.h"
 #include "service/gatt_server_old.h"
 
 namespace bluetooth {
diff --git a/service/logging_helpers.cc b/service/logging_helpers.cc
index 39706ec..70f8720 100644
--- a/service/logging_helpers.cc
+++ b/service/logging_helpers.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/logging_helpers.h b/service/logging_helpers.h
index d3c58d1..aa03e63 100644
--- a/service/logging_helpers.h
+++ b/service/logging_helpers.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/low_energy_advertiser.cc b/service/low_energy_advertiser.cc
index 3df55db..4f4bff9 100644
--- a/service/low_energy_advertiser.cc
+++ b/service/low_energy_advertiser.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -120,7 +120,7 @@
 // LowEnergyAdvertiser implementation
 // ========================================================
 
-LowEnergyAdvertiser::LowEnergyAdvertiser(const UUID& uuid, int advertiser_id)
+LowEnergyAdvertiser::LowEnergyAdvertiser(const Uuid& uuid, int advertiser_id)
     : app_identifier_(uuid),
       advertiser_id_(advertiser_id),
       adv_started_(false),
@@ -226,7 +226,7 @@
   return IsAdvertisingStarted() && adv_stop_callback_;
 }
 
-const UUID& LowEnergyAdvertiser::GetAppIdentifier() const {
+const Uuid& LowEnergyAdvertiser::GetAppIdentifier() const {
   return app_identifier_;
 }
 
@@ -294,13 +294,13 @@
 LowEnergyAdvertiserFactory::~LowEnergyAdvertiserFactory() {}
 
 bool LowEnergyAdvertiserFactory::RegisterInstance(
-    const UUID& app_uuid, const RegisterCallback& callback) {
+    const Uuid& app_uuid, const RegisterCallback& callback) {
   VLOG(1) << __func__;
   lock_guard<mutex> lock(pending_calls_lock_);
 
   if (pending_calls_.find(app_uuid) != pending_calls_.end()) {
-    LOG(ERROR) << "Low-Energy advertiser with given UUID already registered - "
-               << "UUID: " << app_uuid.ToString();
+    LOG(ERROR) << "Low-Energy advertiser with given Uuid already registered - "
+               << "Uuid: " << app_uuid.ToString();
     return false;
   }
 
@@ -319,7 +319,7 @@
 }
 
 void LowEnergyAdvertiserFactory::RegisterAdvertiserCallback(
-    const RegisterCallback& callback, const UUID& app_uuid,
+    const RegisterCallback& callback, const Uuid& app_uuid,
     uint8_t advertiser_id, uint8_t status) {
   VLOG(1) << __func__;
   lock_guard<mutex> lock(pending_calls_lock_);
diff --git a/service/low_energy_advertiser.h b/service/low_energy_advertiser.h
index a014ae1..ec0dd74 100644
--- a/service/low_energy_advertiser.h
+++ b/service/low_energy_advertiser.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include <mutex>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/bluetooth_instance.h"
 #include "service/common/bluetooth/advertise_data.h"
@@ -30,7 +31,6 @@
 #include "service/common/bluetooth/scan_filter.h"
 #include "service/common/bluetooth/scan_result.h"
 #include "service/common/bluetooth/scan_settings.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/hal/bluetooth_gatt_interface.h"
 
 namespace bluetooth {
@@ -75,7 +75,7 @@
   }
 
   // BluetoothClientInstace overrides:
-  const UUID& GetAppIdentifier() const override;
+  const Uuid& GetAppIdentifier() const override;
   int GetInstanceId() const override;
 
  private:
@@ -83,7 +83,7 @@
 
   // Constructor shouldn't be called directly as instances are meant to be
   // obtained from the factory.
-  LowEnergyAdvertiser(const UUID& uuid, int advertiser_id);
+  LowEnergyAdvertiser(const Uuid& uuid, int advertiser_id);
 
   // BluetoothGattInterface::AdvertiserObserver overrides:
   void SetDataCallback(uint8_t advertiser_id, uint8_t status);
@@ -95,7 +95,7 @@
   void InvokeAndClearStopCallback(BLEStatus status);
 
   // See getters above for documentation.
-  UUID app_identifier_;
+  Uuid app_identifier_;
   int advertiser_id_;
 
   // Protects advertising-related members below.
@@ -124,7 +124,7 @@
   ~LowEnergyAdvertiserFactory() override;
 
   // BluetoothInstanceFactory override:
-  bool RegisterInstance(const UUID& app_uuid,
+  bool RegisterInstance(const Uuid& app_uuid,
                         const RegisterCallback& callback) override;
 
  private:
@@ -132,12 +132,12 @@
 
   // BluetoothGattInterface::AdvertiserObserver overrides:
   void RegisterAdvertiserCallback(const RegisterCallback& callback,
-                                  const UUID& app_uuid, uint8_t advertiser_id,
+                                  const Uuid& app_uuid, uint8_t advertiser_id,
                                   uint8_t status);
 
   // Map of pending calls to register.
   std::mutex pending_calls_lock_;
-  std::unordered_set<UUID> pending_calls_;
+  std::unordered_set<Uuid> pending_calls_;
 
   DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserFactory);
 };
diff --git a/service/low_energy_client.cc b/service/low_energy_client.cc
index 97f3ca6..cc127c3 100644
--- a/service/low_energy_client.cc
+++ b/service/low_energy_client.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
 // LowEnergyClient implementation
 // ========================================================
 
-LowEnergyClient::LowEnergyClient(Adapter& adapter, const UUID& uuid,
+LowEnergyClient::LowEnergyClient(Adapter& adapter, const Uuid& uuid,
                                  int client_id)
     : adapter_(adapter),
       app_identifier_(uuid),
@@ -126,7 +126,7 @@
   delegate_ = delegate;
 }
 
-const UUID& LowEnergyClient::GetAppIdentifier() const {
+const Uuid& LowEnergyClient::GetAppIdentifier() const {
   return app_identifier_;
 }
 
@@ -205,21 +205,20 @@
 }
 
 bool LowEnergyClientFactory::RegisterInstance(
-    const UUID& uuid, const RegisterCallback& callback) {
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+    const Uuid& uuid, const RegisterCallback& callback) {
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   if (pending_calls_.find(uuid) != pending_calls_.end()) {
-    LOG(ERROR) << "Low-Energy client with given UUID already registered - "
-               << "UUID: " << uuid.ToString();
+    LOG(ERROR) << "Low-Energy client with given Uuid already registered - "
+               << "Uuid: " << uuid.ToString();
     return false;
   }
 
   const btgatt_client_interface_t* hal_iface =
       hal::BluetoothGattInterface::Get()->GetClientHALInterface();
-  bt_uuid_t app_uuid = uuid.GetBlueDroid();
 
-  if (hal_iface->register_client(app_uuid) != BT_STATUS_SUCCESS) return false;
+  if (hal_iface->register_client(uuid) != BT_STATUS_SUCCESS) return false;
 
   pending_calls_[uuid] = callback;
 
@@ -228,10 +227,10 @@
 
 void LowEnergyClientFactory::RegisterClientCallback(
     hal::BluetoothGattInterface* gatt_iface, int status, int client_id,
-    const bt_uuid_t& app_uuid) {
-  UUID uuid(app_uuid);
+    const bluetooth::Uuid& app_uuid) {
+  Uuid uuid(app_uuid);
 
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   auto iter = pending_calls_.find(uuid);
diff --git a/service/low_energy_client.h b/service/low_energy_client.h
index 16ef4a5..4a7939b 100644
--- a/service/low_energy_client.h
+++ b/service/low_energy_client.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -22,13 +22,13 @@
 #include <mutex>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/bluetooth_instance.h"
 #include "service/common/bluetooth/low_energy_constants.h"
 #include "service/common/bluetooth/scan_filter.h"
 #include "service/common/bluetooth/scan_result.h"
 #include "service/common/bluetooth/scan_settings.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/hal/bluetooth_gatt_interface.h"
 
 namespace bluetooth {
@@ -91,7 +91,7 @@
   bool SetMtu(const std::string& address, int mtu);
 
   // BluetoothClientInstace overrides:
-  const UUID& GetAppIdentifier() const override;
+  const Uuid& GetAppIdentifier() const override;
   int GetInstanceId() const override;
 
  private:
@@ -99,7 +99,7 @@
 
   // Constructor shouldn't be called directly as instances are meant to be
   // obtained from the factory.
-  LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id);
+  LowEnergyClient(Adapter& adapter, const Uuid& uuid, int client_id);
 
   // BluetoothGattInterface::ClientObserver overrides:
   void ConnectCallback(hal::BluetoothGattInterface* gatt_iface, int conn_id,
@@ -119,7 +119,7 @@
   Adapter& adapter_;
 
   // See getters above for documentation.
-  UUID app_identifier_;
+  Uuid app_identifier_;
   int client_id_;
 
   // Raw handle to the Delegate, which must outlive this LowEnergyClient
@@ -151,7 +151,7 @@
   ~LowEnergyClientFactory() override;
 
   // BluetoothInstanceFactory override:
-  bool RegisterInstance(const UUID& uuid,
+  bool RegisterInstance(const Uuid& uuid,
                         const RegisterCallback& callback) override;
 
  private:
@@ -160,11 +160,11 @@
   // BluetoothGattInterface::ClientObserver overrides:
   void RegisterClientCallback(hal::BluetoothGattInterface* gatt_iface,
                               int status, int client_id,
-                              const bt_uuid_t& app_uuid) override;
+                              const bluetooth::Uuid& app_uuid) override;
 
   // Map of pending calls to register.
   std::mutex pending_calls_lock_;
-  std::map<UUID, RegisterCallback> pending_calls_;
+  std::map<Uuid, RegisterCallback> pending_calls_;
 
   // Raw pointer to the Adapter that owns this factory.
   Adapter& adapter_;
diff --git a/service/low_energy_scanner.cc b/service/low_energy_scanner.cc
index 093a554..1527563 100644
--- a/service/low_energy_scanner.cc
+++ b/service/low_energy_scanner.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
@@ -65,7 +65,7 @@
 // LowEnergyScanner implementation
 // ========================================================
 
-LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const UUID& uuid,
+LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const Uuid& uuid,
                                    int scanner_id)
     : adapter_(adapter),
       app_identifier_(uuid),
@@ -131,7 +131,7 @@
   return true;
 }
 
-const UUID& LowEnergyScanner::GetAppIdentifier() const {
+const Uuid& LowEnergyScanner::GetAppIdentifier() const {
   return app_identifier_;
 }
 
@@ -170,13 +170,13 @@
 }
 
 bool LowEnergyScannerFactory::RegisterInstance(
-    const UUID& uuid, const RegisterCallback& callback) {
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+    const Uuid& uuid, const RegisterCallback& callback) {
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   if (pending_calls_.find(uuid) != pending_calls_.end()) {
-    LOG(ERROR) << "Low-Energy scanner with given UUID already registered - "
-               << "UUID: " << uuid.ToString();
+    LOG(ERROR) << "Low-Energy scanner with given Uuid already registered - "
+               << "Uuid: " << uuid.ToString();
     return false;
   }
 
@@ -193,11 +193,11 @@
 }
 
 void LowEnergyScannerFactory::RegisterScannerCallback(
-    const RegisterCallback& callback, const UUID& app_uuid, uint8_t scanner_id,
+    const RegisterCallback& callback, const Uuid& app_uuid, uint8_t scanner_id,
     uint8_t status) {
-  UUID uuid(app_uuid);
+  Uuid uuid(app_uuid);
 
-  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
   lock_guard<mutex> lock(pending_calls_lock_);
 
   auto iter = pending_calls_.find(uuid);
diff --git a/service/low_energy_scanner.h b/service/low_energy_scanner.h
index 279ea7b..b27b72e 100644
--- a/service/low_energy_scanner.h
+++ b/service/low_energy_scanner.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
@@ -22,6 +22,7 @@
 #include <mutex>
 
 #include <base/macros.h>
+#include <bluetooth/uuid.h>
 
 #include "service/bluetooth_instance.h"
 #include "service/common/bluetooth/advertise_data.h"
@@ -30,7 +31,6 @@
 #include "service/common/bluetooth/scan_filter.h"
 #include "service/common/bluetooth/scan_result.h"
 #include "service/common/bluetooth/scan_settings.h"
-#include "service/common/bluetooth/uuid.h"
 #include "service/hal/bluetooth_gatt_interface.h"
 
 namespace bluetooth {
@@ -81,7 +81,7 @@
   const ScanSettings& scan_settings() const { return scan_settings_; }
 
   // BluetoothInstace overrides:
-  const UUID& GetAppIdentifier() const override;
+  const Uuid& GetAppIdentifier() const override;
   int GetInstanceId() const override;
 
   void ScanResultCallback(hal::BluetoothGattInterface* gatt_iface,
@@ -93,7 +93,7 @@
 
   // Constructor shouldn't be called directly as instances are meant to be
   // obtained from the factory.
-  LowEnergyScanner(Adapter& adapter, const UUID& uuid, int scanner_id);
+  LowEnergyScanner(Adapter& adapter, const Uuid& uuid, int scanner_id);
 
   // Calls and clears the pending callbacks.
   void InvokeAndClearStartCallback(BLEStatus status);
@@ -103,7 +103,7 @@
   Adapter& adapter_;
 
   // See getters above for documentation.
-  UUID app_identifier_;
+  Uuid app_identifier_;
   int scanner_id_;
 
   // Protects device scan related members below.
@@ -137,7 +137,7 @@
   ~LowEnergyScannerFactory() override;
 
   // BluetoothInstanceFactory override:
-  bool RegisterInstance(const UUID& app_uuid,
+  bool RegisterInstance(const Uuid& app_uuid,
                         const RegisterCallback& callback) override;
 
  private:
@@ -145,12 +145,12 @@
 
   // BluetoothGattInterface::ScannerObserver overrides:
   void RegisterScannerCallback(const RegisterCallback& callback,
-                               const UUID& app_uuid, uint8_t scanner_id,
+                               const Uuid& app_uuid, uint8_t scanner_id,
                                uint8_t status);
 
   // Map of pending calls to register.
   std::mutex pending_calls_lock_;
-  std::unordered_set<UUID> pending_calls_;
+  std::unordered_set<Uuid> pending_calls_;
 
   // Raw pointer to the Adapter that owns this factory.
   Adapter& adapter_;
diff --git a/service/main.cc b/service/main.cc
index df66497..019098e 100644
--- a/service/main.cc
+++ b/service/main.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -55,16 +55,14 @@
     return EXIT_SUCCESS;
   }
 
-#if !defined(OS_GENERIC)
   // TODO(armansito): Remove Chromecast specific property out of here. This
   // should just be obtained from global config.
   char disable_value[PROPERTY_VALUE_MAX];
-  int status = property_get(kDisableProperty, disable_value, nullptr);
+  int status = osi_property_get(kDisableProperty, disable_value, nullptr);
   if (status && !strcmp(disable_value, "1")) {
     LOG(INFO) << "service disabled";
     return EXIT_SUCCESS;
   }
-#endif  // !defined(OS_GENERIC)
 
   if (!bluetooth::Daemon::Initialize()) {
     LOG(ERROR) << "Failed to initialize Daemon";
diff --git a/service/settings.cc b/service/settings.cc
index 79ac030..af67fbe 100644
--- a/service/settings.cc
+++ b/service/settings.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/settings.h b/service/settings.h
index 4e7a6b4..1f298d6 100644
--- a/service/settings.h
+++ b/service/settings.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/switches.h b/service/switches.h
index fe6056a..aa1658c 100644
--- a/service/switches.h
+++ b/service/switches.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/adapter_unittest.cc b/service/test/adapter_unittest.cc
index c3827dc..e6f5d10 100644
--- a/service/test/adapter_unittest.cc
+++ b/service/test/adapter_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/advertise_data_unittest.cc b/service/test/advertise_data_unittest.cc
index bd0787e..28c27bf 100644
--- a/service/test/advertise_data_unittest.cc
+++ b/service/test/advertise_data_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/fake_hal_util.cc b/service/test/fake_hal_util.cc
index 0fdc19b..263be64 100644
--- a/service/test/fake_hal_util.cc
+++ b/service/test/fake_hal_util.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -22,4 +22,4 @@
 // tests. Instead of doing it this way, however, we should instead provide a C++
 // class abstraction for this (and all other btif interfaces) that we can mock
 // for testing.
-int hal_util_load_bt_library(const struct hw_module_t** module) { return -1; }
+int hal_util_load_bt_library(const bt_interface_t** interface) { return -1; }
diff --git a/service/test/gatt_client_unittest.cc b/service/test/gatt_client_unittest.cc
index 2d59106..310e4b9 100644
--- a/service/test/gatt_client_unittest.cc
+++ b/service/test/gatt_client_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
   MockGattHandler() = default;
   ~MockGattHandler() override = default;
 
-  MOCK_METHOD1(RegisterClient, bt_status_t(const bt_uuid_t&));
+  MOCK_METHOD1(RegisterClient, bt_status_t(const bluetooth::Uuid&));
   MOCK_METHOD1(UnregisterClient, bt_status_t(int));
   MOCK_METHOD1(Scan, bt_status_t(bool));
   MOCK_METHOD4(Connect, bt_status_t(int, const RawAddress&, bool, int));
@@ -85,11 +85,11 @@
   // These will be asynchronously populated with a result when the callback
   // executes.
   BLEStatus status = BLE_STATUS_SUCCESS;
-  UUID cb_uuid;
+  Uuid cb_uuid;
   std::unique_ptr<GattClient> client;
   int callback_count = 0;
 
-  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+  auto callback = [&](BLEStatus in_status, const Uuid& uuid,
                       std::unique_ptr<BluetoothInstance> in_client) {
     status = in_status;
     cb_uuid = uuid;
@@ -98,7 +98,7 @@
     callback_count++;
   };
 
-  UUID uuid0 = UUID::GetRandom();
+  Uuid uuid0 = Uuid::GetRandom();
 
   // HAL returns failure.
   EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
@@ -108,30 +108,28 @@
   EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
   EXPECT_EQ(0, callback_count);
 
-  // Calling twice with the same UUID should fail with no additional call into
+  // Calling twice with the same Uuid should fail with no additional call into
   // the stack.
   EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
 
   testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Call with a different UUID while one is pending.
-  UUID uuid1 = UUID::GetRandom();
+  // Call with a different Uuid while one is pending.
+  Uuid uuid1 = Uuid::GetRandom();
   EXPECT_CALL(*mock_handler_, RegisterClient(_))
       .Times(1)
       .WillOnce(Return(BT_STATUS_SUCCESS));
   EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback));
 
-  // Trigger callback with an unknown UUID. This should get ignored.
-  UUID uuid2 = UUID::GetRandom();
-  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
-  fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
+  // Trigger callback with an unknown Uuid. This should get ignored.
+  Uuid uuid2 = Uuid::GetRandom();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, uuid2);
   EXPECT_EQ(0, callback_count);
 
   // |uuid0| succeeds.
   int client_id0 = 2;  // Pick something that's not 0.
-  hal_uuid = uuid0.GetBlueDroid();
   fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_SUCCESS,
-                                                     client_id0, hal_uuid);
+                                                     client_id0, uuid0);
 
   EXPECT_EQ(1, callback_count);
   ASSERT_TRUE(client.get() != nullptr);  // Assert to terminate in case of error
@@ -149,9 +147,8 @@
 
   // |uuid1| fails.
   int client_id1 = 3;
-  hal_uuid = uuid1.GetBlueDroid();
   fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_FAIL, client_id1,
-                                                     hal_uuid);
+                                                     uuid1);
 
   EXPECT_EQ(2, callback_count);
   ASSERT_TRUE(client.get() == nullptr);  // Assert to terminate in case of error
diff --git a/service/test/gatt_server_unittest.cc b/service/test/gatt_server_unittest.cc
index 0e70ac9..7d7fec2 100644
--- a/service/test/gatt_server_unittest.cc
+++ b/service/test/gatt_server_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -32,11 +32,12 @@
   MockGattHandler() = default;
   ~MockGattHandler() override = default;
 
-  MOCK_METHOD1(RegisterServer, bt_status_t(const bt_uuid_t&));
+  MOCK_METHOD1(RegisterServer, bt_status_t(const bluetooth::Uuid&));
   MOCK_METHOD1(UnregisterServer, bt_status_t(int));
   MOCK_METHOD2(AddService, bt_status_t(int, std::vector<btgatt_db_element_t>));
-  MOCK_METHOD5(AddCharacteristic, bt_status_t(int, int, bt_uuid_t*, int, int));
-  MOCK_METHOD4(AddDescriptor, bt_status_t(int, int, bt_uuid_t*, int));
+  MOCK_METHOD5(AddCharacteristic,
+               bt_status_t(int, int, bluetooth::Uuid*, int, int));
+  MOCK_METHOD4(AddDescriptor, bt_status_t(int, int, bluetooth::Uuid*, int));
   MOCK_METHOD3(StartService, bt_status_t(int, int, int));
   MOCK_METHOD2(DeleteService, bt_status_t(int, int));
   MOCK_METHOD5(SendIndication,
@@ -211,8 +212,8 @@
 
   void SetUp() override {
     GattServerTest::SetUp();
-    UUID uuid = UUID::GetRandom();
-    auto callback = [&](BLEStatus status, const UUID& in_uuid,
+    Uuid uuid = Uuid::GetRandom();
+    auto callback = [&](BLEStatus status, const Uuid& in_uuid,
                         std::unique_ptr<BluetoothInstance> in_client) {
       CHECK(in_uuid == uuid);
       CHECK(in_client.get());
@@ -228,9 +229,8 @@
 
     factory_->RegisterInstance(uuid, callback);
 
-    bt_uuid_t hal_uuid = uuid.GetBlueDroid();
-    fake_hal_gatt_iface_->NotifyRegisterServerCallback(
-        BT_STATUS_SUCCESS, kDefaultServerId, hal_uuid);
+    fake_hal_gatt_iface_->NotifyRegisterServerCallback(BT_STATUS_SUCCESS,
+                                                       kDefaultServerId, uuid);
   }
 
   void TearDown() override {
@@ -246,9 +246,9 @@
         .Times(1)
         .WillOnce(Return(BT_STATUS_SUCCESS));
 
-    UUID uuid0 = UUID::GetRandom();
-    UUID uuid1 = UUID::GetRandom();
-    UUID uuid2 = UUID::GetRandom();
+    Uuid uuid0 = Uuid::GetRandom();
+    Uuid uuid1 = Uuid::GetRandom();
+    Uuid uuid2 = Uuid::GetRandom();
 
     bool register_success = false;
 
@@ -257,7 +257,7 @@
     ASSERT_TRUE(gatt_server_->AddService(
         service, [&](BLEStatus status, const Service& added_service) {
           ASSERT_EQ(BLE_STATUS_SUCCESS, status);
-          ASSERT_TRUE(UUID(added_service.uuid()) == UUID(service.uuid()));
+          ASSERT_TRUE(Uuid(added_service.uuid()) == Uuid(service.uuid()));
           ASSERT_TRUE(added_service.handle() == 0x0001);
           register_success = true;
         }));
@@ -268,13 +268,13 @@
 
     std::vector<btgatt_db_element_t> service_with_handles = {
         {.type = BTGATT_DB_PRIMARY_SERVICE,
-         .uuid = uuid0.GetBlueDroid(),
+         .uuid = uuid0,
          .attribute_handle = srvc_handle_},
         {.type = BTGATT_DB_CHARACTERISTIC,
-         .uuid = uuid1.GetBlueDroid(),
+         .uuid = uuid1,
          .attribute_handle = char_handle_},
         {.type = BTGATT_DB_DESCRIPTOR,
-         .uuid = uuid2.GetBlueDroid(),
+         .uuid = uuid2,
          .attribute_handle = desc_handle_},
     };
 
@@ -306,11 +306,11 @@
   // These will be asynchronously populate with a result when the callback
   // executes.
   BLEStatus status = BLE_STATUS_SUCCESS;
-  UUID cb_uuid;
+  Uuid cb_uuid;
   std::unique_ptr<GattServer> server;
   int callback_count = 0;
 
-  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+  auto callback = [&](BLEStatus in_status, const Uuid& uuid,
                       std::unique_ptr<BluetoothInstance> in_server) {
     status = in_status;
     cb_uuid = uuid;
@@ -319,7 +319,7 @@
     callback_count++;
   };
 
-  UUID uuid0 = UUID::GetRandom();
+  Uuid uuid0 = Uuid::GetRandom();
 
   // HAL returns failure.
   EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
@@ -329,30 +329,28 @@
   EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
   EXPECT_EQ(0, callback_count);
 
-  // Calling twice with the same UUID should fail with no additional calls into
+  // Calling twice with the same Uuid should fail with no additional calls into
   // the stack.
   EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
 
   testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Call with a different UUID while one is pending.
-  UUID uuid1 = UUID::GetRandom();
+  // Call with a different Uuid while one is pending.
+  Uuid uuid1 = Uuid::GetRandom();
   EXPECT_CALL(*mock_handler_, RegisterServer(_))
       .Times(1)
       .WillOnce(Return(BT_STATUS_SUCCESS));
   EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback));
 
-  // Trigger callback with an unknown UUID. This should get ignored.
-  UUID uuid2 = UUID::GetRandom();
-  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+  // Trigger callback with an unknown Uuid. This should get ignored.
+  bluetooth::Uuid hal_uuid = bluetooth::Uuid::GetRandom();
   fake_hal_gatt_iface_->NotifyRegisterServerCallback(0, 0, hal_uuid);
   EXPECT_EQ(0, callback_count);
 
   // |uuid0| succeeds.
   int server_if0 = 2;  // Pick something that's not 0.
-  hal_uuid = uuid0.GetBlueDroid();
   fake_hal_gatt_iface_->NotifyRegisterServerCallback(BT_STATUS_SUCCESS,
-                                                     server_if0, hal_uuid);
+                                                     server_if0, uuid0);
 
   EXPECT_EQ(1, callback_count);
   ASSERT_TRUE(server.get() != nullptr);  // Assert to terminate in case of error
@@ -371,9 +369,8 @@
 
   // |uuid1| fails.
   int server_if1 = 3;
-  hal_uuid = uuid1.GetBlueDroid();
   fake_hal_gatt_iface_->NotifyRegisterServerCallback(BT_STATUS_FAIL, server_if1,
-                                                     hal_uuid);
+                                                     uuid1);
 
   EXPECT_EQ(2, callback_count);
   ASSERT_TRUE(server.get() == nullptr);  // Assert to terminate in case of error
diff --git a/service/test/ipc_linux_unittest.cc b/service/test/ipc_linux_unittest.cc
index 39cc741..4a347ae 100644
--- a/service/test/ipc_linux_unittest.cc
+++ b/service/test/ipc_linux_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
 #include <base/command_line.h>
 #include <base/files/scoped_file.h>
 #include <base/macros.h>
+#include <base/run_loop.h>
 #include <base/strings/stringprintf.h>
 #include <gtest/gtest.h>
 
@@ -167,7 +168,7 @@
 
   // Run the message loop. We will stop the loop when we receive a delegate
   // event.
-  message_loop_.Run();
+  base::RunLoop().Run();
 
   // We should have received the started event.
   EXPECT_EQ(1, delegate.started_count());
@@ -177,7 +178,7 @@
   // connections. TearDown should gracefully clean up the thread and the test
   // should succeed without hanging.
   ipc_manager_.reset();
-  message_loop_.Run();
+  base::RunLoop().Run();
   EXPECT_EQ(1, delegate.stopped_count());
 }
 
@@ -188,7 +189,7 @@
 
   // Run the message loop. We will stop the loop when we receive a delegate
   // event.
-  message_loop_.Run();
+  base::RunLoop().Run();
 
   // We should have received the started event.
   EXPECT_EQ(1, delegate.started_count());
diff --git a/service/test/low_energy_advertiser_unittest.cc b/service/test/low_energy_advertiser_unittest.cc
index 03188d7..ad76d82 100644
--- a/service/test/low_energy_advertiser_unittest.cc
+++ b/service/test/low_energy_advertiser_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -126,8 +126,8 @@
   void RegisterTestAdvertiser(
       const std::function<void(std::unique_ptr<LowEnergyAdvertiser> advertiser)>
           callback) {
-    UUID uuid = UUID::GetRandom();
-    auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+    Uuid uuid = Uuid::GetRandom();
+    auto api_callback = [&](BLEStatus status, const Uuid& in_uuid,
                             std::unique_ptr<BluetoothInstance> in_client) {
       CHECK(in_uuid == uuid);
       CHECK(in_client.get());
@@ -207,11 +207,11 @@
   // These will be asynchronously populated with a result when the callback
   // executes.
   BLEStatus status = BLE_STATUS_SUCCESS;
-  UUID cb_uuid;
+  Uuid cb_uuid;
   std::unique_ptr<LowEnergyAdvertiser> advertiser;
   int callback_count = 0;
 
-  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+  auto callback = [&](BLEStatus in_status, const Uuid& uuid,
                       std::unique_ptr<BluetoothInstance> in_client) {
     status = in_status;
     cb_uuid = uuid;
@@ -220,7 +220,7 @@
     callback_count++;
   };
 
-  UUID uuid0 = UUID::GetRandom();
+  Uuid uuid0 = Uuid::GetRandom();
 
   reg_cb reg_adv1_cb;
   EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
@@ -231,14 +231,14 @@
   EXPECT_TRUE(ble_advertiser_factory_->RegisterInstance(uuid0, callback));
   EXPECT_EQ(0, callback_count);
 
-  // Calling twice with the same UUID should fail with no additional call into
+  // Calling twice with the same Uuid should fail with no additional call into
   // the stack.
   EXPECT_FALSE(ble_advertiser_factory_->RegisterInstance(uuid0, callback));
 
   ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Call with a different UUID while one is pending.
-  UUID uuid1 = UUID::GetRandom();
+  // Call with a different Uuid while one is pending.
+  Uuid uuid1 = Uuid::GetRandom();
   reg_cb reg_adv2_cb;
   EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
       .Times(1)
@@ -426,11 +426,11 @@
 }
 
 TEST_F(LowEnergyAdvertiserPostRegisterTest, AdvertiseDataParsing) {
-  const std::vector<uint8_t> kUUID16BitData{
+  const std::vector<uint8_t> kUuid16BitData{
       0x03, HCI_EIR_COMPLETE_16BITS_UUID_TYPE, 0xDE, 0xAD,
   };
 
-  const std::vector<uint8_t> kUUID32BitData{
+  const std::vector<uint8_t> kUuid32BitData{
       0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02};
 
   const std::vector<uint8_t> kUUID128BitData{
@@ -444,7 +444,7 @@
       0x0B, 0x0C,
       0x0D, 0x0E};
 
-  const std::vector<uint8_t> kMultiUUIDData{
+  const std::vector<uint8_t> kMultiUuidData{
       0x11, HCI_EIR_COMPLETE_128BITS_UUID_TYPE,
       0xDE, 0xAD,
       0x01, 0x02,
@@ -492,7 +492,7 @@
       0xDE, 0xAD,
       0xBE, 0xEF};
 
-  const std::vector<uint8_t> kServiceUUIDMatch{
+  const std::vector<uint8_t> kServiceUuidMatch{
       0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE,
       0xDE, 0xAD,
       0x01, 0x02,
@@ -501,7 +501,7 @@
       0x01, 0x02,
       0xBE, 0xEF};
 
-  const std::vector<uint8_t> kServiceUUIDMismatch{
+  const std::vector<uint8_t> kServiceUuidMismatch{
       0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE,
       0xDE, 0xAD,
       0x01, 0x01,
@@ -510,18 +510,18 @@
       0x01, 0x02,
       0xBE, 0xEF};
 
-  AdvertiseData uuid_16bit_adv(kUUID16BitData);
-  AdvertiseData uuid_32bit_adv(kUUID32BitData);
+  AdvertiseData uuid_16bit_adv(kUuid16BitData);
+  AdvertiseData uuid_32bit_adv(kUuid32BitData);
   AdvertiseData uuid_128bit_adv(kUUID128BitData);
-  AdvertiseData multi_uuid_adv(kMultiUUIDData);
+  AdvertiseData multi_uuid_adv(kMultiUuidData);
 
   AdvertiseData service_16bit_adv(kServiceData16Bit);
   AdvertiseData service_32bit_adv(kServiceData32Bit);
   AdvertiseData service_128bit_adv(kServiceData128Bit);
   AdvertiseData multi_service_adv(kMultiServiceData);
 
-  AdvertiseData service_uuid_match(kServiceUUIDMatch);
-  AdvertiseData service_uuid_mismatch(kServiceUUIDMismatch);
+  AdvertiseData service_uuid_match(kServiceUuidMatch);
+  AdvertiseData service_uuid_mismatch(kServiceUuidMismatch);
 
   AdvertiseSettings settings;
 
@@ -533,7 +533,7 @@
   };
 
   status_cb start_advertising_cb;
-  // Multiple UUID test
+  // Multiple Uuid test
   EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
       .Times(1)
       .WillOnce(SaveArg<1>(&start_advertising_cb));
@@ -612,7 +612,7 @@
   EXPECT_EQ(8, callback_count);
   ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Service data and UUID where the UUID for both match, should succeed.
+  // Service data and Uuid where the Uuid for both match, should succeed.
   EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
       .Times(1)
       .WillOnce(SaveArg<1>(&start_advertising_cb));
@@ -620,7 +620,7 @@
   EXPECT_EQ(9, callback_count);
   ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Service data and UUID where the UUID for dont match, should fail
+  // Service data and Uuid where the Uuid for dont match, should fail
   EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
       .Times(1)
       .WillOnce(SaveArg<1>(&start_advertising_cb));
diff --git a/service/test/low_energy_client_unittest.cc b/service/test/low_energy_client_unittest.cc
index 5870f2e..3bf566c 100644
--- a/service/test/low_energy_client_unittest.cc
+++ b/service/test/low_energy_client_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@
   MockGattHandler(){};
   ~MockGattHandler() override = default;
 
-  MOCK_METHOD1(RegisterClient, bt_status_t(const bt_uuid_t&));
+  MOCK_METHOD1(RegisterClient, bt_status_t(const bluetooth::Uuid&));
   MOCK_METHOD1(UnregisterClient, bt_status_t(int));
   MOCK_METHOD4(Connect, bt_status_t(int, const RawAddress&, bool, int));
   MOCK_METHOD3(Disconnect, bt_status_t(int, const RawAddress&, int));
@@ -134,8 +134,8 @@
   void RegisterTestClient(
       const std::function<void(std::unique_ptr<LowEnergyClient> client)>
           callback) {
-    UUID uuid = UUID::GetRandom();
-    auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+    Uuid uuid = Uuid::GetRandom();
+    auto api_callback = [&](BLEStatus status, const Uuid& in_uuid,
                             std::unique_ptr<BluetoothInstance> in_client) {
       CHECK(in_uuid == uuid);
       CHECK(in_client.get());
@@ -151,9 +151,8 @@
 
     ble_factory_->RegisterInstance(uuid, api_callback);
 
-    bt_uuid_t hal_uuid = uuid.GetBlueDroid();
     fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, next_client_id_++,
-                                                       hal_uuid);
+                                                       uuid);
     ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
   }
 
@@ -175,11 +174,11 @@
   // These will be asynchronously populated with a result when the callback
   // executes.
   BLEStatus status = BLE_STATUS_SUCCESS;
-  UUID cb_uuid;
+  Uuid cb_uuid;
   std::unique_ptr<LowEnergyClient> client;
   int callback_count = 0;
 
-  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+  auto callback = [&](BLEStatus in_status, const Uuid& uuid,
                       std::unique_ptr<BluetoothInstance> in_client) {
     status = in_status;
     cb_uuid = uuid;
@@ -188,7 +187,7 @@
     callback_count++;
   };
 
-  UUID uuid0 = UUID::GetRandom();
+  Uuid uuid0 = Uuid::GetRandom();
 
   // HAL returns failure.
   EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
@@ -198,30 +197,28 @@
   EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
   EXPECT_EQ(0, callback_count);
 
-  // Calling twice with the same UUID should fail with no additional call into
+  // Calling twice with the same Uuid should fail with no additional call into
   // the stack.
   EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
 
   ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Call with a different UUID while one is pending.
-  UUID uuid1 = UUID::GetRandom();
+  // Call with a different Uuid while one is pending.
+  Uuid uuid1 = Uuid::GetRandom();
   EXPECT_CALL(*mock_handler_, RegisterClient(_))
       .Times(1)
       .WillOnce(Return(BT_STATUS_SUCCESS));
   EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
 
-  // Trigger callback with an unknown UUID. This should get ignored.
-  UUID uuid2 = UUID::GetRandom();
-  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
-  fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
+  // Trigger callback with an unknown Uuid. This should get ignored.
+  Uuid uuid2 = Uuid::GetRandom();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, uuid2);
   EXPECT_EQ(0, callback_count);
 
   // |uuid0| succeeds.
   int client_if0 = 2;  // Pick something that's not 0.
-  hal_uuid = uuid0.GetBlueDroid();
   fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_SUCCESS,
-                                                     client_if0, hal_uuid);
+                                                     client_if0, uuid0);
 
   EXPECT_EQ(1, callback_count);
   ASSERT_TRUE(client.get() != nullptr);  // Assert to terminate in case of error
@@ -239,9 +236,8 @@
 
   // |uuid1| fails.
   int client_if1 = 3;
-  hal_uuid = uuid1.GetBlueDroid();
   fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_FAIL, client_if1,
-                                                     hal_uuid);
+                                                     uuid1);
 
   EXPECT_EQ(2, callback_count);
   ASSERT_TRUE(client.get() == nullptr);  // Assert to terminate in case of error
diff --git a/service/test/low_energy_scanner_unittest.cc b/service/test/low_energy_scanner_unittest.cc
index d723a50..c8b16f3 100644
--- a/service/test/low_energy_scanner_unittest.cc
+++ b/service/test/low_energy_scanner_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 The Android Open Source Project
+//  Copyright 2016 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.
@@ -71,14 +71,8 @@
                                StartSyncCb, SyncReportCb, SyncLostCb));
   MOCK_METHOD1(StopSync, void(uint16_t));
 
-  void ScanFilterAddRemove(int action, int filt_type, int filt_index,
-                           int company_id, int company_id_mask,
-                           const bt_uuid_t* p_uuid,
-                           const bt_uuid_t* p_uuid_mask,
-                           const RawAddress* bd_addr, char addr_type,
-                           std::vector<uint8_t> data,
-                           std::vector<uint8_t> p_mask,
-                           FilterConfigCallback cb){};
+  void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
+                     FilterConfigCallback cb){};
 
   void ScanFilterParamSetup(
       uint8_t client_if, uint8_t action, uint8_t filt_index,
@@ -164,8 +158,8 @@
   void RegisterTestScanner(
       const std::function<void(std::unique_ptr<LowEnergyScanner> scanner)>
           callback) {
-    UUID uuid = UUID::GetRandom();
-    auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+    Uuid uuid = Uuid::GetRandom();
+    auto api_callback = [&](BLEStatus status, const Uuid& in_uuid,
                             std::unique_ptr<BluetoothInstance> in_scanner) {
       CHECK(in_uuid == uuid);
       CHECK(in_scanner.get());
@@ -204,11 +198,11 @@
   // These will be asynchronously populated with a result when the callback
   // executes.
   BLEStatus status = BLE_STATUS_SUCCESS;
-  UUID cb_uuid;
+  Uuid cb_uuid;
   std::unique_ptr<LowEnergyScanner> scanner;
   int callback_count = 0;
 
-  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+  auto callback = [&](BLEStatus in_status, const Uuid& uuid,
                       std::unique_ptr<BluetoothInstance> in_scanner) {
     status = in_status;
     cb_uuid = uuid;
@@ -217,20 +211,20 @@
     callback_count++;
   };
 
-  UUID uuid0 = UUID::GetRandom();
+  Uuid uuid0 = Uuid::GetRandom();
 
   // HAL returns success.
   EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
   EXPECT_EQ(0, callback_count);
 
-  // Calling twice with the same UUID should fail with no additional call into
+  // Calling twice with the same Uuid should fail with no additional call into
   // the stack.
   EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
 
   ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
 
-  // Call with a different UUID while one is pending.
-  UUID uuid1 = UUID::GetRandom();
+  // Call with a different Uuid while one is pending.
+  Uuid uuid1 = Uuid::GetRandom();
   BleScannerInterface::RegisterCallback reg_scanner_cb2;
   EXPECT_CALL(*mock_handler_, RegisterScanner(_))
       .Times(1)
diff --git a/service/test/main.cc b/service/test/main.cc
index 55e0d07..d9a1735 100644
--- a/service/test/main.cc
+++ b/service/test/main.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/mock_adapter.h b/service/test/mock_adapter.h
index 1a762fb..4b93792 100644
--- a/service/test/mock_adapter.h
+++ b/service/test/mock_adapter.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/mock_daemon.h b/service/test/mock_daemon.h
index a5dd974..9947915 100644
--- a/service/test/mock_daemon.h
+++ b/service/test/mock_daemon.h
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/parcelable_unittest.cc b/service/test/parcelable_unittest.cc
index dcfb8fb..3bc2b61 100644
--- a/service/test/parcelable_unittest.cc
+++ b/service/test/parcelable_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2016 Google, Inc.
+//  Copyright 2016 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@
 using bluetooth::ScanResult;
 using bluetooth::ScanSettings;
 using bluetooth::Service;
-using bluetooth::UUID;
+using bluetooth::Uuid;
 
 namespace bluetooth {
 namespace {
@@ -82,11 +82,11 @@
   EXPECT_TRUE(result);
 }
 
-TEST(ParcelableTest, UUID) {
-  // Try a whole bunch of UUIDs.
+TEST(ParcelableTest, Uuid) {
+  // Try a whole bunch of Uuids.
   for (int i = 0; i < 10; i++) {
-    UUID uuid = UUID::GetRandom();
-    TestData<UUID, android::bluetooth::UUID>(uuid);
+    Uuid uuid = Uuid::GetRandom();
+    TestData<Uuid, android::bluetooth::UUID>(uuid);
   }
 }
 
@@ -115,13 +115,13 @@
   bool result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
   EXPECT_TRUE(result);
 
-  UUID uuid = UUID::GetRandom();
+  Uuid uuid = Uuid::GetRandom();
   filter.SetServiceUuid(uuid);
 
   result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
   EXPECT_TRUE(result);
 
-  UUID mask = UUID::GetRandom();
+  Uuid mask = Uuid::GetRandom();
   filter.SetServiceUuidWithMask(uuid, mask);
   result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
   EXPECT_TRUE(result);
@@ -146,11 +146,11 @@
 }
 
 TEST(ParcelableTest, GattDescriptor) {
-  Descriptor s = Descriptor(0x0000, UUID::GetRandom(),
+  Descriptor s = Descriptor(0x0000, Uuid::GetRandom(),
                             bluetooth::kAttributePermissionRead);
-  Descriptor s2 = Descriptor(0xFFFE, UUID::GetRandom(),
+  Descriptor s2 = Descriptor(0xFFFE, Uuid::GetRandom(),
                              bluetooth::kAttributePermissionWrite);
-  Descriptor s3 = Descriptor(0x003D, UUID::GetRandom(),
+  Descriptor s3 = Descriptor(0x003D, Uuid::GetRandom(),
                              bluetooth::kAttributePermissionReadEncryptedMITM |
                                  bluetooth::kAttributePermissionRead);
 
@@ -168,10 +168,10 @@
 }
 
 TEST(ParcelableTest, GattCharacteristic) {
-  Characteristic c = Characteristic(0x0004, UUID::GetRandom(), 0, 0,
-                                    {Descriptor(0x0005, UUID::GetRandom(), 0),
-                                     Descriptor(0x0007, UUID::GetRandom(), 0),
-                                     Descriptor(0x00A1, UUID::GetRandom(), 0)});
+  Characteristic c = Characteristic(0x0004, Uuid::GetRandom(), 0, 0,
+                                    {Descriptor(0x0005, Uuid::GetRandom(), 0),
+                                     Descriptor(0x0007, Uuid::GetRandom(), 0),
+                                     Descriptor(0x00A1, Uuid::GetRandom(), 0)});
 
   bool result =
       TestData<Characteristic, android::bluetooth::BluetoothGattCharacteristic>(
@@ -181,19 +181,19 @@
 
 TEST(ParcelableTest, GattService) {
   Service s =
-      Service(0x0001, true, UUID("CAFE"),
-              {Characteristic(0x0004, UUID::GetRandom(),
+      Service(0x0001, true, Uuid::FromString("CAFE", nullptr),
+              {Characteristic(0x0004, Uuid::GetRandom(),
                               bluetooth::kCharacteristicPropertyNotify,
                               bluetooth::kAttributePermissionRead,
-                              {Descriptor(0x0005, UUID::GetRandom(), 0),
-                               Descriptor(0x0007, UUID::GetRandom(), 0),
-                               Descriptor(0x0009, UUID::GetRandom(), 0)}),
-               Characteristic(0x000D, UUID::GetRandom(),
+                              {Descriptor(0x0005, Uuid::GetRandom(), 0),
+                               Descriptor(0x0007, Uuid::GetRandom(), 0),
+                               Descriptor(0x0009, Uuid::GetRandom(), 0)}),
+               Characteristic(0x000D, Uuid::GetRandom(),
                               bluetooth::kCharacteristicPropertyWrite,
                               bluetooth::kAttributePermissionWrite,
-                              {Descriptor(0x0010, UUID::GetRandom(), 0),
-                               Descriptor(0x0012, UUID::GetRandom(), 0)}),
-               Characteristic(0x0015, UUID::GetRandom(), 0, 0, {})},
+                              {Descriptor(0x0010, Uuid::GetRandom(), 0),
+                               Descriptor(0x0012, Uuid::GetRandom(), 0)}),
+               Characteristic(0x0015, Uuid::GetRandom(), 0, 0, {})},
               {});
 
   Parcel parcel;
diff --git a/service/test/settings_unittest.cc b/service/test/settings_unittest.cc
index 62b6db5..551c1e0 100644
--- a/service/test/settings_unittest.cc
+++ b/service/test/settings_unittest.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/stub_ipc_handler_binder.cc b/service/test/stub_ipc_handler_binder.cc
index 8ce064b..2fb450f 100644
--- a/service/test/stub_ipc_handler_binder.cc
+++ b/service/test/stub_ipc_handler_binder.cc
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2015 Google, Inc.
+//  Copyright 2015 Google, Inc.
 //
 //  Licensed under the Apache License, Version 2.0 (the "License");
 //  you may not use this file except in compliance with the License.
diff --git a/service/test/stub_ipc_handler_linux.cc b/service/test/stub_ipc_handler_linux.cc
deleted file mode 100644
index 011b965..0000000
--- a/service/test/stub_ipc_handler_linux.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-//  Copyright (C) 2015 Google, Inc.
-//
-//  Licensed under the Apache License, Version 2.0 (the "License");
-//  you may not use this file except in compliance with the License.
-//  You may obtain a copy of the License at:
-//
-//  http://www.apache.org/licenses/LICENSE-2.0
-//
-//  Unless required by applicable law or agreed to in writing, software
-//  distributed under the License is distributed on an "AS IS" BASIS,
-//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//  See the License for the specific language governing permissions and
-//  limitations under the License.
-//
-
-#include "service/ipc/ipc_handler_linux.h"
-
-// TODO(keybuk): This is a crappy workaround to link IPCHandlerLinux into
-// host-native unit tests. IPCManager shouldn't explicitly reference these
-// classes.
-
-namespace ipc {
-
-IPCHandlerLinux::IPCHandlerLinux(bluetooth::Adapter* adapter,
-                                 IPCManager::Delegate* delegate)
-    : IPCHandler(adapter, delegate),
-      running_(false),
-      thread_("IPCHandlerLinux"),
-      keep_running_(true) {
-  // Stub
-}
-
-IPCHandlerLinux::~IPCHandlerLinux() {
-  // Stub
-}
-
-bool IPCHandlerLinux::Run() {
-  // Stub
-  return false;
-}
-
-void IPCHandlerLinux::Stop() {
-  // Stub
-}
-
-void IPCHandlerLinux::StartListeningOnThread() {
-  // Stub
-}
-
-void IPCHandlerLinux::ShutDownOnOriginThread() {
-  // Stub
-}
-
-void IPCHandlerLinux::NotifyStartedOnOriginThread() {
-  // Stub
-}
-
-void IPCHandlerLinux::NotifyStartedOnCurrentThread() {
-  // Stub
-}
-
-void IPCHandlerLinux::NotifyStoppedOnOriginThread() {
-  // Stub
-}
-
-void IPCHandlerLinux::NotifyStoppedOnCurrentThread() {
-  // Stub
-}
-
-}  // namespace
diff --git a/service/test/uuid_unittest.cc b/service/test/uuid_unittest.cc
deleted file mode 100644
index 3a8103a..0000000
--- a/service/test/uuid_unittest.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-//
-//  Copyright (C) 2015 Google, Inc.
-//
-//  Licensed under the Apache License, Version 2.0 (the "License");
-//  you may not use this file except in compliance with the License.
-//  You may obtain a copy of the License at:
-//
-//  http://www.apache.org/licenses/LICENSE-2.0
-//
-//  Unless required by applicable law or agreed to in writing, software
-//  distributed under the License is distributed on an "AS IS" BASIS,
-//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//  See the License for the specific language governing permissions and
-//  limitations under the License.
-//
-
-#include <stdint.h>
-#include <algorithm>
-#include <array>
-
-#include <gtest/gtest.h>
-
-#include "service/common/bluetooth/uuid.h"
-
-using namespace bluetooth;
-
-namespace {
-
-const std::array<uint8_t, UUID::kNumBytes128> kBtSigBaseUUID = {{
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-    0x5f, 0x9b, 0x34, 0xfb,
-}};
-
-}  // namespace
-
-// Verify that an uninitialized UUID is equal
-// To the BT SIG Base UUID.
-TEST(UUIDTest, DefaultUUID) {
-  UUID uuid;
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == kBtSigBaseUUID);
-}
-
-// Verify that we initialize a 16-bit UUID in a
-// way consistent with how we read it.
-TEST(UUIDTest, Init16Bit) {
-  auto my_uuid_16 = kBtSigBaseUUID;
-  my_uuid_16[2] = 0xde;
-  my_uuid_16[3] = 0xad;
-  UUID uuid(UUID::UUID16Bit({{0xde, 0xad}}));
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
-  ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
-}
-
-// Verify that we initialize a 16-bit UUID in a
-// way consistent with how we read it.
-TEST(UUIDTest, Init16BitString) {
-  auto my_uuid_16 = kBtSigBaseUUID;
-  my_uuid_16[2] = 0xde;
-  my_uuid_16[3] = 0xad;
-  UUID uuid("dead");
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
-  ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
-
-  uuid = UUID("0xdead");
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
-  ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
-}
-
-// Verify that we initialize a 32-bit UUID in a
-// way consistent with how we read it.
-TEST(UUIDTest, Init32Bit) {
-  auto my_uuid_32 = kBtSigBaseUUID;
-  my_uuid_32[0] = 0xde;
-  my_uuid_32[1] = 0xad;
-  my_uuid_32[2] = 0xbe;
-  my_uuid_32[3] = 0xef;
-  UUID uuid(UUID::UUID32Bit({{0xde, 0xad, 0xbe, 0xef}}));
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
-  ASSERT_TRUE(UUID::kNumBytes32 == uuid.GetShortestRepresentationSize());
-}
-
-// Verify correct reading of a 32-bit UUID initialized from string.
-TEST(UUIDTest, Init32BitString) {
-  auto my_uuid_32 = kBtSigBaseUUID;
-  my_uuid_32[0] = 0xde;
-  my_uuid_32[1] = 0xad;
-  my_uuid_32[2] = 0xbe;
-  my_uuid_32[3] = 0xef;
-  UUID uuid("deadbeef");
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
-  ASSERT_TRUE(UUID::kNumBytes32 == uuid.GetShortestRepresentationSize());
-}
-
-// Verify that we initialize a 128-bit UUID in a
-// way consistent with how we read it.
-TEST(UUIDTest, Init128Bit) {
-  auto my_uuid_128 = kBtSigBaseUUID;
-  for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
-    my_uuid_128[i] = i;
-  }
-
-  UUID uuid(my_uuid_128);
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_128);
-  ASSERT_TRUE(UUID::kNumBytes128 == uuid.GetShortestRepresentationSize());
-}
-
-// Verify that we initialize a 128-bit UUID in a
-// way consistent with how we read it as LE.
-TEST(UUIDTest, Init128BitLittleEndian) {
-  auto my_uuid_128 = kBtSigBaseUUID;
-  for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
-    my_uuid_128[i] = i;
-  }
-
-  UUID uuid(my_uuid_128);
-  std::reverse(my_uuid_128.begin(), my_uuid_128.end());
-  ASSERT_TRUE(uuid.is_valid());
-  ASSERT_TRUE(uuid.GetFullLittleEndian() == my_uuid_128);
-}
-
-// Verify that we initialize a 128-bit UUID in a
-// way consistent with how we read it.
-TEST(UUIDTest, Init128BitString) {
-  UUID::UUID128Bit my_uuid{
-      {7, 1, 6, 8, 14, 255, 16, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
-  std::string my_uuid_string("07010608-0eff-1002-0304-05060708090a");
-
-  UUID uuid0(my_uuid);
-  UUID uuid1(my_uuid_string);
-
-  ASSERT_TRUE(uuid0.is_valid());
-  ASSERT_TRUE(uuid1.is_valid());
-  ASSERT_TRUE(uuid0 == uuid1);
-  ASSERT_TRUE(UUID::kNumBytes128 == uuid0.GetShortestRepresentationSize());
-}
-
-TEST(UUIDTest, InitInvalid) {
-  UUID uuid0("000102030405060708090A0B0C0D0E0F");
-  ASSERT_FALSE(uuid0.is_valid());
-
-  UUID uuid1("1*90");
-  ASSERT_FALSE(uuid1.is_valid());
-
-  UUID uuid2("109g");
-  ASSERT_FALSE(uuid1.is_valid());
-}
-
-TEST(UUIDTest, ToString) {
-  const UUID::UUID16Bit data{{0x18, 0x0d}};
-  UUID uuid(data);
-  std::string uuid_string = uuid.ToString();
-  EXPECT_EQ("0000180d-0000-1000-8000-00805f9b34fb", uuid_string);
-}
diff --git a/stack/Android.bp b/stack/Android.bp
index 5cb5678..ceb2f13 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -20,10 +20,11 @@
         "srvc",
     ],
     header_libs: [
-        "libhardware_headers",
+        "libbluetooth_headers",
     ],
     include_dirs: [
         "external/aac/libAACenc/include",
+        "external/aac/libAACdec/include",
         "external/aac/libSYS/include",
         "external/libldac/inc",
         "external/libldac/abr/inc",
@@ -33,7 +34,7 @@
         "system/bt/vnd/ble",
         "system/bt/btif/include",
         "system/bt/hci/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/udrv/include",
         "system/bt/bta/include",
         "system/bt/bta/sys",
@@ -41,10 +42,12 @@
     ],
     srcs: [
         "a2dp/a2dp_aac.cc",
+        "a2dp/a2dp_aac_decoder.cc",
         "a2dp/a2dp_aac_encoder.cc",
         "a2dp/a2dp_api.cc",
         "a2dp/a2dp_codec_config.cc",
         "a2dp/a2dp_sbc.cc",
+        "a2dp/a2dp_sbc_decoder.cc",
         "a2dp/a2dp_sbc_encoder.cc",
         "a2dp/a2dp_sbc_up_sample.cc",
         "a2dp/a2dp_vendor.cc",
@@ -125,7 +128,6 @@
         "l2cap/l2c_fcr.cc",
         "l2cap/l2c_link.cc",
         "l2cap/l2c_main.cc",
-        "l2cap/l2c_ucd.cc",
         "l2cap/l2c_utils.cc",
         "l2cap/l2cap_client.cc",
         "mcap/mca_api.cc",
@@ -193,19 +195,82 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
+        "system/bt/internal_include",
     ],
-    srcs: ["test/stack_a2dp_test.cc"],
+    srcs: [
+        "test/stack_a2dp_test.cc",
+    ],
     shared_libs: [
+        "libhidlbase",
         "liblog",
+        "libprotobuf-cpp-lite",
         "libcutils",
+        "libutils",
     ],
     static_libs: [
+        "libbt-bta",
         "libbt-stack",
+        "libbt-sbc-decoder",
         "libbt-sbc-encoder",
         "libFraunhoferAAC",
+        "libbtdevice",
+        "libbt-hci",
         "libosi",
+        "libbt-protos-lite",
     ],
+    whole_static_libs: [
+        "libbluetooth-for-tests",
+    ],
+}
+
+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
@@ -221,7 +286,7 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/btcore/include",
         "system/bt/hci/include",
         "system/bt/utils/include",
@@ -229,6 +294,9 @@
     srcs: [
         "smp/smp_keys.cc",
         "smp/aes.cc",
+        "smp/p_256_curvepara.cc",
+        "smp/p_256_ecc_pp.cc",
+        "smp/p_256_multprecision.cc",
         "smp/smp_api.cc",
         "smp/smp_main.cc",
         "smp/smp_utils.cc",
@@ -256,10 +324,10 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/btcore/include",
         "system/bt/hci/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/utils/include",
     ],
     srcs: [
@@ -274,6 +342,9 @@
         "liblog",
         "libgmock",
     ],
+    sanitize: {
+        cfi: false,
+    },
 }
 
 // Bluetooth stack advertise data parsing unit tests for target
@@ -305,7 +376,7 @@
     ],
     include_dirs: [
         "system/bt/",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/btcore/include",
         "system/bt/bta/include",
     ],
@@ -322,6 +393,9 @@
         "libbluetooth-types",
         "libgmock",
         "libosi",
-        "libbt-protos",
+        "libbt-protos-lite",
     ],
+    sanitize: {
+        cfi: false,
+    },
 }
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 9e386ab..6f3c55a 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -17,10 +17,12 @@
 static_library("stack") {
   sources = [
     "a2dp/a2dp_aac.cc",
+    "a2dp/a2dp_aac_decoder.cc",
     "a2dp/a2dp_aac_encoder.cc",
     "a2dp/a2dp_api.cc",
     "a2dp/a2dp_codec_config.cc",
     "a2dp/a2dp_sbc.cc",
+    "a2dp/a2dp_sbc_decoder.cc",
     "a2dp/a2dp_sbc_encoder.cc",
     "a2dp/a2dp_sbc_up_sample.cc",
     "a2dp/a2dp_vendor.cc",
@@ -101,7 +103,6 @@
     "l2cap/l2c_fcr.cc",
     "l2cap/l2c_link.cc",
     "l2cap/l2c_main.cc",
-    "l2cap/l2c_ucd.cc",
     "l2cap/l2c_utils.cc",
     "l2cap/l2cap_client.cc",
     "mcap/mca_api.cc",
@@ -166,7 +167,7 @@
     "//vnd/ble",
     "//btif/include",
     "//hci/include",
-    "//include",
+    "//internal_include",
     "//udrv/include",
     "//rpc/include",
     "//hcis",
@@ -200,7 +201,7 @@
     "//btcore/include",
     "//embdrv/sbc/encoder/include",
     "//hci/include",
-    "//include",
+    "//internal_include",
     "//stack/a2dp",
     "//stack/btm",
     "//stack/include",
@@ -227,7 +228,7 @@
     "//embdrv/sbc",
     "//hci",
     "//types",
-    "//main:bluetooth.default",
+    "//main:bluetooth",
     "//third_party/googletest:gmock_main",
     "//third_party/libchrome:base",
   ]
@@ -245,7 +246,7 @@
     "//",
     "//btcore/include",
     "//hci/include",
-    "//include",
+    "//internal_include",
     "//stack/btm",
   ]
 
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
index 730aee3..7792631 100644
--- a/stack/a2dp/a2dp_aac.cc
+++ b/stack/a2dp/a2dp_aac.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -30,6 +30,7 @@
 #include <string.h>
 
 #include <base/logging.h>
+#include "a2dp_aac_decoder.h"
 #include "a2dp_aac_encoder.h"
 #include "bt_utils.h"
 #include "osi/include/log.h"
@@ -50,7 +51,7 @@
 } tA2DP_AAC_CIE;
 
 /* AAC Source codec capabilities */
-static const tA2DP_AAC_CIE a2dp_aac_caps = {
+static const tA2DP_AAC_CIE a2dp_aac_source_caps = {
     // objectType
     A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
     // sampleRate
@@ -65,6 +66,21 @@
     // bits_per_sample
     BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
 
+/* AAC Sink codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_sink_caps = {
+    // objectType
+    A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+    // sampleRate
+    A2DP_AAC_SAMPLING_FREQ_44100 | A2DP_AAC_SAMPLING_FREQ_48000,
+    // channelMode
+    A2DP_AAC_CHANNEL_MODE_MONO | A2DP_AAC_CHANNEL_MODE_STEREO,
+    // variableBitRateSupport
+    A2DP_AAC_VARIABLE_BIT_RATE_ENABLED,
+    // bitRate
+    A2DP_AAC_DEFAULT_BITRATE,
+    // bits_per_sample
+    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+
 /* Default AAC codec configuration */
 static const tA2DP_AAC_CIE a2dp_aac_default_config = {
     A2DP_AAC_OBJECT_TYPE_MPEG2_LC,        // objectType
@@ -85,9 +101,14 @@
     nullptr  // set_transmit_queue_length
 };
 
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_aac = {
+    a2dp_aac_decoder_init, a2dp_aac_decoder_cleanup,
+    a2dp_aac_decoder_decode_packet,
+};
+
 UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
     const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
-    bool is_peer_codec_info);
+    bool is_capability);
 
 // Builds the AAC Media Codec Capabilities byte sequence beginning from the
 // LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
@@ -191,11 +212,19 @@
 }
 
 bool A2DP_IsSinkCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
+  tA2DP_AAC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
 }
 
 bool A2DP_IsPeerSourceCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
+  tA2DP_AAC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
 }
 
 bool A2DP_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info) {
@@ -206,27 +235,20 @@
          (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
 }
 
-bool A2DP_IsSinkCodecSupportedAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
+bool A2DP_IsSinkCodecSupportedAac(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+                                            false) == A2DP_SUCCESS;
 }
 
-bool A2DP_IsPeerSourceCodecSupportedAac(
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
-}
-
-tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(UNUSED_ATTR const uint8_t* p_src_cap,
-                                         UNUSED_ATTR uint8_t* p_pref_cfg) {
-  return A2DP_NS_CODEC_TYPE;
+bool A2DP_IsPeerSourceCodecSupportedAac(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+                                            true) == A2DP_SUCCESS;
 }
 
 // Checks whether A2DP AAC codec configuration matches with a device's codec
 // capabilities. |p_cap| is the AAC codec configuration. |p_codec_info| is
-// the device's codec capabilities.
-// If |is_capability| is true, the byte sequence is codec capabilities,
-// otherwise is codec configuration.
-// |p_codec_info| contains the codec capabilities for a peer device that
-// is acting as an A2DP source.
+// the device's codec capabilities. |is_capability| is true if
+// |p_codec_info| contains A2DP codec capability.
 // Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
 // otherwise the corresponding A2DP error status code.
 static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
@@ -390,13 +412,24 @@
   return -1;
 }
 
-int A2DP_GetSinkTrackChannelTypeAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return -1;
-}
+int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
 
-int A2DP_GetSinkFramesCountToProcessAac(
-    UNUSED_ATTR uint64_t time_interval_ms,
-    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (aac_cie.channelMode) {
+    case A2DP_AAC_CHANNEL_MODE_MONO:
+      return 1;
+    case A2DP_AAC_CHANNEL_MODE_STEREO:
+      return 3;
+  }
+
   return -1;
 }
 
@@ -529,84 +562,82 @@
   return true;
 }
 
-bool A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
+std::string A2DP_CodecInfoStringAac(const uint8_t* p_codec_info) {
+  std::stringstream res;
+  std::string field;
   tA2DP_STATUS a2dp_status;
   tA2DP_AAC_CIE aac_cie;
 
-  LOG_VERBOSE(LOG_TAG, "%s", __func__);
-
   a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, true);
   if (a2dp_status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAac fail:%d", __func__, a2dp_status);
-    return false;
+    res << "A2DP_ParseInfoAac fail: " << loghex(a2dp_status);
+    return res.str();
   }
 
-  LOG_VERBOSE(LOG_TAG, "\tobjectType: 0x%x", aac_cie.objectType);
-  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG2_LC) {
-    LOG_VERBOSE(LOG_TAG, "\tobjectType: (MPEG-2 AAC LC)");
-  }
-  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LC) {
-    LOG_VERBOSE(LOG_TAG, "\tobjectType: (MPEG-4 AAC LC)");
-  }
-  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LTP) {
-    LOG_VERBOSE(LOG_TAG, "\tobjectType: (MPEG-4 AAC LTP)");
-  }
-  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE) {
-    LOG_VERBOSE(LOG_TAG, "\tobjectType: (MPEG-4 AAC Scalable)");
-  }
+  res << "\tname: AAC\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tsamp_freq: 0x%x", aac_cie.sampleRate);
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_8000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (8000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_11025) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (11025)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_12000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (12000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_16000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (16000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_22050) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (22050)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_24000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (24000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_32000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (32000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (44100)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (48000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_64000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (64000)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (88200)");
-  }
-  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (96000)");
-  }
+  // Object type
+  field.clear();
+  AppendField(&field, (aac_cie.objectType == 0), "NONE");
+  AppendField(&field, (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG2_LC),
+              "(MPEG-2 AAC LC)");
+  AppendField(&field, (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LC),
+              "(MPEG-4 AAC LC)");
+  AppendField(&field, (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LTP),
+              "(MPEG-4 AAC LTP)");
+  AppendField(&field,
+              (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE),
+              "(MPEG-4 AAC Scalable)");
+  res << "\tobjectType: " << field << " (" << loghex(aac_cie.objectType)
+      << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tch_mode: 0x%x", aac_cie.channelMode);
-  if (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_MONO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Mono)");
-  }
-  if (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_STEREO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Stereo)");
-  }
+  // Sample frequency
+  field.clear();
+  AppendField(&field, (aac_cie.sampleRate == 0), "NONE");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_8000),
+              "8000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_11025),
+              "11025");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_12000),
+              "12000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_16000),
+              "16000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_22050),
+              "22050");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_24000),
+              "24000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_32000),
+              "32000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100),
+              "44100");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000),
+              "48000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_64000),
+              "64000");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200),
+              "88200");
+  AppendField(&field, (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000),
+              "96000");
+  res << "\tsamp_freq: " << field << " (" << loghex(aac_cie.sampleRate)
+      << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tvariableBitRateSupport: %s",
-              (aac_cie.variableBitRateSupport != 0) ? "true" : "false");
+  // Channel mode
+  field.clear();
+  AppendField(&field, (aac_cie.channelMode == 0), "NONE");
+  AppendField(&field, (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_MONO),
+              "Mono");
+  AppendField(&field, (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_STEREO),
+              "Stereo");
+  res << "\tch_mode: " << field << " (" << loghex(aac_cie.channelMode) << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tbitRate: %u", aac_cie.bitRate);
+  // Variable bit rate support
+  res << "\tvariableBitRateSupport: " << std::boolalpha
+      << (aac_cie.variableBitRateSupport != 0) << "\n";
 
-  return true;
+  // Bit rate
+  res << "\tbitRate: " << std::to_string(aac_cie.bitRate) << "\n";
+
+  return res.str();
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
@@ -616,6 +647,13 @@
   return &a2dp_encoder_interface_aac;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceAac(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsSinkCodecValidAac(p_codec_info)) return NULL;
+
+  return &a2dp_decoder_interface_aac;
+}
+
 bool A2DP_AdjustCodecAac(uint8_t* p_codec_info) {
   tA2DP_AAC_CIE cfg_cie;
 
@@ -631,10 +669,17 @@
   return BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
 }
 
+btav_a2dp_codec_index_t A2DP_SinkCodecIndexAac(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return BTAV_A2DP_CODEC_INDEX_SINK_AAC;
+}
+
 const char* A2DP_CodecIndexStrAac(void) { return "AAC"; }
 
-bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg) {
-  if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_caps,
+const char* A2DP_CodecIndexStrAacSink(void) { return "AAC SINK"; }
+
+bool A2DP_InitCodecConfigAac(AvdtpSepConfig* p_cfg) {
+  if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_source_caps,
                         p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -650,6 +695,11 @@
   return true;
 }
 
+bool A2DP_InitCodecConfigAacSink(AvdtpSepConfig* p_cfg) {
+  return A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_sink_caps,
+                           p_cfg->codec_info) == A2DP_SUCCESS;
+}
+
 UNUSED_ATTR static void build_codec_config(const tA2DP_AAC_CIE& config_cie,
                                            btav_a2dp_codec_config_t* result) {
   if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100)
@@ -670,34 +720,36 @@
   }
 }
 
-A2dpCodecConfigAac::A2dpCodecConfigAac(
+A2dpCodecConfigAacSource::A2dpCodecConfigAacSource(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC", codec_priority) {
+    : A2dpCodecConfigAacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
+                             A2DP_CodecIndexStrAac(), codec_priority, true) {
   // Compute the local capability
-  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+  if (a2dp_aac_source_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+  if (a2dp_aac_source_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+  if (a2dp_aac_source_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
   }
-  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+  if (a2dp_aac_source_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_aac_caps.bits_per_sample;
-  if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_aac_source_caps.bits_per_sample;
+  if (a2dp_aac_source_caps.channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+  if (a2dp_aac_source_caps.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
 
-A2dpCodecConfigAac::~A2dpCodecConfigAac() {}
+A2dpCodecConfigAacSource::~A2dpCodecConfigAacSource() {}
 
-bool A2dpCodecConfigAac::init() {
+bool A2dpCodecConfigAacSource::init() {
   if (!isValid()) return false;
 
   // Load the encoder
@@ -709,7 +761,7 @@
   return true;
 }
 
-bool A2dpCodecConfigAac::useRtpHeaderMarkerBit() const { return true; }
+bool A2dpCodecConfigAacSource::useRtpHeaderMarkerBit() const { return true; }
 
 //
 // Selects the best sample rate from |sampleRate|.
@@ -782,6 +834,8 @@
       break;
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       break;
   }
@@ -905,15 +959,17 @@
   return false;
 }
 
-bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info,
-                                        bool is_capability,
-                                        uint8_t* p_result_codec_config) {
+bool A2dpCodecConfigAacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
+                                            bool is_capability,
+                                            uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_AAC_CIE sink_info_cie;
+  tA2DP_AAC_CIE peer_info_cie;
   tA2DP_AAC_CIE result_config_cie;
   uint8_t channelMode;
   uint16_t sampleRate;
   btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+  const tA2DP_AAC_CIE* p_a2dp_aac_caps =
+      (is_source_) ? &a2dp_aac_source_caps : &a2dp_aac_sink_caps;
 
   // Save the internal state
   btav_a2dp_codec_config_t saved_codec_config = codec_config_;
@@ -932,9 +988,9 @@
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoAac(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoAac(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -945,31 +1001,33 @@
   memset(&result_config_cie, 0, sizeof(result_config_cie));
 
   // NOTE: Always assign the Object Type and Variable Bit Rate Support.
-  result_config_cie.objectType = a2dp_aac_caps.objectType;
+  result_config_cie.objectType = p_a2dp_aac_caps->objectType;
+  // The Variable Bit Rate Support is disabled if either side disables it
   result_config_cie.variableBitRateSupport =
-      a2dp_aac_caps.variableBitRateSupport;
+      p_a2dp_aac_caps->variableBitRateSupport &
+      peer_info_cie.variableBitRateSupport;
 
   // Set the bit rate as follows:
-  // 1. If the Sink device reports a bogus bit rate
+  // 1. If the remote device reports a bogus bit rate
   //    (bitRate < A2DP_AAC_MIN_BITRATE), then use the bit rate from our
   //    configuration. Examples of observed bogus bit rates are zero
   //    and 24576.
-  // 2. If the Sink device reports valid bit rate
+  // 2. If the remote device reports valid bit rate
   //    (bitRate >= A2DP_AAC_MIN_BITRATE), then use the smaller
-  //    of the Sink device's bit rate and the bit rate from our configuration.
+  //    of the remote device's bit rate and the bit rate from our configuration.
   // In either case, the actual streaming bit rate will also consider the MTU.
-  if (sink_info_cie.bitRate < A2DP_AAC_MIN_BITRATE) {
+  if (peer_info_cie.bitRate < A2DP_AAC_MIN_BITRATE) {
     // Bogus bit rate
-    result_config_cie.bitRate = a2dp_aac_caps.bitRate;
+    result_config_cie.bitRate = p_a2dp_aac_caps->bitRate;
   } else {
     result_config_cie.bitRate =
-        std::min(a2dp_aac_caps.bitRate, sink_info_cie.bitRate);
+        std::min(p_a2dp_aac_caps->bitRate, peer_info_cie.bitRate);
   }
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_aac_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = p_a2dp_aac_caps->sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -1002,6 +1060,8 @@
       break;
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
       codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
@@ -1048,7 +1108,7 @@
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_aac_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_aac_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1062,8 +1122,8 @@
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
               "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aac_caps.sampleRate, sink_info_cie.sampleRate);
+              "peer info = 0x%x",
+              __func__, p_a2dp_aac_caps->sampleRate, peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -1072,7 +1132,7 @@
   //
   // NOTE: this information is NOT included in the AAC A2DP codec description
   // that is sent OTA.
-  bits_per_sample = a2dp_aac_caps.bits_per_sample;
+  bits_per_sample = p_a2dp_aac_caps->bits_per_sample;
   codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
   switch (codec_user_config_.bits_per_sample) {
     case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
@@ -1107,7 +1167,7 @@
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_aac_caps.bits_per_sample;
+        p_a2dp_aac_caps->bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -1117,7 +1177,7 @@
 
     // No user preference - the the codec audio config
     if (select_audio_bits_per_sample(&codec_audio_config_,
-                                     a2dp_aac_caps.bits_per_sample,
+                                     p_a2dp_aac_caps->bits_per_sample,
                                      &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1129,7 +1189,7 @@
     }
 
     // No user preference - use the best match
-    if (select_best_bits_per_sample(a2dp_aac_caps.bits_per_sample,
+    if (select_best_bits_per_sample(p_a2dp_aac_caps->bits_per_sample,
                                     &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1146,7 +1206,7 @@
   //
   // Select the channel mode
   //
-  channelMode = a2dp_aac_caps.channelMode & sink_info_cie.channelMode;
+  channelMode = p_a2dp_aac_caps->channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -1198,7 +1258,7 @@
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_aac_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_aac_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1212,8 +1272,9 @@
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
               "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aac_caps.channelMode, sink_info_cie.channelMode);
+              "peer info = 0x%x",
+              __func__, p_a2dp_aac_caps->channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
@@ -1234,13 +1295,13 @@
   if (codec_user_config_.codec_specific_4 != 0)
     codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
 
-  // Create a local copy of the peer codec capability, and the
+  // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -1263,3 +1324,116 @@
          sizeof(ota_codec_peer_config_));
   return false;
 }
+bool A2dpCodecConfigAacBase::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_AAC_CIE peer_info_cie;
+  uint8_t channelMode;
+  uint16_t sampleRate;
+  const tA2DP_AAC_CIE* p_a2dp_aac_caps =
+      (is_source_) ? &a2dp_aac_source_caps : &a2dp_aac_sink_caps;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoAac(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = p_a2dp_aac_caps->sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+  }
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      p_a2dp_aac_caps->bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = p_a2dp_aac_caps->channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                             ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
+
+A2dpCodecConfigAacSink::A2dpCodecConfigAacSink(
+    btav_a2dp_codec_priority_t codec_priority)
+    : A2dpCodecConfigAacBase(BTAV_A2DP_CODEC_INDEX_SINK_AAC,
+                             A2DP_CodecIndexStrAacSink(), codec_priority,
+                             false) {}
+
+A2dpCodecConfigAacSink::~A2dpCodecConfigAacSink() {}
+
+bool A2dpCodecConfigAacSink::init() {
+  if (!isValid()) return false;
+
+  // Load the decoder
+  if (!A2DP_LoadDecoderAac()) {
+    LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+    return false;
+  }
+
+  return true;
+}
+
+period_ms_t A2dpCodecConfigAacSink::encoderIntervalMs() const {
+  // TODO: This method applies only to Source codecs
+  return 0;
+}
+
+int A2dpCodecConfigAacSink::getEffectiveMtu() const {
+  // TODO: This method applies only to Source codecs
+  return 0;
+}
+
+bool A2dpCodecConfigAacSink::useRtpHeaderMarkerBit() const {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
+
+bool A2dpCodecConfigAacSink::updateEncoderUserConfig(
+    UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+    UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+    UNUSED_ATTR bool* p_config_updated) {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
diff --git a/stack/a2dp/a2dp_aac_decoder.cc b/stack/a2dp/a2dp_aac_decoder.cc
new file mode 100644
index 0000000..d9cd85d
--- /dev/null
+++ b/stack/a2dp/a2dp_aac_decoder.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "a2dp_aac_decoder"
+
+#include "a2dp_aac_decoder.h"
+
+#include <aacdecoder_lib.h>
+#include <base/logging.h>
+
+#include "a2dp_aac.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+#define DECODE_BUF_LEN (8 * 2 * 1024)
+
+typedef struct {
+  HANDLE_AACDECODER aac_handle;
+  bool has_aac_handle;  // True if aac_handle is valid
+  INT_PCM* decode_buf;
+  decoded_data_callback_t decode_callback;
+} tA2DP_AAC_DECODER_CB;
+
+static tA2DP_AAC_DECODER_CB a2dp_aac_decoder_cb;
+
+bool A2DP_LoadDecoderAac(void) {
+  // Nothing to do - the library is statically linked
+  return true;
+}
+
+void A2DP_UnloadDecoderAac(void) { a2dp_aac_decoder_cleanup(); }
+
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback) {
+  a2dp_aac_decoder_cleanup();
+
+  a2dp_aac_decoder_cb.aac_handle =
+      aacDecoder_Open(TT_MP4_LATM_MCP1, 1 /* nrOfLayers */);
+  a2dp_aac_decoder_cb.has_aac_handle = true;
+  a2dp_aac_decoder_cb.decode_buf = static_cast<INT_PCM*>(
+      osi_malloc(sizeof(a2dp_aac_decoder_cb.decode_buf[0]) * DECODE_BUF_LEN));
+  a2dp_aac_decoder_cb.decode_callback = decode_callback;
+  return true;
+}
+
+void a2dp_aac_decoder_cleanup(void) {
+  if (a2dp_aac_decoder_cb.has_aac_handle)
+    aacDecoder_Close(a2dp_aac_decoder_cb.aac_handle);
+  free(a2dp_aac_decoder_cb.decode_buf);
+  memset(&a2dp_aac_decoder_cb, 0, sizeof(a2dp_aac_decoder_cb));
+}
+
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf) {
+  auto* pBuffer = reinterpret_cast<UCHAR*>(p_buf->data + p_buf->offset);
+  UINT bufferSize = p_buf->len;
+  UINT bytesValid = p_buf->len;
+  while (bytesValid > 0) {
+    AAC_DECODER_ERROR err = aacDecoder_Fill(a2dp_aac_decoder_cb.aac_handle,
+                                            &pBuffer, &bufferSize, &bytesValid);
+    if (err != AAC_DEC_OK) {
+      LOG_ERROR(LOG_TAG, "%s: aacDecoder_Fill failed: 0x%x", __func__,
+                static_cast<unsigned>(err));
+      return false;
+    }
+
+    while (true) {
+      err = aacDecoder_DecodeFrame(a2dp_aac_decoder_cb.aac_handle,
+                                   a2dp_aac_decoder_cb.decode_buf,
+                                   DECODE_BUF_LEN, 0 /* flags */);
+      if (err == AAC_DEC_NOT_ENOUGH_BITS) {
+        break;
+      }
+      if (err != AAC_DEC_OK) {
+        LOG_ERROR(LOG_TAG, "%s: aacDecoder_DecodeFrame failed: 0x%x", __func__,
+                  static_cast<int>(err));
+        break;
+      }
+
+      CStreamInfo* info =
+          aacDecoder_GetStreamInfo(a2dp_aac_decoder_cb.aac_handle);
+      if (!info || info->sampleRate <= 0) {
+        LOG_ERROR(LOG_TAG, "%s: Invalid stream info", __func__);
+        break;
+      }
+
+      size_t frame_len = info->frameSize * info->numChannels *
+                         sizeof(a2dp_aac_decoder_cb.decode_buf[0]);
+      a2dp_aac_decoder_cb.decode_callback(
+          reinterpret_cast<uint8_t*>(a2dp_aac_decoder_cb.decode_buf),
+          frame_len);
+    }
+  }
+
+  return true;
+}
diff --git a/stack/a2dp/a2dp_aac_encoder.cc b/stack/a2dp/a2dp_aac_encoder.cc
index 6c79149..43b6181 100644
--- a/stack/a2dp/a2dp_aac_encoder.cc
+++ b/stack/a2dp/a2dp_aac_encoder.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -109,7 +109,7 @@
                                              uint8_t* num_of_frames,
                                              uint64_t timestamp_us);
 static void a2dp_aac_encode_frames(uint8_t nb_frame);
-static bool a2dp_aac_read_feeding(uint8_t* read_buffer);
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read);
 
 bool A2DP_LoadEncoderAac(void) {
   // Nothing to do - the library is statically linked
@@ -154,7 +154,7 @@
                           &restart_input, &restart_output, &config_updated);
 }
 
-bool A2dpCodecConfigAac::updateEncoderUserConfig(
+bool A2dpCodecConfigAacSource::updateEncoderUserConfig(
     const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
     bool* p_restart_output, bool* p_config_updated) {
   a2dp_aac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
@@ -222,6 +222,7 @@
   LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
             __func__, p_feeding_params->sample_rate,
             p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+  a2dp_aac_feeding_reset();
 
   // The codec parameters
   p_encoder_params->sample_rate =
@@ -587,6 +588,7 @@
       .numOutBytes = 0, .numInSamples = 0, .numAncBytes = 0};
 
   uint32_t count;
+  uint32_t total_bytes_read = 0;
   int written = 0;
 
   while (nb_frame) {
@@ -601,7 +603,8 @@
       //
       // Read the PCM data and encode it
       //
-      if (a2dp_aac_read_feeding(read_buffer)) {
+      uint32_t bytes_read = 0;
+      if (a2dp_aac_read_feeding(read_buffer, &bytes_read)) {
         uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
         if (!a2dp_aac_encoder_cb.has_aac_handle) {
           LOG_ERROR(LOG_TAG, "%s: invalid AAC handle", __func__);
@@ -636,6 +639,7 @@
         // no more pcm to read
         nb_frame = 0;
       }
+      total_bytes_read += bytes_read;
     } while ((written == 0) && nb_frame);
 
     // NOTE: We don't check whether the packet will fit in the MTU,
@@ -654,7 +658,9 @@
 
       uint8_t done_nb_frame = remain_nb_frame - nb_frame;
       remain_nb_frame = nb_frame;
-      if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+      if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                total_bytes_read))
+        return;
     } else {
       a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++;
       osi_free(p_buf);
@@ -662,7 +668,7 @@
   }
 }
 
-static bool a2dp_aac_read_feeding(uint8_t* read_buffer) {
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read) {
   uint32_t read_size = a2dp_aac_encoder_cb.aac_encoder_params.frame_length *
                        a2dp_aac_encoder_cb.feeding_params.channel_count *
                        a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8;
@@ -674,6 +680,7 @@
   uint32_t nb_byte_read =
       a2dp_aac_encoder_cb.read_callback(read_buffer, read_size);
   a2dp_aac_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;
+  *bytes_read = nb_byte_read;
 
   if (nb_byte_read < read_size) {
     if (nb_byte_read == 0) return false;
@@ -687,11 +694,15 @@
   return true;
 }
 
-period_ms_t A2dpCodecConfigAac::encoderIntervalMs() const {
+period_ms_t A2dpCodecConfigAacSource::encoderIntervalMs() const {
   return a2dp_aac_get_encoder_interval_ms();
 }
 
-void A2dpCodecConfigAac::debug_codec_dump(int fd) {
+int A2dpCodecConfigAacSource::getEffectiveMtu() const {
+  return a2dp_aac_encoder_cb.TxAaMtuSize;
+}
+
+void A2dpCodecConfigAacSource::debug_codec_dump(int fd) {
   a2dp_aac_encoder_stats_t* stats = &a2dp_aac_encoder_cb.stats;
 
   A2dpCodecConfig::debug_codec_dump(fd);
diff --git a/stack/a2dp/a2dp_api.cc b/stack/a2dp/a2dp_api.cc
index 4be2bdd..cc7d01e 100644
--- a/stack/a2dp/a2dp_api.cc
+++ b/stack/a2dp/a2dp_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,6 +35,8 @@
 #include "osi/include/log.h"
 #include "sdpdefs.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Global data
  ****************************************************************************/
@@ -66,8 +68,9 @@
   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);
+  LOG_INFO(LOG_TAG, "%s: status: %d", __func__, status);
 
   if (status == SDP_SUCCESS) {
     /* loop through all records we found */
@@ -78,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)) !=
@@ -116,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;
@@ -269,22 +273,26 @@
 tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, const RawAddress& bd_addr,
                               tA2DP_SDP_DB_PARAMS* p_db,
                               tA2DP_FIND_CBACK* p_cback) {
-  tSDP_UUID uuid_list;
   bool result = true;
 
-  LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid);
+  LOG_INFO(LOG_TAG, "%s: peer: %s UUID: 0x%x", __func__,
+           bd_addr.ToString().c_str(), service_uuid);
   if ((service_uuid != UUID_SERVCLASS_AUDIO_SOURCE &&
        service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
-      p_db == NULL || p_cback == NULL)
+      p_db == NULL || p_cback == NULL) {
+    LOG_ERROR(LOG_TAG,
+              "%s: cannot find service for peer %s UUID 0x%x: "
+              "invalid parameters",
+              __func__, bd_addr.ToString().c_str(), service_uuid);
     return A2DP_INVALID_PARAMS;
+  }
 
   if (a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE ||
-      a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK)
+      a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK) {
+    LOG_ERROR(LOG_TAG, "%s: cannot find service for peer %s UUID 0x%x: busy",
+              __func__, bd_addr.ToString().c_str(), service_uuid);
     return A2DP_BUSY;
-
-  /* set up discovery database */
-  uuid_list.len = LEN_UUID_16;
-  uuid_list.uu.uuid16 = service_uuid;
+  }
 
   if (p_db->p_attrs == NULL || p_db->num_attr == 0) {
     p_db->p_attrs = a2dp_attr_list;
@@ -294,10 +302,11 @@
   if (a2dp_cb.find.p_db == NULL)
     a2dp_cb.find.p_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_db->db_len);
 
+  Uuid uuid_list = Uuid::From16Bit(service_uuid);
   result = SDP_InitDiscoveryDb(a2dp_cb.find.p_db, p_db->db_len, 1, &uuid_list,
                                p_db->num_attr, p_db->p_attrs);
 
-  if (result == true) {
+  if (result) {
     /* store service_uuid */
     a2dp_cb.find.service_uuid = service_uuid;
     a2dp_cb.find.p_cback = p_cback;
@@ -305,12 +314,19 @@
     /* perform service search */
     result = SDP_ServiceSearchAttributeRequest(bd_addr, a2dp_cb.find.p_db,
                                                a2dp_sdp_cback);
-    if (false == result) {
+    if (!result) {
       a2dp_cb.find.service_uuid = 0;
     }
   }
+  if (!result) {
+    LOG_ERROR(LOG_TAG,
+              "%s: cannot find service for peer %s UUID 0x%x: "
+              "SDP error",
+              __func__, bd_addr.ToString().c_str(), service_uuid);
+    return A2DP_FAIL;
+  }
 
-  return (result ? A2DP_SUCCESS : A2DP_FAIL);
+  return A2DP_SUCCESS;
 }
 
 /******************************************************************************
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 0bf5985..47856fe 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -31,15 +31,21 @@
 #include "a2dp_vendor_aptx.h"
 #include "a2dp_vendor_aptx_hd.h"
 #include "a2dp_vendor_ldac.h"
+#include "bta/av/bta_av_int.h"
 #include "osi/include/log.h"
+#include "osi/include/properties.h"
 
 /* The Media Type offset within the codec info byte array */
 #define A2DP_MEDIA_TYPE_OFFSET 1
 
+/* A2DP Offload enabled in stack */
+static bool a2dp_offload_status;
+
 // Initializes the codec config.
 // |codec_config| is the codec config to initialize.
 // |codec_index| and |codec_priority| are the codec type and priority to use
 // for the initialization.
+
 static void init_btav_a2dp_codec_config(
     btav_a2dp_codec_config_t* codec_config, btav_a2dp_codec_index_t codec_index,
     btav_a2dp_codec_priority_t codec_priority) {
@@ -83,6 +89,7 @@
   } else {
     codec_priority_ = codec_priority;
   }
+  codec_config_.codec_priority = codec_priority_;
 }
 
 void A2dpCodecConfig::setDefaultCodecPriority() {
@@ -93,6 +100,7 @@
     uint32_t priority = 1000 * (codec_index_ + 1) + 1;
     codec_priority_ = static_cast<btav_a2dp_codec_priority_t>(priority);
   }
+  codec_config_.codec_priority = codec_priority_;
 }
 
 A2dpCodecConfig* A2dpCodecConfig::createCodec(
@@ -103,13 +111,16 @@
   A2dpCodecConfig* codec_config = nullptr;
   switch (codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
-      codec_config = new A2dpCodecConfigSbc(codec_priority);
+      codec_config = new A2dpCodecConfigSbcSource(codec_priority);
       break;
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
       codec_config = new A2dpCodecConfigSbcSink(codec_priority);
       break;
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
-      codec_config = new A2dpCodecConfigAac(codec_priority);
+      codec_config = new A2dpCodecConfigAacSource(codec_priority);
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+      codec_config = new A2dpCodecConfigAacSink(codec_priority);
       break;
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       codec_config = new A2dpCodecConfigAptx(codec_priority);
@@ -120,7 +131,6 @@
     case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
       codec_config = new A2dpCodecConfigLdac(codec_priority);
       break;
-    // Add a switch statement for each vendor-specific codec
     case BTAV_A2DP_CODEC_INDEX_MAX:
       break;
   }
@@ -135,6 +145,96 @@
   return codec_config;
 }
 
+int A2dpCodecConfig::getTrackBitRate() const {
+  uint8_t p_codec_info[AVDT_CODEC_SIZE];
+  memcpy(p_codec_info, ota_codec_config_, sizeof(ota_codec_config_));
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetBitrateSbc();
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetBitRateAac(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetBitRate(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+bool A2dpCodecConfig::getCodecSpecificConfig(tBT_A2DP_OFFLOAD* p_a2dp_offload) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+  uint8_t codec_config[AVDT_CODEC_SIZE];
+  uint32_t vendor_id;
+  uint16_t codec_id;
+
+  memset(p_a2dp_offload->codec_info, 0, sizeof(p_a2dp_offload->codec_info));
+
+  if (!A2DP_IsSourceCodecValid(ota_codec_config_)) {
+    return false;
+  }
+
+  memcpy(codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(codec_config);
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      p_a2dp_offload->codec_info[0] =
+          codec_config[4];  // blk_len | subbands | Alloc Method
+      p_a2dp_offload->codec_info[1] = codec_config[5];  // Min bit pool
+      p_a2dp_offload->codec_info[2] = codec_config[6];  // Max bit pool
+      break;
+    case A2DP_MEDIA_CT_AAC:
+      p_a2dp_offload->codec_info[0] = codec_config[3];  // object type
+      p_a2dp_offload->codec_info[1] = codec_config[6];  // VBR | BR
+      break;
+    case A2DP_MEDIA_CT_NON_A2DP:
+      vendor_id = A2DP_VendorCodecGetVendorId(codec_config);
+      codec_id = A2DP_VendorCodecGetCodecId(codec_config);
+      p_a2dp_offload->codec_info[0] = (vendor_id & 0x000000FF);
+      p_a2dp_offload->codec_info[1] = (vendor_id & 0x0000FF00) >> 8;
+      p_a2dp_offload->codec_info[2] = (vendor_id & 0x00FF0000) >> 16;
+      p_a2dp_offload->codec_info[3] = (vendor_id & 0xFF000000) >> 24;
+      p_a2dp_offload->codec_info[4] = (codec_id & 0x000000FF);
+      p_a2dp_offload->codec_info[5] = (codec_id & 0x0000FF00) >> 8;
+      if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+        if (codec_config_.codec_specific_1 == 0) {  // default is 0, ABR
+          p_a2dp_offload->codec_info[6] =
+              A2DP_LDAC_QUALITY_ABR_OFFLOAD;  // ABR in offload
+        } else {
+          switch (codec_config_.codec_specific_1 % 10) {
+            case 0:
+              p_a2dp_offload->codec_info[6] =
+                  A2DP_LDAC_QUALITY_HIGH;  // High bitrate
+              break;
+            case 1:
+              p_a2dp_offload->codec_info[6] =
+                  A2DP_LDAC_QUALITY_MID;  // Mid birate
+              break;
+            case 2:
+              p_a2dp_offload->codec_info[6] =
+                  A2DP_LDAC_QUALITY_LOW;  // Low birate
+              break;
+            case 3:  // fall through
+            default:
+              p_a2dp_offload->codec_info[6] =
+                  A2DP_LDAC_QUALITY_ABR_OFFLOAD;  // ABR in offload
+              break;
+          }
+        }
+      }
+      break;
+    default:
+      break;
+  }
+  return true;
+}
+
 bool A2dpCodecConfig::isValid() const { return true; }
 
 bool A2dpCodecConfig::copyOutOtaCodecConfig(uint8_t* p_codec_info) {
@@ -271,12 +371,15 @@
   bool encoder_restart_input = *p_restart_input;
   bool encoder_restart_output = *p_restart_output;
   bool encoder_config_updated = *p_config_updated;
-  if (updateEncoderUserConfig(p_peer_params, &encoder_restart_input,
-                              &encoder_restart_output,
-                              &encoder_config_updated)) {
-    if (encoder_restart_input) *p_restart_input = true;
-    if (encoder_restart_output) *p_restart_output = true;
-    if (encoder_config_updated) *p_config_updated = true;
+
+  if (!a2dp_offload_status) {
+    if (updateEncoderUserConfig(p_peer_params, &encoder_restart_input,
+                                &encoder_restart_output,
+                                &encoder_config_updated)) {
+      if (encoder_restart_input) *p_restart_input = true;
+      if (encoder_restart_output) *p_restart_output = true;
+      if (encoder_config_updated) *p_config_updated = true;
+    }
   }
   if (*p_restart_input || *p_restart_output) *p_config_updated = true;
 
@@ -396,6 +499,7 @@
   dprintf(fd, "\nA2DP %s State:\n", name().c_str());
   dprintf(fd, "  Priority: %d\n", codecPriority());
   dprintf(fd, "  Encoder interval (ms): %" PRIu64 "\n", encoderIntervalMs());
+  dprintf(fd, "  Effective MTU: %d\n", getEffectiveMtu());
 
   result = codecConfig2Str(getCodecConfig());
   dprintf(fd, "  Config: %s\n", result.c_str());
@@ -443,6 +547,41 @@
 bool A2dpCodecs::init() {
   LOG_DEBUG(LOG_TAG, "%s", __func__);
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  char* tok = NULL;
+  char* tmp_token = NULL;
+  bool offload_codec_support[BTAV_A2DP_CODEC_INDEX_MAX] = {false};
+  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_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) {
+        LOG_INFO(LOG_TAG, "%s: SBC offload supported", __func__);
+        offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_SBC] = true;
+      } else if (strcmp(tok, "aac") == 0) {
+        LOG_INFO(LOG_TAG, "%s: AAC offload supported", __func__);
+        offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_AAC] = true;
+      } else if (strcmp(tok, "aptx") == 0) {
+        LOG_INFO(LOG_TAG, "%s: APTX offload supported", __func__);
+        offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_APTX] = true;
+      } else if (strcmp(tok, "aptxhd") == 0) {
+        LOG_INFO(LOG_TAG, "%s: APTXHD offload supported", __func__);
+        offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD] = true;
+      } else if (strcmp(tok, "ldac") == 0) {
+        LOG_INFO(LOG_TAG, "%s: LDAC offload supported", __func__);
+        offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC] = true;
+      }
+      tok = strtok_r(NULL, "-", &tmp_token);
+    };
+  }
 
   for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
     btav_a2dp_codec_index_t codec_index =
@@ -456,6 +595,12 @@
       codec_priority = cp_iter->second;
     }
 
+    // In offload mode, disable the codecs based on the property
+    if ((codec_index < BTAV_A2DP_CODEC_INDEX_SOURCE_MAX) &&
+        a2dp_offload_status && (offload_codec_support[i] != true)) {
+      codec_priority = BTAV_A2DP_CODEC_PRIORITY_DISABLED;
+    }
+
     A2dpCodecConfig* codec_config =
         A2dpCodecConfig::createCodec(codec_index, codec_priority);
     if (codec_config == nullptr) continue;
@@ -513,6 +658,16 @@
   return iter->second;
 }
 
+A2dpCodecConfig* A2dpCodecs::findSinkCodecConfig(const uint8_t* p_codec_info) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  btav_a2dp_codec_index_t codec_index = A2DP_SinkCodecIndex(p_codec_info);
+  if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) return nullptr;
+
+  auto iter = indexed_codecs_.find(codec_index);
+  if (iter == indexed_codecs_.end()) return nullptr;
+  return iter->second;
+}
+
 bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info,
                                 bool is_capability,
                                 uint8_t* p_result_codec_config,
@@ -530,6 +685,23 @@
   return true;
 }
 
+bool A2dpCodecs::setSinkCodecConfig(const uint8_t* p_peer_codec_info,
+                                    bool is_capability,
+                                    uint8_t* p_result_codec_config,
+                                    bool select_current_codec) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  A2dpCodecConfig* a2dp_codec_config = findSinkCodecConfig(p_peer_codec_info);
+  if (a2dp_codec_config == nullptr) return false;
+  if (!a2dp_codec_config->setCodecConfig(p_peer_codec_info, is_capability,
+                                         p_result_codec_config)) {
+    return false;
+  }
+  if (select_current_codec) {
+    current_codec_config_ = a2dp_codec_config;
+  }
+  return true;
+}
+
 bool A2dpCodecs::setCodecUserConfig(
     const btav_a2dp_codec_config_t& codec_user_config,
     const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
@@ -543,22 +715,8 @@
   *p_restart_output = false;
   *p_config_updated = false;
 
-  LOG_DEBUG(
-      LOG_TAG,
-      "%s: Configuring: codec_type=%d codec_priority=%d "
-      "sample_rate=0x%x bits_per_sample=0x%x "
-      "channel_mode=0x%x codec_specific_1=%" PRIi64
-      " "
-      "codec_specific_2=%" PRIi64
-      " "
-      "codec_specific_3=%" PRIi64
-      " "
-      "codec_specific_4=%" PRIi64,
-      __func__, codec_user_config.codec_type, codec_user_config.codec_priority,
-      codec_user_config.sample_rate, codec_user_config.bits_per_sample,
-      codec_user_config.channel_mode, codec_user_config.codec_specific_1,
-      codec_user_config.codec_specific_2, codec_user_config.codec_specific_3,
-      codec_user_config.codec_specific_4);
+  LOG_DEBUG(LOG_TAG, "%s: Configuring: %s", __func__,
+            codec_user_config.ToString().c_str());
 
   if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) {
     auto iter = indexed_codecs_.find(codec_user_config.codec_type);
@@ -593,6 +751,7 @@
     // Check if there was no previous codec
     if (last_codec_config == nullptr) {
       current_codec_config_ = a2dp_codec_config;
+      *p_restart_input = true;
       *p_restart_output = true;
       break;
     }
@@ -628,6 +787,7 @@
       // connection to select a new codec.
       current_codec_config_ = a2dp_codec_config;
       last_codec_config->setDefaultCodecPriority();
+      *p_restart_input = true;
       *p_restart_output = true;
     }
   } while (false);
@@ -755,6 +915,28 @@
   return false;
 }
 
+bool A2dpCodecs::setPeerSinkCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+  if (!A2DP_IsPeerSinkCodecValid(p_peer_codec_capabilities)) return false;
+  A2dpCodecConfig* a2dp_codec_config =
+      findSourceCodecConfig(p_peer_codec_capabilities);
+  if (a2dp_codec_config == nullptr) return false;
+  return a2dp_codec_config->setPeerCodecCapabilities(p_peer_codec_capabilities);
+}
+
+bool A2dpCodecs::setPeerSourceCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+  if (!A2DP_IsPeerSourceCodecValid(p_peer_codec_capabilities)) return false;
+  A2dpCodecConfig* a2dp_codec_config =
+      findSinkCodecConfig(p_peer_codec_capabilities);
+  if (a2dp_codec_config == nullptr) return false;
+  return a2dp_codec_config->setPeerCodecCapabilities(p_peer_codec_capabilities);
+}
+
 bool A2dpCodecs::getCodecConfigAndCapabilities(
     btav_a2dp_codec_config_t* p_codec_config,
     std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,
@@ -934,27 +1116,6 @@
   A2DP_InitDefaultCodecSbc(p_codec_info);
 }
 
-tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
-                                      uint8_t* p_pref_cfg) {
-  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_src_cap);
-
-  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
-
-  switch (codec_type) {
-    case A2DP_MEDIA_CT_SBC:
-      return A2DP_BuildSrc2SinkConfigSbc(p_src_cap, p_pref_cfg);
-    case A2DP_MEDIA_CT_AAC:
-      return A2DP_BuildSrc2SinkConfigAac(p_src_cap, p_pref_cfg);
-    case A2DP_MEDIA_CT_NON_A2DP:
-      return A2DP_VendorBuildSrc2SinkConfig(p_src_cap, p_pref_cfg);
-    default:
-      break;
-  }
-
-  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
-  return A2DP_NS_CODEC_TYPE;
-}
-
 bool A2DP_UsesRtpHeader(bool content_protection_enabled,
                         const uint8_t* p_codec_info) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
@@ -1093,30 +1254,6 @@
   return -1;
 }
 
-int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
-                                     const uint8_t* p_codec_info) {
-  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
-
-  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
-
-  switch (codec_type) {
-    case A2DP_MEDIA_CT_SBC:
-      return A2DP_GetSinkFramesCountToProcessSbc(time_interval_ms,
-                                                 p_codec_info);
-    case A2DP_MEDIA_CT_AAC:
-      return A2DP_GetSinkFramesCountToProcessAac(time_interval_ms,
-                                                 p_codec_info);
-    case A2DP_MEDIA_CT_NON_A2DP:
-      return A2DP_VendorGetSinkFramesCountToProcess(time_interval_ms,
-                                                    p_codec_info);
-    default:
-      break;
-  }
-
-  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
-  return -1;
-}
-
 bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
                              uint32_t* p_timestamp) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
@@ -1177,6 +1314,27 @@
   return NULL;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
+    const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetDecoderInterfaceSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetDecoderInterfaceAac(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetDecoderInterface(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return NULL;
+}
+
 bool A2DP_AdjustCodec(uint8_t* p_codec_info) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
 
@@ -1215,6 +1373,26 @@
   return BTAV_A2DP_CODEC_INDEX_MAX;
 }
 
+btav_a2dp_codec_index_t A2DP_SinkCodecIndex(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_SinkCodecIndexSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_SinkCodecIndexAac(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorSinkCodecIndex(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return BTAV_A2DP_CODEC_INDEX_MAX;
+}
+
 const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index) {
   switch (codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
@@ -1223,6 +1401,8 @@
       return A2DP_CodecIndexStrSbcSink();
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
       return A2DP_CodecIndexStrAac();
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+      return A2DP_CodecIndexStrAacSink();
     default:
       break;
   }
@@ -1234,7 +1414,7 @@
 }
 
 bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
-                          tAVDT_CFG* p_cfg) {
+                          AvdtpSepConfig* p_cfg) {
   LOG_VERBOSE(LOG_TAG, "%s: codec %s", __func__,
               A2DP_CodecIndexStr(codec_index));
 
@@ -1249,6 +1429,8 @@
       return A2DP_InitCodecConfigSbcSink(p_cfg);
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
       return A2DP_InitCodecConfigAac(p_cfg);
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+      return A2DP_InitCodecConfigAacSink(p_cfg);
     default:
       break;
   }
@@ -1259,22 +1441,19 @@
   return false;
 }
 
-bool A2DP_DumpCodecInfo(const uint8_t* p_codec_info) {
+std::string A2DP_CodecInfoString(const uint8_t* p_codec_info) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
 
-  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
-
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
-      return A2DP_DumpCodecInfoSbc(p_codec_info);
+      return A2DP_CodecInfoStringSbc(p_codec_info);
     case A2DP_MEDIA_CT_AAC:
-      return A2DP_DumpCodecInfoAac(p_codec_info);
+      return A2DP_CodecInfoStringAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
-      return A2DP_VendorDumpCodecInfo(p_codec_info);
+      return A2DP_VendorCodecInfoString(p_codec_info);
     default:
       break;
   }
 
-  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
-  return false;
+  return "Unsupported codec type: " + loghex(codec_type);
 }
diff --git a/stack/a2dp/a2dp_int.h b/stack/a2dp/a2dp_int.h
index 6fb4543..708f908 100644
--- a/stack/a2dp/a2dp_int.h
+++ b/stack/a2dp/a2dp_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -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/a2dp/a2dp_sbc.cc b/stack/a2dp/a2dp_sbc.cc
index cfdaad4..bef5bf9 100644
--- a/stack/a2dp/a2dp_sbc.cc
+++ b/stack/a2dp/a2dp_sbc.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
 #include <string.h>
 
 #include <base/logging.h>
+#include "a2dp_sbc_decoder.h"
 #include "a2dp_sbc_encoder.h"
 #include "bt_utils.h"
 #include "embdrv/sbc/encoder/include/sbc_encoder.h"
@@ -52,9 +53,9 @@
   btav_a2dp_codec_bits_per_sample_t bits_per_sample;
 } tA2DP_SBC_CIE;
 
-/* SBC SRC codec capabilities */
-static const tA2DP_SBC_CIE a2dp_sbc_caps = {
-    A2DP_SBC_IE_SAMP_FREQ_44,                           /* samp_freq */
+/* 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_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
      A2DP_SBC_IE_BLOCKS_4),            /* block_len */
@@ -65,7 +66,7 @@
     BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
 };
 
-/* SBC SINK codec capabilities */
+/* SBC Sink codec capabilities */
 static const tA2DP_SBC_CIE a2dp_sbc_sink_caps = {
     (A2DP_SBC_IE_SAMP_FREQ_48 | A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
     (A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_STEREO |
@@ -101,6 +102,11 @@
     nullptr  // set_transmit_queue_length
 };
 
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_sbc = {
+    a2dp_sbc_decoder_init, a2dp_sbc_decoder_cleanup,
+    a2dp_sbc_decoder_decode_packet,
+};
+
 static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
     const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
     bool is_capability);
@@ -375,64 +381,6 @@
   return A2DP_SUCCESS;
 }
 
-tA2DP_STATUS A2DP_BuildSrc2SinkConfigSbc(const uint8_t* p_src_cap,
-                                         uint8_t* p_pref_cfg) {
-  tA2DP_SBC_CIE src_cap;
-  tA2DP_SBC_CIE pref_cap;
-
-  /* initialize it to default SBC configuration */
-  A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_default_config,
-                    p_pref_cfg);
-
-  /* now try to build a preferred one */
-  /* parse configuration */
-  tA2DP_STATUS status = A2DP_ParseInfoSbc(&src_cap, p_src_cap, true);
-  if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse src cap ret = %d", __func__, status);
-    return A2DP_FAIL;
-  }
-
-  if (src_cap.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48)
-    pref_cap.samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
-  else if (src_cap.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44)
-    pref_cap.samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
-
-  if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_JOINT)
-    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_JOINT;
-  else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_STEREO)
-    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_STEREO;
-  else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_DUAL)
-    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
-  else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_MONO)
-    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_MONO;
-
-  if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_16)
-    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_16;
-  else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_12)
-    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_12;
-  else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_8)
-    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_8;
-  else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_4)
-    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_4;
-
-  if (src_cap.num_subbands & A2DP_SBC_IE_SUBBAND_8)
-    pref_cap.num_subbands = A2DP_SBC_IE_SUBBAND_8;
-  else if (src_cap.num_subbands & A2DP_SBC_IE_SUBBAND_4)
-    pref_cap.num_subbands = A2DP_SBC_IE_SUBBAND_4;
-
-  if (src_cap.alloc_method & A2DP_SBC_IE_ALLOC_MD_L)
-    pref_cap.alloc_method = A2DP_SBC_IE_ALLOC_MD_L;
-  else if (src_cap.alloc_method & A2DP_SBC_IE_ALLOC_MD_S)
-    pref_cap.alloc_method = A2DP_SBC_IE_ALLOC_MD_S;
-
-  pref_cap.min_bitpool = src_cap.min_bitpool;
-  pref_cap.max_bitpool = src_cap.max_bitpool;
-
-  A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &pref_cap, p_pref_cfg);
-
-  return A2DP_SUCCESS;
-}
-
 bool A2DP_CodecTypeEqualsSbc(const uint8_t* p_codec_info_a,
                              const uint8_t* p_codec_info_b) {
   tA2DP_SBC_CIE sbc_cie_a;
@@ -692,6 +640,7 @@
   return sbc_cie.max_bitpool;
 }
 
+uint32_t A2DP_GetBitrateSbc() { return a2dp_sbc_get_bitrate(); }
 int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info) {
   tA2DP_SBC_CIE sbc_cie;
 
@@ -716,138 +665,6 @@
   return -1;
 }
 
-int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
-                                        const uint8_t* p_codec_info) {
-  tA2DP_SBC_CIE sbc_cie;
-  uint32_t freq_multiple;
-  uint32_t num_blocks;
-  uint32_t num_subbands;
-  int frames_to_process;
-
-  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
-  if (a2dp_status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
-              a2dp_status);
-    return -1;
-  }
-
-  // Check the sample frequency
-  switch (sbc_cie.samp_freq) {
-    case A2DP_SBC_IE_SAMP_FREQ_16:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (16000)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = 16 * time_interval_ms;
-      break;
-    case A2DP_SBC_IE_SAMP_FREQ_32:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (32000)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = 32 * time_interval_ms;
-      break;
-    case A2DP_SBC_IE_SAMP_FREQ_44:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (44100)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = (441 * time_interval_ms) / 10;
-      break;
-    case A2DP_SBC_IE_SAMP_FREQ_48:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (48000)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = 48 * time_interval_ms;
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown frequency: %d", __func__,
-                sbc_cie.samp_freq);
-      return -1;
-  }
-
-  // Check the channel mode
-  switch (sbc_cie.ch_mode) {
-    case A2DP_SBC_IE_CH_MD_MONO:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, sbc_cie.ch_mode);
-      break;
-    case A2DP_SBC_IE_CH_MD_DUAL:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, sbc_cie.ch_mode);
-      break;
-    case A2DP_SBC_IE_CH_MD_STEREO:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__,
-                  sbc_cie.ch_mode);
-      break;
-    case A2DP_SBC_IE_CH_MD_JOINT:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, sbc_cie.ch_mode);
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown channel mode: %d", __func__,
-                sbc_cie.ch_mode);
-      return -1;
-  }
-
-  // Check the block length
-  switch (sbc_cie.block_len) {
-    case A2DP_SBC_IE_BLOCKS_4:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (4)", __func__, sbc_cie.block_len);
-      num_blocks = 4;
-      break;
-    case A2DP_SBC_IE_BLOCKS_8:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (8)", __func__, sbc_cie.block_len);
-      num_blocks = 8;
-      break;
-    case A2DP_SBC_IE_BLOCKS_12:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (12)", __func__,
-                  sbc_cie.block_len);
-      num_blocks = 12;
-      break;
-    case A2DP_SBC_IE_BLOCKS_16:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (16)", __func__,
-                  sbc_cie.block_len);
-      num_blocks = 16;
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown block length: %d", __func__,
-                sbc_cie.block_len);
-      return -1;
-  }
-
-  // Check the number of sub-bands
-  switch (sbc_cie.num_subbands) {
-    case A2DP_SBC_IE_SUBBAND_4:
-      LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (4)", __func__,
-                  sbc_cie.num_subbands);
-      num_subbands = 4;
-      break;
-    case A2DP_SBC_IE_SUBBAND_8:
-      LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (8)", __func__,
-                  sbc_cie.num_subbands);
-      num_subbands = 8;
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown number of subbands: %d", __func__,
-                sbc_cie.num_subbands);
-      return -1;
-  }
-
-  // Check the allocation method
-  switch (sbc_cie.alloc_method) {
-    case A2DP_SBC_IE_ALLOC_MD_S:
-      LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__,
-                  sbc_cie.alloc_method);
-      break;
-    case A2DP_SBC_IE_ALLOC_MD_L:
-      LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__,
-                  sbc_cie.alloc_method);
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown allocation method: %d", __func__,
-                sbc_cie.alloc_method);
-      return -1;
-  }
-
-  LOG_VERBOSE(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__,
-              sbc_cie.min_bitpool, sbc_cie.max_bitpool);
-
-  frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
-
-  return frames_to_process;
-}
-
 bool A2DP_GetPacketTimestampSbc(UNUSED_ATTR const uint8_t* p_codec_info,
                                 const uint8_t* p_data, uint32_t* p_timestamp) {
   *p_timestamp = *(const uint32_t*)p_data;
@@ -867,80 +684,69 @@
   return true;
 }
 
-bool A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
+std::string A2DP_CodecInfoStringSbc(const uint8_t* p_codec_info) {
+  std::stringstream res;
+  std::string field;
   tA2DP_STATUS a2dp_status;
   tA2DP_SBC_CIE sbc_cie;
 
-  LOG_VERBOSE(LOG_TAG, "%s", __func__);
-
   a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, true);
   if (a2dp_status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoSbc fail:%d", __func__, a2dp_status);
-    return false;
+    res << "A2DP_ParseInfoSbc fail: " << loghex(a2dp_status);
+    return res.str();
   }
 
-  LOG_VERBOSE(LOG_TAG, "\tsamp_freq: 0x%x", sbc_cie.samp_freq);
-  if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_16) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (16000)");
-  }
-  if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_32) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (32000)");
-  }
-  if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (44100)");
-  }
-  if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (48000)");
-  }
+  res << "\tname: SBC\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tch_mode: 0x%x", sbc_cie.ch_mode);
-  if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Mono)");
-  }
-  if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Dual)");
-  }
-  if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Stereo)");
-  }
-  if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Joint)");
-  }
+  // Sample frequency
+  field.clear();
+  AppendField(&field, (sbc_cie.samp_freq == 0), "NONE");
+  AppendField(&field, (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_16), "16000");
+  AppendField(&field, (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_32), "32000");
+  AppendField(&field, (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44), "44100");
+  AppendField(&field, (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48), "48000");
+  res << "\tsamp_freq: " << field << " (" << loghex(sbc_cie.samp_freq) << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tblock_len: 0x%x", sbc_cie.block_len);
-  if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_4) {
-    LOG_VERBOSE(LOG_TAG, "\tblock_len: (4)");
-  }
-  if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_8) {
-    LOG_VERBOSE(LOG_TAG, "\tblock_len: (8)");
-  }
-  if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_12) {
-    LOG_VERBOSE(LOG_TAG, "\tblock_len: (12)");
-  }
-  if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_16) {
-    LOG_VERBOSE(LOG_TAG, "\tblock_len: (16)");
-  }
+  // Channel mode
+  field.clear();
+  AppendField(&field, (sbc_cie.ch_mode == 0), "NONE");
+  AppendField(&field, (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO), "Mono");
+  AppendField(&field, (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_DUAL), "Dual");
+  AppendField(&field, (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_STEREO), "Stereo");
+  AppendField(&field, (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_JOINT), "Joint");
+  res << "\tch_mode: " << field << " (" << loghex(sbc_cie.ch_mode) << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tnum_subbands: 0x%x", sbc_cie.num_subbands);
-  if (sbc_cie.num_subbands & A2DP_SBC_IE_SUBBAND_4) {
-    LOG_VERBOSE(LOG_TAG, "\tnum_subbands: (4)");
-  }
-  if (sbc_cie.num_subbands & A2DP_SBC_IE_SUBBAND_8) {
-    LOG_VERBOSE(LOG_TAG, "\tnum_subbands: (8)");
-  }
+  // Block length
+  field.clear();
+  AppendField(&field, (sbc_cie.block_len == 0), "NONE");
+  AppendField(&field, (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_4), "4");
+  AppendField(&field, (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_8), "8");
+  AppendField(&field, (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_12), "12");
+  AppendField(&field, (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_16), "16");
+  res << "\tblock_len: " << field << " (" << loghex(sbc_cie.block_len) << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\talloc_method: 0x%x)", sbc_cie.alloc_method);
-  if (sbc_cie.alloc_method & A2DP_SBC_IE_ALLOC_MD_S) {
-    LOG_VERBOSE(LOG_TAG, "\talloc_method: (SNR)");
-  }
-  if (sbc_cie.alloc_method & A2DP_SBC_IE_ALLOC_MD_L) {
-    LOG_VERBOSE(LOG_TAG, "\talloc_method: (Loundess)");
-  }
+  // Number of subbands
+  field.clear();
+  AppendField(&field, (sbc_cie.num_subbands == 0), "NONE");
+  AppendField(&field, (sbc_cie.num_subbands & A2DP_SBC_IE_SUBBAND_4), "4");
+  AppendField(&field, (sbc_cie.num_subbands & A2DP_SBC_IE_SUBBAND_8), "8");
+  res << "\tnum_subbands: " << field << " (" << loghex(sbc_cie.num_subbands)
+      << ")\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool,
-              sbc_cie.max_bitpool);
+  // Allocation method
+  field.clear();
+  AppendField(&field, (sbc_cie.alloc_method == 0), "NONE");
+  AppendField(&field, (sbc_cie.alloc_method & A2DP_SBC_IE_ALLOC_MD_S), "SNR");
+  AppendField(&field, (sbc_cie.alloc_method & A2DP_SBC_IE_ALLOC_MD_L),
+              "Loundess");
+  res << "\talloc_method: " << field << " (" << loghex(sbc_cie.alloc_method)
+      << ")\n";
 
-  return true;
+  // Min/max bitloop
+  res << "\tBit pool Min: " << std::to_string(sbc_cie.min_bitpool)
+      << " Max: " << std::to_string(sbc_cie.max_bitpool);
+
+  return res.str();
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
@@ -950,6 +756,13 @@
   return &a2dp_encoder_interface_sbc;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceSbc(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsSinkCodecValidSbc(p_codec_info)) return NULL;
+
+  return &a2dp_decoder_interface_sbc;
+}
+
 bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info) {
   tA2DP_SBC_CIE cfg_cie;
 
@@ -972,12 +785,17 @@
   return BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
 }
 
+btav_a2dp_codec_index_t A2DP_SinkCodecIndexSbc(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return BTAV_A2DP_CODEC_INDEX_SINK_SBC;
+}
+
 const char* A2DP_CodecIndexStrSbc(void) { return "SBC"; }
 
 const char* A2DP_CodecIndexStrSbcSink(void) { return "SBC SINK"; }
 
-bool A2DP_InitCodecConfigSbc(tAVDT_CFG* p_cfg) {
-  if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_caps,
+bool A2DP_InitCodecConfigSbc(AvdtpSepConfig* p_cfg) {
+  if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_source_caps,
                         p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -993,7 +811,7 @@
   return true;
 }
 
-bool A2DP_InitCodecConfigSbcSink(tAVDT_CFG* p_cfg) {
+bool A2DP_InitCodecConfigSbcSink(AvdtpSepConfig* p_cfg) {
   if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_sink_caps,
                         p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
@@ -1020,34 +838,36 @@
   }
 }
 
-A2dpCodecConfigSbc::A2dpCodecConfigSbc(
+A2dpCodecConfigSbcSource::A2dpCodecConfigSbcSource(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC", codec_priority) {
+    : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC",
+                             codec_priority, true) {
   // Compute the local capability
-  if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+  if (a2dp_sbc_source_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+  if (a2dp_sbc_source_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_sbc_caps.bits_per_sample;
-  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_sbc_source_caps.bits_per_sample;
+  if (a2dp_sbc_source_caps.ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+  if (a2dp_sbc_source_caps.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
-  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+  if (a2dp_sbc_source_caps.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
-  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+  if (a2dp_sbc_source_caps.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
 
-A2dpCodecConfigSbc::~A2dpCodecConfigSbc() {}
+A2dpCodecConfigSbcSource::~A2dpCodecConfigSbcSource() {}
 
-bool A2dpCodecConfigSbc::init() {
+bool A2dpCodecConfigSbcSource::init() {
   if (!isValid()) return false;
 
   // Load the encoder
@@ -1059,7 +879,7 @@
   return true;
 }
 
-bool A2dpCodecConfigSbc::useRtpHeaderMarkerBit() const { return false; }
+bool A2dpCodecConfigSbcSource::useRtpHeaderMarkerBit() const { return false; }
 
 //
 // Selects the best sample rate from |samp_freq|.
@@ -1109,6 +929,8 @@
     case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       break;
   }
@@ -1218,17 +1040,19 @@
   return false;
 }
 
-bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info,
-                                        bool is_capability,
-                                        uint8_t* p_result_codec_config) {
+bool A2dpCodecConfigSbcBase::setCodecConfig(const uint8_t* p_peer_codec_info,
+                                            bool is_capability,
+                                            uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_SBC_CIE sink_info_cie;
+  tA2DP_SBC_CIE peer_info_cie;
   tA2DP_SBC_CIE result_config_cie;
   uint8_t samp_freq;
   uint8_t ch_mode;
   uint8_t block_len;
   uint8_t num_subbands;
   uint8_t alloc_method;
+  const tA2DP_SBC_CIE* p_a2dp_sbc_caps =
+      (is_source_) ? &a2dp_sbc_source_caps : &a2dp_sbc_sink_caps;
 
   // Save the internal state
   btav_a2dp_codec_config_t saved_codec_config = codec_config_;
@@ -1247,20 +1071,30 @@
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoSbc(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoSbc(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
   // Try using the prefered peer codec config (if valid), instead of the peer
   // capability.
-  if (is_capability && A2DP_IsPeerSinkCodecValidSbc(ota_codec_peer_config_)) {
-    status = A2DP_ParseInfoSbc(&sink_info_cie, ota_codec_peer_config_, false);
+  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 (status != A2DP_SUCCESS) {
       // Use the peer codec capability
       status =
-          A2DP_ParseInfoSbc(&sink_info_cie, p_peer_codec_info, is_capability);
+          A2DP_ParseInfoSbc(&peer_info_cie, p_peer_codec_info, is_capability);
       CHECK(status == A2DP_SUCCESS);
     }
   }
@@ -1273,7 +1107,7 @@
   //
   // Select the sample frequency
   //
-  samp_freq = a2dp_sbc_caps.samp_freq & sink_info_cie.samp_freq;
+  samp_freq = p_a2dp_sbc_caps->samp_freq & peer_info_cie.samp_freq;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -1294,6 +1128,8 @@
     case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
       codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
@@ -1328,7 +1164,7 @@
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_sbc_default_config.samp_freq & sink_info_cie.samp_freq,
+            a2dp_sbc_default_config.samp_freq & peer_info_cie.samp_freq,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1341,9 +1177,9 @@
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_sbc_caps.samp_freq, sink_info_cie.samp_freq);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, p_a2dp_sbc_caps->samp_freq, peer_info_cie.samp_freq);
     goto fail;
   }
 
@@ -1370,7 +1206,7 @@
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_sbc_caps.bits_per_sample;
+        p_a2dp_sbc_caps->bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -1404,7 +1240,7 @@
   //
   // Select the channel mode
   //
-  ch_mode = a2dp_sbc_caps.ch_mode & sink_info_cie.ch_mode;
+  ch_mode = p_a2dp_sbc_caps->ch_mode & peer_info_cie.ch_mode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -1478,7 +1314,7 @@
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_sbc_default_config.ch_mode & sink_info_cie.ch_mode,
+            a2dp_sbc_default_config.ch_mode & peer_info_cie.ch_mode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1490,16 +1326,16 @@
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_sbc_caps.ch_mode, sink_info_cie.ch_mode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, p_a2dp_sbc_caps->ch_mode, peer_info_cie.ch_mode);
     goto fail;
   }
 
   //
   // Select the block length
   //
-  block_len = a2dp_sbc_caps.block_len & sink_info_cie.block_len;
+  block_len = p_a2dp_sbc_caps->block_len & peer_info_cie.block_len;
   if (block_len & A2DP_SBC_IE_BLOCKS_16) {
     result_config_cie.block_len = A2DP_SBC_IE_BLOCKS_16;
   } else if (block_len & A2DP_SBC_IE_BLOCKS_12) {
@@ -1510,59 +1346,62 @@
     result_config_cie.block_len = A2DP_SBC_IE_BLOCKS_4;
   } else {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match block length: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_sbc_caps.block_len, sink_info_cie.block_len);
+              "%s: cannot match block length: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, p_a2dp_sbc_caps->block_len, peer_info_cie.block_len);
     goto fail;
   }
 
   //
   // Select the number of sub-bands
   //
-  num_subbands = a2dp_sbc_caps.num_subbands & sink_info_cie.num_subbands;
+  num_subbands = p_a2dp_sbc_caps->num_subbands & peer_info_cie.num_subbands;
   if (num_subbands & A2DP_SBC_IE_SUBBAND_8) {
     result_config_cie.num_subbands = A2DP_SBC_IE_SUBBAND_8;
   } else if (num_subbands & A2DP_SBC_IE_SUBBAND_4) {
     result_config_cie.num_subbands = A2DP_SBC_IE_SUBBAND_4;
   } else {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match number of sub-bands: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_sbc_caps.num_subbands, sink_info_cie.num_subbands);
+              "%s: cannot match number of sub-bands: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, p_a2dp_sbc_caps->num_subbands,
+              peer_info_cie.num_subbands);
     goto fail;
   }
 
   //
   // Select the allocation method
   //
-  alloc_method = a2dp_sbc_caps.alloc_method & sink_info_cie.alloc_method;
+  alloc_method = p_a2dp_sbc_caps->alloc_method & peer_info_cie.alloc_method;
   if (alloc_method & A2DP_SBC_IE_ALLOC_MD_L) {
     result_config_cie.alloc_method = A2DP_SBC_IE_ALLOC_MD_L;
   } else if (alloc_method & A2DP_SBC_IE_ALLOC_MD_S) {
     result_config_cie.alloc_method = A2DP_SBC_IE_ALLOC_MD_S;
   } else {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match allocation method: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_sbc_caps.alloc_method, sink_info_cie.alloc_method);
+              "%s: cannot match allocation method: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, p_a2dp_sbc_caps->alloc_method,
+              peer_info_cie.alloc_method);
     goto fail;
   }
 
   //
   // Select the min/max bitpool
   //
-  result_config_cie.min_bitpool = a2dp_sbc_caps.min_bitpool;
-  if (result_config_cie.min_bitpool < sink_info_cie.min_bitpool)
-    result_config_cie.min_bitpool = sink_info_cie.min_bitpool;
-  result_config_cie.max_bitpool = a2dp_sbc_caps.max_bitpool;
-  if (result_config_cie.max_bitpool > sink_info_cie.max_bitpool)
-    result_config_cie.max_bitpool = sink_info_cie.max_bitpool;
+  result_config_cie.min_bitpool = p_a2dp_sbc_caps->min_bitpool;
+  if (result_config_cie.min_bitpool < peer_info_cie.min_bitpool)
+    result_config_cie.min_bitpool = peer_info_cie.min_bitpool;
+  result_config_cie.max_bitpool = p_a2dp_sbc_caps->max_bitpool;
+  if (result_config_cie.max_bitpool > peer_info_cie.max_bitpool)
+    result_config_cie.max_bitpool = peer_info_cie.max_bitpool;
   if (result_config_cie.min_bitpool > result_config_cie.max_bitpool) {
     LOG_ERROR(LOG_TAG,
               "%s: cannot match min/max bitpool: "
-              "source caps min/max = 0x%x/0x%x sink info min/max = 0x%x/0x%x",
-              __func__, a2dp_sbc_caps.min_bitpool, a2dp_sbc_caps.max_bitpool,
-              sink_info_cie.min_bitpool, sink_info_cie.max_bitpool);
+              "local caps min/max = 0x%x/0x%x peer info min/max = 0x%x/0x%x",
+              __func__, p_a2dp_sbc_caps->min_bitpool,
+              p_a2dp_sbc_caps->max_bitpool, peer_info_cie.min_bitpool,
+              peer_info_cie.max_bitpool);
     goto fail;
   }
 
@@ -1586,12 +1425,13 @@
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    memcpy(ota_codec_peer_capability_, p_peer_codec_info,
-           sizeof(ota_codec_peer_capability_));
+    status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                               ota_codec_peer_capability_);
   } else {
-    memcpy(ota_codec_peer_config_, p_peer_codec_info,
-           sizeof(ota_codec_peer_config_));
+    status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                               ota_codec_peer_config_);
   }
+  CHECK(status == A2DP_SUCCESS);
   status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
                              ota_codec_config_);
   CHECK(status == A2DP_SUCCESS);
@@ -1612,16 +1452,93 @@
   return false;
 }
 
+bool A2dpCodecConfigSbcBase::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_SBC_CIE peer_info_cie;
+  uint8_t samp_freq;
+  uint8_t ch_mode;
+  const tA2DP_SBC_CIE* p_a2dp_sbc_caps =
+      (is_source_) ? &a2dp_sbc_source_caps : &a2dp_sbc_sink_caps;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoSbc(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  samp_freq = p_a2dp_sbc_caps->samp_freq & peer_info_cie.samp_freq;
+  if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      p_a2dp_sbc_caps->bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  ch_mode = p_a2dp_sbc_caps->ch_mode & peer_info_cie.ch_mode;
+  if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+  if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+  if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                             ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
+
 A2dpCodecConfigSbcSink::A2dpCodecConfigSbcSink(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_SBC, "SBC(Sink)",
-                      codec_priority) {}
+    : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SINK_SBC, "SBC(Sink)",
+                             codec_priority, false) {}
 
 A2dpCodecConfigSbcSink::~A2dpCodecConfigSbcSink() {}
 
 bool A2dpCodecConfigSbcSink::init() {
   if (!isValid()) return false;
 
+  // Load the decoder
+  if (!A2DP_LoadDecoderSbc()) {
+    LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+    return false;
+  }
+
   return true;
 }
 
@@ -1630,14 +1547,6 @@
   return false;
 }
 
-bool A2dpCodecConfigSbcSink::setCodecConfig(
-    UNUSED_ATTR const uint8_t* p_peer_codec_info,
-    UNUSED_ATTR bool is_capability,
-    UNUSED_ATTR uint8_t* p_result_codec_config) {
-  // TODO: This method applies only to Source codecs
-  return false;
-}
-
 bool A2dpCodecConfigSbcSink::updateEncoderUserConfig(
     UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
     UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
@@ -1650,3 +1559,8 @@
   // TODO: This method applies only to Source codecs
   return 0;
 }
+
+int A2dpCodecConfigSbcSink::getEffectiveMtu() const {
+  // TODO: This method applies only to Source codecs
+  return 0;
+}
diff --git a/stack/a2dp/a2dp_sbc_decoder.cc b/stack/a2dp/a2dp_sbc_decoder.cc
new file mode 100644
index 0000000..bc64513
--- /dev/null
+++ b/stack/a2dp/a2dp_sbc_decoder.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "a2dp_sbc_decoder"
+
+#include "a2dp_sbc_decoder.h"
+
+#include <base/logging.h>
+
+#include "embdrv/sbc/decoder/include/oi_codec_sbc.h"
+#include "embdrv/sbc/decoder/include/oi_status.h"
+#include "osi/include/log.h"
+
+typedef struct {
+  OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
+  uint32_t context_data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+  int16_t decode_buf[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+  decoded_data_callback_t decode_callback;
+} tA2DP_SBC_DECODER_CB;
+
+static tA2DP_SBC_DECODER_CB a2dp_sbc_decoder_cb;
+
+bool A2DP_LoadDecoderSbc(void) {
+  // Nothing to do - the library is statically linked
+  return true;
+}
+
+void A2DP_UnloadDecoderSbc(void) { a2dp_sbc_decoder_cleanup(); }
+
+bool a2dp_sbc_decoder_init(decoded_data_callback_t decode_callback) {
+  OI_STATUS status = OI_CODEC_SBC_DecoderReset(
+      &a2dp_sbc_decoder_cb.decoder_context, a2dp_sbc_decoder_cb.context_data,
+      sizeof(a2dp_sbc_decoder_cb.context_data), 2, 2, false);
+  if (!OI_SUCCESS(status)) {
+    LOG_ERROR(LOG_TAG,
+              "%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
+              __func__, status);
+    return false;
+  }
+
+  a2dp_sbc_decoder_cb.decode_callback = decode_callback;
+  return true;
+}
+
+void a2dp_sbc_decoder_cleanup(void) {
+  // Do nothing.
+}
+
+bool a2dp_sbc_decoder_decode_packet(BT_HDR* p_buf) {
+  uint8_t* data = p_buf->data + p_buf->offset;
+  size_t data_size = p_buf->len;
+
+  if (data_size == 0) {
+    LOG_ERROR(LOG_TAG, "%s: Empty packet", __func__);
+    return false;
+  }
+  size_t num_frames = data[0] & 0xf;
+  data += 1;
+  data_size -= 1;
+
+  const OI_BYTE* oi_data = data;
+  uint32_t oi_size = data_size;
+  size_t out_avail = sizeof(a2dp_sbc_decoder_cb.decode_buf);
+  int16_t* out_ptr = a2dp_sbc_decoder_cb.decode_buf;
+
+  for (size_t i = 0; i < num_frames; ++i) {
+    uint32_t out_size = out_avail;
+    OI_STATUS status =
+        OI_CODEC_SBC_DecodeFrame(&a2dp_sbc_decoder_cb.decoder_context, &oi_data,
+                                 &oi_size, out_ptr, &out_size);
+    if (!OI_SUCCESS(status)) {
+      LOG_ERROR(LOG_TAG, "%s: Decoding failure: %d", __func__, status);
+      return false;
+    }
+    out_avail -= out_size;
+    out_ptr += out_size / sizeof(*out_ptr);
+  }
+
+  size_t out_used =
+      (out_ptr - a2dp_sbc_decoder_cb.decode_buf) * sizeof(*out_ptr);
+  a2dp_sbc_decoder_cb.decode_callback(
+      reinterpret_cast<uint8_t*>(a2dp_sbc_decoder_cb.decode_buf), out_used);
+  return true;
+}
diff --git a/stack/a2dp/a2dp_sbc_encoder.cc b/stack/a2dp/a2dp_sbc_encoder.cc
index e4c2049..bd09989 100644
--- a/stack/a2dp/a2dp_sbc_encoder.cc
+++ b/stack/a2dp/a2dp_sbc_encoder.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -118,13 +118,13 @@
                                     bool* p_restart_input,
                                     bool* p_restart_output,
                                     bool* p_config_updated);
-static bool a2dp_sbc_read_feeding(void);
+static bool a2dp_sbc_read_feeding(uint32_t* bytes);
 static void a2dp_sbc_encode_frames(uint8_t nb_frame);
 static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
                                              uint8_t* num_of_frames,
                                              uint64_t timestamp_us);
 static uint8_t calculate_max_frames_per_packet(void);
-static uint16_t a2dp_sbc_source_rate(void);
+static uint16_t a2dp_sbc_source_rate();
 static uint32_t a2dp_sbc_frame_length(void);
 
 bool A2DP_LoadEncoderSbc(void) {
@@ -160,7 +160,7 @@
                           &restart_input, &restart_output, &config_updated);
 }
 
-bool A2dpCodecConfigSbc::updateEncoderUserConfig(
+bool A2dpCodecConfigSbcSource::updateEncoderUserConfig(
     const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
     bool* p_restart_output, bool* p_config_updated) {
   a2dp_sbc_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
@@ -222,6 +222,7 @@
   LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
             __func__, p_feeding_params->sample_rate,
             p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+  a2dp_sbc_feeding_reset();
 
   // The codec parameters
   p_encoder_params->s16ChannelMode = A2DP_GetChannelModeCodeSbc(p_codec_info);
@@ -368,7 +369,7 @@
   LOG_DEBUG(LOG_TAG, "%s: final bit rate %d, final bit pool %d", __func__,
             p_encoder_params->u16BitRate, p_encoder_params->s16BitPool);
 
-  /* Reset entirely the SBC encoder */
+  /* Reset the SBC encoder */
   SBC_Encoder_Init(&a2dp_sbc_encoder_cb.sbc_encoder_params);
   a2dp_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet();
 }
@@ -529,8 +530,11 @@
       p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
 
   uint8_t last_frame_len = 0;
+
   while (nb_frame) {
     BT_HDR* p_buf = (BT_HDR*)osi_malloc(A2DP_SBC_BUFFER_SIZE);
+    uint32_t bytes_read = 0;
+
     p_buf->offset = A2DP_SBC_OFFSET;
     p_buf->len = 0;
     p_buf->layer_specific = 0;
@@ -540,11 +544,11 @@
       /* Fill allocated buffer with 0 */
       memset(a2dp_sbc_encoder_cb.pcmBuffer, 0,
              blocm_x_subband * p_encoder_params->s16NumOfChannels);
-
       //
       // Read the PCM data and encode it. If necessary, upsample the data.
       //
-      if (a2dp_sbc_read_feeding()) {
+      uint32_t num_bytes = 0;
+      if (a2dp_sbc_read_feeding(&num_bytes)) {
         uint8_t* output = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
         int16_t* input = a2dp_sbc_encoder_cb.pcmBuffer;
         uint16_t output_len = SBC_Encode(p_encoder_params, input, output);
@@ -554,6 +558,8 @@
         p_buf->len += output_len;
         nb_frame--;
         p_buf->layer_specific++;
+
+        bytes_read += num_bytes;
       } else {
         LOG_WARN(LOG_TAG, "%s: underflow %d, %d", __func__, nb_frame,
                  a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue);
@@ -580,7 +586,9 @@
 
       uint8_t done_nb_frame = remain_nb_frame - nb_frame;
       remain_nb_frame = nb_frame;
-      if (!a2dp_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+      if (!a2dp_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                bytes_read))
+        return;
     } else {
       a2dp_sbc_encoder_cb.stats.media_read_total_dropped_packets++;
       osi_free(p_buf);
@@ -588,7 +596,7 @@
   }
 }
 
-static bool a2dp_sbc_read_feeding(void) {
+static bool a2dp_sbc_read_feeding(uint32_t* bytes_read) {
   SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
   uint16_t blocm_x_subband =
       p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
@@ -639,6 +647,7 @@
     a2dp_sbc_encoder_cb.stats.media_read_total_actual_read_bytes +=
         nb_byte_read;
 
+    *bytes_read = nb_byte_read;
     if (nb_byte_read != read_size) {
       a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue += nb_byte_read;
       return false;
@@ -823,7 +832,7 @@
   return result;
 }
 
-static uint16_t a2dp_sbc_source_rate(void) {
+static uint16_t a2dp_sbc_source_rate() {
   uint16_t rate = A2DP_SBC_DEFAULT_BITRATE;
 
   /* restrict bitrate if a2dp link is non-edr */
@@ -893,11 +902,22 @@
   return frame_len;
 }
 
-period_ms_t A2dpCodecConfigSbc::encoderIntervalMs() const {
+uint32_t a2dp_sbc_get_bitrate() {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  LOG_DEBUG(LOG_TAG, "%s: bit rate %d ", __func__,
+            p_encoder_params->u16BitRate);
+  return p_encoder_params->u16BitRate * 1000;
+}
+
+period_ms_t A2dpCodecConfigSbcSource::encoderIntervalMs() const {
   return a2dp_sbc_get_encoder_interval_ms();
 }
 
-void A2dpCodecConfigSbc::debug_codec_dump(int fd) {
+int A2dpCodecConfigSbcSource::getEffectiveMtu() const {
+  return a2dp_sbc_encoder_cb.TxAaMtuSize;
+}
+
+void A2dpCodecConfigSbcSource::debug_codec_dump(int fd) {
   a2dp_sbc_encoder_stats_t* stats = &a2dp_sbc_encoder_cb.stats;
 
   A2dpCodecConfig::debug_codec_dump(fd);
diff --git a/stack/a2dp/a2dp_sbc_up_sample.cc b/stack/a2dp/a2dp_sbc_up_sample.cc
index da15fe9..28cac85 100644
--- a/stack/a2dp/a2dp_sbc_up_sample.cc
+++ b/stack/a2dp/a2dp_sbc_up_sample.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/a2dp/a2dp_vendor.cc b/stack/a2dp/a2dp_vendor.cc
index f0fc277..1a6dcc2 100644
--- a/stack/a2dp/a2dp_vendor.cc
+++ b/stack/a2dp/a2dp_vendor.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -122,17 +122,6 @@
   return false;
 }
 
-tA2DP_STATUS A2DP_VendorBuildSrc2SinkConfig(
-    UNUSED_ATTR const uint8_t* p_src_cap, UNUSED_ATTR uint8_t* p_pref_cfg) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
-
-  // Add checks based on <vendor_id, codec_id>
-  // NOTE: Should be done only for local Sink codecs.
-
-  return A2DP_NS_CODEC_TYPE;
-}
-
 uint32_t A2DP_VendorCodecGetVendorId(const uint8_t* p_codec_info) {
   const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX];
 
@@ -287,6 +276,32 @@
   return false;
 }
 
+int A2DP_VendorGetBitRate(const uint8_t* p_codec_info) {
+  uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Check for aptX
+  if (vendor_id == A2DP_APTX_VENDOR_ID &&
+      codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+    return A2DP_VendorGetBitRateAptx(p_codec_info);
+  }
+
+  // Check for aptX-HD
+  if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+      codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+    return A2DP_VendorGetBitRateAptxHd(p_codec_info);
+  }
+
+  // Check for LDAC
+  if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+    return A2DP_VendorGetBitRateLdac(p_codec_info);
+  }
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
 int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info) {
   uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
   uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -350,18 +365,6 @@
   return -1;
 }
 
-int A2DP_VendorGetSinkFramesCountToProcess(
-    UNUSED_ATTR uint64_t time_interval_ms,
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
-
-  // Add checks based on <vendor_id, codec_id>
-  // NOTE: Should be done only for local Sink codecs.
-
-  return -1;
-}
-
 bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
                                    const uint8_t* p_data,
                                    uint32_t* p_timestamp) {
@@ -448,6 +451,12 @@
   return NULL;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
+    const uint8_t* p_codec_info) {
+  // We do not support vendor codecs for decoding right now.
+  return NULL;
+}
+
 bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info) {
   uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
   uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -501,12 +510,22 @@
   return BTAV_A2DP_CODEC_INDEX_MAX;
 }
 
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndex(const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return BTAV_A2DP_CODEC_INDEX_MAX;
+}
+
 const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index) {
   // Add checks based on codec_index
   switch (codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
       break;  // These are not vendor-specific codecs
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       return A2DP_VendorCodecIndexStrAptx();
@@ -523,12 +542,13 @@
 }
 
 bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
-                                tAVDT_CFG* p_cfg) {
+                                AvdtpSepConfig* p_cfg) {
   // Add checks based on codec_index
   switch (codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
       break;  // These are not vendor-specific codecs
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       return A2DP_VendorInitCodecConfigAptx(p_cfg);
@@ -544,28 +564,29 @@
   return false;
 }
 
-bool A2DP_VendorDumpCodecInfo(const uint8_t* p_codec_info) {
+std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info) {
   uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
   uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
 
   // Check for aptX
   if (vendor_id == A2DP_APTX_VENDOR_ID &&
       codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
-    return A2DP_VendorDumpCodecInfoAptx(p_codec_info);
+    return A2DP_VendorCodecInfoStringAptx(p_codec_info);
   }
 
   // Check for aptX-HD
   if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
       codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
-    return A2DP_VendorDumpCodecInfoAptxHd(p_codec_info);
+    return A2DP_VendorCodecInfoStringAptxHd(p_codec_info);
   }
 
   // Check for LDAC
   if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
-    return A2DP_VendorDumpCodecInfoLdac(p_codec_info);
+    return A2DP_VendorCodecInfoStringLdac(p_codec_info);
   }
 
   // Add checks based on <vendor_id, codec_id>
 
-  return false;
+  return "Unsupported codec vendor_id: " + loghex(vendor_id) +
+         " codec_id: " + loghex(codec_id);
 }
diff --git a/stack/a2dp/a2dp_vendor_aptx.cc b/stack/a2dp/a2dp_vendor_aptx.cc
index 92ff7c8..7017f06 100644
--- a/stack/a2dp/a2dp_vendor_aptx.cc
+++ b/stack/a2dp/a2dp_vendor_aptx.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -33,6 +33,7 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx_encoder.h"
 #include "bt_utils.h"
+#include "btif_av_co.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 
@@ -48,7 +49,7 @@
 } tA2DP_APTX_CIE;
 
 /* aptX Source codec capabilities */
-static const tA2DP_APTX_CIE a2dp_aptx_caps = {
+static const tA2DP_APTX_CIE a2dp_aptx_source_caps = {
     A2DP_APTX_VENDOR_ID,                                       /* vendorId */
     A2DP_APTX_CODEC_ID_BLUETOOTH,                              /* codecId */
     (A2DP_APTX_SAMPLERATE_44100 | A2DP_APTX_SAMPLERATE_48000), /* sampleRate */
@@ -62,7 +63,7 @@
 static const tA2DP_APTX_CIE a2dp_aptx_default_config = {
     A2DP_APTX_VENDOR_ID,               /* vendorId */
     A2DP_APTX_CODEC_ID_BLUETOOTH,      /* codecId */
-    A2DP_APTX_SAMPLERATE_44100,        /* sampleRate */
+    A2DP_APTX_SAMPLERATE_48000,        /* sampleRate */
     A2DP_APTX_CHANNELS_STEREO,         /* channelMode */
     A2DP_APTX_FUTURE_1,                /* future1 */
     A2DP_APTX_FUTURE_2,                /* future2 */
@@ -279,6 +280,13 @@
          (aptx_cie_a.channelMode == aptx_cie_b.channelMode);
 }
 
+int A2DP_VendorGetBitRateAptx(const uint8_t* p_codec_info) {
+  A2dpCodecConfig* CodecConfig = bta_av_get_a2dp_current_codec();
+  tA2DP_BITS_PER_SAMPLE bits_per_sample = CodecConfig->getAudioBitsPerSample();
+  uint16_t samplerate = A2DP_GetTrackSampleRate(p_codec_info);
+  return (samplerate * bits_per_sample * 2) / 4;
+}
+
 int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info) {
   tA2DP_APTX_CIE aptx_cie;
 
@@ -332,35 +340,40 @@
   return true;
 }
 
-bool A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info) {
+std::string A2DP_VendorCodecInfoStringAptx(const uint8_t* p_codec_info) {
+  std::stringstream res;
+  std::string field;
   tA2DP_STATUS a2dp_status;
   tA2DP_APTX_CIE aptx_cie;
 
-  LOG_VERBOSE(LOG_TAG, "%s", __func__);
-
   a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, true);
   if (a2dp_status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAptx fail:%d", __func__, a2dp_status);
-    return false;
+    res << "A2DP_ParseInfoAptx fail: " << loghex(a2dp_status);
+    return res.str();
   }
 
-  LOG_VERBOSE(LOG_TAG, "\tsamp_freq: 0x%x", aptx_cie.sampleRate);
-  if (aptx_cie.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (44100)");
-  }
-  if (aptx_cie.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (48000)");
-  }
+  res << "\tname: aptX\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tch_mode: 0x%x", aptx_cie.channelMode);
-  if (aptx_cie.channelMode & A2DP_APTX_CHANNELS_MONO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Mono)");
-  }
-  if (aptx_cie.channelMode & A2DP_APTX_CHANNELS_STEREO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Stereo)");
-  }
+  // Sample frequency
+  field.clear();
+  AppendField(&field, (aptx_cie.sampleRate == 0), "NONE");
+  AppendField(&field, (aptx_cie.sampleRate & A2DP_APTX_SAMPLERATE_44100),
+              "44100");
+  AppendField(&field, (aptx_cie.sampleRate & A2DP_APTX_SAMPLERATE_48000),
+              "48000");
+  res << "\tsamp_freq: " << field << " (" << loghex(aptx_cie.sampleRate)
+      << ")\n";
 
-  return true;
+  // Channel mode
+  field.clear();
+  AppendField(&field, (aptx_cie.channelMode == 0), "NONE");
+  AppendField(&field, (aptx_cie.channelMode & A2DP_APTX_CHANNELS_MONO), "Mono");
+  AppendField(&field, (aptx_cie.channelMode & A2DP_APTX_CHANNELS_STEREO),
+              "Stereo");
+  res << "\tch_mode: " << field << " (" << loghex(aptx_cie.channelMode)
+      << ")\n";
+
+  return res.str();
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptx(
@@ -387,8 +400,8 @@
 
 const char* A2DP_VendorCodecIndexStrAptx(void) { return "aptX"; }
 
-bool A2DP_VendorInitCodecConfigAptx(tAVDT_CFG* p_cfg) {
-  if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_caps,
+bool A2DP_VendorInitCodecConfigAptx(AvdtpSepConfig* p_cfg) {
+  if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_source_caps,
                          p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -409,17 +422,18 @@
     : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX",
                       codec_priority) {
   // Compute the local capability
-  if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+  if (a2dp_aptx_source_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+  if (a2dp_aptx_source_caps.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_aptx_caps.bits_per_sample;
-  if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_aptx_source_caps.bits_per_sample;
+  if (a2dp_aptx_source_caps.channelMode & A2DP_APTX_CHANNELS_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_STEREO) {
+  if (a2dp_aptx_source_caps.channelMode & A2DP_APTX_CHANNELS_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
@@ -489,6 +503,8 @@
     case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       break;
   }
@@ -582,7 +598,7 @@
                                          bool is_capability,
                                          uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_APTX_CIE sink_info_cie;
+  tA2DP_APTX_CIE peer_info_cie;
   tA2DP_APTX_CIE result_config_cie;
   uint8_t sampleRate;
   uint8_t channelMode;
@@ -604,9 +620,9 @@
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoAptx(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoAptx(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -615,13 +631,13 @@
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_aptx_caps.vendorId;
-  result_config_cie.codecId = a2dp_aptx_caps.codecId;
+  result_config_cie.vendorId = a2dp_aptx_source_caps.vendorId;
+  result_config_cie.codecId = a2dp_aptx_source_caps.codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_aptx_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = a2dp_aptx_source_caps.sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -642,6 +658,8 @@
     case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
       codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
@@ -676,7 +694,7 @@
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_aptx_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_aptx_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -689,9 +707,10 @@
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_caps.sampleRate, sink_info_cie.sampleRate);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_source_caps.sampleRate,
+              peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -718,7 +737,7 @@
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_aptx_caps.bits_per_sample;
+        a2dp_aptx_source_caps.bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -752,7 +771,7 @@
   //
   // Select the channel mode
   //
-  channelMode = a2dp_aptx_caps.channelMode & sink_info_cie.channelMode;
+  channelMode = a2dp_aptx_source_caps.channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -803,7 +822,7 @@
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_aptx_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_aptx_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -816,17 +835,20 @@
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_caps.channelMode, sink_info_cie.channelMode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_source_caps.channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
   //
   // Set the rest of the fields as bit-wise AND operation
   //
-  result_config_cie.future1 = a2dp_aptx_caps.future1 & sink_info_cie.future1;
-  result_config_cie.future2 = a2dp_aptx_caps.future2 & sink_info_cie.future2;
+  result_config_cie.future1 =
+      a2dp_aptx_source_caps.future1 & peer_info_cie.future1;
+  result_config_cie.future2 =
+      a2dp_aptx_source_caps.future2 & peer_info_cie.future2;
 
   if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
                          p_result_codec_config) != A2DP_SUCCESS) {
@@ -848,10 +870,10 @@
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -875,3 +897,64 @@
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+bool A2dpCodecConfigAptx::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_APTX_CIE peer_info_cie;
+  uint8_t sampleRate;
+  uint8_t channelMode;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoAptx(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = a2dp_aptx_source_caps.sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      a2dp_aptx_source_caps.bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = a2dp_aptx_source_caps.channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_APTX_CHANNELS_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_APTX_CHANNELS_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                              ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
diff --git a/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
index 3fcb6de..0252935 100644
--- a/stack/a2dp/a2dp_vendor_aptx_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -61,7 +61,7 @@
 #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET - AVDT_MEDIA_HDR_SIZE)
 #endif
 
-#define A2DP_APTX_MAX_PCM_BYTES_PER_READ 1024
+#define A2DP_APTX_MAX_PCM_BYTES_PER_READ 4096
 
 typedef struct {
   uint64_t sleep_time_ns;
@@ -263,8 +263,7 @@
   LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
             __func__, p_feeding_params->sample_rate,
             p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
-
-  aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
+  a2dp_vendor_aptx_feeding_reset();
 }
 
 void a2dp_vendor_aptx_encoder_cleanup(void) {
@@ -391,32 +390,38 @@
   //
   // Read the PCM data and encode it
   //
-  LOG_VERBOSE(LOG_TAG, "%s: %u PCM reads of size %u", __func__,
-              framing_params->pcm_reads, framing_params->pcm_bytes_per_read);
+  uint16_t read_buffer16[A2DP_APTX_MAX_PCM_BYTES_PER_READ / sizeof(uint16_t)];
+  uint32_t expected_read_bytes =
+      framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
   size_t encoded_ptr_index = 0;
   size_t pcm_bytes_encoded = 0;
+  uint32_t bytes_read = 0;
+
   a2dp_aptx_encoder_cb.stats.media_read_total_expected_packets++;
-  a2dp_aptx_encoder_cb.stats.media_read_total_expected_reads_count +=
-      framing_params->pcm_reads;
+  a2dp_aptx_encoder_cb.stats.media_read_total_expected_reads_count++;
   a2dp_aptx_encoder_cb.stats.media_read_total_expected_read_bytes +=
-      framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
-  for (size_t reads = 0; reads < framing_params->pcm_reads; reads++) {
-    uint16_t read_buffer16[A2DP_APTX_MAX_PCM_BYTES_PER_READ / sizeof(uint16_t)];
-    size_t pcm_bytes_read = a2dp_aptx_encoder_cb.read_callback(
-        (uint8_t*)read_buffer16, framing_params->pcm_bytes_per_read);
-    a2dp_aptx_encoder_cb.stats.media_read_total_actual_read_bytes +=
-        pcm_bytes_read;
-    if (pcm_bytes_read < framing_params->pcm_bytes_per_read) {
-      LOG_WARN(LOG_TAG,
-               "%s: underflow at PCM reading iteration %zu: read %zu "
-               "instead of %d",
-               __func__, reads, pcm_bytes_read,
-               framing_params->pcm_bytes_per_read);
-      break;
-    }
-    a2dp_aptx_encoder_cb.stats.media_read_total_actual_reads_count++;
+      expected_read_bytes;
+
+  LOG_VERBOSE(LOG_TAG, "%s: PCM read of size %u", __func__,
+              expected_read_bytes);
+  bytes_read = a2dp_aptx_encoder_cb.read_callback((uint8_t*)read_buffer16,
+                                                  expected_read_bytes);
+  a2dp_aptx_encoder_cb.stats.media_read_total_actual_read_bytes += bytes_read;
+  if (bytes_read < expected_read_bytes) {
+    LOG_WARN(LOG_TAG,
+             "%s: underflow at PCM reading: read %u bytes instead of %u",
+             __func__, bytes_read, expected_read_bytes);
+    a2dp_aptx_encoder_cb.stats.media_read_total_dropped_packets++;
+    osi_free(p_buf);
+    return;
+  }
+  a2dp_aptx_encoder_cb.stats.media_read_total_actual_reads_count++;
+
+  for (uint32_t reads = 0, offset = 0; reads < framing_params->pcm_reads;
+       reads++, offset +=
+                (framing_params->pcm_bytes_per_read / sizeof(uint16_t))) {
     pcm_bytes_encoded += aptx_encode_16bit(framing_params, &encoded_ptr_index,
-                                           read_buffer16, encoded_ptr);
+                                           read_buffer16 + offset, encoded_ptr);
   }
 
   // Compute the number of encoded bytes
@@ -435,7 +440,7 @@
   a2dp_aptx_encoder_cb.timestamp += rtp_timestamp;
 
   if (p_buf->len > 0) {
-    a2dp_aptx_encoder_cb.enqueue_callback(p_buf, 1);
+    a2dp_aptx_encoder_cb.enqueue_callback(p_buf, 1, bytes_read);
   } else {
     a2dp_aptx_encoder_cb.stats.media_read_total_dropped_packets++;
     osi_free(p_buf);
@@ -479,6 +484,10 @@
   return a2dp_vendor_aptx_get_encoder_interval_ms();
 }
 
+int A2dpCodecConfigAptx::getEffectiveMtu() const {
+  return a2dp_aptx_encoder_cb.peer_mtu;
+}
+
 void A2dpCodecConfigAptx::debug_codec_dump(int fd) {
   a2dp_aptx_encoder_stats_t* stats = &a2dp_aptx_encoder_cb.stats;
 
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd.cc b/stack/a2dp/a2dp_vendor_aptx_hd.cc
index 85f2365..798e4fd 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -33,6 +33,7 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx_hd_encoder.h"
 #include "bt_utils.h"
+#include "btif_av_co.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 
@@ -50,7 +51,7 @@
 } tA2DP_APTX_HD_CIE;
 
 /* aptX-HD Source codec capabilities */
-static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_caps = {
+static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_source_caps = {
     A2DP_APTX_HD_VENDOR_ID,          /* vendorId */
     A2DP_APTX_HD_CODEC_ID_BLUETOOTH, /* codecId */
     (A2DP_APTX_HD_SAMPLERATE_44100 |
@@ -67,7 +68,7 @@
 static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_default_config = {
     A2DP_APTX_HD_VENDOR_ID,            /* vendorId */
     A2DP_APTX_HD_CODEC_ID_BLUETOOTH,   /* codecId */
-    A2DP_APTX_HD_SAMPLERATE_44100,     /* sampleRate */
+    A2DP_APTX_HD_SAMPLERATE_48000,     /* sampleRate */
     A2DP_APTX_HD_CHANNELS_STEREO,      /* channelMode */
     A2DP_APTX_HD_ACL_SPRINT_RESERVED0, /* acl_sprint_reserved0 */
     A2DP_APTX_HD_ACL_SPRINT_RESERVED1, /* acl_sprint_reserved1 */
@@ -293,6 +294,13 @@
          (aptx_hd_cie_a.channelMode == aptx_hd_cie_b.channelMode);
 }
 
+int A2DP_VendorGetBitRateAptxHd(const uint8_t* p_codec_info) {
+  A2dpCodecConfig* CodecConfig = bta_av_get_a2dp_current_codec();
+  tA2DP_BITS_PER_SAMPLE bits_per_sample = CodecConfig->getAudioBitsPerSample();
+  uint16_t samplerate = A2DP_GetTrackSampleRate(p_codec_info);
+  return (samplerate * bits_per_sample * 2) / 4;
+}
+
 int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info) {
   tA2DP_APTX_HD_CIE aptx_hd_cie;
 
@@ -348,36 +356,41 @@
   return true;
 }
 
-bool A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info) {
+std::string A2DP_VendorCodecInfoStringAptxHd(const uint8_t* p_codec_info) {
+  std::stringstream res;
+  std::string field;
   tA2DP_STATUS a2dp_status;
   tA2DP_APTX_HD_CIE aptx_hd_cie;
 
-  LOG_VERBOSE(LOG_TAG, "%s", __func__);
-
   a2dp_status = A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, true);
   if (a2dp_status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAptxHd fail:%d", __func__,
-              a2dp_status);
-    return false;
+    res << "A2DP_ParseInfoAptxHd fail: " << loghex(a2dp_status);
+    return res.str();
   }
 
-  LOG_VERBOSE(LOG_TAG, "\tsamp_freq: 0x%x", aptx_hd_cie.sampleRate);
-  if (aptx_hd_cie.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (44100)");
-  }
-  if (aptx_hd_cie.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (48000)");
-  }
+  res << "\tname: aptX-HD\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tch_mode: 0x%x", aptx_hd_cie.channelMode);
-  if (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Mono)");
-  }
-  if (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Stereo)");
-  }
+  // Sample frequency
+  field.clear();
+  AppendField(&field, (aptx_hd_cie.sampleRate == 0), "NONE");
+  AppendField(&field, (aptx_hd_cie.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100),
+              "44100");
+  AppendField(&field, (aptx_hd_cie.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000),
+              "48000");
+  res << "\tsamp_freq: " << field << " (" << loghex(aptx_hd_cie.sampleRate)
+      << ")\n";
 
-  return true;
+  // Channel mode
+  field.clear();
+  AppendField(&field, (aptx_hd_cie.channelMode == 0), "NONE");
+  AppendField(&field, (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_MONO),
+              "Mono");
+  AppendField(&field, (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_STEREO),
+              "Stereo");
+  res << "\tch_mode: " << field << " (" << loghex(aptx_hd_cie.channelMode)
+      << ")\n";
+
+  return res.str();
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptxHd(
@@ -404,8 +417,8 @@
 
 const char* A2DP_VendorCodecIndexStrAptxHd(void) { return "aptX-HD"; }
 
-bool A2DP_VendorInitCodecConfigAptxHd(tAVDT_CFG* p_cfg) {
-  if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_hd_caps,
+bool A2DP_VendorInitCodecConfigAptxHd(AvdtpSepConfig* p_cfg) {
+  if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_hd_source_caps,
                            p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -426,17 +439,18 @@
     : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD",
                       codec_priority) {
   // Compute the local capability
-  if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+  if (a2dp_aptx_hd_source_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+  if (a2dp_aptx_hd_source_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_aptx_hd_caps.bits_per_sample;
-  if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_aptx_hd_source_caps.bits_per_sample;
+  if (a2dp_aptx_hd_source_caps.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+  if (a2dp_aptx_hd_source_caps.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
@@ -506,6 +520,8 @@
     case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       break;
   }
@@ -599,7 +615,7 @@
                                            bool is_capability,
                                            uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_APTX_HD_CIE sink_info_cie;
+  tA2DP_APTX_HD_CIE peer_info_cie;
   tA2DP_APTX_HD_CIE result_config_cie;
   uint8_t sampleRate;
   uint8_t channelMode;
@@ -621,9 +637,9 @@
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoAptxHd(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoAptxHd(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -632,13 +648,13 @@
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_aptx_hd_caps.vendorId;
-  result_config_cie.codecId = a2dp_aptx_hd_caps.codecId;
+  result_config_cie.vendorId = a2dp_aptx_hd_source_caps.vendorId;
+  result_config_cie.codecId = a2dp_aptx_hd_source_caps.codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_aptx_hd_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = a2dp_aptx_hd_source_caps.sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -659,6 +675,8 @@
     case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
       codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
@@ -693,7 +711,7 @@
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_aptx_hd_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_aptx_hd_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -706,9 +724,10 @@
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_hd_caps.sampleRate, sink_info_cie.sampleRate);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_hd_source_caps.sampleRate,
+              peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -735,7 +754,7 @@
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_aptx_hd_caps.bits_per_sample;
+        a2dp_aptx_hd_source_caps.bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -769,7 +788,8 @@
   //
   // Select the channel mode
   //
-  channelMode = a2dp_aptx_hd_caps.channelMode & sink_info_cie.channelMode;
+  channelMode =
+      a2dp_aptx_hd_source_caps.channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -820,7 +840,7 @@
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_aptx_hd_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_aptx_hd_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -833,10 +853,10 @@
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_hd_caps.channelMode,
-              sink_info_cie.channelMode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_hd_source_caps.channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
@@ -844,17 +864,17 @@
   // Set the rest of the fields as bit-wise AND operation
   //
   result_config_cie.acl_sprint_reserved0 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved0 &
-      sink_info_cie.acl_sprint_reserved0;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved0 &
+      peer_info_cie.acl_sprint_reserved0;
   result_config_cie.acl_sprint_reserved1 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved1 &
-      sink_info_cie.acl_sprint_reserved1;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved1 &
+      peer_info_cie.acl_sprint_reserved1;
   result_config_cie.acl_sprint_reserved2 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved2 &
-      sink_info_cie.acl_sprint_reserved2;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved2 &
+      peer_info_cie.acl_sprint_reserved2;
   result_config_cie.acl_sprint_reserved3 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved3 &
-      sink_info_cie.acl_sprint_reserved3;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved3 &
+      peer_info_cie.acl_sprint_reserved3;
 
   if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
                            p_result_codec_config) != A2DP_SUCCESS) {
@@ -876,10 +896,10 @@
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                   ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                   ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -902,3 +922,65 @@
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+bool A2dpCodecConfigAptxHd::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_APTX_HD_CIE peer_info_cie;
+  uint8_t sampleRate;
+  uint8_t channelMode;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoAptxHd(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = a2dp_aptx_hd_source_caps.sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      a2dp_aptx_hd_source_caps.bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode =
+      a2dp_aptx_hd_source_caps.channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                                ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
index 084291f..d72ec5a 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -61,7 +61,7 @@
 #define A2DP_APTX_HD_OFFSET AVDT_MEDIA_OFFSET
 #endif
 
-#define A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ 1024
+#define A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ 4096
 
 typedef struct {
   uint64_t sleep_time_ns;
@@ -90,7 +90,7 @@
   bool use_SCMS_T;
   bool is_peer_edr;          // True if the peer device supports EDR
   bool peer_supports_3mbps;  // True if the peer device supports 3Mbps EDR
-  uint16_t peer_mtu;         // // MTU of the A2DP peer
+  uint16_t peer_mtu;         // MTU of the A2DP peer
   uint32_t timestamp;        // Timestamp for the A2DP frames
 
   tA2DP_FEEDING_PARAMS feeding_params;
@@ -264,8 +264,7 @@
   LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
             __func__, p_feeding_params->sample_rate,
             p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
-
-  aptx_hd_init_framing_params(&a2dp_aptx_hd_encoder_cb.framing_params);
+  a2dp_vendor_aptx_hd_feeding_reset();
 }
 
 void a2dp_vendor_aptx_hd_encoder_cleanup(void) {
@@ -376,33 +375,41 @@
   //
   // Read the PCM data and encode it
   //
-  LOG_VERBOSE(LOG_TAG, "%s: %u PCM reads of size %u", __func__,
-              framing_params->pcm_reads, framing_params->pcm_bytes_per_read);
+  uint32_t
+      read_buffer32[A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ / sizeof(uint32_t)];
+  uint32_t expected_read_bytes =
+      framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
   size_t encoded_ptr_index = 0;
   size_t pcm_bytes_encoded = 0;
+  uint32_t bytes_read = 0;
+
   a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_packets++;
-  a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_reads_count +=
-      framing_params->pcm_reads;
+  a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_reads_count++;
   a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_read_bytes +=
-      framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
-  for (size_t reads = 0; reads < framing_params->pcm_reads; reads++) {
-    uint32_t
-        read_buffer32[A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ / sizeof(uint32_t)];
-    size_t pcm_bytes_read = a2dp_aptx_hd_encoder_cb.read_callback(
-        (uint8_t*)read_buffer32, framing_params->pcm_bytes_per_read);
-    a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_read_bytes +=
-        pcm_bytes_read;
-    if (pcm_bytes_read < framing_params->pcm_bytes_per_read) {
-      LOG_WARN(LOG_TAG,
-               "%s: underflow at PCM reading iteration %zu: read %zu "
-               "instead of %d",
-               __func__, reads, pcm_bytes_read,
-               framing_params->pcm_bytes_per_read);
-      break;
-    }
-    a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_reads_count++;
-    pcm_bytes_encoded += aptx_hd_encode_24bit(
-        framing_params, &encoded_ptr_index, read_buffer32, encoded_ptr);
+      expected_read_bytes;
+
+  LOG_VERBOSE(LOG_TAG, "%s: PCM read of size %u", __func__,
+              expected_read_bytes);
+  bytes_read = a2dp_aptx_hd_encoder_cb.read_callback((uint8_t*)read_buffer32,
+                                                     expected_read_bytes);
+  a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_read_bytes +=
+      bytes_read;
+  if (bytes_read < expected_read_bytes) {
+    LOG_WARN(LOG_TAG,
+             "%s: underflow at PCM reading: read %u bytes instead of %u",
+             __func__, bytes_read, expected_read_bytes);
+    a2dp_aptx_hd_encoder_cb.stats.media_read_total_dropped_packets++;
+    osi_free(p_buf);
+    return;
+  }
+  a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_reads_count++;
+
+  for (uint32_t reads = 0, offset = 0; reads < framing_params->pcm_reads;
+       reads++, offset +=
+                framing_params->pcm_bytes_per_read / sizeof(uint32_t)) {
+    pcm_bytes_encoded +=
+        aptx_hd_encode_24bit(framing_params, &encoded_ptr_index,
+                             read_buffer32 + offset, encoded_ptr);
   }
 
   // Compute the number of encoded bytes
@@ -422,7 +429,7 @@
   a2dp_aptx_hd_encoder_cb.timestamp += rtp_timestamp;
 
   if (p_buf->len > 0) {
-    a2dp_aptx_hd_encoder_cb.enqueue_callback(p_buf, 1);
+    a2dp_aptx_hd_encoder_cb.enqueue_callback(p_buf, 1, bytes_read);
   } else {
     a2dp_aptx_hd_encoder_cb.stats.media_read_total_dropped_packets++;
     osi_free(p_buf);
@@ -474,6 +481,10 @@
   return a2dp_vendor_aptx_hd_get_encoder_interval_ms();
 }
 
+int A2dpCodecConfigAptxHd::getEffectiveMtu() const {
+  return a2dp_aptx_hd_encoder_cb.peer_mtu;
+}
+
 void A2dpCodecConfigAptxHd::debug_codec_dump(int fd) {
   a2dp_aptx_hd_encoder_stats_t* stats = &a2dp_aptx_hd_encoder_cb.stats;
 
diff --git a/stack/a2dp/a2dp_vendor_ldac.cc b/stack/a2dp/a2dp_vendor_ldac.cc
index e38424f..266db81 100644
--- a/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/stack/a2dp/a2dp_vendor_ldac.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -33,6 +33,7 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_ldac_encoder.h"
 #include "bt_utils.h"
+#include "btif_av_co.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 
@@ -47,7 +48,7 @@
 } tA2DP_LDAC_CIE;
 
 /* LDAC Source codec capabilities */
-static const tA2DP_LDAC_CIE a2dp_ldac_caps = {
+static const tA2DP_LDAC_CIE a2dp_ldac_source_caps = {
     A2DP_LDAC_VENDOR_ID,  // vendorId
     A2DP_LDAC_CODEC_ID,   // codecId
     // sampleRate
@@ -301,6 +302,36 @@
          (ldac_cie_a.channelMode == ldac_cie_b.channelMode);
 }
 
+int A2DP_VendorGetBitRateLdac(const uint8_t* p_codec_info) {
+  A2dpCodecConfig* current_codec = bta_av_get_a2dp_current_codec();
+  btav_a2dp_codec_config_t codec_config_ = current_codec->getCodecConfig();
+  int samplerate = A2DP_GetTrackSampleRate(p_codec_info);
+  switch (codec_config_.codec_specific_1 % 10) {
+    case 0:
+      if (samplerate == 44100 || samplerate == 88200)
+        return 909000;
+      else
+        return 990000;
+    case 1:
+      if (samplerate == 44100 || samplerate == 88200)
+        return 606000;
+      else
+        return 660000;
+    case 2:
+      if (samplerate == 44100 || samplerate == 88200)
+        return 303000;
+      else
+        return 330000;
+    case 3:
+    default:
+      if (samplerate == 44100 || samplerate == 88200)
+        return 909000;
+      else
+        return 990000;
+  }
+  return 0;
+}
+
 int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info) {
   tA2DP_LDAC_CIE ldac_cie;
 
@@ -398,50 +429,51 @@
   return true;
 }
 
-bool A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info) {
+std::string A2DP_VendorCodecInfoStringLdac(const uint8_t* p_codec_info) {
+  std::stringstream res;
+  std::string field;
   tA2DP_STATUS a2dp_status;
   tA2DP_LDAC_CIE ldac_cie;
 
-  LOG_VERBOSE(LOG_TAG, "%s", __func__);
-
   a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, true);
   if (a2dp_status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoLdac fail:%d", __func__, a2dp_status);
-    return false;
+    res << "A2DP_ParseInfoLdac fail: " << loghex(a2dp_status);
+    return res.str();
   }
 
-  LOG_VERBOSE(LOG_TAG, "\tsamp_freq: 0x%x", ldac_cie.sampleRate);
-  if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (44100)");
-  }
-  if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (48000)");
-  }
-  if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (88200)");
-  }
-  if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (96000)");
-  }
-  if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (176400)");
-  }
-  if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
-    LOG_VERBOSE(LOG_TAG, "\tsamp_freq: (192000)");
-  }
+  res << "\tname: LDAC\n";
 
-  LOG_VERBOSE(LOG_TAG, "\tch_mode: 0x%x", ldac_cie.channelMode);
-  if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Mono)");
-  }
-  if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Dual)");
-  }
-  if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
-    LOG_VERBOSE(LOG_TAG, "\tch_mode: (Stereo)");
-  }
+  // Sample frequency
+  field.clear();
+  AppendField(&field, (ldac_cie.sampleRate == 0), "NONE");
+  AppendField(&field, (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100),
+              "44100");
+  AppendField(&field, (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000),
+              "48000");
+  AppendField(&field, (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200),
+              "88200");
+  AppendField(&field, (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000),
+              "96000");
+  AppendField(&field, (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400),
+              "176400");
+  AppendField(&field, (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000),
+              "192000");
+  res << "\tsamp_freq: " << field << " (" << loghex(ldac_cie.sampleRate)
+      << ")\n";
 
-  return true;
+  // Channel mode
+  field.clear();
+  AppendField(&field, (ldac_cie.channelMode == 0), "NONE");
+  AppendField(&field, (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO),
+              "Mono");
+  AppendField(&field, (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL),
+              "Dual");
+  AppendField(&field, (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO),
+              "Stereo");
+  res << "\tch_mode: " << field << " (" << loghex(ldac_cie.channelMode)
+      << ")\n";
+
+  return res.str();
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
@@ -468,8 +500,8 @@
 
 const char* A2DP_VendorCodecIndexStrLdac(void) { return "LDAC"; }
 
-bool A2DP_VendorInitCodecConfigLdac(tAVDT_CFG* p_cfg) {
-  if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_caps,
+bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) {
+  if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_source_caps,
                          p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -515,32 +547,33 @@
     : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC",
                       codec_priority) {
   // Compute the local capability
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_ldac_caps.bits_per_sample;
-  if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_ldac_source_caps.bits_per_sample;
+  if (a2dp_ldac_source_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+  if (a2dp_ldac_source_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
-  if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+  if (a2dp_ldac_source_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
@@ -654,6 +687,8 @@
         return true;
       }
       break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       break;
   }
@@ -791,7 +826,7 @@
                                          bool is_capability,
                                          uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_LDAC_CIE sink_info_cie;
+  tA2DP_LDAC_CIE peer_info_cie;
   tA2DP_LDAC_CIE result_config_cie;
   uint8_t channelMode;
   uint8_t sampleRate;
@@ -814,9 +849,9 @@
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoLdac(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoLdac(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -825,13 +860,13 @@
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_ldac_caps.vendorId;
-  result_config_cie.codecId = a2dp_ldac_caps.codecId;
+  result_config_cie.vendorId = a2dp_ldac_source_caps.vendorId;
+  result_config_cie.codecId = a2dp_ldac_source_caps.codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_ldac_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -875,6 +910,8 @@
         codec_capability_.sample_rate = codec_user_config_.sample_rate;
         codec_config_.sample_rate = codec_user_config_.sample_rate;
       }
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
     case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
       codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
       codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
@@ -933,7 +970,7 @@
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_ldac_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_ldac_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -946,9 +983,10 @@
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_ldac_caps.sampleRate, sink_info_cie.sampleRate);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_ldac_source_caps.sampleRate,
+              peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -957,7 +995,7 @@
   //
   // NOTE: this information is NOT included in the LDAC A2DP codec description
   // that is sent OTA.
-  bits_per_sample = a2dp_ldac_caps.bits_per_sample;
+  bits_per_sample = a2dp_ldac_source_caps.bits_per_sample;
   codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
   switch (codec_user_config_.bits_per_sample) {
     case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
@@ -992,7 +1030,7 @@
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_ldac_caps.bits_per_sample;
+        a2dp_ldac_source_caps.bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -1002,7 +1040,7 @@
 
     // No user preference - the the codec audio config
     if (select_audio_bits_per_sample(&codec_audio_config_,
-                                     a2dp_ldac_caps.bits_per_sample,
+                                     a2dp_ldac_source_caps.bits_per_sample,
                                      &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1014,7 +1052,7 @@
     }
 
     // No user preference - use the best match
-    if (select_best_bits_per_sample(a2dp_ldac_caps.bits_per_sample,
+    if (select_best_bits_per_sample(a2dp_ldac_source_caps.bits_per_sample,
                                     &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1031,7 +1069,7 @@
   //
   // Select the channel mode
   //
-  channelMode = a2dp_ldac_caps.channelMode & sink_info_cie.channelMode;
+  channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -1095,7 +1133,7 @@
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_ldac_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_ldac_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1108,9 +1146,10 @@
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_ldac_caps.channelMode, sink_info_cie.channelMode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_ldac_source_caps.channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
@@ -1134,10 +1173,10 @@
   // Create a local copy of the peer codec capability, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -1160,3 +1199,84 @@
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+bool A2dpCodecConfigLdac::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_LDAC_CIE peer_info_cie;
+  uint8_t channelMode;
+  uint8_t sampleRate;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoLdac(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      a2dp_ldac_source_caps.bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+  if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                              ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
diff --git a/stack/a2dp/a2dp_vendor_ldac_abr.cc b/stack/a2dp/a2dp_vendor_ldac_abr.cc
index 784da88..7715af4 100644
--- a/stack/a2dp/a2dp_vendor_ldac_abr.cc
+++ b/stack/a2dp/a2dp_vendor_ldac_abr.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/stack/a2dp/a2dp_vendor_ldac_encoder.cc
index 4ca3cdf..21d5e72 100644
--- a/stack/a2dp/a2dp_vendor_ldac_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_ldac_encoder.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -180,7 +180,7 @@
                                               uint8_t* num_of_frames,
                                               uint64_t timestamp_us);
 static void a2dp_ldac_encode_frames(uint8_t nb_frame);
-static bool a2dp_ldac_read_feeding(uint8_t* read_buffer);
+static bool a2dp_ldac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read);
 static std::string quality_mode_index_to_name(int quality_mode_index);
 
 static void* load_func(const char* func_name) {
@@ -359,6 +359,7 @@
     }
     a2dp_ldac_encoder_cb.has_ldac_handle = true;
   }
+  CHECK(a2dp_ldac_encoder_cb.ldac_handle != nullptr);
 
   if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
     LOG_ERROR(LOG_TAG,
@@ -381,6 +382,7 @@
   LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
             __func__, p_feeding_params->sample_rate,
             p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+  a2dp_vendor_ldac_feeding_reset();
 
   // The codec parameters
   p_encoder_params->sample_rate =
@@ -493,8 +495,13 @@
       p_encoder_params->channel_mode, p_encoder_params->pcm_fmt,
       p_encoder_params->sample_rate);
   if (result != 0) {
-    LOG_ERROR(LOG_TAG, "%s: error initializing the LDAC encoder: %d", __func__,
-              result);
+    int err_code = ldac_get_error_code_func(a2dp_ldac_encoder_cb.ldac_handle);
+    LOG_ERROR(LOG_TAG,
+              "%s: error initializing the LDAC encoder: %d api_error = %d "
+              "handle_error = %d block_error = %d error_code = 0x%x",
+              __func__, result, LDACBT_API_ERR(err_code),
+              LDACBT_HANDLE_ERR(err_code), LDACBT_BLOCK_ERR(err_code),
+              err_code);
   }
 }
 
@@ -627,6 +634,7 @@
   int32_t out_frames = 0;
   int written = 0;
 
+  uint32_t bytes_read = 0;
   while (nb_frame) {
     BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
     p_buf->offset = A2DP_LDAC_OFFSET;
@@ -639,7 +647,9 @@
       //
       // Read the PCM data and encode it
       //
-      if (a2dp_ldac_read_feeding(read_buffer)) {
+      uint32_t temp_bytes_read = 0;
+      if (a2dp_ldac_read_feeding(read_buffer, &temp_bytes_read)) {
+        bytes_read += temp_bytes_read;
         uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
         if (a2dp_ldac_encoder_cb.ldac_handle == NULL) {
           LOG_ERROR(LOG_TAG, "%s: invalid LDAC handle", __func__);
@@ -655,9 +665,10 @@
               ldac_get_error_code_func(a2dp_ldac_encoder_cb.ldac_handle);
           LOG_ERROR(LOG_TAG,
                     "%s: LDAC encoding error: %d api_error = %d "
-                    "handle_error = %d block_error = %d",
+                    "handle_error = %d block_error = %d error_code = 0x%x",
                     __func__, result, LDACBT_API_ERR(err_code),
-                    LDACBT_HANDLE_ERR(err_code), LDACBT_BLOCK_ERR(err_code));
+                    LDACBT_HANDLE_ERR(err_code), LDACBT_BLOCK_ERR(err_code),
+                    err_code);
           a2dp_ldac_encoder_cb.stats.media_read_total_dropped_packets++;
           osi_free(p_buf);
           return;
@@ -689,7 +700,9 @@
 
       uint8_t done_nb_frame = remain_nb_frame - nb_frame;
       remain_nb_frame = nb_frame;
-      if (!a2dp_ldac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+      if (!a2dp_ldac_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                 bytes_read))
+        return;
     } else {
       // NOTE: Unlike the execution path for other codecs, it is normal for
       // LDAC to NOT write encoded data to the last buffer if there wasn't
@@ -701,7 +714,7 @@
   }
 }
 
-static bool a2dp_ldac_read_feeding(uint8_t* read_buffer) {
+static bool a2dp_ldac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read) {
   uint32_t read_size = LDACBT_ENC_LSU *
                        a2dp_ldac_encoder_cb.feeding_params.channel_count *
                        a2dp_ldac_encoder_cb.feeding_params.bits_per_sample / 8;
@@ -723,6 +736,7 @@
   }
   a2dp_ldac_encoder_cb.stats.media_read_total_actual_reads_count++;
 
+  *bytes_read = nb_byte_read;
   return true;
 }
 
@@ -749,6 +763,10 @@
   return a2dp_vendor_ldac_get_encoder_interval_ms();
 }
 
+int A2dpCodecConfigLdac::getEffectiveMtu() const {
+  return a2dp_ldac_encoder_cb.TxAaMtuSize;
+}
+
 void A2dpCodecConfigLdac::debug_codec_dump(int fd) {
   a2dp_ldac_encoder_stats_t* stats = &a2dp_ldac_encoder_cb.stats;
   tA2DP_LDAC_ENCODER_PARAMS* p_encoder_params =
diff --git a/stack/avct/avct_api.cc b/stack/avct/avct_api.cc
index af789e3..5ced71f 100644
--- a/stack/avct/avct_api.cc
+++ b/stack/avct/avct_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/avct/avct_bcb_act.cc b/stack/avct/avct_bcb_act.cc
index 011a52d..616976e 100644
--- a/stack/avct/avct_bcb_act.cc
+++ b/stack/avct/avct_bcb_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -17,12 +17,12 @@
  ******************************************************************************/
 
 /*****************************************************************************
-*
-*  Name:           avct_bcb_act.cc
-*
-*  Description:    This module contains action functions of the browsing control
-*                  state machine.
-*
+ *
+ *  Name:           avct_bcb_act.cc
+ *
+ *  Description:    This module contains action functions of the browsing
+ *                  control state machine.
+ *
  *****************************************************************************/
 
 #include <log/log.h>
@@ -187,7 +187,7 @@
   }
 
   /* if no ccbs bound to this lcb, disconnect */
-  if (bind == false) {
+  if (!bind) {
     avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
     return;
   }
diff --git a/stack/avct/avct_ccb.cc b/stack/avct/avct_ccb.cc
index d15fff2..e551eaf 100644
--- a/stack/avct/avct_ccb.cc
+++ b/stack/avct/avct_ccb.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/avct/avct_defs.h b/stack/avct/avct_defs.h
index 73d4fcf..71748c5 100644
--- a/stack/avct/avct_defs.h
+++ b/stack/avct/avct_defs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/avct/avct_int.h b/stack/avct/avct_int.h
index 53b8b97..ff1bba2 100644
--- a/stack/avct/avct_int.h
+++ b/stack/avct/avct_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/avct/avct_l2c.cc b/stack/avct/avct_l2c.cc
index f81ed56..718a9c9 100644
--- a/stack/avct/avct_l2c.cc
+++ b/stack/avct/avct_l2c.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -48,19 +48,18 @@
 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
 
 /* L2CAP callback function structure */
-const tL2CAP_APPL_INFO avct_l2c_appl = {
-    avct_l2c_connect_ind_cback,
-    avct_l2c_connect_cfm_cback,
-    NULL,
-    avct_l2c_config_ind_cback,
-    avct_l2c_config_cfm_cback,
-    avct_l2c_disconnect_ind_cback,
-    avct_l2c_disconnect_cfm_cback,
-    NULL,
-    avct_l2c_data_ind_cback,
-    avct_l2c_congestion_ind_cback,
-    NULL /* tL2CA_TX_COMPLETE_CB */
-};
+const tL2CAP_APPL_INFO avct_l2c_appl = {avct_l2c_connect_ind_cback,
+                                        avct_l2c_connect_cfm_cback,
+                                        NULL,
+                                        avct_l2c_config_ind_cback,
+                                        avct_l2c_config_cfm_cback,
+                                        avct_l2c_disconnect_ind_cback,
+                                        avct_l2c_disconnect_cfm_cback,
+                                        NULL,
+                                        avct_l2c_data_ind_cback,
+                                        avct_l2c_congestion_ind_cback,
+                                        NULL, /* tL2CA_TX_COMPLETE_CB */
+                                        NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 /*******************************************************************************
  *
diff --git a/stack/avct/avct_l2c_br.cc b/stack/avct/avct_l2c_br.cc
index 3b364cd..1be8a7b 100644
--- a/stack/avct/avct_l2c_br.cc
+++ b/stack/avct/avct_l2c_br.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2016 Broadcom Corporation
+ *  Copyright 2008-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -92,8 +92,8 @@
     NULL,
     avct_l2c_br_data_ind_cback,
     avct_l2c_br_congestion_ind_cback,
-    NULL /* tL2CA_TX_COMPLETE_CB */
-};
+    NULL, /* tL2CA_TX_COMPLETE_CB */
+    NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 /* Browsing channel eL2CAP default options */
 const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def = {
diff --git a/stack/avct/avct_lcb.cc b/stack/avct/avct_lcb.cc
index 96156a2..8a9c8ee 100644
--- a/stack/avct/avct_lcb.cc
+++ b/stack/avct/avct_lcb.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/avct/avct_lcb_act.cc b/stack/avct/avct_lcb_act.cc
index e2ce9db..faa098b 100644
--- a/stack/avct/avct_lcb_act.cc
+++ b/stack/avct/avct_lcb_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -235,7 +235,7 @@
   }
 
   /* if no ccbs bound to this lcb, disconnect */
-  if (bind == false) {
+  if (!bind) {
     avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
   }
 }
@@ -419,7 +419,7 @@
   /* set event */
   event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
   p_lcb->cong = p_data->cong;
-  if (p_lcb->cong == false && !fixed_queue_is_empty(p_lcb->tx_q)) {
+  if (!p_lcb->cong && !fixed_queue_is_empty(p_lcb->tx_q)) {
     while (!p_lcb->cong &&
            (p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_lcb->tx_q)) != NULL) {
       if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) {
@@ -528,7 +528,7 @@
       UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
     }
 
-    if (p_lcb->cong == true) {
+    if (p_lcb->cong) {
       fixed_queue_enqueue(p_lcb->tx_q, p_buf);
     }
 
diff --git a/stack/avdt/avdt_ad.cc b/stack/avdt/avdt_ad.cc
index 6143985..cc994b0 100644
--- a/stack/avdt/avdt_ad.cc
+++ b/stack/avdt/avdt_ad.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,6 +35,24 @@
 #include "l2cdefs.h"
 #include "osi/include/osi.h"
 
+AvdtpScb* AvdtpAdaptationLayer::LookupAvdtpScb(
+    const AvdtpTransportChannel& tc) {
+  if (tc.ccb_idx >= AVDT_NUM_LINKS) {
+    AVDT_TRACE_ERROR("%s: AvdtpScb entry not found: invalid ccb_idx:%d",
+                     __func__, tc.ccb_idx);
+    return nullptr;
+  }
+  if (tc.tcid >= AVDT_NUM_RT_TBL) {
+    AVDT_TRACE_ERROR("%s: AvdtpScb entry not found: invalid tcid:%d", __func__,
+                     tc.tcid);
+    return nullptr;
+  }
+  const AvdtpRoutingEntry& re = rt_tbl[tc.ccb_idx][tc.tcid];
+  AVDT_TRACE_DEBUG("%s: ccb_idx:%d tcid:%d scb_hdl:%d", __func__, tc.ccb_idx,
+                   tc.tcid, re.scb_hdl);
+  return avdt_scb_by_hdl(re.scb_hdl);
+}
+
 /*******************************************************************************
  *
  * Function         avdt_ad_type_to_tcid
@@ -45,19 +63,19 @@
  * Returns          TCID value.
  *
  ******************************************************************************/
-uint8_t avdt_ad_type_to_tcid(uint8_t type, tAVDT_SCB* p_scb) {
-  uint8_t scb_idx;
-
+uint8_t avdt_ad_type_to_tcid(uint8_t type, AvdtpScb* p_scb) {
   if (type == AVDT_CHAN_SIG) {
     return 0;
-  } else {
-    scb_idx = avdt_scb_to_hdl(p_scb) - 1;
-    /*
-    AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx *
-    (AVDT_CHAN_NUM_TYPES - 1)) + type));
-    */
-    return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
   }
+  // The SCB Handle is unique in the [1, AVDT_NUM_LINKS * AVDT_NUM_SEPS]
+  // range. The scb_idx computed here is the SCB index for the corresponding
+  // SEP, and it is in the range [0, AVDT_NUM_SEPS) for a particular link.
+  uint8_t scb_idx = (avdt_scb_to_hdl(p_scb) - 1) % AVDT_NUM_LINKS;
+  // There are AVDT_CHAN_NUM_TYPES channel types per SEP. Here we compute
+  // the type index (TCID) from the SEP index and the type itself.
+  uint8_t tcid = (scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type;
+  AVDT_TRACE_DEBUG("%s: type:%d, tcid: %d", __func__, type, tcid);
+  return tcid;
 }
 
 /*******************************************************************************
@@ -99,8 +117,8 @@
  ******************************************************************************/
 void avdt_ad_init(void) {
   int i;
-  tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
-  memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
+  AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
+  avdtp_cb.ad.Reset();
 
   /* make sure the peer_mtu is a valid value */
   for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
@@ -121,10 +139,10 @@
  *                  first matching entry (there could be more than one).
  *
  ******************************************************************************/
-tAVDT_TC_TBL* avdt_ad_tc_tbl_by_st(uint8_t type, tAVDT_CCB* p_ccb,
-                                   uint8_t state) {
+AvdtpTransportChannel* avdt_ad_tc_tbl_by_st(uint8_t type, AvdtpCcb* p_ccb,
+                                            uint8_t state) {
   int i;
-  tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+  AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
   uint8_t ccb_idx;
 
   if (p_ccb == NULL) {
@@ -173,13 +191,13 @@
  * Returns          Pointer to entry.
  *
  ******************************************************************************/
-tAVDT_TC_TBL* avdt_ad_tc_tbl_by_lcid(uint16_t lcid) {
+AvdtpTransportChannel* avdt_ad_tc_tbl_by_lcid(uint16_t lcid) {
   uint8_t idx;
 
-  idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+  idx = avdtp_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
 
   if (idx < AVDT_NUM_TC_TBL) {
-    return &avdt_cb.ad.tc_tbl[idx];
+    return &avdtp_cb.ad.tc_tbl[idx];
   } else {
     return NULL;
   }
@@ -196,11 +214,11 @@
  * Returns          Pointer to transport channel table entry.
  *
  ******************************************************************************/
-tAVDT_TC_TBL* avdt_ad_tc_tbl_by_type(uint8_t type, tAVDT_CCB* p_ccb,
-                                     tAVDT_SCB* p_scb) {
+AvdtpTransportChannel* avdt_ad_tc_tbl_by_type(uint8_t type, AvdtpCcb* p_ccb,
+                                              AvdtpScb* p_scb) {
   uint8_t tcid;
   int i;
-  tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+  AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
   uint8_t ccb_idx = avdt_ccb_to_idx(p_ccb);
 
   /* get tcid from type, scb */
@@ -227,9 +245,9 @@
  * Returns          Pointer to entry.
  *
  ******************************************************************************/
-tAVDT_TC_TBL* avdt_ad_tc_tbl_alloc(tAVDT_CCB* p_ccb) {
+AvdtpTransportChannel* avdt_ad_tc_tbl_alloc(AvdtpCcb* p_ccb) {
   int i;
-  tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+  AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
 
   /* find next free entry in tc table */
   for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
@@ -259,10 +277,10 @@
  * Returns          Index value.
  *
  ******************************************************************************/
-uint8_t avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL* p_tbl) {
-  AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
+uint8_t avdt_ad_tc_tbl_to_idx(AvdtpTransportChannel* p_tbl) {
+  AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdtp_cb.ad.tc_tbl));
   /* use array arithmetic to determine index */
-  return (uint8_t)(p_tbl - avdt_cb.ad.tc_tbl);
+  return (uint8_t)(p_tbl - avdtp_cb.ad.tc_tbl);
 }
 
 /*******************************************************************************
@@ -279,9 +297,10 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ad_tc_close_ind(tAVDT_TC_TBL* p_tbl, UNUSED_ATTR uint16_t reason) {
-  tAVDT_CCB* p_ccb;
-  tAVDT_SCB* p_scb;
+void avdt_ad_tc_close_ind(AvdtpTransportChannel* p_tbl,
+                          UNUSED_ATTR uint16_t reason) {
+  AvdtpCcb* p_ccb;
+  AvdtpScb* p_scb;
   tAVDT_SCB_TC_CLOSE close;
 
   close.old_tc_state = p_tbl->state;
@@ -290,26 +309,27 @@
   p_tbl->cfg_flags = 0;
   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
 
-  AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d", p_tbl->tcid,
+  AVDT_TRACE_DEBUG("%s: tcid: %d, old: %d", __func__, p_tbl->tcid,
                    close.old_tc_state);
   /* if signaling channel, notify ccb that channel open */
   if (p_tbl->tcid == 0) {
     p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
     avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
+    return;
   }
   /* if media or other channel, notify scb that channel close */
-  else {
-    /* look up scb in stream routing table by ccb, tcid */
-    p_scb =
-        avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
-    if (p_scb != NULL) {
-      close.tcid = p_tbl->tcid;
-      close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
-      tAVDT_SCB_EVT avdt_scb_evt;
-      avdt_scb_evt.close = close;
-      avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, &avdt_scb_evt);
-    }
+  /* look up scb in stream routing table by ccb, tcid */
+  p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
+  if (p_scb == nullptr) {
+    AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d",
+                     __func__, p_tbl->ccb_idx, p_tbl->tcid);
+    return;
   }
+  close.tcid = p_tbl->tcid;
+  close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
+  tAVDT_SCB_EVT avdt_scb_evt;
+  avdt_scb_evt.close = close;
+  avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, &avdt_scb_evt);
 }
 
 /*******************************************************************************
@@ -324,18 +344,22 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ad_tc_open_ind(tAVDT_TC_TBL* p_tbl) {
-  tAVDT_CCB* p_ccb;
-  tAVDT_SCB* p_scb;
+void avdt_ad_tc_open_ind(AvdtpTransportChannel* p_tbl) {
+  AvdtpCcb* p_ccb;
+  AvdtpScb* p_scb;
   tAVDT_OPEN open;
   tAVDT_EVT_HDR evt;
 
+  AVDT_TRACE_DEBUG("%s: p_tbl:%p state:%d ccb_idx:%d tcid:%d scb_hdl:%d",
+                   __func__, p_tbl, p_tbl->state, p_tbl->ccb_idx, p_tbl->tcid,
+                   avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+
   p_tbl->state = AVDT_AD_ST_OPEN;
 
   /* if signaling channel, notify ccb that channel open */
   if (p_tbl->tcid == 0) {
     /* set the signal channel to use high priority within the ACL link */
-    L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid,
+    L2CA_SetTxPriority(avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid,
                        L2CAP_CHNL_PRIORITY_HIGH);
 
     p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
@@ -348,23 +372,23 @@
     tAVDT_CCB_EVT avdt_ccb_evt;
     avdt_ccb_evt.msg.hdr = evt;
     avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, &avdt_ccb_evt);
+    return;
   }
   /* if media or other channel, notify scb that channel open */
-  else {
-    /* look up scb in stream routing table by ccb, tcid */
-    p_scb =
-        avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
-
-    /* put lcid in event data */
-    if (p_scb != NULL) {
-      open.peer_mtu = p_tbl->peer_mtu;
-      open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
-      open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
-      tAVDT_SCB_EVT avdt_scb_evt;
-      avdt_scb_evt.open = open;
-      avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, &avdt_scb_evt);
-    }
+  /* look up scb in stream routing table by ccb, tcid */
+  p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
+  if (p_scb == nullptr) {
+    AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d",
+                     __func__, p_tbl->ccb_idx, p_tbl->tcid);
+    return;
   }
+  /* put lcid in event data */
+  open.peer_mtu = p_tbl->peer_mtu;
+  open.lcid = avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
+  open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
+  tAVDT_SCB_EVT avdt_scb_evt;
+  avdt_scb_evt.open = open;
+  avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, &avdt_scb_evt);
 }
 
 /*******************************************************************************
@@ -381,9 +405,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ad_tc_cong_ind(tAVDT_TC_TBL* p_tbl, bool is_congested) {
-  tAVDT_CCB* p_ccb;
-  tAVDT_SCB* p_scb;
+void avdt_ad_tc_cong_ind(AvdtpTransportChannel* p_tbl, bool is_congested) {
+  AvdtpCcb* p_ccb;
+  AvdtpScb* p_scb;
 
   /* if signaling channel, notify ccb of congestion */
   if (p_tbl->tcid == 0) {
@@ -391,18 +415,19 @@
     tAVDT_CCB_EVT avdt_ccb_evt;
     avdt_ccb_evt.llcong = is_congested;
     avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, &avdt_ccb_evt);
+    return;
   }
   /* if media or other channel, notify scb that channel open */
-  else {
-    /* look up scb in stream routing table by ccb, tcid */
-    p_scb =
-        avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
-    if (p_scb != NULL) {
-      tAVDT_SCB_EVT avdt_scb_evt;
-      avdt_scb_evt.llcong = is_congested;
-      avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &avdt_scb_evt);
-    }
+  /* look up scb in stream routing table by ccb, tcid */
+  p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
+  if (p_scb == nullptr) {
+    AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d",
+                     __func__, p_tbl->ccb_idx, p_tbl->tcid);
+    return;
   }
+  tAVDT_SCB_EVT avdt_scb_evt;
+  avdt_scb_evt.llcong = is_congested;
+  avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &avdt_scb_evt);
 }
 
 /*******************************************************************************
@@ -417,9 +442,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ad_tc_data_ind(tAVDT_TC_TBL* p_tbl, BT_HDR* p_buf) {
-  tAVDT_CCB* p_ccb;
-  tAVDT_SCB* p_scb;
+void avdt_ad_tc_data_ind(AvdtpTransportChannel* p_tbl, BT_HDR* p_buf) {
+  AvdtpCcb* p_ccb;
+  AvdtpScb* p_scb;
 
   /* store type (media, recovery, reporting) */
   p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
@@ -428,18 +453,18 @@
   if (p_tbl->tcid == 0) {
     p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
     avdt_msg_ind(p_ccb, p_buf);
+    return;
   }
   /* if media or other channel, send event to scb */
-  else {
-    p_scb =
-        avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
-    if (p_scb != NULL) {
-      avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf);
-    } else {
-      osi_free(p_buf);
-      AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
-    }
+  p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
+  if (p_scb == nullptr) {
+    AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d",
+                     __func__, p_tbl->ccb_idx, p_tbl->tcid);
+    osi_free(p_buf);
+    AVDT_TRACE_ERROR("%s: buffer freed", __func__);
+    return;
   }
+  avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf);
 }
 
 /*******************************************************************************
@@ -458,14 +483,14 @@
  *                  AVDT_AD_FAILED, if error
  *
  ******************************************************************************/
-uint8_t avdt_ad_write_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb,
+uint8_t avdt_ad_write_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb,
                           BT_HDR* p_buf) {
   uint8_t tcid;
 
   /* get tcid from type, scb */
   tcid = avdt_ad_type_to_tcid(type, p_scb);
 
-  return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid,
+  return L2CA_DataWrite(avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid,
                         p_buf);
 }
 
@@ -485,9 +510,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ad_open_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb,
+void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb,
                       uint8_t role) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
   uint16_t lcid;
 
   p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
@@ -502,17 +527,17 @@
 
   if (type == AVDT_CHAN_SIG) {
     /* if signaling, get mtu from registration control block */
-    p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+    p_tbl->my_mtu = avdtp_cb.rcb.ctrl_mtu;
     p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
   } else {
     /* otherwise get mtu from scb */
-    p_tbl->my_mtu = p_scb->cs.mtu;
-    p_tbl->my_flush_to = p_scb->cs.flush_to;
+    p_tbl->my_mtu = p_scb->stream_config.mtu;
+    p_tbl->my_flush_to = p_scb->stream_config.flush_to;
 
     /* also set scb_hdl in rt_tbl */
-    avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl =
+    avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl =
         avdt_scb_to_hdl(p_scb);
-    AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
+    AVDT_TRACE_DEBUG("avdtp_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
                      avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
                      avdt_scb_to_hdl(p_scb));
   }
@@ -529,14 +554,14 @@
     lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr);
     if (lcid != 0) {
       /* if connect req ok, store tcid in lcid table  */
-      avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] =
+      avdtp_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] =
           avdt_ad_tc_tbl_to_idx(p_tbl);
-      AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
+      AVDT_TRACE_DEBUG("avdtp_cb.ad.lcid_tbl[%d] = %d",
                        (lcid - L2CAP_BASE_APPL_CID),
                        avdt_ad_tc_tbl_to_idx(p_tbl));
 
-      avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
-      AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
+      avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+      AVDT_TRACE_DEBUG("avdtp_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
                        avdt_ccb_to_idx(p_ccb), p_tbl->tcid, lcid);
     } else {
       /* if connect req failed, call avdt_ad_tc_close_ind() */
@@ -557,9 +582,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ad_close_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb) {
+void avdt_ad_close_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb) {
   uint8_t tcid;
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
   AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state);
@@ -577,6 +602,6 @@
       tcid = avdt_ad_type_to_tcid(type, p_scb);
 
       /* call l2cap disconnect req */
-      L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
+      L2CA_DisconnectReq(avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
   }
 }
diff --git a/stack/avdt/avdt_api.cc b/stack/avdt/avdt_api.cc
index a507841..43954b4 100644
--- a/stack/avdt/avdt_api.cc
+++ b/stack/avdt/avdt_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,11 +34,11 @@
 #include "l2c_api.h"
 #include "stack/include/a2dp_codec_api.h"
 
-/* Control block for AVDT */
-tAVDT_CB avdt_cb;
+/* Control block for AVDTP */
+AvdtpCb avdtp_cb;
 
 void avdt_ccb_idle_ccb_timer_timeout(void* data) {
-  tAVDT_CCB* p_ccb = (tAVDT_CCB*)data;
+  AvdtpCcb* p_ccb = (AvdtpCcb*)data;
   uint8_t avdt_event = AVDT_CCB_IDLE_TOUT_EVT;
   uint8_t err_code = AVDT_ERR_TIMEOUT;
 
@@ -48,7 +48,7 @@
 }
 
 void avdt_ccb_ret_ccb_timer_timeout(void* data) {
-  tAVDT_CCB* p_ccb = (tAVDT_CCB*)data;
+  AvdtpCcb* p_ccb = (AvdtpCcb*)data;
   uint8_t avdt_event = AVDT_CCB_RET_TOUT_EVT;
   uint8_t err_code = AVDT_ERR_TIMEOUT;
 
@@ -58,7 +58,7 @@
 }
 
 void avdt_ccb_rsp_ccb_timer_timeout(void* data) {
-  tAVDT_CCB* p_ccb = (tAVDT_CCB*)data;
+  AvdtpCcb* p_ccb = (AvdtpCcb*)data;
   uint8_t avdt_event = AVDT_CCB_RSP_TOUT_EVT;
   uint8_t err_code = AVDT_ERR_TIMEOUT;
 
@@ -68,7 +68,7 @@
 }
 
 void avdt_scb_transport_channel_timer_timeout(void* data) {
-  tAVDT_SCB* p_scb = (tAVDT_SCB*)data;
+  AvdtpScb* p_scb = (AvdtpScb*)data;
   uint8_t avdt_event = AVDT_SCB_TC_TOUT_EVT;
 
   avdt_scb_event(p_scb, avdt_event, NULL);
@@ -88,7 +88,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void AVDT_Register(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback) {
+void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) {
   /* register PSM with L2CAP */
   L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl);
 
@@ -104,13 +104,11 @@
   BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
                        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
 
-#if (AVDT_REPORTING == TRUE)
   /* do not use security on the reporting channel */
   BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
                        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
   BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
                        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
-#endif
 
   /* initialize AVDTP data structures */
   avdt_scb_init();
@@ -118,8 +116,8 @@
   avdt_ad_init();
 
   /* copy registration struct */
-  memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG));
-  avdt_cb.p_conn_cback = p_cback;
+  avdtp_cb.rcb = *p_reg;
+  avdtp_cb.p_conn_cback = p_cback;
 }
 
 /*******************************************************************************
@@ -144,7 +142,7 @@
 void AVDT_AbortReq(uint8_t handle) {
   AVDT_TRACE_WARNING("%s: handle=%d", __func__, handle);
 
-  tAVDT_SCB* p_scb = avdt_scb_by_hdl(handle);
+  AvdtpScb* p_scb = avdt_scb_by_hdl(handle);
   if (p_scb != NULL) {
     avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL);
   } else {
@@ -166,20 +164,21 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-uint16_t AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs) {
+uint16_t AVDT_CreateStream(uint8_t peer_id, uint8_t* p_handle,
+                           const AvdtpStreamConfig& avdtp_stream_config) {
   uint16_t result = AVDT_SUCCESS;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
 
-  AVDT_TRACE_DEBUG("%s", __func__);
+  AVDT_TRACE_DEBUG("%s: peer_id=%d", __func__, peer_id);
 
   /* Verify parameters; if invalid, return failure */
-  if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) ||
-      (p_cs->p_ctrl_cback == NULL)) {
+  if (((avdtp_stream_config.cfg.psc_mask & (~AVDT_PSC)) != 0) ||
+      (avdtp_stream_config.p_avdt_ctrl_cback == NULL)) {
     result = AVDT_BAD_PARAMS;
   }
   /* Allocate scb; if no scbs, return failure */
   else {
-    p_scb = avdt_scb_alloc(p_cs);
+    p_scb = avdt_scb_alloc(peer_id, avdtp_stream_config);
     if (p_scb == NULL) {
       result = AVDT_NO_RESOURCES;
     } else {
@@ -187,7 +186,8 @@
     }
   }
 
-  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+  AVDT_TRACE_DEBUG("%s: result=%d handle=%d scb_index=%d", __func__, result,
+                   *p_handle, avdtp_stream_config.scb_index);
 
   return result;
 }
@@ -208,7 +208,7 @@
  ******************************************************************************/
 uint16_t AVDT_RemoveStream(uint8_t handle) {
   uint16_t result = AVDT_SUCCESS;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
 
   AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle);
 
@@ -252,9 +252,10 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr, tAVDT_SEP_INFO* p_sep_info,
-                          uint8_t max_seps, tAVDT_CTRL_CBACK* p_cback) {
-  tAVDT_CCB* p_ccb;
+uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr, uint8_t channel_index,
+                          tAVDT_SEP_INFO* p_sep_info, uint8_t max_seps,
+                          tAVDT_CTRL_CBACK* p_cback) {
+  AvdtpCcb* p_ccb;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_CCB_EVT evt;
 
@@ -263,7 +264,7 @@
   /* find channel control block for this bd addr; if none, allocate one */
   p_ccb = avdt_ccb_by_bd(bd_addr);
   if (p_ccb == NULL) {
-    p_ccb = avdt_ccb_alloc(bd_addr);
+    p_ccb = avdt_ccb_alloc_by_channel_index(bd_addr, channel_index);
     if (p_ccb == NULL) {
       /* could not allocate channel control block */
       result = AVDT_NO_RESOURCES;
@@ -293,15 +294,15 @@
  *
  * Function         avdt_get_cap_req
  *
- * Description      internal function to serve both AVDT_GetCapReq and
- *                  AVDT_GetAllCapReq
+ * Description      internal function to serve AVDT_GetCapReq
  *
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
 static uint16_t avdt_get_cap_req(const RawAddress& bd_addr,
+                                 uint8_t channel_index,
                                  tAVDT_CCB_API_GETCAP* p_evt) {
-  tAVDT_CCB* p_ccb = NULL;
+  AvdtpCcb* p_ccb = NULL;
   uint16_t result = AVDT_SUCCESS;
 
   AVDT_TRACE_DEBUG("%s", __func__);
@@ -316,7 +317,7 @@
   else {
     p_ccb = avdt_ccb_by_bd(bd_addr);
     if (p_ccb == NULL) {
-      p_ccb = avdt_ccb_alloc(bd_addr);
+      p_ccb = avdt_ccb_alloc_by_channel_index(bd_addr, channel_index);
       if (p_ccb == NULL) {
         /* could not allocate channel control block */
         result = AVDT_NO_RESOURCES;
@@ -364,60 +365,23 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t seid,
-                        tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback) {
+uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t channel_index,
+                        uint8_t seid, AvdtpSepConfig* p_cfg,
+                        tAVDT_CTRL_CBACK* p_cback, bool get_all_cap) {
   tAVDT_CCB_API_GETCAP getcap;
   uint16_t result = AVDT_SUCCESS;
 
   AVDT_TRACE_DEBUG("%s", __func__);
 
   getcap.single.seid = seid;
-  getcap.single.sig_id = AVDT_SIG_GETCAP;
+  if (get_all_cap) {
+    getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
+  } else {
+    getcap.single.sig_id = AVDT_SIG_GETCAP;
+  }
   getcap.p_cfg = p_cfg;
   getcap.p_cback = p_cback;
-  result = avdt_get_cap_req(bd_addr, &getcap);
-
-  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
-
-  return result;
-}
-
-/*******************************************************************************
- *
- * Function         AVDT_GetAllCapReq
- *
- * Description      This function initiates a connection to the AVDTP service
- *                  on the peer device, if not already present, and gets the
- *                  capabilities of a stream endpoint on the peer device.
- *                  This function can be called at any time regardless of
- *                  whether there is an AVDTP connection to the peer device.
- *
- *                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
- *                  sent to the application via its callback function.  The
- *                  application must not call AVDT_GetCapReq() or
- *                  AVDT_DiscoverReq() again until the procedure is complete.
- *
- *                  The memory pointed to by p_cfg is allocated by the
- *                  application.  This memory is written to by AVDTP as part
- *                  of the get capabilities procedure.  This memory must
- *                  remain accessible until the application receives
- *                  the AVDT_GETCAP_CFM_EVT.
- *
- * Returns          AVDT_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-uint16_t AVDT_GetAllCapReq(const RawAddress& bd_addr, uint8_t seid,
-                           tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback) {
-  tAVDT_CCB_API_GETCAP getcap;
-  uint16_t result = AVDT_SUCCESS;
-
-  AVDT_TRACE_DEBUG("%s", __func__);
-
-  getcap.single.seid = seid;
-  getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
-  getcap.p_cfg = p_cfg;
-  getcap.p_cback = p_cback;
-  result = avdt_get_cap_req(bd_addr, &getcap);
+  result = avdt_get_cap_req(bd_addr, channel_index, &getcap);
 
   AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
 
@@ -436,7 +400,7 @@
  *
  ******************************************************************************/
 uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_SCB_EVT evt;
 
@@ -474,10 +438,11 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr, uint8_t seid,
-                      tAVDT_CFG* p_cfg) {
-  tAVDT_CCB* p_ccb = NULL;
-  tAVDT_SCB* p_scb = NULL;
+uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr,
+                      uint8_t channel_index, uint8_t seid,
+                      AvdtpSepConfig* p_cfg) {
+  AvdtpCcb* p_ccb = NULL;
+  AvdtpScb* p_scb = NULL;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_SCB_EVT evt;
 
@@ -497,7 +462,7 @@
     else {
       p_ccb = avdt_ccb_by_bd(bd_addr);
       if (p_ccb == NULL) {
-        p_ccb = avdt_ccb_alloc(bd_addr);
+        p_ccb = avdt_ccb_alloc_by_channel_index(bd_addr, channel_index);
         if (p_ccb == NULL) {
           /* could not allocate channel control block */
           result = AVDT_NO_RESOURCES;
@@ -508,7 +473,8 @@
 
   /* send event to scb */
   if (result == AVDT_SUCCESS) {
-    A2DP_DumpCodecInfo(p_cfg->codec_info);
+    AVDT_TRACE_DEBUG("%s: codec: %s", __func__,
+                     A2DP_CodecInfoString(p_cfg->codec_info).c_str());
 
     evt.msg.config_cmd.hdr.seid = seid;
     evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
@@ -536,13 +502,13 @@
  ******************************************************************************/
 uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
                         uint8_t category) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   tAVDT_SCB_EVT evt;
   uint16_t result = AVDT_SUCCESS;
   uint8_t event_code;
 
-  AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d category=%d", __func__,
-                   handle, label, error_code, category);
+  AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=0x%x category=%d",
+                   __func__, handle, label, error_code, category);
 
   /* map handle to scb */
   p_scb = avdt_scb_by_hdl(handle);
@@ -589,7 +555,7 @@
  *
  ******************************************************************************/
 uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) {
-  tAVDT_SCB* p_scb = NULL;
+  AvdtpScb* p_scb = NULL;
   tAVDT_CCB_EVT evt;
   uint16_t result = AVDT_SUCCESS;
   int i;
@@ -641,7 +607,7 @@
  *
  ******************************************************************************/
 uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) {
-  tAVDT_SCB* p_scb = NULL;
+  AvdtpScb* p_scb = NULL;
   tAVDT_CCB_EVT evt;
   uint16_t result = AVDT_SUCCESS;
   int i;
@@ -692,7 +658,7 @@
  *
  ******************************************************************************/
 uint16_t AVDT_CloseReq(uint8_t handle) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   uint16_t result = AVDT_SUCCESS;
 
   AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle);
@@ -729,8 +695,8 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg) {
-  tAVDT_SCB* p_scb;
+uint16_t AVDT_ReconfigReq(uint8_t handle, AvdtpSepConfig* p_cfg) {
+  AvdtpScb* p_scb;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_SCB_EVT evt;
 
@@ -768,12 +734,12 @@
  ******************************************************************************/
 uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
                           uint8_t category) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   tAVDT_SCB_EVT evt;
   uint16_t result = AVDT_SUCCESS;
 
-  AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d category=%d", __func__,
-                   handle, label, error_code, category);
+  AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=0x%x category=%d",
+                   __func__, handle, label, error_code, category);
 
   /* map handle to scb */
   p_scb = avdt_scb_by_hdl(handle);
@@ -808,7 +774,7 @@
  *
  ******************************************************************************/
 uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_SCB_EVT evt;
 
@@ -847,11 +813,11 @@
  ******************************************************************************/
 uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code,
                           uint8_t* p_data, uint16_t len) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_SCB_EVT evt;
 
-  AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d len=%d", __func__,
+  AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=0x%x len=%d", __func__,
                    handle, label, error_code, len);
 
   /* map handle to scb */
@@ -912,7 +878,7 @@
  ******************************************************************************/
 uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
                           uint8_t m_pt, tAVDT_DATA_OPT_MASK opt) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   tAVDT_SCB_EVT evt;
   uint16_t result = AVDT_SUCCESS;
 
@@ -990,23 +956,24 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t sec_mask,
-                         tAVDT_CTRL_CBACK* p_cback) {
-  tAVDT_CCB* p_ccb = NULL;
+uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t channel_index,
+                         uint8_t sec_mask, tAVDT_CTRL_CBACK* p_cback) {
+  AvdtpCcb* p_ccb = NULL;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_CCB_EVT evt;
 
-  AVDT_TRACE_DEBUG("%s: sec_mask=0x%x", __func__, sec_mask);
+  AVDT_TRACE_WARNING("%s: address=%s channel_index=%d sec_mask=0x%x", __func__,
+                     bd_addr.ToString().c_str(), channel_index, sec_mask);
 
   /* find channel control block for this bd addr; if none, allocate one */
   p_ccb = avdt_ccb_by_bd(bd_addr);
   if (p_ccb == NULL) {
-    p_ccb = avdt_ccb_alloc(bd_addr);
+    p_ccb = avdt_ccb_alloc_by_channel_index(bd_addr, channel_index);
     if (p_ccb == NULL) {
       /* could not allocate channel control block */
       result = AVDT_NO_RESOURCES;
     }
-  } else if (p_ccb->ll_opened == false) {
+  } else if (!p_ccb->ll_opened) {
     AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening");
 
     /* ccb was already allocated for the incoming signalling. */
@@ -1020,7 +987,8 @@
     avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
   }
 
-  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+  AVDT_TRACE_WARNING("%s: address=%s result=%d", __func__,
+                     bd_addr.ToString().c_str(), result);
 
   return result;
 }
@@ -1039,7 +1007,7 @@
  ******************************************************************************/
 uint16_t AVDT_DisconnectReq(const RawAddress& bd_addr,
                             tAVDT_CTRL_CBACK* p_cback) {
-  tAVDT_CCB* p_ccb = NULL;
+  AvdtpCcb* p_ccb = NULL;
   uint16_t result = AVDT_SUCCESS;
   tAVDT_CCB_EVT evt;
 
@@ -1073,8 +1041,8 @@
  *
  ******************************************************************************/
 uint16_t AVDT_GetL2CapChannel(uint8_t handle) {
-  tAVDT_SCB* p_scb;
-  tAVDT_CCB* p_ccb;
+  AvdtpScb* p_scb;
+  AvdtpCcb* p_ccb;
   uint8_t tcid;
   uint16_t lcid = 0;
 
@@ -1084,7 +1052,7 @@
     /* get tcid from type, scb */
     tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
 
-    lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+    lcid = avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
   }
 
   return (lcid);
@@ -1101,26 +1069,25 @@
  *
  ******************************************************************************/
 uint16_t AVDT_GetSignalChannel(uint8_t handle, const RawAddress& bd_addr) {
-  tAVDT_SCB* p_scb;
-  tAVDT_CCB* p_ccb;
+  AvdtpScb* p_scb;
+  AvdtpCcb* p_ccb;
   uint8_t tcid = 0; /* tcid is always 0 for signal channel */
   uint16_t lcid = 0;
 
   /* map handle to scb */
   if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) &&
       ((p_ccb = p_scb->p_ccb) != NULL)) {
-    lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+    lcid = avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
   } else {
     p_ccb = avdt_ccb_by_bd(bd_addr);
     if (p_ccb != NULL) {
-      lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+      lcid = avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
     }
   }
 
   return (lcid);
 }
 
-#if (AVDT_REPORTING == TRUE)
 /*******************************************************************************
  *
  * Function         AVDT_SendReport
@@ -1134,9 +1101,9 @@
  ******************************************************************************/
 uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
                          tAVDT_REPORT_DATA* p_data) {
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   uint16_t result = AVDT_BAD_PARAMS;
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
   uint8_t *p, *plen, *pm1, *p_end;
   uint32_t ssrc;
   uint16_t len;
@@ -1145,8 +1112,10 @@
 
   /* map handle to scb && verify parameters */
   if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && (p_scb->p_ccb != NULL) &&
-      (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) ||
-       ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) ||
+      (((type == AVDT_RTCP_PT_SR) &&
+        (p_scb->stream_config.tsep == AVDT_TSEP_SRC)) ||
+       ((type == AVDT_RTCP_PT_RR) &&
+        (p_scb->stream_config.tsep == AVDT_TSEP_SNK)) ||
        (type == AVDT_RTCP_PT_SDES))) {
     result = AVDT_NO_RESOURCES;
 
@@ -1214,7 +1183,6 @@
 
   return result;
 }
-#endif
 
 /******************************************************************************
  *
@@ -1238,7 +1206,65 @@
  *
  *****************************************************************************/
 uint8_t AVDT_SetTraceLevel(uint8_t new_level) {
-  if (new_level != 0xFF) avdt_cb.trace_level = new_level;
+  if (new_level != 0xFF) avdtp_cb.SetTraceLevel(new_level);
 
-  return (avdt_cb.trace_level);
+  return avdtp_cb.TraceLevel();
+}
+
+void stack_debug_avdtp_api_dump(int fd) {
+  dprintf(fd, "\nAVDTP Stack State:\n");
+  dprintf(fd, "  AVDTP signalling L2CAP channel MTU: %d\n",
+          avdtp_cb.rcb.ctrl_mtu);
+  dprintf(fd, "  Security mask: 0x%x\n", avdtp_cb.rcb.sec_mask);
+
+  for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
+    const AvdtpCcb& ccb = avdtp_cb.ccb[i];
+    dprintf(fd, "\n  Channel control block: %zu peer: %s\n", i,
+            ccb.peer_addr.ToString().c_str());
+    dprintf(fd, "    Allocated: %s\n", ccb.allocated ? "true" : "false");
+    dprintf(fd, "    State: %d\n", ccb.state);
+    dprintf(fd, "    Link-layer opened: %s\n",
+            ccb.ll_opened ? "true" : "false");
+    dprintf(fd, "    Discover in progress: %s\n",
+            ccb.proc_busy ? "true" : "false");
+    dprintf(fd, "    Congested: %s\n", ccb.cong ? "true" : "false");
+    dprintf(fd, "    Reinitiate connection on idle: %s\n",
+            ccb.reconn ? "true" : "false");
+    dprintf(fd, "    Command retransmission count: %d\n", ccb.ret_count);
+    dprintf(fd, "    BTA AV SCB index: %d\n", ccb.BtaAvScbIndex());
+
+    for (size_t i = 0; i < AVDT_NUM_SEPS; i++) {
+      const AvdtpScb& scb = ccb.scb[i];
+      dprintf(fd, "\n    Stream control block: %zu\n", i);
+      dprintf(fd, "      SEP codec: %s\n",
+              A2DP_CodecName(scb.stream_config.cfg.codec_info));
+      dprintf(fd, "      SEP protocol service capabilities: 0x%x\n",
+              scb.stream_config.cfg.psc_mask);
+      dprintf(fd, "      SEP type: 0x%x\n", scb.stream_config.tsep);
+      dprintf(fd, "      Media type: 0x%x\n", scb.stream_config.media_type);
+      dprintf(fd, "      MTU: %d\n", scb.stream_config.mtu);
+      dprintf(fd, "      SCB handle: %d\n", scb.ScbHandle());
+      dprintf(fd, "      SCB index: %d\n", scb.stream_config.scb_index);
+      dprintf(fd, "      Configured codec: %s\n",
+              A2DP_CodecName(scb.curr_cfg.codec_info));
+      dprintf(fd, "      Requested codec: %s\n",
+              A2DP_CodecName(scb.req_cfg.codec_info));
+      dprintf(fd, "      Transport channel connect timer: %s\n",
+              alarm_is_scheduled(scb.transport_channel_timer)
+                  ? "Scheduled"
+                  : "Not scheduled");
+      dprintf(fd, "      Channel control block peer: %s\n",
+              (scb.p_ccb != nullptr) ? scb.p_ccb->peer_addr.ToString().c_str()
+                                     : "null");
+      dprintf(fd, "      Allocated: %s\n", scb.allocated ? "true" : "false");
+      dprintf(fd, "      In use: %s\n", scb.in_use ? "true" : "false");
+      dprintf(fd, "      Role: 0x%x\n", scb.role);
+      dprintf(fd, "      Remove: %s\n", scb.remove ? "true" : "false");
+      dprintf(fd, "      State: %d\n", scb.state);
+      dprintf(fd, "      Peer SEID: %d\n", scb.peer_seid);
+      dprintf(fd, "      Current event: %d\n", scb.curr_evt);
+      dprintf(fd, "      Congested: %s\n", scb.cong ? "true" : "false");
+      dprintf(fd, "      Close response code: %d\n", scb.close_code);
+    }
+  }
 }
diff --git a/stack/avdt/avdt_ccb.cc b/stack/avdt/avdt_ccb.cc
index 87e2fd5..edaf4f9 100644
--- a/stack/avdt/avdt_ccb.cc
+++ b/stack/avdt/avdt_ccb.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -348,8 +348,10 @@
  *
  ******************************************************************************/
 void avdt_ccb_init(void) {
-  memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS);
-  avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION*)avdt_ccb_action;
+  for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
+    avdtp_cb.ccb[i].Reset(i);
+  }
+  avdtp_cb.p_ccb_act = avdt_ccb_action;
 }
 
 /*******************************************************************************
@@ -362,15 +364,15 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_ccb_event(tAVDT_CCB* p_ccb, uint8_t event, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_event(AvdtpCcb* p_ccb, uint8_t event, tAVDT_CCB_EVT* p_data) {
   tAVDT_CCB_ST_TBL state_table;
   uint8_t action;
   int i;
 
 #if (AVDT_DEBUG == TRUE)
-  AVDT_TRACE_EVENT("%s: CCB ccb=%d event=%s state=%s", __func__,
+  AVDT_TRACE_EVENT("%s: CCB ccb=%d event=%s state=%s p_ccb=%p", __func__,
                    avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event],
-                   avdt_ccb_st_str[p_ccb->state]);
+                   avdt_ccb_st_str[p_ccb->state], p_ccb);
 #endif
 
   /* look up the state table for the current state */
@@ -388,7 +390,7 @@
                      avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state],
                      action);
     if (action != AVDT_CCB_IGNORE) {
-      (*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
+      (*avdtp_cb.p_ccb_act[action])(p_ccb, p_data);
     } else {
       break;
     }
@@ -405,8 +407,8 @@
  * Returns          pointer to the ccb, or NULL if none found.
  *
  ******************************************************************************/
-tAVDT_CCB* avdt_ccb_by_bd(const RawAddress& bd_addr) {
-  tAVDT_CCB* p_ccb = &avdt_cb.ccb[0];
+AvdtpCcb* avdt_ccb_by_bd(const RawAddress& bd_addr) {
+  AvdtpCcb* p_ccb = &avdtp_cb.ccb[0];
   int i;
 
   for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) {
@@ -435,32 +437,53 @@
  * Returns          pointer to the ccb, or NULL if none could be allocated.
  *
  ******************************************************************************/
-tAVDT_CCB* avdt_ccb_alloc(const RawAddress& bd_addr) {
-  tAVDT_CCB* p_ccb = &avdt_cb.ccb[0];
-  int i;
-
-  for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) {
+AvdtpCcb* avdt_ccb_alloc(const RawAddress& bd_addr) {
+  // Find available entry
+  AvdtpCcb* p_ccb = &avdtp_cb.ccb[0];
+  for (int i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) {
     if (!p_ccb->allocated) {
-      p_ccb->allocated = true;
-      p_ccb->peer_addr = bd_addr;
-      p_ccb->cmd_q = fixed_queue_new(SIZE_MAX);
-      p_ccb->rsp_q = fixed_queue_new(SIZE_MAX);
-      p_ccb->idle_ccb_timer = alarm_new("avdt_ccb.idle_ccb_timer");
-      p_ccb->ret_ccb_timer = alarm_new("avdt_ccb.ret_ccb_timer");
-      p_ccb->rsp_ccb_timer = alarm_new("avdt_ccb.rsp_ccb_timer");
-      AVDT_TRACE_DEBUG("avdt_ccb_alloc %d", i);
-      break;
+      p_ccb->Allocate(bd_addr);
+      AVDT_TRACE_DEBUG("%s: allocated (index %d) for peer %s", __func__, i,
+                       bd_addr.ToString().c_str());
+      return p_ccb;
     }
   }
 
-  if (i == AVDT_NUM_LINKS) {
-    /* out of ccbs */
-    p_ccb = NULL;
-    AVDT_TRACE_WARNING("Out of ccbs");
+  AVDT_TRACE_WARNING("%s: out of AvdtpCcb entries", __func__);
+  return nullptr;
+}
+
+AvdtpCcb* avdt_ccb_alloc_by_channel_index(const RawAddress& bd_addr,
+                                          uint8_t channel_index) {
+  // Allocate the entry for the specified channel index
+  if (channel_index >= AVDT_NUM_LINKS) {
+    AVDT_TRACE_ERROR("%s: peer %s invalid channel index %d (max %d)", __func__,
+                     bd_addr.ToString().c_str(), channel_index, AVDT_NUM_LINKS);
+    return nullptr;
   }
+  AvdtpCcb* p_ccb = &avdtp_cb.ccb[channel_index];
+  if (p_ccb->allocated) {
+    AVDT_TRACE_ERROR("%s: peer %s channel index %d already allocated", __func__,
+                     bd_addr.ToString().c_str(), channel_index);
+    return nullptr;
+  }
+  p_ccb->Allocate(bd_addr);
+  AVDT_TRACE_DEBUG("%s: allocated (index %d) peer=%s p_ccb=%p", __func__,
+                   channel_index, p_ccb->peer_addr.ToString().c_str(), p_ccb);
   return p_ccb;
 }
 
+void AvdtpCcb::Allocate(const RawAddress& peer_address) {
+  ResetCcb();
+  peer_addr = peer_address;
+  cmd_q = fixed_queue_new(SIZE_MAX);
+  rsp_q = fixed_queue_new(SIZE_MAX);
+  idle_ccb_timer = alarm_new("avdtp_ccb.idle_ccb_timer");
+  ret_ccb_timer = alarm_new("avdtp_ccb.ret_ccb_timer");
+  rsp_ccb_timer = alarm_new("avdtp_ccb.rsp_ccb_timer");
+  allocated = true;
+}
+
 /*******************************************************************************
  *
  * Function         avdt_ccb_dealloc
@@ -471,14 +494,11 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_dealloc(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
-  AVDT_TRACE_DEBUG("avdt_ccb_dealloc %d", avdt_ccb_to_idx(p_ccb));
-  alarm_free(p_ccb->idle_ccb_timer);
-  alarm_free(p_ccb->ret_ccb_timer);
-  alarm_free(p_ccb->rsp_ccb_timer);
-  fixed_queue_free(p_ccb->cmd_q, NULL);
-  fixed_queue_free(p_ccb->rsp_q, NULL);
-  memset(p_ccb, 0, sizeof(tAVDT_CCB));
+void avdt_ccb_dealloc(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+  AVDT_TRACE_DEBUG("%s: deallocated (index %d) peer=%s p_ccb=%p", __func__,
+                   avdt_ccb_to_idx(p_ccb), p_ccb->peer_addr.ToString().c_str(),
+                   p_ccb);
+  p_ccb->ResetCcb();
 }
 
 /*******************************************************************************
@@ -491,9 +511,9 @@
  * Returns          Index of ccb.
  *
  ******************************************************************************/
-uint8_t avdt_ccb_to_idx(tAVDT_CCB* p_ccb) {
+uint8_t avdt_ccb_to_idx(AvdtpCcb* p_ccb) {
   /* use array arithmetic to determine index */
-  return (uint8_t)(p_ccb - avdt_cb.ccb);
+  return (uint8_t)(p_ccb - avdtp_cb.ccb);
 }
 
 /*******************************************************************************
@@ -506,12 +526,12 @@
  * Returns          pointer to the ccb, or NULL if none found.
  *
  ******************************************************************************/
-tAVDT_CCB* avdt_ccb_by_idx(uint8_t idx) {
-  tAVDT_CCB* p_ccb;
+AvdtpCcb* avdt_ccb_by_idx(uint8_t idx) {
+  AvdtpCcb* p_ccb;
 
   /* verify index */
   if (idx < AVDT_NUM_LINKS) {
-    p_ccb = &avdt_cb.ccb[idx];
+    p_ccb = &avdtp_cb.ccb[idx];
   } else {
     p_ccb = NULL;
     AVDT_TRACE_WARNING("No ccb for idx %d", idx);
diff --git a/stack/avdt/avdt_ccb_act.cc b/stack/avdt/avdt_ccb_act.cc
index f679dab..52f3857 100644
--- a/stack/avdt/avdt_ccb_act.cc
+++ b/stack/avdt/avdt_ccb_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-static void avdt_ccb_clear_ccb(tAVDT_CCB* p_ccb) {
+static void avdt_ccb_clear_ccb(AvdtpCcb* p_ccb) {
   BT_HDR* p_buf;
 
   /* clear certain ccb variables */
@@ -75,7 +75,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_chan_open(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_chan_open(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
   avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
 }
@@ -91,7 +91,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_chan_close(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_chan_close(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   /* close the transport channel used by this CCB */
   avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL);
 }
@@ -107,9 +107,9 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_chk_close(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_chk_close(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   int i;
-  tAVDT_SCB* p_scb = &avdt_cb.scb[0];
+  AvdtpScb* p_scb = &(p_ccb->scb[0]);
 
   /* see if there are any active scbs associated with this ccb */
   for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
@@ -122,7 +122,7 @@
   if (i == AVDT_NUM_SEPS) {
     alarm_cancel(p_ccb->ret_ccb_timer);
     alarm_cancel(p_ccb->rsp_ccb_timer);
-    period_ms_t interval_ms = avdt_cb.rcb.idle_tout * 1000;
+    period_ms_t interval_ms = avdtp_cb.rcb.idle_tout * 1000;
     alarm_set_on_mloop(p_ccb->idle_ccb_timer, interval_ms,
                        avdt_ccb_idle_ccb_timer_timeout, p_ccb);
   }
@@ -141,23 +141,25 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_discover_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS];
-  tAVDT_SCB* p_scb = &avdt_cb.scb[0];
-  int i;
+  AvdtpScb* p_scb = &(p_ccb->scb[0]);
+
+  AVDT_TRACE_DEBUG("%s: p_ccb index=%d", __func__, avdt_ccb_to_idx(p_ccb));
 
   p_data->msg.discover_rsp.p_sep_info = sep_info;
   p_data->msg.discover_rsp.num_seps = 0;
 
   /* for all allocated scbs */
-  for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
+  for (int i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
     if (p_scb->allocated) {
       /* copy sep info */
       sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use;
-      sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1;
+      sep_info[p_data->msg.discover_rsp.num_seps].seid = p_scb->ScbHandle();
       sep_info[p_data->msg.discover_rsp.num_seps].media_type =
-          p_scb->cs.media_type;
-      sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep;
+          p_scb->stream_config.media_type;
+      sep_info[p_data->msg.discover_rsp.num_seps].tsep =
+          p_scb->stream_config.tsep;
 
       p_data->msg.discover_rsp.num_seps++;
     }
@@ -179,13 +181,14 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_discover_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   /* we're done with procedure */
   p_ccb->proc_busy = false;
 
   /* call app callback with results */
-  (*p_ccb->proc_cback)(0, &p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
-                       (tAVDT_CTRL*)(&p_data->msg.discover_rsp));
+  (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
+                       (tAVDT_CTRL*)(&p_data->msg.discover_rsp),
+                       p_ccb->BtaAvScbIndex());
 }
 
 /*******************************************************************************
@@ -201,13 +204,13 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
-  tAVDT_SCB* p_scb;
+void avdt_ccb_hdl_getcap_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
+  AvdtpScb* p_scb;
 
   /* look up scb for seid sent to us */
   p_scb = avdt_scb_by_hdl(p_data->msg.single.seid);
 
-  p_data->msg.svccap.p_cfg = &p_scb->cs.cfg;
+  p_data->msg.svccap.p_cfg = &p_scb->stream_config.cfg;
 
   avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data);
 }
@@ -224,13 +227,14 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_getcap_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   /* we're done with procedure */
   p_ccb->proc_busy = false;
 
   /* call app callback with results */
-  (*p_ccb->proc_cback)(0, &p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
-                       (tAVDT_CTRL*)(&p_data->msg.svccap));
+  (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
+                       (tAVDT_CTRL*)(&p_data->msg.svccap),
+                       p_ccb->BtaAvScbIndex());
 }
 
 /*******************************************************************************
@@ -246,7 +250,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   uint8_t err_code = 0;
 
   /* verify all streams in the right state */
@@ -277,11 +281,11 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_start_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   uint8_t event;
   int i;
   uint8_t* p;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
 
   /* determine rsp or rej event */
   event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_START_RSP_EVT
@@ -313,7 +317,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_suspend_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   uint8_t seid;
   uint8_t err_code = 0;
 
@@ -347,11 +351,11 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_hdl_suspend_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   uint8_t event;
   int i;
   uint8_t* p;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
 
   /* determine rsp or rej event */
   event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_SUSPEND_RSP_EVT
@@ -382,7 +386,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_discover_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   /* store info in ccb struct */
   p_ccb->p_proc_data = p_data->discover.p_sep_info;
   p_ccb->proc_cback = p_data->discover.p_cback;
@@ -407,7 +411,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_discover_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   /* send response */
   avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg);
 }
@@ -425,7 +429,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_getcap_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   uint8_t sig_id = AVDT_SIG_GETCAP;
 
   /* store info in ccb struct */
@@ -454,7 +458,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_getcap_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   uint8_t sig_id = AVDT_SIG_GETCAP;
 
   if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
@@ -477,9 +481,9 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   int i;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   tAVDT_MSG avdt_msg;
   uint8_t seid_list[AVDT_NUM_SEPS];
 
@@ -527,8 +531,8 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
-  tAVDT_SCB* p_scb;
+void avdt_ccb_snd_start_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
+  AvdtpScb* p_scb;
   int i;
 
   /* send response message */
@@ -557,9 +561,9 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_suspend_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   int i;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   tAVDT_MSG avdt_msg;
   uint8_t seid_list[AVDT_NUM_SEPS];
 
@@ -602,8 +606,8 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
-  tAVDT_SCB* p_scb;
+void avdt_ccb_snd_suspend_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
+  AvdtpScb* p_scb;
   int i;
 
   /* send response message */
@@ -632,9 +636,9 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_clear_cmds(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_clear_cmds(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   int i;
-  tAVDT_SCB* p_scb = &avdt_cb.scb[0];
+  AvdtpScb* p_scb = &(p_ccb->scb[0]);
   uint8_t err_code = AVDT_ERR_CONNECT;
 
   /* clear the ccb */
@@ -675,10 +679,10 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_cmd_fail(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_cmd_fail(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   tAVDT_MSG msg;
   uint8_t evt;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
 
   if (p_ccb->p_curr_cmd != NULL) {
     /* set up data */
@@ -718,7 +722,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_free_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_free_cmd(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   osi_free_and_reset((void**)&p_ccb->p_curr_cmd);
 }
 
@@ -733,7 +737,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_cong_state(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_cong_state(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   p_ccb->cong = p_data->llcong;
 }
 
@@ -750,7 +754,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_ret_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_ret_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   p_ccb->ret_count++;
   if (p_ccb->ret_count == AVDT_RET_MAX) {
     /* command failed */
@@ -776,7 +780,7 @@
     /* restart ret timer */
     alarm_cancel(p_ccb->idle_ccb_timer);
     alarm_cancel(p_ccb->rsp_ccb_timer);
-    period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000;
+    period_ms_t interval_ms = avdtp_cb.rcb.ret_tout * 1000;
     alarm_set_on_mloop(p_ccb->ret_ccb_timer, interval_ms,
                        avdt_ccb_ret_ccb_timer_timeout, p_ccb);
   }
@@ -793,7 +797,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_cmd(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   BT_HDR* p_msg;
 
   /* do we have commands to send?  send next command;  make sure we're clear;
@@ -822,7 +826,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_snd_msg(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_snd_msg(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   BT_HDR* p_msg;
 
   /* if not congested */
@@ -834,7 +838,7 @@
     /* do we have responses to send?  send them */
     else if (!fixed_queue_is_empty(p_ccb->rsp_q)) {
       while ((p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) {
-        if (avdt_msg_send(p_ccb, p_msg) == true) {
+        if (avdt_msg_send(p_ccb, p_msg)) {
           /* break out if congested */
           break;
         }
@@ -858,7 +862,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_set_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_set_reconn(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   p_ccb->reconn = true;
 }
 
@@ -872,7 +876,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_clr_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_clr_reconn(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   p_ccb->reconn = false;
 }
 
@@ -888,7 +892,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_chk_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_chk_reconn(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   if (p_ccb->reconn) {
     p_ccb->reconn = false;
 
@@ -919,7 +923,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_chk_timer(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_chk_timer(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   alarm_cancel(p_ccb->idle_ccb_timer);
 }
 
@@ -933,7 +937,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_set_conn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_set_conn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   /* save callback */
   p_ccb->p_conn_cback = p_data->connect.p_cback;
 
@@ -953,7 +957,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_set_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_set_disconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   /*
   AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x",
       p_ccb->p_conn_cback, p_data->disconnect.p_cback);
@@ -973,7 +977,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_do_disconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_do_disconn(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   /* clear any pending commands */
   avdt_ccb_clear_cmds(p_ccb, NULL);
 
@@ -991,17 +995,20 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_ll_closed(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_ll_closed(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
   tAVDT_CTRL_CBACK* p_cback;
   tAVDT_CTRL avdt_ctrl;
 
+  AVDT_TRACE_DEBUG("%s peer %s", __func__, p_ccb->peer_addr.ToString().c_str());
+
   /* clear any pending commands */
   avdt_ccb_clear_cmds(p_ccb, NULL);
 
   /* save callback pointer, bd addr */
   p_cback = p_ccb->p_conn_cback;
-  if (!p_cback) p_cback = avdt_cb.p_conn_cback;
+  if (!p_cback) p_cback = avdtp_cb.p_conn_cback;
   RawAddress bd_addr = p_ccb->peer_addr;
+  uint8_t bta_av_scb_index = p_ccb->BtaAvScbIndex();
 
   /* dealloc ccb */
   avdt_ccb_dealloc(p_ccb, NULL);
@@ -1009,7 +1016,8 @@
   /* call callback */
   if (p_cback) {
     avdt_ctrl.hdr.err_code = 0;
-    (*p_cback)(0, &bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl);
+    (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl,
+               bta_av_scb_index);
   }
 }
 
@@ -1023,18 +1031,21 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_ccb_ll_opened(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+void avdt_ccb_ll_opened(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
 
+  AVDT_TRACE_DEBUG("%s peer %s BtaAvScbIndex=%d p_ccb=%p", __func__,
+                   p_ccb->peer_addr.ToString().c_str(), p_ccb->BtaAvScbIndex(),
+                   p_ccb);
   p_ccb->ll_opened = true;
 
-  if (!p_ccb->p_conn_cback) p_ccb->p_conn_cback = avdt_cb.p_conn_cback;
+  if (!p_ccb->p_conn_cback) p_ccb->p_conn_cback = avdtp_cb.p_conn_cback;
 
   /* call callback */
   if (p_ccb->p_conn_cback) {
     avdt_ctrl.hdr.err_code = 0;
     avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param;
-    (*p_ccb->p_conn_cback)(0, &p_ccb->peer_addr, AVDT_CONNECT_IND_EVT,
-                           &avdt_ctrl);
+    (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT,
+                           &avdt_ctrl, p_ccb->BtaAvScbIndex());
   }
 }
diff --git a/stack/avdt/avdt_defs.h b/stack/avdt/avdt_defs.h
index 02e9241..5e3c0bd 100644
--- a/stack/avdt/avdt_defs.h
+++ b/stack/avdt/avdt_defs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h
index 1f593ef..1c35448 100644
--- a/stack/avdt/avdt_int.h
+++ b/stack/avdt/avdt_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -45,20 +45,13 @@
 enum {
   AVDT_CHAN_SIG,   /* signaling channel */
   AVDT_CHAN_MEDIA, /* media channel */
-#if (AVDT_REPORTING == TRUE)
   AVDT_CHAN_REPORT, /* reporting channel */
-#endif
   AVDT_CHAN_NUM_TYPES
 };
 
 /* protocol service capabilities of this AVDTP implementation */
-#if (AVDT_REPORTING == TRUE)
 #define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
 #define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT)
-#else /* AVDT_REPORTING  */
-#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT)
-#define AVDT_LEG_PSC (AVDT_PSC_TRANS)
-#endif /* AVDT_REPORTING  */
 
 /* initiator/acceptor signaling roles */
 #define AVDT_CLOSE_ACP 0
@@ -216,13 +209,9 @@
   AVDT_SCB_HDL_SUSPEND_CMD,
   AVDT_SCB_HDL_SUSPEND_RSP,
   AVDT_SCB_HDL_TC_CLOSE,
-#if (AVDT_REPORTING == TRUE)
   AVDT_SCB_HDL_TC_CLOSE_STO,
-#endif
   AVDT_SCB_HDL_TC_OPEN,
-#if (AVDT_REPORTING == TRUE)
   AVDT_SCB_HDL_TC_OPEN_STO,
-#endif
   AVDT_SCB_SND_DELAY_RPT_REQ,
   AVDT_SCB_HDL_DELAY_RPT_CMD,
   AVDT_SCB_HDL_DELAY_RPT_RSP,
@@ -314,12 +303,8 @@
 };
 
 /* adaption layer number of stream routing table entries */
-#if (AVDT_REPORTING == TRUE)
 /* 2 channels(1 media, 1 report) for each SEP and one for signalling */
-#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS << 1) + 1)
-#else
-#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1)
-#endif
+#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS * AVDT_CHAN_NUM_TYPES + 1)
 
 /* adaption layer number of transport channel table entries - moved to target.h
 #define AVDT_NUM_TC_TBL     (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */
@@ -335,7 +320,7 @@
 #define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */
 #define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */
 
-/* Configuration flags. tAVDT_TC_TBL.cfg_flags */
+/* Configuration flags. AvdtpTransportChannel.cfg_flags */
 #define AVDT_L2C_CFG_IND_DONE (1 << 0)
 #define AVDT_L2C_CFG_CFM_DONE (1 << 1)
 #define AVDT_L2C_CFG_CONN_INT (1 << 2)
@@ -375,7 +360,7 @@
 typedef struct {
   tAVDT_EVT_HDR single;
   tAVDT_CTRL_CBACK* p_cback;
-  tAVDT_CFG* p_cfg;
+  AvdtpSepConfig* p_cfg;
 } tAVDT_CCB_API_GETCAP;
 
 /* data type for AVDT_CCB_API_CONNECT_REQ_EVT */
@@ -398,42 +383,6 @@
   uint8_t err_code;
 } tAVDT_CCB_EVT;
 
-/* channel control block type */
-typedef struct {
-  RawAddress peer_addr; /* BD address of peer */
-  /*
-   * NOTE: idle_ccb_timer, ret_ccb_timer and rsp_ccb_timer are mutually
-   * exclusive - no more than one timer should be running at the same time.
-   */
-  alarm_t* idle_ccb_timer; /* Idle CCB timer entry */
-  alarm_t* ret_ccb_timer;  /* Ret CCB timer entry */
-  alarm_t* rsp_ccb_timer;  /* Rsp CCB timer entry */
-  fixed_queue_t* cmd_q;    /* Queue for outgoing command messages */
-  fixed_queue_t* rsp_q;    /* Queue for outgoing response and reject messages */
-  tAVDT_CTRL_CBACK* proc_cback; /* Procedure callback function */
-  tAVDT_CTRL_CBACK*
-      p_conn_cback;   /* Connection/disconnection callback function */
-  void* p_proc_data;  /* Pointer to data storage for procedure */
-  BT_HDR* p_curr_cmd; /* Current command being sent awaiting response */
-  BT_HDR* p_curr_msg; /* Current message being sent */
-  BT_HDR* p_rx_msg;   /* Current message being received */
-  bool allocated;     /* Whether ccb is allocated */
-  uint8_t state;      /* The CCB state machine state */
-  bool ll_opened;     /* true if LL is opened */
-  bool proc_busy;     /* true when a discover or get capabilities procedure in
-                         progress */
-  uint8_t proc_param; /* Procedure parameter; either SEID for get capabilities
-                         or number of SEPS for discover */
-  bool cong;          /* Whether signaling channel is congested */
-  uint8_t label;      /* Message header "label" (sequence number) */
-  bool reconn;        /* If true, reinitiate connection after transitioning from
-                         CLOSING to IDLE state */
-  uint8_t ret_count;  /* Command retransmission count */
-} tAVDT_CCB;
-
-/* type for action functions */
-typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-
 /* type for AVDT_SCB_API_WRITE_REQ_EVT */
 typedef struct {
   BT_HDR* p_buf;
@@ -460,67 +409,404 @@
   BT_HDR* p_pkt;
 } tAVDT_SCB_EVT;
 
-/* stream control block type */
-typedef struct {
-  tAVDT_CS cs;                      /* stream creation struct */
-  tAVDT_CFG curr_cfg;               /* current configuration */
-  tAVDT_CFG req_cfg;                /* requested configuration */
-  alarm_t* transport_channel_timer; /* transport channel connect timer */
-  BT_HDR* p_pkt;                    /* packet waiting to be sent */
-  tAVDT_CCB* p_ccb;                 /* ccb associated with this scb */
-  uint16_t media_seq;               /* media packet sequence number */
-  bool allocated;                   /* whether scb is allocated or unused */
-  bool in_use;                      /* whether stream being used by peer */
-  uint8_t role;       /* initiator/acceptor role in current procedure */
-  bool remove;        /* whether CB is marked for removal */
-  uint8_t state;      /* state machine state */
-  uint8_t peer_seid;  /* SEID of peer stream */
-  uint8_t curr_evt;   /* current event; set only by state machine */
-  bool cong;          /* Whether media transport channel is congested */
-  uint8_t close_code; /* Error code received in close response */
-} tAVDT_SCB;
+class AvdtpCcb;
 
-/* type for action functions */
-typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+/**
+ * AVDTP Stream Control Block.
+ */
+class AvdtpScb {
+ public:
+  AvdtpScb()
+      : transport_channel_timer(nullptr),
+        p_pkt(nullptr),
+        p_ccb(nullptr),
+        media_seq(0),
+        allocated(false),
+        in_use(false),
+        role(0),
+        remove(false),
+        state(0),
+        peer_seid(0),
+        curr_evt(0),
+        cong(false),
+        close_code(0),
+        scb_handle_(0) {}
 
-/* adaption layer type for transport channel table */
-typedef struct {
-  uint16_t peer_mtu;    /* L2CAP mtu of the peer device */
-  uint16_t my_mtu;      /* Our MTU for this channel */
-  uint16_t my_flush_to; /* Our flush timeout for this channel */
+  /**
+   * Allocate the entry for usage.
+   * Previous state will be reset and initialized.
+   *
+   * @param p_avdtp_ccb the AvdtCcb entry to use
+   * @param avdtp_stream_config the stream config to use
+   */
+  void Allocate(AvdtpCcb* p_avdtp_ccb,
+                const AvdtpStreamConfig& avdtp_stream_config);
+
+  /**
+   * Recycle the entry by resetting it, mark it as allocated and keeping
+   * the following state:
+   *  - stream_config
+   *  - p_ccb
+   */
+  void Recycle() {
+    AvdtpStreamConfig stream_config_saved = stream_config;
+    AvdtpCcb* p_ccb_saved = p_ccb;
+    Allocate(p_ccb_saved, stream_config_saved);
+  }
+
+  /**
+   * Reset all the state.
+   *
+   * @param scb_handle the AVDTP SCB handle to use
+   */
+  void Reset(uint8_t scb_handle) {
+    stream_config.Reset();
+    curr_cfg.Reset();
+    req_cfg.Reset();
+
+    alarm_free(transport_channel_timer);
+    transport_channel_timer = nullptr;
+
+    p_pkt = nullptr;
+    p_ccb = nullptr;
+    media_seq = 0;
+    allocated = false;
+    in_use = false;
+    role = 0;
+    remove = false;
+    state = 0;
+    peer_seid = 0;
+    curr_evt = 0;
+    cong = false;
+    close_code = 0;
+    scb_handle_ = scb_handle;
+  }
+
+  /**
+   * Get the AVDTP SCB handle for this entry.
+   */
+  uint8_t ScbHandle() const { return scb_handle_; }
+
+  AvdtpStreamConfig stream_config;   // Stream configuration
+  AvdtpSepConfig curr_cfg;           // Current configuration
+  AvdtpSepConfig req_cfg;            // Requested configuration
+  alarm_t* transport_channel_timer;  // Transport channel connect timer
+  BT_HDR* p_pkt;                     // Packet waiting to be sent
+  AvdtpCcb* p_ccb;                   // CCB associated with this SCB
+  uint16_t media_seq;                // Media packet sequence number
+  bool allocated;                    // True if the SCB is allocated
+  bool in_use;                       // True if used by peer
+  uint8_t role;        // Initiator/acceptor role in current procedure
+  bool remove;         // True if the SCB is marked for removal
+  uint8_t state;       // State machine state
+  uint8_t peer_seid;   // SEID of peer stream
+  uint8_t curr_evt;    // current event; set only by the state machine
+  bool cong;           // True if the media transport channel is congested
+  uint8_t close_code;  // Error code received in close response
+
+ private:
+  uint8_t scb_handle_;  // Unique handle for this AvdtpScb entry
+};
+
+/**
+ * AVDTP Channel Control Block.
+ */
+class AvdtpCcb {
+ public:
+  AvdtpCcb()
+      : peer_addr(RawAddress::kEmpty),
+        scb{},
+        idle_ccb_timer(nullptr),
+        ret_ccb_timer(nullptr),
+        rsp_ccb_timer(nullptr),
+        cmd_q(nullptr),
+        rsp_q(nullptr),
+        proc_cback(nullptr),
+        p_conn_cback(nullptr),
+        p_proc_data(nullptr),
+        p_curr_cmd(nullptr),
+        p_curr_msg(nullptr),
+        p_rx_msg(nullptr),
+        allocated(false),
+        state(0),
+        ll_opened(false),
+        proc_busy(false),
+        proc_param(0),
+        cong(false),
+        label(0),
+        reconn(false),
+        ret_count(0),
+        bta_av_scb_index_(0) {}
+
+  /**
+   * Allocate the entry for usage.
+   *
+   * NOTE: The corresponding AvdtpScb entries are allocated independently.
+   * @param peer_address the peer address
+   */
+  void Allocate(const RawAddress& peer_address);
+
+  /**
+   * Reset all the state.
+   *
+   * @param bta_av_scb_index the BTA AV SCB index to use
+   */
+  void Reset(uint8_t bta_av_scb_index) {
+    bta_av_scb_index_ = bta_av_scb_index;
+    ResetCcb();
+    for (size_t i = 0; i < AVDT_NUM_SEPS; i++) {
+      scb[i].Reset(0);
+    }
+  }
+
+  /**
+   * Reset only the Channel Control Block state without the Stream
+   * Control Block entries. The bta_av_scb_index_ is also preserved.
+   */
+  void ResetCcb() {
+    peer_addr = RawAddress::kEmpty;
+
+    alarm_free(idle_ccb_timer);
+    idle_ccb_timer = nullptr;
+
+    alarm_free(ret_ccb_timer);
+    ret_ccb_timer = nullptr;
+
+    alarm_free(rsp_ccb_timer);
+    rsp_ccb_timer = nullptr;
+
+    fixed_queue_free(cmd_q, nullptr);
+    cmd_q = nullptr;
+
+    fixed_queue_free(rsp_q, nullptr);
+    rsp_q = nullptr;
+
+    proc_cback = nullptr;
+    p_conn_cback = nullptr;
+    p_proc_data = nullptr;
+    p_curr_cmd = nullptr;
+    p_curr_msg = nullptr;
+    p_rx_msg = nullptr;
+    allocated = false;
+    state = 0;
+    ll_opened = false;
+    proc_busy = false;
+    proc_param = 0;
+    cong = false;
+    label = 0;
+    reconn = false;
+    ret_count = 0;
+  }
+
+  /**
+   * Get the corresponding BTA AV stream control block index for this entry.
+   */
+  uint8_t BtaAvScbIndex() const { return bta_av_scb_index_; }
+
+  RawAddress peer_addr;         // Bluetooth address of peer
+  AvdtpScb scb[AVDT_NUM_SEPS];  // The AVDTP stream control blocks
+
+  /*
+   * NOTE: idle_ccb_timer, ret_ccb_timer and rsp_ccb_timer are mutually
+   * exclusive - no more than one timer should be running at the same time.
+   */
+  alarm_t* idle_ccb_timer;  // Idle CCB timer entry
+  alarm_t* ret_ccb_timer;   // Ret CCB timer entry
+  alarm_t* rsp_ccb_timer;   // Rsp CCB timer entry
+  fixed_queue_t* cmd_q;     // Queue for outgoing command messages
+  fixed_queue_t* rsp_q;     // Queue for outgoing response and reject messages
+  tAVDT_CTRL_CBACK* proc_cback;    // Procedure callback function
+  tAVDT_CTRL_CBACK* p_conn_cback;  // Connection/disconnection callback function
+  void* p_proc_data;               // Pointer to data storage for procedure
+  BT_HDR* p_curr_cmd;  // Current command being sent awaiting response
+  BT_HDR* p_curr_msg;  // Current message being sent
+  BT_HDR* p_rx_msg;    // Current message being received
+  bool allocated;      // Whether ccb is allocated
+  uint8_t state;       // The CCB state machine state
+  bool ll_opened;      // True if LL is opened
+  bool proc_busy;      // True when a discover or get capabilities procedure in
+                       // progress
+  uint8_t proc_param;  // Procedure parameter; either SEID for get capabilities
+                       // or number of SEPS for discover
+  bool cong;           // True if the signaling channel is congested
+  uint8_t label;       // Message header "label" (sequence number)
+  bool reconn;        // If true, reinitiate connection after transitioning from
+                      // CLOSING to IDLE state
+  uint8_t ret_count;  // Command retransmission count
+
+ private:
+  // The corresponding BTA AV stream control block index for this entry
+  uint8_t bta_av_scb_index_;
+};
+
+/**
+ * AVDTP transport channel entry.
+ * Used in the transport channel table in the adaptation layer.
+ */
+class AvdtpTransportChannel {
+ public:
+  AvdtpTransportChannel()
+      : peer_mtu(0),
+        my_mtu(0),
+        my_flush_to(0),
+        lcid(0),
+        tcid(0),
+        ccb_idx(0),
+        state(0),
+        cfg_flags(0),
+        id(0) {}
+
+  void Reset() {
+    peer_mtu = 0;
+    my_mtu = 0;
+    my_flush_to = 0;
+    lcid = 0;
+    tcid = 0;
+    ccb_idx = 0;
+    state = 0;
+    cfg_flags = 0;
+    id = 0;
+  }
+
+  uint16_t peer_mtu;     // L2CAP MTU of the peer device
+  uint16_t my_mtu;       // Our MTU for this channel
+  uint16_t my_flush_to;  // Our flush timeout for this channel
   uint16_t lcid;
-  uint8_t tcid;      /* transport channel id */
-  uint8_t ccb_idx;   /* channel control block associated with this tc */
-  uint8_t state;     /* transport channel state */
-  uint8_t cfg_flags; /* L2CAP configuration flags */
+  uint8_t tcid;       // Transport channel ID
+  uint8_t ccb_idx;    // Channel control block for with this transport channel
+  uint8_t state;      // Transport channel state
+  uint8_t cfg_flags;  // L2CAP configuration flags
   uint8_t id;
-} tAVDT_TC_TBL;
+};
 
-/* adaption layer type for stream routing table */
-typedef struct {
-  uint16_t lcid;   /* L2CAP LCID of the associated transport channel */
-  uint8_t scb_hdl; /* stream control block associated with this tc */
-} tAVDT_RT_TBL;
+/**
+ * AVDTP stream routing entry.
+ * Used in the routing table in the adaption layer.
+ */
+class AvdtpRoutingEntry {
+ public:
+  AvdtpRoutingEntry() : lcid(0), scb_hdl(0) {}
 
-/* adaption layer control block */
-typedef struct {
-  tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
-  tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL];
-  uint8_t lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
-} tAVDT_AD;
+  void Reset() {
+    lcid = 0;
+    scb_hdl = 0;
+  }
 
-/* Control block for AVDT */
-typedef struct {
-  tAVDT_REG rcb;                   /* registration control block */
-  tAVDT_CCB ccb[AVDT_NUM_LINKS];   /* channel control blocks */
-  tAVDT_SCB scb[AVDT_NUM_SEPS];    /* stream control blocks */
-  tAVDT_AD ad;                     /* adaption layer control block */
-  tAVDTC_CTRL_CBACK* p_conf_cback; /* conformance callback function */
-  tAVDT_CCB_ACTION* p_ccb_act;     /* pointer to CCB action functions */
-  tAVDT_SCB_ACTION* p_scb_act;     /* pointer to SCB action functions */
-  tAVDT_CTRL_CBACK* p_conn_cback;  /* connection callback function */
-  uint8_t trace_level;             /* trace level */
-} tAVDT_CB;
+  uint16_t lcid;    // L2CAP LCID of the associated transport channel
+  uint8_t scb_hdl;  // Stream control block for this transport channel
+};
+
+/**
+ * AVDTP adaption layer control block.
+ */
+class AvdtpAdaptationLayer {
+ public:
+  AvdtpAdaptationLayer() : lcid_tbl{} {}
+
+  void Reset() {
+    for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
+      for (size_t j = 0; j < AVDT_NUM_RT_TBL; j++) {
+        rt_tbl[i][j].Reset();
+      }
+    }
+    for (size_t i = 0; i < AVDT_NUM_TC_TBL; i++) {
+      tc_tbl[i].Reset();
+    }
+    memset(lcid_tbl, 0, sizeof(lcid_tbl));
+  }
+
+  /**
+   * Lookup AvdtpScb entry for a transport channel.
+   *
+   * @param tc the transport channel
+   * @return the corresponding AvdtpScb entry or null of the transport
+   * channel is invalid.
+   */
+  AvdtpScb* LookupAvdtpScb(const AvdtpTransportChannel& tc);
+
+  AvdtpRoutingEntry rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
+  AvdtpTransportChannel tc_tbl[AVDT_NUM_TC_TBL];
+  uint8_t lcid_tbl[MAX_L2CAP_CHANNELS];  // Map LCID to tc_tbl index
+};
+
+/**
+ * Types for action functions.
+ */
+typedef void (*tAVDT_CCB_ACTION)(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+typedef void (*tAVDT_SCB_ACTION)(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+
+/**
+ * Control block for AVDTP.
+ */
+class AvdtpCb {
+ public:
+  AvdtpCb()
+      : p_conf_cback(nullptr),
+        p_ccb_act(nullptr),
+        p_scb_act(nullptr),
+        p_conn_cback(nullptr),
+        trace_level_(0) {}
+
+  void Reset() {
+    rcb.Reset();
+    for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
+      ccb[i].Reset(i);
+    }
+    ad.Reset();
+    p_conf_cback = nullptr;
+    p_ccb_act = nullptr;
+    p_scb_act = nullptr;
+    p_conn_cback = nullptr;
+    trace_level_ = 0;
+  }
+
+  AvdtpRcb rcb;                       // Registration control block
+  AvdtpCcb ccb[AVDT_NUM_LINKS];       // Channel control blocks
+  AvdtpAdaptationLayer ad;            // Adaption layer control block
+  tAVDTC_CTRL_CBACK* p_conf_cback;    // Conformance callback function
+  const tAVDT_CCB_ACTION* p_ccb_act;  // Pointer to CCB action functions
+  const tAVDT_SCB_ACTION* p_scb_act;  // Pointer to SCB action functions
+  tAVDT_CTRL_CBACK* p_conn_cback;     // Connection callback function
+
+  /**
+   * Compute the SCB handle for a given AvdtpScb entry.
+   *
+   * @param p_scb the entry to use
+   * @return the computed SCB handle or 0 if the entry is invalid.
+   */
+  uint8_t ComputeScbHandle(const AvdtpScb* p_scb) const {
+    uint8_t scb_handle = 0;
+
+    // Find the entry and in the process compute the unique index
+    // TODO: This mechanism is sub-efficient and should be refactored.
+    for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
+      for (size_t j = 0; j < AVDT_NUM_SEPS; j++) {
+        scb_handle++;
+        if (&ccb[i].scb[j] == p_scb) {
+          return scb_handle;
+        }
+      }
+    }
+    return 0;  // Not found
+  }
+
+  /**
+   * Get the current trace level used for logging.
+   *
+   * @return the current trace level
+   */
+  uint8_t TraceLevel() const { return trace_level_; }
+
+  /**
+   * Set the current trace level used for logging.
+   *
+   * @param trace_level the trace level to set. Should be in the range [1, 6].
+   */
+  void SetTraceLevel(uint8_t trace_level) { trace_level_ = trace_level; }
+
+ private:
+  uint8_t trace_level_; /* trace level */
+};
 
 /*****************************************************************************
  * function declarations
@@ -528,156 +814,162 @@
 
 /* CCB function declarations */
 extern void avdt_ccb_init(void);
-extern void avdt_ccb_event(tAVDT_CCB* p_ccb, uint8_t event,
+extern void avdt_ccb_event(AvdtpCcb* p_ccb, uint8_t event,
                            tAVDT_CCB_EVT* p_data);
-extern tAVDT_CCB* avdt_ccb_by_bd(const RawAddress& bd_addr);
-extern tAVDT_CCB* avdt_ccb_alloc(const RawAddress& bd_addr);
-extern void avdt_ccb_dealloc(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern uint8_t avdt_ccb_to_idx(tAVDT_CCB* p_ccb);
-extern tAVDT_CCB* avdt_ccb_by_idx(uint8_t idx);
+extern AvdtpCcb* avdt_ccb_by_bd(const RawAddress& bd_addr);
+extern AvdtpCcb* avdt_ccb_alloc(const RawAddress& bd_addr);
+extern AvdtpCcb* avdt_ccb_alloc_by_channel_index(const RawAddress& bd_addr,
+                                                 uint8_t channel_index);
+extern void avdt_ccb_dealloc(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern uint8_t avdt_ccb_to_idx(AvdtpCcb* p_ccb);
+extern AvdtpCcb* avdt_ccb_by_idx(uint8_t idx);
 
 /* CCB action functions */
-extern void avdt_ccb_chan_open(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_chan_close(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_chk_close(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_clear_cmds(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_cmd_fail(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_free_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_cong_state(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_ret_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_snd_msg(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_set_reconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_clr_reconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_chk_reconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_chk_timer(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_set_conn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_set_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_do_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_ll_closed(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
-extern void avdt_ccb_ll_opened(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chan_open(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chan_close(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chk_close(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_discover_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_discover_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_getcap_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_getcap_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_start_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_suspend_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_suspend_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_discover_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_discover_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_getcap_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_getcap_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_start_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_suspend_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_suspend_rsp(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_clear_cmds(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_cmd_fail(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_free_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_cong_state(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_ret_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_msg(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_set_reconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_clr_reconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chk_reconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chk_timer(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_set_conn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_set_disconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_do_disconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_ll_closed(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_ll_opened(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data);
 
 /* SCB function prototypes */
-extern void avdt_scb_event(tAVDT_SCB* p_scb, uint8_t event,
+extern void avdt_scb_event(AvdtpScb* p_scb, uint8_t event,
                            tAVDT_SCB_EVT* p_data);
 extern void avdt_scb_init(void);
-extern tAVDT_SCB* avdt_scb_alloc(tAVDT_CS* p_cs);
-extern void avdt_scb_dealloc(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern uint8_t avdt_scb_to_hdl(tAVDT_SCB* p_scb);
-extern tAVDT_SCB* avdt_scb_by_hdl(uint8_t hdl);
-extern uint8_t avdt_scb_verify(tAVDT_CCB* p_ccb, uint8_t state, uint8_t* p_seid,
+extern AvdtpScb* avdt_scb_alloc(uint8_t peer_id,
+                                const AvdtpStreamConfig& avdtp_stream_config);
+extern void avdt_scb_dealloc(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern uint8_t avdt_scb_to_hdl(AvdtpScb* p_scb);
+extern AvdtpScb* avdt_scb_by_hdl(uint8_t hdl);
+extern uint8_t avdt_scb_verify(AvdtpCcb* p_ccb, uint8_t state, uint8_t* p_seid,
                                uint16_t num_seid, uint8_t* p_err_code);
 extern void avdt_scb_peer_seid_list(tAVDT_MULTI* p_multi);
-extern uint32_t avdt_scb_gen_ssrc(tAVDT_SCB* p_scb);
+extern uint32_t avdt_scb_gen_ssrc(AvdtpScb* p_scb);
 
 /* SCB action functions */
-extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_close_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_open_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_open_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_drop_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_security_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_start_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_start_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_tc_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_tc_open(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_hdl_write_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_abort_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_abort_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_close_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_stream_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_getconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_open_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_reconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_security_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_setconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_snd_tc_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_cb_err(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_cong_state(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_rej_state(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_rej_in_use(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_rej_not_in_use(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_set_remove(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_free_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_chk_snd_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_clr_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_transport_channel_timer(tAVDT_SCB* p_scb,
+extern void avdt_scb_hdl_abort_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_abort_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_close_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_close_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_getconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_getconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_open_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_open_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_open_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_drop_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_reconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_reconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_security_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_security_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_setconfig_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_setconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_start_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_start_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_suspend_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_suspend_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_delay_rpt_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_delay_rpt_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_delay_rpt_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_close(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_open(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_close_sto(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_open_sto(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_write_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_abort_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_abort_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_close_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_stream_close(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_close_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_getconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_getconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_open_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_open_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_reconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_reconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_security_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_security_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_setconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_setconfig_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_setconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_tc_close(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_cb_err(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_cong_state(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_rej_state(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_rej_in_use(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_rej_not_in_use(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_set_remove(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_free_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_chk_snd_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_clr_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_transport_channel_timer(AvdtpScb* p_scb,
                                              tAVDT_SCB_EVT* p_data);
-extern void avdt_scb_clr_vars(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_clr_vars(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
 
 /* msg function declarations */
-extern bool avdt_msg_send(tAVDT_CCB* p_ccb, BT_HDR* p_msg);
-extern void avdt_msg_send_cmd(tAVDT_CCB* p_ccb, void* p_scb, uint8_t sig_id,
+extern bool avdt_msg_send(AvdtpCcb* p_ccb, BT_HDR* p_msg);
+extern void avdt_msg_send_cmd(AvdtpCcb* p_ccb, void* p_scb, uint8_t sig_id,
                               tAVDT_MSG* p_params);
-extern void avdt_msg_send_rsp(tAVDT_CCB* p_ccb, uint8_t sig_id,
+extern void avdt_msg_send_rsp(AvdtpCcb* p_ccb, uint8_t sig_id,
                               tAVDT_MSG* p_params);
-extern void avdt_msg_send_rej(tAVDT_CCB* p_ccb, uint8_t sig_id,
+extern void avdt_msg_send_rej(AvdtpCcb* p_ccb, uint8_t sig_id,
                               tAVDT_MSG* p_params);
-extern void avdt_msg_send_grej(tAVDT_CCB* p_ccb, uint8_t sig_id,
+extern void avdt_msg_send_grej(AvdtpCcb* p_ccb, uint8_t sig_id,
                                tAVDT_MSG* p_params);
-extern void avdt_msg_ind(tAVDT_CCB* p_ccb, BT_HDR* p_buf);
+extern void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf);
 
 /* adaption layer function declarations */
 extern void avdt_ad_init(void);
-extern uint8_t avdt_ad_type_to_tcid(uint8_t type, tAVDT_SCB* p_scb);
-extern tAVDT_TC_TBL* avdt_ad_tc_tbl_by_st(uint8_t type, tAVDT_CCB* p_ccb,
-                                          uint8_t state);
-extern tAVDT_TC_TBL* avdt_ad_tc_tbl_by_lcid(uint16_t lcid);
-extern tAVDT_TC_TBL* avdt_ad_tc_tbl_alloc(tAVDT_CCB* p_ccb);
-extern uint8_t avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL* p_tbl);
-extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL* p_tbl, uint16_t reason);
-extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL* p_tbl);
-extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL* p_tbl, bool is_congested);
-extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL* p_tbl, BT_HDR* p_buf);
-extern tAVDT_TC_TBL* avdt_ad_tc_tbl_by_type(uint8_t type, tAVDT_CCB* p_ccb,
-                                            tAVDT_SCB* p_scb);
-extern uint8_t avdt_ad_write_req(uint8_t type, tAVDT_CCB* p_ccb,
-                                 tAVDT_SCB* p_scb, BT_HDR* p_buf);
-extern void avdt_ad_open_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb,
+extern uint8_t avdt_ad_type_to_tcid(uint8_t type, AvdtpScb* p_scb);
+extern AvdtpTransportChannel* avdt_ad_tc_tbl_by_st(uint8_t type,
+                                                   AvdtpCcb* p_ccb,
+                                                   uint8_t state);
+extern AvdtpTransportChannel* avdt_ad_tc_tbl_by_lcid(uint16_t lcid);
+extern AvdtpTransportChannel* avdt_ad_tc_tbl_alloc(AvdtpCcb* p_ccb);
+extern uint8_t avdt_ad_tc_tbl_to_idx(AvdtpTransportChannel* p_tbl);
+extern void avdt_ad_tc_close_ind(AvdtpTransportChannel* p_tbl, uint16_t reason);
+extern void avdt_ad_tc_open_ind(AvdtpTransportChannel* p_tbl);
+extern void avdt_ad_tc_cong_ind(AvdtpTransportChannel* p_tbl,
+                                bool is_congested);
+extern void avdt_ad_tc_data_ind(AvdtpTransportChannel* p_tbl, BT_HDR* p_buf);
+extern AvdtpTransportChannel* avdt_ad_tc_tbl_by_type(uint8_t type,
+                                                     AvdtpCcb* p_ccb,
+                                                     AvdtpScb* p_scb);
+extern uint8_t avdt_ad_write_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb,
+                                 BT_HDR* p_buf);
+extern void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb,
                              uint8_t role);
-extern void avdt_ad_close_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb);
+extern void avdt_ad_close_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb);
 
 extern void avdt_ccb_idle_ccb_timer_timeout(void* data);
 extern void avdt_ccb_ret_ccb_timer_timeout(void* data);
@@ -704,7 +996,7 @@
 /******************************************************************************
  * Main Control Block
  ******************************************************************************/
-extern tAVDT_CB avdt_cb;
+extern AvdtpCb avdtp_cb;
 
 /* L2CAP callback registration structure */
 extern const tL2CAP_APPL_INFO avdt_l2c_appl;
diff --git a/stack/avdt/avdt_l2c.cc b/stack/avdt/avdt_l2c.cc
index 8ae1d43..db1bf2f 100644
--- a/stack/avdt/avdt_l2c.cc
+++ b/stack/avdt/avdt_l2c.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
 #include "bt_target.h"
 #include "bt_types.h"
 #include "bt_utils.h"
+#include "bta/include/bta_av_api.h"
 #include "btm_api.h"
 #include "btm_int.h"
 #include "device/include/interop.h"
@@ -48,19 +49,18 @@
 void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
 
 /* L2CAP callback function structure */
-const tL2CAP_APPL_INFO avdt_l2c_appl = {
-    avdt_l2c_connect_ind_cback,
-    avdt_l2c_connect_cfm_cback,
-    NULL,
-    avdt_l2c_config_ind_cback,
-    avdt_l2c_config_cfm_cback,
-    avdt_l2c_disconnect_ind_cback,
-    avdt_l2c_disconnect_cfm_cback,
-    NULL,
-    avdt_l2c_data_ind_cback,
-    avdt_l2c_congestion_ind_cback,
-    NULL /* tL2CA_TX_COMPLETE_CB */
-};
+const tL2CAP_APPL_INFO avdt_l2c_appl = {avdt_l2c_connect_ind_cback,
+                                        avdt_l2c_connect_cfm_cback,
+                                        NULL,
+                                        avdt_l2c_config_ind_cback,
+                                        avdt_l2c_config_cfm_cback,
+                                        avdt_l2c_disconnect_ind_cback,
+                                        avdt_l2c_disconnect_cfm_cback,
+                                        NULL,
+                                        avdt_l2c_data_ind_cback,
+                                        avdt_l2c_congestion_ind_cback,
+                                        NULL, /* tL2CA_TX_COMPLETE_CB */
+                                        NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 /*******************************************************************************
  *
@@ -76,9 +76,9 @@
                                          tBT_TRANSPORT transport,
                                          UNUSED_ATTR void* p_ref_data,
                                          uint8_t res) {
-  tAVDT_CCB* p_ccb = NULL;
+  AvdtpCcb* p_ccb = NULL;
   tL2CAP_CFG_INFO cfg;
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d", res);
   p_ccb = avdt_ccb_by_bd(*bd_addr);
@@ -92,9 +92,9 @@
                     L2CAP_CONN_OK);
 
     /* store idx in LCID table, store LCID in routing table */
-    avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] =
+    avdtp_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] =
         avdt_ad_tc_tbl_to_idx(p_tbl);
-    avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
+    avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
 
     /* transition to configuration state */
     p_tbl->state = AVDT_AD_ST_CFG;
@@ -127,9 +127,9 @@
                                          tBT_TRANSPORT trasnport,
                                          UNUSED_ATTR void* p_ref_data,
                                          uint8_t res) {
-  tAVDT_CCB* p_ccb = NULL;
+  AvdtpCcb* p_ccb = NULL;
   tL2CAP_CFG_INFO cfg;
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res);
   if (bd_addr) p_ccb = avdt_ccb_by_bd(*bd_addr);
@@ -164,8 +164,8 @@
  ******************************************************************************/
 void avdt_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
                                 UNUSED_ATTR uint16_t psm, uint8_t id) {
-  tAVDT_CCB* p_ccb;
-  tAVDT_TC_TBL* p_tbl = NULL;
+  AvdtpCcb* p_ccb;
+  AvdtpTransportChannel* p_tbl = NULL;
   uint16_t result;
   tL2CAP_CFG_INFO cfg;
   tBTM_STATUS rc;
@@ -174,14 +174,20 @@
   p_ccb = avdt_ccb_by_bd(bd_addr);
   if (p_ccb == NULL) {
     /* no, allocate ccb */
-    p_ccb = avdt_ccb_alloc(bd_addr);
+    int channel_index = BTA_AvObtainPeerChannelIndex(bd_addr);
+    if (channel_index >= 0) {
+      p_ccb = avdt_ccb_alloc_by_channel_index(bd_addr, channel_index);
+    }
+    if (p_ccb == nullptr) {
+      p_ccb = avdt_ccb_alloc(bd_addr);
+    }
     if (p_ccb == NULL) {
       /* no ccb available, reject L2CAP connection */
       result = L2CAP_CONN_NO_RESOURCES;
     } else {
       /* allocate and set up entry; first channel is always signaling */
       p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
-      p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+      p_tbl->my_mtu = avdtp_cb.rcb.ctrl_mtu;
       p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
       p_tbl->tcid = AVDT_CHAN_SIG;
       p_tbl->lcid = lcid;
@@ -208,36 +214,30 @@
       }
       return;
     }
-  }
-  /* deal with simultaneous control channel connect case */
-  else {
+  } else {
+    /* deal with simultaneous control channel connect case */
     p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN);
     if (p_tbl != NULL) {
       /* reject their connection */
       result = L2CAP_CONN_NO_RESOURCES;
-    }
-    /* this must be a traffic channel; are we accepting a traffic channel
-    ** for this ccb?
-    */
-    else {
+    } else {
+      /* This must be a traffic channel; are we accepting a traffic channel
+       * for this ccb?
+       */
       p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP);
       if (p_tbl != NULL) {
         /* yes; proceed with connection */
         result = L2CAP_CONN_OK;
-      }
-#if (AVDT_REPORTING == TRUE)
-      /* this must be a reporting channel; are we accepting a reporting channel
-      ** for this ccb?
-      */
-      else {
+      } else {
+        /* this must be a reporting channel; are we accepting a reporting
+         * channel for this ccb?
+         */
         p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP);
         if (p_tbl != NULL) {
           /* yes; proceed with connection */
           result = L2CAP_CONN_OK;
-        }
-#endif
-        /* else we're not listening for traffic channel; reject */
-        else {
+        } else {
+          /* else we're not listening for traffic channel; reject */
           result = L2CAP_CONN_NO_PSM;
         }
       }
@@ -250,9 +250,9 @@
   /* if result ok, proceed with connection */
   if (result == L2CAP_CONN_OK) {
     /* store idx in LCID table, store LCID in routing table */
-    avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] =
+    avdtp_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] =
         avdt_ad_tc_tbl_to_idx(p_tbl);
-    avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+    avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
 
     /* transition to configuration state */
     p_tbl->state = AVDT_AD_ST_CFG;
@@ -278,9 +278,9 @@
  *
  ******************************************************************************/
 void avdt_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
   tL2CAP_CFG_INFO cfg;
-  tAVDT_CCB* p_ccb;
+  AvdtpCcb* p_ccb;
 
   AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d", lcid,
                    result);
@@ -351,7 +351,9 @@
  *
  ******************************************************************************/
 void avdt_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
+
+  AVDT_TRACE_DEBUG("%s: lcid: %d", __func__, lcid);
 
   /* look up info for this channel */
   p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
@@ -390,7 +392,9 @@
  *
  ******************************************************************************/
 void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
+
+  AVDT_TRACE_DEBUG("%s: lcid: %d", __func__, lcid);
 
   /* look up info for this channel */
   p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
@@ -401,7 +405,8 @@
     } else {
       p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
     }
-    AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x", p_tbl->peer_mtu, lcid);
+    AVDT_TRACE_DEBUG("%s: peer_mtu: %d, lcid: %d", __func__, p_tbl->peer_mtu,
+                     lcid);
 
     /* send L2CAP configure response */
     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
@@ -432,7 +437,7 @@
  *
  ******************************************************************************/
 void avdt_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
                    lcid, ack_needed);
@@ -459,7 +464,7 @@
  *
  ******************************************************************************/
 void avdt_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d", lcid,
                    result);
@@ -481,7 +486,7 @@
  *
  ******************************************************************************/
 void avdt_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   /* look up info for this channel */
   p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
@@ -501,7 +506,7 @@
  *
  ******************************************************************************/
 void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
 
   /* look up info for this channel */
   p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
diff --git a/stack/avdt/avdt_msg.cc b/stack/avdt/avdt_msg.cc
index 52ce2e8..cf517d1 100644
--- a/stack/avdt/avdt_msg.cc
+++ b/stack/avdt/avdt_msg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -272,7 +272,7 @@
  * Returns          void.
  *
  ******************************************************************************/
-static void avdt_msg_bld_cfg(uint8_t** p, tAVDT_CFG* p_cfg) {
+static void avdt_msg_bld_cfg(uint8_t** p, AvdtpSepConfig* p_cfg) {
   uint8_t len;
 
   /* for now, just build media transport, codec, and content protection, and
@@ -284,13 +284,11 @@
     *(*p)++ = 0; /* length */
   }
 
-#if (AVDT_REPORTING == TRUE)
   /* reporting transport */
   if (p_cfg->psc_mask & AVDT_PSC_REPORT) {
     *(*p)++ = AVDT_CAT_REPORT;
     *(*p)++ = 0; /* length */
   }
-#endif
 
   /* codec */
   if (p_cfg->num_codec != 0) {
@@ -470,11 +468,11 @@
  *
  ******************************************************************************/
 static void avdt_msg_bld_svccap(uint8_t** p, tAVDT_MSG* p_msg) {
-  tAVDT_CFG cfg;
+  AvdtpSepConfig cfg = *p_msg->svccap.p_cfg;
 
-  /* make sure the delay report category is not reported */
-  memcpy(&cfg, p_msg->svccap.p_cfg, sizeof(tAVDT_CFG));
-  cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
+  // Include only the Basic Capability
+  cfg.psc_mask &= AVDT_LEG_PSC;
+
   avdt_msg_bld_cfg(p, &cfg);
 }
 
@@ -521,7 +519,7 @@
  *                  in p_elem.
  *
  ******************************************************************************/
-static uint8_t avdt_msg_prs_cfg(tAVDT_CFG* p_cfg, uint8_t* p, uint16_t len,
+static uint8_t avdt_msg_prs_cfg(AvdtpSepConfig* p_cfg, uint8_t* p, uint16_t len,
                                 uint8_t* p_elem, uint8_t sig_id) {
   uint8_t* p_end;
   uint8_t elem = 0;
@@ -640,6 +638,8 @@
         break;
 
       case AVDT_CAT_DELAY_RPT:
+        AVDT_TRACE_DEBUG("%s: Remote device supports delay reporting",
+                         __func__);
         break;
 
       default:
@@ -1036,11 +1036,11 @@
  * Returns          Congested state; true if CCB congested, false if not.
  *
  ******************************************************************************/
-bool avdt_msg_send(tAVDT_CCB* p_ccb, BT_HDR* p_msg) {
+bool avdt_msg_send(AvdtpCcb* p_ccb, BT_HDR* p_msg) {
   uint16_t curr_msg_len;
   uint8_t pkt_type;
   uint8_t hdr_len;
-  tAVDT_TC_TBL* p_tbl;
+  AvdtpTransportChannel* p_tbl;
   BT_HDR* p_buf;
   uint8_t* p;
   uint8_t label;
@@ -1132,16 +1132,16 @@
       if (msg == AVDT_MSG_TYPE_CMD) {
         /* if retransmit timeout set to zero, sig doesn't use retransmit */
         if ((sig == AVDT_SIG_DISCOVER) || (sig == AVDT_SIG_GETCAP) ||
-            (sig == AVDT_SIG_SECURITY) || (avdt_cb.rcb.ret_tout == 0)) {
+            (sig == AVDT_SIG_SECURITY) || (avdtp_cb.rcb.ret_tout == 0)) {
           alarm_cancel(p_ccb->idle_ccb_timer);
           alarm_cancel(p_ccb->ret_ccb_timer);
-          period_ms_t interval_ms = avdt_cb.rcb.sig_tout * 1000;
+          period_ms_t interval_ms = avdtp_cb.rcb.sig_tout * 1000;
           alarm_set_on_mloop(p_ccb->rsp_ccb_timer, interval_ms,
                              avdt_ccb_rsp_ccb_timer_timeout, p_ccb);
         } else if (sig != AVDT_SIG_DELAY_RPT) {
           alarm_cancel(p_ccb->idle_ccb_timer);
           alarm_cancel(p_ccb->rsp_ccb_timer);
-          period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000;
+          period_ms_t interval_ms = avdtp_cb.rcb.ret_tout * 1000;
           alarm_set_on_mloop(p_ccb->ret_ccb_timer, interval_ms,
                              avdt_ccb_ret_ccb_timer_timeout, p_ccb);
         }
@@ -1184,7 +1184,7 @@
  *                  available.
  *
  ******************************************************************************/
-BT_HDR* avdt_msg_asmbl(tAVDT_CCB* p_ccb, BT_HDR* p_buf) {
+BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
   uint8_t* p;
   uint8_t pkt_type;
   BT_HDR* p_ret;
@@ -1305,7 +1305,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_msg_send_cmd(tAVDT_CCB* p_ccb, void* p_scb, uint8_t sig_id,
+void avdt_msg_send_cmd(AvdtpCcb* p_ccb, void* p_scb, uint8_t sig_id,
                        tAVDT_MSG* p_params) {
   uint8_t* p;
   uint8_t* p_start;
@@ -1331,7 +1331,7 @@
     }
     /* for all others, p_scb points to scb as usual */
     else {
-      *p = avdt_scb_to_hdl((tAVDT_SCB*)p_scb);
+      *p = avdt_scb_to_hdl((AvdtpScb*)p_scb);
     }
   }
 
@@ -1362,7 +1362,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_msg_send_rsp(tAVDT_CCB* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+void avdt_msg_send_rsp(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
   uint8_t* p;
   uint8_t* p_start;
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
@@ -1402,7 +1402,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_msg_send_rej(tAVDT_CCB* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+void avdt_msg_send_rej(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
   uint8_t* p;
   uint8_t* p_start;
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
@@ -1453,7 +1453,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_msg_send_grej(tAVDT_CCB* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+void avdt_msg_send_grej(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
   uint8_t* p;
   uint8_t* p_start;
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
@@ -1489,8 +1489,8 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_msg_ind(tAVDT_CCB* p_ccb, BT_HDR* p_buf) {
-  tAVDT_SCB* p_scb;
+void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
+  AvdtpScb* p_scb;
   uint8_t* p;
   bool ok = true;
   bool handle_rsp = false;
@@ -1500,7 +1500,7 @@
   uint8_t msg_type;
   uint8_t sig = 0;
   tAVDT_MSG msg;
-  tAVDT_CFG cfg;
+  AvdtpSepConfig cfg;
   uint8_t err;
   uint8_t evt = 0;
   uint8_t scb_hdl;
@@ -1565,7 +1565,7 @@
     } else if ((msg_type == AVDT_MSG_TYPE_RSP) &&
                ((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP))) {
       /* parse discover rsp message to struct supplied by app */
-      msg.svccap.p_cfg = (tAVDT_CFG*)p_ccb->p_proc_data;
+      msg.svccap.p_cfg = (AvdtpSepConfig*)p_ccb->p_proc_data;
     } else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG)) {
       /* parse get config rsp message to struct allocated locally */
       msg.svccap.p_cfg = &cfg;
diff --git a/stack/avdt/avdt_scb.cc b/stack/avdt/avdt_scb.cc
index 777cc73..eacdf83 100644
--- a/stack/avdt/avdt_scb.cc
+++ b/stack/avdt/avdt_scb.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -89,13 +89,9 @@
                                             avdt_scb_hdl_suspend_cmd,
                                             avdt_scb_hdl_suspend_rsp,
                                             avdt_scb_hdl_tc_close,
-#if (AVDT_REPORTING == TRUE)
                                             avdt_scb_hdl_tc_close_sto,
-#endif
                                             avdt_scb_hdl_tc_open,
-#if (AVDT_REPORTING == TRUE)
                                             avdt_scb_hdl_tc_open_sto,
-#endif
                                             avdt_scb_snd_delay_rpt_req,
                                             avdt_scb_hdl_delay_rpt_cmd,
                                             avdt_scb_hdl_delay_rpt_rsp,
@@ -528,17 +524,10 @@
     {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
     /* TC_TOUT_EVT */
     {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
-#if (AVDT_REPORTING == TRUE)
     /* TC_OPEN_EVT */
     {AVDT_SCB_HDL_TC_OPEN_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
     /* TC_CLOSE_EVT */
     {AVDT_SCB_HDL_TC_CLOSE_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
-#else
-    /* TC_OPEN_EVT */
-    {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
-    /* TC_CLOSE_EVT */
-    {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
-#endif
     /* TC_CONG_EVT */
     {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
     /* TC_DATA_EVT */
@@ -766,15 +755,16 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_event(tAVDT_SCB* p_scb, uint8_t event, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_event(AvdtpScb* p_scb, uint8_t event, tAVDT_SCB_EVT* p_data) {
   tAVDT_SCB_ST_TBL state_table;
   uint8_t action;
   int i;
 
 #if (AVDT_DEBUG == TRUE)
-  AVDT_TRACE_EVENT("%s: SCB hdl=%d event=%d/%s state=%s", __func__,
-                   avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event],
-                   avdt_scb_st_str[p_scb->state]);
+  AVDT_TRACE_EVENT(
+      "%s: SCB hdl=%d event=%d/%s state=%s p_avdt_scb=%p scb_index=%d",
+      __func__, avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event],
+      avdt_scb_st_str[p_scb->state], p_scb, p_scb->stream_config.scb_index);
 #endif
   /* set current event */
   p_scb->curr_evt = event;
@@ -791,7 +781,7 @@
   for (i = 0; i < AVDT_SCB_ACTIONS; i++) {
     action = state_table[event][i];
     if (action != AVDT_SCB_IGNORE) {
-      (*avdt_cb.p_scb_act[action])(p_scb, p_data);
+      (*avdtp_cb.p_scb_act[action])(p_scb, p_data);
     } else {
       break;
     }
@@ -809,8 +799,13 @@
  *
  ******************************************************************************/
 void avdt_scb_init(void) {
-  memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS);
-  avdt_cb.p_scb_act = (tAVDT_SCB_ACTION*)avdt_scb_action;
+  for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
+    for (size_t j = 0; j < AVDT_NUM_SEPS; j++) {
+      avdtp_cb.ccb[i].scb[j].Reset(0);
+    }
+  }
+
+  avdtp_cb.p_scb_act = avdt_scb_action;
 }
 
 /*******************************************************************************
@@ -823,33 +818,34 @@
  * Returns          pointer to the scb, or NULL if none could be allocated.
  *
  ******************************************************************************/
-tAVDT_SCB* avdt_scb_alloc(tAVDT_CS* p_cs) {
-  tAVDT_SCB* p_scb = &avdt_cb.scb[0];
-  int i;
+AvdtpScb* avdt_scb_alloc(uint8_t peer_id,
+                         const AvdtpStreamConfig& avdtp_stream_config) {
+  CHECK(peer_id < AVDT_NUM_LINKS);
 
-  /* find available scb */
-  for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
+  // Find available entry
+  AvdtpScb* p_scb = &avdtp_cb.ccb[peer_id].scb[0];
+  for (int i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
     if (!p_scb->allocated) {
-      memset(p_scb, 0, sizeof(tAVDT_SCB));
-      p_scb->allocated = true;
-      p_scb->p_ccb = NULL;
-
-      memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
-      p_scb->transport_channel_timer =
-          alarm_new("avdt_scb.transport_channel_timer");
-      AVDT_TRACE_DEBUG("%s: hdl=%d, psc_mask:0x%x", __func__, i + 1,
-                       p_cs->cfg.psc_mask);
-      break;
+      p_scb->Allocate(&avdtp_cb.ccb[peer_id], avdtp_stream_config);
+      AVDT_TRACE_DEBUG("%s: allocated (handle=%d, psc_mask:0x%x)", __func__,
+                       p_scb->ScbHandle(), avdtp_stream_config.cfg.psc_mask);
+      return p_scb;
     }
   }
 
-  if (i == AVDT_NUM_SEPS) {
-    /* out of ccbs */
-    p_scb = NULL;
-    AVDT_TRACE_WARNING("Out of scbs");
-  }
+  AVDT_TRACE_WARNING("%s: out of AvdtScb entries for peer_id %d", __func__,
+                     peer_id);
+  return nullptr;
+}
 
-  return p_scb;
+void AvdtpScb::Allocate(AvdtpCcb* p_avdtp_ccb,
+                        const AvdtpStreamConfig& avdtp_stream_config) {
+  uint8_t scb_handle = avdtp_cb.ComputeScbHandle(this);
+  Reset(scb_handle);
+  p_ccb = p_avdtp_ccb;
+  stream_config = avdtp_stream_config;
+  transport_channel_timer = alarm_new("avdtp_scb.transport_channel_timer");
+  allocated = true;
 }
 
 /*******************************************************************************
@@ -862,10 +858,9 @@
  * Returns          void.
  *
  ******************************************************************************/
-void avdt_scb_dealloc(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_dealloc(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   AVDT_TRACE_DEBUG("%s: hdl=%d", __func__, avdt_scb_to_hdl(p_scb));
-  alarm_free(p_scb->transport_channel_timer);
-  memset(p_scb, 0, sizeof(tAVDT_SCB));
+  p_scb->Recycle();
 }
 
 /*******************************************************************************
@@ -878,9 +873,7 @@
  * Returns          Index of scb.
  *
  ******************************************************************************/
-uint8_t avdt_scb_to_hdl(tAVDT_SCB* p_scb) {
-  return (uint8_t)(p_scb - avdt_cb.scb + 1);
-}
+uint8_t avdt_scb_to_hdl(AvdtpScb* p_scb) { return p_scb->ScbHandle(); }
 
 /*******************************************************************************
  *
@@ -893,22 +886,26 @@
  *                  is not allocated.
  *
  ******************************************************************************/
-tAVDT_SCB* avdt_scb_by_hdl(uint8_t hdl) {
-  tAVDT_SCB* p_scb;
-
-  /* verify index */
-  if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS)) {
-    p_scb = &avdt_cb.scb[hdl - 1];
-
-    /* verify scb is allocated */
-    if (!p_scb->allocated) {
-      p_scb = NULL;
-      AVDT_TRACE_WARNING("scb hdl %d not allocated", hdl);
-    }
-  } else {
-    p_scb = NULL;
-    AVDT_TRACE_WARNING("scb hdl %d out of range", hdl);
+AvdtpScb* avdt_scb_by_hdl(uint8_t hdl) {
+  // Verify the index
+  if ((hdl < 1) || (hdl > AVDT_NUM_LINKS * AVDT_NUM_SEPS)) {
+    AVDT_TRACE_WARNING("%s: SCB handle %d out of range", __func__, hdl);
+    return nullptr;
   }
+
+  uint8_t index = hdl - 1;
+  size_t i = index / AVDT_NUM_LINKS;
+  size_t j = index % AVDT_NUM_SEPS;
+
+  AvdtpScb* p_scb = &avdtp_cb.ccb[i].scb[j];
+  // Verify the whether the scb is allocated
+  if (!p_scb->allocated) {
+    AVDT_TRACE_WARNING("%s: SCB handle %d not allocated", __func__, hdl);
+    return nullptr;
+  }
+
+  AVDT_TRACE_DEBUG("%s: SCB for handle %d found: p_scb=%p scb_index=%d",
+                   __func__, hdl, p_scb, p_scb->stream_config.scb_index);
   return p_scb;
 }
 
@@ -922,10 +919,10 @@
  * Returns          SEID that failed, or 0 if success.
  *
  ******************************************************************************/
-uint8_t avdt_scb_verify(tAVDT_CCB* p_ccb, uint8_t state, uint8_t* p_seid,
+uint8_t avdt_scb_verify(AvdtpCcb* p_ccb, uint8_t state, uint8_t* p_seid,
                         uint16_t num_seid, uint8_t* p_err_code) {
   int i;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
   uint8_t nsc_mask;
   uint8_t ret = 0;
 
@@ -933,7 +930,9 @@
   /* set nonsupported command mask */
   /* translate public state into private state */
   nsc_mask = 0;
-  if (state == AVDT_VERIFY_SUSPEND) nsc_mask = AVDT_NSC_SUSPEND;
+  if (state == AVDT_VERIFY_SUSPEND) {
+    nsc_mask = AvdtpStreamConfig::AVDT_NSC_SUSPEND;
+  }
 
   /* verify every scb */
   for (i = 0, *p_err_code = 0;
@@ -943,7 +942,7 @@
       *p_err_code = AVDT_ERR_BAD_STATE;
     else if (p_scb->p_ccb != p_ccb)
       *p_err_code = AVDT_ERR_BAD_STATE;
-    else if (p_scb->cs.nsc_mask & nsc_mask)
+    else if (p_scb->stream_config.nsc_mask & nsc_mask)
       *p_err_code = AVDT_ERR_NSC;
 
     switch (state) {
@@ -982,7 +981,7 @@
  ******************************************************************************/
 void avdt_scb_peer_seid_list(tAVDT_MULTI* p_multi) {
   int i;
-  tAVDT_SCB* p_scb;
+  AvdtpScb* p_scb;
 
   for (i = 0; i < p_multi->num_seps; i++) {
     p_scb = avdt_scb_by_hdl(p_multi->seid_list[i]);
diff --git a/stack/avdt/avdt_scb_act.cc b/stack/avdt/avdt_scb_act.cc
index de6912b..d55a22e 100644
--- a/stack/avdt/avdt_scb_act.cc
+++ b/stack/avdt/avdt_scb_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@
  * state machine API request event.  Note that state machine API request
  * events are at the beginning of the event list starting at zero, thus
  * allowing for this table.
-*/
+ */
 const uint8_t avdt_scb_cback_evt[] = {
     0,                     /* API_REMOVE_EVT (no event) */
     AVDT_WRITE_CFM_EVT,    /* API_WRITE_REQ_EVT */
@@ -62,10 +62,10 @@
  * Returns          SSRC value.
  *
  ******************************************************************************/
-uint32_t avdt_scb_gen_ssrc(tAVDT_SCB* p_scb) {
+uint32_t avdt_scb_gen_ssrc(AvdtpScb* p_scb) {
   /* combine the value of the media type and codec type of the SCB */
-  return (
-      (uint32_t)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2]));
+  return ((uint32_t)(p_scb->stream_config.cfg.codec_info[1] |
+                     p_scb->stream_config.cfg.codec_info[2]));
 }
 
 /*******************************************************************************
@@ -78,7 +78,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_abort_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_abort_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_scb->role = AVDT_CLOSE_ACP;
   avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data);
 }
@@ -93,7 +93,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_abort_rsp(UNUSED_ATTR tAVDT_SCB* p_scb,
+void avdt_scb_hdl_abort_rsp(UNUSED_ATTR AvdtpScb* p_scb,
                             UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   return;
 }
@@ -108,7 +108,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_close_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_close_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_scb->role = AVDT_CLOSE_ACP;
   avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data);
 }
@@ -123,7 +123,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_close_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_scb->close_code = p_data->msg.hdr.err_code;
 }
 
@@ -138,7 +138,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_getconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
 
   avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data);
@@ -154,7 +154,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_getconfig_rsp(UNUSED_ATTR tAVDT_SCB* p_scb,
+void avdt_scb_hdl_getconfig_rsp(UNUSED_ATTR AvdtpScb* p_scb,
                                 UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   return;
 }
@@ -169,7 +169,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_open_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_open_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data);
 }
 
@@ -185,7 +185,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_open_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_open_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   /* do exactly same as setconfig reject */
   avdt_scb_hdl_setconfig_rej(p_scb, p_data);
 }
@@ -200,8 +200,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_open_rsp(tAVDT_SCB* p_scb,
-                           UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_open_rsp(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   /* initiate opening of trans channels for this SEID */
   p_scb->role = AVDT_OPEN_INT;
   avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT);
@@ -221,7 +220,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_pkt_no_frag(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   uint8_t *p, *p_start;
   uint8_t o_v, o_p, o_x, o_cc;
   uint8_t m_pt;
@@ -271,19 +270,18 @@
     p_data->p_pkt->len -= (offset + pad_len);
     p_data->p_pkt->offset += offset;
 
-    if (p_scb->cs.p_sink_data_cback != NULL) {
+    if (p_scb->stream_config.p_sink_data_cback != NULL) {
       /* report sequence number */
       p_data->p_pkt->layer_specific = seq;
-      (*p_scb->cs.p_sink_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt,
-                                     time_stamp,
-                                     (uint8_t)(m_pt | (marker << 7)));
+      (*p_scb->stream_config.p_sink_data_cback)(
+          avdt_scb_to_hdl(p_scb), p_data->p_pkt, time_stamp,
+          (uint8_t)(m_pt | (marker << 7)));
     } else {
       osi_free_and_reset((void**)&p_data->p_pkt);
     }
   }
 }
 
-#if (AVDT_REPORTING == TRUE)
 /*******************************************************************************
  *
  * Function         avdt_scb_hdl_report
@@ -293,7 +291,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
+uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) {
   uint16_t result = AVDT_SUCCESS;
   uint8_t* p_start = p;
   uint32_t ssrc;
@@ -302,7 +300,7 @@
   tAVDT_REPORT_DATA report;
 
   AVDT_TRACE_DEBUG("%s", __func__);
-  if (p_scb->cs.p_report_cback) {
+  if (p_scb->stream_config.p_report_cback) {
     /* parse report packet header */
     AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
     pt = *p++;
@@ -352,12 +350,12 @@
     }
 
     if (result == AVDT_SUCCESS)
-      (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, &report);
+      (*p_scb->stream_config.p_report_cback)(avdt_scb_to_hdl(p_scb), pt,
+                                             &report);
   }
   p_start += len;
   return p_start;
 }
-#endif
 
 /*******************************************************************************
  *
@@ -368,15 +366,14 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-#if (AVDT_REPORTING == TRUE)
+void avdt_scb_hdl_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   if (p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT) {
     uint8_t* p = (uint8_t*)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
     avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len);
     osi_free_and_reset((void**)&p_data->p_pkt);
-  } else
-#endif
+  } else {
     avdt_scb_hdl_pkt_no_frag(p_scb, p_data);
+  }
 }
 
 /*******************************************************************************
@@ -389,7 +386,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_drop_pkt(UNUSED_ATTR tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_drop_pkt(UNUSED_ATTR AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   AVDT_TRACE_ERROR("%s dropped incoming media packet", __func__);
   osi_free_and_reset((void**)&p_data->p_pkt);
 }
@@ -404,21 +401,21 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_reconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   /* if command not supported */
-  if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG) {
+  if (p_scb->stream_config.nsc_mask & AvdtpStreamConfig::AVDT_NSC_RECONFIG) {
     /* send reject */
     p_data->msg.hdr.err_code = AVDT_ERR_NSC;
     p_data->msg.hdr.err_param = 0;
     avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data);
   } else {
     /* store requested configuration */
-    memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG));
+    p_scb->req_cfg = *p_data->msg.reconfig_cmd.p_cfg;
 
     /* call application callback */
-    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
-                              AVDT_RECONFIG_IND_EVT,
-                              (tAVDT_CTRL*)&p_data->msg.reconfig_cmd);
+    (*p_scb->stream_config.p_avdt_ctrl_cback)(
+        avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_RECONFIG_IND_EVT,
+        (tAVDT_CTRL*)&p_data->msg.reconfig_cmd, p_scb->stream_config.scb_index);
   }
 }
 
@@ -432,7 +429,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_reconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   if (p_data->msg.hdr.err_code == 0) {
     /* store new configuration */
     if (p_scb->req_cfg.num_codec > 0) {
@@ -450,8 +447,9 @@
   p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
 
   /* call application callback */
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_RECONFIG_CFM_EVT,
-                            (tAVDT_CTRL*)&p_data->msg.svccap);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_RECONFIG_CFM_EVT,
+      (tAVDT_CTRL*)&p_data->msg.svccap, p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -464,17 +462,17 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_security_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_security_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   /* if command not supported */
-  if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY) {
+  if (p_scb->stream_config.nsc_mask & AvdtpStreamConfig::AVDT_NSC_SECURITY) {
     /* send reject */
     p_data->msg.hdr.err_code = AVDT_ERR_NSC;
     avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data);
   } else {
     /* call application callback */
-    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
-                              AVDT_SECURITY_IND_EVT,
-                              (tAVDT_CTRL*)&p_data->msg.security_cmd);
+    (*p_scb->stream_config.p_avdt_ctrl_cback)(
+        avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_SECURITY_IND_EVT,
+        (tAVDT_CTRL*)&p_data->msg.security_cmd, p_scb->stream_config.scb_index);
   }
 }
 
@@ -488,10 +486,11 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_security_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   /* call application callback */
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_SECURITY_CFM_EVT,
-                            (tAVDT_CTRL*)&p_data->msg.security_cmd);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_SECURITY_CFM_EVT,
+      (tAVDT_CTRL*)&p_data->msg.security_cmd, p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -505,30 +504,44 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-  tAVDT_CFG* p_cfg;
-
-  AVDT_TRACE_DEBUG("%s: p_scb->in_use=%d", __func__, p_scb->in_use);
+void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
+  AVDT_TRACE_DEBUG("%s: p_scb->in_use=%d p_avdt_scb=%p scb_index=%d", __func__,
+                   p_scb->in_use, p_scb, p_scb->stream_config.scb_index);
 
   if (!p_scb->in_use) {
-    A2DP_DumpCodecInfo(p_scb->cs.cfg.codec_info);
-    A2DP_DumpCodecInfo(p_data->msg.config_cmd.p_cfg->codec_info);
-    p_cfg = p_data->msg.config_cmd.p_cfg;
-    if (A2DP_GetCodecType(p_scb->cs.cfg.codec_info) ==
+    AVDT_TRACE_DEBUG(
+        "%s: codec: %s", __func__,
+        A2DP_CodecInfoString(p_scb->stream_config.cfg.codec_info).c_str());
+    AVDT_TRACE_DEBUG(
+        "%s: codec: %s", __func__,
+        A2DP_CodecInfoString(p_data->msg.config_cmd.p_cfg->codec_info).c_str());
+    AvdtpSepConfig* p_cfg = p_data->msg.config_cmd.p_cfg;
+    if (A2DP_GetCodecType(p_scb->stream_config.cfg.codec_info) ==
         A2DP_GetCodecType(p_cfg->codec_info)) {
+      /* copy info to scb */
+      AvdtpCcb* p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+      if (p_scb->p_ccb != p_ccb) {
+        AVDT_TRACE_ERROR(
+            "%s: mismatch in AVDTP SCB/CCB state: (p_scb->p_ccb=%p != "
+            "p_ccb=%p): "
+            "p_scb=%p scb_handle=%d ccb_idx=%d",
+            __func__, p_scb->p_ccb, p_ccb, p_scb, p_scb->ScbHandle(),
+            p_data->msg.config_cmd.hdr.ccb_idx);
+        avdt_scb_rej_not_in_use(p_scb, p_data);
+        return;
+      }
       /* set sep as in use */
       p_scb->in_use = true;
 
-      /* copy info to scb */
-      p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
       p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
-      memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
+      p_scb->req_cfg = *p_cfg;
       /* call app callback */
       /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/
-      (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                                p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                                AVDT_CONFIG_IND_EVT,
-                                (tAVDT_CTRL*)&p_data->msg.config_cmd);
+      (*p_scb->stream_config.p_avdt_ctrl_cback)(
+          avdt_scb_to_hdl(p_scb),
+          p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+          AVDT_CONFIG_IND_EVT, (tAVDT_CTRL*)&p_data->msg.config_cmd,
+          p_scb->stream_config.scb_index);
     } else {
       p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG;
       p_data->msg.hdr.err_param = 0;
@@ -552,7 +565,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_setconfig_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   /* clear scb variables */
   avdt_scb_clr_vars(p_scb, p_data);
 
@@ -561,8 +574,9 @@
                  AVDT_CCB_UL_CLOSE_EVT, NULL);
 
   /* call application callback */
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_OPEN_CFM_EVT,
-                            (tAVDT_CTRL*)&p_data->msg.hdr);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_OPEN_CFM_EVT,
+      (tAVDT_CTRL*)&p_data->msg.hdr, p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -575,13 +589,13 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB* p_scb,
+void avdt_scb_hdl_setconfig_rsp(AvdtpScb* p_scb,
                                 UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_EVT_HDR single;
 
   if (p_scb->p_ccb != NULL) {
     /* save configuration */
-    memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+    p_scb->curr_cfg = p_scb->req_cfg;
 
     /* initiate open */
     single.seid = p_scb->peer_seid;
@@ -601,11 +615,12 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_start_cmd(tAVDT_SCB* p_scb,
+void avdt_scb_hdl_start_cmd(AvdtpScb* p_scb,
                             UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                            p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                            AVDT_START_IND_EVT, NULL);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+      AVDT_START_IND_EVT, NULL, p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -618,10 +633,12 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_start_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                            p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                            AVDT_START_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+void avdt_scb_hdl_start_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+      AVDT_START_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr,
+      p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -634,11 +651,12 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_suspend_cmd(tAVDT_SCB* p_scb,
+void avdt_scb_hdl_suspend_cmd(AvdtpScb* p_scb,
                               UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                            p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                            AVDT_SUSPEND_IND_EVT, NULL);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+      AVDT_SUSPEND_IND_EVT, NULL, p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -651,10 +669,12 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_suspend_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-  (*p_scb->cs.p_ctrl_cback)(
-      avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-      AVDT_SUSPEND_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+void avdt_scb_hdl_suspend_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+      AVDT_SUSPEND_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr,
+      p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -673,13 +693,14 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_tc_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_tc_close(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   uint8_t hdl = avdt_scb_to_hdl(p_scb);
-  tAVDT_CTRL_CBACK* p_ctrl_cback = p_scb->cs.p_ctrl_cback;
+  tAVDT_CTRL_CBACK* p_avdt_ctrl_cback = p_scb->stream_config.p_avdt_ctrl_cback;
   tAVDT_CTRL avdt_ctrl;
   uint8_t event;
-  tAVDT_CCB* p_ccb = p_scb->p_ccb;
+  AvdtpCcb* p_ccb = p_scb->p_ccb;
   RawAddress remote_addr = p_ccb->peer_addr;
+  uint8_t scb_index = p_scb->stream_config.scb_index;
 
   /* set up hdr */
   avdt_ctrl.hdr.err_code = p_scb->close_code;
@@ -707,7 +728,7 @@
   }
 
   /* call app callback */
-  (*p_ctrl_cback)(hdl, &remote_addr, event, &avdt_ctrl);
+  (*p_avdt_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl, scb_index);
 }
 
 /*******************************************************************************
@@ -720,7 +741,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_delay_rpt_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_delay_rpt_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT,
                     (tAVDT_MSG*)&p_data->apidelay);
 }
@@ -735,10 +756,12 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-  (*p_scb->cs.p_ctrl_cback)(
-      avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-      AVDT_DELAY_REPORT_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+void avdt_scb_hdl_delay_rpt_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+      AVDT_DELAY_REPORT_EVT, (tAVDT_CTRL*)&p_data->msg.hdr,
+      p_scb->stream_config.scb_index);
 
   if (p_scb->p_ccb)
     avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
@@ -756,13 +779,14 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-  (*p_scb->cs.p_ctrl_cback)(
-      avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-      AVDT_DELAY_REPORT_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+void avdt_scb_hdl_delay_rpt_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+      AVDT_DELAY_REPORT_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr,
+      p_scb->stream_config.scb_index);
 }
 
-#if (AVDT_REPORTING == TRUE)
 /*******************************************************************************
  *
  * Function         avdt_scb_hdl_tc_close_sto
@@ -773,7 +797,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_tc_close_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_tc_close_sto(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
   /* AVDT_CHAN_SIG does not visit this action */
   if (p_data && p_data->close.type != AVDT_CHAN_MEDIA) {
@@ -783,9 +807,10 @@
       avdt_ctrl.hdr.err_code = 0;
       avdt_ctrl.hdr.err_param = 0;
       /* call app callback */
-      (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                                p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                                AVDT_REPORT_DISCONN_EVT, &avdt_ctrl);
+      (*p_scb->stream_config.p_avdt_ctrl_cback)(
+          avdt_scb_to_hdl(p_scb),
+          p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+          AVDT_REPORT_DISCONN_EVT, &avdt_ctrl, p_scb->stream_config.scb_index);
     }
   } else {
     /* must be in OPEN state. need to go back to idle */
@@ -793,7 +818,6 @@
     avdt_scb_hdl_tc_close(p_scb, p_data);
   }
 }
-#endif
 
 /*******************************************************************************
  *
@@ -807,11 +831,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_tc_open(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_tc_open(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   uint8_t event;
-#if (AVDT_REPORTING == TRUE)
   uint8_t role;
-#endif
 
   alarm_cancel(p_scb->transport_channel_timer);
 
@@ -819,24 +841,22 @@
       (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT;
   p_data->open.hdr.err_code = 0;
 
-  AVDT_TRACE_DEBUG("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x",
-                   p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask,
+  AVDT_TRACE_DEBUG("%s: psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x", __func__,
+                   p_scb->stream_config.cfg.psc_mask, p_scb->req_cfg.psc_mask,
                    p_scb->curr_cfg.psc_mask);
-#if (AVDT_REPORTING == TRUE)
   if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) {
     /* open the reporting channel, if both devices support it */
     role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP;
     avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role);
   }
-#endif
 
   /* call app callback */
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                            p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                            event, (tAVDT_CTRL*)&p_data->open);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb),
+      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty, event,
+      (tAVDT_CTRL*)&p_data->open, p_scb->stream_config.scb_index);
 }
 
-#if (AVDT_REPORTING == TRUE)
 /*******************************************************************************
  *
  * Function         avdt_scb_hdl_tc_open_sto
@@ -849,7 +869,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_tc_open_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_tc_open_sto(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
   /* open reporting channel here, when it is implemented */
 
@@ -857,12 +877,12 @@
   if (p_data->open.hdr.err_code == AVDT_CHAN_REPORT) {
     avdt_ctrl.hdr.err_code = 0;
     avdt_ctrl.hdr.err_param = 1;
-    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
-                              p_scb->p_ccb ? &p_scb->p_ccb->peer_addr : NULL,
-                              AVDT_REPORT_CONN_EVT, &avdt_ctrl);
+    (*p_scb->stream_config.p_avdt_ctrl_cback)(
+        avdt_scb_to_hdl(p_scb),
+        p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
+        AVDT_REPORT_CONN_EVT, &avdt_ctrl, p_scb->stream_config.scb_index);
   }
 }
-#endif
 
 /*******************************************************************************
  *
@@ -875,7 +895,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_hdl_write_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_hdl_write_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   uint8_t* p;
   uint32_t ssrc;
   bool add_rtp_header = !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP);
@@ -923,7 +943,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_abort_req(tAVDT_SCB* p_scb,
+void avdt_scb_snd_abort_req(AvdtpScb* p_scb,
                             UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_EVT_HDR hdr;
 
@@ -949,7 +969,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_abort_rsp(UNUSED_ATTR tAVDT_SCB* p_scb,
+void avdt_scb_snd_abort_rsp(UNUSED_ATTR AvdtpScb* p_scb,
                             tAVDT_SCB_EVT* p_data) {
   avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT,
                     &p_data->msg);
@@ -964,7 +984,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_close_req(tAVDT_SCB* p_scb,
+void avdt_scb_snd_close_req(AvdtpScb* p_scb,
                             UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_EVT_HDR hdr;
 
@@ -986,7 +1006,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_stream_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_stream_close(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   osi_free_and_reset((void**)&p_scb->p_pkt);
   avdt_scb_snd_close_req(p_scb, p_data);
 }
@@ -1000,7 +1020,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_close_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg);
 }
 
@@ -1013,7 +1033,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_getconfig_req(tAVDT_SCB* p_scb,
+void avdt_scb_snd_getconfig_req(AvdtpScb* p_scb,
                                 UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_EVT_HDR hdr;
 
@@ -1033,7 +1053,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_getconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_getconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg);
 }
 
@@ -1046,8 +1066,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_open_req(tAVDT_SCB* p_scb,
-                           UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_open_req(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_EVT_HDR hdr;
 
   hdr.seid = p_scb->peer_seid;
@@ -1068,7 +1087,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_open_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   /* notify adaption that we're waiting for transport channel open */
   p_scb->role = AVDT_OPEN_ACP;
   avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP);
@@ -1091,12 +1110,14 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_reconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_reconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   AVDT_TRACE_DEBUG("%s: p_scb->peer_seid=%d p_data->msg.hdr.seid=%d", __func__,
                    p_scb->peer_seid, p_data->msg.hdr.seid);
-  A2DP_DumpCodecInfo(p_data->msg.config_cmd.p_cfg->codec_info);
+  AVDT_TRACE_DEBUG(
+      "%s: codec: %s", __func__,
+      A2DP_CodecInfoString(p_data->msg.config_cmd.p_cfg->codec_info).c_str());
 
-  memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+  p_scb->req_cfg = *p_data->msg.config_cmd.p_cfg;
   p_data->msg.hdr.seid = p_scb->peer_seid;
   avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
 }
@@ -1111,7 +1132,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_reconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   if (p_data->msg.hdr.err_code == 0) {
     /* store new configuration */
     if (p_scb->req_cfg.num_codec > 0) {
@@ -1142,7 +1163,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_security_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_security_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_data->msg.hdr.seid = p_scb->peer_seid;
   avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg);
 }
@@ -1156,7 +1177,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_security_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   if (p_data->msg.hdr.err_code == 0) {
     avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
   } else {
@@ -1174,7 +1195,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_setconfig_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   if (p_scb->p_ccb != NULL) {
     avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
 
@@ -1195,19 +1216,30 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_setconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
-  tAVDT_CFG *p_req, *p_cfg;
+void avdt_scb_snd_setconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
+  AvdtpSepConfig *p_req, *p_cfg;
 
-  AVDT_TRACE_DEBUG("%s", __func__);
-  A2DP_DumpCodecInfo(p_data->msg.config_cmd.p_cfg->codec_info);
+  AVDT_TRACE_DEBUG(
+      "%s: codec: %s", __func__,
+      A2DP_CodecInfoString(p_data->msg.config_cmd.p_cfg->codec_info).c_str());
 
   /* copy API parameters to scb, set scb as in use */
+
+  AvdtpCcb* p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+  if (p_scb->p_ccb != p_ccb) {
+    AVDT_TRACE_ERROR(
+        "%s: mismatch in AVDTP SCB/CCB state: (p_scb->p_ccb=%p != p_ccb=%p): "
+        "p_scb=%p scb_handle=%d ccb_idx=%d",
+        __func__, p_scb->p_ccb, p_ccb, p_scb, p_scb->ScbHandle(),
+        p_data->msg.config_cmd.hdr.ccb_idx);
+    avdt_scb_rej_not_in_use(p_scb, p_data);
+    return;
+  }
   p_scb->in_use = true;
-  p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
   p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid;
   p_req = p_data->msg.config_cmd.p_cfg;
-  p_cfg = &p_scb->cs.cfg;
-  memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+  p_cfg = &p_scb->stream_config.cfg;
+  p_scb->req_cfg = *p_data->msg.config_cmd.p_cfg;
 
   avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
 
@@ -1226,9 +1258,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_setconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_snd_setconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   if (p_scb->p_ccb != NULL) {
-    memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+    p_scb->curr_cfg = p_scb->req_cfg;
 
     avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
   }
@@ -1244,12 +1276,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_snd_tc_close(tAVDT_SCB* p_scb,
-                           UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
-#if (AVDT_REPORTING == TRUE)
+void avdt_scb_snd_tc_close(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
     avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
-#endif
   avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
 }
 
@@ -1263,7 +1292,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_cb_err(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_cb_err(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
 
   /* set error code and parameter */
@@ -1271,8 +1300,10 @@
   avdt_ctrl.hdr.err_param = 0;
 
   /* call callback, using lookup table to get callback event */
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
-                            avdt_scb_cback_evt[p_scb->curr_evt], &avdt_ctrl);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb), RawAddress::kEmpty,
+      avdt_scb_cback_evt[p_scb->curr_evt], &avdt_ctrl,
+      p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -1285,7 +1316,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_cong_state(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_cong_state(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_scb->cong = p_data->llcong;
 }
 
@@ -1299,7 +1330,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_rej_state(UNUSED_ATTR tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_rej_state(UNUSED_ATTR AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE;
   p_data->msg.hdr.err_param = 0;
   avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
@@ -1316,7 +1347,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_rej_in_use(UNUSED_ATTR tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_rej_in_use(UNUSED_ATTR AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   p_data->msg.hdr.err_code = AVDT_ERR_IN_USE;
   p_data->msg.hdr.err_param = 0;
   avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
@@ -1333,7 +1364,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_rej_not_in_use(UNUSED_ATTR tAVDT_SCB* p_scb,
+void avdt_scb_rej_not_in_use(UNUSED_ATTR AvdtpScb* p_scb,
                              tAVDT_SCB_EVT* p_data) {
   p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE;
   p_data->msg.hdr.err_param = 0;
@@ -1350,7 +1381,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_set_remove(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_set_remove(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   p_scb->remove = true;
 }
 
@@ -1363,7 +1394,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_free_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+void avdt_scb_free_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
 
   /* set error code and parameter */
@@ -1375,8 +1406,9 @@
   AVDT_TRACE_WARNING("Dropped media packet");
 
   /* we need to call callback to keep data flow going */
-  (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
-                            &avdt_ctrl);
+  (*p_scb->stream_config.p_avdt_ctrl_cback)(
+      avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_WRITE_CFM_EVT,
+      &avdt_ctrl, p_scb->stream_config.scb_index);
 }
 
 /*******************************************************************************
@@ -1388,9 +1420,9 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_clr_pkt(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_clr_pkt(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
-  tAVDT_CCB* p_ccb;
+  AvdtpCcb* p_ccb;
   uint8_t tcid;
   uint16_t lcid;
 
@@ -1403,7 +1435,7 @@
     /* get tcid from type, scb */
     tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
 
-    lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+    lcid = avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
     L2CA_FlushChannel(lcid, L2CAP_FLUSH_CHANS_ALL);
   }
 
@@ -1413,8 +1445,9 @@
     AVDT_TRACE_DEBUG("Dropped stored media packet");
 
     /* we need to call callback to keep data flow going */
-    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
-                              &avdt_ctrl);
+    (*p_scb->stream_config.p_avdt_ctrl_cback)(
+        avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_WRITE_CFM_EVT,
+        &avdt_ctrl, p_scb->stream_config.scb_index);
   }
 }
 
@@ -1430,7 +1463,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_chk_snd_pkt(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_chk_snd_pkt(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   tAVDT_CTRL avdt_ctrl;
   BT_HDR* p_pkt;
 
@@ -1442,8 +1475,9 @@
       p_scb->p_pkt = NULL;
       avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
 
-      (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
-                                AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+      (*p_scb->stream_config.p_avdt_ctrl_cback)(
+          avdt_scb_to_hdl(p_scb), RawAddress::kEmpty, AVDT_WRITE_CFM_EVT,
+          &avdt_ctrl, p_scb->stream_config.scb_index);
     }
   }
 }
@@ -1459,7 +1493,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_transport_channel_timer(tAVDT_SCB* p_scb,
+void avdt_scb_transport_channel_timer(AvdtpScb* p_scb,
                                       UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   alarm_set_on_mloop(p_scb->transport_channel_timer,
                      AVDT_SCB_TC_DISC_TIMEOUT_MS,
@@ -1475,8 +1509,7 @@
  * Returns          Nothing.
  *
  ******************************************************************************/
-void avdt_scb_clr_vars(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+void avdt_scb_clr_vars(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
   p_scb->in_use = false;
-  p_scb->p_ccb = NULL;
   p_scb->peer_seid = 0;
 }
diff --git a/stack/avrc/avrc_api.cc b/stack/avrc/avrc_api.cc
index bdf78b7..69534e9 100644
--- a/stack/avrc/avrc_api.cc
+++ b/stack/avrc/avrc_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -84,13 +84,13 @@
                             const RawAddress* peer_addr) {
   uint8_t avrc_event;
 
-  if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback) {
+  if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].ctrl_cback) {
     avrc_event = avrc_ctrl_event_map[event];
     if (event == AVCT_CONNECT_CFM_EVT) {
       if (result != 0) /* failed */
         avrc_event = AVRC_CLOSE_IND_EVT;
     }
-    (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
+    avrc_cb.ccb[handle].ctrl_cback.Run(handle, avrc_event, result, peer_addr);
   }
 
   if ((event == AVCT_DISCONNECT_CFM_EVT) ||
@@ -135,8 +135,8 @@
                    param->handle, param->label);
 
   /* Notify app */
-  if (avrc_cb.ccb[param->handle].p_ctrl_cback) {
-    (*avrc_cb.ccb[param->handle].p_ctrl_cback)(
+  if (avrc_cb.ccb[param->handle].ctrl_cback) {
+    avrc_cb.ccb[param->handle].ctrl_cback.Run(
         param->handle, AVRC_CMD_TIMEOUT_EVT, param->label, NULL);
   }
 
@@ -246,7 +246,6 @@
   return p_pkt_copy;
 }
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
 /******************************************************************************
  *
  * Function         avrc_prep_end_frag
@@ -266,10 +265,9 @@
   p_fcb = &avrc_cb.fcb[handle];
 
   /* The response type of the end fragment should be the same as the the PDU of
-  *"End Fragment
-  ** Response" Errata:
-  *https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
-  */
+   * "End Fragment Response" Errata:
+   * https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
+   */
   p_orig_data = ((uint8_t*)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
   rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
 
@@ -498,16 +496,16 @@
       p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
 
       /*
-          * Free original START packet, replace with pointer to
-          * reassembly buffer.
-          */
+       * Free original START packet, replace with pointer to
+       * reassembly buffer.
+       */
       osi_free(p_pkt);
       *pp_pkt = p_rcb->p_rmsg;
 
       /*
-          * Set offset to point to where to copy next - use the same
-          * reassembly logic as AVCT.
-          */
+       * Set offset to point to where to copy next - use the same
+       * reassembly logic as AVCT.
+       */
       p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
       req_continue = true;
     } else if (p_rcb->p_rmsg == NULL) {
@@ -522,9 +520,9 @@
     } else {
       /* get size of buffer holding assembled message */
       /*
-          * NOTE: The buffer is allocated above at the beginning of the
-          * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
-          */
+       * NOTE: The buffer is allocated above at the beginning of the
+       * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+       */
       uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
       /* adjust offset and len of fragment for header byte */
       p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
@@ -582,10 +580,10 @@
       drop_code = 4;
 
   } else if (cr == AVCT_RSP) {
-    if (req_continue == true) {
+    if (req_continue) {
       avrc_cmd.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
       drop_code = 2;
-    } else if (buf_overflow == true) {
+    } else if (buf_overflow) {
       /* Incoming message too big to fit in BT_DEFAULT_BUFFER_SIZE. Send abort
        * to peer  */
       avrc_cmd.pdu = AVRC_PDU_ABORT_CONTINUATION_RSP;
@@ -606,7 +604,6 @@
 
   return drop_code;
 }
-#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
 
 /******************************************************************************
  *
@@ -756,7 +753,6 @@
         p_msg->p_vendor_data = p_data;
         p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
         uint8_t drop_code = 0;
         if (p_msg->company_id == AVRC_CO_METADATA) {
           /* Validate length for metadata message */
@@ -791,7 +787,6 @@
               p_drop_msg = "sent_fragd";
           }
         }
-#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
         /* If vendor response received, and did not ask for continuation */
         /* then check queue for addition commands to send */
         if ((cr == AVCT_RSP) && (drop_code != 2)) {
@@ -863,9 +858,9 @@
     drop = true;
   }
 
-  if (drop == false) {
+  if (!drop) {
     msg.hdr.opcode = opcode;
-    (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+    avrc_cb.ccb[handle].msg_cback.Run(handle, label, opcode, &msg);
   } else {
     AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
                        __func__, p_drop_msg, handle,
@@ -879,62 +874,6 @@
   if (do_free) osi_free(p_pkt);
 }
 
-static void AVRC_build_empty_packet(BT_HDR* p_pkt) {
-  uint8_t* p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
-  *p_start = AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK;
-  p_start += AVRC_VENDOR_HDR_SIZE;
-  UINT8_TO_BE_STREAM(p_start, 0);
-  UINT8_TO_BE_STREAM(p_start, AVRC_PKT_SINGLE);
-  UINT16_TO_BE_STREAM(p_start, 0);
-  p_pkt->len = AVRC_VENDOR_HDR_SIZE + 4;
-}
-
-static void AVRC_build_error_packet(BT_HDR* p_pkt) {
-  uint8_t* p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
-  *p_start = AVRC_RSP_REJ & AVRC_CTYPE_MASK;
-  p_start += AVRC_VENDOR_HDR_SIZE;
-  UINT8_TO_BE_STREAM(p_start, 0);
-  UINT8_TO_BE_STREAM(p_start, AVRC_PKT_SINGLE);
-  UINT16_TO_BE_STREAM(p_start, 1);
-  UINT8_TO_BE_STREAM(p_start, AVRC_STS_BAD_PARAM);
-  p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
-}
-
-static uint16_t AVRC_HandleContinueRsp(uint8_t handle, uint8_t label,
-                                       BT_HDR* p_pkt) {
-  AVRC_TRACE_DEBUG("%s()", __func__);
-
-  uint8_t* p_data =
-      ((uint8_t*)(p_pkt + 1) + p_pkt->offset + AVRC_VENDOR_HDR_SIZE);
-  tAVRC_FRAG_CB* p_fcb = &avrc_cb.fcb[handle];
-
-  uint8_t pdu, pkt_type, target_pdu;
-  uint16_t len;
-
-  BE_STREAM_TO_UINT8(pdu, p_data);
-  BE_STREAM_TO_UINT8(pkt_type, p_data);
-  BE_STREAM_TO_UINT16(len, p_data);
-  BE_STREAM_TO_UINT8(target_pdu, p_data);
-
-  if (pdu == AVRC_PDU_REQUEST_CONTINUATION_RSP &&
-      target_pdu == p_fcb->frag_pdu) {
-    return avrc_send_continue_frag(handle, label);
-  }
-
-  if (pdu == AVRC_PDU_ABORT_CONTINUATION_RSP && target_pdu == p_fcb->frag_pdu) {
-    AVRC_build_empty_packet(p_pkt);
-  } else {
-    AVRC_TRACE_ERROR("%s() error: target_pdu: 0x%02x, frag_pdu: 0x%02x",
-                     __func__, *(p_data + 4), p_fcb->frag_pdu);
-    AVRC_build_error_packet(p_pkt);
-  }
-
-  p_fcb->frag_enabled = false;
-  osi_free_and_reset((void**)&p_fcb->p_fmsg);
-
-  return AVCT_MsgReq(handle, label, AVCT_RSP, p_pkt);
-}
-
 /******************************************************************************
  *
  * Function         avrc_pass_msg
@@ -1043,12 +982,10 @@
 
   status = AVCT_CreateConn(p_handle, &cc, peer_addr);
   if (status == AVCT_SUCCESS) {
-    memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
+    avrc_cb.ccb[*p_handle] = *p_ccb;
     memset(&avrc_cb.ccb_int[*p_handle], 0, sizeof(tAVRC_CONN_INT_CB));
-#if (AVRC_METADATA_INCLUDED == TRUE)
     memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
     memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
-#endif
     avrc_cb.ccb_int[*p_handle].tle = alarm_new("avrcp.commandTimer");
     avrc_cb.ccb_int[*p_handle].cmd_q = fixed_queue_new(SIZE_MAX);
   }
@@ -1078,6 +1015,7 @@
  *****************************************************************************/
 uint16_t AVRC_Close(uint8_t handle) {
   AVRC_TRACE_DEBUG("%s handle:%d", __func__, handle);
+  avrc_flush_cmd_q(handle);
   return AVCT_RemoveConn(handle);
 }
 
@@ -1134,7 +1072,6 @@
  *****************************************************************************/
 uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
                      BT_HDR* p_pkt) {
-#if (AVRC_METADATA_INCLUDED == TRUE)
   uint8_t* p_data;
   uint8_t cr = AVCT_CMD;
   bool chk_frag = true;
@@ -1152,12 +1089,6 @@
 
   if (ctype >= AVRC_RSP_NOT_IMPL) cr = AVCT_RSP;
 
-  p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
-  if (*p_data == AVRC_PDU_REQUEST_CONTINUATION_RSP ||
-      *p_data == AVRC_PDU_ABORT_CONTINUATION_RSP) {
-    return AVRC_HandleContinueRsp(handle, label, p_pkt);
-  }
-
   if (p_pkt->event == AVRC_OP_VENDOR) {
     /* add AVRCP Vendor Dependent headers */
     p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
@@ -1218,7 +1149,7 @@
   /* AVRCP spec has not defined any control channel commands that needs
    * fragmentation at this level
    * check for fragmentation only on the response */
-  if ((cr == AVCT_RSP) && (chk_frag == true)) {
+  if ((cr == AVCT_RSP) && (chk_frag)) {
     if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
       int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
       BT_HDR* p_pkt_new =
@@ -1290,9 +1221,6 @@
   }
 
   return status;
-#else
-  return AVRC_NO_RESOURCES;
-#endif
 }
 
 /******************************************************************************
diff --git a/stack/avrc/avrc_bld_ct.cc b/stack/avrc/avrc_bld_ct.cc
index 2cb1246..afb1784b 100644
--- a/stack/avrc/avrc_bld_ct.cc
+++ b/stack/avrc/avrc_bld_ct.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2013 Broadcom Corporation
+ *  Copyright 2006-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
  *  Global data
  ****************************************************************************/
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
 /*******************************************************************************
  *
  * Function         avrc_bld_next_cmd
@@ -661,4 +660,3 @@
   AVRC_TRACE_API("AVRC_BldCommand: returning %d", status);
   return status;
 }
-#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/stack/avrc/avrc_bld_tg.cc b/stack/avrc/avrc_bld_tg.cc
index f96a5d3..b28c9e2 100644
--- a/stack/avrc/avrc_bld_tg.cc
+++ b/stack/avrc/avrc_bld_tg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@
 /*****************************************************************************
  *  Global data
  ****************************************************************************/
-#if (AVRC_METADATA_INCLUDED == TRUE)
 #define AVRC_ITEM_PLAYER_IS_VALID(_p_player)                 \
   ((_p_player)->name.p_str &&                                \
    ((_p_player)->major_type & AVRC_MJ_TYPE_INVALID) == 0 &&  \
@@ -955,7 +954,7 @@
   /* min len required = item_type(1) + item len(2) + min item (14) = 17 */
   for (xx = 0;
        xx < p_rsp->item_count && len_left > AVRC_MIN_LEN_GET_FOLDER_ITEMS_RSP &&
-       multi_items_add_fail == false;
+       !multi_items_add_fail;
        xx++) {
     p_item_start = p_data;
     UINT8_TO_BE_STREAM(p_data, p_item_list[xx].item_type);
@@ -970,8 +969,7 @@
         p_player = &p_item_list[xx].u.player;
         item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12;
 
-        if ((len_left <= item_len) ||
-            AVRC_ITEM_PLAYER_IS_VALID(p_player) == false) {
+        if ((len_left <= item_len) || !AVRC_ITEM_PLAYER_IS_VALID(p_player)) {
           p_data = p_item_start;
         } else {
           UINT16_TO_BE_STREAM(p_data, p_player->player_id);
@@ -1058,7 +1056,7 @@
       /* fill in variable item lenth */
       UINT16_TO_BE_STREAM(p_item_len, item_len);
     } else {
-      if (multi_items_add_fail == false) {
+      if (!multi_items_add_fail) {
         /* some item is not added properly - set an error status */
         if (len_left < item_len)
           status = AVRC_STS_INTERNAL_ERR;
@@ -1066,7 +1064,7 @@
           status = AVRC_STS_BAD_PARAM;
       }
     }
-    if (multi_items_add_fail == false) {
+    if (!multi_items_add_fail) {
       len += item_len;
       len += 3; /* the item_type(1) and item_len(2) */
     }
@@ -1519,5 +1517,3 @@
   AVRC_TRACE_API("%s returning %d", __func__, status);
   return status;
 }
-
-#endif /* (AVRC_METADATA_INCLUDED == true)*/
diff --git a/stack/avrc/avrc_int.h b/stack/avrc/avrc_int.h
index d6c79c8..779a90a 100644
--- a/stack/avrc/avrc_int.h
+++ b/stack/avrc/avrc_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -118,7 +118,6 @@
  *  Type definitions
  ****************************************************************************/
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
 /* type for Metadata fragmentation control block */
 typedef struct {
   BT_HDR* p_fmsg;    /* the fragmented message */
@@ -132,7 +131,6 @@
   uint16_t rasm_offset; /* re-assembly flag, the offset of the start fragment */
   uint8_t rasm_pdu;     /* the PDU ID for re-assembly */
 } tAVRC_RASM_CB;
-#endif
 
 /* AVRC internal connection control block */
 typedef struct {
@@ -147,11 +145,9 @@
       ccb[AVCT_NUM_CONN]; /* Connection control block from AVRC_Open API */
   tAVRC_CONN_INT_CB
       ccb_int[AVCT_NUM_CONN]; /* Internal connection control block  */
-#if (AVRC_METADATA_INCLUDED == TRUE)
   tAVRC_FRAG_CB fcb[AVCT_NUM_CONN];
   tAVRC_RASM_CB rcb[AVCT_NUM_CONN];
-#endif
-  tAVRC_FIND_CBACK* p_cback; /* pointer to application callback */
+  tAVRC_FIND_CBACK find_cback; /* sdp discovery callback */
   tSDP_DISCOVERY_DB* p_db;   /* pointer to discovery database */
   uint16_t service_uuid;     /* service UUID to search */
   uint8_t trace_level;
diff --git a/stack/avrc/avrc_opt.cc b/stack/avrc/avrc_opt.cc
index 1c0acb8..de42e15 100644
--- a/stack/avrc/avrc_opt.cc
+++ b/stack/avrc/avrc_opt.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -50,13 +50,8 @@
 
   CHECK(p_msg != NULL);
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
   CHECK(AVRC_META_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->vendor_len));
   p_cmd = (BT_HDR*)osi_malloc(AVRC_META_CMD_BUF_SIZE);
-#else
-  CHECK(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->vendor_len));
-  p_cmd = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
-#endif
 
   p_cmd->offset = AVCT_MSG_OFFSET;
   p_data = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index fbfeeaf..4421c91 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2013 Broadcom Corporation
+ *  Copyright 2006-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -29,8 +29,6 @@
  *  Global data
  ****************************************************************************/
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
-
 /*******************************************************************************
  *
  * Function         avrc_pars_vendor_rsp
@@ -707,4 +705,3 @@
   }
   return status;
 }
-#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/stack/avrc/avrc_pars_tg.cc b/stack/avrc/avrc_pars_tg.cc
index 12b7598..c0504ee 100644
--- a/stack/avrc/avrc_pars_tg.cc
+++ b/stack/avrc/avrc_pars_tg.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
 /*****************************************************************************
  *  Global data
  ****************************************************************************/
-#if (AVRC_METADATA_INCLUDED == TRUE)
 
 /*******************************************************************************
  *
@@ -560,5 +559,3 @@
   AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
   return status;
 }
-
-#endif /* (AVRC_METADATA_INCLUDED == true) */
diff --git a/stack/avrc/avrc_sdp.cc b/stack/avrc/avrc_sdp.cc
index 3a7ed96..860a8d0 100644
--- a/stack/avrc/avrc_sdp.cc
+++ b/stack/avrc/avrc_sdp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,6 +27,8 @@
 #include "avrc_int.h"
 #include "bt_common.h"
 
+using bluetooth::Uuid;
+
 /*****************************************************************************
  *  Global data
  ****************************************************************************/
@@ -59,7 +61,7 @@
   avrc_cb.service_uuid = 0;
 
   /* return info from sdp record in app callback function */
-  (*avrc_cb.p_cback)(status);
+  avrc_cb.find_cback.Run(status);
 
   return;
 }
@@ -105,14 +107,13 @@
  *****************************************************************************/
 uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr,
                           tAVRC_SDP_DB_PARAMS* p_db,
-                          tAVRC_FIND_CBACK* p_cback) {
-  tSDP_UUID uuid_list;
+                          const tAVRC_FIND_CBACK& find_cback) {
   bool result = true;
 
   AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
   if ((service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET &&
        service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
-      p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+      p_db == NULL || p_db->p_db == NULL || find_cback.is_null())
     return AVRC_BAD_PARAM;
 
   /* check if it is busy */
@@ -120,23 +121,21 @@
       avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
     return AVRC_NO_RESOURCES;
 
-  /* set up discovery database */
-  uuid_list.len = LEN_UUID_16;
-  uuid_list.uu.uuid16 = service_uuid;
 
   if (p_db->p_attrs == NULL || p_db->num_attr == 0) {
     p_db->p_attrs = a2dp_attr_list_sdp;
     p_db->num_attr = AVRC_NUM_ATTR;
   }
 
+  Uuid uuid_list = Uuid::From16Bit(service_uuid);
   result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list,
                                p_db->num_attr, p_db->p_attrs);
 
-  if (result == true) {
+  if (result) {
     /* store service_uuid and discovery db pointer */
     avrc_cb.p_db = p_db->p_db;
     avrc_cb.service_uuid = service_uuid;
-    avrc_cb.p_cback = p_cback;
+    avrc_cb.find_cback = find_cback;
 
     /* perform service search */
     result =
@@ -210,7 +209,17 @@
   }
   result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
 
-  /* add protocol descriptor list   */
+  uint16_t protocol_reported_version;
+  /* AVRCP versions 1.3 to 1.5 report (version - 1) in the protocol
+     descriptor list. Oh, and 1.6 and 1.6.1 report version 1.4.
+     /because-we-smart */
+  if (profile_version < AVRC_REV_1_6) {
+    protocol_reported_version = profile_version - 1;
+  } else {
+    protocol_reported_version = AVCT_REV_1_4;
+  }
+
+  /* add protocol descriptor list */
   tSDP_PROTOCOL_ELEM avrc_proto_desc_list[AVRC_NUM_PROTO_ELEMS];
   avrc_proto_desc_list[0].num_params = 1;
   avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
@@ -219,13 +228,13 @@
   for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++) {
     avrc_proto_desc_list[index].num_params = 1;
     avrc_proto_desc_list[index].protocol_uuid = UUID_PROTOCOL_AVCTP;
-    avrc_proto_desc_list[index].params[0] = AVCT_REV_1_4;
+    avrc_proto_desc_list[index].params[0] = protocol_reported_version;
     avrc_proto_desc_list[index].params[1] = 0;
   }
   result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS,
-                                (tSDP_PROTOCOL_ELEM*)avrc_proto_desc_list);
+                                &avrc_proto_desc_list[0]);
 
-  /* additional protocal descriptor, required only for version > 1.3    */
+  /* additional protocal descriptor, required only for version > 1.3 */
   if ((profile_version > AVRC_REV_1_3) && (browse_supported)) {
     tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list;
     avrc_add_proto_desc_list.num_elems = 2;
@@ -235,11 +244,11 @@
     avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
     avrc_add_proto_desc_list.list_elem[1].num_params = 1;
     avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
-    avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
+    avrc_add_proto_desc_list.list_elem[1].params[0] = protocol_reported_version;
     avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
 
-    result &= SDP_AddAdditionProtoLists(
-        sdp_handle, 1, (tSDP_PROTO_LIST_ELEM*)&avrc_add_proto_desc_list);
+    result &=
+        SDP_AddAdditionProtoLists(sdp_handle, 1, &avrc_add_proto_desc_list);
   }
   /* add profile descriptor list   */
   result &= SDP_AddProfileDescriptorList(
diff --git a/stack/avrc/avrc_utils.cc b/stack/avrc/avrc_utils.cc
index 6504ac4..927f62b 100644
--- a/stack/avrc/avrc_utils.cc
+++ b/stack/avrc/avrc_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2016 Broadcom Corporation
+ *  Copyright 2003-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,8 +21,6 @@
 #include "avrc_int.h"
 #include "bt_common.h"
 
-#if (AVRC_METADATA_INCLUDED == TRUE)
-
 /**************************************************************************
  *
  * Function         AVRC_IsValidAvcType
@@ -230,5 +228,3 @@
   }
   return is_valid;
 }
-
-#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/stack/bnep/bnep_api.cc b/stack/bnep/bnep_api.cc
index e5d3c09..0e7b692 100644
--- a/stack/bnep/bnep_api.cc
+++ b/stack/bnep/bnep_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,10 +23,11 @@
  ******************************************************************************/
 
 #include "bnep_api.h"
-#include <log/log.h>
 #include <string.h>
 #include "bnep_int.h"
 
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *
  * Function         BNEP_Init
@@ -124,8 +125,8 @@
  *                  BNEP_NO_RESOURCES           if no resources
  *
  ******************************************************************************/
-tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda, tBT_UUID* src_uuid,
-                          tBT_UUID* dst_uuid, uint16_t* p_handle) {
+tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda, const Uuid& src_uuid,
+                          const Uuid& dst_uuid, uint16_t* p_handle) {
   uint16_t cid;
   tBNEP_CONN* p_bcb = bnepu_find_bcb_by_bd_addr(p_rem_bda);
 
@@ -133,9 +134,6 @@
 
   if (!bnep_cb.profile_registered) return BNEP_WRONG_STATE;
 
-  /* Both source and destination UUID lengths should be same */
-  if (src_uuid->len != dst_uuid->len) return BNEP_CONN_FAILED_UUID_SIZE;
-
   if (!p_bcb) {
     p_bcb = bnepu_allocate_bcb(p_rem_bda);
     if (p_bcb == NULL) return (BNEP_NO_RESOURCES);
@@ -143,29 +141,27 @@
     return BNEP_WRONG_STATE;
   else {
     /* Backup current UUID values to restore if role change fails */
-    memcpy((uint8_t*)&(p_bcb->prv_src_uuid), (uint8_t*)&(p_bcb->src_uuid),
-           sizeof(tBT_UUID));
-    memcpy((uint8_t*)&(p_bcb->prv_dst_uuid), (uint8_t*)&(p_bcb->dst_uuid),
-           sizeof(tBT_UUID));
+    p_bcb->prv_src_uuid = p_bcb->src_uuid;
+    p_bcb->prv_dst_uuid = p_bcb->dst_uuid;
   }
 
   /* We are the originator of this connection */
   p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG;
 
-  memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)src_uuid, sizeof(tBT_UUID));
-  memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)dst_uuid, sizeof(tBT_UUID));
+  p_bcb->src_uuid = src_uuid;
+  p_bcb->dst_uuid = dst_uuid;
 
   if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
     /* Transition to the next appropriate state, waiting for connection confirm.
      */
     p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
 
-    BNEP_TRACE_API("BNEP initiating security procedures for src uuid 0x%x",
-                   p_bcb->src_uuid.uu.uuid16);
+    BNEP_TRACE_API("BNEP initiating security procedures for src uuid %s",
+                   p_bcb->src_uuid.ToString().c_str());
 
 #if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE)
     btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
-                              BTM_SEC_PROTO_BNEP, bnep_get_uuid32(src_uuid),
+                              BTM_SEC_PROTO_BNEP, src_uuid.As32Bit(),
                               &bnep_sec_check_complete, p_bcb);
 #else
     bnep_sec_check_complete(p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
@@ -250,10 +246,8 @@
     p_bcb->con_state = BNEP_STATE_CONNECTED;
     p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
 
-    memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
-           sizeof(tBT_UUID));
-    memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
-           sizeof(tBT_UUID));
+    p_bcb->src_uuid = p_bcb->prv_src_uuid;
+    p_bcb->dst_uuid = p_bcb->prv_dst_uuid;
   }
 
   /* Process remaining part of the setup message (extension headers) */
@@ -384,10 +378,7 @@
         protocol = 0;
       else {
         new_len += 4;
-        if (new_len > org_len) {
-          android_errorWriteLog(0x534e4554, "74947856");
-          return BNEP_IGNORE_CMD;
-        }
+        if (new_len > org_len) return BNEP_IGNORE_CMD;
         p_data[2] = 0;
         p_data[3] = 0;
       }
@@ -484,10 +475,7 @@
         protocol = 0;
       else {
         new_len += 4;
-        if (new_len > org_len) {
-          android_errorWriteLog(0x534e4554, "74947856");
-          return BNEP_IGNORE_CMD;
-        }
+        if (new_len > org_len) return BNEP_IGNORE_CMD;
         p_data[2] = 0;
         p_data[3] = 0;
       }
@@ -689,8 +677,8 @@
   p_status->rcvd_mcast_filters = p_bcb->rcvd_mcast_filters;
 
   p_status->rem_bda = p_bcb->rem_bda;
-  memcpy(&(p_status->src_uuid), &(p_bcb->src_uuid), sizeof(tBT_UUID));
-  memcpy(&(p_status->dst_uuid), &(p_bcb->dst_uuid), sizeof(tBT_UUID));
+  p_status->src_uuid = p_bcb->src_uuid;
+  p_status->dst_uuid = p_bcb->dst_uuid;
 
   return BNEP_SUCCESS;
 #else
diff --git a/stack/bnep/bnep_int.h b/stack/bnep/bnep_int.h
index e25e7f8..2587147 100644
--- a/stack/bnep/bnep_int.h
+++ b/stack/bnep/bnep_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -149,10 +149,10 @@
   uint16_t bad_pkts_rcvd;
   uint8_t re_transmits;
   uint16_t handle;
-  tBT_UUID prv_src_uuid;
-  tBT_UUID prv_dst_uuid;
-  tBT_UUID src_uuid;
-  tBT_UUID dst_uuid;
+  bluetooth::Uuid prv_src_uuid;
+  bluetooth::Uuid prv_dst_uuid;
+  bluetooth::Uuid src_uuid;
+  bluetooth::Uuid dst_uuid;
 
 } tBNEP_CONN;
 
@@ -231,6 +231,5 @@
                                            uint16_t protocol,
                                            bool fw_ext_present,
                                            uint8_t* p_data);
-extern uint32_t bnep_get_uuid32(tBT_UUID* src_uuid);
 
 #endif
diff --git a/stack/bnep/bnep_main.cc b/stack/bnep/bnep_main.cc
index 8772e57..ae6c51b 100644
--- a/stack/bnep/bnep_main.cc
+++ b/stack/bnep/bnep_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -255,9 +255,9 @@
                        bnep_conn_timer_timeout, p_bcb);
 
     if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
-      btm_sec_mx_access_request(
-          p_bcb->rem_bda, BT_PSM_BNEP, true, BTM_SEC_PROTO_BNEP,
-          bnep_get_uuid32(&(p_bcb->src_uuid)), &bnep_sec_check_complete, p_bcb);
+      btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
+                                BTM_SEC_PROTO_BNEP, p_bcb->src_uuid.As32Bit(),
+                                &bnep_sec_check_complete, p_bcb);
     }
   }
 }
@@ -299,8 +299,7 @@
 
       if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
         btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
-                                  BTM_SEC_PROTO_BNEP,
-                                  bnep_get_uuid32(&(p_bcb->src_uuid)),
+                                  BTM_SEC_PROTO_BNEP, p_bcb->src_uuid.As32Bit(),
                                   &bnep_sec_check_complete, p_bcb);
       }
     }
@@ -623,7 +622,6 @@
   if (bnep_cb.p_data_buf_cb) {
     (*bnep_cb.p_data_buf_cb)(p_bcb->handle, *p_src_addr, *p_dst_addr, protocol,
                              p_buf, fw_ext_present);
-    osi_free(p_buf);
   } else if (bnep_cb.p_data_ind_cb) {
     (*bnep_cb.p_data_ind_cb)(p_bcb->handle, *p_src_addr, *p_dst_addr, protocol,
                              p, rem_len, fw_ext_present);
diff --git a/stack/bnep/bnep_utils.cc b/stack/bnep/bnep_utils.cc
index 3bab9ee..48fd5d1 100644
--- a/stack/bnep/bnep_utils.cc
+++ b/stack/bnep/bnep_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,6 +35,8 @@
 #include "device/include/controller.h"
 #include "osi/include/osi.h"
 
+using bluetooth::Uuid;
+
 /******************************************************************************/
 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
 /******************************************************************************/
@@ -166,8 +168,8 @@
   BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
   uint8_t *p, *p_start;
 
-  BNEP_TRACE_DEBUG("%s: sending setup req with dst uuid %x", __func__,
-                   p_bcb->dst_uuid.uu.uuid16);
+  BNEP_TRACE_DEBUG("%s: sending setup req with dst uuid %s", __func__,
+                   p_bcb->dst_uuid.ToString().c_str());
 
   p_buf->offset = L2CAP_MIN_OFFSET;
   p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
@@ -178,22 +180,26 @@
   /* Put in filter message type - set filters */
   UINT8_TO_BE_STREAM(p, BNEP_SETUP_CONNECTION_REQUEST_MSG);
 
-  UINT8_TO_BE_STREAM(p, p_bcb->dst_uuid.len);
+  int len = std::max(p_bcb->dst_uuid.GetShortestRepresentationSize(),
+                     p_bcb->src_uuid.GetShortestRepresentationSize());
 
-  if (p_bcb->dst_uuid.len == 2) {
-    UINT16_TO_BE_STREAM(p, p_bcb->dst_uuid.uu.uuid16);
-    UINT16_TO_BE_STREAM(p, p_bcb->src_uuid.uu.uuid16);
-  } else if (p_bcb->dst_uuid.len == 4) {
-    UINT32_TO_BE_STREAM(p, p_bcb->dst_uuid.uu.uuid32);
-    UINT32_TO_BE_STREAM(p, p_bcb->src_uuid.uu.uuid32);
-  } else if (p_bcb->dst_uuid.len == 16) {
-    memcpy(p, p_bcb->dst_uuid.uu.uuid128, p_bcb->dst_uuid.len);
-    p += p_bcb->dst_uuid.len;
-    memcpy(p, p_bcb->src_uuid.uu.uuid128, p_bcb->dst_uuid.len);
-    p += p_bcb->dst_uuid.len;
+  UINT8_TO_BE_STREAM(p, len);
+
+  if (len == Uuid::kNumBytes16) {
+    UINT16_TO_BE_STREAM(p, p_bcb->dst_uuid.As16Bit());
+    UINT16_TO_BE_STREAM(p, p_bcb->src_uuid.As16Bit());
+  } else if (len == Uuid::kNumBytes32) {
+    UINT32_TO_BE_STREAM(p, p_bcb->dst_uuid.As32Bit());
+    UINT32_TO_BE_STREAM(p, p_bcb->src_uuid.As32Bit());
+  } else if (len == Uuid::kNumBytes128) {
+    memcpy(p, p_bcb->dst_uuid.To128BitBE().data(), Uuid::kNumBytes128);
+    p += Uuid::kNumBytes128;
+    memcpy(p, p_bcb->src_uuid.To128BitBE().data(), Uuid::kNumBytes128);
+    p += Uuid::kNumBytes128;
   } else {
-    BNEP_TRACE_ERROR("%s: uuid: %x, invalid length: %x", __func__,
-                     p_bcb->dst_uuid.uu.uuid16, p_bcb->dst_uuid.len);
+    BNEP_TRACE_ERROR("%s: uuid: %s, invalid length: %zu", __func__,
+                     p_bcb->dst_uuid.ToString().c_str(),
+                     p_bcb->dst_uuid.GetShortestRepresentationSize());
   }
 
   p_buf->len = (uint16_t)(p - p_start);
@@ -525,8 +531,7 @@
  ******************************************************************************/
 void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup,
                                  uint8_t len) {
-  BNEP_TRACE_EVENT("BNEP - bnep_process_setup_conn_req for CID: 0x%x",
-                   p_bcb->l2cap_cid);
+  BNEP_TRACE_EVENT("BNEP - %s for CID: 0x%x", __func__, p_bcb->l2cap_cid);
 
   if (p_bcb->con_state != BNEP_STATE_CONN_SETUP &&
       p_bcb->con_state != BNEP_STATE_SEC_CHECKING &&
@@ -555,36 +560,43 @@
   }
 
   if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
-    memcpy((uint8_t*)&(p_bcb->prv_src_uuid), (uint8_t*)&(p_bcb->src_uuid),
-           sizeof(tBT_UUID));
-    memcpy((uint8_t*)&(p_bcb->prv_dst_uuid), (uint8_t*)&(p_bcb->dst_uuid),
-           sizeof(tBT_UUID));
+    p_bcb->prv_src_uuid = p_bcb->src_uuid;
+    p_bcb->prv_dst_uuid = p_bcb->dst_uuid;
   }
 
-  p_bcb->dst_uuid.len = p_bcb->src_uuid.len = len;
-
-  if (p_bcb->dst_uuid.len == 2) {
+  if (len == Uuid::kNumBytes16) {
     /* because peer initiated connection keep src uuid as dst uuid */
-    BE_STREAM_TO_UINT16(p_bcb->src_uuid.uu.uuid16, p_setup);
-    BE_STREAM_TO_UINT16(p_bcb->dst_uuid.uu.uuid16, p_setup);
+    uint16_t tmp;
+
+    BE_STREAM_TO_UINT16(tmp, p_setup);
+    p_bcb->src_uuid = Uuid::From16Bit(tmp);
+
+    BE_STREAM_TO_UINT16(tmp, p_setup);
+    p_bcb->dst_uuid = Uuid::From16Bit(tmp);
 
     /* If nothing has changed don't bother the profile */
     if (p_bcb->con_state == BNEP_STATE_CONNECTED &&
-        p_bcb->src_uuid.uu.uuid16 == p_bcb->prv_src_uuid.uu.uuid16 &&
-        p_bcb->dst_uuid.uu.uuid16 == p_bcb->prv_dst_uuid.uu.uuid16) {
+        p_bcb->src_uuid == p_bcb->prv_src_uuid &&
+        p_bcb->dst_uuid == p_bcb->prv_dst_uuid) {
       bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_OK);
       return;
     }
-  } else if (p_bcb->dst_uuid.len == 4) {
-    BE_STREAM_TO_UINT32(p_bcb->src_uuid.uu.uuid32, p_setup);
-    BE_STREAM_TO_UINT32(p_bcb->dst_uuid.uu.uuid32, p_setup);
-  } else if (p_bcb->dst_uuid.len == 16) {
-    memcpy(p_bcb->src_uuid.uu.uuid128, p_setup, p_bcb->src_uuid.len);
-    p_setup += p_bcb->src_uuid.len;
-    memcpy(p_bcb->dst_uuid.uu.uuid128, p_setup, p_bcb->dst_uuid.len);
-    p_setup += p_bcb->dst_uuid.len;
+  } else if (len == Uuid::kNumBytes32) {
+    uint32_t tmp;
+
+    BE_STREAM_TO_UINT32(tmp, p_setup);
+    p_bcb->src_uuid = Uuid::From32Bit(tmp);
+
+    BE_STREAM_TO_UINT32(tmp, p_setup);
+    p_bcb->dst_uuid = Uuid::From32Bit(tmp);
+  } else if (len == Uuid::kNumBytes128) {
+    p_bcb->src_uuid = Uuid::From128BitBE(p_setup);
+    p_setup += len;
+
+    p_bcb->dst_uuid = Uuid::From128BitBE(p_setup);
+    p_setup += len;
   } else {
-    BNEP_TRACE_ERROR("BNEP - Bad UID len %d in ConnReq", p_bcb->dst_uuid.len);
+    BNEP_TRACE_ERROR("BNEP - Bad UID len %d in ConnReq", len);
     bnep_send_conn_responce(p_bcb, BNEP_SETUP_INVALID_UUID_SIZE);
     return;
   }
@@ -593,16 +605,16 @@
   p_bcb->con_flags |= BNEP_FLAGS_SETUP_RCVD;
 
   BNEP_TRACE_EVENT(
-      "BNEP initiating security check for incoming call for uuid 0x%x",
-      p_bcb->src_uuid.uu.uuid16);
+      "BNEP initiating security check for incoming call for uuid %s",
+      p_bcb->src_uuid.ToString().c_str());
 #if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == FALSE)
   if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
     bnep_sec_check_complete(p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
   else
 #endif
-    btm_sec_mx_access_request(
-        p_bcb->rem_bda, BT_PSM_BNEP, false, BTM_SEC_PROTO_BNEP,
-        bnep_get_uuid32(&(p_bcb->src_uuid)), &bnep_sec_check_complete, p_bcb);
+    btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, false,
+                              BTM_SEC_PROTO_BNEP, p_bcb->src_uuid.As32Bit(),
+                              &bnep_sec_check_complete, p_bcb);
 
   return;
 }
@@ -666,10 +678,8 @@
       /* Restore the earlier BNEP status */
       p_bcb->con_state = BNEP_STATE_CONNECTED;
       p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
-      memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
-             sizeof(tBT_UUID));
-      memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
-             sizeof(tBT_UUID));
+      p_bcb->src_uuid = p_bcb->prv_src_uuid;
+      p_bcb->dst_uuid = p_bcb->prv_dst_uuid;
 
       /* Ensure timer is stopped */
       alarm_cancel(p_bcb->conn_timer);
@@ -1177,10 +1187,8 @@
                                      BNEP_SECURITY_FAIL, is_role_change);
 
         p_bcb->con_state = BNEP_STATE_CONNECTED;
-        memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
-               sizeof(tBT_UUID));
-        memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
-               sizeof(tBT_UUID));
+        p_bcb->src_uuid = p_bcb->prv_src_uuid;
+        p_bcb->dst_uuid = p_bcb->prv_dst_uuid;
         return;
       }
 
@@ -1213,10 +1221,8 @@
        * state */
       p_bcb->con_state = BNEP_STATE_CONNECTED;
       p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
-      memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
-             sizeof(tBT_UUID));
-      memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
-             sizeof(tBT_UUID));
+      p_bcb->src_uuid = p_bcb->prv_src_uuid;
+      p_bcb->dst_uuid = p_bcb->prv_dst_uuid;
       return;
     }
 
@@ -1228,8 +1234,8 @@
 
   if (bnep_cb.p_conn_ind_cb) {
     p_bcb->con_state = BNEP_STATE_CONN_SETUP;
-    (*bnep_cb.p_conn_ind_cb)(p_bcb->handle, p_bcb->rem_bda, &p_bcb->dst_uuid,
-                             &p_bcb->src_uuid, is_role_change);
+    (*bnep_cb.p_conn_ind_cb)(p_bcb->handle, p_bcb->rem_bda, p_bcb->dst_uuid,
+                             p_bcb->src_uuid, is_role_change);
   } else {
     /* Profile didn't register connection indication call back */
     bnep_send_conn_responce(p_bcb, resp_code);
@@ -1317,26 +1323,3 @@
 
   return BNEP_SUCCESS;
 }
-
-/*******************************************************************************
- *
- * Function         bnep_get_uuid32
- *
- * Description      This function returns the 32-bit equivalent of the UUID
- *
- * Returns          uint32_t - 32-bit equivalent of the UUID
- *
- ******************************************************************************/
-uint32_t bnep_get_uuid32(tBT_UUID* src_uuid) {
-  uint32_t result;
-
-  if (src_uuid->len == 2)
-    return ((uint32_t)src_uuid->uu.uuid16);
-  else if (src_uuid->len == 4)
-    return (src_uuid->uu.uuid32 & 0x0000FFFF);
-  else {
-    result = src_uuid->uu.uuid128[2];
-    result = (result << 8) | (src_uuid->uu.uuid128[3]);
-    return result;
-  }
-}
diff --git a/stack/btm/ble_advertiser_hci_interface.cc b/stack/btm/ble_advertiser_hci_interface.cc
index 377f1d4..93b517d 100644
--- a/stack/btm/ble_advertiser_hci_interface.cc
+++ b/stack/btm/ble_advertiser_hci_interface.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -318,7 +318,9 @@
   }
 
   void SetAdvertisingEventObserver(
-      AdvertisingEventObserver* observer) override {}
+      AdvertisingEventObserver* observer) override {
+    this->advertising_event_observer = observer;
+  }
 
   void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min,
                      uint32_t adv_int_max, uint8_t channel_map,
@@ -457,6 +459,19 @@
     // Legacy Advertising don't have remove method.
     command_complete.Run(0);
   }
+
+ public:
+  void OnAdvertisingSetTerminated(uint8_t status, uint16_t connection_handle) {
+    VLOG(1) << __func__;
+
+    AdvertisingEventObserver* observer = this->advertising_event_observer;
+    if (observer)
+      observer->OnAdvertisingSetTerminated(status, 0 /*advertising_handle*/,
+                                           connection_handle, 0);
+  }
+
+ private:
+  AdvertisingEventObserver* advertising_event_observer = nullptr;
 };
 
 class BleAdvertiserHciExtendedImpl : public BleAdvertiserHciInterface {
@@ -697,6 +712,15 @@
   }
 }
 
+bool legacy_advertising_in_use = false;
+void btm_ble_advertiser_notify_terminated_legacy(uint8_t status,
+                                                 uint16_t connection_handle) {
+  if (BleAdvertiserHciInterface::Get() && legacy_advertising_in_use) {
+    ((BleAdvertiserLegacyHciInterfaceImpl*)BleAdvertiserHciInterface::Get())
+        ->OnAdvertisingSetTerminated(status, connection_handle);
+  }
+}
+
 void BleAdvertiserHciInterface::Initialize() {
   VLOG(1) << __func__;
   LOG_ASSERT(instance == nullptr) << "Was already initialized.";
@@ -712,6 +736,7 @@
   } else {
     LOG(INFO) << "Legacy advertising will be in use";
     instance = new BleAdvertiserLegacyHciInterfaceImpl();
+    legacy_advertising_in_use = true;
   }
 }
 
diff --git a/stack/btm/ble_advertiser_hci_interface.h b/stack/btm/ble_advertiser_hci_interface.h
index 166c1f6..c08bb86 100644
--- a/stack/btm/ble_advertiser_hci_interface.h
+++ b/stack/btm/ble_advertiser_hci_interface.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index 8df6acb..ee2530a 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,6 +31,8 @@
  *
  *****************************************************************************/
 
+#define LOG_TAG "btm_acl"
+
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -48,6 +50,7 @@
 #include "hcidefs.h"
 #include "hcimsgs.h"
 #include "l2c_int.h"
+#include "osi/include/log.h"
 #include "osi/include/osi.h"
 
 static void btm_read_remote_features(uint16_t handle);
@@ -191,8 +194,9 @@
   tACL_CONN* p;
   uint8_t xx;
 
-  BTM_TRACE_DEBUG("btm_acl_created hci_handle=%d link_role=%d  transport=%d",
-                  hci_handle, link_role, transport);
+  BTM_TRACE_DEBUG("%s: peer %s hci_handle=%d link_role=%d  transport=%d",
+                  __func__, bda.ToString().c_str(), hci_handle, link_role,
+                  transport);
   /* Ensure we don't have duplicates */
   p = btm_bda_to_acl(bda, transport);
   if (p != (tACL_CONN*)NULL) {
@@ -240,7 +244,8 @@
       p_dev_rec = btm_find_dev_by_handle(hci_handle);
 
       if (p_dev_rec) {
-        BTM_TRACE_DEBUG("device_type=0x%x", p_dev_rec->device_type);
+        BTM_TRACE_DEBUG("%s: peer %s device_type=0x%x", __func__,
+                        bda.ToString().c_str(), p_dev_rec->device_type);
       }
 
       if (p_dev_rec && !(transport == BT_TRANSPORT_LE)) {
@@ -281,8 +286,6 @@
         } else {
           btm_establish_continue(p);
         }
-      } else {
-        btm_read_remote_features(p->hci_handle);
       }
 
       /* read page 1 - on rmt feature event for buffer reasons */
@@ -349,7 +352,7 @@
     if (p->link_up_issued) {
       p->link_up_issued = false;
 
-      /* If anyone cares, tell him database changed */
+      /* If anyone cares, indicate the database changed */
       if (btm_cb.p_bl_changed_cb) {
         tBTM_BL_EVENT_DATA evt_data;
         evt_data.event = BTM_BL_DISCN_EVT;
@@ -540,7 +543,10 @@
   tBTM_STATUS status;
   tBTM_PM_MODE pwr_mode;
   tBTM_PM_PWR_MD settings;
-  VLOG(1) << __func__ << " BDA: " << remote_bd_addr;
+
+  LOG_INFO(LOG_TAG, "%s: peer %s new_role=0x%x p_cb=%p p_switch_role_cb=%p",
+           __func__, remote_bd_addr.ToString().c_str(), new_role, p_cb,
+           btm_cb.devcb.p_switch_role_cb);
 
   /* Make sure the local device supports switching */
   if (!controller_get_interface()->supports_master_slave_role_switch())
@@ -565,7 +571,7 @@
   /* Check if there is any SCO Active on this BD Address */
   is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
 
-  if (is_sco_active == true) return (BTM_NO_RESOURCES);
+  if (is_sco_active) return (BTM_NO_RESOURCES);
 #endif
 
   /* Ignore role switch request if the previous request was not completed */
@@ -690,8 +696,8 @@
       (*btm_cb.p_bl_changed_cb)(&btm_bl_event_data);
 
       BTM_TRACE_DEBUG(
-          "Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
-          evt.new_role, evt.hci_status, p->switch_role_state);
+          "%s: Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+          __func__, evt.new_role, evt.hci_status, p->switch_role_state);
     }
 
 #if (BTM_DISC_DURING_RS == TRUE)
@@ -882,6 +888,10 @@
         STREAM_TO_UINT8(p_acl_cb->lmp_version, p);
         STREAM_TO_UINT16(p_acl_cb->manufacturer, p);
         STREAM_TO_UINT16(p_acl_cb->lmp_subversion, p);
+
+        if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) {
+          btm_read_remote_features(p_acl_cb->hci_handle);
+        }
       }
 
       if (p_acl_cb->transport == BT_TRANSPORT_LE) {
@@ -931,6 +941,16 @@
            HCI_FEATURE_BYTES_PER_PAGE);
   }
 
+  if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) ||
+      p_dev_rec->is_originator) {
+    BTM_TRACE_DEBUG("%s: Calling Next Security Procedure", __func__);
+    uint8_t status = btm_sec_execute_procedure(p_dev_rec);
+    if (status != BTM_CMD_STARTED) {
+      BTM_TRACE_ERROR("%s: Security procedure not started! status %d", __func__,
+                      status);
+      btm_sec_dev_rec_cback_event(p_dev_rec, status, false);
+    }
+  }
   const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
 
   /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
@@ -1175,6 +1195,10 @@
       BTM_SetLinkPolicy(p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
   }
 #endif
+  if (p_acl_cb->link_up_issued) {
+    BTM_TRACE_ERROR("%s: Already link is up ", __func__);
+    return;
+  }
   p_acl_cb->link_up_issued = true;
 
   /* If anyone cares, tell him database changed */
@@ -1435,7 +1459,9 @@
   tBTM_ROLE_SWITCH_CMPL* p_data = &btm_cb.devcb.switch_role_ref_data;
   tBTM_SEC_DEV_REC* p_dev_rec;
 
-  BTM_TRACE_DEBUG("btm_acl_role_changed");
+  BTM_TRACE_DEBUG("%s: peer %s hci_status:0x%x new_role:%d", __func__,
+                  (p_bda != nullptr) ? bd_addr->ToString().c_str() : "nullptr",
+                  hci_status, new_role);
   /* Ignore any stray events */
   if (p == NULL) {
     /* it could be a failure */
@@ -1498,7 +1524,9 @@
   }
 
   BTM_TRACE_DEBUG(
-      "Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+      "%s: peer %s Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, "
+      "rs_st:%d",
+      __func__, (p_bda != nullptr) ? p_bda->ToString().c_str() : "nullptr",
       p_data->role, p_data->hci_status, p->switch_role_state);
 
 #if (BTM_DISC_DURING_RS == TRUE)
@@ -1507,10 +1535,13 @@
   if (p_dev_rec != NULL) {
     if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
       BTM_TRACE_WARNING(
-          "btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!");
+          "%s peer %s Issuing delayed HCI_Disconnect!!!", __func__,
+          (p_bda != nullptr) ? p_bda->ToString().c_str() : "nullptr");
       btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
     }
-    BTM_TRACE_ERROR("tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+    BTM_TRACE_ERROR("%s: peer %s tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+                    __func__,
+                    (p_bda != nullptr) ? p_bda->ToString().c_str() : "nullptr",
                     PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
     p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
   }
@@ -1899,8 +1930,7 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_ReadRSSI(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) {
-  tACL_CONN* p;
-  tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+  tACL_CONN* p = NULL;
   tBT_DEVICE_TYPE dev_type;
   tBLE_ADDR_TYPE addr_type;
 
@@ -1908,10 +1938,16 @@
   if (btm_cb.devcb.p_rssi_cmpl_cb) return (BTM_BUSY);
 
   BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
-  if (dev_type == BT_DEVICE_TYPE_BLE) transport = BT_TRANSPORT_LE;
 
-  p = btm_bda_to_acl(remote_bda, transport);
-  if (p != (tACL_CONN*)NULL) {
+  if (dev_type & BT_DEVICE_TYPE_BLE) {
+    p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
+  }
+
+  if (p == NULL && dev_type & BT_DEVICE_TYPE_BREDR) {
+    p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+  }
+
+  if (p) {
     btm_cb.devcb.p_rssi_cmpl_cb = p_cb;
     alarm_set_on_mloop(btm_cb.devcb.read_rssi_timer, BTM_DEV_REPLY_TIMEOUT_MS,
                        btm_read_rssi_timeout, NULL);
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index cd52216..ca93e1a 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -47,6 +47,10 @@
 extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
                                      uint16_t length, uint16_t tlen,
                                      uint8_t* p_signature);
+extern void gatt_notify_phy_updated(uint8_t status, uint16_t handle,
+                                    uint8_t tx_phy, uint8_t rx_phy);
+extern void btm_ble_advertiser_notify_terminated_legacy(
+    uint8_t status, uint16_t connection_handle);
 
 /******************************************************************************/
 /* External Function to be called by other modules                            */
@@ -85,8 +89,9 @@
     p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_PARAM_UNDEF;
     p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_PARAM_UNDEF;
 
-    BTM_TRACE_DEBUG("%s: Device added, handle=0x%x ", __func__,
-                    p_dev_rec->ble_hci_handle);
+    BTM_TRACE_DEBUG("%s: Device added, handle=0x%x, p_dev_rec=%p, bd_addr=%s",
+                    __func__, p_dev_rec->ble_hci_handle, p_dev_rec,
+                    bd_addr.ToString().c_str());
   }
 
   memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
@@ -871,7 +876,7 @@
       !controller_get_interface()->supports_ble_coded_phy()) {
     BTM_TRACE_ERROR("%s failed, request not supported in local controller!",
                     __func__);
-    cb.Run(0, 0, HCI_ERR_ILLEGAL_COMMAND);
+    cb.Run(0, 0, GATT_REQ_NOT_SUPPORTED);
     return;
   }
 
@@ -958,22 +963,24 @@
       "= 0x%04x",
       __func__, all_phys, tx_phys, rx_phys, phy_options);
 
+  uint16_t handle = p_acl->hci_handle;
+
   // checking if local controller supports it!
   if (!controller_get_interface()->supports_ble_2m_phy() &&
       !controller_get_interface()->supports_ble_coded_phy()) {
     BTM_TRACE_ERROR("%s failed, request not supported in local controller!",
                     __func__);
+    gatt_notify_phy_updated(GATT_REQ_NOT_SUPPORTED, handle, tx_phys, rx_phys);
     return;
   }
 
   if (!HCI_LE_2M_PHY_SUPPORTED(p_acl->peer_le_features) &&
       !HCI_LE_CODED_PHY_SUPPORTED(p_acl->peer_le_features)) {
     BTM_TRACE_ERROR("%s failed, peer does not support request", __func__);
+    gatt_notify_phy_updated(GATT_REQ_NOT_SUPPORTED, handle, tx_phys, rx_phys);
     return;
   }
 
-  uint16_t handle = p_acl->hci_handle;
-
   const uint8_t len = HCIC_PARAM_SIZE_BLE_SET_PHY;
   uint8_t data[len];
   uint8_t* pp = data;
@@ -1311,8 +1318,11 @@
         p_rec->ble.static_addr = p_keys->pid_key.static_addr;
         p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
         p_rec->ble.key_type |= BTM_LE_KEY_PID;
-        BTM_TRACE_DEBUG("BTM_LE_KEY_PID key_type=0x%x save peer IRK",
-                        p_rec->ble.key_type);
+        BTM_TRACE_DEBUG(
+            "%s: BTM_LE_KEY_PID key_type=0x%x save peer IRK, change bd_addr=%s "
+            "to static_addr=%s",
+            __func__, p_rec->ble.key_type, p_rec->bd_addr.ToString().c_str(),
+            p_keys->pid_key.static_addr.ToString().c_str());
         /* update device record address as static address */
         p_rec->bd_addr = p_keys->pid_key.static_addr;
         /* combine DUMO device security record if needed */
@@ -1374,7 +1384,7 @@
         return;
     }
 
-    VLOG(1) << "BLE key type 0x" << std::hex << key_type
+    VLOG(1) << "BLE key type 0x" << loghex(key_type)
             << " updated for BDA: " << bd_addr << " (btm_sec_save_le_key)";
 
     /* Notify the application that one of the BLE keys has been updated
@@ -1388,7 +1398,7 @@
     return;
   }
 
-  LOG(WARNING) << "BLE key type 0x" << std::hex << key_type
+  LOG(WARNING) << "BLE key type 0x" << loghex(key_type)
                << " called for Unknown BDA or type: " << bd_addr
                << "(btm_sec_save_le_key)";
 
@@ -1548,8 +1558,8 @@
     case BTM_BLE_SEC_ENCRYPT_NO_MITM:
     case BTM_BLE_SEC_ENCRYPT_MITM:
       auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
-                     ? SMP_AUTH_GEN_BOND
-                     : (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT);
+                     ? SMP_AUTH_BOND
+                     : (SMP_AUTH_BOND | SMP_AUTH_YN_BIT);
       btm_ble_link_sec_check(bd_addr, auth_req, &sec_req_act);
       if (sec_req_act == BTM_BLE_SEC_REQ_ACT_NONE ||
           sec_req_act == BTM_BLE_SEC_REQ_ACT_DISCARD) {
@@ -1860,13 +1870,15 @@
   */
   if (p_dev_rec) {
     VLOG(1) << __func__ << " Security Manager: handle:" << handle
-            << " enc_mode:" << enc_mode << "  bda: " << bda
-            << " RName: " << p_dev_rec->sec_bd_name;
+            << " enc_mode:" << loghex(enc_mode) << "  bda: " << bda
+            << " RName: " << p_dev_rec->sec_bd_name
+            << " p_dev_rec:" << p_dev_rec;
 
     BTM_TRACE_DEBUG("btm_ble_connected sec_flags=0x%x", p_dev_rec->sec_flags);
   } else {
     VLOG(1) << __func__ << " Security Manager: handle:" << handle
-            << " enc_mode:" << enc_mode << "  bda: " << bda;
+            << " enc_mode:" << loghex(enc_mode) << "  bda: " << bda
+            << " p_dev_rec:" << p_dev_rec;
   }
 
   if (!p_dev_rec) {
@@ -1978,7 +1990,7 @@
 #endif
   } else {
     role = HCI_ROLE_UNKNOWN;
-    if (status != HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) {
+    if (status != HCI_ERR_ADVERTISING_TIMEOUT) {
       btm_ble_set_conn_st(BLE_CONN_IDLE);
 #if (BLE_PRIVACY_SPT == TRUE)
       btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
@@ -1992,6 +2004,9 @@
   }
 
   btm_ble_update_mode_operation(role, &bda, status);
+
+  if (role == HCI_ROLE_SLAVE)
+    btm_ble_advertiser_notify_terminated_legacy(status, handle);
 }
 
 /*****************************************************************************
@@ -2001,9 +2016,20 @@
  *
  *****************************************************************************/
 void btm_ble_create_ll_conn_complete(uint8_t status) {
-  if (status != HCI_SUCCESS) {
-    btm_ble_set_conn_st(BLE_CONN_IDLE);
-    btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+  if (status == HCI_SUCCESS) return;
+
+  btm_ble_set_conn_st(BLE_CONN_IDLE);
+  btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+
+  LOG(WARNING) << "LE Create Connection attempt failed, status="
+               << loghex(status);
+
+  if (status == HCI_ERR_COMMAND_DISALLOWED) {
+    /* There is already either direct connect, or whitelist connection
+     * pending, but we don't know which one, or to which state should we
+     * transition now. This can be triggered only in case of rare race
+     * condition. Crash to recover. */
+    LOG(FATAL) << "LE Create Connection - command disallowed";
   }
 }
 /*****************************************************************************
@@ -2174,7 +2200,7 @@
     ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf,
                                    (uint16_t)(len + 4), BTM_CMAC_TLEN_SIZE,
                                    p_mac);
-    if (ret == true) {
+    if (ret) {
       btm_ble_increment_sign_ctr(bd_addr, true);
     }
 
@@ -2329,7 +2355,7 @@
 extern uint8_t BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) {
 #if (L2CAP_LE_COC_INCLUDED == TRUE)
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
-  tBTM_LE_IO_REQ dev_io_cfg;
+  tBTM_LE_EVT_DATA btm_le_evt_data;
   uint8_t callback_rc;
 
   if (!p_dev_rec) {
@@ -2344,7 +2370,7 @@
   }
 
   callback_rc = (*btm_cb.api.p_le_callback)(
-      BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA*)&dev_io_cfg);
+      BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, &btm_le_evt_data);
 
   if (callback_rc != BTM_SUCCESS) {
     BTM_TRACE_ERROR("%s can't access supported key size", __func__);
@@ -2352,8 +2378,8 @@
   }
 
   BTM_TRACE_DEBUG("%s device supports key size = %d", __func__,
-                  dev_io_cfg.max_key_size);
-  return (dev_io_cfg.max_key_size);
+                  btm_le_evt_data.io_req.max_key_size);
+  return (btm_le_evt_data.io_req.max_key_size);
 #else
   return 0;
 #endif
@@ -2373,7 +2399,7 @@
  *
  ******************************************************************************/
 static void btm_notify_new_key(uint8_t key_type) {
-  tBTM_BLE_LOCAL_KEYS* p_locak_keys = NULL;
+  tBTM_BLE_LOCAL_KEYS* p_local_keys = NULL;
 
   BTM_TRACE_DEBUG("btm_notify_new_key key_type=%d", key_type);
 
@@ -2381,12 +2407,12 @@
     switch (key_type) {
       case BTM_BLE_KEY_TYPE_ID:
         BTM_TRACE_DEBUG("BTM_BLE_KEY_TYPE_ID");
-        p_locak_keys = (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.id_keys;
+        p_local_keys = (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.id_keys;
         break;
 
       case BTM_BLE_KEY_TYPE_ER:
         BTM_TRACE_DEBUG("BTM_BLE_KEY_TYPE_ER");
-        p_locak_keys =
+        p_local_keys =
             (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.ble_encryption_key_value;
         break;
 
@@ -2394,8 +2420,8 @@
         BTM_TRACE_ERROR("unknown key type: %d", key_type);
         break;
     }
-    if (p_locak_keys != NULL)
-      (*btm_cb.api.p_le_key_callback)(key_type, p_locak_keys);
+    if (p_local_keys != NULL)
+      (*btm_cb.api.p_le_key_callback)(key_type, p_local_keys);
   }
 }
 
diff --git a/stack/btm/btm_ble_addr.cc b/stack/btm/btm_ble_addr.cc
index 5459c53..2d0acc6 100644
--- a/stack/btm/btm_ble_addr.cc
+++ b/stack/btm/btm_ble_addr.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/btm/btm_ble_adv_filter.cc b/stack/btm/btm_ble_adv_filter.cc
index eb3fc4d..1f68fb6 100644
--- a/stack/btm/btm_ble_adv_filter.cc
+++ b/stack/btm/btm_ble_adv_filter.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014  Broadcom Corporation
+ *  Copyright 2014  Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,6 +34,9 @@
 #include "hcidefs.h"
 #include "hcimsgs.h"
 
+using base::Bind;
+using bluetooth::Uuid;
+
 #define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3
 #define BTM_BLE_ADV_FILT_FEAT_SELN_LEN 13
 #define BTM_BLE_ADV_FILT_TRACK_NUM 2
@@ -73,30 +76,8 @@
 #define BTM_BLE_ADV_FILT_CB_EVT_MASK 0xF0
 #define BTM_BLE_ADV_FILT_SUBCODE_MASK 0x0F
 
-/*******************************************************************************
- *
- * Function         btm_ble_obtain_vsc_details
- *
- * Description      This function obtains the VSC details
- *
- * Parameters
- *
- * Returns          status
- *
- ******************************************************************************/
-tBTM_STATUS btm_ble_obtain_vsc_details() {
-  tBTM_STATUS st = BTM_SUCCESS;
-
-#if (BLE_VND_INCLUDED == TRUE)
-  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
-  if (cmn_ble_vsc_cb.filter_support && 0 == cmn_ble_vsc_cb.max_filter) {
-    st = BTM_MODE_UNSUPPORTED;
-    return st;
-  }
-#else
-  cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER;
-#endif
-  return st;
+bool is_filtering_supported() {
+  return cmn_ble_vsc_cb.filter_support != 0 && cmn_ble_vsc_cb.max_filter != 0;
 }
 
 /*******************************************************************************
@@ -457,8 +438,6 @@
   tBTM_BLE_PF_COUNT* p_addr_filter = NULL;
   uint8_t* p_counter = NULL;
 
-  btm_ble_obtain_vsc_details();
-
   if (cond_type > BTM_BLE_PF_TYPE_ALL) {
     BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type);
     return BTM_BLE_INVALID_COUNTER;
@@ -520,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);
   }
@@ -537,9 +529,10 @@
  */
 void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
                            tBTM_BLE_PF_FILT_INDEX filt_index,
-                           tBTM_BLE_PF_COND_TYPE filter_type, tBT_UUID uuid,
+                           tBTM_BLE_PF_COND_TYPE filter_type,
+                           const bluetooth::Uuid& uuid,
                            tBTM_BLE_PF_LOGIC_TYPE cond_logic,
-                           tBTM_BLE_PF_COND_MASK* p_uuid_mask,
+                           const bluetooth::Uuid& uuid_mask,
                            tBTM_BLE_PF_CFG_CBACK cb) {
   uint8_t evt_type;
 
@@ -559,36 +552,39 @@
   UINT8_TO_STREAM(p, action);
   UINT8_TO_STREAM(p, filt_index);
 
+  uint8_t uuid_len = uuid.GetShortestRepresentationSize();
   if (action != BTM_BLE_SCAN_COND_CLEAR) {
-    if (uuid.len == LEN_UUID_16) {
-      UINT16_TO_STREAM(p, uuid.uu.uuid16);
-      len += LEN_UUID_16;
-    } else if (uuid.len == LEN_UUID_32) {
-      UINT32_TO_STREAM(p, uuid.uu.uuid32);
-      len += LEN_UUID_32;
-    } else if (uuid.len == LEN_UUID_128) {
-      ARRAY_TO_STREAM(p, uuid.uu.uuid128, LEN_UUID_128);
-      len += LEN_UUID_128;
+    if (uuid_len == Uuid::kNumBytes16) {
+      UINT16_TO_STREAM(p, uuid.As16Bit());
+      len += Uuid::kNumBytes16;
+    } else if (uuid_len == Uuid::kNumBytes32) {
+      UINT32_TO_STREAM(p, uuid.As32Bit());
+      len += Uuid::kNumBytes32;
+    } else if (uuid_len == Uuid::kNumBytes128) {
+      const auto& tmp = uuid.To128BitLE();
+      ARRAY_TO_STREAM(p, tmp.data(), (int)Uuid::kNumBytes128);
+      len += Uuid::kNumBytes128;
     } else {
-      BTM_TRACE_ERROR("illegal UUID length: %d", uuid.len);
+      BTM_TRACE_ERROR("illegal UUID length: %d", uuid_len);
       cb.Run(0, BTM_BLE_PF_CONFIG, 1 /*BTA_FAILURE*/);
       return;
     }
 
-    if (p_uuid_mask) {
-      if (uuid.len == LEN_UUID_16) {
-        UINT16_TO_STREAM(p, p_uuid_mask->uuid16_mask);
-        len += LEN_UUID_16;
-      } else if (uuid.len == LEN_UUID_32) {
-        UINT32_TO_STREAM(p, p_uuid_mask->uuid32_mask);
-        len += LEN_UUID_32;
-      } else if (uuid.len == LEN_UUID_128) {
-        ARRAY_TO_STREAM(p, p_uuid_mask->uuid128_mask, LEN_UUID_128);
-        len += LEN_UUID_128;
+    if (!uuid_mask.IsEmpty()) {
+      if (uuid_len == Uuid::kNumBytes16) {
+        UINT16_TO_STREAM(p, uuid_mask.As16Bit());
+        len += Uuid::kNumBytes16;
+      } else if (uuid_len == Uuid::kNumBytes32) {
+        UINT32_TO_STREAM(p, uuid_mask.As32Bit());
+        len += Uuid::kNumBytes32;
+      } else if (uuid_len == Uuid::kNumBytes128) {
+        const auto& tmp = uuid.To128BitLE();
+        ARRAY_TO_STREAM(p, tmp.data(), (int)Uuid::kNumBytes128);
+        len += Uuid::kNumBytes128;
       }
     } else {
-      memset(p, 0xff, uuid.len);
-      len += uuid.len;
+      memset(p, 0xff, uuid_len);
+      len += uuid_len;
     }
   }
 
@@ -598,11 +594,83 @@
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
 }
 
+void DoNothing(uint8_t a, uint8_t b, uint8_t c) {}
+
+void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
+                   std::vector<ApcfCommand> commands,
+                   tBTM_BLE_PF_CFG_CBACK cb) {
+  if (!is_filtering_supported()) {
+    cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+    return;
+  }
+
+  int action = BTM_BLE_SCAN_COND_ADD;
+  for (const ApcfCommand& cmd : commands) {
+    /* If data is passed, both mask and data have to be the same length */
+    if (cmd.data.size() != cmd.data_mask.size() && cmd.data.size() != 0 &&
+        cmd.data_mask.size() != 0) {
+      LOG(ERROR) << __func__ << " data(" << cmd.data.size() << ") and mask("
+                 << cmd.data_mask.size() << ") are of different size";
+      continue;
+    }
+
+    switch (cmd.type) {
+      case BTM_BLE_PF_ADDR_FILTER: {
+        tBLE_BD_ADDR target_addr;
+        target_addr.bda = cmd.address;
+        target_addr.type = cmd.addr_type;
+
+        BTM_LE_PF_addr_filter(action, filt_index, target_addr, Bind(DoNothing));
+        break;
+      }
+
+      case BTM_BLE_PF_SRVC_DATA:
+        BTM_LE_PF_srvc_data(action, filt_index);
+        break;
+
+      case BTM_BLE_PF_SRVC_UUID:
+      case BTM_BLE_PF_SRVC_SOL_UUID: {
+        BTM_LE_PF_uuid_filter(action, filt_index, cmd.type, cmd.uuid,
+                              BTM_BLE_PF_LOGIC_AND, cmd.uuid_mask,
+                              Bind(DoNothing));
+        break;
+      }
+
+      case BTM_BLE_PF_LOCAL_NAME: {
+        BTM_LE_PF_local_name(action, filt_index, cmd.name, Bind(DoNothing));
+        break;
+      }
+
+      case BTM_BLE_PF_MANU_DATA: {
+        BTM_LE_PF_manu_data(action, filt_index, cmd.company, cmd.company_mask,
+                            cmd.data, cmd.data_mask, Bind(DoNothing));
+        break;
+      }
+
+      case BTM_BLE_PF_SRVC_DATA_PATTERN: {
+        BTM_LE_PF_srvc_data_pattern(action, filt_index, cmd.data, cmd.data_mask,
+                                    Bind(DoNothing));
+        break;
+      }
+
+      default:
+        LOG(ERROR) << __func__ << ": Unknown filter type: " << +cmd.type;
+        break;
+    }
+  }
+  cb.Run(0, 0, 0);
+}
+
 /**
  * all adv payload filter by de-selecting all the adv pf feature bits
  */
 void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
                      tBTM_BLE_PF_CFG_CBACK cb) {
+  if (!is_filtering_supported()) {
+    cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+    return;
+  }
+
   /* clear the general filter entry */
   {
     tBTM_BLE_PF_CFG_CBACK fDoNothing;
@@ -619,10 +687,12 @@
 
     /* clear UUID filter */
     BTM_LE_PF_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
-                          BTM_BLE_PF_SRVC_UUID, {}, 0, nullptr, fDoNothing);
+                          BTM_BLE_PF_SRVC_UUID, {}, 0, Uuid::kEmpty,
+                          fDoNothing);
 
     BTM_LE_PF_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
-                          BTM_BLE_PF_SRVC_SOL_UUID, {}, 0, nullptr, fDoNothing);
+                          BTM_BLE_PF_SRVC_SOL_UUID, {}, 0, Uuid::kEmpty,
+                          fDoNothing);
 
     /* clear service data filter */
     BTM_LE_PF_srvc_data_pattern(BTM_BLE_SCAN_COND_CLEAR, filt_index, {}, {},
@@ -673,7 +743,7 @@
                 BTM_BLE_ADV_FILT_FEAT_SELN_LEN + BTM_BLE_ADV_FILT_TRACK_NUM;
   uint8_t param[len], *p;
 
-  if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+  if (!is_filtering_supported()) {
     cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
     return;
   }
@@ -791,7 +861,7 @@
  ******************************************************************************/
 void BTM_BleEnableDisableFilterFeature(uint8_t enable,
                                        tBTM_BLE_PF_STATUS_CBACK p_stat_cback) {
-  if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+  if (!is_filtering_supported()) {
     if (p_stat_cback) p_stat_cback.Run(BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
     return;
   }
@@ -821,7 +891,10 @@
  ******************************************************************************/
 void btm_ble_adv_filter_init(void) {
   memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_ADV_FILTER_CB));
-  if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) return;
+
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+  if (!is_filtering_supported()) return;
 
   if (cmn_ble_vsc_cb.max_filter > 0) {
     btm_ble_adv_filt_cb.p_addr_filter_count = (tBTM_BLE_PF_COUNT*)osi_malloc(
diff --git a/stack/btm/btm_ble_batchscan.cc b/stack/btm/btm_ble_batchscan.cc
index a0b159c..89b3e6c 100644
--- a/stack/btm/btm_ble_batchscan.cc
+++ b/stack/btm/btm_ble_batchscan.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Broadcom Corporation
+ *  Copyright 2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -496,8 +496,8 @@
 
   /* Check only for modes, as scan reports can be called after disabling batch
    * scan */
-  if (read_scan_mode < 0 || (scan_mode != BTM_BLE_BATCH_SCAN_MODE_PASS &&
-                             scan_mode != BTM_BLE_BATCH_SCAN_MODE_ACTI)) {
+  if (scan_mode != BTM_BLE_BATCH_SCAN_MODE_PASS &&
+      scan_mode != BTM_BLE_BATCH_SCAN_MODE_ACTI) {
     BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode,
                     scan_mode, ble_batchscan_cb.cur_state);
     cb.Run(BTM_ILLEGAL_VALUE, 0, 0, {});
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index f2f8307..952e953 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -344,6 +344,21 @@
   BTM_TRACE_EVENT("%s status=%d", __func__, *p);
 }
 
+void btm_ble_create_conn_cancel_complete(uint8_t* p) {
+  uint8_t status;
+  STREAM_TO_UINT8(status, p);
+
+  if (status == HCI_ERR_COMMAND_DISALLOWED) {
+    /* This is a sign that logic around keeping connection state is broken */
+    LOG(ERROR)
+        << "Attempt to cancel LE connection, when no connection is pending.";
+    if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
+      btm_ble_set_conn_st(BLE_CONN_IDLE);
+      btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, nullptr, status);
+    }
+  }
+}
+
 void btm_send_hci_create_connection(
     uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
     uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
diff --git a/stack/btm/btm_ble_cont_energy.cc b/stack/btm/btm_ble_cont_energy.cc
index 61c5327..4e87308 100644
--- a/stack/btm/btm_ble_cont_energy.cc
+++ b/stack/btm/btm_ble_cont_energy.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014  Broadcom Corporation
+ *  Copyright 2014  Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index 341d85d..1f8263f 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2014 Broadcom Corporation
+ *  Copyright 2008-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -435,7 +435,7 @@
                              ? BTM_BLE_SCAN_MODE_ACTI
                              : p_inq->scan_type;
 /* assume observe always not using white list */
-#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == true)
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
       /* enable resolving list */
       btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
 #endif
@@ -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__,
@@ -576,7 +577,7 @@
 #if (BLE_VND_INCLUDED == TRUE)
 extern void BTM_BleReadControllerFeatures(
     tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {
-  if (true == btm_cb.cmn_ble_vsc_cb.values_read) return;
+  if (btm_cb.cmn_ble_vsc_cb.values_read) return;
 
   BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures");
 
@@ -630,7 +631,8 @@
   /* if LE is not supported, return error */
   if (!controller_get_interface()->supports_ble()) return false;
 
-  uint8_t addr_resolution = 0;
+  tGAP_BLE_ATTR_VALUE gap_ble_attr_value;
+  gap_ble_attr_value.addr_resolution = 0;
   if (!privacy_mode) /* if privacy disabled, always use public address */
   {
     p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
@@ -645,7 +647,7 @@
     /* 4.2 controller only allow privacy 1.2 or mixed mode, resolvable private
      * address in controller */
     if (controller_get_interface()->supports_ble_privacy()) {
-      addr_resolution = 1;
+      gap_ble_attr_value.addr_resolution = 1;
       /* check vendor specific capability */
       p_cb->privacy_mode =
           btm_cb.ble_ctr_cb.mixed_mode ? BTM_PRIVACY_MIXED : BTM_PRIVACY_1_2;
@@ -653,8 +655,7 @@
       p_cb->privacy_mode = BTM_PRIVACY_1_1;
   }
 
-  GAP_BleAttrDBUpdate(GATT_UUID_GAP_CENTRAL_ADDR_RESOL,
-                      (tGAP_BLE_ATTR_VALUE*)&addr_resolution);
+  GAP_BleAttrDBUpdate(GATT_UUID_GAP_CENTRAL_ADDR_RESOL, &gap_ble_attr_value);
 
   return true;
 #else
@@ -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();
@@ -1841,10 +1843,10 @@
   }
 }
 
-void btm_ble_process_adv_addr(RawAddress& bda, uint8_t addr_type) {
+void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) {
 #if (BLE_PRIVACY_SPT == TRUE)
   /* map address to security record */
-  bool match = btm_identity_addr_to_random_pseudo(&bda, &addr_type, false);
+  bool match = btm_identity_addr_to_random_pseudo(&bda, addr_type, false);
 
   VLOG(1) << __func__ << ": bda=" << bda;
   /* always do RRA resolution on host */
@@ -1909,13 +1911,20 @@
 
     uint8_t* pkt_data = p;
     p += pkt_data_len; /* Advance to the the next packet*/
-
-    if (rssi >= 21 && rssi <= 126) {
-      BTM_TRACE_ERROR("%s: bad rssi value in advertising report: ", __func__,
-                      pkt_data_len, rssi);
+    if (p > data + data_len) {
+      LOG(ERROR) << "Invalid pkt_data_len: " << +pkt_data_len;
+      return;
     }
 
-    btm_ble_process_adv_addr(bda, addr_type);
+    if (rssi >= 21 && rssi <= 126) {
+      BTM_TRACE_ERROR("%s: bad rssi value in advertising report: %d", __func__,
+                      rssi);
+    }
+
+    if (addr_type != BLE_ADDR_ANONYMOUS) {
+      btm_ble_process_adv_addr(bda, &addr_type);
+    }
+
     btm_ble_process_adv_pkt_cont(event_type, addr_type, bda, primary_phy,
                                  secondary_phy, advertising_sid, tx_power, rssi,
                                  periodic_adv_int, pkt_data_len, pkt_data);
@@ -1954,6 +1963,10 @@
 
     uint8_t* pkt_data = p;
     p += pkt_data_len; /* Advance to the the rssi byte */
+    if (p > data + data_len - sizeof(rssi)) {
+      LOG(ERROR) << "Invalid pkt_data_len: " << +pkt_data_len;
+      return;
+    }
 
     STREAM_TO_INT8(rssi, p);
 
@@ -1962,7 +1975,7 @@
                       pkt_data_len, rssi);
     }
 
-    btm_ble_process_adv_addr(bda, addr_type);
+    btm_ble_process_adv_addr(bda, &addr_type);
 
     uint16_t event_type;
     if (legacy_evt_type == 0x00) {  // ADV_IND;
@@ -2013,7 +2026,8 @@
   bool is_start =
       ble_evt_type_is_legacy(evt_type) && is_scannable && !is_scan_resp;
 
-  if (is_start) AdvertiseDataParser::RemoveTrailingZeros(tmp);
+  if (ble_evt_type_is_legacy(evt_type))
+    AdvertiseDataParser::RemoveTrailingZeros(tmp);
 
   // We might have send scan request to this device before, but didn't get the
   // response. In such case make sure data is put at start, not appended to
@@ -2140,17 +2154,7 @@
   STREAM_TO_UINT8(tx_phy, p);
   STREAM_TO_UINT8(rx_phy, p);
 
-  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
-  if (!p_dev_rec) {
-    BTM_TRACE_WARNING("%s: No Device Found!", __func__);
-    return;
-  }
-
-  tGATT_TCB* p_tcb =
-      gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
-  if (p_tcb == NULL) return;
-
-  gatt_notify_phy_updated(p_tcb, tx_phy, rx_phy, status);
+  gatt_notify_phy_updated(status, handle, tx_phy, rx_phy);
 }
 
 /*******************************************************************************
@@ -2257,8 +2261,7 @@
 
   if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) btm_ble_stop_scan();
 
-  if (p_obs_cb)
-    (p_obs_cb)((tBTM_INQUIRY_CMPL*)&btm_cb.btm_inq_vars.inq_cmpl_info);
+  if (p_obs_cb) (p_obs_cb)(&btm_cb.btm_inq_vars.inq_cmpl_info);
 }
 /*******************************************************************************
  *
@@ -2564,7 +2567,7 @@
  ******************************************************************************/
 void btm_ble_update_mode_operation(uint8_t link_role, const RawAddress* bd_addr,
                                    uint8_t status) {
-  if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) {
+  if (status == HCI_ERR_ADVERTISING_TIMEOUT) {
     btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
     /* make device fall back into undirected adv mode by default */
     btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
@@ -2579,7 +2582,7 @@
 
   /* in case of disconnected, we must cancel bgconn and restart
      in order to add back device to white list in order to reconnect */
-  btm_ble_bgconn_cancel_if_disconnected(*bd_addr);
+  if (bd_addr) btm_ble_bgconn_cancel_if_disconnected(*bd_addr);
 
   /* when no connection is attempted, and controller is not rejecting last
      request
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index 895d6ba..d4cb411 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/btm/btm_ble_int_types.h b/stack/btm/btm_ble_int_types.h
index b539211..2167f2f 100644
--- a/stack/btm/btm_ble_int_types.h
+++ b/stack/btm/btm_ble_int_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index 99b8cb5..60490fb 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017  The Android Open Source Project
- *  Copyright (C) 2014  Broadcom Corporation
+ *  Copyright 2017  The Android Open Source Project
+ *  Copyright 2014  Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,7 +18,9 @@
  ******************************************************************************/
 
 #include <base/bind.h>
+#include <base/location.h>
 #include <base/logging.h>
+#include <base/memory/weak_ptr.h>
 #include <base/strings/string_number_conversions.h>
 #include <base/time/time.h>
 #include <string.h>
@@ -101,7 +103,11 @@
 
   ~AdvertisingInstance() {
     alarm_free(adv_raddr_timer);
-    if (timeout_timer) alarm_free(timeout_timer);
+    adv_raddr_timer = nullptr;
+    if (timeout_timer) {
+      alarm_free(timeout_timer);
+      timeout_timer = nullptr;
+    }
   }
 };
 
@@ -138,7 +144,7 @@
 /* a temporary type for holding all the data needed in callbacks below*/
 struct CreatorParams {
   uint8_t inst_id;
-  BleAdvertisingManagerImpl* self;
+  base::WeakPtr<BleAdvertisingManagerImpl> self;
   IdTxPowerStatusCb cb;
   tBTM_BLE_ADV_PARAMS params;
   std::vector<uint8_t> advertise_data;
@@ -152,15 +158,18 @@
 
 using c_type = std::unique_ptr<CreatorParams>;
 
+BleAdvertisingManager* instance;
+base::WeakPtr<BleAdvertisingManagerImpl> instance_weakptr;
+
 class BleAdvertisingManagerImpl
     : public BleAdvertisingManager,
       public BleAdvertiserHciInterface::AdvertisingEventObserver {
  public:
-  BleAdvertisingManagerImpl(BleAdvertiserHciInterface* interface) {
-    this->hci_interface = interface;
+  BleAdvertisingManagerImpl(BleAdvertiserHciInterface* interface)
+      : hci_interface(interface), weak_factory_(this) {
     hci_interface->ReadInstanceCount(
         base::Bind(&BleAdvertisingManagerImpl::ReadInstanceCountCb,
-                   base::Unretained(this)));
+                   weak_factory_.GetWeakPtr()));
   }
 
   ~BleAdvertisingManagerImpl() { adv_inst.clear(); }
@@ -209,7 +218,7 @@
   void GenerateRpa(base::Callback<void(RawAddress)> cb) {
     btm_gen_resolvable_private_addr(
         Bind(&BleAdvertisingManagerImpl::OnRpaGenerationComplete,
-             base::Unretained(this), std::move(cb)));
+             weak_factory_.GetWeakPtr(), std::move(cb)));
   }
 
   void ConfigureRpa(AdvertisingInstance* p_inst, MultiAdvCb configuredCb) {
@@ -231,9 +240,8 @@
           /* Connectable advertising set must be disabled when updating RPA */
           bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
 
-          auto hci_interface =
-              ((BleAdvertisingManagerImpl*)BleAdvertisingManager::Get())
-                  ->GetHciInterface();
+          if (!instance_weakptr.get()) return;
+          auto hci_interface = instance_weakptr.get()->GetHciInterface();
 
           if (restart) {
             p_inst->enable_status = false;
@@ -243,7 +251,7 @@
 
           /* set it to controller */
           hci_interface->SetRandomAddress(
-              p_inst->inst_id, p_inst->own_address,
+              p_inst->inst_id, bda,
               Bind(
                   [](AdvertisingInstance* p_inst, RawAddress bda,
                      MultiAdvCb configuredCb, uint8_t status) {
@@ -307,7 +315,7 @@
     /* a temporary type for holding all the data needed in callbacks below*/
     struct CreatorParams {
       uint8_t inst_id;
-      BleAdvertisingManagerImpl* self;
+      base::WeakPtr<BleAdvertisingManagerImpl> self;
       MultiAdvCb cb;
       tBTM_BLE_ADV_PARAMS params;
       std::vector<uint8_t> advertise_data;
@@ -319,7 +327,7 @@
     std::unique_ptr<CreatorParams> c;
     c.reset(new CreatorParams());
 
-    c->self = this;
+    c->self = weak_factory_.GetWeakPtr();
     c->cb = std::move(cb);
     c->params = *params;
     c->advertise_data = std::move(advertise_data);
@@ -335,7 +343,12 @@
     // clang-format off
     c->self->SetParameters(c->inst_id, &c->params, Bind(
       [](c_type c, uint8_t status, int8_t tx_power) {
-        if (status != 0) {
+        if (!c->self) {
+          LOG(INFO) << "Stack was shut down";
+          return;
+        }
+
+        if (status) {
           LOG(ERROR) << "setting parameters failed, status: " << +status;
           c->cb.Run(status);
           return;
@@ -346,6 +359,11 @@
         const RawAddress& rpa = c->self->adv_inst[c->inst_id].own_address;
         c->self->GetHciInterface()->SetRandomAddress(c->inst_id, rpa, Bind(
           [](c_type c, uint8_t status) {
+            if (!c->self) {
+              LOG(INFO) << "Stack was shut down";
+              return;
+            }
+
             if (status != 0) {
               LOG(ERROR) << "setting random address failed, status: " << +status;
               c->cb.Run(status);
@@ -354,6 +372,11 @@
 
             c->self->SetData(c->inst_id, false, std::move(c->advertise_data), Bind(
               [](c_type c, uint8_t status) {
+                if (!c->self) {
+                  LOG(INFO) << "Stack was shut down";
+                  return;
+                }
+
                 if (status != 0) {
                   LOG(ERROR) << "setting advertise data failed, status: " << +status;
                   c->cb.Run(status);
@@ -362,6 +385,11 @@
 
                 c->self->SetData(c->inst_id, true, std::move(c->scan_response_data), Bind(
                   [](c_type c, uint8_t status) {
+                    if (!c->self) {
+                      LOG(INFO) << "Stack was shut down";
+                      return;
+                    }
+
                     if (status != 0) {
                       LOG(ERROR) << "setting scan response data failed, status: " << +status;
                       c->cb.Run(status);
@@ -387,7 +415,7 @@
     std::unique_ptr<CreatorParams> c;
     c.reset(new CreatorParams());
 
-    c->self = this;
+    c->self = weak_factory_.GetWeakPtr();
     c->cb = std::move(cb);
     c->params = *params;
     c->advertise_data = std::move(advertise_data);
@@ -403,8 +431,13 @@
     // clang-format off
     c->self->RegisterAdvertiser(Bind(
       [](c_type c, uint8_t advertiser_id, uint8_t status) {
+        if (!c->self) {
+          LOG(INFO) << "Stack was shut down";
+          return;
+        }
+
         if (status != 0) {
-          LOG(ERROR) << "registering advertiser failed, status: " << +status;
+          LOG(ERROR) << " failed, status: " << +status;
           c->cb.Run(0, 0, status);
           return;
         }
@@ -413,6 +446,11 @@
 
         c->self->SetParameters(c->inst_id, &c->params, Bind(
           [](c_type c, uint8_t status, int8_t tx_power) {
+            if (!c->self) {
+              LOG(INFO) << "Stack was shut down";
+              return;
+            }
+
             if (status != 0) {
               c->self->Unregister(c->inst_id);
               LOG(ERROR) << "setting parameters failed, status: " << +status;
@@ -422,9 +460,20 @@
 
             c->self->adv_inst[c->inst_id].tx_power = tx_power;
 
+            if (c->self->adv_inst[c->inst_id].own_address_type == BLE_ADDR_PUBLIC) {
+              c->self->StartAdvertisingSetAfterAddressPart(std::move(c));
+              return;
+            }
+
+            //own_address_type == BLE_ADDR_RANDOM
             const RawAddress& rpa = c->self->adv_inst[c->inst_id].own_address;
             c->self->GetHciInterface()->SetRandomAddress(c->inst_id, rpa, Bind(
               [](c_type c, uint8_t status) {
+                if (!c->self) {
+                  LOG(INFO) << "Stack was shut down";
+                  return;
+                }
+
                 if (status != 0) {
                   c->self->Unregister(c->inst_id);
                   LOG(ERROR) << "setting random address failed, status: " << +status;
@@ -432,35 +481,59 @@
                   return;
                 }
 
-                c->self->SetData(c->inst_id, false, std::move(c->advertise_data), Bind(
-                  [](c_type c, uint8_t status) {
-                    if (status != 0) {
-                      c->self->Unregister(c->inst_id);
-                      LOG(ERROR) << "setting advertise data failed, status: " << +status;
-                      c->cb.Run(0, 0, status);
-                      return;
-                    }
+                c->self->StartAdvertisingSetAfterAddressPart(std::move(c));
+          }, base::Passed(&c)));
+        }, base::Passed(&c)));
+    }, base::Passed(&c)));
+    // clang-format on
+  }
 
-                    c->self->SetData(c->inst_id, true, std::move(c->scan_response_data), Bind(
+  void StartAdvertisingSetAfterAddressPart(c_type c) {
+    c->self->SetData(
+        c->inst_id, false, std::move(c->advertise_data),
+        Bind(
+            [](c_type c, uint8_t status) {
+              if (!c->self) {
+                LOG(INFO) << "Stack was shut down";
+                return;
+              }
+
+              if (status != 0) {
+                c->self->Unregister(c->inst_id);
+                LOG(ERROR) << "setting advertise data failed, status: "
+                           << +status;
+                c->cb.Run(0, 0, status);
+                return;
+              }
+
+              c->self->SetData(
+                  c->inst_id, true, std::move(c->scan_response_data),
+                  Bind(
                       [](c_type c, uint8_t status) {
+                        if (!c->self) {
+                          LOG(INFO) << "Stack was shut down";
+                          return;
+                        }
+
                         if (status != 0) {
                           c->self->Unregister(c->inst_id);
-                          LOG(ERROR) << "setting scan response data failed, status: " << +status;
+                          LOG(ERROR)
+                              << "setting scan response data failed, status: "
+                              << +status;
                           c->cb.Run(0, 0, status);
                           return;
                         }
 
                         if (c->periodic_params.enable) {
-                          c->self->StartAdvertisingSetPeriodicPart(std::move(c));
+                          c->self->StartAdvertisingSetPeriodicPart(
+                              std::move(c));
                         } else {
                           c->self->StartAdvertisingSetFinish(std::move(c));
                         }
-                    }, base::Passed(&c)));
-                }, base::Passed(&c)));
-            }, base::Passed(&c)));
-        }, base::Passed(&c)));
-    }, base::Passed(&c)));
-    // clang-format on
+                      },
+                      base::Passed(&c)));
+            },
+            base::Passed(&c)));
   }
 
   void StartAdvertisingSetPeriodicPart(c_type c) {
@@ -469,6 +542,11 @@
     // clang-format off
     c->self->SetPeriodicAdvertisingParameters(c->inst_id, &c->periodic_params, Bind(
       [](c_type c, uint8_t status) {
+        if (!c->self) {
+          LOG(INFO) << "Stack was shut down";
+          return;
+        }
+
         if (status != 0) {
           c->self->Unregister(c->inst_id);
           LOG(ERROR) << "setting periodic parameters failed, status: " << +status;
@@ -478,6 +556,11 @@
 
         c->self->SetPeriodicAdvertisingData(c->inst_id, std::move(c->periodic_data), Bind(
           [](c_type c, uint8_t status) {
+            if (!c->self) {
+              LOG(INFO) << "Stack was shut down";
+              return;
+            }
+
             if (status != 0) {
               c->self->Unregister(c->inst_id);
               LOG(ERROR) << "setting periodic parameters failed, status: " << +status;
@@ -487,6 +570,11 @@
 
             c->self->SetPeriodicAdvertisingEnable(c->inst_id, true, Bind(
               [](c_type c, uint8_t status) {
+                if (!c->self) {
+                  LOG(INFO) << "Stack was shut down";
+                  return;
+                }
+
                 if (status != 0) {
                   c->self->Unregister(c->inst_id);
                   LOG(ERROR) << "enabling periodic advertising failed, status: " << +status;
@@ -507,9 +595,14 @@
     uint16_t duration = c->duration;
     uint8_t maxExtAdvEvents = c->maxExtAdvEvents;
     RegisterCb timeout_cb = std::move(c->timeout_cb);
-    BleAdvertisingManagerImpl* self = c->self;
+    base::WeakPtr<BleAdvertisingManagerImpl> self = c->self;
     MultiAdvCb enable_cb = Bind(
         [](c_type c, uint8_t status) {
+          if (!c->self) {
+            LOG(INFO) << "Stack was shut down";
+            return;
+          }
+
           if (status != 0) {
             c->self->Unregister(c->inst_id);
             LOG(ERROR) << "enabling advertiser failed, status: " << +status;
@@ -535,9 +628,9 @@
 
     p_inst->timeout_timer = alarm_new("btm_ble.adv_timeout");
 
-    base::Closure cb = Bind(&BleAdvertisingManagerImpl::Enable,
-                            base::Unretained(this), inst_id, 0 /* disable */,
-                            std::move(timeout_cb), 0, 0, base::Bind(DoNothing));
+    base::Closure cb = Bind(
+        &BleAdvertisingManagerImpl::Enable, weak_factory_.GetWeakPtr(), inst_id,
+        0 /* disable */, std::move(timeout_cb), 0, 0, base::Bind(DoNothing));
 
     // schedule disable when the timeout passes
     alarm_set_closure(FROM_HERE, p_inst->timeout_timer, duration * 10,
@@ -570,8 +663,8 @@
     if (enable && p_inst->address_update_required) {
       p_inst->address_update_required = false;
       ConfigureRpa(p_inst, base::Bind(&BleAdvertisingManagerImpl::EnableFinish,
-                                      base::Unretained(this), p_inst, enable,
-                                      std::move(cb)));
+                                      weak_factory_.GetWeakPtr(), p_inst,
+                                      enable, std::move(cb)));
       return;
     }
 
@@ -585,7 +678,7 @@
       // TODO(jpawlowski): HCI implementation that can't do duration should
       // emulate it, not EnableWithTimerCb.
       myCb = Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb,
-                  base::Unretained(this), p_inst->inst_id, std::move(cb),
+                  weak_factory_.GetWeakPtr(), p_inst->inst_id, std::move(cb),
                   p_inst->duration, p_inst->timeout_cb);
     } else {
       myCb = std::move(cb);
@@ -683,7 +776,7 @@
     DivideAndSendData(
         inst_id, data, cb,
         base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender,
-                   base::Unretained(this), is_scan_rsp));
+                   weak_factory_.GetWeakPtr(), is_scan_rsp));
   }
 
   void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id,
@@ -872,11 +965,12 @@
       uint8_t status, uint8_t advertising_handle, uint16_t connection_handle,
       uint8_t num_completed_extended_adv_events) override {
     AdvertisingInstance* p_inst = &adv_inst[advertising_handle];
-    VLOG(1) << __func__ << "status: 0x" << std::hex << +status
-            << ", advertising_handle: 0x" << std::hex << +advertising_handle
-            << ", connection_handle: 0x" << std::hex << +connection_handle;
+    VLOG(1) << __func__ << "status: " << loghex(status)
+            << ", advertising_handle: " << loghex(advertising_handle)
+            << ", connection_handle: " << loghex(connection_handle);
 
-    if (status == 0x43 || status == 0x3C) {
+    if (status == HCI_ERR_LIMIT_REACHED ||
+        status == HCI_ERR_ADVERTISING_TIMEOUT) {
       // either duration elapsed, or maxExtAdvEvents reached
       p_inst->enable_status = false;
 
@@ -896,7 +990,7 @@
 
     VLOG(1) << "reneabling advertising";
 
-    if (p_inst->in_use == true) {
+    if (p_inst->in_use) {
       // TODO(jpawlowski): we don't really allow to do directed advertising
       // right now. This should probably be removed, check with Andre.
       if ((p_inst->advertising_event_properties & 0x0C) == 0) {
@@ -915,34 +1009,55 @@
     }
   }
 
+  base::WeakPtr<BleAdvertisingManagerImpl> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  void CancelAdvAlarms() {
+    AdvertisingInstance* p_inst = &adv_inst[0];
+    for (uint8_t i = 0; i < inst_count; i++, p_inst++) {
+      if (p_inst->timeout_timer) {
+        alarm_cancel(p_inst->timeout_timer);
+      }
+      if (p_inst->adv_raddr_timer) {
+        alarm_cancel(p_inst->adv_raddr_timer);
+      }
+    }
+  }
+
  private:
   BleAdvertiserHciInterface* GetHciInterface() { return hci_interface; }
 
   BleAdvertiserHciInterface* hci_interface = nullptr;
   std::vector<AdvertisingInstance> adv_inst;
   uint8_t inst_count;
+
+  // Member variables should appear before the WeakPtrFactory, to ensure
+  // that any WeakPtrs are invalidated before its members
+  // variable's destructors are executed, rendering them invalid.
+  base::WeakPtrFactory<BleAdvertisingManagerImpl> weak_factory_;
 };
 
-BleAdvertisingManager* instance;
-
 void btm_ble_adv_raddr_timer_timeout(void* data) {
-  ((BleAdvertisingManagerImpl*)BleAdvertisingManager::Get())
-      ->ConfigureRpa((AdvertisingInstance*)data, base::Bind(DoNothing));
+  BleAdvertisingManagerImpl* ptr = instance_weakptr.get();
+  if (ptr) ptr->ConfigureRpa((AdvertisingInstance*)data, base::Bind(DoNothing));
 }
 }  // namespace
 
 void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) {
   instance = new BleAdvertisingManagerImpl(interface);
+  instance_weakptr = ((BleAdvertisingManagerImpl*)instance)->GetWeakPtr();
 }
 
 bool BleAdvertisingManager::IsInitialized() { return instance; }
 
-BleAdvertisingManager* BleAdvertisingManager::Get() {
-  CHECK(instance);
-  return instance;
+base::WeakPtr<BleAdvertisingManager> BleAdvertisingManager::Get() {
+  return instance_weakptr;
 };
 
 void BleAdvertisingManager::CleanUp() {
+  if (instance_weakptr.get()) instance_weakptr.get()->CancelAdvAlarms();
+
   delete instance;
   instance = nullptr;
 };
@@ -954,11 +1069,11 @@
   BleAdvertiserHciInterface::Initialize();
   BleAdvertisingManager::Initialize(BleAdvertiserHciInterface::Get());
   BleAdvertiserHciInterface::Get()->SetAdvertisingEventObserver(
-      (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get());
+      (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get());
 
   if (BleAdvertiserHciInterface::Get()->QuirkAdvertiserZeroHandle()) {
     // If handle 0 can't be used, register advertiser for it, but never use it.
-    BleAdvertisingManager::Get()->RegisterAdvertiser(Bind(DoNothing2));
+    BleAdvertisingManager::Get().get()->RegisterAdvertiser(Bind(DoNothing2));
   }
 }
 
@@ -985,7 +1100,7 @@
 // verify that if duration passed, or is about to pass, recomputation will shut
 // down the advertiser completly
 void testRecomputeTimeout1() {
-  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get();
+  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get();
 
   TimeTicks start = TimeTicks::Now();
   TimeTicks end = start + TimeDelta::FromMilliseconds(111);
@@ -997,15 +1112,15 @@
 
   manager->RecomputeTimeout(&test1, end);
 
-  CHECK(timeout_triggered == true);
+  CHECK(timeout_triggered);
   timeout_triggered = false;
-  CHECK(test1.enable_status == false);
+  CHECK(!test1.enable_status);
 }
 
 // verify that duration and maxExtAdvEvents are properly adjusted when
 // recomputing.
 void testRecomputeTimeout2() {
-  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get();
+  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get();
 
   TimeTicks start = TimeTicks::Now();
   TimeTicks end = start + TimeDelta::FromMilliseconds(250);
@@ -1019,8 +1134,8 @@
 
   manager->RecomputeTimeout(&test1, end);
 
-  CHECK(timeout_triggered == false);
-  CHECK(test1.enable_status == true);
+  CHECK(!timeout_triggered);
+  CHECK(test1.enable_status);
   CHECK(test1.duration == 25);
   CHECK(test1.maxExtAdvEvents == 25);
 }
@@ -1028,7 +1143,7 @@
 // verify that if maxExtAdvEvents were sent, or are close to end, recomputation
 // wil shut down the advertiser completly
 void testRecomputeTimeout3() {
-  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get();
+  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get();
 
   TimeTicks start = TimeTicks::Now();
   TimeTicks end = start + TimeDelta::FromMilliseconds(495);
@@ -1041,7 +1156,7 @@
 
   manager->RecomputeTimeout(&test1, end);
 
-  CHECK(timeout_triggered == true);
+  CHECK(timeout_triggered);
   timeout_triggered = false;
-  CHECK(test1.enable_status == false);
+  CHECK(!test1.enable_status);
 }
diff --git a/stack/btm/btm_ble_privacy.cc b/stack/btm/btm_ble_privacy.cc
index f1aa509..3845ba6 100644
--- a/stack/btm/btm_ble_privacy.cc
+++ b/stack/btm/btm_ble_privacy.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -681,85 +681,97 @@
  *
  ******************************************************************************/
 bool btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
-  bool rt = false;
-  uint8_t rl_mask = btm_cb.ble_ctr_cb.rl_state;
+  const uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state;
 
-  BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
-                  btm_cb.ble_ctr_cb.privacy_mode);
-
-  /* if controller does not support RPA offloading or privacy 1.2, skip */
-  if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+  if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+    BTM_TRACE_DEBUG(
+        "%s: Controller does not support RPA offloading or privacy 1.2",
+        __func__);
     return false;
+  }
 
-  BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
+  BTM_TRACE_DEBUG("%s: btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
                   btm_cb.ble_ctr_cb.privacy_mode);
 
+  if (!p_dev_rec) {
+    BTM_TRACE_DEBUG("%s: No device security record", __func__);
+    return false;
+  }
+
   /* only add RPA enabled device into resolving list */
-  if (p_dev_rec != NULL && /* RPA is being used and PID is known */
-      ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0 ||
-       (p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0)) {
-    if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
-        btm_ble_brcm_find_resolving_pending_entry(
-            p_dev_rec->bd_addr, BTM_BLE_META_ADD_IRK_ENTRY) == false) {
-      if (btm_cb.ble_ctr_cb.resolving_list_avail_size > 0) {
-        if (rl_mask) {
-          if (!btm_ble_disable_resolving_list(rl_mask, false)) return false;
-        }
+  if (controller_get_interface()->supports_ble_privacy()) {
+    if ((p_dev_rec->ble.key_type & (BTM_LE_KEY_PID | BTM_LE_KEY_LID)) == 0) {
+      BTM_TRACE_DEBUG("%s: privacy 1.2: Device not a RPA enabled device",
+                      __func__);
+      return false;
+    }
+  } else if ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) == 0) {
+    BTM_TRACE_DEBUG("%s: RPA offloading: Device not a RPA enabled device",
+                    __func__);
+    return false;
+  }
 
-        btm_ble_update_resolving_list(p_dev_rec->bd_addr, true);
-        if (controller_get_interface()->supports_ble_privacy()) {
-          uint8_t* peer_irk = p_dev_rec->ble.keys.irk;
-          uint8_t* local_irk = btm_cb.devcb.id_keys.irk;
+  if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) ||
+      btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
+                                                BTM_BLE_META_ADD_IRK_ENTRY)) {
+    BTM_TRACE_ERROR("%s: Device already in Resolving list", __func__);
+    return true;
+  }
 
-          if (p_dev_rec->ble.static_addr.IsEmpty()) {
-            p_dev_rec->ble.static_addr = p_dev_rec->bd_addr;
-            p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
-          }
+  if (btm_cb.ble_ctr_cb.resolving_list_avail_size == 0) {
+    return false;
+  }
 
-          BTM_TRACE_DEBUG("%s:adding device to controller resolving list",
-                          __func__);
-          // use identical IRK for now
-          btsnd_hcic_ble_add_device_resolving_list(
-              p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr,
-              peer_irk, local_irk);
+  if (rl_state && !btm_ble_disable_resolving_list(rl_state, false)) {
+    return false;
+  }
 
-          if (controller_get_interface()->supports_ble_set_privacy_mode()) {
-            BTM_TRACE_DEBUG("%s: adding device privacy mode", __func__);
-            btsnd_hcic_ble_set_privacy_mode(p_dev_rec->ble.static_addr_type,
-                                            p_dev_rec->ble.static_addr, 0x01);
-          }
-        } else {
-          uint8_t param[40] = {0};
-          uint8_t* p = param;
+  btm_ble_update_resolving_list(p_dev_rec->bd_addr, true);
+  if (controller_get_interface()->supports_ble_privacy()) {
+    uint8_t* peer_irk = p_dev_rec->ble.keys.irk;
+    uint8_t* local_irk = btm_cb.devcb.id_keys.irk;
 
-          UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
-          ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
-          UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
-          BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+    if (p_dev_rec->ble.static_addr.IsEmpty()) {
+      p_dev_rec->ble.static_addr = p_dev_rec->bd_addr;
+      p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
+    }
 
-          BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
-                                    BTM_BLE_META_ADD_IRK_LEN, param,
-                                    btm_ble_resolving_list_vsc_op_cmpl);
-        }
+    BTM_TRACE_DEBUG("%s: adding device %s to controller resolving list",
+                    __func__, p_dev_rec->ble.static_addr.ToString().c_str());
 
-        rt = true;
-        btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
-                                           BTM_BLE_META_ADD_IRK_ENTRY);
+    // use identical IRK for now
+    btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type,
+                                             p_dev_rec->ble.static_addr,
+                                             peer_irk, local_irk);
 
-        /* if resolving list has been turned on, re-enable it */
-        if (rl_mask)
-          btm_ble_enable_resolving_list(rl_mask);
-        else
-          btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
-      }
-    } else {
-      BTM_TRACE_ERROR("Device already in Resolving list");
-      rt = true;
+    if (controller_get_interface()->supports_ble_set_privacy_mode()) {
+      BTM_TRACE_DEBUG("%s: adding device privacy mode", __func__);
+      btsnd_hcic_ble_set_privacy_mode(p_dev_rec->ble.static_addr_type,
+                                      p_dev_rec->ble.static_addr, 0x01);
     }
   } else {
-    BTM_TRACE_DEBUG("Device not a RPA enabled device");
+    uint8_t param[40] = {0};
+    uint8_t* p = param;
+
+    UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
+    ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
+    UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+    BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+
+    BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_ADD_IRK_LEN,
+                              param, btm_ble_resolving_list_vsc_op_cmpl);
   }
-  return rt;
+
+  btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+                                     BTM_BLE_META_ADD_IRK_ENTRY);
+
+  /* if resolving list has been turned on, re-enable it */
+  if (rl_state)
+    btm_ble_enable_resolving_list(rl_state);
+  else
+    btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
+
+  return true;
 }
 
 /*******************************************************************************
@@ -782,8 +794,8 @@
   }
 
   if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
-      btm_ble_brcm_find_resolving_pending_entry(
-          p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY) == false) {
+      !btm_ble_brcm_find_resolving_pending_entry(
+          p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY)) {
     btm_ble_update_resolving_list(p_dev_rec->bd_addr, false);
     btm_ble_remove_resolving_list_entry(p_dev_rec);
   } else {
diff --git a/stack/btm/btm_dev.cc b/stack/btm/btm_dev.cc
index 0fe5c20..5368fad 100644
--- a/stack/btm/btm_dev.cc
+++ b/stack/btm/btm_dev.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -68,6 +68,8 @@
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
   if (!p_dev_rec) {
     p_dev_rec = btm_sec_allocate_dev_rec();
+    BTM_TRACE_API("%s: allocated p_dev_rec=%p, bd_addr=%s", __func__, p_dev_rec,
+                  bd_addr.ToString().c_str());
 
     p_dev_rec->bd_addr = bd_addr;
     p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
@@ -225,10 +227,12 @@
  ******************************************************************************/
 tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr) {
   tBTM_INQ_INFO* p_inq_info;
-  BTM_TRACE_EVENT("btm_sec_alloc_dev");
 
   tBTM_SEC_DEV_REC* p_dev_rec = btm_sec_allocate_dev_rec();
 
+  BTM_TRACE_EVENT("%s: allocated p_dev_rec=%p, bd_addr=%s", __func__, p_dev_rec,
+                  bd_addr.ToString().c_str());
+
   /* Check with the BT manager if details about remote device are known */
   /* outgoing connection */
   p_inq_info = BTM_InqDbRead(bd_addr);
@@ -410,6 +414,8 @@
 
       /* remove the combined record */
       list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+      // p_dev_rec gets freed in list_remove, we should not  access it further
+      continue;
     }
 
     /* an RPA device entry is a duplicate of the target record */
diff --git a/stack/btm/btm_devctl.cc b/stack/btm/btm_devctl.cc
index 4910315..2e425aa 100644
--- a/stack/btm/btm_devctl.cc
+++ b/stack/btm/btm_devctl.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -117,7 +117,6 @@
  ******************************************************************************/
 static void btm_db_reset(void) {
   tBTM_CMPL_CB* p_cb;
-  tBTM_STATUS status = BTM_DEV_RESET;
 
   btm_inq_db_reset();
 
@@ -132,21 +131,33 @@
     p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
     btm_cb.devcb.p_rssi_cmpl_cb = NULL;
 
-    if (p_cb) (*p_cb)((tBTM_RSSI_RESULT*)&status);
+    if (p_cb) {
+      tBTM_RSSI_RESULT btm_rssi_result;
+      btm_rssi_result.status = BTM_DEV_RESET;
+      (*p_cb)(&btm_rssi_result);
+    }
   }
 
   if (btm_cb.devcb.p_failed_contact_counter_cmpl_cb) {
     p_cb = btm_cb.devcb.p_failed_contact_counter_cmpl_cb;
     btm_cb.devcb.p_failed_contact_counter_cmpl_cb = NULL;
 
-    if (p_cb) (*p_cb)((tBTM_FAILED_CONTACT_COUNTER_RESULT*)&status);
+    if (p_cb) {
+      tBTM_FAILED_CONTACT_COUNTER_RESULT btm_failed_contact_counter_result;
+      btm_failed_contact_counter_result.status = BTM_DEV_RESET;
+      (*p_cb)(&btm_failed_contact_counter_result);
+    }
   }
 
   if (btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb) {
     p_cb = btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb;
     btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb = NULL;
 
-    if (p_cb) (*p_cb)((tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT*)&status);
+    if (p_cb) {
+      tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT btm_automatic_flush_timeout_result;
+      btm_automatic_flush_timeout_result.status = BTM_DEV_RESET;
+      (*p_cb)(&btm_automatic_flush_timeout_result);
+    }
   }
 }
 
@@ -607,7 +618,7 @@
  *
  ******************************************************************************/
 void btm_vsc_complete(uint8_t* p, uint16_t opcode, uint16_t evt_len,
-                      tBTM_CMPL_CB* p_vsc_cplt_cback) {
+                      tBTM_VSC_CMPL_CB* p_vsc_cplt_cback) {
   tBTM_VSC_CMPL vcs_cplt_params;
 
   /* If there was a callback address for vcs complete, call it */
@@ -647,7 +658,7 @@
       free_idx = i;
     } else if (btm_cb.devcb.p_vend_spec_cb[i] == p_cb) {
       /* Found callback in lookup table. If deregistering, clear the entry. */
-      if (is_register == false) {
+      if (!is_register) {
         btm_cb.devcb.p_vend_spec_cb[i] = NULL;
         BTM_TRACE_EVENT("BTM Deregister For VSEvents is successfully");
       }
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index 213683c..bdcce38 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2014 Broadcom Corporation
+ *  Copyright 1999-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -43,6 +43,8 @@
 #include "hcidefs.h"
 #include "hcimsgs.h"
 
+using bluetooth::Uuid;
+
 /* 3 second timeout waiting for responses */
 #define BTM_INQ_REPLY_TIMEOUT_MS (3 * 1000)
 
@@ -121,8 +123,6 @@
                                             uint8_t uuid_size,
                                             uint8_t* p_num_uuid,
                                             uint8_t* p_uuid_list_type);
-static uint16_t btm_convert_uuid_to_uuid16(const uint8_t* p_uuid,
-                                           uint8_t uuid_size);
 
 /*******************************************************************************
  *
@@ -502,7 +502,7 @@
   /* Only cancel if one is active */
   if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
     btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE;
-    btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB*)NULL;
+    btm_cb.btm_inq_vars.p_inq_results_cb = NULL;
 
     btsnd_hcic_exit_per_inq();
 
@@ -649,9 +649,6 @@
 tBTM_STATUS BTM_CancelInquiry(void) {
   tBTM_STATUS status = BTM_SUCCESS;
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  uint8_t active_mode = p_inq->inq_active;
-#endif
   BTM_TRACE_API("BTM_CancelInquiry called");
 
   /*** Make sure the device is ready ***/
@@ -663,10 +660,8 @@
       (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))) {
     p_inq->inq_active = BTM_INQUIRY_INACTIVE;
     p_inq->state = BTM_INQ_INACTIVE_STATE;
-    p_inq->p_inq_results_cb =
-        (tBTM_INQ_RESULTS_CB*)NULL; /* Do not notify caller anymore */
-    p_inq->p_inq_cmpl_cb =
-        (tBTM_CMPL_CB*)NULL; /* Do not notify caller anymore */
+    p_inq->p_inq_results_cb = NULL; /* Do not notify caller anymore */
+    p_inq->p_inq_cmpl_cb = NULL;    /* Do not notify caller anymore */
 
     /* If the event filter is in progress, mark it so that the processing of the
        return
@@ -677,18 +672,10 @@
     }
     /* Initiate the cancel inquiry */
     else {
-      if (((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0)
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-          && (active_mode & BTM_BR_INQUIRY_MASK)
-#endif
-              ) {
+      if ((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0) {
         btsnd_hcic_inq_cancel();
       }
-      if (((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-          && (active_mode & BTM_BLE_INQ_ACTIVE_MASK)
-#endif
-              )
+      if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
         btm_ble_stop_inquiry();
     }
 
@@ -744,7 +731,6 @@
 tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
                              tBTM_INQ_RESULTS_CB* p_results_cb,
                              tBTM_CMPL_CB* p_cmpl_cb) {
-  tBTM_STATUS status = BTM_CMD_STARTED;
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
 
   BTM_TRACE_API("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
@@ -756,31 +742,34 @@
   if (p_inq->inq_active || p_inq->inqfilt_active) {
     /*check if LE observe is already running*/
     if (p_inq->scan_type == INQ_LE_OBSERVE &&
-        p_inq->p_inq_ble_results_cb != NULL) {
+        p_inq->p_inq_ble_results_cb != nullptr) {
       BTM_TRACE_API("BTM_StartInquiry: LE observe in progress");
       p_inq->scan_type = INQ_GENERAL;
       p_inq->inq_active = BTM_INQUIRY_INACTIVE;
       btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
       btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
     } else {
-      BTM_TRACE_API("BTM_StartInquiry: return BUSY");
+      LOG(ERROR) << __func__ << ": BTM_BUSY";
       return (BTM_BUSY);
     }
-  } else
+  } else {
     p_inq->scan_type = INQ_GENERAL;
+  }
 
   /*** Make sure the device is ready ***/
-  if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+  if (!BTM_IsDeviceUp()) {
+    LOG(ERROR) << __func__ << ": adapter is not up";
+    return BTM_WRONG_MODE;
+  }
 
   if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_GENERAL_INQUIRY &&
       (p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_LIMITED_INQUIRY &&
       (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_GENERAL_INQUIRY &&
-      (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_LIMITED_INQUIRY)
+      (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_LIMITED_INQUIRY) {
+    LOG(ERROR) << __func__ << ": illegal inquiry mode "
+               << std::to_string(p_inqparms->mode);
     return (BTM_ILLEGAL_VALUE);
-
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  if (p_inq->next_state == BTM_FINISH) return BTM_ILLEGAL_VALUE;
-#endif
+  }
 
   /* Save the inquiry parameters to be used upon the completion of
    * setting/clearing the inquiry filter */
@@ -796,136 +785,70 @@
   BTM_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x",
                   p_inq->inq_active);
 
-/* interleave scan minimal conditions */
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-
-  /* check if both modes are present */
-  if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) &&
-      (p_inqparms->mode & BTM_BR_INQUIRY_MASK)) {
-    BTM_TRACE_API("BTM:Interleave Inquiry Mode Set");
-    p_inqparms->duration = p_inqparms->intl_duration[p_inq->next_state];
-    p_inq->inqparms.duration = p_inqparms->duration;
-  } else {
-    BTM_TRACE_API("BTM:Single Mode: No interleaving, Mode:0x%02x",
-                  p_inqparms->mode);
-    p_inq->next_state = BTM_NO_INTERLEAVING;
-  }
-#endif
-
+  tBTM_STATUS status = BTM_CMD_STARTED;
   /* start LE inquiry here if requested */
-  if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-      &&
-      (p_inq->next_state == BTM_BLE_ONE || p_inq->next_state == BTM_BLE_TWO ||
-       p_inq->next_state == BTM_NO_INTERLEAVING)
-#endif
-          )
-
-  {
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-    p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK);
-    BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x",
-                  p_inqparms->duration,
-                  (p_inqparms->mode & BTM_BLE_INQUIRY_MASK));
-#endif
+  if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)) {
     if (!controller_get_interface()->supports_ble()) {
+      LOG(ERROR) << __func__ << ": trying to do LE scan on a non-LE adapter";
       p_inq->inqparms.mode &= ~BTM_BLE_INQUIRY_MASK;
       status = BTM_ILLEGAL_VALUE;
-    }
-    /* BLE for now does not support filter condition for inquiry */
-    else {
+    } else {
+      /* BLE for now does not support filter condition for inquiry */
       status = btm_ble_start_inquiry(
           (uint8_t)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
           p_inqparms->duration);
       if (status != BTM_CMD_STARTED) {
-        BTM_TRACE_ERROR("Err Starting LE Inquiry.");
+        LOG(ERROR) << __func__ << ": Error Starting LE Inquiry";
         p_inq->inqparms.mode &= ~BTM_BLE_INQUIRY_MASK;
       }
     }
-#if (BTA_HOST_INTERLEAVE_SEARCH == FALSE)
     p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
-#endif
-
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-    if (p_inq->next_state == BTM_NO_INTERLEAVING) {
-      p_inq->next_state = BTM_FINISH;
-    } else {
-      BTM_TRACE_API(
-          "BTM:Interleaving: started LE scan, Advancing to next state: %d",
-          p_inq->next_state + 1);
-      p_inq->next_state += 1;
-    }
-    /* reset next_state if status <> BTM_Started */
-    if (status != BTM_CMD_STARTED) p_inq->next_state = BTM_BR_ONE;
-
-    /* if interleave scan..return here */
-    return status;
-#endif
 
     BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
   }
 
   /* we're done with this routine if BR/EDR inquiry is not desired. */
-  if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE)
+  if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE) {
     return status;
+  }
 
-/* BR/EDR inquiry portion */
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  if ((p_inq->next_state == BTM_BR_ONE || p_inq->next_state == BTM_BR_TWO ||
-       p_inq->next_state == BTM_NO_INTERLEAVING)) {
-    p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK);
-#endif
-    /* If a filter is specified, then save it for later and clear the current
-       filter.
-       The setting of the filter is done upon completion of clearing of the
-       previous
-       filter.
-    */
-    switch (p_inqparms->filter_cond_type) {
-      case BTM_CLR_INQUIRY_FILTER:
-        p_inq->state = BTM_INQ_SET_FILT_STATE;
-        break;
+  /* BR/EDR inquiry portion */
+  /* If a filter is specified, then save it for later and clear the current
+     filter.
+     The setting of the filter is done upon completion of clearing of the
+     previous
+     filter.
+  */
+  switch (p_inqparms->filter_cond_type) {
+    case BTM_CLR_INQUIRY_FILTER:
+      p_inq->state = BTM_INQ_SET_FILT_STATE;
+      break;
 
-      case BTM_FILTER_COND_DEVICE_CLASS:
-      case BTM_FILTER_COND_BD_ADDR:
-        /* The filter is not being used so simply clear it;
-            the inquiry can start after this operation */
-        p_inq->state = BTM_INQ_CLR_FILT_STATE;
-        p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
-        /* =============>>>> adding LE filtering here ????? */
-        break;
+    case BTM_FILTER_COND_DEVICE_CLASS:
+    case BTM_FILTER_COND_BD_ADDR:
+      /* The filter is not being used so simply clear it;
+          the inquiry can start after this operation */
+      p_inq->state = BTM_INQ_CLR_FILT_STATE;
+      p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+      /* =============>>>> adding LE filtering here ????? */
+      break;
 
-      default:
-        return (BTM_ILLEGAL_VALUE);
+    default:
+      LOG(ERROR) << __func__ << ": invalid filter condition type "
+                 << std::to_string(p_inqparms->filter_cond_type);
+      return (BTM_ILLEGAL_VALUE);
     }
 
     /* Before beginning the inquiry the current filter must be cleared, so
      * initiate the command */
     status = btm_set_inq_event_filter(p_inqparms->filter_cond_type,
                                       &p_inqparms->filter_cond);
-    if (status != BTM_CMD_STARTED) p_inq->state = BTM_INQ_INACTIVE_STATE;
-
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-    if (p_inq->next_state == BTM_NO_INTERLEAVING)
-      p_inq->next_state = BTM_FINISH;
-    else {
-      BTM_TRACE_API(
-          "BTM:Interleaving: Started BTM inq, Advancing to next state: %d",
-          p_inq->next_state + 1);
-      p_inq->next_state += 1;
+    if (status != BTM_CMD_STARTED) {
+      LOG(ERROR) << __func__ << ": failed to set inquiry event filter";
+      p_inq->state = BTM_INQ_INACTIVE_STATE;
     }
-  }
-  if (status != BTM_CMD_STARTED) {
-    /* Some error beginning the scan process.
-       Reset the next_state parameter.. Do we need to reset the inq_active also?
-    */
-    BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x",
-                  status);
-    p_inq->next_state = BTM_BR_ONE;
-  }
-#endif
 
-  return (status);
+    return (status);
 }
 
 /*******************************************************************************
@@ -1532,7 +1455,7 @@
 
   /* Only process the inquiry filter; Ignore the connection filter until it
      is used by the upper layers */
-  if (p_inq->inqfilt_active == true) {
+  if (p_inq->inqfilt_active) {
     /* Extract the returned status from the buffer */
     STREAM_TO_UINT8(hci_status, p);
     if (hci_status != HCI_SUCCESS) {
@@ -1804,7 +1727,7 @@
     else
       p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI;
 
-    if (is_new == true) {
+    if (is_new) {
       /* Save the info */
       p_cur = &p_i->inq_info.results;
       p_cur->page_scan_rep_mode = page_scan_rep_mode;
@@ -1861,7 +1784,8 @@
 
       /* If a callback is registered, call it with the results */
       if (p_inq_results_cb)
-        (p_inq_results_cb)((tBTM_INQ_RESULTS*)p_cur, p_eir_data, 62);
+        (p_inq_results_cb)((tBTM_INQ_RESULTS*)p_cur, p_eir_data,
+                           HCI_EXT_INQ_RESPONSE_LEN);
     }
   }
 }
@@ -1920,27 +1844,12 @@
   tBTM_CMPL_CB* p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
 
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  /* inquiry inactive case happens when inquiry is cancelled.
-     Make mode 0 for no further inquiries from the current inquiry process
-  */
-  if (status != HCI_SUCCESS || p_inq->next_state == BTM_FINISH ||
-      !p_inq->inq_active) {
-    /* re-initialize for next inquiry request */
-    p_inq->next_state = BTM_BR_ONE;
-    /* make the mode 0 here */
-    p_inq->inqparms.mode &= ~(p_inq->inqparms.mode);
-  }
-#endif
-
-#if (BTA_HOST_INTERLEAVE_SEARCH == FALSE)
   p_inq->inqparms.mode &= ~(mode);
-#endif
 
   if (p_inq->scan_type == INQ_LE_OBSERVE && !p_inq->inq_active) {
     /*end of LE observe*/
-    p_inq->p_inq_ble_results_cb = (tBTM_INQ_RESULTS_CB*)NULL;
-    p_inq->p_inq_ble_cmpl_cb = (tBTM_CMPL_CB*)NULL;
+    p_inq->p_inq_ble_results_cb = NULL;
+    p_inq->p_inq_ble_cmpl_cb = NULL;
     p_inq->scan_type = INQ_NONE;
   }
 
@@ -1974,9 +1883,9 @@
       }
 
       /* Clear the results callback if set */
-      p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB*)NULL;
+      p_inq->p_inq_results_cb = NULL;
       p_inq->inq_active = BTM_INQUIRY_INACTIVE;
-      p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB*)NULL;
+      p_inq->p_inq_cmpl_cb = NULL;
 
       /* If we have a callback registered for inquiry complete, call it */
       BTM_TRACE_DEBUG("BTM Inq Compl Callback: status 0x%02x, num results %d",
@@ -1985,16 +1894,6 @@
 
       if (p_inq_cb) (p_inq_cb)((tBTM_INQUIRY_CMPL*)&p_inq->inq_cmpl_info);
     }
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-    if (p_inq->inqparms.mode != 0 &&
-        !(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)) {
-      /* make inquiry inactive for next iteration */
-      p_inq->inq_active = BTM_INQUIRY_INACTIVE;
-      /* call the inquiry again */
-      BTM_StartInquiry(&p_inq->inqparms, p_inq->p_inq_results_cb,
-                       p_inq->p_inq_cmpl_cb);
-    }
-#endif
   }
   if (p_inq->inqparms.mode == 0 &&
       p_inq->scan_type == INQ_GENERAL)  // this inquiry is complete
@@ -2127,8 +2026,7 @@
 
   /* If the inquire BDA and remote DBA are the same, then stop the timer and set
    * the active to false */
-  if ((p_inq->remname_active == true) &&
-      (!bda || (*bda == p_inq->remname_bda))) {
+  if ((p_inq->remname_active) && (!bda || (*bda == p_inq->remname_bda))) {
     if (BTM_UseLeLink(p_inq->remname_bda)) {
       if (hci_status == HCI_ERR_UNSPECIFIED)
         btm_ble_cancel_remote_name(p_inq->remname_bda);
@@ -2167,7 +2065,7 @@
     p_inq->remname_bda = RawAddress::kEmpty;
 
     p_inq->p_remname_cmpl_cb = NULL;
-    if (p_cb) (p_cb)((tBTM_REMOTE_DEV_NAME*)&rem_name);
+    if (p_cb) (p_cb)(&rem_name);
   }
 }
 
@@ -2309,7 +2207,7 @@
  *                  false - if not found
  *
  ******************************************************************************/
-bool BTM_HasEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
+bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) {
   uint8_t service_id;
 
   service_id = btm_convert_uuid_to_eir_service(uuid16);
@@ -2433,7 +2331,8 @@
  *
  * Parameters       p_eir - EIR
  *                  eir_len - EIR len
- *                  uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+ *                  uuid_size - Uuid::kNumBytes16, Uuid::kNumBytes32,
+ *                              Uuid::kNumBytes128
  *                  p_num_uuid - return number of UUID in found list
  *                  p_uuid_list - return UUID list
  *                  max_num_uuid - maximum number of UUID to be returned
@@ -2455,7 +2354,7 @@
   uint8_t yy, xx;
   uint16_t* p_uuid16 = (uint16_t*)p_uuid_list;
   uint32_t* p_uuid32 = (uint32_t*)p_uuid_list;
-  char buff[LEN_UUID_128 * 2 + 1];
+  char buff[Uuid::kNumBytes128 * 2 + 1];
 
   p_uuid_data =
       btm_eir_get_uuid_list(p_eir, eir_len, uuid_size, p_num_uuid, &type);
@@ -2472,22 +2371,22 @@
   BTM_TRACE_DEBUG("%s: type = %02X, number of uuid = %d", __func__, type,
                   *p_num_uuid);
 
-  if (uuid_size == LEN_UUID_16) {
+  if (uuid_size == Uuid::kNumBytes16) {
     for (yy = 0; yy < *p_num_uuid; yy++) {
       STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data);
       BTM_TRACE_DEBUG("                     0x%04X", *(p_uuid16 + yy));
     }
-  } else if (uuid_size == LEN_UUID_32) {
+  } else if (uuid_size == Uuid::kNumBytes32) {
     for (yy = 0; yy < *p_num_uuid; yy++) {
       STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data);
       BTM_TRACE_DEBUG("                     0x%08X", *(p_uuid32 + yy));
     }
-  } else if (uuid_size == LEN_UUID_128) {
+  } else if (uuid_size == Uuid::kNumBytes128) {
     for (yy = 0; yy < *p_num_uuid; yy++) {
-      STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data);
-      for (xx = 0; xx < LEN_UUID_128; xx++)
+      STREAM_TO_ARRAY16(p_uuid_list + yy * Uuid::kNumBytes128, p_uuid_data);
+      for (xx = 0; xx < Uuid::kNumBytes128; xx++)
         snprintf(buff + xx * 2, sizeof(buff) - xx * 2, "%02X",
-                 *(p_uuid_list + yy * LEN_UUID_128 + xx));
+                 *(p_uuid_list + yy * Uuid::kNumBytes128 + xx));
       BTM_TRACE_DEBUG("                     0x%s", buff);
     }
   }
@@ -2520,15 +2419,15 @@
   uint8_t uuid_len;
 
   switch (uuid_size) {
-    case LEN_UUID_16:
+    case Uuid::kNumBytes16:
       complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
       more_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
       break;
-    case LEN_UUID_32:
+    case Uuid::kNumBytes32:
       complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
       more_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
       break;
-    case LEN_UUID_128:
+    case Uuid::kNumBytes128:
       complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
       more_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
       break;
@@ -2567,7 +2466,7 @@
  ******************************************************************************/
 static uint16_t btm_convert_uuid_to_uuid16(const uint8_t* p_uuid,
                                            uint8_t uuid_size) {
-  static const uint8_t base_uuid[LEN_UUID_128] = {
+  static const uint8_t base_uuid[Uuid::kNumBytes128] = {
       0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
   uint16_t uuid16 = 0;
@@ -2576,26 +2475,26 @@
   uint8_t xx;
 
   switch (uuid_size) {
-    case LEN_UUID_16:
+    case Uuid::kNumBytes16:
       STREAM_TO_UINT16(uuid16, p_uuid);
       break;
-    case LEN_UUID_32:
+    case Uuid::kNumBytes32:
       STREAM_TO_UINT32(uuid32, p_uuid);
       if (uuid32 < 0x10000) uuid16 = (uint16_t)uuid32;
       break;
-    case LEN_UUID_128:
+    case Uuid::kNumBytes128:
       /* See if we can compress his UUID down to 16 or 32bit UUIDs */
       is_base_uuid = true;
-      for (xx = 0; xx < LEN_UUID_128 - 4; xx++) {
+      for (xx = 0; xx < Uuid::kNumBytes128 - 4; xx++) {
         if (p_uuid[xx] != base_uuid[xx]) {
           is_base_uuid = false;
           break;
         }
       }
       if (is_base_uuid) {
-        if ((p_uuid[LEN_UUID_128 - 1] == 0) &&
-            (p_uuid[LEN_UUID_128 - 2] == 0)) {
-          p_uuid += (LEN_UUID_128 - 4);
+        if ((p_uuid[Uuid::kNumBytes128 - 1] == 0) &&
+            (p_uuid[Uuid::kNumBytes128 - 2] == 0)) {
+          p_uuid += (Uuid::kNumBytes128 - 4);
           STREAM_TO_UINT16(uuid16, p_uuid);
         }
       }
@@ -2629,7 +2528,7 @@
   uint8_t type = BTM_EIR_MORE_16BITS_UUID_TYPE;
 
   p_uuid_data = btm_eir_get_uuid_list(p_eir, HCI_EXT_INQ_RESPONSE_LEN,
-                                      LEN_UUID_16, &num_uuid, &type);
+                                      Uuid::kNumBytes16, &num_uuid, &type);
 
   if (type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE) {
     p_results->eir_complete_list = true;
@@ -2648,21 +2547,21 @@
   }
 
   p_uuid_data = btm_eir_get_uuid_list(p_eir, HCI_EXT_INQ_RESPONSE_LEN,
-                                      LEN_UUID_32, &num_uuid, &type);
+                                      Uuid::kNumBytes32, &num_uuid, &type);
   if (p_uuid_data) {
     for (yy = 0; yy < num_uuid; yy++) {
-      uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, LEN_UUID_32);
-      p_uuid_data += LEN_UUID_32;
+      uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, Uuid::kNumBytes32);
+      p_uuid_data += Uuid::kNumBytes32;
       if (uuid16) BTM_AddEirService(p_results->eir_uuid, uuid16);
     }
   }
 
   p_uuid_data = btm_eir_get_uuid_list(p_eir, HCI_EXT_INQ_RESPONSE_LEN,
-                                      LEN_UUID_128, &num_uuid, &type);
+                                      Uuid::kNumBytes128, &num_uuid, &type);
   if (p_uuid_data) {
     for (yy = 0; yy < num_uuid; yy++) {
-      uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, LEN_UUID_128);
-      p_uuid_data += LEN_UUID_128;
+      uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, Uuid::kNumBytes128);
+      p_uuid_data += Uuid::kNumBytes128;
       if (uuid16) BTM_AddEirService(p_results->eir_uuid, uuid16);
     }
   }
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index e6e0dff..21f7ce3 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@
  *******************************************
 */
 extern void btm_init(void);
+extern void btm_free(void);
 
 /* Internal functions provided by btm_inq.cc
  ******************************************
@@ -184,6 +185,7 @@
 extern void btm_ble_remove_from_white_list_complete(uint8_t* p,
                                                     uint16_t evt_len);
 extern void btm_ble_clear_white_list_complete(uint8_t* p, uint16_t evt_len);
+extern void btm_ble_create_conn_cancel_complete(uint8_t* p);
 extern bool btm_ble_addr_resolvable(const RawAddress& rpa,
                                     tBTM_SEC_DEV_REC* p_dev_rec);
 extern tBTM_STATUS btm_ble_read_resolving_list_entry(
@@ -193,7 +195,7 @@
 
 /* Vendor Specific Command complete evt handler */
 extern void btm_vsc_complete(uint8_t* p, uint16_t cc_opcode, uint16_t evt_len,
-                             tBTM_CMPL_CB* p_vsc_cplt_cback);
+                             tBTM_VSC_CMPL_CB* p_vsc_cplt_cback);
 extern void btm_inq_db_reset(void);
 extern void btm_vendor_specific_evt(uint8_t* p, uint8_t evt_len);
 extern void btm_delete_stored_link_key_complete(uint8_t* p);
@@ -287,5 +289,6 @@
 extern void btm_acl_paging(BT_HDR* p, const RawAddress& dest);
 extern uint8_t btm_sec_clr_service_by_psm(uint16_t psm);
 extern void btm_sec_clr_temp_auth_service(const RawAddress& bda);
+extern tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec);
 
 #endif
diff --git a/stack/btm/btm_int_types.h b/stack/btm/btm_int_types.h
index c633cf0..8f91cef 100644
--- a/stack/btm/btm_int_types.h
+++ b/stack/btm/btm_int_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -291,10 +291,6 @@
   uint8_t state;      /* Current state that the inquiry process is in */
   uint8_t inq_active; /* Bit Mask indicating type of inquiry is active */
   bool no_inc_ssp;    /* true, to stop inquiry on incoming SSP */
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  btm_inq_state
-      next_state; /*interleaving state to determine next mode to be inquired*/
-#endif
 } tBTM_INQUIRY_VAR_ST;
 
 /* The MSB of the clock offset field indicates whether the offset is valid. */
@@ -354,9 +350,6 @@
 */
 typedef struct {
   tBTM_ESCO_INFO esco; /* Current settings             */
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  fixed_queue_t* xmit_data_q; /* SCO data transmitting queue  */
-#endif
   tBTM_SCO_CB* p_conn_cb; /* Callback for when connected  */
   tBTM_SCO_CB* p_disc_cb; /* Callback for when disconnect */
   uint16_t state;         /* The state of the SCO link    */
@@ -369,9 +362,6 @@
 /* SCO Management control block */
 typedef struct {
   tBTM_SCO_IND_CBACK* app_sco_ind_cb;
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  tBTM_SCO_DATA_CB* p_data_cb; /* Callback for SCO data over HCI */
-#endif
   tSCO_CONN sco_db[BTM_MAX_SCO_LINKS];
   enh_esco_params_t def_esco_parms;
   uint16_t sco_disc_reason;
@@ -417,10 +407,6 @@
   uint16_t psm;             /* L2CAP PSM value */
   uint16_t security_flags;  /* Bitmap of required security features */
   uint8_t service_id;       /* Passed in authorization callback */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  uint16_t
-      ucd_security_flags; /* Bitmap of required security features for UCD */
-#endif
 #if BTM_SEC_SERVICE_NAME_LEN > 0
   uint8_t orig_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
   uint8_t term_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
@@ -538,10 +524,6 @@
 
   uint8_t sec_state;  /* Operating state                    */
   bool is_originator; /* true if device is originating connection */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  bool is_ucd; /* true if device is sending or receiving UCD */
-               /* if incoming security failed, received UCD will be discarded */
-#endif
   bool role_master;           /* true if current mode is master     */
   uint16_t security_required; /* Security required for connection   */
   bool link_key_not_sent; /* link key notification has not been sent waiting for
@@ -746,26 +728,10 @@
   tBTM_BLE_SEC_ACT sec_act;
 } tBTM_SEC_QUEUE_ENTRY;
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-
-#define CONN_ORIENT_TERM 0x00          /* incoming connection oriented */
-#define CONN_ORIENT_ORIG 0x01          /* outgoing connection oriented */
-#define CONNLESS_TERM 0x02             /* incoming connectionless      */
-#define CONNLESS_ORIG 0x03             /* outgoing connectionless      */
-#define CONNECTION_TYPE_ORIG_MASK 0x01 /* mask for direction           */
-#define CONNECTION_TYPE_CONNLESS_MASK    \
-  0x02 /* mask for connectionless or not \
-          */
-typedef uint8_t CONNECTION_TYPE;
-
-#else
-
 #define CONN_ORIENT_TERM false
 #define CONN_ORIENT_ORIG true
 typedef bool CONNECTION_TYPE;
 
-#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
-
 /* Define a structure to hold all the BTM data
 */
 
diff --git a/stack/btm/btm_main.cc b/stack/btm/btm_main.cc
index 70f3ee4..011feb7 100644
--- a/stack/btm/btm_main.cc
+++ b/stack/btm/btm_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -74,3 +74,21 @@
 
   btm_dev_init(); /* Device Manager Structures & HCI_Reset */
 }
+
+/** This function is called to free dynamic memory and system resource allocated by btm_init */
+void btm_free(void) {
+  fixed_queue_free(btm_cb.page_queue, NULL);
+  btm_cb.page_queue = NULL;
+
+  fixed_queue_free(btm_cb.sec_pending_q, NULL);
+  btm_cb.sec_pending_q = NULL;
+
+  list_free(btm_cb.sec_dev_rec);
+  btm_cb.sec_dev_rec = NULL;
+
+  alarm_free(btm_cb.sec_collision_timer);
+  btm_cb.sec_collision_timer = NULL;
+
+  alarm_free(btm_cb.pairing_timer);
+  btm_cb.pairing_timer = NULL;
+}
diff --git a/stack/btm/btm_pm.cc b/stack/btm/btm_pm.cc
index aeb5170..af06c1b 100644
--- a/stack/btm/btm_pm.cc
+++ b/stack/btm/btm_pm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
 #include "bt_utils.h"
 #include "btm_api.h"
 #include "btm_int.h"
+#include "btm_int_types.h"
 #include "btu.h"
 #include "hcidefs.h"
 #include "hcimsgs.h"
@@ -74,8 +75,8 @@
 /* function prototype */
 static int btm_pm_find_acl_ind(const RawAddress& remote_bda);
 static tBTM_STATUS btm_pm_snd_md_req(uint8_t pm_id, int link_ind,
-                                     tBTM_PM_PWR_MD* p_mode);
-static const char* mode_to_string(tBTM_PM_MODE mode);
+                                     const tBTM_PM_PWR_MD* p_mode);
+static const char* mode_to_string(const tBTM_PM_MODE mode);
 
 #if (BTM_PM_DEBUG == TRUE)
 const char* btm_pm_state_str[] = {"pm_active_state", "pm_hold_state",
@@ -144,19 +145,25 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
-                             tBTM_PM_PWR_MD* p_mode) {
+                             const tBTM_PM_PWR_MD* p_mode) {
   uint8_t* p_features;
   int ind, acl_ind;
-  tBTM_PM_MCB* p_cb = NULL; /* per ACL link */
+  tBTM_PM_MCB* p_cb = nullptr; /* per ACL link */
   tBTM_PM_MODE mode;
   int temp_pm_id;
 
-  if (pm_id >= BTM_MAX_PM_RECORDS) pm_id = BTM_PM_SET_ONLY_ID;
+  if (pm_id >= BTM_MAX_PM_RECORDS) {
+    pm_id = BTM_PM_SET_ONLY_ID;
+  }
 
-  if (p_mode == NULL) return BTM_ILLEGAL_VALUE;
+  if (!p_mode) {
+    LOG(ERROR) << __func__ << ": pm_id " << unsigned(pm_id)
+               << " p_mode is null for " << remote_bda;
+    return BTM_ILLEGAL_VALUE;
+  }
 
   VLOG(2) << __func__ << " pm_id " << pm_id << " BDA: " << remote_bda
-          << " mode:0x" << std::hex << p_mode->mode;
+          << " mode:" << std::to_string(p_mode->mode);
 
   /* take out the force bit */
   mode = p_mode->mode & ~BTM_PM_MD_FORCE;
@@ -170,12 +177,14 @@
     /* check if the requested mode is supported */
     ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
     p_features = BTM_ReadLocalFeatures();
-    if (!(p_features[btm_pm_mode_off[ind]] & btm_pm_mode_msk[ind]))
+    if (!(p_features[btm_pm_mode_off[ind]] & btm_pm_mode_msk[ind])) {
+      LOG(ERROR) << __func__ << ": pm_id " << unsigned(pm_id) << " mode "
+                 << unsigned(mode) << " is not supported for " << remote_bda;
       return BTM_MODE_UNSUPPORTED;
+    }
   }
 
-  if (mode == p_cb->state) /* the requested mode is current mode */
-  {
+  if (mode == p_cb->state) {
     /* already in the requested mode and the current interval has less latency
      * than the max */
     if ((mode == BTM_PM_MD_ACTIVE) ||
@@ -183,14 +192,17 @@
          (p_mode->min <= p_cb->interval)) ||
         ((p_mode->mode & BTM_PM_MD_FORCE) == 0 &&
          (p_mode->max >= p_cb->interval))) {
-      BTM_TRACE_DEBUG("BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d",
-                      p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
+      VLOG(1) << __func__ << " already in requested mode "
+              << std::to_string(p_mode->mode) << ", interval " << p_cb->interval
+              << " max " << p_mode->max << " min " << p_mode->min;
       return BTM_SUCCESS;
     }
   }
 
   temp_pm_id = pm_id;
-  if (pm_id == BTM_PM_SET_ONLY_ID) temp_pm_id = BTM_MAX_PM_RECORDS;
+  if (pm_id == BTM_PM_SET_ONLY_ID) {
+    temp_pm_id = BTM_MAX_PM_RECORDS;
+  }
 
   /* update mode database */
   if (((pm_id != BTM_PM_SET_ONLY_ID) &&
@@ -203,7 +215,7 @@
 #endif  // BTM_PM_DEBUG
     /* Make sure mask is set to BTM_PM_REG_SET */
     btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
-    *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD*)p_mode);
+    *(&p_cb->req_mode[temp_pm_id]) = *p_mode;
     p_cb->chg_ind = true;
   }
 
@@ -213,12 +225,12 @@
 #endif  // BTM_PM_DEBUG
   /* if mode == hold or pending, return */
   if ((p_cb->state == BTM_PM_STS_HOLD) || (p_cb->state == BTM_PM_STS_PENDING) ||
-      (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) /* command pending */
-  {
+      (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) {
+    /* command pending */
     if (acl_ind != btm_cb.pm_pend_link) {
       /* set the stored mask */
       p_cb->state |= BTM_PM_STORED_MASK;
-      BTM_TRACE_DEBUG("btm_pm state stored:%d", acl_ind);
+      BTM_TRACE_DEBUG("%s: btm_pm state stored:%d", __func__, acl_ind);
     }
     return BTM_CMD_STORED;
   }
@@ -416,8 +428,8 @@
  * Returns      void
  *
  ******************************************************************************/
-static tBTM_PM_PWR_MD* btm_pm_compare_modes(tBTM_PM_PWR_MD* p_md1,
-                                            tBTM_PM_PWR_MD* p_md2,
+static tBTM_PM_PWR_MD* btm_pm_compare_modes(const tBTM_PM_PWR_MD* p_md1,
+                                            const tBTM_PM_PWR_MD* p_md2,
                                             tBTM_PM_PWR_MD* p_res) {
   uint8_t res;
 
@@ -425,7 +437,7 @@
     *p_res = *p_md2;
     p_res->mode &= ~BTM_PM_MD_FORCE;
 
-    return p_md2;
+    return p_res;
   }
 
   if (p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE) {
@@ -450,11 +462,11 @@
   switch (res) {
     case BTM_PM_GET_MD1:
       *p_res = *p_md1;
-      return p_md1;
+      return p_res;
 
     case BTM_PM_GET_MD2:
       *p_res = *p_md2;
-      return p_md2;
+      return p_res;
 
     case BTM_PM_GET_COMP:
       p_res->mode = p_md1->mode;
@@ -489,7 +501,7 @@
  *
  ******************************************************************************/
 static tBTM_PM_MODE btm_pm_get_set_mode(uint8_t pm_id, tBTM_PM_MCB* p_cb,
-                                        tBTM_PM_PWR_MD* p_mode,
+                                        const tBTM_PM_PWR_MD* p_mode,
                                         tBTM_PM_PWR_MD* p_res) {
   int xx, loop_max;
   tBTM_PM_PWR_MD* p_md = NULL;
@@ -547,7 +559,7 @@
  *, bool    *p_chg_ind
  ******************************************************************************/
 static tBTM_STATUS btm_pm_snd_md_req(uint8_t pm_id, int link_ind,
-                                     tBTM_PM_PWR_MD* p_mode) {
+                                     const tBTM_PM_PWR_MD* p_mode) {
   tBTM_PM_PWR_MD md_res;
   tBTM_PM_MODE mode;
   tBTM_PM_MCB* p_cb = &btm_cb.pm_mode_db[link_ind];
@@ -574,7 +586,7 @@
   if (mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
     p_cb->chg_ind = true; /* needs to wake, then sleep */
 
-  if (p_cb->chg_ind == true) /* needs to wake first */
+  if (p_cb->chg_ind) /* needs to wake first */
     md_res.mode = BTM_PM_MD_ACTIVE;
 #if (BTM_SSR_INCLUDED == TRUE)
   else if (BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat) {
@@ -785,7 +797,7 @@
     btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
   } else {
     for (zz = 0; zz < MAX_L2CAP_LINKS; zz++) {
-      if (btm_cb.pm_mode_db[zz].chg_ind == true) {
+      if (btm_cb.pm_mode_db[zz].chg_ind) {
 #if (BTM_PM_DEBUG == TRUE)
         BTM_TRACE_DEBUG("btm_pm_proc_mode_change: Sending PM req :%d", zz);
 #endif  // BTM_PM_DEBUG
@@ -928,15 +940,15 @@
  *
  ******************************************************************************/
 tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void) {
-  if (true == btm_pm_device_in_active_or_sniff_mode())
+  if (btm_pm_device_in_active_or_sniff_mode())
     return BTM_CONTRL_ACTIVE;
-  else if (true == btm_pm_device_in_scan_state())
+  else if (btm_pm_device_in_scan_state())
     return BTM_CONTRL_SCAN;
   else
     return BTM_CONTRL_IDLE;
 }
 
-static const char* mode_to_string(tBTM_PM_MODE mode) {
+static const char* mode_to_string(const tBTM_PM_MODE mode) {
   switch (mode) {
     case BTM_PM_MD_ACTIVE:
       return "ACTIVE";
diff --git a/stack/btm/btm_sco.cc b/stack/btm/btm_sco.cc
index dea830f..6e7f97c 100644
--- a/stack/btm/btm_sco.cc
+++ b/stack/btm/btm_sco.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +23,8 @@
  *
  ******************************************************************************/
 
+#include <device/include/esco_parameters.h>
+#include <stack/include/btm_api_types.h>
 #include <string.h>
 #include "bt_common.h"
 #include "bt_target.h"
@@ -30,6 +32,7 @@
 #include "bt_utils.h"
 #include "btm_api.h"
 #include "btm_int.h"
+#include "btm_int_types.h"
 #include "btu.h"
 #include "device/include/controller.h"
 #include "device/include/esco_parameters.h"
@@ -69,21 +72,8 @@
  * Returns          void
  *
  ******************************************************************************/
-#if (BTM_SCO_HCI_INCLUDED == TRUE && BTM_MAX_SCO_LINKS > 0)
-void btm_sco_flush_sco_data(uint16_t sco_inx) {
-  tSCO_CONN* p;
-  BT_HDR* p_buf;
-
-  if (sco_inx < BTM_MAX_SCO_LINKS) {
-    p = &btm_cb.sco_cb.sco_db[sco_inx];
-    while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p->xmit_data_q)) != NULL)
-      osi_free(p_buf);
-  }
-}
-}
-#else
 void btm_sco_flush_sco_data(UNUSED_ATTR uint16_t sco_inx) {}
-#endif
+
 /*******************************************************************************
  *
  * Function         btm_sco_init
@@ -94,10 +84,6 @@
  *
  ******************************************************************************/
 void btm_sco_init(void) {
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  for (int i = 0; i < BTM_MAX_SCO_LINKS; i++)
-    btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(SIZE_MAX);
-#endif
   /* Initialize nonzero defaults */
   btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
   btm_cb.sco_cb.def_esco_parms = esco_parameters_for_codec(ESCO_CODEC_CVSD);
@@ -205,35 +191,6 @@
 #endif
 }
 
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-/*******************************************************************************
- *
- * Function         btm_sco_check_send_pkts
- *
- * Description      This function is called to check if it can send packets
- *                  to the Host Controller.
- *
- * Returns          void
- *
- ******************************************************************************/
-void btm_sco_check_send_pkts(uint16_t sco_inx) {
-  tSCO_CB* p_cb = &btm_cb.sco_cb;
-  tSCO_CONN* p_ccb = &p_cb->sco_db[sco_inx];
-
-  /* If there is data to send, send it now */
-  BT_HDR* p_buf;
-  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) !=
-         NULL) {
-#if (BTM_SCO_HCI_DEBUG == TRUE)
-    BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
-                    fixed_queue_length(p_ccb->xmit_data_q) + 1);
-#endif
-
-    HCI_SCO_DATA_TO_LOWER(p_buf);
-  }
-}
-#endif /* BTM_SCO_HCI_INCLUDED == TRUE */
-
 /*******************************************************************************
  *
  * Function         btm_route_sco_data
@@ -244,36 +201,7 @@
  *
  ******************************************************************************/
 void btm_route_sco_data(BT_HDR* p_msg) {
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
-  uint16_t sco_inx, handle;
-  uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
-  uint8_t pkt_size = 0;
-  uint8_t pkt_status = 0;
-
-  /* Extract Packet_Status_Flag and handle */
-  STREAM_TO_UINT16(handle, p);
-  pkt_status = HCID_GET_EVENT(handle);
-  handle = HCID_GET_HANDLE(handle);
-
-  STREAM_TO_UINT8(pkt_size, p);
-
-  sco_inx = btm_find_scb_by_handle(handle);
-  if (sco_inx != BTM_MAX_SCO_LINKS) {
-    /* send data callback */
-    if (!btm_cb.sco_cb.p_data_cb)
-      /* if no data callback registered,  just free the buffer  */
-      osi_free(p_msg);
-    else {
-      (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg,
-                                 (tBTM_SCO_DATA_FLAG)pkt_status);
-    }
-  } else /* no mapping handle SCO connection is active, free the buffer */
-  {
-    osi_free(p_msg);
-  }
-#else
   osi_free(p_msg);
-#endif
 }
 
 /*******************************************************************************
@@ -297,58 +225,10 @@
  *
  *
  ******************************************************************************/
-#if (BTM_SCO_HCI_INCLUDED == TRUE && BTM_MAX_SCO_LINKS > 0)
-tBTM_STATUS BTM_WriteScoData(uint16_t sco_inx, BT_HDR* p_buf) {
-  tSCO_CONN* p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
-  uint8_t* p;
-  tBTM_STATUS status = BTM_SUCCESS;
-
-  if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb &&
-      p_ccb->state == SCO_ST_CONNECTED) {
-    /* Ensure we have enough space in the buffer for the SCO and HCI headers */
-    if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) {
-      BTM_TRACE_ERROR("BTM SCO - cannot send buffer, offset: %d",
-                      p_buf->offset);
-      osi_free(p_buf);
-      status = BTM_ILLEGAL_VALUE;
-    } else /* write HCI header */
-    {
-      /* Step back 3 bytes to add the headers */
-      p_buf->offset -= HCI_SCO_PREAMBLE_SIZE;
-      /* Set the pointer to the beginning of the data */
-      p = (uint8_t*)(p_buf + 1) + p_buf->offset;
-      /* add HCI handle */
-      UINT16_TO_STREAM(p, p_ccb->hci_handle);
-      /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max,
-         and set warning status */
-      if (p_buf->len > BTM_SCO_DATA_SIZE_MAX) {
-        p_buf->len = BTM_SCO_DATA_SIZE_MAX;
-        status = BTM_SCO_BAD_LENGTH;
-      }
-
-      UINT8_TO_STREAM(p, (uint8_t)p_buf->len);
-      p_buf->len += HCI_SCO_PREAMBLE_SIZE;
-
-      fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf);
-
-      btm_sco_check_send_pkts(sco_inx);
-    }
-  } else {
-    osi_free(p_buf);
-
-    BTM_TRACE_ERROR("%s:invalid sco index: %d at state [%d]", __func__, sco_inx,
-                    btm_cb.sco_cb.sco_db[sco_inx].state);
-    status = BTM_UNKNOWN_ADDR;
-  }
-
-  return status;
-}
-#else
 tBTM_STATUS BTM_WriteScoData(UNUSED_ATTR uint16_t sco_inx,
                              UNUSED_ATTR BT_HDR* p_buf) {
   return (BTM_NO_RESOURCES);
 }
-#endif
 
 #if (BTM_MAX_SCO_LINKS > 0)
 /*******************************************************************************
@@ -367,10 +247,13 @@
 
   /* Send connect request depending on version of spec */
   if (!btm_cb.sco_cb.esco_supported) {
+    LOG(INFO) << __func__ << ": sending non-eSCO request for handle="
+              << unsigned(acl_handle);
     btsnd_hcic_add_SCO_conn(acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types));
   } else {
     uint16_t temp_packet_types =
-        (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+        (p_setup->packet_types &
+         static_cast<uint16_t>(BTM_SCO_SUPPORTED_PKTS_MASK) &
          btm_cb.btm_sco_pkt_types_supported);
 
     /* OR in any exception packet types */
@@ -385,12 +268,12 @@
     if (acl_index < MAX_L2CAP_LINKS) {
       p_acl = &btm_cb.acl_db[acl_index];
       if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->peer_lmp_feature_pages[0])) {
-        BTM_TRACE_WARNING("BTM Remote does not support 2-EDR eSCO");
+        BTM_TRACE_DEBUG("BTM Remote does not support 2-EDR eSCO");
         temp_packet_types |=
             (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5);
       }
       if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->peer_lmp_feature_pages[0])) {
-        BTM_TRACE_WARNING("BTM Remote does not support 3-EDR eSCO");
+        BTM_TRACE_DEBUG("BTM Remote does not support 3-EDR eSCO");
         temp_packet_types |=
             (ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV5);
       }
@@ -405,15 +288,21 @@
 
         /* Return error if no packet types left */
         if (temp_packet_types == 0) {
-          BTM_TRACE_ERROR("%s: SCO Conn (BR/EDR SC): No packet types available",
-                          __func__);
+          LOG(ERROR) << __func__
+                     << ": SCO Conn (BR/EDR SC): No packet types available for "
+                        "acl_handle "
+                     << unsigned(acl_handle);
           return (BTM_WRONG_MODE);
         }
       } else {
-        BTM_TRACE_DEBUG(
-            "%s: SCO Conn(BR/EDR SC):local or peer does not support BR/EDR SC",
-            __func__);
+        LOG(WARNING) << __func__
+                     << ": SCO Conn(BR/EDR SC):local or peer does not support "
+                        "BR/EDR SC for acl_handle "
+                     << unsigned(acl_handle);
       }
+    } else {
+      LOG(ERROR) << __func__ << ": acl_index " << unsigned(acl_index)
+                 << " out of range for acl_handle " << unsigned(acl_handle);
     }
 
     /* Save the previous types in case command fails */
@@ -426,26 +315,26 @@
       /* Use the saved SCO routing */
       p_setup->input_data_path = p_setup->output_data_path =
           btm_cb.sco_cb.sco_route;
-
-      BTM_TRACE_DEBUG(
-          "%s: txbw 0x%x, rxbw 0x%x, "
-          "lat 0x%x, retrans 0x%02x, pkt 0x%04x, path %u",
-          __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
-          p_setup->max_latency_ms, p_setup->retransmission_effort,
-          p_setup->packet_types, p_setup->input_data_path);
-
+      LOG(INFO) << __func__ << std::hex << ": enhanced parameter list"
+                << " txbw=0x" << unsigned(p_setup->transmit_bandwidth)
+                << ", rxbw=0x" << unsigned(p_setup->receive_bandwidth)
+                << ", latency_ms=0x" << unsigned(p_setup->max_latency_ms)
+                << ", retransmit_effort=0x"
+                << unsigned(p_setup->retransmission_effort) << ", pkt_type=0x"
+                << unsigned(p_setup->packet_types) << ", path=0x"
+                << unsigned(p_setup->input_data_path);
       btsnd_hcic_enhanced_set_up_synchronous_connection(acl_handle, p_setup);
       p_setup->packet_types = saved_packet_types;
     } else { /* Use older command */
       uint16_t voice_content_format = btm_sco_voice_settings_to_legacy(p_setup);
-
-      BTM_TRACE_API(
-          "%s: txbw 0x%x, rxbw 0x%x, "
-          "lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
-          __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
-          p_setup->max_latency_ms, voice_content_format,
-          p_setup->retransmission_effort, p_setup->packet_types);
-
+      LOG(INFO) << __func__ << std::hex << ": legacy parameter list"
+                << " txbw=0x" << unsigned(p_setup->transmit_bandwidth)
+                << ", rxbw=0x" << unsigned(p_setup->receive_bandwidth)
+                << ", latency_ms=0x" << unsigned(p_setup->max_latency_ms)
+                << ", retransmit_effort=0x"
+                << unsigned(p_setup->retransmission_effort)
+                << ", voice_content_format=0x" << unsigned(voice_content_format)
+                << ", pkt_type=0x" << unsigned(p_setup->packet_types);
       btsnd_hcic_setup_esco_conn(
           acl_handle, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
           p_setup->max_latency_ms, voice_content_format,
@@ -550,27 +439,19 @@
   uint16_t xx;
   uint16_t acl_handle = 0;
   tACL_CONN* p_acl;
-
-#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
-  tBTM_PM_PWR_MD pm;
-  tBTM_PM_STATE state;
-#else
-  uint8_t mode;
-#endif  // BTM_SCO_WAKE_PARKED_LINK
-
   *p_sco_inx = BTM_INVALID_SCO_INDEX;
 
   /* If originating, ensure that there is an ACL connection to the BD Address */
 
   if (is_orig) {
     if (!remote_bda) {
-      BTM_TRACE_ERROR("%s: remote_bda is null", __func__);
+      LOG(ERROR) << __func__ << ": remote_bda is null";
       return BTM_ILLEGAL_VALUE;
     }
     acl_handle = BTM_GetHCIConnHandle(*remote_bda, BT_TRANSPORT_BR_EDR);
     if (acl_handle == 0xFFFF) {
-      VLOG(2) << __func__ << ": cannot find ACL handle for remote device "
-              << remote_bda;
+      LOG(ERROR) << __func__ << ": cannot find ACL handle for remote device "
+                 << remote_bda;
       return BTM_UNKNOWN_ADDR;
     }
   }
@@ -581,13 +462,20 @@
       if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING) ||
            (p->state == SCO_ST_PEND_UNPARK)) &&
           (p->esco.data.bd_addr == *remote_bda)) {
+        LOG(ERROR) << __func__ << ": a sco connection is already going on for "
+                   << *remote_bda << ", at state " << unsigned(p->state);
         return BTM_BUSY;
       }
     }
   } else {
     /* Support only 1 wildcard BD address at a time */
     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
-      if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known)) return BTM_BUSY;
+      if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known)) {
+        LOG(ERROR)
+            << __func__
+            << ": remote_bda is null and not known and we are still listening";
+        return BTM_BUSY;
+      }
     }
   }
 
@@ -599,19 +487,24 @@
         if (is_orig) {
 /* can not create SCO link if in park mode */
 #if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
-          if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) ==
-               BTM_SUCCESS)) {
+          tBTM_PM_STATE state;
+          if ((btm_read_power_mode_state(*remote_bda, &state) == BTM_SUCCESS)) {
             if (state == BTM_PM_ST_SNIFF || state == BTM_PM_ST_PARK ||
                 state == BTM_PM_ST_PENDING) {
-              BTM_TRACE_DEBUG("%s In sniff, park or pend mode: %d", __func__,
-                              state);
-              memset((void*)&pm, 0, sizeof(pm));
+              LOG(INFO) << __func__ << ": " << *remote_bda
+                        << " in sniff, park or pending mode "
+                        << unsigned(state);
+              tBTM_PM_PWR_MD pm = {};
               pm.mode = BTM_PM_MD_ACTIVE;
               BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, *remote_bda, &pm);
               p->state = SCO_ST_PEND_UNPARK;
             }
+          } else {
+            LOG(ERROR) << __func__ << ": failed to read power mode for "
+                       << *remote_bda;
           }
 #else   // BTM_SCO_WAKE_PARKED_LINK
+          uint8_t mode;
           if ((BTM_ReadPowerMode(*remote_bda, &mode) == BTM_SUCCESS) &&
               (mode == BTM_PM_MD_PARK))
             return (BTM_WRONG_MODE);
@@ -661,22 +554,29 @@
                         acl_handle);
 
           if ((btm_send_connect_request(acl_handle, p_setup)) !=
-              BTM_CMD_STARTED)
+              BTM_CMD_STARTED) {
+            LOG(ERROR) << __func__ << ": failed to send connect request for "
+                       << *remote_bda;
             return (BTM_NO_RESOURCES);
+          }
 
           p->state = SCO_ST_CONNECTING;
-        } else
+        } else {
+          BTM_TRACE_API("%s:(e)SCO listening for ACL handle 0x%04x", __func__,
+                        acl_handle);
           p->state = SCO_ST_LISTENING;
+        }
       }
 
       *p_sco_inx = xx;
-
+      BTM_TRACE_API("%s: BTM_CreateSco succeeded", __func__);
       return BTM_CMD_STARTED;
     }
   }
 
 #endif
   /* If here, all SCO blocks in use */
+  LOG(ERROR) << __func__ << ": all SCO control blocks are in use";
   return BTM_NO_RESOURCES;
 }
 
@@ -694,24 +594,22 @@
  ******************************************************************************/
 void btm_sco_chk_pend_unpark(uint8_t hci_status, uint16_t hci_handle) {
 #if (BTM_MAX_SCO_LINKS > 0)
-  uint16_t xx;
-  uint16_t acl_handle;
   tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
-
-  for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
-    if ((p->state == SCO_ST_PEND_UNPARK) &&
-        ((acl_handle = BTM_GetHCIConnHandle(
-              p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
-
-    {
-      BTM_TRACE_API(
-          "%s:(e)SCO Link for ACL "
-          "handle 0x%04x, hci_status 0x%02x",
-          __func__, acl_handle, hci_status);
-
-      if ((btm_send_connect_request(acl_handle, &p->esco.setup)) ==
-          BTM_CMD_STARTED)
+  for (uint16_t xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+    uint16_t acl_handle =
+        BTM_GetHCIConnHandle(p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR);
+    if ((p->state == SCO_ST_PEND_UNPARK) && (acl_handle == hci_handle)) {
+      LOG(INFO) << __func__ << ": " << p->esco.data.bd_addr
+                << " unparked, sending connection request, acl_handle="
+                << unsigned(acl_handle)
+                << ", hci_status=" << unsigned(hci_status);
+      if (btm_send_connect_request(acl_handle, &p->esco.setup) ==
+          BTM_CMD_STARTED) {
         p->state = SCO_ST_CONNECTING;
+      } else {
+        LOG(ERROR) << __func__ << ": failed to send connection request for "
+                   << p->esco.data.bd_addr;
+      }
     }
   }
 #endif  // BTM_MAX_SCO_LINKS
@@ -788,7 +686,7 @@
  *
  * Function         btm_sco_conn_req
  *
- * Description      This function is called by BTIF when an SCO connection
+ * Description      This function is called by BTU HCIF when an SCO connection
  *                  request is received from a remote.
  *
  * Returns          void
@@ -799,15 +697,15 @@
 #if (BTM_MAX_SCO_LINKS > 0)
   tSCO_CB* p_sco = &btm_cb.sco_cb;
   tSCO_CONN* p = &p_sco->sco_db[0];
-  uint16_t xx;
-  tBTM_ESCO_CONN_REQ_EVT_DATA evt_data;
+  tBTM_ESCO_CONN_REQ_EVT_DATA evt_data = {};
 
-  for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+  for (uint16_t sco_index = 0; sco_index < BTM_MAX_SCO_LINKS;
+       sco_index++, p++) {
     /*
      * If the sco state is in the SCO_ST_CONNECTING state, we still need
      * to return accept sco to avoid race conditon for sco creation
      */
-    int rem_bd_matches = p->rem_bd_known && p->esco.data.bd_addr == bda;
+    bool rem_bd_matches = p->rem_bd_known && p->esco.data.bd_addr == bda;
     if (((p->state == SCO_ST_CONNECTING) && rem_bd_matches) ||
         ((p->state == SCO_ST_LISTENING) &&
          (rem_bd_matches || !p->rem_bd_known))) {
@@ -829,18 +727,19 @@
             ||
             (link_type == BTM_LINK_TYPE_SCO &&
              !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK))) {
-          btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
-        } else /* Accept the request */
-        {
-          btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL);
+          btm_esco_conn_rsp(sco_index, HCI_ERR_HOST_REJECT_RESOURCES, bda,
+                            nullptr);
+        } else {
+          /* Accept the request */
+          btm_esco_conn_rsp(sco_index, HCI_SUCCESS, bda, nullptr);
         }
-      } else /* Notify upper layer of connect indication */
-      {
+      } else {
+        /* Notify upper layer of connect indication */
         evt_data.bd_addr = bda;
         memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN);
         evt_data.link_type = link_type;
-        evt_data.sco_inx = xx;
-        tBTM_ESCO_EVT_DATA btm_esco_evt_data;
+        evt_data.sco_inx = sco_index;
+        tBTM_ESCO_EVT_DATA btm_esco_evt_data = {};
         btm_esco_evt_data.conn_evt = evt_data;
         p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT, &btm_esco_evt_data);
       }
@@ -852,8 +751,9 @@
   /* TCS usage */
   if (btm_cb.sco_cb.app_sco_ind_cb) {
     /* Now, try to find an unused control block */
-    for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS;
-         xx++, p++) {
+    uint16_t sco_index;
+    for (sco_index = 0, p = &btm_cb.sco_cb.sco_db[0];
+         sco_index < BTM_MAX_SCO_LINKS; sco_index++, p++) {
       if (p->state == SCO_ST_UNUSED) {
         p->is_orig = false;
         p->state = SCO_ST_LISTENING;
@@ -864,18 +764,18 @@
         break;
       }
     }
-    if (xx < BTM_MAX_SCO_LINKS) {
-      btm_cb.sco_cb.app_sco_ind_cb(xx);
+    if (sco_index < BTM_MAX_SCO_LINKS) {
+      btm_cb.sco_cb.app_sco_ind_cb(sco_index);
       return;
     }
   }
 
 #endif
   /* If here, no one wants the SCO connection. Reject it */
-  BTM_TRACE_WARNING(
-      "btm_sco_conn_req: No one wants this SCO connection; rejecting it");
+  BTM_TRACE_WARNING("%s: rejecting SCO for %s", __func__,
+                    bda.ToString().c_str());
   btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda,
-                    NULL);
+                    nullptr);
 }
 
 /*******************************************************************************
@@ -894,7 +794,7 @@
   tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
   uint16_t xx;
   bool spt = false;
-  tBTM_CHG_ESCO_PARAMS parms;
+  tBTM_CHG_ESCO_PARAMS parms = {};
 #endif
 
   btm_cb.sco_cb.sco_disc_reason = hci_status;
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 60a3a17..b080901 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -58,7 +58,6 @@
                                                uint32_t mx_proto_id,
                                                uint32_t mx_chan_id);
 
-static tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec);
 static bool btm_sec_start_get_name(tBTM_SEC_DEV_REC* p_dev_rec);
 static void btm_sec_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec);
 static void btm_sec_start_encryption(tBTM_SEC_DEV_REC* p_dev_rec);
@@ -223,7 +222,7 @@
  * Returns          true if registered OK, else false
  *
  ******************************************************************************/
-bool BTM_SecRegister(tBTM_APPL_INFO* p_cb_info) {
+bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) {
   BT_OCTET16 temp_value = {0};
 
   BTM_TRACE_EVENT("%s application registered", __func__);
@@ -454,20 +453,8 @@
 bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
                           uint8_t service_id, uint16_t sec_level, uint16_t psm,
                           uint32_t mx_proto_id, uint32_t mx_chan_id) {
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  CONNECTION_TYPE conn_type;
-
-  if (is_originator)
-    conn_type = CONN_ORIENT_ORIG;
-  else
-    conn_type = CONN_ORIENT_TERM;
-
-  return (btm_sec_set_security_level(conn_type, p_name, service_id, sec_level,
-                                     psm, mx_proto_id, mx_chan_id));
-#else
   return (btm_sec_set_security_level(is_originator, p_name, service_id,
                                      sec_level, psm, mx_proto_id, mx_chan_id));
-#endif
 }
 
 /*******************************************************************************
@@ -500,22 +487,7 @@
   uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
   bool record_allocated = false;
   bool is_originator;
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  bool is_ucd;
-
-  if (conn_type & CONNECTION_TYPE_ORIG_MASK)
-    is_originator = true;
-  else
-    is_originator = false;
-
-  if (conn_type & CONNECTION_TYPE_CONNLESS_MASK) {
-    is_ucd = true;
-  } else {
-    is_ucd = false;
-  }
-#else
   is_originator = conn_type;
-#endif
 
   BTM_TRACE_API("%s : sec: 0x%x", __func__, sec_level);
 
@@ -577,14 +549,6 @@
             BTM_SEC_SERVICE_NAME_LEN + 1);
 #endif
 /* clear out the old setting, just in case it exists */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-    if (is_ucd) {
-      p_srec->ucd_security_flags &= ~(
-          BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT |
-          BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM | BTM_SEC_FORCE_MASTER |
-          BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
-    } else
-#endif
     {
       p_srec->security_flags &= ~(
           BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT |
@@ -610,12 +574,7 @@
 /* outgoing connections usually set the security level right before
  * the connection is initiated.
  * set it to be the outgoing service */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-    if (is_ucd == false)
-#endif
-    {
       btm_cb.p_out_serv = p_srec;
-    }
   } else {
     p_srec->term_mx_chan_id = mx_chan_id;
 #if BTM_SEC_SERVICE_NAME_LEN > 0
@@ -623,15 +582,6 @@
             BTM_SEC_SERVICE_NAME_LEN + 1);
 #endif
 /* clear out the old setting, just in case it exists */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-    if (is_ucd) {
-      p_srec->ucd_security_flags &=
-          ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT |
-            BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | BTM_SEC_FORCE_MASTER |
-            BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE |
-            BTM_SEC_ATTEMPT_SLAVE | BTM_SEC_IN_MIN_16_DIGIT_PIN);
-    } else
-#endif
     {
       p_srec->security_flags &=
           ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT |
@@ -655,28 +605,6 @@
     if (sec_level & BTM_SEC_IN_ENCRYPT) sec_level |= BTM_SEC_IN_AUTHENTICATE;
   }
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (is_ucd) {
-    p_srec->security_flags |= (uint16_t)(BTM_SEC_IN_USE);
-    p_srec->ucd_security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
-  } else {
-    p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
-  }
-
-  BTM_TRACE_API(
-      "BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, "
-      "chan_id %d",
-      index, service_id, conn_type, psm, mx_proto_id, mx_chan_id);
-
-  BTM_TRACE_API(
-      "               : security_flags: 0x%04x, ucd_security_flags: 0x%04x",
-      p_srec->security_flags, p_srec->ucd_security_flags);
-
-#if BTM_SEC_SERVICE_NAME_LEN > 0
-  BTM_TRACE_API("               : service name [%s] (up to %d chars saved)",
-                p_name, BTM_SEC_SERVICE_NAME_LEN);
-#endif
-#else
   p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
 
   BTM_TRACE_API(
@@ -688,7 +616,6 @@
       "               : sec: 0x%x, service name [%s] (up to %d chars saved)",
       p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN);
 #endif
-#endif
 
   return (record_allocated);
 }
@@ -723,9 +650,6 @@
         (!service_id || (service_id == p_srec->service_id))) {
       BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d", i, service_id);
       p_srec->security_flags = 0;
-#if (L2CAP_UCD_INCLUDED == TRUE)
-      p_srec->ucd_security_flags = 0;
-#endif
       num_freed++;
     }
   }
@@ -875,7 +799,7 @@
 
   if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
       (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) &&
-      (btm_cb.security_mode_changed == false)) {
+      (!btm_cb.security_mode_changed)) {
     /* This is start of the dedicated bonding if local device is 2.0 */
     btm_cb.pin_code_len = pin_len;
     memcpy(btm_cb.pin_code, p_pin, pin_len);
@@ -948,7 +872,8 @@
   tACL_CONN* p = btm_bda_to_acl(bd_addr, transport);
   VLOG(1) << __func__ << " BDA: " << bd_addr;
 
-  BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d", transport);
+  BTM_TRACE_DEBUG("%s: Transport used %d, bd_addr=%s", __func__, transport,
+                  bd_addr.ToString().c_str());
 
   /* Other security process is in progress */
   if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
@@ -1314,8 +1239,9 @@
   tBTM_STATUS rc = 0;
 
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
-  if (!p_dev_rec || (transport == BT_TRANSPORT_BR_EDR &&
-                     p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) ||
+  if (!p_dev_rec ||
+      (transport == BT_TRANSPORT_BR_EDR &&
+       p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) ||
       (transport == BT_TRANSPORT_LE &&
        p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE)) {
     /* Connection should be up and runnning */
@@ -1360,9 +1286,9 @@
 
   BTM_TRACE_API(
       "Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x "
-      "Required:0x%x",
+      "Required:0x%x, p_dev_rec=%p, p_callback=%p",
       p_dev_rec->hci_handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
-      p_dev_rec->security_required);
+      p_dev_rec->security_required, p_dev_rec, p_callback);
 
   if (transport == BT_TRANSPORT_LE) {
     tACL_CONN* p = btm_bda_to_acl(bd_addr, transport);
@@ -1379,6 +1305,11 @@
 
   if (rc != BTM_CMD_STARTED && rc != BTM_BUSY) {
     if (p_callback) {
+      BTM_TRACE_DEBUG(
+          "%s: clearing p_callback=%p, p_dev_rec=%p, transport=%d, "
+          "bd_addr=%s",
+          __func__, p_callback, p_dev_rec, transport,
+          bd_addr.ToString().c_str());
       p_dev_rec->p_callback = NULL;
       (*p_callback)(&bd_addr, transport, p_dev_rec->p_ref_data, rc);
     }
@@ -1949,7 +1880,7 @@
   /* Only check if link key already exists */
   if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) return;
 
-  if (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == true) {
+  if (btm_sec_is_upgrade_possible(p_dev_rec, is_originator)) {
     BTM_TRACE_DEBUG("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags);
     /* upgrade is possible: check if the application wants the upgrade.
      * If the application is configured to use a global MITM flag,
@@ -2010,20 +1941,10 @@
       BT_TRANSPORT_BR_EDR; /* should check PSM range in LE connection oriented
                               L2CAP connection */
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (conn_type & CONNECTION_TYPE_ORIG_MASK)
-    is_originator = true;
-  else
-    is_originator = false;
-
-  BTM_TRACE_DEBUG("%s() conn_type: 0x%x, 0x%x", __func__, conn_type,
-                  p_ref_data);
-#else
   is_originator = conn_type;
 
-  BTM_TRACE_DEBUG("%s() is_originator:%d, 0x%x", __func__, is_originator,
-                  p_ref_data);
-#endif
+  BTM_TRACE_DEBUG("%s() is_originator:%d, 0x%x, psm=0x%04x", __func__,
+                  is_originator, p_ref_data, psm);
 
   /* Find or get oldest record */
   p_dev_rec = btm_find_or_alloc_dev(bd_addr);
@@ -2047,68 +1968,11 @@
     (*p_callback)(&bd_addr, transport, p_ref_data, BTM_SUCCESS_NO_SECURITY);
     return (BTM_SUCCESS);
   }
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (conn_type & CONNECTION_TYPE_CONNLESS_MASK) {
-    if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
-      security_required = btm_sec_set_serv_level4_flags(
-          p_serv_rec->ucd_security_flags, is_originator);
-    } else {
-      security_required = p_serv_rec->ucd_security_flags;
-    }
-
-    rc = BTM_CMD_STARTED;
-    if (is_originator) {
-      if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
-          ((((security_required & BTM_SEC_OUT_FLAGS) ==
-             BTM_SEC_OUT_AUTHENTICATE) &&
-            (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
-          ((((security_required & BTM_SEC_OUT_FLAGS) ==
-             (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) &&
-            (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
-          ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) &&
-            (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)))) {
-        rc = BTM_SUCCESS;
-      }
-    } else {
-      if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
-          ((((security_required & BTM_SEC_IN_FLAGS) ==
-             BTM_SEC_IN_AUTHENTICATE) &&
-            (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
-          ((((security_required & BTM_SEC_IN_FLAGS) ==
-             (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) &&
-            (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
-          ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) &&
-            (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)))) {
-        // Check for 16 digits (or MITM)
-        if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
-            (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) ==
-              BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
-             btm_dev_16_digit_authenticated(p_dev_rec))) {
-          rc = BTM_SUCCESS;
-        }
-      }
-    }
-
-    if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
-        (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
-      rc = BTM_CMD_STARTED;
-    }
-
-    if (rc == BTM_SUCCESS) {
-      if (p_callback)
-        (*p_callback)(&bd_addr, transport, (void*)p_ref_data, BTM_SUCCESS);
-
-      return (BTM_SUCCESS);
-    }
-  } else
-#endif
-  {
-    if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
-      security_required = btm_sec_set_serv_level4_flags(
-          p_serv_rec->security_flags, is_originator);
-    } else {
-      security_required = p_serv_rec->security_flags;
-    }
+  if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+    security_required = btm_sec_set_serv_level4_flags(
+        p_serv_rec->security_flags, is_originator);
+  } else {
+    security_required = p_serv_rec->security_flags;
   }
 
   BTM_TRACE_DEBUG(
@@ -2151,7 +2015,7 @@
          btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
         (BTM_SM4_KNOWN == p_dev_rec->sm4) ||
         (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
-         (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == false))) {
+         (!btm_sec_is_upgrade_possible(p_dev_rec, is_originator)))) {
       /* legacy mode - local is legacy or local is lisbon/peer is legacy
        * or SM4 with no possibility of link key upgrade */
       if (is_originator) {
@@ -2258,22 +2122,9 @@
   p_dev_rec->p_ref_data = p_ref_data;
   p_dev_rec->is_originator = is_originator;
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (conn_type & CONNECTION_TYPE_CONNLESS_MASK)
-    p_dev_rec->is_ucd = true;
-  else
-    p_dev_rec->is_ucd = false;
-#endif
-
 /* If there are multiple service records used through the same PSM */
 /* leave security decision for the multiplexor on the top */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (((btm_sec_find_next_serv(p_serv_rec)) != NULL) &&
-      (!(conn_type & CONNECTION_TYPE_CONNLESS_MASK))) /* if not UCD */
-#else
-  if ((btm_sec_find_next_serv(p_serv_rec)) != NULL)
-#endif
-  {
+  if ((btm_sec_find_next_serv(p_serv_rec)) != NULL) {
     BTM_TRACE_DEBUG("no next_serv sm4:0x%x, chk:%d", p_dev_rec->sm4,
                     chk_acp_auth_done);
     if (!BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
@@ -2295,11 +2146,12 @@
    * The layer above L2CAP needs to carry out the security requirement after
    * L2CAP connect
    * response is received */
-  if (is_originator && ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
-                         btm_cb.security_mode == BTM_SEC_MODE_NONE ||
-                         btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
-                         btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
-                        !BTM_SEC_IS_SM4(p_dev_rec->sm4)) &&
+  if (is_originator &&
+      ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+        btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+        btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+        btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+       !BTM_SEC_IS_SM4(p_dev_rec->sm4)) &&
       (psm >= 0x1001)) {
     BTM_TRACE_EVENT(
         "dynamic PSM:0x%x in legacy mode - postponed for upper layer", psm);
@@ -2379,6 +2231,8 @@
 
   rc = btm_sec_execute_procedure(p_dev_rec);
   if (rc != BTM_CMD_STARTED) {
+    BTM_TRACE_DEBUG("%s: p_dev_rec=%p, clearing callback. old p_callback=%p",
+                    __func__, p_dev_rec, p_dev_rec->p_callback);
     p_dev_rec->p_callback = NULL;
     (*p_callback)(&bd_addr, transport, p_dev_rec->p_ref_data, (uint8_t)rc);
   }
@@ -2466,7 +2320,7 @@
          btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
         (BTM_SM4_KNOWN == p_dev_rec->sm4) ||
         (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
-         (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == false))) {
+         (!btm_sec_is_upgrade_possible(p_dev_rec, is_originator)))) {
       /* legacy mode - local is legacy or local is lisbon/peer is legacy
        * or SM4 with no possibility of link key upgrade */
       if (is_originator) {
@@ -2898,6 +2752,9 @@
     return;
 
   p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+  BTM_TRACE_DEBUG("%s: clearing callback. p_dev_rec=%p, p_callback=%p",
+                  __func__, p_dev_rec, p_dev_rec->p_callback);
   p_dev_rec->p_callback = NULL;
 }
 
@@ -2922,9 +2779,8 @@
   }
 
   /* Make sure an L2cap link control block is available */
-  if (!p_lcb &&
-      (p_lcb = l2cu_allocate_lcb(p_dev_rec->bd_addr, true,
-                                 BT_TRANSPORT_BR_EDR)) == NULL) {
+  if (!p_lcb && (p_lcb = l2cu_allocate_lcb(p_dev_rec->bd_addr, true,
+                                           BT_TRANSPORT_BR_EDR)) == NULL) {
     LOG(WARNING) << "Security Manager: failed allocate LCB "
                  << p_dev_rec->bd_addr;
 
@@ -2934,7 +2790,7 @@
   /* set up the control block to indicated dedicated bonding */
   btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
 
-  if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false) {
+  if (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR)) {
     LOG(WARNING) << "Security Manager: failed create allocate LCB "
                  << p_dev_rec->bd_addr;
 
@@ -3599,8 +3455,7 @@
       }
       /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req
        * right now */
-    } else if ((event == BTM_SP_CFM_REQ_EVT) &&
-               (evt_data.cfm_req.just_works == true)) {
+    } else if ((event == BTM_SP_CFM_REQ_EVT) && (evt_data.cfm_req.just_works)) {
       /* automatically reply with just works if no sp_cback */
       status = BTM_SUCCESS;
     }
@@ -3913,14 +3768,14 @@
   bool are_bonding = false;
 
   if (p_dev_rec) {
-    VLOG(2) << __func__ << "Security Manager: in state: "
+    VLOG(2) << __func__ << ": Security Manager: in state: "
             << btm_pair_state_descr(btm_cb.pairing_state)
             << " handle:" << handle << " status:" << status
             << "dev->sec_state:" << p_dev_rec->sec_state
             << " bda:" << p_dev_rec->bd_addr
             << "RName:" << p_dev_rec->sec_bd_name;
   } else {
-    VLOG(2) << __func__ << "Security Manager: in state: "
+    VLOG(2) << __func__ << ": Security Manager: in state: "
             << btm_pair_state_descr(btm_cb.pairing_state)
             << " handle:" << handle << " status:" << status;
   }
@@ -4187,6 +4042,8 @@
   if (p_dev_rec->sec_state != BTM_SEC_STATE_ENCRYPTING) {
     if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state) {
       p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+      BTM_TRACE_DEBUG("%s: clearing callback. p_dev_rec=%p, p_callback=%p",
+                      __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);
     }
@@ -4242,7 +4099,7 @@
  * Function         btm_sec_connected
  *
  * Description      This function is when a connection to the peer device is
- *                  establsihed
+ *                  established
  *
  * Returns          void
  *
@@ -4258,16 +4115,16 @@
   btm_acl_resubmit_page();
 
   if (p_dev_rec) {
-    VLOG(2) << __func__ << "Security Manager: in state: "
+    VLOG(2) << __func__ << ": Security Manager: in state: "
             << btm_pair_state_descr(btm_cb.pairing_state)
-            << " handle:" << handle << " status:" << status
-            << "enc_mode:" << enc_mode << " bda:" << bda
-            << "RName:" << p_dev_rec->sec_bd_name;
+            << " handle:" << handle << " status:" << loghex(status)
+            << " enc_mode:" << loghex(enc_mode) << " bda:" << bda
+            << " RName:" << p_dev_rec->sec_bd_name;
   } else {
-    VLOG(2) << __func__ << "Security Manager: in state: "
+    VLOG(2) << __func__ << ": Security Manager: in state: "
             << btm_pair_state_descr(btm_cb.pairing_state)
-            << " handle:" << handle << " status:" << status
-            << "enc_mode:" << enc_mode << " bda:" << bda;
+            << " handle:" << handle << " status:" << loghex(status)
+            << " enc_mode:" << loghex(enc_mode) << " bda:" << bda;
   }
 
   if (!p_dev_rec) {
@@ -4438,6 +4295,15 @@
       }
     }
 
+    if (btm_cb.pairing_bda != bda) {
+      /* Don't callback unless this Connection-Complete-failure event has the
+       * same mac address as the bonding device */
+      VLOG(1) << __func__
+              << ": Different mac addresses: pairing_bda=" << btm_cb.pairing_bda
+              << ", bda=" << bda << ", do not callback";
+      return;
+    }
+
     if (status == HCI_ERR_CONNECTION_TOUT ||
         status == HCI_ERR_LMP_RESPONSE_TIMEOUT ||
         status == HCI_ERR_UNSPECIFIED || status == HCI_ERR_PAGE_TIMEOUT)
@@ -4635,6 +4501,13 @@
       (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
                                              p_dev_rec->dev_class,
                                              p_dev_rec->sec_bd_name, result);
+
+      // |btm_cb.api.p_auth_complete_callback| may cause |p_dev_rec| to be
+      // deallocated.
+      p_dev_rec = btm_find_dev_by_handle(handle);
+      if (!p_dev_rec) {
+        return;
+      }
     }
   }
 
@@ -4673,6 +4546,8 @@
 
   /* if security is pending, send callback to clean up the security state */
   if (p_callback) {
+    BTM_TRACE_DEBUG("%s: clearing callback. p_dev_rec=%p, p_callback=%p",
+                    __func__, p_dev_rec, p_dev_rec->p_callback);
     p_dev_rec->p_callback =
         NULL; /* when the peer device time out the authentication before
                  we do, this call back must be reset here */
@@ -5037,7 +4912,8 @@
   /* If pairing disabled OR (no PIN callback and not bonding) */
   /* OR we could not allocate entry in the database reject pairing request */
   else if (
-      p_cb->pairing_disabled || (p_cb->api.p_pin_callback == NULL)
+      p_cb->pairing_disabled ||
+      (p_cb->api.p_pin_callback == NULL)
 
       /* OR Microsoft keyboard can for some reason try to establish connection
        */
@@ -5137,7 +5013,7 @@
  *                  BTM_NO_RESOURCES  - permission declined
  *
  ******************************************************************************/
-static tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
+tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
   BTM_TRACE_EVENT(
       "btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
       p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
@@ -5173,12 +5049,6 @@
  * authenticated connections, hence we cannot distinguish here.
  */
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-    /* if incoming UCD packet, discard it */
-    if (!p_dev_rec->is_originator && (p_dev_rec->is_ucd == true))
-      return (BTM_FAILED_ON_SECURITY);
-#endif
-
     BTM_TRACE_EVENT("Security Manager: Start authentication");
 
     /*
@@ -5213,11 +5083,6 @@
        (!p_dev_rec->is_originator &&
         (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT))) &&
       (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
-#if (L2CAP_UCD_INCLUDED == TRUE)
-    /* if incoming UCD packet, discard it */
-    if (!p_dev_rec->is_originator && (p_dev_rec->is_ucd == true))
-      return (BTM_FAILED_ON_SECURITY);
-#endif
 
     BTM_TRACE_EVENT("Security Manager: Start encryption");
 
@@ -5244,11 +5109,10 @@
         "service id:%d, is trusted:%d", p_dev_rec->p_cur_service->service_id,
         (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
                                     p_dev_rec->p_cur_service->service_id)));
-    if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == false) &&
+    if ((!btm_sec_are_all_trusted(p_dev_rec->trusted_mask)) &&
         (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
-        (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
-                                    p_dev_rec->p_cur_service->service_id) ==
-         false)) {
+        (!BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+                                     p_dev_rec->p_cur_service->service_id))) {
       BTM_TRACE_EVENT("Security Manager: Start authorization");
       return (btm_sec_start_authorization(p_dev_rec));
     }
@@ -5414,17 +5278,7 @@
                                            uint16_t psm) {
   tBTM_SEC_SERV_REC* p_serv_rec = &btm_cb.sec_serv_rec[0];
   int i;
-  bool is_originator;
-
-#if (L2CAP_UCD_INCLUDED == TRUE)
-
-  if (conn_type & CONNECTION_TYPE_ORIG_MASK)
-    is_originator = true;
-  else
-    is_originator = false;
-#else
-  is_originator = conn_type;
-#endif
+  bool is_originator = conn_type;
 
   if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm) {
     /* If this is outgoing connection and the PSM matches p_out_serv,
@@ -5530,11 +5384,11 @@
 
 /*******************************************************************************
  *
- * Function         btm_sec_link_key_request
+ * Function         btm_send_link_key_notif
  *
- * Description      This function is called when controller requests link key
+ * Description      Call the link key callback.
  *
- * Returns          Pointer to the record or NULL
+ * Returns          void
  *
  ******************************************************************************/
 static void btm_send_link_key_notif(tBTM_SEC_DEV_REC* p_dev_rec) {
@@ -5705,6 +5559,10 @@
                                  bool is_le_transport) {
   tBTM_SEC_CALLBACK* p_callback = p_dev_rec->p_callback;
 
+  BTM_TRACE_DEBUG("%s: p_callback=%p, is_le_transport=%d, res=%d, p_dev_rec=%p",
+                  __func__, p_dev_rec->p_callback, is_le_transport, res,
+                  p_dev_rec);
+
   if (p_dev_rec->p_callback) {
     p_dev_rec->p_callback = NULL;
 
@@ -5766,7 +5624,7 @@
         "0x%02x",
         __func__, major, minor);
 
-    if (btm_cb.security_mode_changed == false) {
+    if (!btm_cb.security_mode_changed) {
       btm_cb.security_mode_changed = true;
 #ifdef APPL_AUTH_WRITE_EXCEPTION
       if (!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index ee40445..eac71a6 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -588,6 +588,13 @@
 
   handle = HCID_GET_HANDLE(handle);
 
+  if (status != HCI_SUCCESS) {
+    HCI_TRACE_DEBUG(
+        "%s: Connection failed: status=%d, handle=%d, link_type=%d, "
+        "enc_mode=%d",
+        __func__, status, handle, link_type, enc_mode);
+  }
+
   if (link_type == HCI_LINK_TYPE_ACL) {
     btm_sec_connected(bda, handle, status, enc_mode);
 
@@ -652,6 +659,13 @@
 
   handle = HCID_GET_HANDLE(handle);
 
+  if ((reason != HCI_ERR_CONN_CAUSE_LOCAL_HOST) &&
+      (reason != HCI_ERR_PEER_USER)) {
+    /* Uncommon disconnection reasons */
+    HCI_TRACE_DEBUG("%s: Got Disconn Complete Event: reason=%d, handle=%d",
+                    __func__, reason, handle);
+  }
+
 #if (BTM_SCO_INCLUDED == TRUE)
   /* If L2CAP doesn't know about it, send it to SCO */
   if (!l2c_link_hci_disc_comp(handle, reason)) btm_sco_removed(handle, reason);
@@ -954,7 +968,13 @@
       break;
 
     case HCI_BLE_CREATE_LL_CONN:
-      btm_ble_create_ll_conn_complete(*p);
+    case HCI_LE_EXTENDED_CREATE_CONNECTION:
+      // No command complete event for those commands according to spec
+      LOG(ERROR) << "No command complete expected, but received!";
+      break;
+
+    case HCI_BLE_CREATE_CONN_CANCEL:
+      btm_ble_create_conn_cancel_complete(p);
       break;
 
     case HCI_BLE_TRANSMITTER_TEST:
@@ -987,7 +1007,7 @@
 #endif
     default:
       if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
-        btm_vsc_complete(p, opcode, evt_len, (tBTM_CMPL_CB*)p_cplt_cback);
+        btm_vsc_complete(p, opcode, evt_len, (tBTM_VSC_CMPL_CB*)p_cplt_cback);
       break;
   }
 }
@@ -1129,6 +1149,7 @@
             break;
 
           case HCI_BLE_CREATE_LL_CONN:
+          case HCI_LE_EXTENDED_CREATE_CONNECTION:
             btm_ble_create_ll_conn_complete(status);
             break;
 
@@ -1160,14 +1181,14 @@
           default:
             if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
               btm_vsc_complete(&status, opcode, 1,
-                               (tBTM_CMPL_CB*)p_vsc_status_cback);
+                               (tBTM_VSC_CMPL_CB*)p_vsc_status_cback);
             break;
         }
 
       } else {
         if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
           btm_vsc_complete(&status, opcode, 1,
-                           (tBTM_CMPL_CB*)p_vsc_status_cback);
+                           (tBTM_VSC_CMPL_CB*)p_vsc_status_cback);
       }
   }
 }
diff --git a/stack/btu/btu_init.cc b/stack/btu/btu_init.cc
index e383fd3..cad79df 100644
--- a/stack/btu/btu_init.cc
+++ b/stack/btu/btu_init.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -87,11 +87,13 @@
  *****************************************************************************/
 void btu_free_core(void) {
   /* Free the mandatory core stack components */
+  gatt_free();
+
   l2c_free();
 
   sdp_free();
 
-  gatt_free();
+  btm_free();
 }
 
 /*****************************************************************************
diff --git a/stack/btu/btu_task.cc b/stack/btu/btu_task.cc
index c0f374d..7d2527a 100644
--- a/stack/btu/btu_task.cc
+++ b/stack/btu/btu_task.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/gap/gap_ble.cc b/stack/gap/gap_ble.cc
index 2247a14..cce62d4 100644
--- a/stack/gap/gap_ble.cc
+++ b/stack/gap/gap_ble.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -26,6 +26,7 @@
 #include "gatt_api.h"
 
 using base::StringPrintf;
+using bluetooth::Uuid;
 
 namespace {
 
@@ -122,7 +123,7 @@
   for (const tGAP_ATTR& db_attr : gatt_attr) {
     const tGAP_BLE_ATTR_VALUE& attr_value = db_attr.attr_value;
     if (handle == db_attr.handle) {
-      if (db_attr.uuid != GATT_UUID_GAP_DEVICE_NAME && is_long == true)
+      if (db_attr.uuid != GATT_UUID_GAP_DEVICE_NAME && is_long)
         return GATT_NOT_LONG;
 
       switch (db_attr.uuid) {
@@ -246,8 +247,7 @@
   tGATT_READ_PARAM param;
   memset(&param, 0, sizeof(tGATT_READ_PARAM));
 
-  param.service.uuid.len = LEN_UUID_16;
-  param.service.uuid.uu.uuid16 = uuid;
+  param.service.uuid = Uuid::From16Bit(uuid);
   param.service.s_handle = 1;
   param.service.e_handle = 0xFFFF;
   param.service.auth_req = 0;
@@ -393,23 +393,22 @@
  *
  ******************************************************************************/
 void gap_attr_db_init(void) {
-  tBT_UUID app_uuid = {LEN_UUID_128, {0}};
   uint16_t service_handle;
 
   /* Fill our internal UUID with a fixed pattern 0x82 */
-  memset(&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
+  std::array<uint8_t, Uuid::kNumBytes128> tmp;
+  tmp.fill(0x82);
+  Uuid app_uuid = Uuid::From128BitBE(tmp);
   gatt_attr.fill({});
 
-  gatt_if = GATT_Register(&app_uuid, &gap_cback);
+  gatt_if = GATT_Register(app_uuid, &gap_cback);
 
   GATT_StartIf(gatt_if);
 
-  bt_uuid_t svc_uuid, name_uuid, icon_uuid, pref_uuid, addr_res_uuid;
-  uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_GAP_SERVER);
-  uuid_128_from_16(&name_uuid, GATT_UUID_GAP_DEVICE_NAME);
-  uuid_128_from_16(&icon_uuid, GATT_UUID_GAP_ICON);
-  uuid_128_from_16(&pref_uuid, GATT_UUID_GAP_PREF_CONN_PARAM);
-  uuid_128_from_16(&addr_res_uuid, GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
+  Uuid svc_uuid = Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER);
+  Uuid name_uuid = Uuid::From16Bit(GATT_UUID_GAP_DEVICE_NAME);
+  Uuid icon_uuid = Uuid::From16Bit(GATT_UUID_GAP_ICON);
+  Uuid addr_res_uuid = Uuid::From16Bit(GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
 
   btgatt_db_element_t service[] = {
     {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = svc_uuid},
@@ -428,7 +427,7 @@
 #if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
     ,
     {.type = BTGATT_DB_CHARACTERISTIC,
-     .uuid = pref_uuid,
+     .uuid = Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM),
      .properties = GATT_CHAR_PROP_BIT_READ,
      .permissions = GATT_PERM_READ}
 #endif
diff --git a/stack/gap/gap_conn.cc b/stack/gap/gap_conn.cc
index 7d75986..72183bb 100644
--- a/stack/gap/gap_conn.cc
+++ b/stack/gap/gap_conn.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include "bt_utils.h"
 #include "btm_int.h"
 #include "btu.h"
+#include "device/include/controller.h"
 #include "gap_api.h"
 #include "l2c_int.h"
 #include "l2cdefs.h"
@@ -92,6 +93,9 @@
 static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
 static void gap_congestion_ind(uint16_t lcid, bool is_congested);
 static void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent);
+static void gap_credits_received_cb(uint16_t l2cap_cid,
+                                    uint16_t credits_received,
+                                    uint16_t credit_count);
 
 static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid);
 static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle);
@@ -122,6 +126,7 @@
   conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
   conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
   conn.reg_info.pL2CA_TxComplete_Cb = gap_tx_complete_ind;
+  conn.reg_info.pL2CA_CreditsReceived_Cb = gap_credits_received_cb;
 }
 
 /*******************************************************************************
@@ -143,6 +148,7 @@
  *                                remote BD Address, then NULL should be passed.
  *
  *                  psm         - the PSM used for the connection
+ *                  le_mps      - Maximum PDU Size for LE CoC
  *
  *                  p_config    - Optional pointer to configuration structure.
  *                                If NULL, the default GAP configuration will
@@ -161,9 +167,10 @@
  ******************************************************************************/
 uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
                       bool is_server, const RawAddress* p_rem_bda, uint16_t psm,
-                      tL2CAP_CFG_INFO* p_cfg, tL2CAP_ERTM_INFO* ertm_info,
-                      uint16_t security, uint8_t chan_mode_mask,
-                      tGAP_CONN_CALLBACK* p_cb, tBT_TRANSPORT transport) {
+                      uint16_t le_mps, tL2CAP_CFG_INFO* p_cfg,
+                      tL2CAP_ERTM_INFO* ertm_info, uint16_t security,
+                      uint8_t chan_mode_mask, tGAP_CONN_CALLBACK* p_cb,
+                      tBT_TRANSPORT transport) {
   tGAP_CCB* p_ccb;
   uint16_t cid;
 
@@ -203,9 +210,19 @@
 
   /* Configure L2CAP COC, if transport is LE */
   if (transport == BT_TRANSPORT_LE) {
-    p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
+    p_ccb->local_coc_cfg.credits = L2CAP_LE_CREDIT_DEFAULT;
     p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
-    p_ccb->local_coc_cfg.mps = L2CAP_LE_DEFAULT_MPS;
+
+    uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
+    if (le_mps > max_mps) {
+      LOG(INFO) << "Limiting MPS to one buffer size - " << max_mps;
+      le_mps = max_mps;
+    }
+    p_ccb->local_coc_cfg.mps = le_mps;
+
+    VLOG(2) << __func__ << ": credits=" << p_ccb->local_coc_cfg.credits
+            << ", mps=" << p_ccb->local_coc_cfg.mps
+            << ", mtu=" << p_ccb->local_coc_cfg.mtu;
   }
 
   p_ccb->p_callback = p_cb;
@@ -391,8 +408,9 @@
 
   mutex_global_unlock();
 
-  DVLOG(1) << StringPrintf("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
-                  p_ccb->rx_queue_size, *p_len);
+  DVLOG(1) << StringPrintf(
+      "GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
+      p_ccb->rx_queue_size, *p_len);
 
   return (BT_PASS);
 }
@@ -423,8 +441,8 @@
   } else
     rc = GAP_INVALID_HANDLE;
 
-  DVLOG(1) << StringPrintf("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", rc,
-                  *p_rx_queue_count);
+  DVLOG(1) << StringPrintf("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d",
+                           rc, *p_rx_queue_count);
 
   return (rc);
 }
@@ -463,6 +481,25 @@
   }
 }
 
+/* Try to write the queued data to l2ca. Return true on success, or if queue is
+ * congested. False if error occured when writing. */
+static bool gap_try_write_queued_data(tGAP_CCB* p_ccb) {
+  if (p_ccb->is_congested) return true;
+
+  /* Send the buffer through L2CAP */
+  BT_HDR* p_buf;
+  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
+    uint8_t status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
+
+    if (status == L2CAP_DW_CONGESTED) {
+      p_ccb->is_congested = true;
+      return true;
+    } else if (status != L2CAP_DW_SUCCESS)
+      return false;
+  }
+  return true;
+}
+
 /*******************************************************************************
  *
  * Function         GAP_ConnWriteData
@@ -471,9 +508,8 @@
  *                  to send data to the connection.
  *
  * Parameters:      handle      - Handle of the connection returned in the Open
- *                  p_data      - Data area
- *                  max_len     - Byte count requested
- *                  p_len       - Byte count received
+ *                  msg         - pointer to single SDU to send. This function
+ *                                will take ownership of it.
  *
  * Returns          BT_PASS                 - data read
  *                  GAP_ERR_BAD_HANDLE      - invalid handle
@@ -481,54 +517,30 @@
  *                  GAP_CONGESTION          - system is congested
  *
  ******************************************************************************/
-uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
-                           uint16_t max_len, uint16_t* p_len) {
+uint16_t GAP_ConnWriteData(uint16_t gap_handle, BT_HDR* msg) {
   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
-  BT_HDR* p_buf;
 
-  *p_len = 0;
-
-  if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
-
-  if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) return (GAP_ERR_BAD_STATE);
-
-  while (max_len) {
-    if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
-      p_buf = (BT_HDR*)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE);
-    else
-      p_buf = (BT_HDR*)osi_malloc(GAP_DATA_BUF_SIZE);
-
-    p_buf->offset = L2CAP_MIN_OFFSET;
-    p_buf->len =
-        (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
-    p_buf->event = BT_EVT_TO_BTU_SP_DATA;
-
-    memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
-
-    *p_len += p_buf->len;
-    max_len -= p_buf->len;
-    p_data += p_buf->len;
-
-    DVLOG(1) << StringPrintf("GAP_WriteData %d bytes", p_buf->len);
-
-    fixed_queue_enqueue(p_ccb->tx_queue, p_buf);
+  if (!p_ccb) {
+    osi_free(msg);
+    return GAP_ERR_BAD_HANDLE;
   }
 
-  if (p_ccb->is_congested) {
-    return (BT_PASS);
+  if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+    osi_free(msg);
+    return GAP_ERR_BAD_STATE;
   }
 
-  /* Send the buffer through L2CAP */
-  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
-    uint8_t status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
-
-    if (status == L2CAP_DW_CONGESTED) {
-      p_ccb->is_congested = true;
-      break;
-    } else if (status != L2CAP_DW_SUCCESS)
-      return (GAP_ERR_BAD_STATE);
+  if (msg->len > p_ccb->rem_mtu_size) {
+    osi_free(msg);
+    return GAP_ERR_ILL_PARM;
   }
 
+  DVLOG(1) << StringPrintf("GAP_WriteData %d bytes", msg->len);
+
+  fixed_queue_enqueue(p_ccb->tx_queue, msg);
+
+  if (!gap_try_write_queued_data(p_ccb)) return GAP_ERR_BAD_STATE;
+
   return (BT_PASS);
 }
 
@@ -678,10 +690,20 @@
 
   if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF)) {
     DVLOG(1) << StringPrintf("%s: GAP_EVT_TX_EMPTY", __func__);
-    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
+    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY, nullptr);
   }
 }
 
+void gap_credits_received_cb(uint16_t l2cap_cid, uint16_t credits_received,
+                             uint16_t credit_count) {
+  tGAP_CCB* p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+  if (!p_ccb) return;
+
+  tGAP_CB_DATA data{.coc_credits = {.credits_received = credits_received,
+                                    .credit_count = credit_count}};
+  p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_LE_COC_CREDITS, &data);
+}
+
 /*******************************************************************************
  *
  * Function         gap_connect_ind
@@ -701,8 +723,7 @@
   /* See if we have a CCB listening for the connection */
   for (xx = 0, p_ccb = conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
     if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING) && (p_ccb->psm == psm) &&
-        ((p_ccb->rem_addr_specified == false) ||
-         (bd_addr == p_ccb->rem_dev_address)))
+        (!p_ccb->rem_addr_specified || (bd_addr == p_ccb->rem_dev_address)))
       break;
   }
 
@@ -745,7 +766,7 @@
   }
 
   DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x",
-                  p_ccb->connection_id);
+                           p_ccb->connection_id);
 
   /* Send a Configuration Request. */
   if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
@@ -768,7 +789,7 @@
   if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) {
     p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
 
-    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
+    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED, nullptr);
   }
 }
 
@@ -850,7 +871,7 @@
   } else {
     /* Tell the user if he has a callback */
     if (p_ccb->p_callback)
-      (*p_ccb->p_callback)(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+      (*p_ccb->p_callback)(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED, nullptr);
 
     gap_release_ccb(p_ccb);
   }
@@ -927,7 +948,7 @@
 
     gap_checks_con_flags(p_ccb);
   } else {
-    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED, nullptr);
     gap_release_ccb(p_ccb);
   }
 }
@@ -953,7 +974,7 @@
 
   if (ack_needed) L2CA_DISCONNECT_RSP(l2cap_cid);
 
-  p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+  p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED, nullptr);
   gap_release_ccb(p_ccb);
 }
 
@@ -985,7 +1006,7 @@
                                    p_ccb->rx_queue_size, p_msg->len);
      */
 
-    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
+    p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL, nullptr);
   } else {
     osi_free(p_msg);
   }
@@ -1000,35 +1021,20 @@
  *
  ******************************************************************************/
 static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
-  tGAP_CCB* p_ccb;
-  uint16_t event;
-  BT_HDR* p_buf;
-  uint8_t status;
-
   DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
-                  is_congested, lcid);
+                           is_congested, lcid);
 
-  /* Find CCB based on CID */
-  p_ccb = gap_find_ccb_by_cid(lcid);
-  if (p_ccb == NULL) return;
+  tGAP_CCB* p_ccb = gap_find_ccb_by_cid(lcid); /* Find CCB based on CID */
+  if (!p_ccb) return;
 
   p_ccb->is_congested = is_congested;
 
-  event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
-  p_ccb->p_callback(p_ccb->gap_handle, event);
+  p_ccb->p_callback(
+      p_ccb->gap_handle,
+      (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED,
+      nullptr);
 
-  if (!is_congested) {
-    while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) !=
-           NULL) {
-      status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
-
-      if (status == L2CAP_DW_CONGESTED) {
-        p_ccb->is_congested = true;
-        break;
-      } else if (status != L2CAP_DW_SUCCESS)
-        break;
-    }
-  }
+  gap_try_write_queued_data(p_ccb);
 }
 
 /*******************************************************************************
@@ -1142,7 +1148,7 @@
     if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) &&
         (p_ccb_local->psm == p_ccb->psm)) {
       DVLOG(1) << __func__ << " : " << +p_ccb_local->psm
-              << " PSM is still in use, do not deregister";
+               << " PSM is still in use, do not deregister";
       return;
     }
   }
diff --git a/stack/gatt/att_protocol.cc b/stack/gatt/att_protocol.cc
index 82fa5a3..142216c 100644
--- a/stack/gatt/att_protocol.cc
+++ b/stack/gatt/att_protocol.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2014 Broadcom Corporation
+ *  Copyright 2008-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
 #define GATT_START_END_HANDLE_SIZE 4
 
 using base::StringPrintf;
+using bluetooth::Uuid;
 /**********************************************************************
  *   ATT protocl message building utility                              *
  **********************************************************************/
@@ -124,9 +125,9 @@
  *
  ******************************************************************************/
 BT_HDR* attp_build_browse_cmd(uint8_t op_code, uint16_t s_hdl, uint16_t e_hdl,
-                              tBT_UUID uuid) {
+                              const bluetooth::Uuid& uuid) {
   const size_t payload_size =
-      (GATT_OP_CODE_SIZE) + (GATT_START_END_HANDLE_SIZE) + (LEN_UUID_128);
+      (GATT_OP_CODE_SIZE) + (GATT_START_END_HANDLE_SIZE) + (Uuid::kNumBytes128);
   BT_HDR* p_buf =
       (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
 
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index c77a4c5..b983318 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
  ******************************************************************************/
 #include "bt_target.h"
 
+#include <base/strings/string_number_conversions.h>
 #include <base/strings/stringprintf.h>
 #include <stdio.h>
 #include <string.h>
@@ -34,6 +35,7 @@
 #include "l2c_api.h"
 
 using base::StringPrintf;
+using bluetooth::Uuid;
 
 /**
  * Add an service handle range to the list in decending order of the start
@@ -95,53 +97,6 @@
   return status;
 }
 
-static uint8_t BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
-                                0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-static int uuidType(unsigned char* p_uuid) {
-  if (memcmp(p_uuid, BASE_UUID, 12) != 0) return LEN_UUID_128;
-  if (memcmp(p_uuid + 14, BASE_UUID + 14, 2) != 0) return LEN_UUID_32;
-
-  return LEN_UUID_16;
-}
-
-/*******************************************************************************
- * BTIF -> BTA conversion functions
- ******************************************************************************/
-
-static void btif_to_bta_uuid(tBT_UUID* p_dest, bt_uuid_t* p_src) {
-  char* p_byte = (char*)p_src;
-  int i = 0;
-
-  p_dest->len = uuidType(p_src->uu);
-
-  switch (p_dest->len) {
-    case LEN_UUID_16:
-      p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
-      break;
-
-    case LEN_UUID_32:
-      p_dest->uu.uuid32 = (p_src->uu[15] << 24) + (p_src->uu[14] << 16) +
-                          (p_src->uu[13] << 8) + p_src->uu[12];
-      break;
-
-    case LEN_UUID_128:
-      for (i = 0; i != 16; ++i) p_dest->uu.uuid128[i] = p_byte[i];
-      break;
-
-    default:
-      LOG(ERROR) << __func__ << ": Unknown UUID length %d!" << +p_dest->len;
-      break;
-  }
-}
-
-void uuid_128_from_16(bt_uuid_t* uuid, uint16_t uuid16) {
-  memcpy(uuid, &BASE_UUID, sizeof(bt_uuid_t));
-
-  uuid->uu[13] = (uint8_t)((0xFF00 & uuid16) >> 8);
-  uuid->uu[12] = (uint8_t)(0x00FF & uuid16);
-}
-
 static uint16_t compute_service_size(btgatt_db_element_t* service, int count) {
   int db_size = 0;
   btgatt_db_element_t* el = service;
@@ -160,22 +115,23 @@
   return db_size;
 }
 
-static bool is_gatt_attr_type(const tBT_UUID& uuid) {
-  if (uuid.len == LEN_UUID_16 && (uuid.uu.uuid16 == GATT_UUID_PRI_SERVICE ||
-                                  uuid.uu.uuid16 == GATT_UUID_SEC_SERVICE ||
-                                  uuid.uu.uuid16 == GATT_UUID_INCLUDE_SERVICE ||
-                                  uuid.uu.uuid16 == GATT_UUID_CHAR_DECLARE)) {
+static bool is_gatt_attr_type(const Uuid& uuid) {
+  if (uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) ||
+      uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE) ||
+      uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE) ||
+      uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) {
     return true;
   }
   return false;
 }
 
-/** Update the the last primary info for the service list info */
-static void gatt_update_last_pri_srv_info() {
-  gatt_cb.last_primary_s_handle = 0;
+/** Update the the last service info for the service list info */
+static void gatt_update_last_srv_info() {
+  gatt_cb.last_service_handle = 0;
 
-  for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info)
-    if (el.is_primary) gatt_cb.last_primary_s_handle = el.s_hdl;
+  for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+    gatt_cb.last_service_handle = el.s_hdl;
+  }
 }
 
 /*******************************************************************************
@@ -198,28 +154,22 @@
   uint16_t s_hdl = 0;
   bool save_hdl = false;
   tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
-  tBT_UUID* p_app_uuid128;
 
   bool is_pri = (service->type == BTGATT_DB_PRIMARY_SERVICE) ? true : false;
-  tBT_UUID svc_uuid;
-  btif_to_bta_uuid(&svc_uuid, &service->uuid);
+  Uuid svc_uuid = service->uuid;
 
   LOG(INFO) << __func__;
 
-  if (p_reg == NULL) {
+  if (!p_reg) {
     LOG(ERROR) << "Inavlid gatt_if=" << +gatt_if;
     return GATT_INTERNAL_ERROR;
   }
 
-  p_app_uuid128 = &p_reg->app_uuid128;
-
   uint16_t num_handles = compute_service_size(service, count);
 
-  if ((svc_uuid.len == LEN_UUID_16) &&
-      (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) {
+  if (svc_uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) {
     s_hdl = gatt_cb.hdl_cfg.gatt_start_hdl;
-  } else if ((svc_uuid.len == LEN_UUID_16) &&
-             (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) {
+  } else if (svc_uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) {
     s_hdl = gatt_cb.hdl_cfg.gap_start_hdl;
   } else {
     if (!gatt_cb.hdl_list_info->empty()) {
@@ -241,7 +191,7 @@
   }
 
   tGATT_HDL_LIST_ELEM& list = gatt_add_an_item_to_list(s_hdl);
-  list.asgn_range.app_uuid128 = *p_app_uuid128;
+  list.asgn_range.app_uuid128 = p_reg->app_uuid128;
   list.asgn_range.svc_uuid = svc_uuid;
   list.asgn_range.s_handle = s_hdl;
   list.asgn_range.e_handle = s_hdl + num_handles - 1;
@@ -252,20 +202,18 @@
       (*gatt_cb.cb_info.p_nv_save_callback)(true, &list.asgn_range);
   }
 
-  gatts_init_service_db(list.svc_db, &svc_uuid, is_pri, s_hdl, num_handles);
+  gatts_init_service_db(list.svc_db, svc_uuid, is_pri, s_hdl, num_handles);
 
   VLOG(1) << StringPrintf(
-      "%s: handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", __func__,
+      "%s: handles needed:%u s_hdl=%u e_hdl=%u %s is_primary=%d", __func__,
       num_handles, list.asgn_range.s_handle, list.asgn_range.e_handle,
-      ((list.asgn_range.svc_uuid.len == 2) ? "uuid16" : "uuid128"),
-      list.asgn_range.svc_uuid.uu.uuid16, list.asgn_range.is_primary);
+      list.asgn_range.svc_uuid.ToString().c_str(), list.asgn_range.is_primary);
 
   service->attribute_handle = s_hdl;
 
   btgatt_db_element_t* el = service + 1;
   for (int i = 0; i < count - 1; i++, el++) {
-    tBT_UUID uuid;
-    btif_to_bta_uuid(&uuid, &el->uuid);
+    const Uuid& uuid = el->uuid;
 
     if (el->type == BTGATT_DB_CHARACTERISTIC) {
       /* data validity checking */
@@ -282,8 +230,8 @@
       if (is_gatt_attr_type(uuid)) {
         LOG(ERROR) << StringPrintf(
             "%s: attept to add characteristic with UUID equal to GATT "
-            "Attribute Type 0x%04x ",
-            __func__, uuid.uu.uuid16);
+            "Attribute Type %s ",
+            __func__, uuid.ToString().c_str());
         return GATT_INTERNAL_ERROR;
       }
 
@@ -293,8 +241,8 @@
       if (is_gatt_attr_type(uuid)) {
         LOG(ERROR) << StringPrintf(
             "%s: attept to add descriptor with UUID equal to GATT "
-            "Attribute Type 0x%04x ",
-            __func__, uuid.uu.uuid16);
+            "Attribute Type %s",
+            __func__, uuid.ToString().c_str());
         return GATT_INTERNAL_ERROR;
       }
 
@@ -333,18 +281,18 @@
   elem.p_db = &list.svc_db;
   elem.is_primary = list.asgn_range.is_primary;
 
-  memcpy(&elem.app_uuid, &list.asgn_range.app_uuid128, sizeof(tBT_UUID));
+  elem.app_uuid = list.asgn_range.app_uuid128;
   elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE
                                          : GATT_UUID_SEC_SERVICE;
 
   if (elem.type == GATT_UUID_PRI_SERVICE) {
-    tBT_UUID* p_uuid = gatts_get_service_uuid(elem.p_db);
-    elem.sdp_handle = gatt_add_sdp_record(p_uuid, elem.s_hdl, elem.e_hdl);
+    Uuid* p_uuid = gatts_get_service_uuid(elem.p_db);
+    elem.sdp_handle = gatt_add_sdp_record(*p_uuid, elem.s_hdl, elem.e_hdl);
   } else {
     elem.sdp_handle = 0;
   }
 
-  gatt_update_last_pri_srv_info();
+  gatt_update_last_srv_info();
 
   VLOG(1) << StringPrintf(
       "%s: allocated el: s_hdl=%d e_hdl=%d type=0x%x sdp_hdl=0x%x", __func__,
@@ -355,17 +303,14 @@
   return GATT_SERVICE_STARTED;
 }
 
-bool is_active_service(tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid,
+bool is_active_service(const Uuid& app_uuid128, Uuid* p_svc_uuid,
                        uint16_t start_handle) {
   for (auto& info : *gatt_cb.srv_list_info) {
-    tBT_UUID* p_this_uuid = gatts_get_service_uuid(info.p_db);
+    Uuid* p_this_uuid = gatts_get_service_uuid(info.p_db);
 
-    if (p_this_uuid && gatt_uuid_compare(*p_app_uuid128, info.app_uuid) &&
-        gatt_uuid_compare(*p_svc_uuid, *p_this_uuid) &&
-        (start_handle == info.s_hdl)) {
-      LOG(ERROR) << "Active Service Found";
-      gatt_dbg_display_uuid(*p_svc_uuid);
-
+    if (p_this_uuid && app_uuid128 == info.app_uuid &&
+        *p_svc_uuid == *p_this_uuid && (start_handle == info.s_hdl)) {
+      LOG(ERROR) << "Active Service Found: " << *p_svc_uuid;
       return true;
     }
   }
@@ -386,7 +331,7 @@
  *                  was not found.
  *
  ******************************************************************************/
-bool GATTS_DeleteService(tGATT_IF gatt_if, tBT_UUID* p_svc_uuid,
+bool GATTS_DeleteService(tGATT_IF gatt_if, Uuid* p_svc_uuid,
                          uint16_t svc_inst) {
   VLOG(1) << __func__;
 
@@ -396,8 +341,8 @@
     return false;
   }
 
-  tBT_UUID* p_app_uuid128 = &p_reg->app_uuid128;
-  auto it = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst);
+  auto it =
+      gatt_find_hdl_buffer_by_app_id(p_reg->app_uuid128, p_svc_uuid, svc_inst);
   if (it == gatt_cb.hdl_list_info->end()) {
     LOG(ERROR) << "No Service found";
     return false;
@@ -405,7 +350,7 @@
 
   gatt_proc_srv_chg();
 
-  if (is_active_service(p_app_uuid128, p_svc_uuid, svc_inst)) {
+  if (is_active_service(p_reg->app_uuid128, p_svc_uuid, svc_inst)) {
     GATTS_StopService(it->asgn_range.s_handle);
   }
 
@@ -445,7 +390,7 @@
   }
 
   gatt_cb.srv_list_info->erase(it);
-  gatt_update_last_pri_srv_info();
+  gatt_update_last_srv_info();
 }
 /*******************************************************************************
  *
@@ -664,7 +609,6 @@
   return attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg);
 }
 
-
 /*******************************************************************************
  *
  * Function         GATTC_Discover
@@ -699,7 +643,7 @@
   if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
       !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
       /* search by type does not have a valid UUID param */
-      (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.len == 0)) {
+      (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.IsEmpty())) {
     return GATT_ILLEGAL_PARAMETER;
   }
 
@@ -769,7 +713,7 @@
     case GATT_READ_CHAR_VALUE:
       p_clcb->s_handle = p_read->service.s_handle;
       p_clcb->e_handle = p_read->service.e_handle;
-      memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
+      p_clcb->uuid = p_read->service.uuid;
       break;
     case GATT_READ_MULTIPLE: {
       p_clcb->s_handle = 0;
@@ -782,7 +726,7 @@
     }
     case GATT_READ_BY_HANDLE:
     case GATT_READ_PARTIAL:
-      memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
+      p_clcb->uuid = Uuid::kEmpty;
       p_clcb->s_handle = p_read->by_handle.handle;
 
       if (type == GATT_READ_PARTIAL) {
@@ -996,19 +940,16 @@
  *                  with GATT
  *
  ******************************************************************************/
-tGATT_IF GATT_Register(tBT_UUID* p_app_uuid128, tGATT_CBACK* p_cb_info) {
+tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info) {
   tGATT_REG* p_reg;
   uint8_t i_gatt_if = 0;
   tGATT_IF gatt_if = 0;
 
-  LOG(INFO) << __func__;
-  gatt_dbg_display_uuid(*p_app_uuid128);
+  LOG(INFO) << __func__ << " " << app_uuid128;
 
   for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
        i_gatt_if++, p_reg++) {
-    if (p_reg->in_use &&
-        !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128,
-                LEN_UUID_128)) {
+    if (p_reg->in_use && p_reg->app_uuid128 == app_uuid128) {
       LOG(ERROR) << "application already registered.";
       return 0;
     }
@@ -1019,7 +960,7 @@
     if (!p_reg->in_use) {
       memset(p_reg, 0, sizeof(tGATT_REG));
       i_gatt_if++; /* one based number */
-      p_reg->app_uuid128 = *p_app_uuid128;
+      p_reg->app_uuid128 = app_uuid128;
       gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
       p_reg->app_cb = *p_cb_info;
       p_reg->in_use = true;
@@ -1069,7 +1010,7 @@
   }
 
   /* free all services db buffers if owned by this application */
-  gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
+  gatt_free_srvc_db_buffer_app_id(p_reg->app_uuid128);
 
   /* When an application deregisters, check remove the link associated with the
    * app */
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index f4e028a..75a8057 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,12 +26,12 @@
 #include "bt_target.h"
 #include "bt_utils.h"
 
-#include "btcore/include/uuid.h"
 #include "gatt_api.h"
 #include "gatt_int.h"
 #include "osi/include/osi.h"
 
 using base::StringPrintf;
+using bluetooth::Uuid;
 
 #define GATTP_MAX_NUM_INC_SVR 0
 #define GATTP_MAX_CHAR_NUM 2
@@ -84,6 +84,9 @@
   uint16_t conn_id = GATT_INVALID_CONN_ID;
   GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
                             BT_TRANSPORT_LE);
+  if (conn_id == GATT_INVALID_CONN_ID)
+    GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
+                              BT_TRANSPORT_BR_EDR);
   return conn_id;
 }
 
@@ -210,17 +213,16 @@
     case GATTS_REQ_TYPE_WRITE_EXEC:
     case GATT_CMD_WRITE:
       ignore = true;
-      VLOG(1) << StringPrintf("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD");
+      VLOG(1) << "Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD";
       break;
 
     case GATTS_REQ_TYPE_MTU:
-      VLOG(1) << StringPrintf("Get MTU exchange new mtu size: %d", p_data->mtu);
+      VLOG(1) << "Get MTU exchange new mtu size: " << +p_data->mtu;
       ignore = true;
       break;
 
     default:
-      VLOG(1) << StringPrintf("Unknown/unexpected LE GAP ATT request: 0x%02x",
-                              type);
+      VLOG(1) << "Unknown/unexpected LE GAP ATT request: " << loghex(type);
       break;
   }
 
@@ -240,9 +242,8 @@
                                const RawAddress& bda, uint16_t conn_id,
                                bool connected, tGATT_DISCONN_REASON reason,
                                tBT_TRANSPORT transport) {
-  VLOG(1) << __func__ << ": from " << bda
-          << StringPrintf(" connected:%d conn_id=%d reason = 0x%04x", connected,
-                          conn_id, reason);
+  VLOG(1) << __func__ << ": from " << bda << " connected: " << connected
+          << ", conn_id: " << loghex(conn_id) << "reason: " << loghex(reason);
 
   tGATT_PROFILE_CLCB* p_clcb =
       gatt_profile_find_clcb_by_bd_addr(bda, transport);
@@ -269,21 +270,19 @@
  *
  ******************************************************************************/
 void gatt_profile_db_init(void) {
-  tBT_UUID app_uuid = {LEN_UUID_128, {0}};
   uint16_t service_handle = 0;
 
   /* Fill our internal UUID with a fixed pattern 0x81 */
-  memset(&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
+  std::array<uint8_t, Uuid::kNumBytes128> tmp;
+  tmp.fill(0x81);
 
   /* Create a GATT profile service */
-  gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback);
+  gatt_cb.gatt_if = GATT_Register(Uuid::From128BitBE(tmp), &gatt_profile_cback);
   GATT_StartIf(gatt_cb.gatt_if);
 
-  bt_uuid_t service_uuid;
-  uuid_128_from_16(&service_uuid, UUID_SERVCLASS_GATT_SERVER);
+  Uuid service_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
 
-  bt_uuid_t char_uuid;
-  uuid_128_from_16(&char_uuid, GATT_UUID_GATT_SRV_CHGD);
+  Uuid char_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
 
   btgatt_db_element_t service[] = {
       {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = service_uuid},
@@ -298,8 +297,7 @@
   service_handle = service[0].attribute_handle;
   gatt_cb.handle_of_h_r = service[1].attribute_handle;
 
-  LOG(ERROR) << StringPrintf("gatt_profile_db_init:  gatt_if=%d",
-                             gatt_cb.gatt_if);
+  VLOG(1) << __func__ << ": gatt_if=" << +gatt_cb.gatt_if;
 }
 
 /*******************************************************************************
@@ -329,7 +327,7 @@
       break;
 
     case GATT_DISC_CHAR_DSCPT: /* stage 3 */
-      if (p_data->type.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
+      if (p_data->type == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)) {
         p_clcb->s_handle = p_data->handle;
         p_clcb->ccc_result++;
       }
@@ -352,14 +350,15 @@
 
   if (p_clcb == NULL) return;
 
-  if (status == GATT_SUCCESS && p_clcb->ccc_result > 0) {
-    p_clcb->ccc_result = 0;
-    p_clcb->ccc_stage++;
-    gatt_cl_start_config_ccc(p_clcb);
-  } else {
-    LOG(ERROR) << StringPrintf(
-        "%s() - Unable to register for service changed indication", __func__);
+  if (status != GATT_SUCCESS || p_clcb->ccc_result == 0) {
+    LOG(WARNING) << __func__
+                 << ": Unable to register for service changed indication";
+    return;
   }
+
+  p_clcb->ccc_result = 0;
+  p_clcb->ccc_stage++;
+  gatt_cl_start_config_ccc(p_clcb);
 }
 
 /*******************************************************************************
@@ -389,7 +388,7 @@
   tGATT_DISC_PARAM srvc_disc_param;
   tGATT_VALUE ccc_value;
 
-  VLOG(1) << StringPrintf("%s() - stage: %d", __func__, p_clcb->ccc_stage);
+  VLOG(1) << __func__ << ": stage: " << +p_clcb->ccc_stage;
 
   memset(&srvc_disc_param, 0, sizeof(tGATT_DISC_PARAM));
   memset(&ccc_value, 0, sizeof(tGATT_VALUE));
@@ -398,16 +397,14 @@
     case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
       srvc_disc_param.s_handle = 1;
       srvc_disc_param.e_handle = 0xffff;
-      srvc_disc_param.service.len = 2;
-      srvc_disc_param.service.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
+      srvc_disc_param.service = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
       GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param);
       break;
 
     case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
       srvc_disc_param.s_handle = 1;
       srvc_disc_param.e_handle = p_clcb->e_handle;
-      srvc_disc_param.service.len = 2;
-      srvc_disc_param.service.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+      srvc_disc_param.service = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
       GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param);
       break;
 
diff --git a/stack/gatt/gatt_auth.cc b/stack/gatt/gatt_auth.cc
index b91b56c..3794388 100644
--- a/stack/gatt/gatt_auth.cc
+++ b/stack/gatt/gatt_auth.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index 9e77e15..dca4973 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -44,6 +44,8 @@
 #define GATT_READ_BY_TYPE_RSP_MIN_LEN 1
 
 using base::StringPrintf;
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *                      G L O B A L      G A T T       D A T A                 *
  ******************************************************************************/
@@ -78,46 +80,51 @@
  ******************************************************************************/
 void gatt_act_discovery(tGATT_CLCB* p_clcb) {
   uint8_t op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
-  tGATT_CL_MSG cl_req;
-  tGATT_STATUS st;
 
-  if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0) {
-    memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
-
-    cl_req.browse.s_handle = p_clcb->s_handle;
-    cl_req.browse.e_handle = p_clcb->e_handle;
-
-    if (disc_type_to_uuid[p_clcb->op_subtype] != 0) {
-      cl_req.browse.uuid.len = 2;
-      cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
-    }
-
-    if (p_clcb->op_subtype ==
-        GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
-    {
-      cl_req.find_type_value.uuid.len = 2;
-      cl_req.find_type_value.uuid.uu.uuid16 =
-          disc_type_to_uuid[p_clcb->op_subtype];
-      cl_req.find_type_value.s_handle = p_clcb->s_handle;
-      cl_req.find_type_value.e_handle = p_clcb->e_handle;
-      cl_req.find_type_value.value_len = p_clcb->uuid.len;
-      /* if service type is 32 bits UUID, convert it now */
-      if (p_clcb->uuid.len == LEN_UUID_32) {
-        cl_req.find_type_value.value_len = LEN_UUID_128;
-        gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value,
-                                       p_clcb->uuid.uu.uuid32);
-      } else
-        memcpy(cl_req.find_type_value.value, &p_clcb->uuid.uu,
-               p_clcb->uuid.len);
-    }
-
-    st = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, op_code, &cl_req);
-
-    if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) {
-      gatt_end_operation(p_clcb, GATT_ERROR, NULL);
-    }
-  } else /* end of handle range */
+  if (p_clcb->s_handle > p_clcb->e_handle || p_clcb->s_handle == 0) {
+    /* end of handle range */
     gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+    return;
+  }
+
+  tGATT_CL_MSG cl_req;
+  memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
+
+  cl_req.browse.s_handle = p_clcb->s_handle;
+  cl_req.browse.e_handle = p_clcb->e_handle;
+
+  if (disc_type_to_uuid[p_clcb->op_subtype] != 0) {
+    cl_req.browse.uuid =
+        bluetooth::Uuid::From16Bit(disc_type_to_uuid[p_clcb->op_subtype]);
+  }
+
+  if (p_clcb->op_subtype ==
+      GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
+  {
+    cl_req.find_type_value.uuid =
+        bluetooth::Uuid::From16Bit(disc_type_to_uuid[p_clcb->op_subtype]);
+    cl_req.find_type_value.s_handle = p_clcb->s_handle;
+    cl_req.find_type_value.e_handle = p_clcb->e_handle;
+
+    size_t size = p_clcb->uuid.GetShortestRepresentationSize();
+    cl_req.find_type_value.value_len = size;
+    if (size == Uuid::kNumBytes16) {
+      uint8_t* p = cl_req.find_type_value.value;
+      UINT16_TO_STREAM(p, p_clcb->uuid.As16Bit());
+    } else if (size == Uuid::kNumBytes32) {
+      /* if service type is 32 bits UUID, convert it now */
+      memcpy(cl_req.find_type_value.value, p_clcb->uuid.To128BitLE().data(),
+            Uuid::kNumBytes128);
+      cl_req.find_type_value.value_len = Uuid::kNumBytes128;
+    } else
+      memcpy(cl_req.find_type_value.value, p_clcb->uuid.To128BitLE().data(),
+             size);
+  }
+
+  tGATT_STATUS st = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, op_code, &cl_req);
+  if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) {
+    gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+  }
 }
 
 /*******************************************************************************
@@ -144,10 +151,9 @@
       msg.browse.s_handle = p_clcb->s_handle;
       msg.browse.e_handle = p_clcb->e_handle;
       if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
-        memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
+        msg.browse.uuid = p_clcb->uuid;
       else {
-        msg.browse.uuid.len = LEN_UUID_16;
-        msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
+        msg.browse.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
       }
       break;
 
@@ -376,15 +382,13 @@
     return;
 
   memset(&result, 0, sizeof(tGATT_DISC_RES));
-  result.type.len = 2;
-  result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
+  result.type = bluetooth::Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
 
   /* returns a series of handle ranges */
   while (len >= 4) {
     STREAM_TO_UINT16(result.handle, p);
     STREAM_TO_UINT16(result.value.group_value.e_handle, p);
-    memcpy(&result.value.group_value.service_type, &p_clcb->uuid,
-           sizeof(tBT_UUID));
+    result.value.group_value.service_type = p_clcb->uuid;
 
     len -= 4;
 
@@ -431,9 +435,9 @@
   len -= 1;
 
   if (type == GATT_INFO_TYPE_PAIR_16)
-    uuid_len = LEN_UUID_16;
+    uuid_len = Uuid::kNumBytes16;
   else if (type == GATT_INFO_TYPE_PAIR_128)
-    uuid_len = LEN_UUID_128;
+    uuid_len = Uuid::kNumBytes128;
 
   while (len >= uuid_len + 2) {
     STREAM_TO_UINT16(result.handle, p);
@@ -441,7 +445,7 @@
     if (uuid_len > 0) {
       if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p)) break;
     } else
-      memcpy(&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
+      result.type = p_clcb->uuid;
 
     len -= (uuid_len + 2);
 
@@ -608,9 +612,11 @@
   tGATT_REG* p_reg;
   uint16_t conn_id;
   tGATT_STATUS encrypt_status;
-  uint8_t *p = p_data, i, event = (op_code == GATT_HANDLE_VALUE_NOTIF)
-                                      ? GATTC_OPTYPE_NOTIFICATION
-                                      : GATTC_OPTYPE_INDICATION;
+  uint8_t* p = p_data;
+  uint8_t i;
+  uint8_t event = (op_code == GATT_HANDLE_VALUE_NOTIF)
+                      ? GATTC_OPTYPE_NOTIFICATION
+                      : GATTC_OPTYPE_INDICATION;
 
   VLOG(1) << __func__;
 
@@ -738,8 +744,8 @@
     memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
 
     result.handle = handle;
-    result.type.len = 2;
-    result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+    result.type =
+        bluetooth::Uuid::From16Bit(disc_type_to_uuid[p_clcb->op_subtype]);
 
     /* discover all services */
     if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
@@ -772,8 +778,10 @@
       }
 
       if (value_len == 6) {
-        STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
-        record_value.incl_service.service_type.len = LEN_UUID_16;
+        uint16_t tmp;
+        STREAM_TO_UINT16(tmp, p);
+        record_value.incl_service.service_type =
+            bluetooth::Uuid::From16Bit(tmp);
       } else if (value_len == 4) {
         p_clcb->s_handle = record_value.incl_service.s_handle;
         p_clcb->read_uuid128.wait_for_read_rsp = true;
@@ -827,10 +835,14 @@
       }
 
       /* UUID not matching */
-      if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid)) {
+      if (!p_clcb->uuid.IsEmpty() &&
+          !record_value.dclr_value.char_uuid.IsEmpty() &&
+          record_value.dclr_value.char_uuid != p_clcb->uuid) {
         len -= (value_len + 2);
         continue; /* skip the result, and look for next one */
-      } else if (p_clcb->operation == GATTC_OPTYPE_READ)
+      }
+
+      if (p_clcb->operation == GATTC_OPTYPE_READ)
       /* UUID match for read characteristic value */
       {
         /* only read the first matching UUID characteristic value, and
@@ -926,12 +938,9 @@
         p_clcb->read_uuid128.wait_for_read_rsp) {
       p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
       p_clcb->read_uuid128.wait_for_read_rsp = false;
-      if (len == LEN_UUID_128) {
-        memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu
-                   .uuid128,
-               p, len);
-        p_clcb->read_uuid128.result.value.incl_service.service_type.len =
-            LEN_UUID_128;
+      if (len == Uuid::kNumBytes128) {
+        p_clcb->read_uuid128.result.value.incl_service.service_type =
+            bluetooth::Uuid::From128BitLE(p);
         if (p_clcb->p_reg->app_cb.p_disc_res_cb)
           (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
                                                  p_clcb->op_subtype,
diff --git a/stack/gatt/gatt_db.cc b/stack/gatt/gatt_db.cc
index ac3d959..31a262d 100644
--- a/stack/gatt/gatt_db.cc
+++ b/stack/gatt/gatt_db.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,10 +35,12 @@
 #include "osi/include/osi.h"
 
 using base::StringPrintf;
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *             L O C A L    F U N C T I O N     P R O T O T Y P E S            *
  ******************************************************************************/
-static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
+static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid,
                                        tGATT_PERM perm);
 static tGATT_STATUS gatts_send_app_read_request(
     tGATT_TCB& tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
@@ -47,8 +49,8 @@
 /**
  * Initialize a memory space to be a service database.
  */
-void gatts_init_service_db(tGATT_SVC_DB& db, tBT_UUID* p_service, bool is_pri,
-                           uint16_t s_hdl, uint16_t num_handle) {
+void gatts_init_service_db(tGATT_SVC_DB& db, const Uuid& service_uuid,
+                           bool is_pri, uint16_t s_hdl, uint16_t num_handle) {
   db.attr_list.reserve(num_handle);
 
   VLOG(1) << StringPrintf("%s: s_hdl= %d num_handle= %d", __func__, s_hdl,
@@ -59,14 +61,14 @@
   db.end_handle = s_hdl + num_handle;
 
   /* add service declration record */
-  tBT_UUID uuid = {LEN_UUID_16, {0}};
-  uuid.uu.uuid16 = is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE;
+  Uuid uuid =
+      Uuid::From16Bit(is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE);
   tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
-  attr.p_value.reset((tGATT_ATTR_VALUE*)(new tBT_UUID));
-  memcpy(&attr.p_value->uuid, p_service, sizeof(tBT_UUID));
+  attr.p_value.reset((tGATT_ATTR_VALUE*)(new Uuid));
+  attr.p_value->uuid = service_uuid;
 }
 
-tBT_UUID* gatts_get_service_uuid(tGATT_SVC_DB* p_db) {
+Uuid* gatts_get_service_uuid(tGATT_SVC_DB* p_db) {
   if (!p_db || p_db->attr_list.empty()) {
     LOG(ERROR) << "service DB empty";
     return NULL;
@@ -119,8 +121,8 @@
     return GATT_INSUF_KEY_SIZE;
   }
 
-  if (read_long && attr.uuid.len == LEN_UUID_16) {
-    switch (attr.uuid.uu.uuid16) {
+  if (read_long && attr.uuid.Is16Bit()) {
+    switch (attr.uuid.As16Bit()) {
       case GATT_UUID_PRI_SERVICE:
       case GATT_UUID_SEC_SERVICE:
       case GATT_UUID_CHAR_DECLARE:
@@ -146,13 +148,13 @@
  *
  * Description      Utility function to read an attribute value.
  *
- * Parameter        p_attr: pointer to the attribute to read.
+ * Parameter        attr16: pointer to the attribute to read.
  *                  offset: read offset.
- *                  p_value: output parameter to carry out the attribute value.
- *                  p_len: output parameter to carry out the attribute length.
+ *                  p_data: output parameter to carry out the attribute value.
  *                  read_long: this is a read blob request.
  *                  mtu: MTU
- *                  sec_flag: current link security status.
+ *                  p_len: output parameter to carry out the attribute length.
+ *                   sec_flag: current link security status.
  *                  key_size: encryption key size.
  *
  * Returns          status of operation.
@@ -162,75 +164,73 @@
                                     uint8_t** p_data, bool read_long,
                                     uint16_t mtu, uint16_t* p_len,
                                     tGATT_SEC_FLAG sec_flag, uint8_t key_size) {
-  uint16_t len = 0, uuid16 = 0;
   uint8_t* p = *p_data;
 
-  VLOG(1)
-      << __func__
-      << StringPrintf(
-             " uuid=0x%04x perm=0x%02x sec_flag=0x%x offset=%d read_long=%d",
-             attr16.uuid.uu.uuid16, attr16.permission, sec_flag, offset,
-             read_long);
+  VLOG(1) << __func__ << " uuid=" << attr16.uuid
+          << StringPrintf(" perm=0x%02x sec_flag=0x%x offset=%d read_long=%d",
+                          attr16.permission, sec_flag, offset, read_long);
 
   tGATT_STATUS status = gatts_check_attr_readability(attr16, offset, read_long,
                                                      sec_flag, key_size);
-
   if (status != GATT_SUCCESS) return status;
 
-  if (attr16.uuid.len == LEN_UUID_16) uuid16 = attr16.uuid.uu.uuid16;
-
-  status = GATT_NO_RESOURCES;
-
-  if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) {
-    len = attr16.p_value->uuid.len;
-    if (mtu >= attr16.p_value->uuid.len) {
-      gatt_build_uuid_to_stream(&p, attr16.p_value->uuid);
-      status = GATT_SUCCESS;
-    }
-  } else if (uuid16 == GATT_UUID_CHAR_DECLARE) {
-    tGATT_ATTR* val_attr = &attr16 + 1;
-    len = (val_attr->uuid.len == LEN_UUID_16) ? 5 : 19;
-
-    if (mtu >= len) {
-      UINT8_TO_STREAM(p, attr16.p_value->char_decl.property);
-      UINT16_TO_STREAM(p, attr16.p_value->char_decl.char_val_handle);
-
-      if (val_attr->uuid.len == LEN_UUID_16) {
-        UINT16_TO_STREAM(p, val_attr->uuid.uu.uuid16);
-      }
-      /* convert a 32bits UUID to 128 bits */
-      else if (val_attr->uuid.len == LEN_UUID_32) {
-        gatt_convert_uuid32_to_uuid128(p, val_attr->uuid.uu.uuid32);
-        p += LEN_UUID_128;
-      } else {
-        ARRAY_TO_STREAM(p, val_attr->uuid.uu.uuid128, LEN_UUID_128);
-      }
-      status = GATT_SUCCESS;
-    }
-
-  } else if (uuid16 == GATT_UUID_INCLUDE_SERVICE) {
-    if (attr16.p_value->incl_handle.service_type.len == LEN_UUID_16)
-      len = 6;
-    else
-      len = 4;
-
-    if (mtu >= len) {
-      UINT16_TO_STREAM(p, attr16.p_value->incl_handle.s_handle);
-      UINT16_TO_STREAM(p, attr16.p_value->incl_handle.e_handle);
-
-      if (attr16.p_value->incl_handle.service_type.len == LEN_UUID_16) {
-        UINT16_TO_STREAM(p, attr16.p_value->incl_handle.service_type.uu.uuid16);
-      }
-      status = GATT_SUCCESS;
-    }
-  } else /* characteristic description or characteristic value */
-  {
-    status = GATT_PENDING;
+  if (!attr16.uuid.Is16Bit()) {
+    /* characteristic description or characteristic value */
+    return GATT_PENDING;
   }
 
-  *p_len = len;
-  *p_data = p;
-  return status;
+  uint16_t uuid16 = attr16.uuid.As16Bit();
+
+  if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) {
+    *p_len = gatt_build_uuid_to_stream_len(attr16.p_value->uuid);
+    if (mtu < *p_len) return GATT_NO_RESOURCES;
+
+    gatt_build_uuid_to_stream(&p, attr16.p_value->uuid);
+    *p_data = p;
+    return GATT_SUCCESS;
+  }
+
+  if (uuid16 == GATT_UUID_CHAR_DECLARE) {
+    tGATT_ATTR* val_attr = &attr16 + 1;
+    uint8_t val_len = val_attr->uuid.GetShortestRepresentationSize();
+    *p_len = (val_len == Uuid::kNumBytes16) ? 5 : 19;
+
+    if (mtu < *p_len) return GATT_NO_RESOURCES;
+
+    UINT8_TO_STREAM(p, attr16.p_value->char_decl.property);
+    UINT16_TO_STREAM(p, attr16.p_value->char_decl.char_val_handle);
+
+    if (val_len == Uuid::kNumBytes16) {
+      UINT16_TO_STREAM(p, val_attr->uuid.As16Bit());
+    } else {
+      /* if 32 bit UUID, convert to 128 bit */
+      ARRAY_TO_STREAM(p, val_attr->uuid.To128BitLE(), (int)Uuid::kNumBytes128);
+    }
+    *p_data = p;
+    return GATT_SUCCESS;
+  }
+
+  if (uuid16 == GATT_UUID_INCLUDE_SERVICE) {
+    tGATT_INCL_SRVC& incl_handle = attr16.p_value->incl_handle;
+    if (incl_handle.service_type.Is16Bit())
+      *p_len = 6;
+    else
+      *p_len = 4;
+
+    if (mtu < *p_len) return GATT_NO_RESOURCES;
+
+    UINT16_TO_STREAM(p, incl_handle.s_handle);
+    UINT16_TO_STREAM(p, incl_handle.e_handle);
+
+    if (incl_handle.service_type.Is16Bit()) {
+      UINT16_TO_STREAM(p, incl_handle.service_type.As16Bit());
+    }
+    *p_data = p;
+    return GATT_SUCCESS;
+  }
+
+  /* characteristic description or characteristic value (again) */
+  return GATT_PENDING;
 }
 
 /*******************************************************************************
@@ -253,7 +253,7 @@
  ******************************************************************************/
 tGATT_STATUS gatts_db_read_attr_value_by_type(
     tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
-    uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
+    uint16_t s_handle, uint16_t e_handle, const Uuid& type, uint16_t* p_len,
     tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
     uint16_t* p_cur_handle) {
   tGATT_STATUS status = GATT_NOT_FOUND;
@@ -262,9 +262,7 @@
 
   if (p_db) {
     for (tGATT_ATTR& attr : p_db->attr_list) {
-      tBT_UUID attr_uuid = attr.uuid;
-
-      if (attr.handle >= s_handle && gatt_uuid_compare(type, attr_uuid)) {
+      if (attr.handle >= s_handle && type == attr.uuid) {
         if (*p_len <= 2) {
           status = GATT_NO_RESOURCES;
           break;
@@ -304,7 +302,7 @@
   uint8_t flag = 0;
   if (BTM_GetSecurityFlags(tcb.peer_bda, &flag)) {
     if ((tcb.att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
-        (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) {
+        (type.As16Bit() == GATT_UUID_GAP_DEVICE_NAME)) {
       if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
           BTM_SEC_LINK_KEY_KNOWN) {
         tACL_CONN* p = btm_bda_to_acl(tcb.peer_bda, BT_TRANSPORT_LE);
@@ -328,13 +326,14 @@
  *
  */
 uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
-                                    uint16_t e_handle, tBT_UUID service) {
-  tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}};
+                                    uint16_t e_handle, const Uuid& service) {
+  Uuid uuid = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
 
-  VLOG(1) << StringPrintf("%s: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x",
-                          __func__, s_handle, e_handle, service.uu.uuid16);
+  VLOG(1) << __func__
+          << StringPrintf(": s_hdl=0x%04x e_hdl=0x%04x ", s_handle, e_handle)
+          << "service uuid = " << service;
 
-  if (service.len == 0 || s_handle == 0 || e_handle == 0) {
+  if (service.IsEmpty() || s_handle == 0 || e_handle == 0) {
     LOG(ERROR) << __func__ << ": Illegal Params.";
     return 0;
   }
@@ -344,7 +343,7 @@
   attr.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_INCL_SRVC));
   attr.p_value->incl_handle.s_handle = s_handle;
   attr.p_value->incl_handle.e_handle = e_handle;
-  memcpy(&attr.p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
+  attr.p_value->incl_handle.service_type = service;
 
   return attr.handle;
 }
@@ -366,8 +365,8 @@
  ******************************************************************************/
 uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
                                   tGATT_CHAR_PROP property,
-                                  tBT_UUID& char_uuid) {
-  tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}};
+                                  const Uuid& char_uuid) {
+  Uuid uuid = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
 
   VLOG(1) << StringPrintf("%s: perm=0x%0x property=0x%0x", __func__, perm,
                           property);
@@ -384,46 +383,6 @@
 
 /*******************************************************************************
  *
- * Function         gatt_convertchar_descr_type
- *
- * Description      Convert a char descript UUID into descriptor type.
- *
- * Returns          descriptor type.
- *
- ******************************************************************************/
-uint8_t gatt_convertchar_descr_type(tBT_UUID* p_descr_uuid) {
-  tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
-
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid))
-    return GATT_DESCR_EXT_DSCPTOR;
-
-  std_descr.uu.uuid16++;
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid))
-    return GATT_DESCR_USER_DSCPTOR;
-
-  std_descr.uu.uuid16++;
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid)) return GATT_DESCR_CLT_CONFIG;
-
-  std_descr.uu.uuid16++;
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid)) return GATT_DESCR_SVR_CONFIG;
-
-  std_descr.uu.uuid16++;
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid))
-    return GATT_DESCR_PRES_FORMAT;
-
-  std_descr.uu.uuid16++;
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid))
-    return GATT_DESCR_AGGR_FORMAT;
-
-  std_descr.uu.uuid16++;
-  if (gatt_uuid_compare(std_descr, *p_descr_uuid))
-    return GATT_DESCR_VALID_RANGE;
-
-  return GATT_DESCR_UNKNOWN;
-}
-
-/*******************************************************************************
- *
  * Function         gatts_add_char_descr
  *
  * Description      This function add a characteristics descriptor.
@@ -437,9 +396,9 @@
  *
  ******************************************************************************/
 uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
-                              tBT_UUID& descr_uuid) {
-  VLOG(1) << StringPrintf("gatts_add_char_descr uuid=0x%04x",
-                          descr_uuid.uu.uuid16);
+                              const Uuid& descr_uuid) {
+  VLOG(1) << StringPrintf("gatts_add_char_descr uuid=%s",
+                          descr_uuid.ToString().c_str());
 
   /* Add characteristic descriptors */
   tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, perm);
@@ -626,13 +585,14 @@
     status = GATT_INSUF_AUTHENTICATION;
     LOG(ERROR) << __func__
                << ": GATT_INSUF_AUTHENTICATION: LE security mode 2 required";
-  } else /* writable: must be char value declaration or char descritpors
-            */
+  } else /* writable: must be char value declaration or char descritpors */
   {
     uint16_t max_size = 0;
 
-    if (p_attr->uuid.len == LEN_UUID_16) {
-      switch (p_attr->uuid.uu.uuid16) {
+    if (p_attr->uuid.IsEmpty()) {
+      status = GATT_INVALID_PDU;
+    } else if (p_attr->uuid.Is16Bit()) {
+      switch (p_attr->uuid.As16Bit()) {
         case GATT_UUID_CHAR_PRESENT_FORMAT: /* should be readable only */
         case GATT_UUID_CHAR_EXT_PROP:       /* should be readable only */
         case GATT_UUID_CHAR_AGG_FORMAT:     /* should be readable only */
@@ -650,31 +610,28 @@
           status = GATT_SUCCESS;
           break;
       }
-    } else if (p_attr->uuid.len == LEN_UUID_128 ||
-               p_attr->uuid.len == LEN_UUID_32) {
+    } else {  // 32 or 128 bit UUID
       status = GATT_SUCCESS;
-    } else {
-      status = GATT_INVALID_PDU;
     }
 
     if (p_data == NULL && len > 0) {
-      status = GATT_INVALID_PDU;
+      return GATT_INVALID_PDU;
     }
+
     /* these attribute does not allow write blob */
-    else if ((p_attr->uuid.len == LEN_UUID_16) &&
-             (p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG ||
-              p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_SRVR_CONFIG)) {
-      if (op_code == GATT_REQ_PREPARE_WRITE &&
-          offset != 0) /* does not allow write blob */
-      {
+    if (p_attr->uuid.Is16Bit() &&
+        (p_attr->uuid.As16Bit() == GATT_UUID_CHAR_CLIENT_CONFIG ||
+         p_attr->uuid.As16Bit() == GATT_UUID_CHAR_SRVR_CONFIG)) {
+      if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) {
+        /* does not allow write blob */
         status = GATT_NOT_LONG;
         LOG(ERROR) << __func__ << ": GATT_NOT_LONG";
-      } else if (len != max_size) /* data does not match the required format */
-      {
+      } else if (len != max_size) {
+        /* data does not match the required format */
         status = GATT_INVALID_ATTR_LEN;
         LOG(ERROR) << __func__ << ": GATT_INVALID_PDU";
       } else {
-        status = GATT_SUCCESS;
+        return GATT_SUCCESS;
       }
     }
   }
@@ -682,26 +639,6 @@
   return status;
 }
 
-static void uuid_to_str(const tBT_UUID bt_uuid, char* str_buf, size_t buf_len) {
-  if (bt_uuid.len == LEN_UUID_16) {
-    snprintf(str_buf, buf_len, "0x%04x", bt_uuid.uu.uuid16);
-  } else if (bt_uuid.len == LEN_UUID_32) {
-    snprintf(str_buf, buf_len, "0x%08x", bt_uuid.uu.uuid32);
-  } else if (bt_uuid.len == LEN_UUID_128) {
-    int x = snprintf(str_buf, buf_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-",
-                     bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
-                     bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
-                     bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
-                     bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
-    snprintf(&str_buf[x], buf_len - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
-             bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
-             bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
-             bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
-             bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
-  } else
-    snprintf(str_buf, buf_len, "Unknown (len=%d)", bt_uuid.len);
-}
-
 /**
  * Description      Allocate a memory space for a new attribute, and link this
  *                  attribute into the database attribute list.
@@ -713,7 +650,7 @@
  * Returns          pointer to the newly allocated attribute.
  *
  */
-static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
+static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid,
                                        tGATT_PERM perm) {
   if (db.next_handle >= db.end_handle) {
     LOG(FATAL) << __func__
@@ -726,10 +663,6 @@
   attr.handle = db.next_handle++;
   attr.uuid = uuid;
   attr.permission = perm;
-
-  char uuid_str[37];
-  uuid_to_str(attr.uuid, uuid_str, sizeof(uuid_str));
-
   return attr;
 }
 
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index cb0ad3e..5052918 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -101,7 +101,7 @@
 
 /*  GATT client FIND_TYPE_VALUE_Request data */
 typedef struct {
-  tBT_UUID uuid;      /* type of attribute to be found */
+  bluetooth::Uuid uuid; /* type of attribute to be found */
   uint16_t s_handle;  /* starting handle */
   uint16_t e_handle;  /* ending handle */
   uint16_t value_len; /* length of the attribute value */
@@ -152,7 +152,7 @@
 /* attribute value maintained in the server database
 */
 typedef union {
-  tBT_UUID uuid;               /* service declaration */
+  bluetooth::Uuid uuid;        /* service declaration */
   tGATT_CHAR_DECL char_decl;   /* characteristic declaration */
   tGATT_INCL_SRVC incl_handle; /* included service */
 } tGATT_ATTR_VALUE;
@@ -170,7 +170,7 @@
   std::unique_ptr<tGATT_ATTR_VALUE> p_value;
   tGATT_PERM permission;
   uint16_t handle;
-  tBT_UUID uuid;
+  bluetooth::Uuid uuid;
   bt_gatt_db_attribute_type_t gatt_type;
 } tGATT_ATTR;
 
@@ -188,7 +188,7 @@
 /* attribute handle, service UUID and a set of GATT server callback.          */
 
 typedef struct {
-  tBT_UUID app_uuid128;
+  bluetooth::Uuid app_uuid128;
   tGATT_CBACK app_cb;
   tGATT_IF gatt_if; /* one based */
   bool in_use;
@@ -254,7 +254,7 @@
 /* attribute handle, service UUID and a set of GATT server callback.          */
 typedef struct {
   tGATT_SVC_DB* p_db;  /* pointer to the service database */
-  tBT_UUID app_uuid;   /* applicatino UUID */
+  bluetooth::Uuid app_uuid; /* application UUID */
   uint32_t sdp_handle; /* primamry service SDP handle */
   uint16_t type;       /* service type UUID, primary or secondary */
   uint16_t s_hdl;      /* service starting handle */
@@ -308,7 +308,7 @@
   tGATT_REG* p_reg; /* owner of this CLCB */
   uint8_t sccb_idx;
   uint8_t* p_attr_buf; /* attribute buffer for read multiple, prepare write */
-  tBT_UUID uuid;
+  bluetooth::Uuid uuid;
   uint16_t conn_id; /* connection handle */
   uint16_t s_handle; /* starting handle of the active request */
   uint16_t e_handle; /* ending handle of the active request */
@@ -361,7 +361,7 @@
   fixed_queue_t* sign_op_queue;
 
   uint16_t next_handle;     /* next available handle */
-  uint16_t last_primary_s_handle; /* handle of last primary service */
+  uint16_t last_service_handle; /* handle of last service */
   tGATT_SVC_CHG gattp_attr; /* GATT profile attribute service change */
   tGATT_IF gatt_if;
   std::list<tGATT_HDL_LIST_ELEM>* hdl_list_info;
@@ -432,14 +432,13 @@
 
 /* utility functions */
 extern uint8_t* gatt_dbg_op_name(uint8_t op_code);
-extern uint32_t gatt_add_sdp_record(tBT_UUID* p_uuid, uint16_t start_hdl,
-                                    uint16_t end_hdl);
-extern bool gatt_parse_uuid_from_cmd(tBT_UUID* p_uuid, uint16_t len,
+extern uint32_t gatt_add_sdp_record(const bluetooth::Uuid& uuid,
+                                    uint16_t start_hdl, uint16_t end_hdl);
+extern bool gatt_parse_uuid_from_cmd(bluetooth::Uuid* p_uuid, uint16_t len,
                                      uint8_t** p_data);
-extern uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst, tBT_UUID uuid);
-extern bool gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
-extern void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
-                                           uint32_t uuid_32);
+extern uint8_t gatt_build_uuid_to_stream_len(const bluetooth::Uuid& uuid);
+extern uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst,
+                                         const bluetooth::Uuid& uuid);
 extern void gatt_sr_get_sec_info(const RawAddress& rem_bda,
                                  tBT_TRANSPORT transport, uint8_t* p_sec_flag,
                                  uint8_t* p_key_size);
@@ -452,7 +451,6 @@
 extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB& tcb, uint8_t err_code,
                                         uint8_t op_code, uint16_t handle,
                                         bool deq);
-extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid);
 
 extern bool gatt_is_srv_chg_ind_pending(tGATT_TCB* p_tcb);
 extern tGATTS_SRV_CHG* gatt_is_bda_in_the_srv_chg_clt_list(
@@ -464,12 +462,13 @@
 extern void gatt_set_srv_chg(void);
 extern void gatt_delete_dev_from_srv_chg_clt_list(const RawAddress& bd_addr);
 extern tGATT_VALUE* gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind);
-extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID* p_app_id);
+extern void gatt_free_srvc_db_buffer_app_id(const bluetooth::Uuid& app_id);
 extern bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb);
 
 /* reserved handle list */
 extern std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
-    tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid, uint16_t svc_inst);
+    const bluetooth::Uuid& app_uuid128, bluetooth::Uuid* p_svc_uuid,
+    uint16_t svc_inst);
 extern tGATT_HDL_LIST_ELEM* gatt_find_hdl_buffer_by_handle(uint16_t handle);
 extern tGATTS_SRV_CHG* gatt_add_srv_chg_clt(tGATTS_SRV_CHG* p_srv_chg);
 
@@ -486,9 +485,6 @@
 /* server function */
 extern std::list<tGATT_SRV_LIST_ELEM>::iterator gatt_sr_find_i_rcb_by_handle(
     uint16_t handle);
-extern bool gatt_sr_find_i_rcb_by_app_id(tBT_UUID* p_app_uuid128,
-                                         tBT_UUID* p_svc_uuid,
-                                         uint16_t svc_inst);
 extern tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB& tcb, tGATT_IF gatt_if,
                                             uint32_t trans_id, uint8_t op_code,
                                             tGATT_STATUS status,
@@ -500,9 +496,8 @@
 extern uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint8_t op_code,
                                     uint16_t handle);
 extern bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda);
-extern void gatt_notify_phy_updated(tGATT_TCB* p_tcb, uint8_t tx_phy,
-                                    uint8_t rx_phy, uint8_t status);
-
+extern void gatt_notify_phy_updated(uint8_t status, uint16_t handle,
+                                    uint8_t tx_phy, uint8_t rx_phy);
 /*   */
 
 extern tGATT_REG* gatt_get_regcb(tGATT_IF gatt_if);
@@ -560,21 +555,22 @@
 extern void gatt_set_sec_act(tGATT_TCB* p_tcb, tGATT_SEC_ACTION sec_act);
 
 /* gatt_db.cc */
-extern void gatts_init_service_db(tGATT_SVC_DB& db, tBT_UUID* p_service,
-                                  bool is_pri, uint16_t s_hdl,
-                                  uint16_t num_handle);
+extern void gatts_init_service_db(tGATT_SVC_DB& db,
+                                  const bluetooth::Uuid& service, bool is_pri,
+                                  uint16_t s_hdl, uint16_t num_handle);
 extern uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
-                                           uint16_t e_handle, tBT_UUID service);
+                                           uint16_t e_handle,
+                                           const bluetooth::Uuid& service);
 extern uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
                                          tGATT_CHAR_PROP property,
-                                         tBT_UUID& char_uuid);
+                                         const bluetooth::Uuid& char_uuid);
 extern uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
-                                     tBT_UUID& dscp_uuid);
+                                     const bluetooth::Uuid& dscp_uuid);
 extern tGATT_STATUS gatts_db_read_attr_value_by_type(
     tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
-    uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
-    tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
-    uint16_t* p_cur_handle);
+    uint16_t s_handle, uint16_t e_handle, const bluetooth::Uuid& type,
+    uint16_t* p_len, tGATT_SEC_FLAG sec_flag, uint8_t key_size,
+    uint32_t trans_id, uint16_t* p_cur_handle);
 extern tGATT_STATUS gatts_read_attr_value_by_handle(
     tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
     uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu,
@@ -586,6 +582,6 @@
                                                uint16_t handle,
                                                tGATT_SEC_FLAG sec_flag,
                                                uint8_t key_size);
-extern tBT_UUID* gatts_get_service_uuid(tGATT_SVC_DB* p_db);
+extern bluetooth::Uuid* gatts_get_service_uuid(tGATT_SVC_DB* p_db);
 
 #endif
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index 3556b43..afae25f 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@
 #define GATT_L2C_CFG_CFM_DONE (1 << 1)
 
 /* minimum GATT MTU size over BR/EDR link
-*/
+ */
 #define GATT_MIN_BR_MTU_SIZE 48
 
 /******************************************************************************/
@@ -80,7 +80,8 @@
                                           NULL,
                                           gatt_l2cif_data_ind_cback,
                                           gatt_l2cif_congest_cback,
-                                          NULL};
+                                          NULL,
+                                          NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 tGATT_CB gatt_cb;
 
@@ -476,7 +477,7 @@
   uint16_t conn_id;
 
   /* if uncongested, check to see if there is any more pending data */
-  if (p_tcb != NULL && congested == false) {
+  if (p_tcb != NULL && !congested) {
     gatt_cl_send_next_cmd_inq(*p_tcb);
   }
   /* notifying all applications for the connection up event */
@@ -490,8 +491,18 @@
   }
 }
 
-void gatt_notify_phy_updated(tGATT_TCB* p_tcb, uint8_t tx_phy, uint8_t rx_phy,
-                             uint8_t status) {
+void gatt_notify_phy_updated(uint8_t status, uint16_t handle, uint8_t tx_phy,
+                             uint8_t rx_phy) {
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+  if (!p_dev_rec) {
+    BTM_TRACE_WARNING("%s: No Device Found!", __func__);
+    return;
+  }
+
+  tGATT_TCB* p_tcb =
+      gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+  if (p_tcb == NULL) return;
+
   for (int i = 0; i < GATT_MAX_APPS; i++) {
     tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
     if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) {
@@ -956,8 +967,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;
   }
 
@@ -1075,7 +1089,7 @@
         req.client_read_index = i;
         status = (*gatt_cb.cb_info.p_srv_chg_callback)(
             GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp);
-        if (status == true) {
+        if (status) {
           memcpy(&srv_chg_clt, &rsp.srv_chg, sizeof(tGATTS_SRV_CHG));
           if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) {
             LOG(ERROR) << "Unable to add a service change client";
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index f9e8f53..b9921fe 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,6 +34,8 @@
 #define GATT_MTU_REQ_MIN_LEN 2
 
 using base::StringPrintf;
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *
  * Function         gatt_sr_enqueue_cmd
@@ -333,7 +335,7 @@
   } else /* nothing needs to be executed , send response now */
   {
     LOG(ERROR) << "gatt_process_exec_write_req: no prepare write pending";
-    gatt_send_error_rsp(tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+    gatt_send_error_rsp(tcb, GATT_INVALID_OFFSET, GATT_REQ_EXEC_WRITE, 0, false);
   }
 }
 
@@ -449,57 +451,59 @@
  ******************************************************************************/
 static tGATT_STATUS gatt_build_primary_service_rsp(
     BT_HDR* p_msg, tGATT_TCB& tcb, uint8_t op_code, uint16_t s_hdl,
-    uint16_t e_hdl, UNUSED_ATTR uint8_t* p_data, tBT_UUID value) {
+    uint16_t e_hdl, UNUSED_ATTR uint8_t* p_data, const Uuid& value) {
   tGATT_STATUS status = GATT_NOT_FOUND;
-  uint8_t handle_len = 4, *p;
-  tBT_UUID* p_uuid;
+  uint8_t handle_len = 4;
 
-  p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+  uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
 
   for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
-    if (el.s_hdl >= s_hdl && el.s_hdl <= e_hdl &&
-        el.type == GATT_UUID_PRI_SERVICE) {
-      p_uuid = gatts_get_service_uuid(el.p_db);
-      if (p_uuid != NULL) {
-        if (op_code == GATT_REQ_READ_BY_GRP_TYPE) handle_len = 4 + p_uuid->len;
+    if (el.s_hdl < s_hdl || el.s_hdl > e_hdl ||
+        el.type != GATT_UUID_PRI_SERVICE) {
+      continue;
+    }
 
-        /* get the length byte in the repsonse */
-        if (p_msg->offset == 0) {
-          *p++ = op_code + 1;
-          p_msg->len++;
-          p_msg->offset = handle_len;
+    Uuid* p_uuid = gatts_get_service_uuid(el.p_db);
+    if (!p_uuid) continue;
 
-          if (op_code == GATT_REQ_READ_BY_GRP_TYPE) {
-            *p++ = (uint8_t)p_msg->offset; /* length byte */
-            p_msg->len++;
-          }
-        }
+    if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+      handle_len = 4 + gatt_build_uuid_to_stream_len(*p_uuid);
 
-        if (p_msg->len + p_msg->offset <= tcb.payload_size &&
-            handle_len == p_msg->offset) {
-          if (op_code != GATT_REQ_FIND_TYPE_VALUE ||
-              gatt_uuid_compare(value, *p_uuid)) {
-            UINT16_TO_STREAM(p, el.s_hdl);
+    /* get the length byte in the repsonse */
+    if (p_msg->offset == 0) {
+      *p++ = op_code + 1;
+      p_msg->len++;
+      p_msg->offset = handle_len;
 
-            if (gatt_cb.last_primary_s_handle &&
-                gatt_cb.last_primary_s_handle == el.s_hdl) {
-              VLOG(1) << "Use 0xFFFF for the last primary attribute";
-              /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
-              UINT16_TO_STREAM(p, 0xFFFF);
-            } else {
-              UINT16_TO_STREAM(p, el.e_hdl);
-            }
-
-            if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
-              gatt_build_uuid_to_stream(&p, *p_uuid);
-
-            status = GATT_SUCCESS;
-            p_msg->len += p_msg->offset;
-          }
-        } else
-          break;
+      if (op_code == GATT_REQ_READ_BY_GRP_TYPE) {
+        *p++ = (uint8_t)p_msg->offset; /* length byte */
+        p_msg->len++;
       }
     }
+
+    if (p_msg->len + p_msg->offset > tcb.payload_size ||
+        handle_len != p_msg->offset) {
+      break;
+    }
+
+    if (op_code == GATT_REQ_FIND_TYPE_VALUE && value != *p_uuid) continue;
+
+    UINT16_TO_STREAM(p, el.s_hdl);
+
+    if (gatt_cb.last_service_handle &&
+        gatt_cb.last_service_handle == el.s_hdl) {
+      VLOG(1) << "Use 0xFFFF for the last primary attribute";
+      /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
+      UINT16_TO_STREAM(p, 0xFFFF);
+    } else {
+      UINT16_TO_STREAM(p, el.e_hdl);
+    }
+
+    if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+      gatt_build_uuid_to_stream(&p, *p_uuid);
+
+    status = GATT_SUCCESS;
+    p_msg->len += p_msg->offset;
   }
   p_msg->offset = L2CAP_MIN_OFFSET;
 
@@ -528,25 +532,25 @@
 
     if (attr.handle < s_hdl) continue;
 
+    uint8_t uuid_len = attr.uuid.GetShortestRepresentationSize();
     if (p_msg->offset == 0)
-      p_msg->offset = (attr.uuid.len == LEN_UUID_16) ? GATT_INFO_TYPE_PAIR_16
-                                                     : GATT_INFO_TYPE_PAIR_128;
+      p_msg->offset = (uuid_len == Uuid::kNumBytes16) ? GATT_INFO_TYPE_PAIR_16
+                                                      : GATT_INFO_TYPE_PAIR_128;
 
     if (len < info_pair_len[p_msg->offset - 1]) return GATT_NO_RESOURCES;
 
     if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 &&
-        attr.uuid.len == LEN_UUID_16) {
+        uuid_len == Uuid::kNumBytes16) {
       UINT16_TO_STREAM(p, attr.handle);
-      UINT16_TO_STREAM(p, attr.uuid.uu.uuid16);
+      UINT16_TO_STREAM(p, attr.uuid.As16Bit());
     } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
-               attr.uuid.len == LEN_UUID_128) {
+               uuid_len == Uuid::kNumBytes128) {
       UINT16_TO_STREAM(p, attr.handle);
-      ARRAY_TO_STREAM(p, attr.uuid.uu.uuid128, LEN_UUID_128);
+      ARRAY_TO_STREAM(p, attr.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
     } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
-               attr.uuid.len == LEN_UUID_32) {
+               uuid_len == Uuid::kNumBytes32) {
       UINT16_TO_STREAM(p, attr.handle);
-      gatt_convert_uuid32_to_uuid128(p, attr.uuid.uu.uuid32);
-      p += LEN_UUID_128;
+      ARRAY_TO_STREAM(p, attr.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
     } else {
       LOG(ERROR) << "format mismatch";
       return GATT_NO_RESOURCES;
@@ -571,14 +575,14 @@
 
   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;
 }
 
 static tGATT_STATUS gatts_validate_packet_format(uint8_t op_code, uint16_t& len,
-                                                 uint8_t*& p, tBT_UUID* p_uuid,
+                                                 uint8_t*& p, Uuid* p_uuid,
                                                  uint16_t& s_hdl,
                                                  uint16_t& e_hdl) {
   tGATT_STATUS ret = read_handles(len, p, s_hdl, e_hdl);
@@ -612,7 +616,7 @@
 void gatts_process_primary_service_req(tGATT_TCB& tcb, uint8_t op_code,
                                        uint16_t len, uint8_t* p_data) {
   uint16_t s_hdl = 0, e_hdl = 0;
-  tBT_UUID uuid;
+  Uuid uuid = Uuid::kEmpty;
 
   uint8_t reason =
       gatts_validate_packet_format(op_code, len, p_data, &uuid, s_hdl, e_hdl);
@@ -621,27 +625,25 @@
     return;
   }
 
-  tBT_UUID primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}};
-  if (!gatt_uuid_compare(uuid, primary_service)) {
+  if (uuid != Uuid::From16Bit(GATT_UUID_PRI_SERVICE)) {
     if (op_code == GATT_REQ_READ_BY_GRP_TYPE) {
       gatt_send_error_rsp(tcb, GATT_UNSUPPORT_GRP_TYPE, op_code, s_hdl, false);
-      VLOG(1) << StringPrintf("unexpected ReadByGrpType Group: 0x%04x",
-                              uuid.uu.uuid16);
+      VLOG(1) << StringPrintf("unexpected ReadByGrpType Group: %s",
+                              uuid.ToString().c_str());
       return;
     }
 
     // we do not support ReadByTypeValue with any non-primamry_service type
     gatt_send_error_rsp(tcb, GATT_NOT_FOUND, op_code, s_hdl, false);
-    VLOG(1) << StringPrintf("unexpected ReadByTypeValue type: 0x%04x",
-                            uuid.uu.uuid16);
+    VLOG(1) << StringPrintf("unexpected ReadByTypeValue type: %s",
+                            uuid.ToString().c_str());
     return;
   }
 
   // TODO: we assume theh value is UUID, there is no such requirement in spec
-  tBT_UUID value;
-  memset(&value, 0, sizeof(tBT_UUID));
+  Uuid value = Uuid::kEmpty;
   if (op_code == GATT_REQ_FIND_TYPE_VALUE) {
-    if (gatt_parse_uuid_from_cmd(&value, len, &p_data) == false) {
+    if (!gatt_parse_uuid_from_cmd(&value, len, &p_data)) {
       gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, s_hdl, false);
     }
   }
@@ -787,9 +789,8 @@
  ******************************************************************************/
 void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint8_t op_code,
                                     uint16_t len, uint8_t* p_data) {
-  tBT_UUID uuid;
+  Uuid uuid = Uuid::kEmpty;
   uint16_t s_hdl = 0, e_hdl = 0, err_hdl = 0;
-  if (len < 4) android_errorWriteLog(0x534e4554, "73125709");
   tGATT_STATUS reason =
       gatts_validate_packet_format(op_code, len, p_data, &uuid, s_hdl, e_hdl);
 
diff --git a/stack/gatt/gatt_utils.cc b/stack/gatt/gatt_utils.cc
index e7cc762..9e8d3b9 100644
--- a/stack/gatt/gatt_utils.cc
+++ b/stack/gatt/gatt_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@
 #include "sdp_api.h"
 
 using base::StringPrintf;
+using bluetooth::Uuid;
 
 /* check if [x, y] and [a, b] have overlapping range */
 #define GATT_VALIDATE_HANDLE_RANGE(x, y, a, b) ((y) >= (a) && (x) <= (b))
@@ -76,10 +77,6 @@
                                     "ATT_HANDLE_VALUE_CONF",
                                     "ATT_OP_CODE_MAX"};
 
-static const uint8_t base_uuid[LEN_UUID_128] = {
-    0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
-    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
 /*******************************************************************************
  *
  * Function         gatt_free_pending_ind
@@ -220,12 +217,12 @@
  *
  ******************************************************************************/
 std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
-    tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid, uint16_t start_handle) {
+    const Uuid& app_uuid128, Uuid* p_svc_uuid, uint16_t start_handle) {
   auto end_it = gatt_cb.hdl_list_info->end();
   auto it = gatt_cb.hdl_list_info->begin();
   for (; it != end_it; it++) {
-    if (gatt_uuid_compare(*p_app_uuid128, it->asgn_range.app_uuid128) &&
-        gatt_uuid_compare(*p_svc_uuid, it->asgn_range.svc_uuid) &&
+    if (app_uuid128 == it->asgn_range.app_uuid128 &&
+        *p_svc_uuid == it->asgn_range.svc_uuid &&
         (start_handle == it->asgn_range.s_handle)) {
       return it;
     }
@@ -238,11 +235,11 @@
  * free the service attribute database buffers by the owner of the service app
  * ID.
  */
-void gatt_free_srvc_db_buffer_app_id(tBT_UUID* p_app_id) {
+void gatt_free_srvc_db_buffer_app_id(const Uuid& app_id) {
   auto it = gatt_cb.hdl_list_info->begin();
   auto end = gatt_cb.hdl_list_info->end();
   while (it != end) {
-    if (memcmp(p_app_id, &it->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0) {
+    if (app_id == it->asgn_range.app_uuid128) {
       it = gatt_cb.hdl_list_info->erase(it);
     } else {
       it++;
@@ -291,27 +288,23 @@
  *
  ******************************************************************************/
 bool gatt_is_srv_chg_ind_pending(tGATT_TCB* p_tcb) {
-  bool srv_chg_ind_pending = false;
-
   VLOG(1) << __func__
           << " is_queue_empty=" << fixed_queue_is_empty(p_tcb->pending_ind_q);
 
-  if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r) {
-    srv_chg_ind_pending = true;
-  } else if (!fixed_queue_is_empty(p_tcb->pending_ind_q)) {
-    list_t* list = fixed_queue_get_list(p_tcb->pending_ind_q);
-    for (const list_node_t* node = list_begin(list); node != list_end(list);
-         node = list_next(node)) {
-      tGATT_VALUE* p_buf = (tGATT_VALUE*)list_node(node);
-      if (p_buf->handle == gatt_cb.handle_of_h_r) {
-        srv_chg_ind_pending = true;
-        break;
-      }
+  if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r) return true;
+
+  if (fixed_queue_is_empty(p_tcb->pending_ind_q)) return false;
+
+  list_t* list = fixed_queue_get_list(p_tcb->pending_ind_q);
+  for (const list_node_t* node = list_begin(list); node != list_end(list);
+       node = list_next(node)) {
+    tGATT_VALUE* p_buf = (tGATT_VALUE*)list_node(node);
+    if (p_buf->handle == gatt_cb.handle_of_h_r) {
+      return true;
     }
   }
 
-  VLOG(1) << __func__ << "srv_chg_ind_pending = %d", srv_chg_ind_pending;
-  return srv_chg_ind_pending;
+  return false;
 }
 
 /*******************************************************************************
@@ -461,179 +454,59 @@
   return NULL;
 }
 
-/*******************************************************************************
- *
- * Function         gatt_convert_uuid16_to_uuid128
- *
- * Description      Convert a 16 bits UUID to be an standard 128 bits one.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-void gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
-                                    uint16_t uuid_16) {
-  uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
-
-  memcpy(uuid_128, base_uuid, LEN_UUID_128);
-
-  UINT16_TO_STREAM(p, uuid_16);
+/** gatt_build_uuid_to_stream will convert 32bit UUIDs to 128bit. This function
+ * will return lenght required to build uuid, either |UUID:kNumBytes16| or
+ * |UUID::kNumBytes128| */
+uint8_t gatt_build_uuid_to_stream_len(const Uuid& uuid) {
+  size_t len = uuid.GetShortestRepresentationSize();
+  return len == Uuid::kNumBytes32 ? Uuid::kNumBytes128 : len;
 }
 
-/*******************************************************************************
- *
- * Function         gatt_convert_uuid32_to_uuid128
- *
- * Description      Convert a 32 bits UUID to be an standard 128 bits one.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
-                                    uint32_t uuid_32) {
-  uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
-
-  memcpy(uuid_128, base_uuid, LEN_UUID_128);
-
-  UINT32_TO_STREAM(p, uuid_32);
-}
-/*******************************************************************************
- *
- * Function         gatt_uuid_compare
- *
- * Description      Compare two UUID to see if they are the same.
- *
- * Returns          true if two uuid match; false otherwise.
- *
- ******************************************************************************/
-bool gatt_uuid_compare(tBT_UUID src, tBT_UUID tar) {
-  uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
-  uint8_t *ps, *pt;
-
-  /* any of the UUID is unspecified */
-  if (src.len == 0 || tar.len == 0) {
-    return true;
-  }
-
-  /* If both are 16-bit, we can do a simple compare */
-  if (src.len == LEN_UUID_16 && tar.len == LEN_UUID_16) {
-    return src.uu.uuid16 == tar.uu.uuid16;
-  }
-
-  /* If both are 32-bit, we can do a simple compare */
-  if (src.len == LEN_UUID_32 && tar.len == LEN_UUID_32) {
-    return src.uu.uuid32 == tar.uu.uuid32;
-  }
-
-  /* One or both of the UUIDs is 128-bit */
-  if (src.len == LEN_UUID_16) {
-    /* convert a 16 bits UUID to 128 bits value */
-    gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
-    ps = su;
-  } else if (src.len == LEN_UUID_32) {
-    gatt_convert_uuid32_to_uuid128(su, src.uu.uuid32);
-    ps = su;
-  } else
-    ps = src.uu.uuid128;
-
-  if (tar.len == LEN_UUID_16) {
-    /* convert a 16 bits UUID to 128 bits value */
-    gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
-    pt = tu;
-  } else if (tar.len == LEN_UUID_32) {
-    /* convert a 32 bits UUID to 128 bits value */
-    gatt_convert_uuid32_to_uuid128(tu, tar.uu.uuid32);
-    pt = tu;
-  } else
-    pt = tar.uu.uuid128;
-
-  return (memcmp(ps, pt, LEN_UUID_128) == 0);
-}
-
-/*******************************************************************************
- *
- * Function         gatt_build_uuid_to_stream
- *
- * Description      Add UUID into stream.
- *
- * Returns          UUID length.
- *
- ******************************************************************************/
-uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst, tBT_UUID uuid) {
+/** Add UUID into stream. Returns UUID length. */
+uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst, const Uuid& uuid) {
   uint8_t* p = *p_dst;
-  uint8_t len = 0;
+  size_t len = uuid.GetShortestRepresentationSize();
 
-  if (uuid.len == LEN_UUID_16) {
-    UINT16_TO_STREAM(p, uuid.uu.uuid16);
-    len = LEN_UUID_16;
-  } else if (uuid.len ==
-             LEN_UUID_32) /* always convert 32 bits into 128 bits as alwats */
-  {
-    gatt_convert_uuid32_to_uuid128(p, uuid.uu.uuid32);
-    p += LEN_UUID_128;
-    len = LEN_UUID_128;
-  } else if (uuid.len == LEN_UUID_128) {
-    ARRAY_TO_STREAM(p, uuid.uu.uuid128, LEN_UUID_128);
-    len = LEN_UUID_128;
+  if (uuid.IsEmpty()) {
+    return 0;
+  }
+
+  if (len == Uuid::kNumBytes16) {
+    UINT16_TO_STREAM(p, uuid.As16Bit());
+  } else if (len == Uuid::kNumBytes32) {
+    /* always convert 32 bits into 128 bits */
+    ARRAY_TO_STREAM(p, uuid.To128BitLE(), (int)Uuid::kNumBytes128);
+    len = Uuid::kNumBytes128;
+  } else if (len == Uuid::kNumBytes128) {
+    ARRAY_TO_STREAM(p, uuid.To128BitLE(), (int)Uuid::kNumBytes128);
   }
 
   *p_dst = p;
   return len;
 }
 
-/*******************************************************************************
- *
- * Function         gatt_parse_uuid_from_cmd
- *
- * Description      Convert a 128 bits UUID into a 16 bits UUID.
- *
- * Returns          true if command sent, otherwise false.
- *
- ******************************************************************************/
-bool gatt_parse_uuid_from_cmd(tBT_UUID* p_uuid_rec, uint16_t uuid_size,
+bool gatt_parse_uuid_from_cmd(Uuid* p_uuid_rec, uint16_t uuid_size,
                               uint8_t** p_data) {
-  bool is_base_uuid, ret = true;
-  uint8_t xx;
+  bool ret = true;
   uint8_t* p_uuid = *p_data;
 
-  memset(p_uuid_rec, 0, sizeof(tBT_UUID));
-
   switch (uuid_size) {
-    case LEN_UUID_16:
-      p_uuid_rec->len = uuid_size;
-      STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid);
-      *p_data += LEN_UUID_16;
-      break;
+    case Uuid::kNumBytes16: {
+      uint16_t val;
+      STREAM_TO_UINT16(val, p_uuid);
+      *p_uuid_rec = Uuid::From16Bit(val);
+      *p_data += Uuid::kNumBytes16;
+      return true;
+    }
 
-    case LEN_UUID_128:
-      /* See if we can compress his UUID down to 16 or 32bit UUIDs */
-      is_base_uuid = true;
-      for (xx = 0; xx < LEN_UUID_128 - 4; xx++) {
-        if (p_uuid[xx] != base_uuid[xx]) {
-          is_base_uuid = false;
-          break;
-        }
-      }
-      if (is_base_uuid) {
-        if ((p_uuid[LEN_UUID_128 - 1] == 0) &&
-            (p_uuid[LEN_UUID_128 - 2] == 0)) {
-          p_uuid += (LEN_UUID_128 - 4);
-          p_uuid_rec->len = LEN_UUID_16;
-          STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid);
-        } else {
-          p_uuid += (LEN_UUID_128 - LEN_UUID_32);
-          p_uuid_rec->len = LEN_UUID_32;
-          STREAM_TO_UINT32(p_uuid_rec->uu.uuid32, p_uuid);
-        }
-      }
-      if (!is_base_uuid) {
-        p_uuid_rec->len = LEN_UUID_128;
-        memcpy(p_uuid_rec->uu.uuid128, p_uuid, LEN_UUID_128);
-      }
-      *p_data += LEN_UUID_128;
-      break;
+    case Uuid::kNumBytes128: {
+      *p_uuid_rec = Uuid::From128BitLE(p_uuid);
+      *p_data += Uuid::kNumBytes128;
+      return true;
+    }
 
     /* do not allow 32 bits UUID in ATT PDU now */
-    case LEN_UUID_32:
+    case Uuid::kNumBytes32:
       LOG(ERROR) << "DO NOT ALLOW 32 BITS UUID IN ATT PDU";
       return false;
     case 0:
@@ -877,47 +750,43 @@
  * Returns          0 if error else sdp handle for the record.
  *
  ******************************************************************************/
-uint32_t gatt_add_sdp_record(tBT_UUID* p_uuid, uint16_t start_hdl,
+uint32_t gatt_add_sdp_record(const Uuid& uuid, uint16_t start_hdl,
                              uint16_t end_hdl) {
-  tSDP_PROTOCOL_ELEM proto_elem_list[2];
-  uint32_t sdp_handle;
-  uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
   uint8_t buff[60];
   uint8_t* p = buff;
 
   VLOG(1) << __func__
           << StringPrintf(" s_hdl=0x%x  s_hdl=0x%x", start_hdl, end_hdl);
 
-  sdp_handle = SDP_CreateRecord();
+  uint32_t sdp_handle = SDP_CreateRecord();
   if (sdp_handle == 0) return 0;
 
-  switch (p_uuid->len) {
-    case LEN_UUID_16:
-      SDP_AddServiceClassIdList(sdp_handle, 1, &p_uuid->uu.uuid16);
+  switch (uuid.GetShortestRepresentationSize()) {
+    case Uuid::kNumBytes16: {
+      uint16_t tmp = uuid.As16Bit();
+      SDP_AddServiceClassIdList(sdp_handle, 1, &tmp);
       break;
+    }
 
-    case LEN_UUID_32:
+    case Uuid::kNumBytes32: {
       UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
-      UINT32_TO_BE_STREAM(p, p_uuid->uu.uuid32);
+      uint32_t tmp = uuid.As32Bit();
+      UINT32_TO_BE_STREAM(p, tmp);
       SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
                        DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - buff), buff);
       break;
+    }
 
-    case LEN_UUID_128:
+    case Uuid::kNumBytes128:
       UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
-      ARRAY_TO_BE_STREAM_REVERSE(p, p_uuid->uu.uuid128, LEN_UUID_128);
+      ARRAY_TO_BE_STREAM(p, uuid.To128BitBE().data(), (int)Uuid::kNumBytes128);
       SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
                        DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - buff), buff);
       break;
-
-    default:
-      LOG(ERROR) << "inavlid UUID len=" << +p_uuid->len;
-      SDP_DeleteRecord(sdp_handle);
-      return 0;
-      break;
   }
 
   /*** Fill out the protocol element sequence for SDP ***/
+  tSDP_PROTOCOL_ELEM proto_elem_list[2];
   proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
   proto_elem_list[0].num_params = 1;
   proto_elem_list[0].params[0] = BT_PSM_ATT;
@@ -929,6 +798,7 @@
   SDP_AddProtocolList(sdp_handle, 2, proto_elem_list);
 
   /* Make the service browseable */
+  uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
   SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list);
 
   return (sdp_handle);
@@ -945,8 +815,9 @@
  *
  ******************************************************************************/
 void gatt_set_err_rsp(bool enable, uint8_t req_op_code, uint8_t err_status) {
-  VLOG(1) << __func__ << StringPrintf(" enable=%d op_code=%d, err_status=%d",
-                                      enable, req_op_code, err_status);
+  VLOG(1) << __func__
+          << StringPrintf(" enable=%d op_code=%d, err_status=%d", enable,
+                          req_op_code, err_status);
   gatt_cb.enable_err_rsp = enable;
   gatt_cb.req_op_code = req_op_code;
   gatt_cb.err_status = err_status;
@@ -1234,24 +1105,19 @@
  *
  ******************************************************************************/
 bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda) {
-  tGATT_TCB* p_tcb = NULL;
-  bool status = true;
+  tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bda, BT_TRANSPORT_LE);
+  if (!p_tcb) return true;
 
-  p_tcb = gatt_find_tcb_by_addr(bda, BT_TRANSPORT_LE);
-
-  if (p_tcb) {
-    if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
-      LOG(ERROR) << __func__ << ": link connected Too late to cancel";
-      status = false;
-    } else {
-      gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
-      if (p_tcb->app_hold_link.empty()) {
-        gatt_disconnect(p_tcb);
-      }
-    }
+  if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
+    LOG(ERROR) << __func__ << ": link connected Too late to cancel";
+    return false;
   }
 
-  return status;
+  gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
+
+  if (p_tcb->app_hold_link.empty()) gatt_disconnect(p_tcb);
+
+  return true;
 }
 
 /** Enqueue this command */
@@ -1317,8 +1183,9 @@
   uint16_t conn_id;
   uint8_t operation;
 
-  VLOG(1) << __func__ << StringPrintf(" status=%d op=%d subtype=%d", status,
-                                      p_clcb->operation, p_clcb->op_subtype);
+  VLOG(1) << __func__
+          << StringPrintf(" status=%d op=%d subtype=%d", status,
+                          p_clcb->operation, p_clcb->op_subtype);
   memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
 
   if (p_cmpl_cb != NULL && p_clcb->operation != 0) {
@@ -1440,40 +1307,6 @@
     return (uint8_t*)"Op Code Exceed Max";
 }
 
-/*******************************************************************************
- *
- * Function         gatt_dbg_display_uuid
- *
- * Description      Disaplay the UUID
- *
- * Returns          None
- *
- ******************************************************************************/
-void gatt_dbg_display_uuid(tBT_UUID bt_uuid) {
-  char str_buf[50];
-
-  if (bt_uuid.len == LEN_UUID_16) {
-    snprintf(str_buf, sizeof(str_buf), "0x%04x", bt_uuid.uu.uuid16);
-  } else if (bt_uuid.len == LEN_UUID_32) {
-    snprintf(str_buf, sizeof(str_buf), "0x%08x",
-             (unsigned int)bt_uuid.uu.uuid32);
-  } else if (bt_uuid.len == LEN_UUID_128) {
-    int x = snprintf(
-        str_buf, sizeof(str_buf), "0x%02x%02x%02x%02x%02x%02x%02x%02x",
-        bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14], bt_uuid.uu.uuid128[13],
-        bt_uuid.uu.uuid128[12], bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
-        bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
-    snprintf(
-        &str_buf[x], sizeof(str_buf) - x, "%02x%02x%02x%02x%02x%02x%02x%02x",
-        bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6], bt_uuid.uu.uuid128[5],
-        bt_uuid.uu.uuid128[4], bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
-        bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
-  } else
-    strlcpy(str_buf, "Unknown UUID 0", sizeof(str_buf));
-
-  VLOG(1) << StringPrintf("UUID=[%s]", str_buf);
-}
-
 /** Returns true if this is one of the background devices for the application,
  * false otherwise */
 bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if) {
@@ -1608,27 +1441,22 @@
  ******************************************************************************/
 bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add,
                                   const RawAddress& bd_addr) {
-  bool ret = false;
-  tGATT_REG* p_reg;
   tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
 
   VLOG(1) << __func__;
   /* Make sure app is registered */
-  p_reg = gatt_get_regcb(gatt_if);
-  if (p_reg == NULL) {
+  tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+  if (!p_reg) {
     LOG(ERROR) << __func__ << " gatt_if is not registered " << +gatt_if;
     return false;
   }
 
-  if (add) {
-    ret = gatt_add_bg_dev_list(p_reg, bd_addr);
+  if (!add) return gatt_remove_bg_dev_from_list(p_reg, bd_addr);
 
-    if (ret && p_tcb != NULL) {
-      /* if a connected device, update the link holding number */
-      gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true);
-    }
-  } else {
-    ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr);
+  bool ret = gatt_add_bg_dev_list(p_reg, bd_addr);
+  if (ret && p_tcb != NULL) {
+    /* if a connected device, update the link holding number */
+    gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true);
   }
   return ret;
 }
diff --git a/stack/hcic/hciblecmds.cc b/stack/hcic/hciblecmds.cc
index 041d1e0..30d8d75 100644
--- a/stack/hcic/hciblecmds.cc
+++ b/stack/hcic/hciblecmds.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/hcic/hcicmds.cc b/stack/hcic/hcicmds.cc
index c132054..56ff381 100644
--- a/stack/hcic/hcicmds.cc
+++ b/stack/hcic/hcicmds.cc
@@ -1,20 +1,20 @@
 /******************************************************************************
-*
-*  Copyright (C) 1999-2012 Broadcom Corporation
-*
-*  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.
-*
-******************************************************************************/
+ *
+ *  Copyright 1999-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
 
 /******************************************************************************
  *
diff --git a/stack/hid/hid_conn.h b/stack/hid/hid_conn.h
index 5e3ffe7..46a2850 100644
--- a/stack/hid/hid_conn.h
+++ b/stack/hid/hid_conn.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/hid/hidd_api.cc b/stack/hid/hidd_api.cc
index 8ae70c3..414cf74 100644
--- a/stack/hid/hidd_api.cc
+++ b/stack/hid/hidd_api.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,9 +34,7 @@
 #include "hidd_int.h"
 #include "hiddefs.h"
 
-#if HID_DYNAMIC_MEMORY == FALSE
 tHID_DEV_CTB hd_cb;
-#endif
 
 /*******************************************************************************
  *
diff --git a/stack/hid/hidd_conn.cc b/stack/hid/hidd_conn.cc
index cb08715..e4525f9 100644
--- a/stack/hid/hidd_conn.cc
+++ b/stack/hid/hidd_conn.cc
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -54,17 +54,19 @@
 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg);
 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
 
-static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
-                                              hidd_l2cif_connect_cfm,
-                                              NULL,
-                                              hidd_l2cif_config_ind,
-                                              hidd_l2cif_config_cfm,
-                                              hidd_l2cif_disconnect_ind,
-                                              hidd_l2cif_disconnect_cfm,
-                                              NULL,
-                                              hidd_l2cif_data_ind,
-                                              hidd_l2cif_cong_ind,
-                                              NULL};
+static const tL2CAP_APPL_INFO dev_reg_info = {
+    hidd_l2cif_connect_ind,
+    hidd_l2cif_connect_cfm,
+    NULL,
+    hidd_l2cif_config_ind,
+    hidd_l2cif_config_cfm,
+    hidd_l2cif_disconnect_ind,
+    hidd_l2cif_disconnect_cfm,
+    NULL,
+    hidd_l2cif_data_ind,
+    hidd_l2cif_cong_ind,
+    NULL,
+    NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 /*******************************************************************************
  *
@@ -190,17 +192,6 @@
     return;
   }
 
-  if (p_dev->in_use && bd_addr != p_dev->addr) {
-    HIDD_TRACE_WARNING(
-        "%s: incoming connections from different device, rejecting", __func__);
-    L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
-    return;
-  } else if (!p_dev->in_use) {
-    p_dev->in_use = TRUE;
-    p_dev->addr = bd_addr;
-    p_dev->state = HIDD_DEV_NO_CONN;
-  }
-
   p_hcon = &hd_cb.device.conn;
 
   switch (psm) {
@@ -241,6 +232,12 @@
 
   // for CTRL we need to go through security and we reply in callback from there
   if (psm == HID_PSM_CONTROL) {
+    // We are ready to accept connection from this device, since we aren't
+    // connected to anything and are in the correct state.
+    p_dev->in_use = TRUE;
+    p_dev->addr = bd_addr;
+    p_dev->state = HIDD_DEV_NO_CONN;
+
     p_hcon->conn_flags = 0;
     p_hcon->ctrl_cid = cid;
     p_hcon->ctrl_id = id;
diff --git a/stack/hid/hidd_int.h b/stack/hid/hidd_int.h
index 81e60ca..0981dcc 100644
--- a/stack/hid/hidd_int.h
+++ b/stack/hid/hidd_int.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -80,12 +80,7 @@
 /******************************************************************************
  * Main Control Block
  ******************************************************************************/
-#if HID_DYNAMIC_MEMORY == FALSE
 extern tHID_DEV_CTB hd_cb;
-#else
-extern tHID_DEV_CTB* hidd_cb_ptr;
-#define hd_cb (*hidd_cb_ptr)
-#endif
 
 #ifdef __cplusplus
 }
diff --git a/stack/hid/hidh_api.cc b/stack/hid/hidh_api.cc
index adbc931..ad84daf 100644
--- a/stack/hid/hidh_api.cc
+++ b/stack/hid/hidh_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -35,6 +35,8 @@
 #include "hidh_api.h"
 #include "hidh_int.h"
 
+using bluetooth::Uuid;
+
 tHID_HOST_CTB hh_cb;
 
 static void hidh_search_callback(uint16_t sdp_result);
@@ -51,14 +53,11 @@
 tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr,
                                  tSDP_DISCOVERY_DB* p_db, uint32_t db_len,
                                  tHID_HOST_SDP_CALLBACK* sdp_cback) {
-  tSDP_UUID uuid_list;
 
   if (hh_cb.sdp_busy) return HID_ERR_SDP_BUSY;
 
-  uuid_list.len = 2;
-  uuid_list.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
-
   hh_cb.p_sdp_db = p_db;
+  Uuid uuid_list = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
   SDP_InitDiscoveryDb(p_db, db_len, 1, &uuid_list, 0, NULL);
 
   if (SDP_ServiceSearchRequest(addr, p_db, hidh_search_callback)) {
@@ -92,12 +91,9 @@
   tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db;
   tSDP_DISC_REC* p_rec;
   tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
-  tBT_UUID hid_uuid;
   tHID_DEV_SDP_INFO* p_nvi = &hh_cb.sdp_rec;
   uint16_t attr_mask = 0;
 
-  hid_uuid.len = LEN_UUID_16;
-  hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
 
   hh_cb.sdp_busy = false;
 
@@ -106,7 +102,8 @@
     return;
   }
 
-  p_rec = SDP_FindServiceUUIDInDb(p_db, &hid_uuid, NULL);
+  Uuid hid_uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
+  p_rec = SDP_FindServiceUUIDInDb(p_db, hid_uuid, NULL);
   if (p_rec == NULL) {
     hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
     return;
diff --git a/stack/hid/hidh_conn.cc b/stack/hid/hidh_conn.cc
index a41aa90..6f99c88 100644
--- a/stack/hid/hidh_conn.cc
+++ b/stack/hid/hidh_conn.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -73,8 +73,8 @@
     NULL,
     hidh_l2cif_data_ind,
     hidh_l2cif_cong_ind,
-    NULL /* tL2CA_TX_COMPLETE_CB */
-};
+    NULL, /* tL2CA_TX_COMPLETE_CB */
+    NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 /*******************************************************************************
  *
diff --git a/stack/hid/hidh_int.h b/stack/hid/hidh_int.h
index c332403..8fa8ec8 100644
--- a/stack/hid/hidh_int.h
+++ b/stack/hid/hidh_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/a2dp_aac.h b/stack/include/a2dp_aac.h
index 43f7965..29b2753 100644
--- a/stack/include/a2dp_aac.h
+++ b/stack/include/a2dp_aac.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -25,15 +25,31 @@
 #include "a2dp_codec_api.h"
 #include "avdt_api.h"
 
-class A2dpCodecConfigAac : public A2dpCodecConfig {
+class A2dpCodecConfigAacBase : public A2dpCodecConfig {
+ protected:
+  A2dpCodecConfigAacBase(btav_a2dp_codec_index_t codec_index,
+                         const std::string& name,
+                         btav_a2dp_codec_priority_t codec_priority,
+                         bool is_source)
+      : A2dpCodecConfig(codec_index, name, codec_priority),
+        is_source_(is_source) {}
+  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+                      uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
+
+ private:
+  bool is_source_;  // True if local is Source
+};
+
+class A2dpCodecConfigAacSource : public A2dpCodecConfigAacBase {
  public:
-  A2dpCodecConfigAac(btav_a2dp_codec_priority_t codec_priority);
-  virtual ~A2dpCodecConfigAac();
+  A2dpCodecConfigAacSource(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigAacSource();
 
   bool init() override;
   period_ms_t encoderIntervalMs() const override;
-  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
-                      uint8_t* p_result_codec_config) override;
+  int getEffectiveMtu() const override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -44,6 +60,23 @@
   void debug_codec_dump(int fd) override;
 };
 
+class A2dpCodecConfigAacSink : public A2dpCodecConfigAacBase {
+ public:
+  A2dpCodecConfigAacSink(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigAacSink();
+
+  bool init() override;
+  period_ms_t encoderIntervalMs() const override;
+  int getEffectiveMtu() const override;
+
+ private:
+  bool useRtpHeaderMarkerBit() const override;
+  bool updateEncoderUserConfig(
+      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+      bool* p_restart_input, bool* p_restart_output,
+      bool* p_config_updated) override;
+};
+
 // Checks whether the codec capabilities contain a valid A2DP AAC Source
 // codec.
 // NOTE: only codecs that are implemented are considered valid.
@@ -92,14 +125,6 @@
 bool A2DP_UsesRtpHeaderAac(bool content_protection_enabled,
                            const uint8_t* p_codec_info);
 
-// Builds A2DP preferred AAC Sink capability from AAC Source capability.
-// |p_src_cap| is the Source capability to use.
-// |p_pref_cfg| is the result Sink capability to store.
-// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
-// status code.
-tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(const uint8_t* p_src_cap,
-                                         uint8_t* p_pref_cfg);
-
 // Gets the A2DP AAC codec name for a given |p_codec_info|.
 const char* A2DP_CodecNameAac(const uint8_t* p_codec_info);
 
@@ -135,14 +160,6 @@
 // contains invalid codec information.
 int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// AAC sink codec. |time_interval_ms| is the time interval (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetSinkFramesCountToProcessAac(uint64_t time_interval_ms,
-                                        const uint8_t* p_codec_info);
-
 // Gets the object type code for the A2DP AAC codec.
 // The actual value is codec-specific - see |A2DP_AAC_OBJECT_TYPE_*|.
 // |p_codec_info| is a pointer to the AAC codec_info to decode.
@@ -195,10 +212,10 @@
 bool A2DP_BuildCodecHeaderAac(const uint8_t* p_codec_info, BT_HDR* p_buf,
                               uint16_t frames_per_packet);
 
-// Decodes and displays A2DP AAC codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the AAC codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info);
+// Decodes A2DP AAC codec info into a human readable string.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_CodecInfoStringAac(const uint8_t* p_codec_info);
 
 // Gets the A2DP AAC encoder interface that can be used to encode and prepare
 // A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
@@ -208,6 +225,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
     const uint8_t* p_codec_info);
 
+// Gets the current A2DP AAC decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP AAC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceAac(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP AAC codec, based on local support and Bluetooth
 // specification.
 // |p_codec_info| contains the codec information to adjust.
@@ -219,11 +244,23 @@
 // otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
 btav_a2dp_codec_index_t A2DP_SourceCodecIndexAac(const uint8_t* p_codec_info);
 
+// Gets the A2DP AAC Sink codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_SinkCodecIndexAac(const uint8_t* p_codec_info);
+
 // Gets the A2DP AAC Source codec name.
 const char* A2DP_CodecIndexStrAac(void);
 
-// Initializes A2DP AAC Source codec information into |tAVDT_CFG|
+// Gets the A2DP AAC Sink codec name.
+const char* A2DP_CodecIndexStrAacSink(void);
+
+// Initializes A2DP AAC Source codec information into |AvdtpSepConfig|
 // configuration entry pointed by |p_cfg|.
-bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg);
+bool A2DP_InitCodecConfigAac(AvdtpSepConfig* p_cfg);
+
+// Initializes A2DP AAC Sink codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigAacSink(AvdtpSepConfig* p_cfg);
 
 #endif  // A2DP_AAC_H
diff --git a/stack/include/a2dp_aac_constants.h b/stack/include/a2dp_aac_constants.h
index 6102f92..b356556 100644
--- a/stack/include/a2dp_aac_constants.h
+++ b/stack/include/a2dp_aac_constants.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/a2dp_aac_decoder.h b/stack/include/a2dp_aac_decoder.h
new file mode 100644
index 0000000..53ffc52
--- /dev/null
+++ b/stack/include/a2dp_aac_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+//
+// Interface to the A2DP AAC Decoder
+//
+
+#ifndef A2DP_AAC_DECODER_H
+#define A2DP_AAC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP AAC decoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadDecoderAac(void);
+
+// Unloads the A2DP AAC decoder.
+void A2DP_UnloadDecoderAac(void);
+
+// Initialize the A2DP AAC decoder.
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP AAC decoder.
+void a2dp_aac_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into |a2dp_aac_decoder_init|
+// if decoded frames are available.
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif  // A2DP_AAC_DECODER_H
diff --git a/stack/include/a2dp_aac_encoder.h b/stack/include/a2dp_aac_encoder.h
index e72b18c..e6b7323 100644
--- a/stack/include/a2dp_aac_encoder.h
+++ b/stack/include/a2dp_aac_encoder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/a2dp_api.h b/stack/include/a2dp_api.h
index ee215a9..56e259c 100644
--- a/stack/include/a2dp_api.h
+++ b/stack/include/a2dp_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -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/a2dp_codec_api.h b/stack/include/a2dp_codec_api.h
index cdc4721..9fdc13b 100644
--- a/stack/include/a2dp_codec_api.h
+++ b/stack/include/a2dp_codec_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -36,6 +36,8 @@
 #include "avdt_api.h"
 #include "osi/include/time.h"
 
+class tBT_A2DP_OFFLOAD;
+
 /**
  * Structure used to initialize the A2DP encoder with A2DP peer information
  */
@@ -67,6 +69,15 @@
   // Gets the current priority of the codec.
   btav_a2dp_codec_priority_t codecPriority() const { return codec_priority_; }
 
+  // gets current OTA codec specific config to |p_a2dp_offload->codec_info|.
+  // Returns true if the current codec config is valid and copied,
+  // otherwise false.
+  bool getCodecSpecificConfig(tBT_A2DP_OFFLOAD* p_a2dp_offload);
+
+  // Gets the bitRate for the A2DP codec.
+  // Returns the bitrate of current codec configuration, or 0 if not configured
+  int getTrackBitRate() const;
+
   // Copies out the current OTA codec config to |p_codec_info|.
   // Returns true if the current codec config is valid and copied,
   // otherwise false.
@@ -114,6 +125,11 @@
   // the Marker bit in the header is set according to RFC 6416.
   virtual bool useRtpHeaderMarkerBit() const = 0;
 
+  // Gets the effective MTU for the A2DP codec.
+  // Returns the effective MTU of current codec configuration, or 0 if not
+  // configured.
+  virtual int getEffectiveMtu() const = 0;
+
   // Checks whether |codec_config| is empty and contains no configuration.
   // Returns true if |codec_config| is empty, otherwise false.
   static bool isCodecConfigEmpty(const btav_a2dp_codec_config_t& codec_config);
@@ -179,6 +195,12 @@
       bool* p_restart_input, bool* p_restart_output,
       bool* p_config_updated) = 0;
 
+  // Sets the codec capabilities for a peer.
+  // |p_peer_codec_capabiltities| is the peer codec capabilities to set.
+  // Returns true on success, otherwise false.
+  virtual bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) = 0;
+
   // Constructor where |codec_index| is the unique index that identifies the
   // codec. The user-friendly name is |name|.
   // The default codec priority is |codec_priority|. If the value is
@@ -275,6 +297,11 @@
   // Returns the Source codec if found, otherwise nullptr.
   A2dpCodecConfig* findSourceCodecConfig(const uint8_t* p_codec_info);
 
+  // Finds the Sink codec that corresponds to the A2DP over-the-air
+  // |p_codec_info| information.
+  // Returns the Sink codec if found, otherwise nullptr.
+  A2dpCodecConfig* findSinkCodecConfig(const uint8_t* p_codec_info);
+
   // Gets the codec config that is currently selected.
   // Returns the codec config that is currently selected, or nullptr if
   // no codec is selected.
@@ -331,6 +358,13 @@
                       uint8_t* p_result_codec_config,
                       bool select_current_codec);
 
+  // Sets the A2DP Sink codec configuration to be used with a peer Source
+  // device.
+  // [See setCodecConfig() for description]
+  bool setSinkCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+                          uint8_t* p_result_codec_config,
+                          bool select_current_codec);
+
   // Sets the user prefered codec configuration.
   // |codec_user_config| contains the preferred codec configuration.
   // |p_peer_params| contains the A2DP peer information.
@@ -390,6 +424,16 @@
                          uint8_t* p_result_codec_config, bool* p_restart_input,
                          bool* p_restart_output, bool* p_config_updated);
 
+  // Sets the codec capabilities for a Sink peer.
+  // |p_peer_codec_capabiltities| is the peer codec capabilities to set.
+  // Returns true on success, otherwise false.
+  bool setPeerSinkCodecCapabilities(const uint8_t* p_peer_codec_capabilities);
+
+  // Sets the codec capabilities for a Source peer.
+  // |p_peer_codec_capabiltities| is the peer codec capabilities to set.
+  // Returns true on success, otherwise false.
+  bool setPeerSourceCodecCapabilities(const uint8_t* p_peer_codec_capabilities);
+
   // Gets the current codec configuration and the capabilities of
   // all configured codecs.
   // The current codec configuration is stored in |p_codec_config|.
@@ -453,8 +497,11 @@
 // responsible for freeing |p_buf|.
 // |frames_n| is the number of audio frames in |p_buf| - it is used for
 // statistics purpose.
+// |num_bytes| is the number of audio bytes in |p_buf| - it is used for
+// delay reporting.
 // Returns true if the packet was enqueued, otherwise false.
-typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n);
+typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n,
+                                               uint32_t num_bytes);
 
 //
 // A2DP encoder callbacks interface.
@@ -490,6 +537,27 @@
   void (*set_transmit_queue_length)(size_t transmit_queue_length);
 } tA2DP_ENCODER_INTERFACE;
 
+// Prototype for a callback to receive decoded audio data from a
+// tA2DP_DECODER_INTERFACE|.
+// |buf| is a pointer to the data.
+// |len| is the number of octets pointed to by |buf|.
+typedef void (*decoded_data_callback_t)(uint8_t* buf, uint32_t len);
+
+//
+// A2DP decoder callbacks interface.
+//
+typedef struct {
+  // Initialize the decoder. Can be called multiple times, will reinitalize.
+  bool (*decoder_init)(decoded_data_callback_t decode_callback);
+
+  // Cleanup the A2DP decoder.
+  void (*decoder_cleanup)();
+
+  // Decodes |p_buf| and calls |decode_callback| passed into init for the
+  // decoded data.
+  bool (*decode_packet)(BT_HDR* p_buf);
+} tA2DP_DECODER_INTERFACE;
+
 // Gets the A2DP codec type.
 // |p_codec_info| contains information about the codec capabilities.
 tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info);
@@ -536,14 +604,6 @@
 // |p_codec_info|.
 void A2DP_InitDefaultCodec(uint8_t* p_codec_info);
 
-// Builds A2DP preferred Sink capability from Source capability.
-// |p_src_cap| is the Source capability to use.
-// |p_pref_cfg| is the result Sink capability to store.
-// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
-// status code.
-tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
-                                      uint8_t* p_pref_cfg);
-
 // Checks whether the A2DP data packets should contain RTP header.
 // |content_protection_enabled| is true if Content Protection is
 // enabled. |p_codec_info| contains information about the codec capabilities.
@@ -592,14 +652,6 @@
 // contains invalid codec information.
 int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// Sink codec. |time_interval_ms| is the time interval (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
-                                     const uint8_t* p_codec_info);
-
 // Gets the A2DP audio data timestamp from an audio packet.
 // |p_codec_info| contains the codec information.
 // |p_data| contains the audio data.
@@ -624,6 +676,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
     const uint8_t* p_codec_info);
 
+// Gets the A2DP decoder interface that can be used to decode received A2DP
+// packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP codec, based on local support and Bluetooth specification.
 // |p_codec_info| contains the codec information to adjust.
 // Returns true if |p_codec_info| is valid and supported, otherwise false.
@@ -634,45 +694,52 @@
 // otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
 btav_a2dp_codec_index_t A2DP_SourceCodecIndex(const uint8_t* p_codec_info);
 
+// Gets the A2DP Sink codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_SinkCodecIndex(const uint8_t* p_codec_info);
+
 // Gets the A2DP codec name for a given |codec_index|.
 const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index);
 
-// Initializes A2DP codec-specific information into |tAVDT_CFG| configuration
-// entry pointed by |p_cfg|. The selected codec is defined by |codec_index|.
+// Initializes A2DP codec-specific information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|. The selected codec is defined
+// by |codec_index|.
 // Returns true on success, otherwise false.
 bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
-                          tAVDT_CFG* p_cfg);
+                          AvdtpSepConfig* p_cfg);
 
-// Decodes and displays A2DP codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_DumpCodecInfo(const uint8_t* p_codec_info);
+// Decodes A2DP codec info into a human readable string.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_CodecInfoString(const uint8_t* p_codec_info);
 
 // Add enum-based flag operators to the btav_a2dp_codec_config_t fields
 #ifndef DEFINE_ENUM_FLAG_OPERATORS
+// Use NOLINT to suppress missing parentheses warnings around bitmask.
 #define DEFINE_ENUM_FLAG_OPERATORS(bitmask)                                 \
   extern "C++" {                                                            \
-  inline constexpr bitmask operator&(bitmask X, bitmask Y) {                \
+  inline constexpr bitmask operator&(bitmask X, bitmask Y) {  /* NOLINT */  \
     return static_cast<bitmask>(static_cast<int>(X) & static_cast<int>(Y)); \
   }                                                                         \
-  inline constexpr bitmask operator|(bitmask X, bitmask Y) {                \
+  inline constexpr bitmask operator|(bitmask X, bitmask Y) {  /* NOLINT */  \
     return static_cast<bitmask>(static_cast<int>(X) | static_cast<int>(Y)); \
   }                                                                         \
-  inline constexpr bitmask operator^(bitmask X, bitmask Y) {                \
+  inline constexpr bitmask operator^(bitmask X, bitmask Y) {  /* NOLINT */  \
     return static_cast<bitmask>(static_cast<int>(X) ^ static_cast<int>(Y)); \
   }                                                                         \
-  inline constexpr bitmask operator~(bitmask X) {                           \
+  inline constexpr bitmask operator~(bitmask X) {             /* NOLINT */  \
     return static_cast<bitmask>(~static_cast<int>(X));                      \
   }                                                                         \
-  inline bitmask& operator&=(bitmask& X, bitmask Y) {                       \
+  inline bitmask& operator&=(bitmask& X, bitmask Y) {         /* NOLINT */  \
     X = X & Y;                                                              \
     return X;                                                               \
   }                                                                         \
-  inline bitmask& operator|=(bitmask& X, bitmask Y) {                       \
+  inline bitmask& operator|=(bitmask& X, bitmask Y) {         /* NOLINT */  \
     X = X | Y;                                                              \
     return X;                                                               \
   }                                                                         \
-  inline bitmask& operator^=(bitmask& X, bitmask Y) {                       \
+  inline bitmask& operator^=(bitmask& X, bitmask Y) {         /* NOLINT */  \
     X = X ^ Y;                                                              \
     return X;                                                               \
   }                                                                         \
diff --git a/stack/include/a2dp_constants.h b/stack/include/a2dp_constants.h
index 479d9e4..f0d7b22 100644
--- a/stack/include/a2dp_constants.h
+++ b/stack/include/a2dp_constants.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/a2dp_error_codes.h b/stack/include/a2dp_error_codes.h
index 9983a03..0aa7105 100644
--- a/stack/include/a2dp_error_codes.h
+++ b/stack/include/a2dp_error_codes.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/a2dp_sbc.h b/stack/include/a2dp_sbc.h
index a19dd20..0381d311 100644
--- a/stack/include/a2dp_sbc.h
+++ b/stack/include/a2dp_sbc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -25,15 +25,31 @@
 #include "a2dp_sbc_constants.h"
 #include "avdt_api.h"
 
-class A2dpCodecConfigSbc : public A2dpCodecConfig {
+class A2dpCodecConfigSbcBase : public A2dpCodecConfig {
+ protected:
+  A2dpCodecConfigSbcBase(btav_a2dp_codec_index_t codec_index,
+                         const std::string& name,
+                         btav_a2dp_codec_priority_t codec_priority,
+                         bool is_source)
+      : A2dpCodecConfig(codec_index, name, codec_priority),
+        is_source_(is_source) {}
+  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+                      uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
+
+ private:
+  bool is_source_;  // True if local is Source
+};
+
+class A2dpCodecConfigSbcSource : public A2dpCodecConfigSbcBase {
  public:
-  A2dpCodecConfigSbc(btav_a2dp_codec_priority_t codec_priority);
-  virtual ~A2dpCodecConfigSbc();
+  A2dpCodecConfigSbcSource(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigSbcSource();
 
   bool init() override;
   period_ms_t encoderIntervalMs() const override;
-  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
-                      uint8_t* p_result_codec_config) override;
+  int getEffectiveMtu() const override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -44,15 +60,14 @@
   void debug_codec_dump(int fd) override;
 };
 
-class A2dpCodecConfigSbcSink : public A2dpCodecConfig {
+class A2dpCodecConfigSbcSink : public A2dpCodecConfigSbcBase {
  public:
   A2dpCodecConfigSbcSink(btav_a2dp_codec_priority_t codec_priority);
   virtual ~A2dpCodecConfigSbcSink();
 
   bool init() override;
   period_ms_t encoderIntervalMs() const override;
-  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
-                      uint8_t* p_result_codec_config) override;
+  int getEffectiveMtu() const override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -106,14 +121,6 @@
 // |p_codec_info|.
 void A2DP_InitDefaultCodecSbc(uint8_t* p_codec_info);
 
-// Builds A2DP preferred SBC Sink capability from SBC Source capability.
-// |p_src_cap| is the Source capability to use.
-// |p_pref_cfg| is the result Sink capability to store.
-// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
-// status code.
-tA2DP_STATUS A2DP_BuildSrc2SinkConfigSbc(const uint8_t* p_src_cap,
-                                         uint8_t* p_pref_cfg);
-
 // Gets the A2DP SBC codec name for a given |p_codec_info|.
 const char* A2DP_CodecNameSbc(const uint8_t* p_codec_info);
 
@@ -196,14 +203,6 @@
 // contains invalid codec information.
 int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// SBC sink codec. |time_interval_ms| is the time interval (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
-                                        const uint8_t* p_codec_info);
-
 // Gets the A2DP SBC audio data timestamp from an audio packet.
 // |p_codec_info| contains the codec information.
 // |p_data| contains the audio data.
@@ -220,10 +219,10 @@
 bool A2DP_BuildCodecHeaderSbc(const uint8_t* p_codec_info, BT_HDR* p_buf,
                               uint16_t frames_per_packet);
 
-// Decodes and displays A2DP SBC codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the SBC codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info);
+// Decodes A2DP SBC codec info into a human readable string.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_CodecInfoStringSbc(const uint8_t* p_codec_info);
 
 // Gets the A2DP SBC encoder interface that can be used to encode and prepare
 // A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
@@ -233,6 +232,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
     const uint8_t* p_codec_info);
 
+// Gets the A2DP SBC decoder interface that can be used to decode received A2DP
+// packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP SBC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceSbc(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP SBC codec, based on local support and Bluetooth
 // specification.
 // |p_codec_info| contains the codec information to adjust.
@@ -244,18 +251,27 @@
 // otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
 btav_a2dp_codec_index_t A2DP_SourceCodecIndexSbc(const uint8_t* p_codec_info);
 
+// Gets the A2DP SBC Sink codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_SinkCodecIndexSbc(const uint8_t* p_codec_info);
+
 // Gets the A2DP SBC Source codec name.
 const char* A2DP_CodecIndexStrSbc(void);
 
 // Gets the A2DP SBC Sink codec name.
 const char* A2DP_CodecIndexStrSbcSink(void);
 
-// Initializes A2DP SBC Source codec information into |tAVDT_CFG| configuration
-// entry pointed by |p_cfg|.
-bool A2DP_InitCodecConfigSbc(tAVDT_CFG* p_cfg);
+// Initializes A2DP SBC Source codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigSbc(AvdtpSepConfig* p_cfg);
 
-// Initializes A2DP SBC Sink codec information into |tAVDT_CFG| configuration
-// entry pointed by |p_cfg|.
-bool A2DP_InitCodecConfigSbcSink(tAVDT_CFG* p_cfg);
+// Initializes A2DP SBC Sink codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigSbcSink(AvdtpSepConfig* p_cfg);
+
+// Get SBC bitrate
+// Returns |uint32_t| bitrate value in bits per second
+uint32_t A2DP_GetBitrateSbc();
 
 #endif  // A2DP_SBC_H
diff --git a/stack/include/a2dp_sbc_constants.h b/stack/include/a2dp_sbc_constants.h
index cb3b801..87b9eb9 100644
--- a/stack/include/a2dp_sbc_constants.h
+++ b/stack/include/a2dp_sbc_constants.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2000-2012 Broadcom Corporation
+ *  Copyright 2000-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/a2dp_sbc_decoder.h b/stack/include/a2dp_sbc_decoder.h
new file mode 100644
index 0000000..f5ac99a
--- /dev/null
+++ b/stack/include/a2dp_sbc_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+//
+// Interface to the A2DP SBC Decoder
+//
+
+#ifndef A2DP_SBC_DECODER_H
+#define A2DP_SBC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP SBC decoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadDecoderSbc(void);
+
+// Unloads the A2DP SBC decoder.
+void A2DP_UnloadDecoderSbc(void);
+
+// Initialize the A2DP SBC decoder.
+bool a2dp_sbc_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP SBC decoder.
+void a2dp_sbc_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into |a2dp_sbc_decoder_init|
+// if decoded frames are available.
+bool a2dp_sbc_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif  // A2DP_SBC_DECODER_H
diff --git a/stack/include/a2dp_sbc_encoder.h b/stack/include/a2dp_sbc_encoder.h
index 6ff1cf7..a853012 100644
--- a/stack/include/a2dp_sbc_encoder.h
+++ b/stack/include/a2dp_sbc_encoder.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -60,4 +60,7 @@
 // |timestamp_us| is the current timestamp (in microseconds).
 void a2dp_sbc_send_frames(uint64_t timestamp_us);
 
+// Get SBC bitrate
+// Returns |uint32_t| bitrate in bits per second
+uint32_t a2dp_sbc_get_bitrate();
 #endif  // A2DP_SBC_ENCODER_H
diff --git a/stack/include/a2dp_sbc_up_sample.h b/stack/include/a2dp_sbc_up_sample.h
index 234ce54..ac83961 100644
--- a/stack/include/a2dp_sbc_up_sample.h
+++ b/stack/include/a2dp_sbc_up_sample.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/a2dp_vendor.h b/stack/include/a2dp_vendor.h
index 2b90041..0b5ba7c 100644
--- a/stack/include/a2dp_vendor.h
+++ b/stack/include/a2dp_vendor.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -76,15 +76,6 @@
 // device is supported, otherwise false.
 bool A2DP_IsVendorPeerSourceCodecSupported(const uint8_t* p_codec_info);
 
-// Builds a vendor-specific A2DP preferred Sink capability from a vendor
-// Source capability.
-// |p_src_cap| is the Source capability to use.
-// |p_pref_cfg| is the result Sink capability to store.
-// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
-// status code.
-tA2DP_STATUS A2DP_VendorBuildSrc2SinkConfig(const uint8_t* p_src_cap,
-                                            uint8_t* p_pref_cfg);
-
 // Gets the Vendor ID for the vendor-specific A2DP codec.
 // |p_codec_info| contains information about the codec capabilities.
 // Returns the Vendor ID for the vendor-specific A2DP codec.
@@ -132,6 +123,12 @@
 // contains invalid codec information.
 int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info);
 
+// Gets the bitrate for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetBitRate(const uint8_t* p_codec_info);
+
 // Gets the channel type for the A2DP vendor-specific Sink codec:
 // 1 for mono, or 3 for dual/stereo/joint.
 // |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
@@ -139,15 +136,6 @@
 // contains invalid codec information.
 int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// vendor-specific Sink codec. |time_interval_ms| is the time interval
-// (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_VendorGetSinkFramesCountToProcess(uint64_t time_interval_ms,
-                                           const uint8_t* p_codec_info);
-
 // Gets the A2DP codec-specific audio data timestamp from an audio packet.
 // |p_codec_info| contains the codec information.
 // |p_data| contains the audio data.
@@ -173,6 +161,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
     const uint8_t* p_codec_info);
 
+// Gets the current A2DP vendor decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP vendor decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP vendor-specific codec, based on local support and Bluetooth
 // specification.
 // |p_codec_info| contains the codec information to adjust.
@@ -185,19 +181,24 @@
 btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndex(
     const uint8_t* p_codec_info);
 
+// Gets the A2DP vendor Sink codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndex(const uint8_t* p_codec_info);
+
 // Gets the A2DP vendor codec name for a given |codec_index|.
 const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index);
 
-// Initializes A2DP vendor codec-specific information into |tAVDT_CFG|
+// Initializes A2DP vendor codec-specific information into |AvdtpSepConfig|
 // configuration entry pointed by |p_cfg|. The selected codec is defined by
 // |codec_index|.
 // Returns true on success, otherwise false.
 bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
-                                tAVDT_CFG* p_cfg);
+                                AvdtpSepConfig* p_cfg);
 
-// Decodes and displays A2DP vendor codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_VendorDumpCodecInfo(const uint8_t* p_codec_info);
+// Decodes A2DP vendor codec info into a human readable string.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info);
 
 #endif  // A2DP_VENDOR_H
diff --git a/stack/include/a2dp_vendor_aptx.h b/stack/include/a2dp_vendor_aptx.h
index b1bebf0..38a1245 100644
--- a/stack/include/a2dp_vendor_aptx.h
+++ b/stack/include/a2dp_vendor_aptx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -32,8 +32,11 @@
 
   bool init() override;
   period_ms_t encoderIntervalMs() const override;
+  int getEffectiveMtu() const override;
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -88,6 +91,12 @@
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info);
 
+// Gets the track bitrate value for the A2DP aptX codec.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetBitRateAptx(const uint8_t* p_codec_info);
+
 // Gets the channel count for the A2DP aptX codec.
 // |p_codec_info| is a pointer to the aptX codec_info to decode.
 // Returns the channel count on success, or -1 if |p_codec_info|
@@ -111,10 +120,10 @@
 bool A2DP_VendorBuildCodecHeaderAptx(const uint8_t* p_codec_info, BT_HDR* p_buf,
                                      uint16_t frames_per_packet);
 
-// Decodes and displays A2DP aptX codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the aptX codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info);
+// Decodes A2DP aptX codec info into a human readable string.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_VendorCodecInfoStringAptx(const uint8_t* p_codec_info);
 
 // Gets the A2DP aptX encoder interface that can be used to encode and prepare
 // A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
@@ -139,8 +148,8 @@
 // Gets the A2DP aptX Source codec name.
 const char* A2DP_VendorCodecIndexStrAptx(void);
 
-// Initializes A2DP aptX Source codec information into |tAVDT_CFG|
+// Initializes A2DP aptX Source codec information into |AvdtpSepConfig|
 // configuration entry pointed by |p_cfg|.
-bool A2DP_VendorInitCodecConfigAptx(tAVDT_CFG* p_cfg);
+bool A2DP_VendorInitCodecConfigAptx(AvdtpSepConfig* p_cfg);
 
 #endif  // A2DP_VENDOR_APTX_H
diff --git a/stack/include/a2dp_vendor_aptx_constants.h b/stack/include/a2dp_vendor_aptx_constants.h
index 0f2c7c6..d9e86cc 100644
--- a/stack/include/a2dp_vendor_aptx_constants.h
+++ b/stack/include/a2dp_vendor_aptx_constants.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/a2dp_vendor_aptx_encoder.h b/stack/include/a2dp_vendor_aptx_encoder.h
index 7a67307..7deaca3 100644
--- a/stack/include/a2dp_vendor_aptx_encoder.h
+++ b/stack/include/a2dp_vendor_aptx_encoder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/a2dp_vendor_aptx_hd.h b/stack/include/a2dp_vendor_aptx_hd.h
index 5a4a748..05ca16f 100644
--- a/stack/include/a2dp_vendor_aptx_hd.h
+++ b/stack/include/a2dp_vendor_aptx_hd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -32,8 +32,11 @@
 
   bool init() override;
   period_ms_t encoderIntervalMs() const override;
+  int getEffectiveMtu() const override;
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -88,6 +91,12 @@
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info);
 
+// Gets the track bitrate value for the A2DP aptX-HD codec.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetBitRateAptxHd(const uint8_t* p_codec_info);
+
 // Gets the channel count for the A2DP aptX-HD codec.
 // |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
 // Returns the channel count on success, or -1 if |p_codec_info|
@@ -112,10 +121,10 @@
                                        BT_HDR* p_buf,
                                        uint16_t frames_per_packet);
 
-// Decodes and displays A2DP aptX-HD codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the aptX-HD codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info);
+// Decodes A2DP aptX-HD codec info into a human readable string.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_VendorCodecInfoStringAptxHd(const uint8_t* p_codec_info);
 
 // Gets the A2DP aptX-HD encoder interface that can be used to encode and
 // prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
@@ -140,8 +149,8 @@
 // Gets the A2DP aptX-HD Source codec name.
 const char* A2DP_VendorCodecIndexStrAptxHd(void);
 
-// Initializes A2DP aptX-HD Source codec information into |tAVDT_CFG|
+// Initializes A2DP aptX-HD Source codec information into |AvdtpSepConfig|
 // configuration entry pointed by |p_cfg|.
-bool A2DP_VendorInitCodecConfigAptxHd(tAVDT_CFG* p_cfg);
+bool A2DP_VendorInitCodecConfigAptxHd(AvdtpSepConfig* p_cfg);
 
 #endif  // A2DP_VENDOR_APTX_HD_H
diff --git a/stack/include/a2dp_vendor_aptx_hd_constants.h b/stack/include/a2dp_vendor_aptx_hd_constants.h
index 40ac8b5..e4d8ff8 100644
--- a/stack/include/a2dp_vendor_aptx_hd_constants.h
+++ b/stack/include/a2dp_vendor_aptx_hd_constants.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/a2dp_vendor_aptx_hd_encoder.h b/stack/include/a2dp_vendor_aptx_hd_encoder.h
index b662e8e..53e7d02 100644
--- a/stack/include/a2dp_vendor_aptx_hd_encoder.h
+++ b/stack/include/a2dp_vendor_aptx_hd_encoder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/a2dp_vendor_ldac.h b/stack/include/a2dp_vendor_ldac.h
index 5302c07..ccb5d1e 100644
--- a/stack/include/a2dp_vendor_ldac.h
+++ b/stack/include/a2dp_vendor_ldac.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -32,8 +32,11 @@
 
   bool init() override;
   period_ms_t encoderIntervalMs() const override;
+  int getEffectiveMtu() const override;
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
@@ -88,6 +91,12 @@
 // contains invalid codec information.
 int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info);
 
+// Gets the track bitrate value for the A2DP LDAC codec.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetBitRateLdac(const uint8_t* p_codec_info);
+
 // Gets the channel count for the A2DP LDAC codec.
 // |p_codec_info| is a pointer to the LDAC codec_info to decode.
 // Returns the channel count on success, or -1 if |p_codec_info|
@@ -118,10 +127,10 @@
 bool A2DP_VendorBuildCodecHeaderLdac(const uint8_t* p_codec_info, BT_HDR* p_buf,
                                      uint16_t frames_per_packet);
 
-// Decodes and displays A2DP LDAC codec info when using |LOG_DEBUG|.
-// |p_codec_info| is a pointer to the LDAC codec_info to decode and display.
-// Returns true if the codec information is valid, otherwise false.
-bool A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info);
+// Decodes A2DP LDAC codec info into a human readable string.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_VendorCodecInfoStringLdac(const uint8_t* p_codec_info);
 
 // Gets the A2DP LDAC encoder interface that can be used to encode and prepare
 // A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
@@ -146,8 +155,8 @@
 // Gets the A2DP LDAC Source codec name.
 const char* A2DP_VendorCodecIndexStrLdac(void);
 
-// Initializes A2DP LDAC Source codec information into |tAVDT_CFG|
+// Initializes A2DP LDAC Source codec information into |AvdtpSepConfig|
 // configuration entry pointed by |p_cfg|.
-bool A2DP_VendorInitCodecConfigLdac(tAVDT_CFG* p_cfg);
+bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg);
 
 #endif  // A2DP_VENDOR_LDAC_H
diff --git a/stack/include/a2dp_vendor_ldac_abr.h b/stack/include/a2dp_vendor_ldac_abr.h
index 157dbba..e479ac7 100644
--- a/stack/include/a2dp_vendor_ldac_abr.h
+++ b/stack/include/a2dp_vendor_ldac_abr.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/stack/include/a2dp_vendor_ldac_constants.h b/stack/include/a2dp_vendor_ldac_constants.h
index 6242add..9cb9200 100644
--- a/stack/include/a2dp_vendor_ldac_constants.h
+++ b/stack/include/a2dp_vendor_ldac_constants.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
@@ -26,6 +26,8 @@
 #define A2DP_LDAC_QUALITY_MID 1   // Equal to LDACBT_EQMID_SQ 660kbps
 #define A2DP_LDAC_QUALITY_LOW 2   // Equal to LDACBT_EQMID_MQ 330kbps
 #define A2DP_LDAC_QUALITY_ABR 3   // ABR mode, range: 990,660,492,396,330(kbps)
+// ABR mode in offload, range: 990,660,492,396,330(kbps)
+#define A2DP_LDAC_QUALITY_ABR_OFFLOAD 0x7F
 
 // Length of the LDAC Media Payload header
 #define A2DP_LDAC_MPL_HDR_LEN 1
diff --git a/stack/include/a2dp_vendor_ldac_encoder.h b/stack/include/a2dp_vendor_ldac_encoder.h
index 45694f0..810f03b 100644
--- a/stack/include/a2dp_vendor_ldac_encoder.h
+++ b/stack/include/a2dp_vendor_ldac_encoder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2016 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.
diff --git a/stack/include/advertise_data_parser.h b/stack/include/advertise_data_parser.h
index 473b979..b62dbb3 100644
--- a/stack/include/advertise_data_parser.h
+++ b/stack/include/advertise_data_parser.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -57,12 +57,7 @@
       // end of the packet. Otherwise i.e. gluing scan response to advertise
       // data will result in data with zero padding in the middle.
       if (len == 0) {
-        size_t zeros_start = position;
-        for (size_t i = position + 1; i < ad_len; i++) {
-          if (ad[i] != 0) return;
-        }
-
-        ad.erase(ad.begin() + zeros_start, ad.end());
+        ad.erase(ad.begin() + position, ad.end());
         return;
       }
 
diff --git a/stack/include/avct_api.h b/stack/include/avct_api.h
index a0380b3..21a880a 100644
--- a/stack/include/avct_api.h
+++ b/stack/include/avct_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h
index 6fb1441..fd0721c 100644
--- a/stack/include/avdt_api.h
+++ b/stack/include/avdt_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -31,11 +31,10 @@
 /*****************************************************************************
  *  Constants
  ****************************************************************************/
-#ifndef AVDT_VERSION
-#define AVDT_VERSION 0x0102
-#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
 
@@ -236,11 +235,6 @@
 /* PSM for AVDT */
 #define AVDT_PSM 0x0019
 
-/* Nonsupported protocol command messages.  This value is used in tAVDT_CS */
-#define AVDT_NSC_SUSPEND 0x01  /* Suspend command not supported */
-#define AVDT_NSC_RECONFIG 0x02 /* Reconfigure command not supported */
-#define AVDT_NSC_SECURITY 0x04 /* Security command not supported */
-
 /*****************************************************************************
  *  Type Definitions
  ****************************************************************************/
@@ -270,14 +264,36 @@
   uint8_t cname[AVDT_MAX_CNAME_SIZE + 1];
 } tAVDT_REPORT_DATA;
 
-/* This structure contains parameters which are set at registration. */
-typedef struct {
+/**
+ * AVDTP Registration Control Block.
+ */
+class AvdtpRcb {
+ public:
+  AvdtpRcb()
+      : ctrl_mtu(0),
+        ret_tout(0),
+        sig_tout(0),
+        idle_tout(0),
+        sec_mask(0),
+        scb_index(0) {}
+  AvdtpRcb& operator=(const AvdtpRcb&) = default;
+
+  void Reset() {
+    ctrl_mtu = 0;
+    ret_tout = 0;
+    sig_tout = 0;
+    idle_tout = 0;
+    sec_mask = 0;
+    scb_index = 0;
+  }
+
   uint16_t ctrl_mtu; /* L2CAP MTU of the AVDTP signaling channel */
   uint8_t ret_tout;  /* AVDTP signaling retransmission timeout */
   uint8_t sig_tout;  /* AVDTP signaling message timeout */
   uint8_t idle_tout; /* AVDTP idle signaling channel timeout */
   uint8_t sec_mask;  /* Security mask for BTM_SetSecurityLevel() */
-} tAVDT_REG;
+  uint8_t scb_index; /* The Stream Control Block index */
+};
 
 /* This structure contains the SEP information.  This information is
  * transferred during the discovery procedure.
@@ -289,8 +305,35 @@
   uint8_t tsep;       /* SEP type */
 } tAVDT_SEP_INFO;
 
-/* This structure contains the SEP configuration. */
-typedef struct {
+/**
+ * AVDTP SEP Configuration.
+ */
+class AvdtpSepConfig {
+ public:
+  AvdtpSepConfig()
+      : codec_info{},
+        protect_info{},
+        num_codec(0),
+        num_protect(0),
+        psc_mask(0),
+        recov_type(0),
+        recov_mrws(0),
+        recov_mnmp(0),
+        hdrcmp_mask(0) {}
+  AvdtpSepConfig& operator=(const AvdtpSepConfig&) = default;
+
+  void Reset() {
+    memset(codec_info, 0, sizeof(codec_info));
+    memset(protect_info, 0, sizeof(protect_info));
+    num_codec = 0;
+    num_protect = 0;
+    psc_mask = 0;
+    recov_type = 0;
+    recov_mrws = 0;
+    recov_mnmp = 0;
+    hdrcmp_mask = 0;
+  }
+
   uint8_t codec_info[AVDT_CODEC_SIZE];     /* Codec capabilities array */
   uint8_t protect_info[AVDT_PROTECT_SIZE]; /* Content protection capabilities */
   uint8_t num_codec;   /* Number of media codec information elements */
@@ -300,7 +343,7 @@
   uint8_t recov_mrws;  /* Maximum recovery window size */
   uint8_t recov_mnmp;  /* Recovery maximum number of media packets */
   uint8_t hdrcmp_mask; /* Header compression capabilities */
-} tAVDT_CFG;
+};
 
 /* Header structure for callback event parameters. */
 typedef struct {
@@ -318,13 +361,13 @@
 */
 typedef struct {
   tAVDT_EVT_HDR hdr; /* Event header */
-  tAVDT_CFG* p_cfg;  /* Pointer to configuration for this SEP */
+  AvdtpSepConfig* p_cfg; /* Pointer to configuration for this SEP */
 } tAVDT_CONFIG;
 
 /* This data structure is associated with the AVDT_CONFIG_IND_EVT. */
 typedef struct {
   tAVDT_EVT_HDR hdr; /* Event header */
-  tAVDT_CFG* p_cfg;  /* Pointer to configuration for this SEP */
+  AvdtpSepConfig* p_cfg; /* Pointer to configuration for this SEP */
   uint8_t int_seid;  /* Stream endpoint ID of stream initiating the operation */
 } tAVDT_SETCONFIG;
 
@@ -384,8 +427,9 @@
  * endpoints and for the AVDT_DiscoverReq() and AVDT_GetCapReq() functions.
  *
 */
-typedef void(tAVDT_CTRL_CBACK)(uint8_t handle, const RawAddress* bd_addr,
-                               uint8_t event, tAVDT_CTRL* p_data);
+typedef void(tAVDT_CTRL_CBACK)(uint8_t handle, const RawAddress& bd_addr,
+                               uint8_t event, tAVDT_CTRL* p_data,
+                               uint8_t scb_index);
 
 /* This is the data callback function.  It is executed when AVDTP has a media
  * packet ready for the application.  This function is required for SNK
@@ -394,34 +438,64 @@
 typedef void(tAVDT_SINK_DATA_CBACK)(uint8_t handle, BT_HDR* p_pkt,
                                     uint32_t time_stamp, uint8_t m_pt);
 
-#if (AVDT_REPORTING == TRUE)
 /* This is the report callback function.  It is executed when AVDTP has a
  * reporting packet ready for the application.  This function is required for
  * streams created with AVDT_PSC_REPORT.
 */
 typedef void(tAVDT_REPORT_CBACK)(uint8_t handle, AVDT_REPORT_TYPE type,
                                  tAVDT_REPORT_DATA* p_data);
-#endif
 
-typedef uint16_t(tAVDT_GETCAP_REQ)(const RawAddress& bd_addr, uint8_t seid,
-                                   tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback);
+/**
+ * AVDTP Stream Configuration.
+ * The information is used when a stream is created.
+ */
+class AvdtpStreamConfig {
+ public:
+  //
+  // Non-supported protocol command messages
+  //
+  // Suspend command not supported
+  static constexpr int AVDT_NSC_SUSPEND = 0x01;
+  // Reconfigure command not supported
+  static constexpr int AVDT_NSC_RECONFIG = 0x02;
+  // Security command not supported
+  static constexpr int AVDT_NSC_SECURITY = 0x04;
 
-/* This structure contains information required when a stream is created.
- * It is passed to the AVDT_CreateStream() function.
-*/
-typedef struct {
-  tAVDT_CFG cfg;                            /* SEP configuration */
-  tAVDT_CTRL_CBACK* p_ctrl_cback;           /* Control callback function */
-  tAVDT_SINK_DATA_CBACK* p_sink_data_cback; /* Sink data callback function */
-#if (AVDT_REPORTING == TRUE)
-  tAVDT_REPORT_CBACK* p_report_cback; /* Report callback function. */
-#endif
-  uint16_t mtu;       /* The L2CAP MTU of the transport channel */
-  uint16_t flush_to;  /* The L2CAP flush timeout of the transport channel */
-  uint8_t tsep;       /* SEP type */
-  uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
-  uint16_t nsc_mask;  /* Nonsupported protocol command messages */
-} tAVDT_CS;
+  AvdtpStreamConfig()
+      : p_avdt_ctrl_cback(nullptr),
+        scb_index(0),
+        p_sink_data_cback(nullptr),
+        p_report_cback(nullptr),
+        mtu(0),
+        flush_to(0),
+        tsep(0),
+        media_type(0),
+        nsc_mask(0) {}
+
+  void Reset() {
+    cfg.Reset();
+    p_avdt_ctrl_cback = nullptr;
+    scb_index = 0;
+    p_sink_data_cback = nullptr;
+    p_report_cback = nullptr;
+    mtu = 0;
+    flush_to = 0;
+    tsep = 0;
+    media_type = 0;
+    nsc_mask = 0;
+  }
+
+  AvdtpSepConfig cfg;                   // SEP configuration
+  tAVDT_CTRL_CBACK* p_avdt_ctrl_cback;  // Control callback function
+  uint8_t scb_index;  // The index to the bta_av_cb.p_scb[] entry
+  tAVDT_SINK_DATA_CBACK* p_sink_data_cback;  // Sink data callback function
+  tAVDT_REPORT_CBACK* p_report_cback;        // Report callback function
+  uint16_t mtu;        // The L2CAP MTU of the transport channel
+  uint16_t flush_to;   // The L2CAP flush timeout of the transport channel
+  uint8_t tsep;        // SEP type
+  uint8_t media_type;  // Media type: AVDT_MEDIA_TYPE_*
+  uint16_t nsc_mask;   // Nonsupported protocol command messages
+};
 
 /* AVDT data option mask is used in the write request */
 #define AVDT_DATA_OPT_NONE 0x00          /* No option still add RTP header */
@@ -447,7 +521,7 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void AVDT_Register(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback);
+extern void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback);
 
 /*******************************************************************************
  *
@@ -489,7 +563,8 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-extern uint16_t AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs);
+extern uint16_t AVDT_CreateStream(uint8_t peer_id, uint8_t* p_handle,
+                                  const AvdtpStreamConfig& avdtp_stream_config);
 
 /*******************************************************************************
  *
@@ -534,6 +609,7 @@
  *
  ******************************************************************************/
 extern uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr,
+                                 uint8_t channel_index,
                                  tAVDT_SEP_INFO* p_sep_info, uint8_t max_seps,
                                  tAVDT_CTRL_CBACK* p_cback);
 
@@ -561,35 +637,9 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-extern uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t seid,
-                               tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback);
-
-/*******************************************************************************
- *
- * Function         AVDT_GetAllCapReq
- *
- * Description      This function initiates a connection to the AVDTP service
- *                  on the peer device, if not already present, and gets the
- *                  capabilities of a stream endpoint on the peer device.
- *                  This function can be called at any time regardless of
- *                  whether there is an AVDTP connection to the peer device.
- *
- *                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
- *                  sent to the application via its callback function.  The
- *                  application must not call AVDT_GetCapReq() or
- *                  AVDT_DiscoverReq() again until the procedure is complete.
- *
- *                  The memory pointed to by p_cfg is allocated by the
- *                  application.  This memory is written to by AVDTP as part
- *                  of the get capabilities procedure.  This memory must
- *                  remain accessible until the application receives
- *                  the AVDT_GETCAP_CFM_EVT.
- *
- * Returns          AVDT_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern uint16_t AVDT_GetAllCapReq(const RawAddress& bd_addr, uint8_t seid,
-                                  tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback);
+extern uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t channel_index,
+                               uint8_t seid, AvdtpSepConfig* p_cfg,
+                               tAVDT_CTRL_CBACK* p_cback, bool get_all_cap);
 
 /*******************************************************************************
  *
@@ -619,7 +669,8 @@
  *
  ******************************************************************************/
 extern uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr,
-                             uint8_t seid, tAVDT_CFG* p_cfg);
+                             uint8_t channel_index, uint8_t seid,
+                             AvdtpSepConfig* p_cfg);
 
 /*******************************************************************************
  *
@@ -703,7 +754,7 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-extern uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg);
+extern uint16_t AVDT_ReconfigReq(uint8_t handle, AvdtpSepConfig* p_cfg);
 
 /*******************************************************************************
  *
@@ -845,7 +896,8 @@
  * Returns          AVDT_SUCCESS if successful, otherwise error.
  *
  ******************************************************************************/
-extern uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t sec_mask,
+extern uint16_t AVDT_ConnectReq(const RawAddress& bd_addr,
+                                uint8_t channel_index, uint8_t sec_mask,
                                 tAVDT_CTRL_CBACK* p_cback);
 
 /*******************************************************************************
@@ -924,4 +976,12 @@
  *****************************************************************************/
 extern uint8_t AVDT_SetTraceLevel(uint8_t new_level);
 
+/**
+ * Dump debug-related information for the Stack AVDTP module.
+ *
+ * @param fd the file descriptor to use for writing the ASCII formatted
+ * information
+ */
+void stack_debug_avdtp_api_dump(int fd);
+
 #endif /* AVDT_API_H */
diff --git a/stack/include/avdtc_api.h b/stack/include/avdtc_api.h
index 60a7c5f..6948f83 100644
--- a/stack/include/avdtc_api.h
+++ b/stack/include/avdtc_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -107,7 +107,7 @@
  *
  ******************************************************************************/
 extern void AVDTC_GetCapRsp(const RawAddress& bd_addr, uint8_t label,
-                            tAVDT_CFG* p_cap);
+                            AvdtpSepConfig* p_cap);
 
 /*******************************************************************************
  *
@@ -119,7 +119,7 @@
  *
  ******************************************************************************/
 extern void AVDTC_GetAllCapRsp(const RawAddress& bd_addr, uint8_t label,
-                               tAVDT_CFG* p_cap);
+                               AvdtpSepConfig* p_cap);
 
 /*******************************************************************************
  *
@@ -141,7 +141,8 @@
  * Returns          void
  *
  ******************************************************************************/
-extern void AVDTC_GetConfigRsp(uint8_t handle, uint8_t label, tAVDT_CFG* p_cfg);
+extern void AVDTC_GetConfigRsp(uint8_t handle, uint8_t label,
+                               AvdtpSepConfig* p_cfg);
 
 /*******************************************************************************
  *
diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h
index cfac8d7..1aa8ea4 100644
--- a/stack/include/avrc_api.h
+++ b/stack/include/avrc_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2012 Broadcom Corporation
+ *  Copyright 2006-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +23,9 @@
  ******************************************************************************/
 #ifndef AVRC_API_H
 #define AVRC_API_H
+
+#include <base/bind.h>
+
 #include "avct_api.h"
 #include "avrc_defs.h"
 #include "bt_target.h"
@@ -161,23 +164,24 @@
  * implementation of this callback function must copy the p_service_name
  * and p_provider_name parameters passed to it as they are not guaranteed
  * to remain after the callback function exits. */
-typedef void(tAVRC_FIND_CBACK)(uint16_t status);
+using tAVRC_FIND_CBACK = base::Callback<void(uint16_t status)>;
 
 /* This is the control callback function.  This function passes events
  * listed in Table 20 to the application. */
-typedef void(tAVRC_CTRL_CBACK)(uint8_t handle, uint8_t event, uint16_t result,
-                               const RawAddress* peer_addr);
+using tAVRC_CTRL_CBACK =
+    base::Callback<void(uint8_t handle, uint8_t event, uint16_t result,
+                        const RawAddress* peer_addr)>;
 
 /* This is the message callback function.  It is executed when AVCTP has
  * a message packet ready for the application.  The implementation of this
  * callback function must copy the tAVRC_MSG structure passed to it as it
  * is not guaranteed to remain after the callback function exits. */
-typedef void(tAVRC_MSG_CBACK)(uint8_t handle, uint8_t label, uint8_t opcode,
-                              tAVRC_MSG* p_msg);
+using tAVRC_MSG_CBACK = base::Callback<void(uint8_t handle, uint8_t label,
+                                            uint8_t opcode, tAVRC_MSG* p_msg)>;
 
 typedef struct {
-  tAVRC_CTRL_CBACK* p_ctrl_cback; /* pointer to application control callback */
-  tAVRC_MSG_CBACK* p_msg_cback;   /* pointer to application message callback */
+  tAVRC_CTRL_CBACK ctrl_cback;    /* application control callback */
+  tAVRC_MSG_CBACK msg_cback;      /* application message callback */
   uint32_t company_id;            /* the company ID  */
   uint8_t conn;                   /* Connection role (Initiator/acceptor) */
   uint8_t control;                /* Control role (Control/Target) */
@@ -274,7 +278,7 @@
 extern uint16_t AVRC_FindService(uint16_t service_uuid,
                                  const RawAddress& bd_addr,
                                  tAVRC_SDP_DB_PARAMS* p_db,
-                                 tAVRC_FIND_CBACK* p_cback);
+                                 const tAVRC_FIND_CBACK& cback);
 
 /******************************************************************************
  *
diff --git a/stack/include/avrc_defs.h b/stack/include/avrc_defs.h
index 9fe4397..d1c844f 100644
--- a/stack/include/avrc_defs.h
+++ b/stack/include/avrc_defs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2016 Broadcom Corporation
+ *  Copyright 2006-2016 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/ble_advertiser.h b/stack/include/ble_advertiser.h
index 69305c0..f4fc81c 100644
--- a/stack/include/ble_advertiser.h
+++ b/stack/include/ble_advertiser.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -20,6 +20,7 @@
 #define BLE_ADVERTISER_H
 
 #include <base/bind.h>
+#include <base/memory/weak_ptr.h>
 #include <vector>
 #include "btm_ble_api.h"
 
@@ -72,7 +73,7 @@
   static void Initialize(BleAdvertiserHciInterface* interface);
   static void CleanUp();
   static bool IsInitialized();
-  static BleAdvertisingManager* Get();
+  static base::WeakPtr<BleAdvertisingManager> Get();
 
   /* Register an advertising instance, status will be returned in |cb|
    * callback, with assigned id, if operation succeeds. Instance is freed when
diff --git a/stack/include/bnep_api.h b/stack/include/bnep_api.h
index 4116ac9..03b72e4 100644
--- a/stack/include/bnep_api.h
+++ b/stack/include/bnep_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -91,7 +91,8 @@
  *              use BNEP_ConnectResp call to accept or reject the request
 */
 typedef void(tBNEP_CONNECT_IND_CB)(uint16_t handle, const RawAddress& bd_addr,
-                                   tBT_UUID* remote_uuid, tBT_UUID* local_uuid,
+                                   const bluetooth::Uuid& remote_uuid,
+                                   const bluetooth::Uuid& local_uuid,
                                    bool is_role_change);
 
 /* Data buffer received indication callback prototype. Parameters are
@@ -190,8 +191,8 @@
   uint16_t sent_mcast_filters;
   uint16_t rcvd_num_filters;
   uint16_t rcvd_mcast_filters;
-  tBT_UUID src_uuid;
-  tBT_UUID dst_uuid;
+  bluetooth::Uuid src_uuid;
+  bluetooth::Uuid dst_uuid;
 
 } tBNEP_STATUS;
 
@@ -246,7 +247,8 @@
  *
  ******************************************************************************/
 extern tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda,
-                                 tBT_UUID* src_uuid, tBT_UUID* dst_uuid,
+                                 const bluetooth::Uuid& src_uuid,
+                                 const bluetooth::Uuid& dst_uuid,
                                  uint16_t* p_handle);
 
 /*******************************************************************************
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 380e8cd..54a2eb2 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -324,10 +324,10 @@
     for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t)(a)[(len)-1 - ijk]; \
   }
 
-#define STREAM_TO_INT8(u8, p) \
-  {                           \
-    (u8) = (*((int8_t*)p));   \
-    (p) += 1;                 \
+#define STREAM_TO_INT8(u8, p)   \
+  {                             \
+    (u8) = (*((int8_t*)(p)));   \
+    (p) += 1;                   \
   }
 #define STREAM_TO_UINT8(u8, p) \
   {                            \
@@ -352,6 +352,17 @@
              ((((uint32_t)(*((p) + 3)))) << 24));                     \
     (p) += 4;                                                         \
   }
+#define STREAM_TO_UINT64(u64, p)                                      \
+  {                                                                   \
+    (u64) = (((uint64_t)(*(p))) + ((((uint64_t)(*((p) + 1)))) << 8) + \
+             ((((uint64_t)(*((p) + 2)))) << 16) +                     \
+             ((((uint64_t)(*((p) + 3)))) << 24) +                     \
+             ((((uint64_t)(*((p) + 4)))) << 32) +                     \
+             ((((uint64_t)(*((p) + 5)))) << 40) +                     \
+             ((((uint64_t)(*((p) + 6)))) << 48) +                     \
+             ((((uint64_t)(*((p) + 7)))) << 56));                     \
+    (p) += 8;                                                         \
+  }
 #define STREAM_TO_ARRAY32(a, p)                     \
   {                                                 \
     int ijk;                                        \
@@ -527,7 +538,8 @@
 #define BD_ADDR_LEN 6 /* Device address length */
 
 #ifdef __cplusplus
-#include <hardware/bluetooth.h>
+#include <bluetooth/uuid.h>
+#include <include/hardware/bluetooth.h>
 
 inline void BDADDR_TO_STREAM(uint8_t*& p, const RawAddress& a) {
   for (int ijk = 0; ijk < BD_ADDR_LEN; ijk++)
@@ -639,23 +651,6 @@
 
 #define BT_1SEC_TIMEOUT_MS (1 * 1000) /* 1 second */
 
-/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */
-#define MAX_UUID_SIZE 16
-typedef struct {
-#define LEN_UUID_16 2
-#define LEN_UUID_32 4
-#define LEN_UUID_128 16
-
-  uint16_t len;
-
-  union {
-    uint16_t uuid16;
-    uint32_t uuid32;
-    uint8_t uuid128[MAX_UUID_SIZE];
-  } uu;
-
-} tBT_UUID;
-
 #define BT_EIR_FLAGS_TYPE 0x01
 #define BT_EIR_MORE_16BITS_UUID_TYPE 0x02
 #define BT_EIR_COMPLETE_16BITS_UUID_TYPE 0x03
@@ -728,6 +723,7 @@
 #define BLE_ADDR_RANDOM 0x01
 #define BLE_ADDR_PUBLIC_ID 0x02
 #define BLE_ADDR_RANDOM_ID 0x03
+#define BLE_ADDR_ANONYMOUS 0xFF
 typedef uint8_t tBLE_ADDR_TYPE;
 #define BLE_ADDR_TYPE_MASK (BLE_ADDR_RANDOM | BLE_ADDR_PUBLIC)
 
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 3dd5567..6ffc0f9 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -1218,7 +1218,7 @@
  * Returns          true if registered OK, else false
  *
  ******************************************************************************/
-extern bool BTM_SecRegister(tBTM_APPL_INFO* p_cb_info);
+extern bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info);
 
 /*******************************************************************************
  *
@@ -1776,7 +1776,7 @@
  *
  ******************************************************************************/
 extern tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
-                                    tBTM_PM_PWR_MD* p_mode);
+                                    const tBTM_PM_PWR_MD* p_mode);
 
 /*******************************************************************************
  *
@@ -1880,7 +1880,7 @@
  *                  false - if not found
  *
  ******************************************************************************/
-extern bool BTM_HasEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+extern bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16);
 
 /*******************************************************************************
  *
@@ -1957,7 +1957,8 @@
  *
  * Parameters       p_eir - EIR
  *                  eirl_len - EIR len
- *                  uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+ *                  uuid_size - Uuid::kNumBytes16, Uuid::kNumBytes32,
+ *                              Uuid::kNumBytes128
  *                  p_num_uuid - return number of UUID in found list
  *                  p_uuid_list - return UUID 16-bit list
  *                  max_num_uuid - maximum number of UUID to be returned
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index 058aabc..df7b64d 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -56,17 +56,6 @@
 
 typedef uint8_t tBTM_STATUS;
 
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-typedef enum {
-  BTM_BR_ONE,         /*0 First state or BR/EDR scan 1*/
-  BTM_BLE_ONE,        /*1BLE scan 1*/
-  BTM_BR_TWO,         /*2 BR/EDR scan 2*/
-  BTM_BLE_TWO,        /*3 BLE scan 2*/
-  BTM_FINISH,         /*4 End of Interleave Scan, or normal scan*/
-  BTM_NO_INTERLEAVING /*5 No Interleaving*/
-} btm_inq_state;
-#endif
-
 /*************************
  *  Device Control Types
  *************************/
@@ -608,10 +597,6 @@
                       */
   uint8_t filter_cond_type; /* new devices, BD ADDR, COD, or No filtering */
   tBTM_INQ_FILT_COND filter_cond; /* filter value based on filter cond type */
-#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
-  uint8_t intl_duration
-      [4]; /*duration array storing the interleave scan's time portions*/
-#endif
 } tBTM_INQ_PARMS;
 
 #define BTM_INQ_RESULT_BR 0x01
@@ -1602,7 +1587,7 @@
 typedef uint8_t tBTM_LE_KEY_TYPE;
 
 #define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND /* 0 */
-#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_GEN_BOND   /* 1 << 0 */
+#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_BOND       /* 1 << 0 */
 #define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT     /* 1 << 2 */
 typedef uint8_t tBTM_LE_AUTH_REQ;
 #define BTM_LE_SC_SUPPORT_BIT SMP_SC_SUPPORT_BIT /* (1 << 3) */
diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
index 36c8128..f0fb9e6 100644
--- a/stack/include/btm_ble_api.h
+++ b/stack/include/btm_ble_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -763,33 +763,9 @@
 /**
  * This functions are called to configure the adv data payload filter condition
  */
-extern void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
-                                tBTM_BLE_PF_FILT_INDEX filt_index);
-extern void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
-                                  tBTM_BLE_PF_FILT_INDEX filt_index,
-                                  tBLE_BD_ADDR addr, tBTM_BLE_PF_CFG_CBACK cb);
-extern void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
-                                 tBTM_BLE_PF_FILT_INDEX filt_index,
-                                 std::vector<uint8_t> name,
-                                 tBTM_BLE_PF_CFG_CBACK cb);
-extern void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
-                                  tBTM_BLE_PF_FILT_INDEX filt_index,
-                                  tBTM_BLE_PF_COND_TYPE filter_type,
-                                  tBT_UUID uuid,
-                                  tBTM_BLE_PF_LOGIC_TYPE cond_logic,
-                                  tBTM_BLE_PF_COND_MASK* p_uuid_mask,
-                                  tBTM_BLE_PF_CFG_CBACK cb);
-extern void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action,
-                                tBTM_BLE_PF_FILT_INDEX filt_index,
-                                uint16_t company_id, uint16_t company_id_mask,
-                                std::vector<uint8_t> data,
-                                std::vector<uint8_t> data_mask,
-                                tBTM_BLE_PF_CFG_CBACK cb);
-extern void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action,
-                                        tBTM_BLE_PF_FILT_INDEX filt_index,
-                                        std::vector<uint8_t> data,
-                                        std::vector<uint8_t> data_mask,
-                                        tBTM_BLE_PF_CFG_CBACK cb);
+extern void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
+                          std::vector<ApcfCommand> commands,
+                          tBTM_BLE_PF_CFG_CBACK cb);
 extern void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
                             tBTM_BLE_PF_CFG_CBACK cb);
 
diff --git a/stack/include/btm_ble_api_types.h b/stack/include/btm_ble_api_types.h
index 57ef0d1..327a2e6 100644
--- a/stack/include/btm_ble_api_types.h
+++ b/stack/include/btm_ble_api_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -197,6 +197,12 @@
 #define BTM_BLE_CONN_INT_MIN_LIMIT 0x0009
 #endif
 
+/* minimum acceptable connection interval when there is bonded Hearing Aid
+ * device */
+#ifndef BTM_BLE_CONN_INT_MIN_HEARINGAID
+#define BTM_BLE_CONN_INT_MIN_HEARINGAID 0x0010
+#endif
+
 #define BTM_BLE_DIR_CONN_FALLBACK_UNDIR 1
 #define BTM_BLE_DIR_CONN_FALLBACK_NO_ADV 2
 
@@ -331,14 +337,6 @@
 #define BTM_BLE_DATA_TX_TIME_MIN 0x0148
 #define BTM_BLE_DATA_TX_TIME_MAX 0x0848
 
-/* adv tx power level */
-#define BTM_BLE_ADV_TX_POWER_MIN 0   /* minimum tx power */
-#define BTM_BLE_ADV_TX_POWER_LOW 1   /* low tx power     */
-#define BTM_BLE_ADV_TX_POWER_MID 2   /* middle tx power  */
-#define BTM_BLE_ADV_TX_POWER_UPPER 3 /* upper tx power   */
-#define BTM_BLE_ADV_TX_POWER_MAX 4   /* maximum tx power */
-typedef uint8_t tBTM_BLE_ADV_TX_POWER;
-
 /* adv tx power in dBm */
 typedef struct {
   uint8_t adv_inst_max; /* max adv instance supported in controller */
@@ -459,12 +457,6 @@
 using tBTM_BLE_PF_PARAM_CB = base::Callback<void(
     uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* status */)>;
 
-typedef union {
-  uint16_t uuid16_mask;
-  uint32_t uuid32_mask;
-  uint8_t uuid128_mask[LEN_UUID_128];
-} tBTM_BLE_PF_COND_MASK;
-
 /* per device filter + one generic filter indexed by 0 */
 #define BTM_BLE_MAX_FILTER_COUNTER (BTM_BLE_MAX_ADDR_FILTER + 1)
 
diff --git a/stack/include/btu.h b/stack/include/btu.h
index a69ad41..5841efa 100644
--- a/stack/include/btu.h
+++ b/stack/include/btu.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/gap_api.h b/stack/include/gap_api.h
index d9a7217..9293378 100644
--- a/stack/include/gap_api.h
+++ b/stack/include/gap_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -77,6 +77,7 @@
 #define GAP_EVT_CONN_CONGESTED 0x0103
 #define GAP_EVT_CONN_UNCONGESTED 0x0104
 #define GAP_EVT_TX_EMPTY 0x0105
+#define GAP_EVT_LE_COC_CREDITS 0x0106
 
 /* Values for 'chan_mode_mask' field */
 /* GAP_ConnOpen() - optional channels to negotiate */
@@ -105,13 +106,24 @@
 #define GAP_PREFER_CONN_SP_TOUT 2000
 #endif
 
+struct tGAP_COC_CREDITS {
+  uint16_t gap_handle;
+  uint16_t credits_received;
+  uint16_t credit_count;
+};
+
+union tGAP_CB_DATA {
+  tGAP_COC_CREDITS coc_credits;
+};
+
 /*****************************************************************************
  *  Type Definitions
  ****************************************************************************/
 /*
  * Callback function for connection services
 */
-typedef void(tGAP_CONN_CALLBACK)(uint16_t gap_handle, uint16_t event);
+typedef void(tGAP_CONN_CALLBACK)(uint16_t gap_handle, uint16_t event,
+                                 tGAP_CB_DATA* data);
 
 /*
  * Define the callback function prototypes.  Parameters are specific
@@ -163,7 +175,8 @@
  ******************************************************************************/
 extern uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
                              bool is_server, const RawAddress* p_rem_bda,
-                             uint16_t psm, tL2CAP_CFG_INFO* p_cfg,
+                             uint16_t psm, uint16_t le_mps,
+                             tL2CAP_CFG_INFO* p_cfg,
                              tL2CAP_ERTM_INFO* ertm_info, uint16_t security,
                              uint8_t chan_mode_mask, tGAP_CONN_CALLBACK* p_cb,
                              tBT_TRANSPORT transport);
@@ -238,8 +251,7 @@
  *                  GAP_CONGESTION          - system is congested
  *
  ******************************************************************************/
-extern uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
-                                  uint16_t max_len, uint16_t* p_len);
+extern uint16_t GAP_ConnWriteData(uint16_t gap_handle, BT_HDR* msg);
 
 /*******************************************************************************
  *
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
index 48ca8e3..f9c0642 100644
--- a/stack/include/gatt_api.h
+++ b/stack/include/gatt_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -63,6 +63,9 @@
 #define GATT_NOT_ENCRYPTED 0x8e
 #define GATT_CONGESTED 0x8f
 
+#define GATT_DUP_REG 0x90      /* 0x90 */
+#define GATT_ALREADY_OPEN 0x91 /* 0x91 */
+#define GATT_CANCEL 0x92       /* 0x92 */
 /* 0xE0 ~ 0xFC reserved for future use */
 
 /* Client Characteristic Configuration Descriptor Improperly Configured */
@@ -290,7 +293,6 @@
 #define GATT_CLT_CONFIG_NONE 0x0000
 #define GATT_CLT_CONFIG_NOTIFICATION 0x0001
 #define GATT_CLT_CONFIG_INDICATION 0x0002
-typedef uint16_t tGATT_CLT_CHAR_CONFIG;
 
 /* characteristic descriptor: server configuration value
 */
@@ -411,7 +413,7 @@
 /* Discover parameters of different discovery types
 */
 typedef struct {
-  tBT_UUID service;
+  bluetooth::Uuid service;
   uint16_t s_handle;
   uint16_t e_handle;
 } tGATT_DISC_PARAM;
@@ -434,7 +436,7 @@
   tGATT_AUTH_REQ auth_req;
   uint16_t s_handle;
   uint16_t e_handle;
-  tBT_UUID uuid;
+  bluetooth::Uuid uuid;
 } tGATT_READ_BY_TYPE;
 
 /*   GATT_READ_MULTIPLE request data
@@ -499,20 +501,20 @@
 typedef struct {
   tGATT_CHAR_PROP char_prop; /* characterisitc properties */
   uint16_t val_handle;       /* characteristic value attribute handle */
-  tBT_UUID char_uuid;        /* characteristic UUID type */
+  bluetooth::Uuid char_uuid; /* characteristic UUID type */
 } tGATT_CHAR_DCLR_VAL;
 
 /* primary service group data
 */
 typedef struct {
   uint16_t e_handle;     /* ending handle of the group */
-  tBT_UUID service_type; /* group type */
+  bluetooth::Uuid service_type; /* group type */
 } tGATT_GROUP_VALUE;
 
 /* included service attribute value
 */
 typedef struct {
-  tBT_UUID service_type; /* included service UUID */
+  bluetooth::Uuid service_type; /* included service UUID */
   uint16_t s_handle;     /* starting handle */
   uint16_t e_handle;     /* ending handle */
 } tGATT_INCL_SRVC;
@@ -535,7 +537,7 @@
 /* discover result record
 */
 typedef struct {
-  tBT_UUID type;
+  bluetooth::Uuid type;
   uint16_t handle;
   tGATT_DISC_VALUE value;
 } tGATT_DISC_RES;
@@ -605,8 +607,8 @@
 /*****************  Start Handle Management Definitions   *********************/
 
 typedef struct {
-  tBT_UUID app_uuid128;
-  tBT_UUID svc_uuid;
+  bluetooth::Uuid app_uuid128;
+  bluetooth::Uuid svc_uuid;
   uint16_t s_handle;
   uint16_t e_handle;
   bool is_primary; /* primary service or secondary */
@@ -687,10 +689,6 @@
  ******************************************************************************/
 extern bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info);
 
-/* Converts 16bit uuid to bt_uuid_t that can be used when adding
- * service/characteristic/descriptor with GATTS_AddService */
-void uuid_128_from_16(bt_uuid_t* uuid, uint16_t uuid16);
-
 /*******************************************************************************
  *
  * Function         BTA_GATTS_AddService
@@ -725,7 +723,7 @@
  * Returns          true if operation succeed, else false
  *
  ******************************************************************************/
-extern bool GATTS_DeleteService(tGATT_IF gatt_if, tBT_UUID* p_svc_uuid,
+extern bool GATTS_DeleteService(tGATT_IF gatt_if, bluetooth::Uuid* p_svc_uuid,
                                 uint16_t svc_inst);
 
 /*******************************************************************************
@@ -931,7 +929,8 @@
  *                  with GATT
  *
  ******************************************************************************/
-extern tGATT_IF GATT_Register(tBT_UUID* p_app_uuid128, tGATT_CBACK* p_cb_info);
+extern tGATT_IF GATT_Register(const bluetooth::Uuid& p_app_uuid128,
+                              tGATT_CBACK* p_cb_info);
 
 /*******************************************************************************
  *
diff --git a/stack/include/gattdefs.h b/stack/include/gattdefs.h
index de968a8..5f5093d 100644
--- a/stack/include/gattdefs.h
+++ b/stack/include/gattdefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index c015b97..8f91743 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2014 Broadcom Corporation
+ *  Copyright 1999-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -358,6 +358,7 @@
 #define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL (0x002C | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE (0x002D | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT (0x002E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_MAXIMUM_DATA_LENGTH (0x002F | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_READ_PHY (0x0030 | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_DEFAULT_PHY (0x0031 | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_PHY (0x0032 | HCI_GRP_BLE_CMDS)
@@ -379,6 +380,20 @@
 #define HCI_LE_SET_EXTENDED_SCAN_PARAMETERS (0x0041 | HCI_GRP_BLE_CMDS)
 #define HCI_LE_SET_EXTENDED_SCAN_ENABLE (0x0042 | HCI_GRP_BLE_CMDS)
 #define HCI_LE_EXTENDED_CREATE_CONNECTION (0x0043 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_CREATE_SYNC (0x0044 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL \
+  (0x0045 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC \
+  (0x0046 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST \
+  (0x0047 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST \
+  (0x0048 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_PERIODIC_ADVERTISING_LIST (0x0049 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE (0x004A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_TRANSMIT_POWER (0x004B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RF_COMPENS_POWER (0x004C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RF_COMPENS_POWER (0x004D | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS)
 
 /* LE Get Vendor Capabilities Command OCF */
@@ -405,6 +420,9 @@
 /* Controller debug info OCF */
 #define HCI_CONTROLLER_DEBUG_INFO_OCF (0x015B | HCI_GRP_VENDOR_SPECIFIC)
 
+/* A2DP offload OCF */
+#define HCI_CONTROLLER_A2DP_OPCODE_OCF (0x015D | HCI_GRP_VENDOR_SPECIFIC)
+
 /* subcode for multi adv feature */
 #define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
 #define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA 0x02
@@ -572,7 +590,12 @@
 #define HCI_BLE_DIRECT_ADV_EVT 0x0b
 #define HCI_BLE_PHY_UPDATE_COMPLETE_EVT 0x0c
 #define HCI_LE_EXTENDED_ADVERTISING_REPORT_EVT 0x0D
+#define HCI_BLE_PERIODIC_ADV_SYNC_EST_EVT      0x0E
+#define HCI_BLE_PERIODIC_ADV_REPORT_EVT        0x0F
+#define HCI_BLE_PERIODIC_ADV_SYNC_LOST_EVT     0x10
+#define HCI_BLE_SCAN_TIMEOUT_EVT               0x11
 #define HCI_LE_ADVERTISING_SET_TERMINATED_EVT 0x12
+#define HCI_BLE_SCAN_REQ_RX_EVT                0x13
 
 /* Definitions for LE Channel Map */
 #define HCI_BLE_CHNL_MAP_SIZE 5
@@ -647,9 +670,10 @@
 #define HCI_ERR_REJ_NO_SUITABLE_CHANNEL 0x39
 #define HCI_ERR_CONTROLLER_BUSY 0x3A
 #define HCI_ERR_UNACCEPT_CONN_INTERVAL 0x3B
-#define HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT 0x3C
+#define HCI_ERR_ADVERTISING_TIMEOUT 0x3C
 #define HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE 0x3D
 #define HCI_ERR_CONN_FAILED_ESTABLISHMENT 0x3E
+#define HCI_ERR_LIMIT_REACHED 0x43
 #define HCI_ERR_MAC_CONNECTION_FAILED 0x3F
 
 /* ConnectionLess Broadcast errors */
@@ -1242,6 +1266,8 @@
 #define LMP_TESTCTL_POWCTL_FIXEDTX_OP 0
 #define LMP_TESTCTL_POWCTL_ADAPTIVE 1
 
+#define LMP_COMPID_GOOGLE 0xE0
+
 // TODO(zachoverflow): remove this once broadcom specific hacks are removed
 #define LMP_COMPID_BROADCOM 15
 
diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
index da6be9b..a909751 100644
--- a/stack/include/hcimsgs.h
+++ b/stack/include/hcimsgs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/hidd_api.h b/stack/include/hidd_api.h
index 85785e8..145c0f1 100644
--- a/stack/include/hidd_api.h
+++ b/stack/include/hidd_api.h
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2016 The Android Open Source Project
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/hiddefs.h b/stack/include/hiddefs.h
index 55f7e55..8df616c 100644
--- a/stack/include/hiddefs.h
+++ b/stack/include/hiddefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/hidh_api.h b/stack/include/hidh_api.h
index 5b43b44..37b5205 100644
--- a/stack/include/hidh_api.h
+++ b/stack/include/hidh_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2002-2012 Broadcom Corporation
+ *  Copyright 2002-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h
index 6d7f423..88121af5 100644
--- a/stack/include/l2c_api.h
+++ b/stack/include/l2c_api.h
@@ -1,20 +1,20 @@
 /******************************************************************************
-*
-*  Copyright (C) 1999-2012 Broadcom Corporation
-*
-*  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.
-*
-******************************************************************************/
+ *
+ *  Copyright 1999-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
 
 /******************************************************************************
  *
@@ -43,6 +43,8 @@
 #define L2CAP_LCC_OFFSET \
   (L2CAP_MIN_OFFSET + L2CAP_LCC_SDU_LENGTH) /* plus SDU length(2) */
 
+#define L2CAP_FCS_LENGTH 2
+
 /* ping result codes */
 #define L2CAP_PING_RESULT_OK 0      /* Ping reply received OK     */
 #define L2CAP_PING_RESULT_NO_LINK 1 /* Link could not be setup    */
@@ -284,6 +286,15 @@
  */
 typedef void(tL2CA_TX_COMPLETE_CB)(uint16_t, uint16_t);
 
+/* Callback for receiving credits from the remote device.
+ * |credit_received| parameter represents number of credits received in "LE Flow
+ * Control Credit" packet from the remote. |credit_count| parameter represents
+ * the total available credits, including |credit_received|.
+ */
+typedef void(tL2CA_CREDITS_RECEIVED_CB)(uint16_t local_cid,
+                                        uint16_t credits_received,
+                                        uint16_t credit_count);
+
 /* Define the structure that applications use to register with
  * L2CAP. This structure includes callback functions. All functions
  * MUST be provided, with the exception of the "connect pending"
@@ -301,7 +312,7 @@
   tL2CA_DATA_IND_CB* pL2CA_DataInd_Cb;
   tL2CA_CONGESTION_STATUS_CB* pL2CA_CongestionStatus_Cb;
   tL2CA_TX_COMPLETE_CB* pL2CA_TxComplete_Cb;
-
+  tL2CA_CREDITS_RECEIVED_CB* pL2CA_CreditsReceived_Cb;
 } tL2CAP_APPL_INFO;
 
 /* Define the structure that applications use to create or accept
@@ -379,6 +390,29 @@
 
 /*******************************************************************************
  *
+ * Function         L2CA_AllocateLePSM
+ *
+ * Description      Other layers call this function to find an unused LE PSM for
+ *                  L2CAP services.
+ *
+ * Returns          LE_PSM to use if success. Otherwise returns 0.
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_AllocateLePSM(void);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_FreeLePSM
+ *
+ * Description      Free an assigned LE PSM.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void L2CA_FreeLePSM(uint16_t psm);
+
+/*******************************************************************************
+ *
  * Function         L2CA_ConnectReq
  *
  * Description      Higher layers call this function to create an L2CAP
@@ -1200,6 +1234,10 @@
 extern bool L2CA_UpdateBleConnParams(const RawAddress& rem_bdRa,
                                      uint16_t min_int, uint16_t max_int,
                                      uint16_t latency, uint16_t timeout);
+extern bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda,
+                                     uint16_t min_int, uint16_t max_int,
+                                     uint16_t latency, uint16_t timeout,
+                                     uint16_t min_ce_len, uint16_t max_ce_len);
 
 /*******************************************************************************
  *
@@ -1242,4 +1280,7 @@
 extern uint16_t L2CA_GetDisconnectReason(const RawAddress& remote_bda,
                                          tBT_TRANSPORT transport);
 
+extern void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
+                                           uint16_t* max_interval,
+                                           uint16_t floor_interval);
 #endif /* L2C_API_H */
diff --git a/stack/include/l2cap_client.h b/stack/include/l2cap_client.h
index fb4e922..edb204e 100644
--- a/stack/include/l2cap_client.h
+++ b/stack/include/l2cap_client.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/l2cdefs.h b/stack/include/l2cdefs.h
index 592d7b3..4f4c894 100644
--- a/stack/include/l2cdefs.h
+++ b/stack/include/l2cdefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -322,13 +322,14 @@
   (L2CAP_PKT_OVERHEAD + L2CAP_EXT_CONTROL_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + \
    L2CAP_FCS_LEN)
 
-/* To optimize this, it must be a multiple of the L2CAP PDU length AND match
- * the 3DH5 air including the l2cap headers in each packet. To match the latter,
- * the -5 is added.
- * Changed it to  8087 to have same value between BTIF and L2cap layers
+/* TODO: This value can probably be optimized per transport, and per L2CAP
+ * socket type, but this should not bring any big performance improvements. For
+ * LE CoC, it should be biggest multiple of "PDU length" smaller than 0xffff (so
+ * depend on controller buffer size), for Classic, making it multiple of PDU
+ * length and also of the 3DH5 air including the l2cap headers in each packet.
  */
-#define L2CAP_MAX_SDU_LENGTH (8080 + 26 - (L2CAP_MIN_OFFSET + 6))
-#define L2CAP_MAX_BUF_SIZE (10240 + 24)
+#define L2CAP_SDU_LENGTH_MAX (8080 + 26 - (L2CAP_MIN_OFFSET + 6))
+constexpr uint16_t L2CAP_SDU_LENGTH_LE_MAX = 0xffff;
 
 /* Part of L2CAP_MIN_OFFSET that is not part of L2CAP
 */
diff --git a/stack/include/mca_api.h b/stack/include/mca_api.h
index 3c962d0..539d6c2 100644
--- a/stack/include/mca_api.h
+++ b/stack/include/mca_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/mca_defs.h b/stack/include/mca_defs.h
index a442471..7b6d3c2 100644
--- a/stack/include/mca_defs.h
+++ b/stack/include/mca_defs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/pan_api.h b/stack/include/pan_api.h
index d46aa3f..0f9bab1 100644
--- a/stack/include/pan_api.h
+++ b/stack/include/pan_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/port_api.h b/stack/include/port_api.h
index 7971235..aedbe74 100644
--- a/stack/include/port_api.h
+++ b/stack/include/port_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/port_ext.h b/stack/include/port_ext.h
index ec8eb94..ba31cf0 100644
--- a/stack/include/port_ext.h
+++ b/stack/include/port_ext.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/profiles_api.h b/stack/include/profiles_api.h
index aa3b884..f91826d 100644
--- a/stack/include/profiles_api.h
+++ b/stack/include/profiles_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2013 Broadcom Corporation
+ *  Copyright 2009-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/rfcdefs.h b/stack/include/rfcdefs.h
index ab3ceb6..ca9b3ce 100644
--- a/stack/include/rfcdefs.h
+++ b/stack/include/rfcdefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/sdp_api.h b/stack/include/sdp_api.h
index 72ccd0e..7752fd6 100644
--- a/stack/include/sdp_api.h
+++ b/stack/include/sdp_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -52,9 +52,6 @@
 /* Define the PSM that SDP uses */
 #define SDP_PSM 0x0001
 
-/* Legacy #define to avoid code changes - SDP UUID is same as BT UUID */
-#define tSDP_UUID tBT_UUID
-
 /* Masks for attr_value field of tSDP_DISC_ATTR */
 #define SDP_DISC_ATTR_LEN_MASK 0x0FFF
 #define SDP_DISC_ATTR_TYPE(len_type) ((len_type) >> 12)
@@ -120,7 +117,7 @@
   uint32_t mem_free;          /* Memory still available       */
   tSDP_DISC_REC* p_first_rec; /* Addr of first record in DB   */
   uint16_t num_uuid_filters;  /* Number of UUIds to filter    */
-  tSDP_UUID uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter      */
+  bluetooth::Uuid uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter */
   uint16_t num_attr_filters; /* Number of attribute filters  */
   uint16_t attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */
   uint8_t* p_free_mem; /* Pointer to free memory       */
@@ -176,7 +173,7 @@
  *
  ******************************************************************************/
 bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
-                         uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+                         uint16_t num_uuid, const bluetooth::Uuid* p_uuid_list,
                          uint16_t num_attr, uint16_t* p_attr_list);
 
 /*******************************************************************************
@@ -295,13 +292,13 @@
  *
  * NOTE             the only difference between this function and the previous
  *                  function "SDP_FindServiceInDb()" is that this function takes
- *                  a tBT_UUID input.
+ *                  a Uuid input.
  *
  * Returns          Pointer to record containing service class, or NULL
  *
  ******************************************************************************/
 tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
-                                       tBT_UUID* p_uuid,
+                                       const bluetooth::Uuid& uuid,
                                        tSDP_DISC_REC* p_start_rec);
 
 /*******************************************************************************
@@ -317,7 +314,8 @@
  * Returns          true if found, otherwise false.
  *
  ******************************************************************************/
-bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid);
+bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec,
+                                     bluetooth::Uuid* p_uuid);
 
 /*******************************************************************************
  *
@@ -636,11 +634,6 @@
  * Returns          true if found, otherwise false.
  *
  ******************************************************************************/
-bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid);
-
-// Converts UUID-16 to UUID-128 by including the base UUID.
-// |uuid16| is the 2-byte UUID to convert.
-// The result with the expanded 128-bit UUID is stored in |p_uuid128|.
-void sdpu_uuid16_to_uuid128(uint16_t uuid16, uint8_t* p_uuid128);
+bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid);
 
 #endif /* SDP_API_H */
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
index ad0e611..05b3cc1 100644
--- a/stack/include/sdpdefs.h
+++ b/stack/include/sdpdefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
index 10cff74..816407d 100644
--- a/stack/include/smp_api.h
+++ b/stack/include/smp_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/include/smp_api_types.h b/stack/include/smp_api_types.h
index a21af4b..fad8b75 100644
--- a/stack/include/smp_api_types.h
+++ b/stack/include/smp_api_types.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -122,7 +122,7 @@
 typedef uint8_t tSMP_OOB_DATA_TYPE;
 
 #define SMP_AUTH_NO_BOND 0x00
-#define SMP_AUTH_GEN_BOND 0x01  // todo sdh change GEN_BOND to BOND
+#define SMP_AUTH_BOND 0x01
 
 /* SMP Authentication requirement */
 #define SMP_AUTH_YN_BIT (1 << 2)
@@ -130,11 +130,9 @@
 #define SMP_KP_SUPPORT_BIT (1 << 4)
 #define SMP_H7_SUPPORT_BIT (1 << 5)
 
-#define SMP_AUTH_MASK                                         \
-  (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT | SMP_SC_SUPPORT_BIT | \
-   SMP_KP_SUPPORT_BIT | SMP_H7_SUPPORT_BIT)
-
-#define SMP_AUTH_BOND SMP_AUTH_GEN_BOND
+#define SMP_AUTH_MASK                                                          \
+  (SMP_AUTH_BOND | SMP_AUTH_YN_BIT | SMP_SC_SUPPORT_BIT | SMP_KP_SUPPORT_BIT | \
+   SMP_H7_SUPPORT_BIT)
 
 /* no MITM, No Bonding, encryption only */
 #define SMP_AUTH_NB_ENC_ONLY 0x00  //(SMP_AUTH_MASK | BTM_AUTH_SP_NO)
@@ -143,27 +141,25 @@
 #define SMP_AUTH_NB_IOCAP (SMP_AUTH_NO_BOND | SMP_AUTH_YN_BIT)
 
 /* No MITM, General Bonding, Encryption only */
-#define SMP_AUTH_GB_ENC_ONLY (SMP_AUTH_GEN_BOND)
+#define SMP_AUTH_GB_ENC_ONLY SMP_AUTH_BOND
 
 /* MITM, General Bonding, Use IO Capability to determine authentication
  * procedure */
-#define SMP_AUTH_GB_IOCAP (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT)
+#define SMP_AUTH_GB_IOCAP (SMP_AUTH_BOND | SMP_AUTH_YN_BIT)
 
 /* Secure Connections, no MITM, no Bonding */
 #define SMP_AUTH_SC_ENC_ONLY (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT)
 
 /* Secure Connections, no MITM, Bonding */
-#define SMP_AUTH_SC_GB \
-  (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_GEN_BOND)
+#define SMP_AUTH_SC_GB (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_BOND)
 
 /* Secure Connections, MITM, no Bonding */
 #define SMP_AUTH_SC_MITM_NB \
   (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_NO_BOND)
 
 /* Secure Connections, MITM, Bonding */
-#define SMP_AUTH_SC_MITM_GB                                    \
-  (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | \
-   SMP_AUTH_GEN_BOND)
+#define SMP_AUTH_SC_MITM_GB \
+  (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_BOND)
 
 /* All AuthReq RFU bits are set to 1 - NOTE: reserved bit in Bonding_Flags is
  * not set */
diff --git a/stack/include/srvc_api.h b/stack/include/srvc_api.h
index 9f0e1aa..e968998 100644
--- a/stack/include/srvc_api.h
+++ b/stack/include/srvc_api.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2013 Broadcom Corporation
+ *  Copyright 1999-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc
index 809199f..951a45b 100644
--- a/stack/l2cap/l2c_api.cc
+++ b/stack/l2cap/l2c_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -194,6 +194,75 @@
 
 /*******************************************************************************
  *
+ * Function         L2CA_AllocateLePSM
+ *
+ * Description      To find an unused LE PSM for L2CAP services.
+ *
+ * Returns          LE_PSM to use if success. Otherwise returns 0.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocateLePSM(void) {
+  bool done = false;
+  uint16_t psm = l2cb.le_dyn_psm;
+  uint16_t count = 0;
+
+  L2CAP_TRACE_API("%s: last psm=%d", __func__, psm);
+  while (!done) {
+    count++;
+    if (count > LE_DYNAMIC_PSM_RANGE) {
+      L2CAP_TRACE_ERROR("%s: Out of free BLE PSM", __func__);
+      return 0;
+    }
+
+    psm++;
+    if (psm > LE_DYNAMIC_PSM_END) {
+      psm = LE_DYNAMIC_PSM_START;
+    }
+
+    if (!l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START]) {
+      /* make sure the newly allocated psm is not used right now */
+      if (l2cu_find_ble_rcb_by_psm(psm)) {
+        L2CAP_TRACE_WARNING("%s: supposedly-free PSM=%d have allocated rcb!",
+                            __func__, psm);
+        continue;
+      }
+
+      l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START] = true;
+      L2CAP_TRACE_DEBUG("%s: assigned PSM=%d", __func__, psm);
+      done = true;
+      break;
+    }
+  }
+  l2cb.le_dyn_psm = psm;
+
+  return (psm);
+}
+
+/*******************************************************************************
+ *
+ * Function         L2CA_FreeLePSM
+ *
+ * Description      Free an assigned LE PSM.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void L2CA_FreeLePSM(uint16_t psm) {
+  L2CAP_TRACE_API("%s: to free psm=%d", __func__, psm);
+
+  if ((psm < LE_DYNAMIC_PSM_START) || (psm > LE_DYNAMIC_PSM_END)) {
+    L2CAP_TRACE_ERROR("%s: Invalid PSM=%d value!", __func__, psm);
+    return;
+  }
+
+  if (!l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START]) {
+    L2CAP_TRACE_WARNING("%s: PSM=%d was not allocated!", __func__, psm);
+  }
+  l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START] = false;
+}
+
+/*******************************************************************************
+ *
  * Function         L2CA_ConnectReq
  *
  * Description      Higher layers call this function to create an L2CAP
@@ -256,8 +325,7 @@
     /* 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) == false)) {
+    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);
@@ -359,10 +427,12 @@
 
   /* Check if this is a registration for an outgoing-only connection to */
   /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
-  if ((psm >= 0x0080) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL)) {
-    for (vpsm = 0x0080; vpsm < 0x0100; vpsm++) {
-      p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
-      if (p_rcb == NULL) break;
+  if ((psm >= LE_DYNAMIC_PSM_START) &&
+      (p_cb_info->pL2CA_ConnectInd_Cb == NULL)) {
+    vpsm = L2CA_AllocateLePSM();
+    if (vpsm == 0) {
+      L2CAP_TRACE_ERROR("%s: Out of free BLE PSM", __func__);
+      return 0;
     }
 
     L2CAP_TRACE_API("%s Real PSM: 0x%04x  Virtual PSM: 0x%04x", __func__, psm,
@@ -372,6 +442,7 @@
   /* If registration block already there, just overwrite it */
   p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
   if (p_rcb == NULL) {
+    L2CAP_TRACE_API("%s Allocate rcp for Virtual PSM: 0x%04x", __func__, vpsm);
     p_rcb = l2cu_allocate_ble_rcb(vpsm);
     if (p_rcb == NULL) {
       L2CAP_TRACE_WARNING("%s No BLE RCB available, PSM: 0x%04x  vPSM: 0x%04x",
@@ -401,7 +472,8 @@
 
   tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm);
   if (p_rcb == NULL) {
-    L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", psm);
+    L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", __func__,
+                        psm);
     return;
   }
 
@@ -420,7 +492,7 @@
       l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
   }
 
-  l2cu_release_rcb(p_rcb);
+  l2cu_release_ble_rcb(p_rcb);
 }
 
 /*******************************************************************************
@@ -465,7 +537,7 @@
     p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_LE);
     if ((p_lcb == NULL)
         /* currently use BR/EDR for ERTM mode l2cap connection */
-        || (l2cu_create_conn(p_lcb, BT_TRANSPORT_LE) == false)) {
+        || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_LE))) {
       L2CAP_TRACE_WARNING("%s conn not started for PSM: 0x%04x  p_lcb: 0x%08x",
                           __func__, psm, p_lcb);
       return 0;
@@ -483,7 +555,10 @@
   p_ccb->p_rcb = p_rcb;
 
   /* Save the configuration */
-  if (p_cfg) memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+  if (p_cfg) {
+    memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+    p_ccb->remote_credit_count = p_cfg->credits;
+  }
 
   /* If link is up, start the L2CAP connection */
   if (p_lcb->link_state == LST_CONNECTED) {
@@ -553,7 +628,10 @@
     return false;
   }
 
-  if (p_cfg) memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+  if (p_cfg) {
+    memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+    p_ccb->remote_credit_count = p_cfg->credits;
+  }
 
   if (result == L2CAP_CONN_OK)
     l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
@@ -904,7 +982,7 @@
       L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_ping");
       return (false);
     }
-    if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false) {
+    if (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR)) {
       return (false);
     }
 
@@ -1214,7 +1292,8 @@
  *
  ******************************************************************************/
 bool L2CA_SetAclPriority(const RawAddress& bd_addr, uint8_t priority) {
-  VLOG(1) << __func__ << " BDA: " << bd_addr << ", priority: " << priority;
+  VLOG(1) << __func__ << " BDA: " << bd_addr
+          << ", priority: " << std::to_string(priority);
   return (l2cu_set_acl_priority(bd_addr, priority, false));
 }
 
@@ -2124,7 +2203,7 @@
        * controller */
       if ((HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures())) &&
           (BTM_GetNumScoLinks() == 0)) {
-        if (l2cb.is_flush_active == false) {
+        if (!l2cb.is_flush_active) {
           l2cb.is_flush_active = true;
 
           /* The only packet type defined - 0 - Automatically-Flushable Only */
diff --git a/stack/l2cap/l2c_ble.cc b/stack/l2cap/l2c_ble.cc
index 078f75f..5fc01f9 100644
--- a/stack/l2cap/l2c_ble.cc
+++ b/stack/l2cap/l2c_ble.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
 #include <string.h>
 #include "bt_target.h"
 #include "bt_utils.h"
+#include "bta_hearing_aid_api.h"
 #include "btm_int.h"
 #include "btu.h"
 #include "device/include/controller.h"
@@ -99,7 +100,8 @@
  ******************************************************************************/
 bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
                               uint16_t max_int, uint16_t latency,
-                              uint16_t timeout) {
+                              uint16_t timeout, uint16_t min_ce_len,
+                              uint16_t max_ce_len) {
   tL2C_LCB* p_lcb;
   tACL_CONN* p_acl_cb = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE);
 
@@ -117,17 +119,30 @@
     return (false);
   }
 
+  VLOG(2) << __func__ << ": BD_ADDR=" << rem_bda << ", min_int=" << min_int
+          << ", max_int=" << max_int << ", min_ce_len=" << min_ce_len
+          << ", max_ce_len=" << max_ce_len;
+
   p_lcb->min_interval = min_int;
   p_lcb->max_interval = max_int;
   p_lcb->latency = latency;
   p_lcb->timeout = timeout;
   p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+  p_lcb->min_ce_len = min_ce_len;
+  p_lcb->max_ce_len = max_ce_len;
 
   l2cble_start_conn_update(p_lcb);
 
   return (true);
 }
 
+bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
+                              uint16_t max_int, uint16_t latency,
+                              uint16_t timeout) {
+  return L2CA_UpdateBleConnParams(rem_bda, min_int, max_int, latency, timeout,
+                                  0, 0);
+}
+
 /*******************************************************************************
  *
  *  Function        L2CA_EnableUpdateBleConnParams
@@ -469,6 +484,10 @@
         p_lcb->min_interval > BTM_BLE_CONN_INT_MIN) {
       /* use 7.5 ms as fast connection parameter, 0 slave latency */
       min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
+
+      L2CA_AdjustConnectionIntervals(&min_conn_int, &max_conn_int,
+                                     BTM_BLE_CONN_INT_MIN);
+
       slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
       supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
 
@@ -504,7 +523,8 @@
               ) {
         btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, p_lcb->min_interval,
                                           p_lcb->max_interval, p_lcb->latency,
-                                          p_lcb->timeout, 0, 0);
+                                          p_lcb->timeout, p_lcb->min_ce_len,
+                                          p_lcb->max_ce_len);
         p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
       } else {
         l2cu_send_peer_ble_par_req(p_lcb, p_lcb->min_interval,
@@ -617,15 +637,8 @@
       STREAM_TO_UINT16(timeout, p);      /* 0x000A - 0x0C80 */
       /* If we are a master, the slave wants to update the parameters */
       if (p_lcb->link_role == HCI_ROLE_MASTER) {
-        if (min_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
-          min_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
-
-        // While this could result in connection parameters that fall
-        // outside fo the range requested, this will allow the connection
-        // to remain established.
-        // In other words, this is a workaround for certain peripherals.
-        if (max_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
-          max_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+        L2CA_AdjustConnectionIntervals(&min_interval, &max_interval,
+                                       BTM_BLE_CONN_INT_MIN_LIMIT);
 
         if (min_interval < BTM_BLE_CONN_INT_MIN ||
             min_interval > BTM_BLE_CONN_INT_MAX ||
@@ -1361,7 +1374,8 @@
   uint8_t sec_act;
 
   if (!p_lcb) {
-    L2CAP_TRACE_WARNING("%s security complete for unknown device", __func__);
+    L2CAP_TRACE_WARNING("%s: security complete for unknown device. bda=%s",
+                        __func__, bda->ToString().c_str());
     return;
   }
 
@@ -1466,3 +1480,37 @@
 
   return status;
 }
+
+/* This function is called to adjust the connection intervals based on various
+ * constraints. For example, when there is at least one Hearing Aid device
+ * bonded, the minimum interval is raised. On return, min_interval and
+ * max_interval are updated. */
+void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
+                                    uint16_t* max_interval,
+                                    uint16_t floor_interval) {
+  uint16_t phone_min_interval = floor_interval;
+
+  if (HearingAid::GetDeviceCount() > 0) {
+    // When there are bonded Hearing Aid devices, we will constrained this
+    // minimum interval.
+    phone_min_interval = BTM_BLE_CONN_INT_MIN_HEARINGAID;
+    L2CAP_TRACE_DEBUG("%s: Have Hearing Aids. Min. interval is set to %d",
+                      __func__, phone_min_interval);
+  }
+
+  if (*min_interval < phone_min_interval) {
+    L2CAP_TRACE_DEBUG("%s: requested min_interval=%d too small. Set to %d",
+                      __func__, *min_interval, phone_min_interval);
+    *min_interval = phone_min_interval;
+  }
+
+  // While this could result in connection parameters that fall
+  // outside fo the range requested, this will allow the connection
+  // to remain established.
+  // In other words, this is a workaround for certain peripherals.
+  if (*max_interval < phone_min_interval) {
+    L2CAP_TRACE_DEBUG("%s: requested max_interval=%d too small. Set to %d",
+                      __func__, *max_interval, phone_min_interval);
+    *max_interval = phone_min_interval;
+  }
+}
diff --git a/stack/l2cap/l2c_csm.cc b/stack/l2cap/l2c_csm.cc
index 66033ee..bb89eac 100644
--- a/stack/l2cap/l2c_csm.cc
+++ b/stack/l2cap/l2c_csm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -138,16 +138,6 @@
     return;
   }
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (local_cid == L2CAP_CONNECTIONLESS_CID) {
-    /* check if this event can be processed by UCD */
-    if (l2c_ucd_process_event(p_ccb, event, p_data)) {
-      /* The event is processed by UCD state machine */
-      return;
-    }
-  }
-#endif
-
   disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
   connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
 
@@ -195,22 +185,21 @@
                              true, &l2c_link_sec_comp2, p_ccb);
       } else {
         /* Cancel sniff mode if needed */
-        {
-          tBTM_PM_PWR_MD settings;
-          memset((void*)&settings, 0, sizeof(settings));
-          settings.mode = BTM_PM_MD_ACTIVE;
+        tBTM_PM_PWR_MD settings;
+        memset((void*)&settings, 0, sizeof(settings));
+        settings.mode = BTM_PM_MD_ACTIVE;
 
-          BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr,
-                           &settings);
-        }
+        BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr,
+                         &settings);
 
         /* If sec access does not result in started SEC_COM or COMP_NEG are
          * already processed */
         if (btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr,
                                      p_ccb->p_rcb->psm, p_ccb->p_lcb->handle,
                                      true, &l2c_link_sec_comp,
-                                     p_ccb) == BTM_CMD_STARTED)
+                                     p_ccb) == BTM_CMD_STARTED) {
           p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+        }
       }
       break;
 
@@ -290,11 +279,6 @@
     case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
       l2cu_release_ccb(p_ccb);
       break;
-
-    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
-    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
-      osi_free(p_data);
-      break;
   }
 }
 
@@ -315,18 +299,11 @@
   tL2CA_CONNECT_CFM_CB* connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
   uint16_t local_cid = p_ccb->local_cid;
 
-  L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x  st: ORIG_W4_SEC_COMP  evt: %s",
-                    p_ccb->local_cid, l2c_csm_get_event_name(event));
-
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (local_cid == L2CAP_CONNECTIONLESS_CID) {
-    /* check if this event can be processed by UCD */
-    if (l2c_ucd_process_event(p_ccb, event, p_data)) {
-      /* The event is processed by UCD state machine */
-      return;
-    }
-  }
-#endif
+  L2CAP_TRACE_EVENT(
+      "%s: %sL2CAP - LCID: 0x%04x  st: ORIG_W4_SEC_COMP  evt: %s", __func__,
+      ((p_ccb->p_lcb) && (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)) ? "LE "
+                                                                       : "",
+      p_ccb->local_cid, l2c_csm_get_event_name(event));
 
   switch (event) {
     case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
@@ -418,16 +395,6 @@
   L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x  st: TERM_W4_SEC_COMP  evt: %s",
                     p_ccb->local_cid, l2c_csm_get_event_name(event));
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
-    /* check if this event can be processed by UCD */
-    if (l2c_ucd_process_event(p_ccb, event, p_data)) {
-      /* The event is processed by UCD state machine */
-      return;
-    }
-  }
-#endif
-
   switch (event) {
     case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
       /* Tell security manager to abort */
@@ -584,16 +551,16 @@
       break;
 
     case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer rejected connection */
-      L2CAP_TRACE_API(
-          "L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d",
-          p_ccb->local_cid, p_ci->l2cap_result);
+      LOG(WARNING) << __func__ << ": L2CAP connection rejected, lcid="
+                   << loghex(p_ccb->local_cid)
+                   << ", reason=" << loghex(p_ci->l2cap_result);
       l2cu_release_ccb(p_ccb);
       (*connect_cfm)(local_cid, p_ci->l2cap_result);
       break;
 
     case L2CEVT_TIMEOUT:
-      L2CAP_TRACE_API("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout",
-                      p_ccb->local_cid);
+      LOG(WARNING) << __func__ << ": L2CAP connection timeout, lcid="
+                   << loghex(p_ccb->local_cid);
       l2cu_release_ccb(p_ccb);
       (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
       break;
@@ -635,11 +602,6 @@
         l2cu_send_peer_connect_req(p_ccb); /* Start Connection     */
       }
       break;
-
-    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
-    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
-      osi_free(p_data);
-      break;
   }
 }
 
@@ -861,7 +823,7 @@
       alarm_cancel(p_ccb->l2c_ccb_timer);
 
       /* If failure was channel mode try to renegotiate */
-      if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == false) {
+      if (!l2c_fcr_renegotiate_chan(p_ccb, p_cfg)) {
         L2CAP_TRACE_API(
             "L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d",
             p_ccb->local_cid, p_cfg->result);
@@ -1014,16 +976,6 @@
   L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x  st: OPEN  evt: %s", p_ccb->local_cid,
                     l2c_csm_get_event_name(event));
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (local_cid == L2CAP_CONNECTIONLESS_CID) {
-    /* check if this event can be processed by UCD */
-    if (l2c_ucd_process_event(p_ccb, event, p_data)) {
-      /* The event is processed by UCD state machine */
-      return;
-    }
-  }
-#endif
-
   switch (event) {
     case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
       L2CAP_TRACE_API(
@@ -1047,7 +999,7 @@
       tempstate = p_ccb->chnl_state;
       tempcfgdone = p_ccb->config_done;
       p_ccb->chnl_state = CST_CONFIG;
-      p_ccb->config_done &= ~CFG_DONE_MASK;
+      p_ccb->config_done &= ~IB_CFG_DONE;
 
       alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
                          l2c_ccb_timer_timeout, p_ccb);
@@ -1156,13 +1108,19 @@
     case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
       credit = (uint16_t*)p_data;
       L2CAP_TRACE_DEBUG("%s Credits received %d", __func__, *credit);
-      if ((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_MAX_CREDIT) {
+      if ((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_CREDIT_MAX) {
         /* we have received credits more than max coc credits,
          * so disconnecting the Le Coc Channel
          */
         l2cble_send_peer_disc_req(p_ccb);
       } else {
         p_ccb->peer_conn_cfg.credits += *credit;
+
+        tL2CA_CREDITS_RECEIVED_CB* cr_cb =
+            p_ccb->p_rcb->api.pL2CA_CreditsReceived_Cb;
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE && (cr_cb)) {
+          (*cr_cb)(p_ccb->local_cid, *credit, p_ccb->peer_conn_cfg.credits);
+        }
         l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
       }
       break;
@@ -1223,11 +1181,6 @@
     case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
       osi_free(p_data);
       break;
-
-    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
-    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
-      osi_free(p_data);
-      break;
   }
 }
 
diff --git a/stack/l2cap/l2c_fcr.cc b/stack/l2cap/l2c_fcr.cc
index 0e5a84a..b20b9c1 100644
--- a/stack/l2cap/l2c_fcr.cc
+++ b/stack/l2cap/l2c_fcr.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2004-2012 Broadcom Corporation
+ *  Copyright 2004-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
  ******************************************************************************/
 
 #include <base/logging.h>
+#include <log/log.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -375,7 +376,7 @@
   CHECK(p_ccb != NULL);
   if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
     /* Check if remote side flowed us off or the transmit window is full */
-    if ((p_ccb->fcrb.remote_busy == true) ||
+    if ((p_ccb->fcrb.remote_busy) ||
         (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >=
          p_ccb->peer_cfg.fcr.tx_win_sz)) {
 #if (L2CAP_ERTM_STATS == TRUE)
@@ -802,8 +803,7 @@
   /* If a window has opened, check if we can send any more packets */
   if ((!fixed_queue_is_empty(p_ccb->fcrb.retrans_q) ||
        !fixed_queue_is_empty(p_ccb->xmit_hold_q)) &&
-      (p_ccb->fcrb.wait_ack == false) &&
-      (l2c_fcr_is_flow_controlled(p_ccb) == false)) {
+      (!p_ccb->fcrb.wait_ack) && (!l2c_fcr_is_flow_controlled(p_ccb))) {
     l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
   }
 }
@@ -841,7 +841,7 @@
       return;
     }
 
-    p_data = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
+    p_data = (BT_HDR*)osi_malloc(BT_HDR_SIZE + sdu_length);
     if (p_data == NULL) {
       osi_free(p_buf);
       return;
@@ -855,8 +855,24 @@
     p_buf->offset += sizeof(sdu_length);
     p_data->offset = 0;
 
-  } else
+  } else {
     p_data = p_ccb->ble_sdu;
+    if (p_buf->len > (p_ccb->ble_sdu_length - p_data->len)) {
+      L2CAP_TRACE_ERROR("%s: buffer length=%d too big. max=%d. Dropped",
+                        __func__, p_data->len,
+                        (p_ccb->ble_sdu_length - p_data->len));
+      android_errorWriteWithInfoLog(0x534e4554, "75298652", -1, NULL, 0);
+      osi_free(p_buf);
+
+      /* Throw away all pending fragments and disconnects */
+      p_ccb->is_first_seg = true;
+      osi_free(p_ccb->ble_sdu);
+      p_ccb->ble_sdu = NULL;
+      p_ccb->ble_sdu_length = 0;
+      l2cu_disconnect_chnl(p_ccb);
+      return;
+    }
+  }
 
   memcpy((uint8_t*)(p_data + 1) + p_data->offset + p_data->len,
          (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
@@ -869,9 +885,6 @@
     p_ccb->ble_sdu_length = 0;
   } else if (p_data->len < p_ccb->ble_sdu_length) {
     p_ccb->is_first_seg = false;
-  } else {
-    L2CAP_TRACE_ERROR("%s Length in the SDU messed up", __func__);
-    // TODO: reset every thing may be???
   }
 
   osi_free(p_buf);
@@ -1453,7 +1466,8 @@
                             p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len);
         packet_ok = false;
       } else {
-        p_fcrb->p_rx_sdu = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
+        p_fcrb->p_rx_sdu = (BT_HDR*)osi_malloc(
+            BT_HDR_SIZE + OBX_BUF_MIN_OFFSET + p_fcrb->rx_sdu_len);
         p_fcrb->p_rx_sdu->offset = OBX_BUF_MIN_OFFSET;
         p_fcrb->p_rx_sdu->len = 0;
       }
@@ -1489,7 +1503,7 @@
     }
   }
 
-  if (packet_ok == false) {
+  if (!packet_ok) {
     osi_free(p_buf);
   } else if (p_buf != NULL) {
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
@@ -1790,77 +1804,45 @@
   return (p_xmit);
 }
 
-/*******************************************************************************
- *
- * Function         l2c_lcc_get_next_xmit_sdu_seg
- *
- * Description      Get the next SDU segment to transmit for LE connection
- *                  oriented channel
- *
- * Returns          pointer to buffer with segment or NULL
- *
- ******************************************************************************/
+/** Get the next PDU to transmit for LE connection oriented channel. Returns
+ * pointer to buffer with PDU. |last_piece_of_sdu| will be set to true, if
+ * returned PDU is last piece from this SDU.*/
 BT_HDR* l2c_lcc_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
-                                      uint16_t max_packet_length) {
-  bool first_seg = false; /* The segment is the first part of data  */
-  bool last_seg = false;  /* The segment is the last part of data  */
-  uint16_t no_of_bytes_to_send = 0;
-  uint16_t sdu_len = 0;
-  BT_HDR *p_buf, *p_xmit;
-  uint8_t* p;
-  uint16_t max_pdu = p_ccb->peer_conn_cfg.mps;
+                                      bool* last_piece_of_sdu) {
+  uint16_t max_pdu = p_ccb->peer_conn_cfg.mps - 4 /* Length and CID */;
 
-  p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+  BT_HDR* p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+  bool first_pdu = (p_buf->event == 0) ? true : false;
 
-  /* We are using the "event" field to tell is if we already started
-   * segmentation */
-  if (p_buf->event == 0) {
-    first_seg = true;
-    sdu_len = p_buf->len;
-    if (p_buf->len <= (max_pdu - L2CAP_LCC_SDU_LENGTH)) {
-      last_seg = true;
-      no_of_bytes_to_send = p_buf->len;
-    } else
-      no_of_bytes_to_send = max_pdu - L2CAP_LCC_SDU_LENGTH;
-  } else if (p_buf->len <= max_pdu) {
-    last_seg = true;
-    no_of_bytes_to_send = p_buf->len;
-  } else {
-    /* Middle Packet */
-    no_of_bytes_to_send = max_pdu;
-  }
+  uint16_t no_of_bytes_to_send = std::min(
+      p_buf->len,
+      (uint16_t)(first_pdu ? (max_pdu - L2CAP_LCC_SDU_LENGTH) : max_pdu));
+  bool last_pdu = (no_of_bytes_to_send == p_buf->len);
 
   /* Get a new buffer and copy the data that can be sent in a PDU */
-  if (first_seg == true)
-    p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_LCC_OFFSET, no_of_bytes_to_send);
-  else
-    p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET, no_of_bytes_to_send);
+  BT_HDR* p_xmit =
+      l2c_fcr_clone_buf(p_buf, first_pdu ? L2CAP_LCC_OFFSET : L2CAP_MIN_OFFSET,
+                        no_of_bytes_to_send);
 
-  if (p_xmit != NULL) {
-    p_buf->event = p_ccb->local_cid;
-    p_xmit->event = p_ccb->local_cid;
+  p_buf->event = p_ccb->local_cid;
+  p_xmit->event = p_ccb->local_cid;
 
-    if (first_seg == true) {
-      p_xmit->offset -= L2CAP_LCC_SDU_LENGTH; /* for writing the SDU length. */
-      p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
-      UINT16_TO_STREAM(p, sdu_len);
-      p_xmit->len += L2CAP_LCC_SDU_LENGTH;
-    }
-
-    p_buf->len -= no_of_bytes_to_send;
-    p_buf->offset += no_of_bytes_to_send;
-
-    /* copy PBF setting */
-    p_xmit->layer_specific = p_buf->layer_specific;
-
-  } else /* Should never happen if the application has configured buffers
-            correctly */
-  {
-    L2CAP_TRACE_ERROR("L2CAP - cannot get buffer, for segmentation");
-    return (NULL);
+  if (first_pdu) {
+    p_xmit->offset -= L2CAP_LCC_SDU_LENGTH; /* for writing the SDU length. */
+    uint8_t* p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
+    UINT16_TO_STREAM(p, p_buf->len);
+    p_xmit->len += L2CAP_LCC_SDU_LENGTH;
   }
 
-  if (last_seg == true) {
+  p_buf->len -= no_of_bytes_to_send;
+  p_buf->offset += no_of_bytes_to_send;
+
+  /* copy PBF setting */
+  p_xmit->layer_specific = p_buf->layer_specific;
+
+  if (last_piece_of_sdu) *last_piece_of_sdu = last_pdu;
+
+  if (last_pdu) {
     p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
     osi_free(p_buf);
   }
@@ -1870,7 +1852,7 @@
   p_xmit->len += L2CAP_PKT_OVERHEAD;
 
   /* Set the pointer to the beginning of the data */
-  p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
+  uint8_t* p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
 
   /* Note: if FCS has to be included then the length is recalculated later */
   UINT16_TO_STREAM(p, p_xmit->len - L2CAP_PKT_OVERHEAD);
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 14eb1e5..421e34d 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -37,14 +37,21 @@
 #define L2CAP_MIN_MTU 48 /* Minimum acceptable MTU is 48 bytes */
 
 /* LE credit based L2CAP connection parameters */
-#define L2CAP_LE_MIN_MTU 23
-#define L2CAP_LE_MIN_MPS 23
-#define L2CAP_LE_MAX_MPS 65533
-#define L2CAP_LE_MIN_CREDIT 0
-#define L2CAP_LE_MAX_CREDIT 65535
-#define L2CAP_LE_DEFAULT_MTU 512
-#define L2CAP_LE_DEFAULT_MPS 23
-#define L2CAP_LE_DEFAULT_CREDIT 1
+constexpr uint16_t L2CAP_LE_MIN_MTU = 23;  // Minimum SDU size
+constexpr uint16_t L2CAP_LE_MIN_MPS = 23;
+constexpr uint16_t L2CAP_LE_MAX_MPS = 65533;
+constexpr uint16_t L2CAP_LE_CREDIT_MAX = 65535;
+
+// This is initial amout of credits we send, and amount to which we increase
+// credits once they fall below threshold
+constexpr uint16_t L2CAP_LE_CREDIT_DEFAULT = 0xffff;
+
+// If credit count on remote fall below this value, we send back credits to
+// reach default value.
+constexpr uint16_t L2CAP_LE_CREDIT_THRESHOLD = 0x0040;
+
+static_assert(L2CAP_LE_CREDIT_THRESHOLD < L2CAP_LE_CREDIT_DEFAULT,
+              "Threshold must be smaller then default credits");
 
 /*
  * Timeout values (in milliseconds).
@@ -147,6 +154,11 @@
                                                     */
 #define L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT 36 /* Peer credit packet */
 
+/* Constants for LE Dynamic PSM values */
+#define LE_DYNAMIC_PSM_START 0x0080
+#define LE_DYNAMIC_PSM_END 0x00FF
+#define LE_DYNAMIC_PSM_RANGE (LE_DYNAMIC_PSM_END - LE_DYNAMIC_PSM_START + 1)
+
 /* Bitmask to skip over Broadcom feature reserved (ID) to avoid sending two
    successive ID values, '0' id only or both */
 #define L2CAP_ADJ_BRCM_ID 0x1
@@ -224,31 +236,11 @@
 #endif
 } tL2C_FCRB;
 
-/* Define a registration control block. Every application (e.g. RFCOMM, SDP,
- * TCS etc) that registers with L2CAP is assigned one of these.
-*/
-#if (L2CAP_UCD_INCLUDED == TRUE)
-#define L2C_UCD_RCB_ID 0x00
-#define L2C_UCD_STATE_UNUSED 0x00
-#define L2C_UCD_STATE_W4_DATA 0x01
-#define L2C_UCD_STATE_W4_RECEPTION 0x02
-#define L2C_UCD_STATE_W4_MTU 0x04
-
-typedef struct {
-  uint8_t state;
-  tL2CAP_UCD_CB_INFO cb_info;
-} tL2C_UCD_REG;
-#endif
-
 typedef struct {
   bool in_use;
   uint16_t psm;
   uint16_t real_psm; /* This may be a dummy RCB for an o/b connection but */
                      /* this is the real PSM that we need to connect to */
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  tL2C_UCD_REG ucd;
-#endif
-
   tL2CAP_APPL_INFO api;
 } tL2C_RCB;
 
@@ -340,10 +332,14 @@
   bool is_flushable; /* true if channel is flushable */
 #endif
 
-#if (L2CAP_NUM_FIXED_CHNLS > 0 || L2CAP_UCD_INCLUDED == TRUE)
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
   uint16_t fixed_chnl_idle_tout; /* Idle timeout to use for the fixed channel */
 #endif
   uint16_t tx_data_len;
+
+  /* Number of LE frames that the remote can send to us (credit count in
+   * remote). Valid only for LE CoC */
+  uint16_t remote_credit_count;
 } tL2C_CCB;
 
 /***********************************************************************
@@ -415,13 +411,6 @@
   list_t* link_xmit_data_q;        /* Link transmit data buffer queue */
 
   uint8_t peer_chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  uint16_t ucd_mtu; /* peer MTU on UCD */
-  fixed_queue_t*
-      ucd_out_sec_pending_q; /* Security pending outgoing UCD packet */
-  fixed_queue_t*
-      ucd_in_sec_pending_q; /* Security pending incoming UCD packet */
-#endif
 
   BT_HDR* p_hcit_rcv_acl;   /* Current HCIT ACL buf being rcvd */
   uint16_t idle_timeout_sv; /* Save current Idle timeout */
@@ -454,6 +443,8 @@
   uint16_t max_interval;
   uint16_t latency;
   uint16_t timeout;
+  uint16_t min_ce_len;
+  uint16_t max_ce_len;
 
 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
   /* each priority group is limited burst transmission */
@@ -530,6 +521,10 @@
 #endif /* (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE) */
 
   uint16_t dyn_psm;
+
+  uint16_t le_dyn_psm; /* Next LE dynamic PSM value to try to assign */
+  bool le_dyn_psm_assigned[LE_DYNAMIC_PSM_RANGE]; /* Table of assigned LE PSM */
+
 } tL2C_CB;
 
 /* Define a structure that contains the information about a connection.
@@ -667,23 +662,6 @@
 extern void l2cu_process_fixed_chnl_resp(tL2C_LCB* p_lcb);
 extern bool l2cu_is_ccb_active(tL2C_CCB* p_ccb);
 
-/* Functions provided by l2c_ucd.cc
- ***********************************
-*/
-#if (L2CAP_UCD_INCLUDED == TRUE)
-void l2c_ucd_delete_sec_pending_q(tL2C_LCB* p_lcb);
-void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB* p_ccb, void* p_data);
-bool l2c_ucd_check_pending_info_req(tL2C_CCB* p_ccb);
-bool l2c_ucd_check_pending_out_sec_q(tL2C_CCB* p_ccb);
-void l2c_ucd_send_pending_out_sec_q(tL2C_CCB* p_ccb);
-void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB* p_ccb);
-bool l2c_ucd_check_pending_in_sec_q(tL2C_CCB* p_ccb);
-void l2c_ucd_send_pending_in_sec_q(tL2C_CCB* p_ccb);
-void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB* p_ccb);
-bool l2c_ucd_check_rx_pkts(tL2C_LCB* p_lcb, BT_HDR* p_msg);
-bool l2c_ucd_process_event(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
-#endif
-
 /* Functions provided for Broadcom Aware
  ***************************************
 */
@@ -696,6 +674,7 @@
 extern tL2C_RCB* l2cu_allocate_rcb(uint16_t psm);
 extern tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t psm);
 extern void l2cu_release_rcb(tL2C_RCB* p_rcb);
+extern void l2cu_release_ble_rcb(tL2C_RCB* p_rcb);
 extern tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm);
 extern tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm);
 
@@ -785,7 +764,7 @@
 extern void l2c_fcr_start_timer(tL2C_CCB* p_ccb);
 extern void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf);
 extern BT_HDR* l2c_lcc_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
-                                             uint16_t max_packet_length);
+                                             bool* last_piece_of_sdu);
 
 /* Configuration negotiation */
 extern uint8_t l2c_fcr_chk_chan_modes(tL2C_CCB* p_ccb);
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index bd4a610..db7e613 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -285,7 +285,8 @@
   tL2C_CCB* p_next_ccb;
   uint8_t event;
 
-  L2CAP_TRACE_DEBUG("l2c_link_sec_comp: %d, 0x%x", status, p_ref_data);
+  L2CAP_TRACE_DEBUG("%s: status=%d, p_ref_data=%p, BD_ADDR=%s", __func__,
+                    status, p_ref_data, p_bda.ToString().c_str());
 
   if (status == BTM_SUCCESS_NO_SECURITY) status = BTM_SUCCESS;
 
@@ -396,19 +397,19 @@
     if (p_lcb->ccb_queue.p_first_ccb != NULL || p_lcb->p_pending_ccb) {
       L2CAP_TRACE_DEBUG(
           "l2c_link_hci_disc_comp: Restarting pending ACL request");
+      /* Release any held buffers */
+      while (!list_is_empty(p_lcb->link_xmit_data_q)) {
+        BT_HDR* p_buf =
+            static_cast<BT_HDR*>(list_front(p_lcb->link_xmit_data_q));
+        list_remove(p_lcb->link_xmit_data_q, p_buf);
+        osi_free(p_buf);
+      }
       transport = p_lcb->transport;
       /* for LE link, always drop and re-open to ensure to get LE remote feature
        */
       if (p_lcb->transport == BT_TRANSPORT_LE) {
         l2cb.is_ble_connecting = false;
         btm_acl_removed(p_lcb->remote_bd_addr, p_lcb->transport);
-        /* Release any held buffers */
-        BT_HDR* p_buf;
-        while (!list_is_empty(p_lcb->link_xmit_data_q)) {
-          p_buf = static_cast<BT_HDR*>(list_front(p_lcb->link_xmit_data_q));
-          list_remove(p_lcb->link_xmit_data_q, p_buf);
-          osi_free(p_buf);
-        }
       } else {
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
         /* If we are going to re-use the LCB without dropping it, release all
@@ -523,7 +524,7 @@
 
       p_ccb = pn;
     }
-    if (p_lcb->link_state == LST_CONNECTING && l2cb.is_ble_connecting == true) {
+    if (p_lcb->link_state == LST_CONNECTING && l2cb.is_ble_connecting) {
       L2CA_CancelBleConnectReq(l2cb.ble_connecting_bda);
     }
     /* Release the LCB */
diff --git a/stack/l2cap/l2c_main.cc b/stack/l2cap/l2c_main.cc
index 19ce0a4..eae77a6 100644
--- a/stack/l2cap/l2c_main.cc
+++ b/stack/l2cap/l2c_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -62,71 +62,23 @@
  ******************************************************************************/
 void l2c_rcv_acl_data(BT_HDR* p_msg) {
   uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
-  uint16_t handle, hci_len;
-  uint8_t pkt_type;
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb = NULL;
-  uint16_t l2cap_len, rcv_cid;
-  uint16_t credit;
 
   /* Extract the handle */
+  uint16_t handle;
   STREAM_TO_UINT16(handle, p);
-  pkt_type = HCID_GET_EVENT(handle);
+  uint8_t pkt_type = HCID_GET_EVENT(handle);
   handle = HCID_GET_HANDLE(handle);
 
   /* Since the HCI Transport is putting segmented packets back together, we */
   /* should never get a valid packet with the type set to "continuation"    */
-  if (pkt_type != L2CAP_PKT_CONTINUE) {
-    /* Find the LCB based on the handle */
-    p_lcb = l2cu_find_lcb_by_handle(handle);
-    if (p_lcb == NULL) {
-      uint8_t cmd_code;
-
-      /* There is a slight possibility (specifically with USB) that we get an */
-      /* L2CAP connection request before we get the HCI connection complete.  */
-      /* So for these types of messages, hold them for up to 2 seconds.       */
-      STREAM_TO_UINT16(hci_len, p);
-      STREAM_TO_UINT16(l2cap_len, p);
-      STREAM_TO_UINT16(rcv_cid, p);
-      STREAM_TO_UINT8(cmd_code, p);
-
-      if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID) &&
-          (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ)) {
-        L2CAP_TRACE_WARNING(
-            "L2CAP - holding ACL for unknown handle:%d ls:%d"
-            "  cid:%d opcode:%d cur count:%d",
-            handle, p_msg->layer_specific, rcv_cid, cmd_code,
-            list_length(l2cb.rcv_pending_q));
-        p_msg->layer_specific = 2;
-        list_append(l2cb.rcv_pending_q, p_msg);
-
-        if (list_length(l2cb.rcv_pending_q) == 1) {
-          alarm_set_on_mloop(l2cb.receive_hold_timer, BT_1SEC_TIMEOUT_MS,
-                             l2c_receive_hold_timer_timeout, NULL);
-        }
-
-        return;
-      } else {
-        L2CAP_TRACE_ERROR(
-            "L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d"
-            " opcode:%d cur count:%d",
-            handle, p_msg->layer_specific, rcv_cid, cmd_code,
-            list_length(l2cb.rcv_pending_q));
-      }
-      osi_free(p_msg);
-      return;
-    }
-  } else {
-    L2CAP_TRACE_WARNING("L2CAP - expected pkt start or complete, got: %d",
-                        pkt_type);
+  if (pkt_type == L2CAP_PKT_CONTINUE) {
+    L2CAP_TRACE_WARNING("L2CAP - received packet continuation");
     osi_free(p_msg);
     return;
   }
 
-  /* Extract the length and update the buffer header */
+  uint16_t hci_len;
   STREAM_TO_UINT16(hci_len, p);
-  p_msg->offset += 4;
-
   if (hci_len < L2CAP_PKT_OVERHEAD) {
     /* Must receive at least the L2CAP length and CID */
     L2CAP_TRACE_WARNING("L2CAP - got incorrect hci header");
@@ -134,22 +86,68 @@
     return;
   }
 
-  /* Extract the length and CID */
+  uint16_t l2cap_len, rcv_cid;
   STREAM_TO_UINT16(l2cap_len, p);
   STREAM_TO_UINT16(rcv_cid, p);
 
+  /* Find the LCB based on the handle */
+  tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
+  if (!p_lcb) {
+    /* There is a slight possibility (specifically with USB) that we get an */
+    /* L2CAP connection request before we get the HCI connection complete.  */
+    /* So for these types of messages, hold them for up to 2 seconds.       */
+    uint8_t cmd_code;
+    STREAM_TO_UINT8(cmd_code, p);
+
+    if ((p_msg->layer_specific != 0) || (rcv_cid != L2CAP_SIGNALLING_CID) ||
+        (cmd_code != L2CAP_CMD_INFO_REQ && cmd_code != L2CAP_CMD_CONN_REQ)) {
+      bool qcom_debug_log =
+          (handle == 3804 && cmd_code == 10 && p_msg->layer_specific == 0);
+
+      if (!qcom_debug_log) {
+        L2CAP_TRACE_ERROR(
+            "L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur "
+            "count:%d",
+            handle, p_msg->layer_specific, rcv_cid, cmd_code,
+            list_length(l2cb.rcv_pending_q));
+      }
+
+      osi_free(p_msg);
+      return;
+    }
+
+    L2CAP_TRACE_WARNING(
+        "L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur "
+        "count:%d",
+        handle, p_msg->layer_specific, rcv_cid, cmd_code,
+        list_length(l2cb.rcv_pending_q));
+    p_msg->layer_specific = 2;
+    list_append(l2cb.rcv_pending_q, p_msg);
+
+    if (list_length(l2cb.rcv_pending_q) == 1) {
+      alarm_set_on_mloop(l2cb.receive_hold_timer, BT_1SEC_TIMEOUT_MS,
+                         l2c_receive_hold_timer_timeout, NULL);
+    }
+    return;
+  }
+
+  /* Update the buffer header */
+  p_msg->offset += 4;
+
   /* for BLE channel, always notify connection when ACL data received on the
    * link */
   if (p_lcb && p_lcb->transport == BT_TRANSPORT_LE &&
-      p_lcb->link_state != LST_DISCONNECTING)
+      p_lcb->link_state != LST_DISCONNECTING) {
     /* only process fixed channel data as channel open indication when link is
      * not in disconnecting mode */
     l2cble_notify_le_connection(p_lcb->remote_bd_addr);
+  }
 
   /* Find the CCB for this CID */
+  tL2C_CCB* p_ccb = NULL;
   if (rcv_cid >= L2CAP_BASE_APPL_CID) {
     p_ccb = l2cu_find_ccb_by_cid(p_lcb, rcv_cid);
-    if (p_ccb == NULL) {
+    if (!p_ccb) {
       L2CAP_TRACE_WARNING("L2CAP - unknown CID: 0x%04x", rcv_cid);
       osi_free(p_msg);
       return;
@@ -162,7 +160,6 @@
   if (l2cap_len != p_msg->len) {
     L2CAP_TRACE_WARNING("L2CAP - bad length in pkt. Exp: %d  Act: %d",
                         l2cap_len, p_msg->len);
-
     osi_free(p_msg);
     return;
   }
@@ -171,67 +168,78 @@
   if (rcv_cid == L2CAP_SIGNALLING_CID) {
     process_l2cap_cmd(p_lcb, p, l2cap_len);
     osi_free(p_msg);
-  } else if (rcv_cid == L2CAP_CONNECTIONLESS_CID) {
-    /* process_connectionless_data (p_lcb); */
+    return;
+  }
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-    /* if it is not broadcast, check UCD registration */
-    if (l2c_ucd_check_rx_pkts(p_lcb, p_msg)) {
-      /* nothing to do */
-    } else
-#endif
-      osi_free(p_msg);
-  } else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) {
+  if (rcv_cid == L2CAP_CONNECTIONLESS_CID) {
+    /* process_connectionless_data (p_lcb); */
+    osi_free(p_msg);
+    return;
+  }
+
+  if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) {
     l2cble_process_sig_cmd(p_lcb, p, l2cap_len);
     osi_free(p_msg);
+    return;
   }
-#if (L2CAP_NUM_FIXED_CHNLS > 0)
-  else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) &&
-           (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
-           (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL]
-                .pL2CA_FixedData_Cb != NULL)) {
-    /* If no CCB for this channel, allocate one */
-    if (p_lcb &&
-        /* only process fixed channel data when link is open or wait for data
-           indication */
-        (p_lcb->link_state != LST_DISCONNECTING) &&
-        l2cu_initialize_fixed_ccb(
-            p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL]
-                                 .fixed_chnl_opts)) {
-      p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
 
-      if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
-        l2c_fcr_proc_pdu(p_ccb, p_msg);
-      else
-        (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(
-            rcv_cid, p_lcb->remote_bd_addr, p_msg);
-    } else
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+  if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) &&
+      (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
+      (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb !=
+       NULL)) {
+    /* only process fixed channel data when link is open or wait for data
+     * indication */
+    if (!p_lcb || p_lcb->link_state == LST_DISCONNECTING ||
+        !l2cu_initialize_fixed_ccb(
+            p_lcb, rcv_cid,
+            &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL]
+                 .fixed_chnl_opts)) {
       osi_free(p_msg);
+      return;
+    }
+
+    /* If no CCB for this channel, allocate one */
+    p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
+
+    if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+      l2c_fcr_proc_pdu(p_ccb, p_msg);
+    else
+      (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(
+          rcv_cid, p_lcb->remote_bd_addr, p_msg);
+    return;
   }
 #endif
 
-  else {
-    if (p_ccb == NULL)
-      osi_free(p_msg);
+  if (!p_ccb) {
+    osi_free(p_msg);
+    return;
+  }
+
+  if (p_lcb->transport == BT_TRANSPORT_LE) {
+    l2c_lcc_proc_pdu(p_ccb, p_msg);
+
+    /* The remote device has one less credit left */
+    --p_ccb->remote_credit_count;
+
+    /* If the credits left on the remote device are getting low, send some */
+    if (p_ccb->remote_credit_count <= L2CAP_LE_CREDIT_THRESHOLD) {
+      uint16_t credits = L2CAP_LE_CREDIT_DEFAULT - p_ccb->remote_credit_count;
+      p_ccb->remote_credit_count = L2CAP_LE_CREDIT_DEFAULT;
+
+      /* Return back credits */
+      l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credits);
+    }
+  } else {
+    /* Basic mode packets go straight to the state machine */
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+      l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
     else {
-      if (p_lcb->transport == BT_TRANSPORT_LE) {
-        l2c_lcc_proc_pdu(p_ccb, p_msg);
-        // Got a pkt, valid send out credits to the peer device
-        credit = L2CAP_LE_DEFAULT_CREDIT;
-        l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credit);
-      } else {
-        /* Basic mode packets go straight to the state machine */
-        if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
-          l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
-        else {
-          /* eRTM or streaming mode, so we need to validate states first */
-          if ((p_ccb->chnl_state == CST_OPEN) ||
-              (p_ccb->chnl_state == CST_CONFIG))
-            l2c_fcr_proc_pdu(p_ccb, p_msg);
-          else
-            osi_free(p_msg);
-        }
-      }
+      /* eRTM or streaming mode, so we need to validate states first */
+      if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
+        l2c_fcr_proc_pdu(p_ccb, p_msg);
+      else
+        osi_free(p_msg);
     }
   }
 }
@@ -247,38 +255,27 @@
  *
  ******************************************************************************/
 static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
-  uint8_t *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start;
-  uint8_t cmd_code, cfg_code, cfg_len, id;
   tL2C_CONN_INFO con_info;
-  tL2CAP_CFG_INFO cfg_info;
-  uint16_t rej_reason, rej_mtu, lcid, rcid, info_type;
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-  bool cfg_rej, pkt_size_rej = false;
-  uint16_t cfg_rej_len, cmd_len;
-  uint16_t result;
-  tL2C_CONN_INFO ci;
 
   /* if l2cap command received in CID 1 on top of an LE link, ignore this
    * command */
   if (p_lcb->transport == BT_TRANSPORT_LE) return;
 
   /* Reject the packet if it exceeds the default Signalling Channel MTU */
+  bool pkt_size_rej = false;
   if (pkt_len > L2CAP_DEFAULT_MTU) {
     /* Core Spec requires a single response to the first command found in a
-    *multi-command
-    ** L2cap packet.  If only responses in the packet, then it will be ignored.
-    ** Here we simply mark the bad packet and decide which cmd ID to reject
-    *later
-    */
+     * multi-command L2cap packet.  If only responses in the packet, then it
+     * will be ignored. Here we simply mark the bad packet and decide which cmd
+     * ID to reject later */
     pkt_size_rej = true;
-    L2CAP_TRACE_ERROR("L2CAP SIG MTU Pkt Len Exceeded (672) -> pkt_len: %d",
-                      pkt_len);
+    L2CAP_TRACE_ERROR("L2CAP SIG MTU pkt_len=%d Exceeded 672", pkt_len);
   }
 
-  p_next_cmd = p;
-  p_pkt_end = p + pkt_len;
+  uint8_t* p_next_cmd = p;
+  uint8_t* p_pkt_end = p + pkt_len;
 
+  tL2CAP_CFG_INFO cfg_info;
   memset(&cfg_info, 0, sizeof(cfg_info));
 
   /* An L2CAP packet may contain multiple commands */
@@ -287,6 +284,8 @@
     p = p_next_cmd;
     if (p > (p_pkt_end - 4)) break;
 
+    uint8_t cmd_code, id;
+    uint16_t cmd_len;
     STREAM_TO_UINT8(cmd_code, p);
     STREAM_TO_UINT8(id, p);
     STREAM_TO_UINT16(cmd_len, p);
@@ -307,7 +306,7 @@
 
     L2CAP_TRACE_DEBUG("cmd_code: %d, id:%d, cmd_len:%d", cmd_code, id, cmd_len);
 
-    /* Bad L2CAP packet length, look or cmd to reject */
+    /* Bad L2CAP packet length, look for cmd to reject */
     if (pkt_size_rej) {
       /* If command found rejected it and we're done, otherwise keep looking */
       if (l2c_is_cmd_rejected(cmd_code, id, p_lcb))
@@ -318,30 +317,22 @@
 
     switch (cmd_code) {
       case L2CAP_CMD_REJECT:
-        if (p + 2 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+        uint16_t rej_reason;
+        if (p + 2 > p_next_cmd) return;
         STREAM_TO_UINT16(rej_reason, p);
         if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED) {
-          if (p + 2 > p_next_cmd) {
-            android_errorWriteLog(0x534e4554, "74202041");
-            return;
-          }
+          uint16_t rej_mtu;
+          if (p + 2 > p_next_cmd) return;
           STREAM_TO_UINT16(rej_mtu, p);
           /* What to do with the MTU reject ? We have negotiated an MTU. For now
+           * we will ignore it and let a higher protocol timeout take care of it
            */
-          /* we will ignore it and let a higher protocol timeout take care of it
-           */
-
           L2CAP_TRACE_WARNING("L2CAP - MTU rej Handle: %d MTU: %d",
                               p_lcb->handle, rej_mtu);
         }
         if (rej_reason == L2CAP_CMD_REJ_INVALID_CID) {
-          if (p + 4 > p_next_cmd) {
-            android_errorWriteLog(0x534e4554, "74202041");
-            return;
-          }
+          uint16_t lcid, rcid;
+          if (p + 4 > p_next_cmd) return;
           STREAM_TO_UINT16(rcid, p);
           STREAM_TO_UINT16(lcid, p);
 
@@ -350,7 +341,7 @@
               rcid);
 
           /* Remote CID invalid. Treat as a disconnect */
-          p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+          tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
           if ((p_ccb != NULL) && (p_ccb->remote_cid == rcid)) {
             /* Fake link disconnect - no reply is generated */
             l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
@@ -363,26 +354,25 @@
           alarm_cancel(p_lcb->info_resp_timer);
 
           p_lcb->w4_info_rsp = false;
+          tL2C_CONN_INFO ci;
           ci.status = HCI_SUCCESS;
           ci.bd_addr = p_lcb->remote_bd_addr;
 
           /* For all channels, send the event through their FSMs */
-          for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+          for (tL2C_CCB* p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
                p_ccb = p_ccb->p_next_ccb) {
             l2c_csm_execute(p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
           }
         }
         break;
 
-      case L2CAP_CMD_CONN_REQ:
-        if (p + 4 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+      case L2CAP_CMD_CONN_REQ: {
+        uint16_t rcid;
+        if (p + 4 > p_next_cmd) return;
         STREAM_TO_UINT16(con_info.psm, p);
         STREAM_TO_UINT16(rcid, p);
-        p_rcb = l2cu_find_rcb_by_psm(con_info.psm);
-        if (p_rcb == NULL) {
+        tL2C_RCB* p_rcb = l2cu_find_rcb_by_psm(con_info.psm);
+        if (!p_rcb) {
           L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for unknown PSM: %d",
                               con_info.psm);
           l2cu_reject_connection(p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
@@ -396,8 +386,8 @@
             break;
           }
         }
-        p_ccb = l2cu_allocate_ccb(p_lcb, 0);
-        if (p_ccb == NULL) {
+        tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+        if (!p_ccb) {
           L2CAP_TRACE_ERROR("L2CAP - unable to allocate CCB");
           l2cu_reject_connection(p_lcb, rcid, id, L2CAP_CONN_NO_RESOURCES);
           break;
@@ -408,19 +398,18 @@
 
         l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
         break;
+      }
 
-      case L2CAP_CMD_CONN_RSP:
-        if (p + 8 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+      case L2CAP_CMD_CONN_RSP: {
+        uint16_t lcid;
+        if (p + 8 > p_next_cmd) return;
         STREAM_TO_UINT16(con_info.remote_cid, p);
         STREAM_TO_UINT16(lcid, p);
         STREAM_TO_UINT16(con_info.l2cap_result, p);
         STREAM_TO_UINT16(con_info.l2cap_status, p);
 
-        p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
-        if (p_ccb == NULL) {
+        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+        if (!p_ccb) {
           L2CAP_TRACE_WARNING("L2CAP - no CCB for conn rsp, LCID: %d RCID: %d",
                               lcid, con_info.remote_cid);
           break;
@@ -439,58 +428,46 @@
           l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
 
         break;
+      }
 
-      case L2CAP_CMD_CONFIG_REQ:
-        p_cfg_end = p + cmd_len;
-        cfg_rej = false;
-        cfg_rej_len = 0;
+      case L2CAP_CMD_CONFIG_REQ: {
+        uint8_t* p_cfg_end = p + cmd_len;
+        bool cfg_rej = false;
+        uint16_t cfg_rej_len = 0;
 
-        if (p + 4 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+        uint16_t lcid;
+        if (p + 4 > p_next_cmd) return;
         STREAM_TO_UINT16(lcid, p);
         STREAM_TO_UINT16(cfg_info.flags, p);
 
-        p_cfg_start = p;
+        uint8_t* p_cfg_start = p;
 
         cfg_info.flush_to_present = cfg_info.mtu_present =
             cfg_info.qos_present = cfg_info.fcr_present = cfg_info.fcs_present =
                 false;
 
         while (p < p_cfg_end) {
-          if (p + 2 > p_next_cmd) {
-            android_errorWriteLog(0x534e4554, "74202041");
-            return;
-          }
+          uint8_t cfg_code, cfg_len;
+          if (p + 2 > p_next_cmd) return;
           STREAM_TO_UINT8(cfg_code, p);
           STREAM_TO_UINT8(cfg_len, p);
 
           switch (cfg_code & 0x7F) {
             case L2CAP_CFG_TYPE_MTU:
               cfg_info.mtu_present = true;
-              if (p + 2 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 > p_next_cmd) return;
               STREAM_TO_UINT16(cfg_info.mtu, p);
               break;
 
             case L2CAP_CFG_TYPE_FLUSH_TOUT:
               cfg_info.flush_to_present = true;
-              if (p + 2 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 > p_next_cmd) return;
               STREAM_TO_UINT16(cfg_info.flush_to, p);
               break;
 
             case L2CAP_CFG_TYPE_QOS:
               cfg_info.qos_present = true;
-              if (p + 2 + 5 * 4 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 + 5 * 4 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.qos.qos_flags, p);
               STREAM_TO_UINT8(cfg_info.qos.service_type, p);
               STREAM_TO_UINT32(cfg_info.qos.token_rate, p);
@@ -502,10 +479,7 @@
 
             case L2CAP_CFG_TYPE_FCR:
               cfg_info.fcr_present = true;
-              if (p + 3 + 3 * 2 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 3 + 3 * 2 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.fcr.mode, p);
               STREAM_TO_UINT8(cfg_info.fcr.tx_win_sz, p);
               STREAM_TO_UINT8(cfg_info.fcr.max_transmit, p);
@@ -516,19 +490,13 @@
 
             case L2CAP_CFG_TYPE_FCS:
               cfg_info.fcs_present = true;
-              if (p + 1 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 1 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.fcs, p);
               break;
 
             case L2CAP_CFG_TYPE_EXT_FLOW:
               cfg_info.ext_flow_spec_present = true;
-              if (p + 2 + 2 + 3 * 4 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 + 2 + 3 * 4 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.ext_flow_spec.id, p);
               STREAM_TO_UINT8(cfg_info.ext_flow_spec.stype, p);
               STREAM_TO_UINT16(cfg_info.ext_flow_spec.max_sdu_size, p);
@@ -540,10 +508,7 @@
             default:
               /* sanity check option length */
               if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len) {
-                if (p + cfg_len > p_next_cmd) {
-                  android_errorWriteLog(0x534e4554, "79488381");
-                  return;
-                }
+                if (p + cfg_len > p_next_cmd) return;
                 p += cfg_len;
                 if ((cfg_code & 0x80) == 0) {
                   cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
@@ -559,8 +524,8 @@
           }
         }
 
-        p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
-        if (p_ccb != NULL) {
+        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+        if (p_ccb) {
           p_ccb->remote_id = id;
           if (cfg_rej) {
             l2cu_send_peer_config_rej(
@@ -574,13 +539,12 @@
           l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0);
         }
         break;
+      }
 
-      case L2CAP_CMD_CONFIG_RSP:
-        p_cfg_end = p + cmd_len;
-        if (p + 6 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+      case L2CAP_CMD_CONFIG_RSP: {
+        uint8_t* p_cfg_end = p + cmd_len;
+        uint16_t lcid;
+        if (p + 6 > p_next_cmd) return;
         STREAM_TO_UINT16(lcid, p);
         STREAM_TO_UINT16(cfg_info.flags, p);
         STREAM_TO_UINT16(cfg_info.result, p);
@@ -590,38 +554,27 @@
                 false;
 
         while (p < p_cfg_end) {
-          if (p + 2 > p_next_cmd) {
-            android_errorWriteLog(0x534e4554, "74202041");
-            return;
-          }
+          uint8_t cfg_code, cfg_len;
+          if (p + 2 > p_next_cmd) return;
           STREAM_TO_UINT8(cfg_code, p);
           STREAM_TO_UINT8(cfg_len, p);
 
           switch (cfg_code & 0x7F) {
             case L2CAP_CFG_TYPE_MTU:
               cfg_info.mtu_present = true;
-              if (p + 2 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 > p_next_cmd) return;
               STREAM_TO_UINT16(cfg_info.mtu, p);
               break;
 
             case L2CAP_CFG_TYPE_FLUSH_TOUT:
               cfg_info.flush_to_present = true;
-              if (p + 2 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 > p_next_cmd) return;
               STREAM_TO_UINT16(cfg_info.flush_to, p);
               break;
 
             case L2CAP_CFG_TYPE_QOS:
               cfg_info.qos_present = true;
-              if (p + 2 + 5 * 4 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 + 5 * 4 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.qos.qos_flags, p);
               STREAM_TO_UINT8(cfg_info.qos.service_type, p);
               STREAM_TO_UINT32(cfg_info.qos.token_rate, p);
@@ -633,10 +586,7 @@
 
             case L2CAP_CFG_TYPE_FCR:
               cfg_info.fcr_present = true;
-              if (p + 3 + 3 * 2 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 3 + 3 * 2 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.fcr.mode, p);
               STREAM_TO_UINT8(cfg_info.fcr.tx_win_sz, p);
               STREAM_TO_UINT8(cfg_info.fcr.max_transmit, p);
@@ -647,19 +597,13 @@
 
             case L2CAP_CFG_TYPE_FCS:
               cfg_info.fcs_present = true;
-              if (p + 1 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 1 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.fcs, p);
               break;
 
             case L2CAP_CFG_TYPE_EXT_FLOW:
               cfg_info.ext_flow_spec_present = true;
-              if (p + 2 + 2 + 3 * 4 > p_next_cmd) {
-                android_errorWriteLog(0x534e4554, "74202041");
-                return;
-              }
+              if (p + 2 + 2 + 3 * 4 > p_next_cmd) return;
               STREAM_TO_UINT8(cfg_info.ext_flow_spec.id, p);
               STREAM_TO_UINT8(cfg_info.ext_flow_spec.stype, p);
               STREAM_TO_UINT16(cfg_info.ext_flow_spec.max_sdu_size, p);
@@ -670,8 +614,8 @@
           }
         }
 
-        p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
-        if (p_ccb != NULL) {
+        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+        if (p_ccb) {
           if (p_ccb->local_id != id) {
             L2CAP_TRACE_WARNING("L2CAP - cfg rsp - bad ID. Exp: %d Got: %d",
                                 p_ccb->local_id, id);
@@ -687,17 +631,16 @@
                               lcid);
         }
         break;
+      }
 
-      case L2CAP_CMD_DISC_REQ:
-        if (p + 4 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+      case L2CAP_CMD_DISC_REQ: {
+        uint16_t lcid, rcid;
+        if (p + 4 > p_next_cmd) return;
         STREAM_TO_UINT16(lcid, p);
         STREAM_TO_UINT16(rcid, p);
 
-        p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
-        if (p_ccb != NULL) {
+        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+        if (p_ccb) {
           if (p_ccb->remote_cid == rcid) {
             p_ccb->remote_id = id;
             l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, &con_info);
@@ -706,22 +649,22 @@
           l2cu_send_peer_disc_rsp(p_lcb, id, lcid, rcid);
 
         break;
+      }
 
-      case L2CAP_CMD_DISC_RSP:
-        if (p + 4 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+      case L2CAP_CMD_DISC_RSP: {
+        uint16_t lcid, rcid;
+        if (p + 4 > p_next_cmd) return;
         STREAM_TO_UINT16(rcid, p);
         STREAM_TO_UINT16(lcid, p);
 
-        p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
-        if (p_ccb != NULL) {
+        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+        if (p_ccb) {
           if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id)) {
             l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, &con_info);
           }
         }
         break;
+      }
 
       case L2CAP_CMD_ECHO_REQ:
         l2cu_send_peer_echo_rsp(p_lcb, id, p, cmd_len);
@@ -738,14 +681,13 @@
         }
         break;
 
-      case L2CAP_CMD_INFO_REQ:
-        if (p + 2 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+      case L2CAP_CMD_INFO_REQ: {
+        uint16_t info_type;
+        if (p + 2 > p_next_cmd) return;
         STREAM_TO_UINT16(info_type, p);
         l2cu_send_peer_info_rsp(p_lcb, id, info_type);
         break;
+      }
 
       case L2CAP_CMD_INFO_RSP:
         /* Stop the link connect timer if sent before L2CAP connection is up */
@@ -754,10 +696,8 @@
           p_lcb->w4_info_rsp = false;
         }
 
-        if (p + 4 > p_next_cmd) {
-          android_errorWriteLog(0x534e4554, "74202041");
-          return;
-        }
+        uint16_t info_type, result;
+        if (p + 4 > p_next_cmd) return;
         STREAM_TO_UINT16(info_type, p);
         STREAM_TO_UINT16(result, p);
 
@@ -765,10 +705,7 @@
 
         if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) &&
             (result == L2CAP_INFO_RESP_RESULT_SUCCESS)) {
-          if (p + 4 > p_next_cmd) {
-            android_errorWriteLog(0x534e4554, "74202041");
-            return;
-          }
+          if (p + 4 > p_next_cmd) return;
           STREAM_TO_UINT32(p_lcb->peer_ext_fea, p);
 
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
@@ -790,17 +727,10 @@
           l2cu_process_fixed_chnl_resp(p_lcb);
         }
 #endif
-#if (L2CAP_UCD_INCLUDED == TRUE)
-        else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) {
-          if (result == L2CAP_INFO_RESP_RESULT_SUCCESS) {
-            STREAM_TO_UINT16(p_lcb->ucd_mtu, p);
-          }
-        }
-#endif
-
+        tL2C_CONN_INFO ci;
         ci.status = HCI_SUCCESS;
         ci.bd_addr = p_lcb->remote_bd_addr;
-        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+        for (tL2C_CCB* p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
              p_ccb = p_ccb->p_next_ccb) {
           l2c_csm_execute(p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
         }
@@ -872,6 +802,9 @@
   /* the psm is increased by 2 before being used */
   l2cb.dyn_psm = 0xFFF;
 
+  /* the LE PSM is increased by 1 before being used */
+  l2cb.le_dyn_psm = LE_DYNAMIC_PSM_START - 1;
+
   /* Put all the channel control blocks on the free queue */
   for (xx = 0; xx < MAX_L2CAP_CHANNELS - 1; xx++) {
     l2cb.ccb_pool[xx].p_next_ccb = &l2cb.ccb_pool[xx + 1];
@@ -961,19 +894,18 @@
  *
  ******************************************************************************/
 uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
-  tL2C_CCB* p_ccb;
 
   /* Find the channel control block. We don't know the link it is on. */
-  p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
-  if (p_ccb == NULL) {
+  tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+  if (!p_ccb) {
     L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
     osi_free(p_data);
     return (L2CAP_DW_FAILED);
   }
 
-#ifndef TESTER /* Tester may send any amount of data. otherwise sending \
-                  message                                               \
-                  bigger than mtu size of peer is a violation of protocol */
+#ifndef TESTER
+  /* Tester may send any amount of data. otherwise sending message bigger than
+   * mtu size of peer is a violation of protocol */
   uint16_t mtu;
 
   if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
diff --git a/stack/l2cap/l2c_ucd.cc b/stack/l2cap/l2c_ucd.cc
deleted file mode 100644
index 2216368..0000000
--- a/stack/l2cap/l2c_ucd.cc
+++ /dev/null
@@ -1,1110 +0,0 @@
-/******************************************************************************
- *
- *  Copyright (C) 1999-2012 Broadcom Corporation
- *
- *  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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- *  This file contains the L2CAP UCD code
- *
- ******************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "bt_common.h"
-#include "bt_types.h"
-#include "btm_api.h"
-#include "btm_int.h"
-#include "btu.h"
-#include "hcidefs.h"
-#include "hcimsgs.h"
-#include "l2c_int.h"
-#include "l2cdefs.h"
-
-#if (L2CAP_UCD_INCLUDED == TRUE)
-
-static bool l2c_ucd_connect(const RawAddress& rem_bda);
-
-/*******************************************************************************
- *
- * Function         l2c_ucd_discover_cback
- *
- * Description      UCD Discover callback
- *
- * Returns          void
- *
- ******************************************************************************/
-static void l2c_ucd_discover_cback(const RawAddress& rem_bda, uint8_t info_type,
-                                   uint32_t data) {
-  tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
-  uint16_t xx;
-
-  L2CAP_TRACE_DEBUG("L2CAP - l2c_ucd_discover_cback");
-
-  for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
-    if (p_rcb->in_use) {
-      /* if this application is waiting UCD reception info */
-      if ((info_type == L2CAP_UCD_INFO_TYPE_RECEPTION) &&
-          (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION)) {
-        p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(rem_bda, info_type, data);
-        p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_RECEPTION);
-      }
-
-      /* if this application is waiting UCD MTU info */
-      if ((info_type == L2CAP_UCD_INFO_TYPE_MTU) &&
-          (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU)) {
-        p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(rem_bda, info_type, data);
-        p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_MTU);
-      }
-    }
-  }
-}
-
-/*******************************************************************************
- *
- * Function         l2c_ucd_data_ind_cback
- *
- * Description      UCD Data callback
- *
- * Returns          void
- *
- ******************************************************************************/
-static void l2c_ucd_data_ind_cback(const RawAddress& rem_bda, BT_HDR* p_buf) {
-  uint8_t* p;
-  uint16_t psm;
-  tL2C_RCB* p_rcb;
-
-  L2CAP_TRACE_DEBUG("L2CAP - l2c_ucd_data_ind_cback");
-
-  p = (uint8_t*)(p_buf + 1) + p_buf->offset;
-  STREAM_TO_UINT16(psm, p)
-
-  p_buf->offset += L2CAP_UCD_OVERHEAD;
-  p_buf->len -= L2CAP_UCD_OVERHEAD;
-
-  p_rcb = l2cu_find_rcb_by_psm(psm);
-  if (p_rcb == NULL) {
-    L2CAP_TRACE_ERROR("L2CAP - no RCB for l2c_ucd_data_ind_cback, PSM: 0x%04x",
-                      psm);
-    osi_free(p_buf);
-  } else {
-    p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(rem_bda, p_buf);
-  }
-}
-
-/*******************************************************************************
- *
- * Function         l2c_ucd_congestion_status_cback
- *
- * Description      UCD Congestion Status callback
- *
- * Returns          void
- *
- ******************************************************************************/
-static void l2c_ucd_congestion_status_cback(const RawAddress& rem_bda,
-                                            bool is_congested) {
-  tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
-  uint16_t xx;
-
-  L2CAP_TRACE_DEBUG("L2CAP - l2c_ucd_congestion_status_cback");
-
-  for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
-    if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED)) {
-      if (p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb) {
-        L2CAP_TRACE_DEBUG(
-            "L2CAP - Calling UCDCongestionStatus_Cb (%d), PSM=0x%04x, BDA: "
-            "%08x%04x,",
-            is_congested, p_rcb->psm, (rem_bda[0] << 24) + (rem_bda[1] << 16) +
-                                          (rem_bda[2] << 8) + rem_bda[3],
-            (rem_bda[4] << 8) + rem_bda[5]);
-
-        p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb(rem_bda,
-                                                          is_congested);
-      }
-    }
-  }
-}
-
-/*******************************************************************************
- *
- * Function         l2c_ucd_disconnect_ind_cback
- *
- * Description      UCD disconnect callback (Prevent to access null pointer)
- *
- * Returns          void
- *
- ******************************************************************************/
-static void l2c_ucd_disconnect_ind_cback(uint16_t cid, bool result) {
-  /* do nothing */
-}
-
-/*******************************************************************************
- *
- * Function         l2c_ucd_config_ind_cback
- *
- * Description      UCD config callback (This prevent to access null pointer)
- *
- * Returns          void
- *
- ******************************************************************************/
-static void l2c_ucd_config_ind_cback(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
-  /* do nothing */
-}
-
-/*******************************************************************************
- *
- * Function         l2c_ucd_config_cfm_cback
- *
- * Description      UCD config callback (This prevent to access null pointer)
- *
- * Returns          void
- *
- ******************************************************************************/
-static void l2c_ucd_config_cfm_cback(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
-  /* do nothing */
-}
-
-/*******************************************************************************
- *
- *  Function        L2CA_UcdRegister
- *
- *  Description     Register PSM on UCD.
- *
- *  Parameters:     tL2CAP_UCD_CB_INFO
- *
- *  Return value:   true if successs
- *
- ******************************************************************************/
-bool L2CA_UcdRegister(uint16_t psm, tL2CAP_UCD_CB_INFO* p_cb_info) {
-  tL2C_RCB* p_rcb;
-
-  L2CAP_TRACE_API("L2CA_UcdRegister()  PSM: 0x%04x", psm);
-
-  if ((!p_cb_info->pL2CA_UCD_Discover_Cb) || (!p_cb_info->pL2CA_UCD_Data_Cb)) {
-    L2CAP_TRACE_ERROR("L2CAP - no callback registering PSM(0x%04x) on UCD",
-                      psm);
-    return (false);
-  }
-
-  p_rcb = l2cu_find_rcb_by_psm(psm);
-  if (p_rcb == NULL) {
-    L2CAP_TRACE_ERROR("L2CAP - no RCB for L2CA_UcdRegister, PSM: 0x%04x", psm);
-    return (false);
-  }
-
-  p_rcb->ucd.state = L2C_UCD_STATE_W4_DATA;
-  p_rcb->ucd.cb_info = *p_cb_info;
-
-  /* check if master rcb is created for UCD */
-  p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID);
-  if (p_rcb == NULL) {
-    p_rcb = l2cu_allocate_rcb(L2C_UCD_RCB_ID);
-    if (p_rcb == NULL) {
-      L2CAP_TRACE_ERROR("L2CAP - no RCB available for L2CA_UcdRegister");
-      return (false);
-    } else {
-      /* these callback functions will forward data to each UCD application */
-      p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb = l2c_ucd_discover_cback;
-      p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb = l2c_ucd_data_ind_cback;
-      p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb =
-          l2c_ucd_congestion_status_cback;
-
-      memset(&p_rcb->api, 0, sizeof(tL2CAP_APPL_INFO));
-      p_rcb->api.pL2CA_DisconnectInd_Cb = l2c_ucd_disconnect_ind_cback;
-
-      /* This will make L2CAP check UCD congestion callback */
-      p_rcb->api.pL2CA_CongestionStatus_Cb = NULL;
-
-      /* do nothing but prevent crash */
-      p_rcb->api.pL2CA_ConfigInd_Cb = l2c_ucd_config_ind_cback;
-      p_rcb->api.pL2CA_ConfigCfm_Cb = l2c_ucd_config_cfm_cback;
-    }
-  }
-
-  return (true);
-}
-
-/*******************************************************************************
- *
- *  Function        L2CA_UcdDeregister
- *
- *  Description     Deregister PSM on UCD.
- *
- *  Parameters:     PSM
- *
- *  Return value:   true if successs
- *
- ******************************************************************************/
-bool L2CA_UcdDeregister(uint16_t psm) {
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-  uint16_t xx;
-
-  L2CAP_TRACE_API("L2CA_UcdDeregister()  PSM: 0x%04x", psm);
-
-  p_rcb = l2cu_find_rcb_by_psm(psm);
-  if (p_rcb == NULL) {
-    L2CAP_TRACE_ERROR("L2CAP - no RCB for L2CA_UcdDeregister, PSM: 0x%04x",
-                      psm);
-    return (false);
-  }
-
-  p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
-
-  /* check this was the last UCD registration */
-  p_rcb = &l2cb.rcb_pool[0];
-
-  for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
-    if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED))
-      return (true);
-  }
-
-  /* delete master rcb for UCD */
-  p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID);
-  if (p_rcb != NULL) {
-    l2cu_release_rcb(p_rcb);
-  }
-
-  /* delete CCB for UCD */
-  p_ccb = l2cb.ccb_pool;
-  for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) {
-    if ((p_ccb->in_use) && (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID)) {
-      l2cu_release_ccb(p_ccb);
-    }
-    p_ccb++;
-  }
-
-  return (true);
-}
-
-/*******************************************************************************
- *
- *  Function        L2CA_UcdDiscover
- *
- *  Description     Discover UCD of remote device.
- *
- *  Parameters:     PSM
- *                  BD_ADDR of remote device
- *                  info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
- *                              L2CAP_UCD_INFO_TYPE_MTU
- *
- *
- *  Return value:   true if successs
- *
- ******************************************************************************/
-bool L2CA_UcdDiscover(uint16_t psm, const RawAddress& rem_bda,
-                      uint8_t info_type) {
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-
-  L2CAP_TRACE_API(
-      "L2CA_UcdDiscover()  PSM: 0x%04x  BDA: %08x%04x, InfoType=0x%02x", psm,
-      (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
-      (rem_bda[4] << 8) + rem_bda[5], info_type);
-
-  /* Fail if the PSM is not registered */
-  if (((p_rcb = l2cu_find_rcb_by_psm(psm)) == NULL) ||
-      (p_rcb->ucd.state == L2C_UCD_STATE_UNUSED)) {
-    L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_UcdDiscover, PSM: 0x%04x",
-                        psm);
-    return (false);
-  }
-
-  /* First, see if we already have a link to the remote */
-  /* then find the channel control block for UCD. */
-  if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
-       NULL) ||
-      ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
-       NULL)) {
-    if (l2c_ucd_connect(rem_bda) == false) {
-      return (false);
-    }
-  }
-
-  /* set waiting flags in rcb */
-
-  if (info_type & L2CAP_UCD_INFO_TYPE_RECEPTION)
-    p_rcb->ucd.state |= L2C_UCD_STATE_W4_RECEPTION;
-
-  if (info_type & L2CAP_UCD_INFO_TYPE_MTU)
-    p_rcb->ucd.state |= L2C_UCD_STATE_W4_MTU;
-
-  /* if link is already established */
-  if ((p_lcb) && (p_lcb->link_state == LST_CONNECTED)) {
-    if (!p_ccb) {
-      p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID);
-    }
-    l2c_ucd_check_pending_info_req(p_ccb);
-  }
-  return (true);
-}
-
-/*******************************************************************************
- *
- *  Function        L2CA_UcdDataWrite
- *
- *  Description     Send UCD to remote device
- *
- *  Parameters:     PSM
- *                  BD Address of remote
- *                  Pointer to buffer of type BT_HDR
- *                  flags : L2CAP_FLUSHABLE_CH_BASED
- *                          L2CAP_FLUSHABLE_PKT
- *                          L2CAP_NON_FLUSHABLE_PKT
- *
- * Return value     L2CAP_DW_SUCCESS, if data accepted
- *                  L2CAP_DW_FAILED,  if error
- *
- ******************************************************************************/
-uint16_t L2CA_UcdDataWrite(uint16_t psm, const RawAddress& rem_bda,
-                           BT_HDR* p_buf, uint16_t flags) {
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-  uint8_t* p;
-
-  L2CAP_TRACE_API(
-      "L2CA_UcdDataWrite()  PSM: 0x%04x  BDA: %08x%04x", psm,
-      (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
-      (rem_bda[4] << 8) + rem_bda[5]);
-
-  /* Fail if the PSM is not registered */
-  if (((p_rcb = l2cu_find_rcb_by_psm(psm)) == NULL) ||
-      (p_rcb->ucd.state == L2C_UCD_STATE_UNUSED)) {
-    L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x",
-                        psm);
-    osi_free(p_buf);
-    return (L2CAP_DW_FAILED);
-  }
-
-  /* First, see if we already have a link to the remote */
-  /*  then find the channel control block for UCD */
-  if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
-       NULL) ||
-      ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
-       NULL)) {
-    if (l2c_ucd_connect(rem_bda) == false) {
-      osi_free(p_buf);
-      return (L2CAP_DW_FAILED);
-    }
-
-    /* If we still don't have lcb and ccb after connect attempt, then can't
-     * proceed */
-    if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
-         NULL) ||
-        ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
-         NULL)) {
-      osi_free(p_buf);
-      return (L2CAP_DW_FAILED);
-    }
-  }
-
-  /* write PSM */
-  p_buf->offset -= L2CAP_UCD_OVERHEAD;
-  p_buf->len += L2CAP_UCD_OVERHEAD;
-  p = (uint8_t*)(p_buf + 1) + p_buf->offset;
-
-  UINT16_TO_STREAM(p, psm);
-
-  /* UCD MTU check */
-  if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu)) {
-    L2CAP_TRACE_WARNING(
-        "L2CAP - Handle: 0x%04x  UCD bigger than peer's UCD mtu size cannot be "
-        "sent",
-        p_lcb->handle);
-    osi_free(p_buf);
-    return (L2CAP_DW_FAILED);
-  }
-
-  /* If already congested, do not accept any more packets */
-  if (p_ccb->cong_sent) {
-    L2CAP_TRACE_ERROR(
-        "L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: "
-        "%u  buff_quota: %u",
-        p_lcb->handle, (fixed_queue_length(p_ccb->xmit_hold_q) +
-                        fixed_queue_length(p_lcb->ucd_out_sec_pending_q)),
-        p_ccb->buff_quota);
-
-    osi_free(p_buf);
-    return (L2CAP_DW_FAILED);
-  }
-
-  /* channel based, packet based flushable or non-flushable */
-  p_buf->layer_specific = flags;
-
-  l2c_csm_execute(p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf);
-
-  if (p_ccb->cong_sent)
-    return (L2CAP_DW_CONGESTED);
-  else
-    return (L2CAP_DW_SUCCESS);
-}
-
-/*******************************************************************************
- *
- *  Function        L2CA_UcdSetIdleTimeout
- *
- *  Description     Set UCD Idle timeout.
- *
- *  Parameters:     BD Addr
- *                  Timeout in second
- *
- *  Return value:   true if successs
- *
- ******************************************************************************/
-bool L2CA_UcdSetIdleTimeout(const RawAddress& rem_bda, uint16_t timeout) {
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb;
-
-  L2CAP_TRACE_API(
-      "L2CA_UcdSetIdleTimeout()  Timeout: 0x%04x  BDA: %08x%04x", timeout,
-      (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
-      (rem_bda[4] << 8) + rem_bda[5]);
-
-  /* First, see if we already have a link to the remote */
-  /* then find the channel control block. */
-  if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
-       NULL) ||
-      ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
-       NULL)) {
-    L2CAP_TRACE_WARNING("L2CAP - no UCD channel");
-    return (false);
-  } else {
-    p_ccb->fixed_chnl_idle_tout = timeout;
-    return (true);
-  }
-}
-
-/*******************************************************************************
- *
- * Function         L2CA_UCDSetTxPriority
- *
- * Description      Sets the transmission priority for a connectionless channel.
- *
- * Returns          true if a valid channel, else false
- *
- ******************************************************************************/
-bool L2CA_UCDSetTxPriority(const RawAddress& rem_bda,
-                           tL2CAP_CHNL_PRIORITY priority) {
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb;
-
-  L2CAP_TRACE_API(
-      "L2CA_UCDSetTxPriority()  priority: 0x%02x  BDA: %08x%04x", priority,
-      (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
-      (rem_bda[4] << 8) + rem_bda[5]);
-
-  p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR);
-  if (p_lcb == NULL) {
-    L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_UCDSetTxPriority");
-    return (false);
-  }
-
-  /* Find the channel control block */
-  p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID);
-  if (p_ccb == NULL) {
-    L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_UCDSetTxPriority");
-    return (false);
-  }
-
-  /* it will update the order of CCB in LCB by priority and update round robin
-   * service variables */
-  l2cu_change_pri_ccb(p_ccb, priority);
-
-  return (true);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_connect
- *
- *  Description     Connect UCD to remote device.
- *
- *  Parameters:     BD_ADDR of remote device
- *
- *  Return value:   true if successs
- *
- ******************************************************************************/
-static bool l2c_ucd_connect(const RawAddress& rem_bda) {
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-
-  L2CAP_TRACE_DEBUG(
-      "l2c_ucd_connect()  BDA: %08x%04x",
-      (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
-      (rem_bda[4] << 8) + rem_bda[5]);
-
-  /* Fail if we have not established communications with the controller */
-  if (!BTM_IsDeviceUp()) {
-    L2CAP_TRACE_WARNING("l2c_ucd_connect - BTU not ready");
-    return (false);
-  }
-
-  /* First, see if we already have a link to the remote */
-  p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR);
-  if (p_lcb == NULL) {
-    /* No link. Get an LCB and start link establishment */
-    if (((p_lcb = l2cu_allocate_lcb(rem_bda, false, BT_TRANSPORT_BR_EDR)) ==
-         NULL) ||
-        (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false)) {
-      L2CAP_TRACE_WARNING("L2CAP - conn not started l2c_ucd_connect");
-      return (false);
-    }
-  } else if (p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE)) {
-    if (!(p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) {
-      L2CAP_TRACE_WARNING(
-          "L2CAP - UCD is not supported by peer, l2c_ucd_connect");
-      return (false);
-    }
-  }
-
-  /* Find the channel control block. */
-  p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID);
-  if (p_ccb == NULL) {
-    /* Allocate a channel control block */
-    p_ccb = l2cu_allocate_ccb(p_lcb, 0);
-    if (p_ccb == NULL) {
-      L2CAP_TRACE_WARNING("L2CAP - no CCB for l2c_ucd_connect");
-      return (false);
-    } else {
-      /* Set CID for the connection */
-      p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID;
-      p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
-
-      /* Set the default idle timeout value to use */
-      p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
-
-      /* Set the default channel priority value to use */
-      l2cu_change_pri_ccb(p_ccb, L2CAP_UCD_CH_PRIORITY);
-
-      p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID);
-      if (p_rcb == NULL) {
-        L2CAP_TRACE_WARNING("L2CAP - no UCD registered, l2c_ucd_connect");
-        return (false);
-      }
-      /* Save UCD registration info */
-      p_ccb->p_rcb = p_rcb;
-
-      /* There is no configuration, so if the link is up, the channel is up */
-      if (p_lcb->link_state == LST_CONNECTED) {
-        p_ccb->chnl_state = CST_OPEN;
-      }
-    }
-  }
-
-  return (true);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_delete_sec_pending_q
- *
- * Description      discard all of UCD packets in security pending queue
- *
- * Returns          None
- *
- ******************************************************************************/
-void l2c_ucd_delete_sec_pending_q(tL2C_LCB* p_lcb) {
-  /* clean up any security pending UCD */
-  while (!fixed_queue_is_empty(p_lcb->ucd_out_sec_pending_q))
-    osi_free(fixed_queue_try_dequeue(p_lcb->ucd_out_sec_pending_q));
-  fixed_queue_free(p_lcb->ucd_out_sec_pending_q, NULL);
-  p_lcb->ucd_out_sec_pending_q = NULL;
-
-  while (!fixed_queue_is_empty(p_lcb->ucd_in_sec_pending_q))
-    osi_free(fixed_queue_try_dequeue(p_lcb->ucd_in_sec_pending_q));
-  fixed_queue_free(p_lcb->ucd_in_sec_pending_q);
-  p_lcb->ucd_in_sec_pending_q = NULL;
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_check_pending_info_req
- *
- * Description      check if any application is waiting for UCD information
- *
- *  Return          true if any pending UCD info request
- *
- ******************************************************************************/
-bool l2c_ucd_check_pending_info_req(tL2C_CCB* p_ccb) {
-  tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
-  uint16_t xx;
-  bool pending = false;
-
-  if (p_ccb == NULL) {
-    L2CAP_TRACE_ERROR("L2CAP - NULL p_ccb in l2c_ucd_check_pending_info_req");
-    return (false);
-  }
-
-  for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
-    if (p_rcb->in_use) {
-      /* if application is waiting UCD reception info */
-      if (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION) {
-        /* if this information is available */
-        if (p_ccb->p_lcb->info_rx_bits &
-            (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE)) {
-          if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) {
-            L2CAP_TRACE_WARNING(
-                "L2CAP - UCD is not supported by peer, "
-                "l2c_ucd_check_pending_info_req");
-
-            l2c_ucd_delete_sec_pending_q(p_ccb->p_lcb);
-            l2cu_release_ccb(p_ccb);
-          }
-
-          p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(
-              p_ccb->p_lcb->remote_bd_addr, L2CAP_UCD_INFO_TYPE_RECEPTION,
-              p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION);
-        } else {
-          pending = true;
-          if (p_ccb->p_lcb->w4_info_rsp == false) {
-            l2cu_send_peer_info_req(p_ccb->p_lcb,
-                                    L2CAP_EXTENDED_FEATURES_INFO_TYPE);
-          }
-        }
-      }
-
-      /* if application is waiting for UCD MTU */
-      if (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU) {
-        /* if this information is available */
-        if (p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_CONNLESS_MTU_INFO_TYPE)) {
-          p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(
-              p_ccb->p_lcb->remote_bd_addr, L2CAP_UCD_INFO_TYPE_MTU,
-              p_ccb->p_lcb->ucd_mtu);
-        } else {
-          pending = true;
-          if (p_ccb->p_lcb->w4_info_rsp == false) {
-            l2cu_send_peer_info_req(p_ccb->p_lcb, L2CAP_CONNLESS_MTU_INFO_TYPE);
-          }
-        }
-      }
-    }
-  }
-  return (pending);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_enqueue_pending_out_sec_q
- *
- *  Description     enqueue outgoing UCD packet into security pending queue
- *                  and check congestion
- *
- *  Return          None
- *
- ******************************************************************************/
-void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB* p_ccb, void* p_data) {
-  fixed_queue_enqueue(p_ccb->p_lcb->ucd_out_sec_pending_q, p_data);
-  l2cu_check_channel_congestion(p_ccb);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_check_pending_out_sec_q
- *
- *  Description     check outgoing security
- *
- *  Return          true if any UCD packet for security
- *
- ******************************************************************************/
-bool l2c_ucd_check_pending_out_sec_q(tL2C_CCB* p_ccb) {
-  BT_HDR* p_buf =
-      (BT_HDR*)fixed_queue_try_peek_first(p_ccb->p_lcb->ucd_out_sec_pending_q);
-
-  if (p_buf != NULL) {
-    uint16_t psm;
-    uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
-
-    STREAM_TO_UINT16(psm, p)
-
-    p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
-    btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, psm,
-                             p_ccb->p_lcb->handle, CONNLESS_ORIG,
-                             &l2c_link_sec_comp, p_ccb);
-
-    return (true);
-  }
-  return (false);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_send_pending_out_sec_q
- *
- *  Description     dequeue UCD packet from security pending queue and
- *                  enqueue it into CCB
- *
- *  Return          None
- *
- ******************************************************************************/
-void l2c_ucd_send_pending_out_sec_q(tL2C_CCB* p_ccb) {
-  BT_HDR* p_buf =
-      (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
-
-  if (p_buf != NULL) {
-    l2c_enqueue_peer_data(p_ccb, (BT_HDR*)p_buf);
-    l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
-  }
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_discard_pending_out_sec_q
- *
- *  Description     dequeue UCD packet from security pending queue and
- *                  discard it.
- *
- *  Return          None
- *
- ******************************************************************************/
-void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB* p_ccb) {
-  BT_HDR* p_buf =
-      (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
-
-  /* we may need to report to application */
-  osi_free(p_buf);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_check_pending_in_sec_q
- *
- *  Description     check incoming security
- *
- *  Return          true if any UCD packet for security
- *
- ******************************************************************************/
-bool l2c_ucd_check_pending_in_sec_q(tL2C_CCB* p_ccb) {
-  BT_HDR* p_buf =
-      (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
-
-  if (p_buf != NULL) {
-    uint16_t psm;
-    uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
-    STREAM_TO_UINT16(psm, p)
-
-    p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
-    btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, psm,
-                             p_ccb->p_lcb->handle, CONNLESS_TERM,
-                             &l2c_link_sec_comp, p_ccb);
-
-    return (true);
-  }
-  return (false);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_send_pending_in_sec_q
- *
- *  Description     dequeue UCD packet from security pending queue and
- *                  send it to application
- *
- *  Return          None
- *
- ******************************************************************************/
-void l2c_ucd_send_pending_in_sec_q(tL2C_CCB* p_ccb) {
-  BT_HDR* p_buf =
-      (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q)
-
-          if (p_buf != NULL) {
-    p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr,
-                                                (BT_HDR*)p_buf);
-  }
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_discard_pending_in_sec_q
- *
- *  Description     dequeue UCD packet from security pending queue and
- *                  discard it.
- *
- *  Return          None
- *
- ******************************************************************************/
-void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB* p_ccb) {
-  BT_HDR* p_buf =
-      (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
-  osi_free(p_buf);
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_check_rx_pkts
- *
- *  Description     Check if UCD reception is registered.
- *                  Process received UCD packet if application is expecting.
- *
- *  Return          true if UCD reception is registered
- *
- ******************************************************************************/
-bool l2c_ucd_check_rx_pkts(tL2C_LCB* p_lcb, BT_HDR* p_msg) {
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-
-  if (((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) !=
-       NULL) ||
-      ((p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID)) != NULL)) {
-    if (p_ccb == NULL) {
-      /* Allocate a channel control block */
-      p_ccb = l2cu_allocate_ccb(p_lcb, 0);
-      if (p_ccb == NULL) {
-        L2CAP_TRACE_WARNING("L2CAP - no CCB for UCD reception");
-        osi_free(p_msg);
-        return true;
-      } else {
-        /* Set CID for the connection */
-        p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID;
-        p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
-
-        /* Set the default idle timeout value to use */
-        p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
-
-        /* Set the default channel priority value to use */
-        l2cu_change_pri_ccb(p_ccb, L2CAP_UCD_CH_PRIORITY);
-
-        /* Save registration info */
-        p_ccb->p_rcb = p_rcb;
-
-        p_ccb->chnl_state = CST_OPEN;
-      }
-    }
-    l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
-    return true;
-  } else
-    return false;
-}
-
-/*******************************************************************************
- *
- *  Function        l2c_ucd_process_event
- *
- *  Description     This is called from main state machine when LCID is
- *                  connectionless. Process the event if it is for UCD.
- *
- *  Return          true if the event is consumed by UCD
- *                  false if the event needs to be processed by the main state
- *                        machine
- *
- ******************************************************************************/
-bool l2c_ucd_process_event(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
-  /* if the event is not processed by this function, this variable will be set
-   * to false */
-  bool done = true;
-
-  switch (p_ccb->chnl_state) {
-    case CST_CLOSED:
-      switch (event) {
-        case L2CEVT_LP_CONNECT_CFM: /* Link came up         */
-          /* check if waiting for UCD info */
-          if (!l2c_ucd_check_pending_info_req(p_ccb)) {
-            /* check if any outgoing UCD packet is waiting security check */
-            if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) {
-              p_ccb->chnl_state = CST_OPEN;
-            }
-          }
-          break;
-
-        case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd    */
-          fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
-          break;
-
-        case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
-          l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
-          break;
-
-        case L2CEVT_L2CAP_INFO_RSP:
-          /* check if waiting for UCD info */
-          if (!l2c_ucd_check_pending_info_req(p_ccb)) {
-            /* check if any outgoing UCD packet is waiting security check */
-            if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) {
-              p_ccb->chnl_state = CST_OPEN;
-            }
-          }
-          break;
-
-        default:
-          done = false; /* main state machine continues to process event */
-          break;
-      }
-      break;
-
-    case CST_ORIG_W4_SEC_COMP:
-      switch (event) {
-        case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
-          /* check if any outgoing UCD packet is waiting security check */
-          if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) {
-            p_ccb->chnl_state = CST_OPEN;
-          }
-          break;
-
-        case L2CEVT_SEC_COMP: /* Security completed success */
-          p_ccb->chnl_state = CST_OPEN;
-          l2c_ucd_send_pending_out_sec_q(p_ccb);
-
-          if (!fixed_queue_is_empty(p_ccb->p_lcb->ucd_out_sec_pending_q)) {
-            /* start a timer to send next UCD packet in OPEN state */
-            /* it will prevent stack overflow */
-            alarm_set_on_mloop(p_ccb->l2c_ccb_timer, 0, l2c_ccb_timer_timeout,
-                               p_ccb);
-          } else {
-            /* start a timer for idle timeout of UCD */
-            period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
-            alarm_set_on_mloop(p_ccb->l2c_ccb_timer, timeout_ms,
-                               l2c_ccb_timer_timeout, p_ccb);
-          }
-          break;
-
-        case L2CEVT_SEC_COMP_NEG:
-          p_ccb->chnl_state = CST_OPEN;
-          l2c_ucd_discard_pending_out_sec_q(p_ccb);
-
-          /* start a timer for idle timeout of UCD */
-          period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
-          alarm_set_on_mloop(p_ccb->l2c_ccb_timer, timeout_ms,
-                             l2c_ccb_timer_timeout, p_ccb);
-          break;
-
-        case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
-          l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
-          break;
-
-        case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd    */
-          fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
-          break;
-
-        case L2CEVT_L2CAP_INFO_RSP:
-          /* check if waiting for UCD info */
-          l2c_ucd_check_pending_info_req(p_ccb);
-          break;
-
-        default:
-          done = false; /* main state machine continues to process event */
-          break;
-      }
-      break;
-
-    case CST_TERM_W4_SEC_COMP:
-      switch (event) {
-        case L2CEVT_SEC_COMP:
-          p_ccb->chnl_state = CST_OPEN;
-          l2c_ucd_send_pending_in_sec_q(p_ccb);
-
-          if (!fixed_queue_is_empty(p_ccb->p_lcb->ucd_in_sec_pending_q)) {
-            /* start a timer to check next UCD packet in OPEN state */
-            /* it will prevent stack overflow */
-            alarm_set_on_mloop(p_ccb->l2c_ccb_timer, 0, l2c_ccb_timer_timeout,
-                               p_ccb);
-          } else {
-            /* start a timer for idle timeout of UCD */
-            period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
-            alarm_set_on_mloop(p_ccb->l2c_ccb_timer, timeout_ms,
-                               l2c_ccb_timer_timeout, p_ccb);
-          }
-          break;
-
-        case L2CEVT_SEC_COMP_NEG:
-          if (((tL2C_CONN_INFO*)p_data)->status == BTM_DELAY_CHECK) {
-            done = false;
-            break;
-          }
-          p_ccb->chnl_state = CST_OPEN;
-          l2c_ucd_discard_pending_in_sec_q(p_ccb);
-
-          /* start a timer for idle timeout of UCD */
-          period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
-          alarm_set_on_mloop(p_ccb->l2c_ccb_timer, timeout_ms,
-                             l2c_ccb_timer_timeout, p_ccb);
-          break;
-
-        case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
-          l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
-          break;
-
-        case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd    */
-          fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
-          break;
-
-        case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
-          /* check if any incoming UCD packet is waiting security check */
-          if (!l2c_ucd_check_pending_in_sec_q(p_ccb)) {
-            p_ccb->chnl_state = CST_OPEN;
-          }
-          break;
-
-        case L2CEVT_L2CAP_INFO_RSP:
-          /* check if waiting for UCD info */
-          l2c_ucd_check_pending_info_req(p_ccb);
-          break;
-
-        default:
-          done = false; /* main state machine continues to process event */
-          break;
-      }
-      break;
-
-    case CST_OPEN:
-      switch (event) {
-        case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd    */
-          /* stop idle timer of UCD */
-          alarm_cancel(p_ccb->l2c_ccb_timer);
-
-          fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
-          l2c_ucd_check_pending_in_sec_q(p_ccb);
-          break;
-
-        case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
-          /* stop idle timer of UCD */
-          alarm_cancel(p_ccb->l2c_ccb_timer);
-
-          l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
-
-          /* success changes state, failure stays in current state */
-          l2c_ucd_check_pending_out_sec_q(p_ccb);
-          break;
-
-        case L2CEVT_TIMEOUT:
-          /* check if any UCD packet is waiting security check */
-          if ((!l2c_ucd_check_pending_in_sec_q(p_ccb)) &&
-              (!l2c_ucd_check_pending_out_sec_q(p_ccb))) {
-            l2cu_release_ccb(p_ccb);
-          }
-          break;
-
-        case L2CEVT_L2CAP_INFO_RSP:
-          /* check if waiting for UCD info */
-          l2c_ucd_check_pending_info_req(p_ccb);
-          break;
-
-        default:
-          done = false; /* main state machine continues to process event */
-          break;
-      }
-      break;
-
-    default:
-      done = false; /* main state machine continues to process event */
-      break;
-  }
-
-  return done;
-}
-#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
diff --git a/stack/l2cap/l2c_utils.cc b/stack/l2cap/l2c_utils.cc
index f07f4e3..337e076 100644
--- a/stack/l2cap/l2c_utils.cc
+++ b/stack/l2cap/l2c_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -98,10 +98,6 @@
         l2cb.num_links_active++;
         l2c_link_adjust_allocation();
       }
-#if (L2CAP_UCD_INCLUDED == TRUE)
-      p_lcb->ucd_out_sec_pending_q = fixed_queue_new(SIZE_MAX);
-      p_lcb->ucd_in_sec_pending_q = fixed_queue_new(SIZE_MAX);
-#endif
       p_lcb->link_xmit_data_q = list_new(NULL);
       return (p_lcb);
     }
@@ -176,7 +172,8 @@
   }
 
   // Reset BLE connecting flag only if the address matches
-  if (l2cb.ble_connecting_bda == p_lcb->remote_bd_addr)
+  if (p_lcb->transport == BT_TRANSPORT_LE &&
+      l2cb.ble_connecting_bda == p_lcb->remote_bd_addr)
     l2cb.is_ble_connecting = false;
 
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
@@ -205,11 +202,6 @@
     p_lcb->link_xmit_data_q = NULL;
   }
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  /* clean up any security pending UCD */
-  l2c_ucd_delete_sec_pending_q(p_lcb);
-#endif
-
   /* Re-adjust flow control windows make sure it does not go negative */
   if (p_lcb->transport == BT_TRANSPORT_LE) {
     if (l2cb.num_ble_links_active >= 1) l2cb.num_ble_links_active--;
@@ -1162,7 +1154,7 @@
 #endif
   } else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) {
     UINT16_TO_STREAM(p, L2CAP_INFO_RESP_RESULT_SUCCESS);
-    UINT16_TO_STREAM(p, L2CAP_UCD_MTU);
+    UINT16_TO_STREAM(p, L2CAP_MTU_SIZE);
   } else {
     UINT16_TO_STREAM(
         p, L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED); /* 'not supported' */
@@ -1190,9 +1182,8 @@
   if (p_ccb->p_lcb != NULL) p_q = &p_ccb->p_lcb->ccb_queue;
 
   if ((!p_ccb->in_use) || (p_q == NULL)) {
-    L2CAP_TRACE_ERROR(
-        "l2cu_enqueue_ccb  CID: 0x%04x ERROR in_use: %u  p_lcb: 0x%08x",
-        p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb);
+    L2CAP_TRACE_ERROR("%s: CID: 0x%04x ERROR in_use: %u  p_lcb: %p", __func__,
+                      p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb);
     return;
   }
 
@@ -1604,11 +1595,7 @@
   l2c_fcr_cleanup(p_ccb);
 
   /* Channel may not be assigned to any LCB if it was just pre-reserved */
-  if ((p_lcb) && ((p_ccb->local_cid >= L2CAP_BASE_APPL_CID)
-#if (L2CAP_UCD_INCLUDED == TRUE)
-                  || (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID)
-#endif
-                      )) {
+  if ((p_lcb) && ((p_ccb->local_cid >= L2CAP_BASE_APPL_CID))) {
     l2cu_dequeue_ccb(p_ccb);
 
     /* Delink the CCB from the LCB */
@@ -1691,9 +1678,6 @@
     if (!p_rcb->in_use) {
       p_rcb->in_use = true;
       p_rcb->psm = psm;
-#if (L2CAP_UCD_INCLUDED == TRUE)
-      p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
-#endif
       return (p_rcb);
     }
   }
@@ -1720,9 +1704,6 @@
     if (!p_rcb->in_use) {
       p_rcb->in_use = true;
       p_rcb->psm = psm;
-#if (L2CAP_UCD_INCLUDED == TRUE)
-      p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
-#endif
       return (p_rcb);
     }
   }
@@ -1747,6 +1728,21 @@
 
 /*******************************************************************************
  *
+ * Function         l2cu_release_ble_rcb
+ *
+ * Description      Mark an LE RCB as no longer in use
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void l2cu_release_ble_rcb(tL2C_RCB* p_rcb) {
+  L2CA_FreeLePSM(p_rcb->psm);
+  p_rcb->in_use = false;
+  p_rcb->psm = 0;
+}
+
+/*******************************************************************************
+ *
  * Function         l2cu_disconnect_chnl
  *
  * Description      Disconnect a channel. Typically, this is due to either
@@ -1854,7 +1850,7 @@
     /* Make sure MTU is at least the minimum */
     if (p_cfg->mtu >= L2CAP_MIN_MTU) {
       /* In basic mode, limit the MTU to our buffer size */
-      if ((p_cfg->fcr_present == false) && (p_cfg->mtu > L2CAP_MTU_SIZE))
+      if ((!p_cfg->fcr_present) && (p_cfg->mtu > L2CAP_MTU_SIZE))
         p_cfg->mtu = L2CAP_MTU_SIZE;
 
       /* Save the accepted value in case of renegotiation */
@@ -2158,9 +2154,9 @@
 
       L2CAP_TRACE_API(
           "l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s",
-          (is_sco_active == true) ? "true" : "false");
+          (is_sco_active) ? "true" : "false");
 
-      if (is_sco_active == true)
+      if (is_sco_active)
         continue; /* No Master Slave switch not allowed when SCO Active */
 #endif
       /*4_1_TODO check  if btm_cb.devcb.local_features to be used instead */
@@ -3060,10 +3056,6 @@
  ******************************************************************************/
 tL2C_CCB* l2cu_find_ccb_by_cid(tL2C_LCB* p_lcb, uint16_t local_cid) {
   tL2C_CCB* p_ccb = NULL;
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  uint8_t xx;
-#endif
-
   if (local_cid >= L2CAP_BASE_APPL_CID) {
     /* find the associated CCB by "index" */
     local_cid -= L2CAP_BASE_APPL_CID;
@@ -3081,21 +3073,6 @@
       p_ccb = NULL;
     }
   }
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  else {
-    /* searching fixed channel */
-    p_ccb = l2cb.ccb_pool;
-    for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) {
-      if ((p_ccb->local_cid == local_cid) && (p_ccb->in_use) &&
-          (p_lcb == p_ccb->p_lcb))
-        break;
-      else
-        p_ccb++;
-    }
-    if (xx >= MAX_L2CAP_CHANNELS) return NULL;
-  }
-#endif
-
   return (p_ccb);
 }
 
@@ -3323,10 +3300,16 @@
       L2CAP_TRACE_DEBUG("%s No credits to send packets", __func__);
       return NULL;
     }
-    p_buf = l2c_lcc_get_next_xmit_sdu_seg(p_ccb, 0);
-    if (p_buf == NULL) return (NULL);
 
+    bool last_piece_of_sdu = false;
+    p_buf = l2c_lcc_get_next_xmit_sdu_seg(p_ccb, &last_piece_of_sdu);
     p_ccb->peer_conn_cfg.credits--;
+
+    if (last_piece_of_sdu) {
+      // TODO: send callback up the stack. Investigate setting p_cbi->cb to
+      // notify after controller ack send.
+    }
+
   } else {
     if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
       p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0);
@@ -3409,113 +3392,55 @@
   p_buf->len += HCI_DATA_PREAMBLE_SIZE;
 }
 
-/******************************************************************************
- *
- * Function         l2cu_check_channel_congestion
- *
- * Description      check if any change in congestion status
- *
- * Returns          None
- *
- ******************************************************************************/
-void l2cu_check_channel_congestion(tL2C_CCB* p_ccb) {
-  size_t q_count = fixed_queue_length(p_ccb->xmit_hold_q);
+static void send_congestion_status_to_all_clients(tL2C_CCB* p_ccb,
+                                                  bool status) {
+  p_ccb->cong_sent = status;
 
-#if (L2CAP_UCD_INCLUDED == TRUE)
-  if (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
-    q_count += fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q);
+  if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
+    L2CAP_TRACE_DEBUG(
+        "L2CAP - Calling CongestionStatus_Cb (%d), CID: 0x%04x "
+        "xmit_hold_q.count: %u  buff_quota: %u",
+        status, p_ccb->local_cid, fixed_queue_length(p_ccb->xmit_hold_q),
+        p_ccb->buff_quota);
+
+    /* Prevent recursive calling */
+    if (status == false) l2cb.is_cong_cback_context = true;
+
+    (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, status);
+
+    if (status == false) l2cb.is_cong_cback_context = false;
   }
-#endif
-  /* If the CCB queue limit is subject to a quota, check for congestion */
-  /* if this channel has outgoing traffic */
-  if (p_ccb->buff_quota != 0) {
-    /* If this channel was congested */
-    if (p_ccb->cong_sent) {
-      /* If the channel is not congested now, tell the app */
-      if (q_count <= (p_ccb->buff_quota / 2)) {
-        p_ccb->cong_sent = false;
-        if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
-          L2CAP_TRACE_DEBUG(
-              "L2CAP - Calling CongestionStatus_Cb (false), CID: 0x%04x  "
-              "xmit_hold_q.count: %u  buff_quota: %u",
-              p_ccb->local_cid, q_count, p_ccb->buff_quota);
-
-          /* Prevent recursive calling */
-          l2cb.is_cong_cback_context = true;
-          (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid,
-                                                         false);
-          l2cb.is_cong_cback_context = false;
-        }
-#if (L2CAP_UCD_INCLUDED == TRUE)
-        else if (p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
-          if (p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb) {
-            L2CAP_TRACE_DEBUG(
-                "L2CAP - Calling UCD CongestionStatus_Cb (false), "
-                "SecPendingQ:%u,XmitQ:%u,Quota:%u",
-                fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q),
-                fixed_queue_length(p_ccb->xmit_hold_q), p_ccb->buff_quota);
-            p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb(
-                p_ccb->p_lcb->remote_bd_addr, false);
-          }
-        }
-#endif
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
-        else {
-          uint8_t xx;
-          for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
-            if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) {
-              if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
-                (*l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(
-                    p_ccb->p_lcb->remote_bd_addr, false);
-              break;
-            }
-          }
-        }
-#endif
-      }
-    } else {
-      /* If this channel was not congested but it is congested now, tell the app
-       */
-      if (q_count > p_ccb->buff_quota) {
-        p_ccb->cong_sent = true;
-        if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
-          L2CAP_TRACE_DEBUG(
-              "L2CAP - Calling CongestionStatus_Cb "
-              "(true),CID:0x%04x,XmitQ:%u,Quota:%u",
-              p_ccb->local_cid, q_count, p_ccb->buff_quota);
-
-          (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid,
-                                                         true);
-        }
-#if (L2CAP_UCD_INCLUDED == TRUE)
-        else if (p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
-          if (p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb) {
-            L2CAP_TRACE_DEBUG(
-                "L2CAP - Calling UCD CongestionStatus_Cb (true), "
-                "SecPendingQ:%u,XmitQ:%u,Quota:%u",
-                fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q),
-                fixed_queue_length(p_ccb->xmit_hold_q), p_ccb->buff_quota);
-            p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb(
-                p_ccb->p_lcb->remote_bd_addr, true);
-          }
-        }
-#endif
-#if (L2CAP_NUM_FIXED_CHNLS > 0)
-        else {
-          uint8_t xx;
-          for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
-            if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) {
-              if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
-                (*l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(
-                    p_ccb->p_lcb->remote_bd_addr, true);
-              break;
-            }
-          }
-        }
-#endif
+  else {
+    for (uint8_t xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+      if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) {
+        if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
+          (*l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr,
+                                                   status);
+        break;
       }
     }
   }
+#endif
+}
+
+/* check if any change in congestion status */
+void l2cu_check_channel_congestion(tL2C_CCB* p_ccb) {
+  /* If the CCB queue limit is subject to a quota, check for congestion if this
+   * channel has outgoing traffic */
+  if (p_ccb->buff_quota == 0) return;
+
+  size_t q_count = fixed_queue_length(p_ccb->xmit_hold_q);
+
+  if (p_ccb->cong_sent) {
+    /* if channel was congested, but is not congested now, tell the app */
+    if (q_count <= (p_ccb->buff_quota / 2))
+      send_congestion_status_to_all_clients(p_ccb, false);
+  } else {
+    /* if channel was not congested, but is congested now, tell the app */
+    if (q_count > p_ccb->buff_quota)
+      send_congestion_status_to_all_clients(p_ccb, true);
+  }
 }
 
 /*******************************************************************************
diff --git a/stack/l2cap/l2cap_client.cc b/stack/l2cap/l2cap_client.cc
index 6ccf8c5..76e4138 100644
--- a/stack/l2cap/l2cap_client.cc
+++ b/stack/l2cap/l2cap_client.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/mcap/mca_api.cc b/stack/mcap/mca_api.cc
index 44ab256..578d53e 100644
--- a/stack/mcap/mca_api.cc
+++ b/stack/mcap/mca_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/mcap/mca_cact.cc b/stack/mcap/mca_cact.cc
index f0759ac..48d0c0a 100644
--- a/stack/mcap/mca_cact.cc
+++ b/stack/mcap/mca_cact.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/mcap/mca_csm.cc b/stack/mcap/mca_csm.cc
index 9ff1915..4b3a4a0 100644
--- a/stack/mcap/mca_csm.cc
+++ b/stack/mcap/mca_csm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/mcap/mca_dact.cc b/stack/mcap/mca_dact.cc
index d05f3cd..8ee3ac1 100644
--- a/stack/mcap/mca_dact.cc
+++ b/stack/mcap/mca_dact.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -111,7 +111,7 @@
  *
  ******************************************************************************/
 void mca_dcb_do_disconn(tMCA_DCB* p_dcb, UNUSED_ATTR tMCA_DCB_EVT* p_data) {
-  if ((p_dcb->lcid == 0) || (L2CA_DisconnectReq(p_dcb->lcid) == false)) {
+  if ((p_dcb->lcid == 0) || (!L2CA_DisconnectReq(p_dcb->lcid))) {
     tMCA_CLOSE close;
     close.param = MCA_INT;
     close.reason = L2CAP_DISC_OK;
diff --git a/stack/mcap/mca_dsm.cc b/stack/mcap/mca_dsm.cc
index 3494448..0d26931 100644
--- a/stack/mcap/mca_dsm.cc
+++ b/stack/mcap/mca_dsm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/mcap/mca_int.h b/stack/mcap/mca_int.h
index 55765fd..9ae5d57 100644
--- a/stack/mcap/mca_int.h
+++ b/stack/mcap/mca_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/mcap/mca_l2c.cc b/stack/mcap/mca_l2c.cc
index 78a17ae..e0540fa 100644
--- a/stack/mcap/mca_l2c.cc
+++ b/stack/mcap/mca_l2c.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -33,17 +33,19 @@
 #include "osi/include/osi.h"
 
 /* L2CAP callback function structure */
-const tL2CAP_APPL_INFO mca_l2c_int_appl = {NULL,
-                                           mca_l2c_connect_cfm_cback,
-                                           NULL,
-                                           mca_l2c_config_ind_cback,
-                                           mca_l2c_config_cfm_cback,
-                                           mca_l2c_disconnect_ind_cback,
-                                           mca_l2c_disconnect_cfm_cback,
-                                           NULL,
-                                           mca_l2c_data_ind_cback,
-                                           mca_l2c_congestion_ind_cback,
-                                           NULL};
+const tL2CAP_APPL_INFO mca_l2c_int_appl = {
+    NULL,
+    mca_l2c_connect_cfm_cback,
+    NULL,
+    mca_l2c_config_ind_cback,
+    mca_l2c_config_cfm_cback,
+    mca_l2c_disconnect_ind_cback,
+    mca_l2c_disconnect_cfm_cback,
+    NULL,
+    mca_l2c_data_ind_cback,
+    mca_l2c_congestion_ind_cback,
+    NULL,
+    NULL /* tL2CA_CREDITS_RECEIVED_CB */};
 
 /* Control channel eL2CAP default options */
 const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = {
diff --git a/stack/mcap/mca_main.cc b/stack/mcap/mca_main.cc
index 1cc8e75..0185721 100644
--- a/stack/mcap/mca_main.cc
+++ b/stack/mcap/mca_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -444,17 +444,17 @@
       p_buf->layer_specific = rej_rsp_code;
       /* forward the request/response to state machine */
       mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT*)p_buf);
-    } /* got a valid ccb */
-    else
+    } else {
       osi_free(p_buf);
-  }
-  /* else send event to dcb */
-  else {
+    }
+  } else {
+    /* send event to dcb */
     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
     if (p_dcb != NULL) {
       mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT*)p_buf);
-    } else
+    } else {
       osi_free(p_buf);
+    }
   }
 }
 
diff --git a/stack/pan/pan_api.cc b/stack/pan/pan_api.cc
index a36793c..ea7791b 100644
--- a/stack/pan/pan_api.cc
+++ b/stack/pan/pan_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -37,6 +37,8 @@
 #include "sdp_api.h"
 #include "sdpdefs.h"
 
+using bluetooth::Uuid;
+
 /*******************************************************************************
  *
  * Function         PAN_Register
@@ -266,9 +268,6 @@
  ******************************************************************************/
 tPAN_RESULT PAN_Connect(const RawAddress& rem_bda, uint8_t src_role,
                         uint8_t dst_role, uint16_t* handle) {
-  tPAN_CONN* pcb;
-  tBNEP_RESULT result;
-  tBT_UUID src_uuid, dst_uuid;
   uint32_t mx_chan_id;
 
   /*
@@ -294,8 +293,9 @@
   }
 
   /* Check if connection exists for this remote device */
-  pcb = pan_get_pcb_by_addr(rem_bda);
+  tPAN_CONN* pcb = pan_get_pcb_by_addr(rem_bda);
 
+  uint16_t src_uuid, dst_uuid;
   /* If we are PANU for this role validate destination role */
   if (src_role == PAN_ROLE_CLIENT) {
     if ((pan_cb.num_conns > 1) || (pan_cb.num_conns && (!pcb))) {
@@ -310,15 +310,15 @@
       return PAN_INVALID_SRC_ROLE;
     }
 
-    src_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+    src_uuid = UUID_SERVCLASS_PANU;
     if (dst_role == PAN_ROLE_CLIENT) {
-      dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+      dst_uuid = UUID_SERVCLASS_PANU;
     } else if (dst_role == PAN_ROLE_GN_SERVER) {
-      dst_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+      dst_uuid = UUID_SERVCLASS_GN;
     } else {
-      dst_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+      dst_uuid = UUID_SERVCLASS_NAP;
     }
-    mx_chan_id = dst_uuid.uu.uuid16;
+    mx_chan_id = dst_uuid;
   }
   /* If destination is PANU role validate source role */
   else if (dst_role == PAN_ROLE_CLIENT) {
@@ -327,13 +327,13 @@
       return PAN_INVALID_SRC_ROLE;
     }
 
-    dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+    dst_uuid = UUID_SERVCLASS_PANU;
     if (src_role == PAN_ROLE_GN_SERVER) {
-      src_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+      src_uuid = UUID_SERVCLASS_GN;
     } else {
-      src_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+      src_uuid = UUID_SERVCLASS_NAP;
     }
-    mx_chan_id = src_uuid.uu.uuid16;
+    mx_chan_id = src_uuid;
   }
   /* The role combination is not valid */
   else {
@@ -364,16 +364,14 @@
   pcb->prv_src_uuid = pcb->src_uuid;
   pcb->prv_dst_uuid = pcb->dst_uuid;
 
-  pcb->src_uuid = src_uuid.uu.uuid16;
-  pcb->dst_uuid = dst_uuid.uu.uuid16;
+  pcb->src_uuid = src_uuid;
+  pcb->dst_uuid = dst_uuid;
 
-  src_uuid.len = 2;
-  dst_uuid.len = 2;
-
-  result = BNEP_Connect(rem_bda, &src_uuid, &dst_uuid, &(pcb->handle));
-  if (result != BNEP_SUCCESS) {
+  tBNEP_RESULT ret = BNEP_Connect(rem_bda, Uuid::From16Bit(src_uuid),
+                                  Uuid::From16Bit(dst_uuid), &(pcb->handle));
+  if (ret != BNEP_SUCCESS) {
     pan_release_pcb(pcb);
-    return result;
+    return ret;
   }
 
   PAN_TRACE_DEBUG("PAN_Connect() current active role set to %d", src_role);
diff --git a/stack/pan/pan_int.h b/stack/pan/pan_int.h
index 27fe666..1f76628 100644
--- a/stack/pan/pan_int.h
+++ b/stack/pan/pan_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -98,7 +98,8 @@
 /******************************************************************************/
 extern void pan_register_with_bnep(void);
 extern void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda,
-                            tBT_UUID* remote_uuid, tBT_UUID* local_uuid,
+                            const bluetooth::Uuid& remote_uuid,
+                            const bluetooth::Uuid& local_uuid,
                             bool is_role_change);
 extern void pan_connect_state_cb(uint16_t handle, const RawAddress& rem_bda,
                                  tBNEP_RESULT result, bool is_role_change);
diff --git a/stack/pan/pan_main.cc b/stack/pan/pan_main.cc
index d7cd27b..21bd1c9 100644
--- a/stack/pan/pan_main.cc
+++ b/stack/pan/pan_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -36,11 +36,9 @@
 #include "sdp_api.h"
 #include "sdpdefs.h"
 
-tPAN_CB pan_cb;
+using bluetooth::Uuid;
 
-#define UUID_CONSTANT_PART 12
-uint8_t constant_pan_uuid[UUID_CONSTANT_PART] = {
-    0, 0, 0x10, 0, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+tPAN_CB pan_cb;
 
 /*******************************************************************************
  *
@@ -90,127 +88,62 @@
  *
  ******************************************************************************/
 void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda,
-                     tBT_UUID* remote_uuid, tBT_UUID* local_uuid,
+                     const Uuid& remote_uuid, const Uuid& local_uuid,
                      bool is_role_change) {
-  tPAN_CONN* pcb;
-  uint8_t req_role;
-  bool wrong_uuid;
+  /* If we are in GN or NAP role and have one or more active connections and the
+   * received connection is for user role reject it. If we are in user role with
+   * one connection active reject the connection. Allocate PCB and store the
+   * parameters. Make bridge request to the host system if connection is for NAP
+   */
 
-  /*
-  ** If we are in GN or NAP role and have one or more
-  ** active connections and the received connection is
-  ** for user role reject it.
-  ** If we are in user role with one connection active
-  ** reject the connection.
-  ** Allocate PCB and store the parameters
-  ** Make bridge request to the host system if connection
-  ** is for NAP
-  */
-  wrong_uuid = false;
-  if (remote_uuid->len == 16) {
-    /*
-    ** If the UUID is 16 bytes forst two bytes should be zeros
-    ** and last 12 bytes should match the spec defined constant value
-    */
-    if (memcmp(constant_pan_uuid, remote_uuid->uu.uuid128 + 4,
-               UUID_CONSTANT_PART))
-      wrong_uuid = true;
-
-    if (remote_uuid->uu.uuid128[0] || remote_uuid->uu.uuid128[1])
-      wrong_uuid = true;
-
-    /* Extract the 16 bit equivalent of the UUID */
-    remote_uuid->uu.uuid16 = (uint16_t)((remote_uuid->uu.uuid128[2] << 8) |
-                                        remote_uuid->uu.uuid128[3]);
-    remote_uuid->len = 2;
-  }
-  if (remote_uuid->len == 4) {
-    /* First two bytes should be zeros */
-    if (remote_uuid->uu.uuid32 & 0xFFFF0000) wrong_uuid = true;
-
-    remote_uuid->uu.uuid16 = (uint16_t)remote_uuid->uu.uuid32;
-    remote_uuid->len = 2;
-  }
-
-  if (wrong_uuid) {
+  if (!remote_uuid.Is16Bit()) {
     PAN_TRACE_ERROR("PAN Connection failed because of wrong remote UUID ");
     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
     return;
   }
 
-  wrong_uuid = false;
-  if (local_uuid->len == 16) {
-    /*
-    ** If the UUID is 16 bytes forst two bytes should be zeros
-    ** and last 12 bytes should match the spec defined constant value
-    */
-    if (memcmp(constant_pan_uuid, local_uuid->uu.uuid128 + 4,
-               UUID_CONSTANT_PART))
-      wrong_uuid = true;
-
-    if (local_uuid->uu.uuid128[0] || local_uuid->uu.uuid128[1])
-      wrong_uuid = true;
-
-    /* Extract the 16 bit equivalent of the UUID */
-    local_uuid->uu.uuid16 = (uint16_t)((local_uuid->uu.uuid128[2] << 8) |
-                                       local_uuid->uu.uuid128[3]);
-    local_uuid->len = 2;
-  }
-  if (local_uuid->len == 4) {
-    /* First two bytes should be zeros */
-    if (local_uuid->uu.uuid32 & 0xFFFF0000) wrong_uuid = true;
-
-    local_uuid->uu.uuid16 = (uint16_t)local_uuid->uu.uuid32;
-    local_uuid->len = 2;
-  }
-
-  if (wrong_uuid) {
+  if (!local_uuid.Is16Bit()) {
     PAN_TRACE_ERROR("PAN Connection failed because of wrong local UUID ");
     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
     return;
   }
 
+  uint16_t remote_uuid16 = remote_uuid.As16Bit();
+  uint16_t local_uuid16 = local_uuid.As16Bit();
+
   PAN_TRACE_EVENT(
-      "pan_conn_ind_cb - for handle %d, current role %d, dst uuid 0x%x, src "
-      "uuid 0x%x, role change %s",
-      handle, pan_cb.role, local_uuid->uu.uuid16, remote_uuid->uu.uuid16,
+      "%s - handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role "
+      "change %s",
+      __func__, handle, pan_cb.role, local_uuid16, remote_uuid16,
       is_role_change ? "YES" : "NO");
-  /* The acceptable UUID size is only 2 */
-  if (remote_uuid->len != 2) {
-    PAN_TRACE_ERROR("PAN Connection failed because of wrong UUID size %d",
-                    remote_uuid->len);
-    BNEP_ConnectResp(handle, BNEP_CONN_FAILED_UUID_SIZE);
-    return;
-  }
 
   /* Check if the source UUID is a valid one */
-  if (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
-      remote_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
-      remote_uuid->uu.uuid16 != UUID_SERVCLASS_GN) {
-    PAN_TRACE_ERROR("Src UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+  if (remote_uuid16 != UUID_SERVCLASS_PANU &&
+      remote_uuid16 != UUID_SERVCLASS_NAP &&
+      remote_uuid16 != UUID_SERVCLASS_GN) {
+    PAN_TRACE_ERROR("Src UUID 0x%x is not valid", remote_uuid16);
     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
     return;
   }
 
   /* Check if the destination UUID is a valid one */
-  if (local_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
-      local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
-      local_uuid->uu.uuid16 != UUID_SERVCLASS_GN) {
-    PAN_TRACE_ERROR("Dst UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+  if (local_uuid16 != UUID_SERVCLASS_PANU &&
+      local_uuid16 != UUID_SERVCLASS_NAP && local_uuid16 != UUID_SERVCLASS_GN) {
+    PAN_TRACE_ERROR("Dst UUID 0x%x is not valid", local_uuid16);
     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
     return;
   }
 
   /* Check if currently we support the destination role requested */
   if (((!(pan_cb.role & UUID_SERVCLASS_PANU)) &&
-       local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) ||
+       local_uuid16 == UUID_SERVCLASS_PANU) ||
       ((!(pan_cb.role & UUID_SERVCLASS_GN)) &&
-       local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) ||
+       local_uuid16 == UUID_SERVCLASS_GN) ||
       ((!(pan_cb.role & UUID_SERVCLASS_NAP)) &&
-       local_uuid->uu.uuid16 == UUID_SERVCLASS_NAP)) {
+       local_uuid16 == UUID_SERVCLASS_NAP)) {
     PAN_TRACE_ERROR(
         "PAN Connection failed because of unsupported destination UUID 0x%x",
-        local_uuid->uu.uuid16);
+        local_uuid16);
     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
     return;
   }
@@ -221,11 +154,10 @@
    * Note: the remote is the initiator.
    */
   bool is_valid_interaction = false;
-  switch (remote_uuid->uu.uuid16) {
+  switch (remote_uuid16) {
     case UUID_SERVCLASS_NAP:
     case UUID_SERVCLASS_GN:
-      if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
-        is_valid_interaction = true;
+      if (local_uuid16 == UUID_SERVCLASS_PANU) is_valid_interaction = true;
       break;
     case UUID_SERVCLASS_PANU:
       is_valid_interaction = true;
@@ -235,23 +167,24 @@
    * Explicitly disable connections to the local PANU if the remote is
    * not PANU.
    */
-  if ((local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) &&
-      (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU)) {
+  if ((local_uuid16 == UUID_SERVCLASS_PANU) &&
+      (remote_uuid16 != UUID_SERVCLASS_PANU)) {
     is_valid_interaction = false;
   }
   if (!is_valid_interaction) {
     PAN_TRACE_ERROR(
         "PAN Connection failed because of invalid PAN profile roles "
         "interaction: Remote UUID 0x%x Local UUID 0x%x",
-        remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+        remote_uuid16, local_uuid16);
     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
     return;
   }
 
+  uint8_t req_role;
   /* Requested destination role is */
-  if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+  if (local_uuid16 == UUID_SERVCLASS_PANU)
     req_role = PAN_ROLE_CLIENT;
-  else if (local_uuid->uu.uuid16 == UUID_SERVCLASS_GN)
+  else if (local_uuid16 == UUID_SERVCLASS_GN)
     req_role = PAN_ROLE_GN_SERVER;
   else
     req_role = PAN_ROLE_NAP_SERVER;
@@ -259,9 +192,9 @@
   /* If the connection indication is for the existing connection
   ** Check if the new destination role is acceptable
   */
-  pcb = pan_get_pcb_by_handle(handle);
+  tPAN_CONN* pcb = pan_get_pcb_by_handle(handle);
   if (pcb) {
-    if (pan_cb.num_conns > 1 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) {
+    if (pan_cb.num_conns > 1 && local_uuid16 == UUID_SERVCLASS_PANU) {
       /* There are connections other than this one
       ** so we cann't accept PANU role. Reject
       */
@@ -274,14 +207,14 @@
 
     /* If it is already in connected state check for bridging status */
     if (pcb->con_state == PAN_STATE_CONNECTED) {
-      PAN_TRACE_EVENT("PAN Role changing New Src 0x%x Dst 0x%x",
-                      remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+      PAN_TRACE_EVENT("PAN Role changing New Src 0x%x Dst 0x%x", remote_uuid16,
+                      local_uuid16);
 
       pcb->prv_src_uuid = pcb->src_uuid;
       pcb->prv_dst_uuid = pcb->dst_uuid;
 
       if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
-          local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP) {
+          local_uuid16 != UUID_SERVCLASS_NAP) {
         /* Remove bridging */
         if (pan_cb.pan_bridge_req_cb)
           (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
@@ -289,8 +222,8 @@
     }
     /* Set the latest active PAN role */
     pan_cb.active_role = req_role;
-    pcb->src_uuid = local_uuid->uu.uuid16;
-    pcb->dst_uuid = remote_uuid->uu.uuid16;
+    pcb->src_uuid = local_uuid16;
+    pcb->dst_uuid = remote_uuid16;
     BNEP_ConnectResp(handle, BNEP_SUCCESS);
     return;
   } else {
@@ -298,7 +231,7 @@
     ** we already have a connection then reject the request.
     ** If we have a connection in PANU role then reject it
     */
-    if (pan_cb.num_conns && (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU ||
+    if (pan_cb.num_conns && (local_uuid16 == UUID_SERVCLASS_PANU ||
                              pan_cb.active_role == PAN_ROLE_CLIENT)) {
       PAN_TRACE_ERROR("PAN already have a connection and can't be user");
       BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
@@ -315,12 +248,11 @@
     return;
   }
 
-  PAN_TRACE_EVENT("PAN connection destination UUID is 0x%x",
-                  local_uuid->uu.uuid16);
+  PAN_TRACE_EVENT("PAN connection destination UUID is 0x%x", local_uuid16);
   /* Set the latest active PAN role */
   pan_cb.active_role = req_role;
-  pcb->src_uuid = local_uuid->uu.uuid16;
-  pcb->dst_uuid = remote_uuid->uu.uuid16;
+  pcb->src_uuid = local_uuid16;
+  pcb->dst_uuid = remote_uuid16;
   pcb->con_state = PAN_STATE_CONN_START;
   pan_cb.num_conns++;
 
@@ -595,12 +527,11 @@
       if (pan_cb.pan_data_buf_ind_cb)
         (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf,
                                       ext, forward);
-      else if (pan_cb.pan_data_ind_cb) {
+      else if (pan_cb.pan_data_ind_cb)
         (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len,
                                   ext, forward);
-        osi_free(p_buf);
-      }
 
+      osi_free(p_buf);
       return;
     }
 
@@ -625,13 +556,10 @@
   if (pan_cb.pan_data_buf_ind_cb)
     (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf, ext,
                                   forward);
-  else if (pan_cb.pan_data_ind_cb) {
+  else if (pan_cb.pan_data_ind_cb)
     (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len, ext,
                               forward);
-    osi_free(p_buf);
-  } else
-    osi_free(p_buf);
-
+  osi_free(p_buf);
   return;
 }
 
diff --git a/stack/pan/pan_utils.cc b/stack/pan/pan_utils.cc
index b2eed2d..fa76200 100644
--- a/stack/pan/pan_utils.cc
+++ b/stack/pan/pan_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/rfcomm/port_api.cc b/stack/rfcomm/port_api.cc
index 808b567..1ae8667 100644
--- a/stack/rfcomm/port_api.cc
+++ b/stack/rfcomm/port_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -115,44 +115,45 @@
 int RFCOMM_CreateConnection(uint16_t uuid, uint8_t scn, bool is_server,
                             uint16_t mtu, const RawAddress& bd_addr,
                             uint16_t* p_handle, tPORT_CALLBACK* p_mgmt_cb) {
-  tPORT* p_port;
-  uint8_t dlci;
-  tRFC_MCB* p_mcb = port_find_mcb(bd_addr);
-  uint16_t rfcomm_mtu;
-
-  VLOG(0) << __func__ << " BDA: " << bd_addr;
-
   *p_handle = 0;
 
   if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
     /* Server Channel Number(SCN) should be in range 1...30 */
-    RFCOMM_TRACE_ERROR("RFCOMM_CreateConnection - invalid SCN");
+    LOG(ERROR) << __func__ << ": Invalid SCN, bd_addr=" << bd_addr
+               << ", scn=" << static_cast<int>(scn)
+               << ", is_server=" << is_server
+               << ", mtu=" << static_cast<int>(mtu)
+               << ", uuid=" << loghex(uuid);
     return (PORT_INVALID_SCN);
   }
 
   /* For client that originate connection on the existing none initiator */
   /* multiplexer channel DLCI should be odd */
-  if (p_mcb && !p_mcb->is_initiator && !is_server)
-    dlci = (scn << 1) + 1;
-  else
+  uint8_t dlci;
+  tRFC_MCB* p_mcb = port_find_mcb(bd_addr);
+  if (p_mcb && !p_mcb->is_initiator && !is_server) {
+    dlci = static_cast<uint8_t>((scn << 1) + 1);
+  } else {
     dlci = (scn << 1);
-  RFCOMM_TRACE_API(
-      "RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, "
-      "p_mcb:%p",
-      scn, dlci, is_server, mtu, p_mcb);
+  }
 
   /* 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 */
+  tPORT* p_port;
   if (!is_server) {
     p_port = port_find_port(dlci, bd_addr);
-    if (p_port != NULL) {
+    if (p_port != nullptr) {
       /* if existing port is also a client port */
-      if (p_port->is_server == false) {
-        RFCOMM_TRACE_ERROR(
-            "RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, "
-            "MCB state:%d",
-            p_port->state, p_port->rfc.state,
-            p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0);
+      if (!p_port->is_server) {
+        LOG(ERROR) << __func__ << ": already at opened state "
+                   << static_cast<int>(p_port->state)
+                   << ", RFC_state=" << static_cast<int>(p_port->rfc.state)
+                   << ", MCB_state="
+                   << (p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0)
+                   << ", 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;
         return (PORT_ALREADY_OPENED);
       }
@@ -160,17 +161,13 @@
   }
 
   p_port = port_allocate_port(dlci, bd_addr);
-  if (p_port == NULL) {
-    RFCOMM_TRACE_WARNING("RFCOMM_CreateConnection - no resources");
+  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);
   }
-  RFCOMM_TRACE_API(
-      "RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, "
-      "p_mcb:%p, p_port:%p",
-      scn, dlci, is_server, mtu, p_mcb, p_port);
-
-  p_port->default_signal_state =
-      (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
 
   switch (uuid) {
     case UUID_PROTOCOL_OBEX:
@@ -186,11 +183,12 @@
     case UUID_SERVCLASS_FAX:
       p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE;
       break;
+    default:
+      p_port->default_signal_state =
+          (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+      break;
   }
 
-  RFCOMM_TRACE_EVENT("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci,
-                     p_port->default_signal_state);
-
   *p_handle = p_port->inx;
 
   p_port->state = PORT_STATE_OPENING;
@@ -205,12 +203,13 @@
    * will know for sure our prefered MTU
    */
 
-  rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+  uint16_t rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
 
-  if (mtu)
+  if (mtu) {
     p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
-  else
+  } else {
     p_port->mtu = rfcomm_mtu;
+  }
 
   /* server doesn't need to release port when closing */
   if (is_server) {
@@ -228,6 +227,13 @@
 
   p_port->bd_addr = bd_addr;
 
+  LOG(INFO) << __func__ << ": bd_addr=" << bd_addr
+            << ", scn=" << std::to_string(scn) << ", is_server=" << is_server
+            << ", mtu=" << mtu << ", uuid=" << loghex(uuid)
+            << ", dlci=" << std::to_string(dlci)
+            << ", 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 (p_port->is_server) {
     return (PORT_SUCCESS);
@@ -1422,9 +1428,9 @@
   }
   int available = 0;
   // if(ioctl(fd, FIONREAD, &available) < 0)
-  if (p_port->p_data_co_callback(
-          handle, (uint8_t*)&available, sizeof(available),
-          DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == false) {
+  if (!p_port->p_data_co_callback(handle, (uint8_t*)&available,
+                                  sizeof(available),
+                                  DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE)) {
     RFCOMM_TRACE_ERROR(
         "p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, "
         "available:%d",
@@ -1447,9 +1453,9 @@
       (((int)p_buf->len + available) <= (int)length)) {
     // if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len,
     // available, 0) != available)
-    if (p_port->p_data_co_callback(
+    if (!p_port->p_data_co_callback(
             handle, (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len,
-            available, DATA_CO_CALLBACK_TYPE_OUTGOING) == false)
+            available, DATA_CO_CALLBACK_TYPE_OUTGOING))
 
     {
       error(
@@ -1503,9 +1509,9 @@
     // memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset, p_data, length);
     // if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset, (int)length, 0) !=
     // (int)length)
-    if (p_port->p_data_co_callback(
-            handle, (uint8_t*)(p_buf + 1) + p_buf->offset, length,
-            DATA_CO_CALLBACK_TYPE_OUTGOING) == false) {
+    if (!p_port->p_data_co_callback(handle,
+                                    (uint8_t*)(p_buf + 1) + p_buf->offset,
+                                    length, DATA_CO_CALLBACK_TYPE_OUTGOING)) {
       error(
           "p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d",
           length);
diff --git a/stack/rfcomm/port_int.h b/stack/rfcomm/port_int.h
index 018a9fad..db7d0fd 100644
--- a/stack/rfcomm/port_int.h
+++ b/stack/rfcomm/port_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/rfcomm/port_rfc.cc b/stack/rfcomm/port_rfc.cc
index f4e84ae..5ec5631 100644
--- a/stack/rfcomm/port_rfc.cc
+++ b/stack/rfcomm/port_rfc.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -282,14 +282,18 @@
     /* This can be a first request for this port */
     p_port = port_find_dlci_port(dlci);
     if (!p_port) {
+      LOG(ERROR) << __func__ << ": Disconnect RFCOMM, port not found, dlci="
+                 << std::to_string(dlci) << ", p_mcb=" << p_mcb
+                 << ", bd_addr=" << p_mcb->bd_addr;
       /* If the port cannot be opened, send a DM.  Per Errata 1205 */
       rfc_send_dm(p_mcb, dlci, false);
       /* check if this is the last port open, some headsets have
       problem, they don't disconnect if we send DM */
       rfc_check_mcb_active(p_mcb);
-      RFCOMM_TRACE_EVENT("PORT_ParNegInd: port not found");
       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;
   }
 
diff --git a/stack/rfcomm/port_utils.cc b/stack/rfcomm/port_utils.cc
index 1390e60..e9a9036 100644
--- a/stack/rfcomm/port_utils.cc
+++ b/stack/rfcomm/port_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -91,7 +91,7 @@
   }
 
   /* If here, no free PORT found */
-  return (NULL);
+  return nullptr;
 }
 
 /*******************************************************************************
@@ -104,7 +104,7 @@
  ******************************************************************************/
 void port_set_defaults(tPORT* p_port) {
   p_port->ev_mask = 0;
-  p_port->p_callback = NULL;
+  p_port->p_callback = nullptr;
   p_port->port_ctrl = 0;
   p_port->error = 0;
   p_port->line_status = 0;
@@ -207,12 +207,16 @@
 
   mutex_global_lock();
   BT_HDR* p_buf;
-  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
+  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue)) !=
+         nullptr) {
     osi_free(p_buf);
+  }
   p_port->rx.queue_size = 0;
 
-  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
+  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue)) !=
+         nullptr) {
     osi_free(p_buf);
+  }
   p_port->tx.queue_size = 0;
   mutex_global_unlock();
 
@@ -231,10 +235,10 @@
     rfc_port_timer_stop(p_port);
 
     mutex_global_lock();
-    fixed_queue_free(p_port->tx.queue, NULL);
-    p_port->tx.queue = NULL;
-    fixed_queue_free(p_port->rx.queue, NULL);
-    p_port->rx.queue = NULL;
+    fixed_queue_free(p_port->tx.queue, nullptr);
+    p_port->tx.queue = nullptr;
+    fixed_queue_free(p_port->rx.queue, nullptr);
+    p_port->rx.queue = nullptr;
     mutex_global_unlock();
 
     if (p_port->keep_port_handle) {
@@ -254,7 +258,7 @@
       p_port->mtu = p_port->keep_mtu;
 
       p_port->state = PORT_STATE_OPENING;
-      p_port->rfc.p_mcb = NULL;
+      p_port->rfc.p_mcb = nullptr;
       if (p_port->is_server) p_port->dlci &= 0xfe;
 
       p_port->local_ctrl.modem_signal = p_port->default_signal_state;
@@ -276,21 +280,16 @@
  *
  ******************************************************************************/
 tRFC_MCB* port_find_mcb(const RawAddress& bd_addr) {
-  int i;
-
-  for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
-    if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) &&
-        rfc_cb.port.rfc_mcb[i].bd_addr == bd_addr) {
+  for (tRFC_MCB& mcb : rfc_cb.port.rfc_mcb) {
+    if ((mcb.state != RFC_MX_STATE_IDLE) && (mcb.bd_addr == bd_addr)) {
       /* Multiplexer channel found do not change anything */
-      VLOG(1) << __func__ << ": found bd_addr:" << bd_addr;
-      RFCOMM_TRACE_DEBUG(
-          "port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d", i,
-          &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
-      return (&rfc_cb.port.rfc_mcb[i]);
+      VLOG(1) << __func__ << ": found bd_addr=" << bd_addr
+              << ", rfc_mcb=" << &mcb << ", lcid=" << loghex(mcb.lcid);
+      return &mcb;
     }
   }
   VLOG(1) << __func__ << ": not found, bd_addr:" << bd_addr;
-  return (NULL);
+  return nullptr;
 }
 
 /*******************************************************************************
@@ -306,20 +305,26 @@
  *
  ******************************************************************************/
 tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci) {
-  uint8_t inx;
+  if (!p_mcb) {
+    LOG(ERROR) << __func__ << ": p_mcb is null, dlci=" << std::to_string(dlci);
+    return nullptr;
+  }
 
-  if (!p_mcb) return (NULL);
+  if (dlci > RFCOMM_MAX_DLCI) {
+    LOG(WARNING) << __func__ << ": DLCI " << std::to_string(dlci)
+                 << " is too large, bd_addr=" << p_mcb->bd_addr
+                 << ", p_mcb=" << p_mcb;
+    return nullptr;
+  }
 
-  if (dlci > RFCOMM_MAX_DLCI) return (NULL);
-
-  inx = p_mcb->port_inx[dlci];
+  uint8_t inx = p_mcb->port_inx[dlci];
   if (inx == 0) {
-    RFCOMM_TRACE_DEBUG(
-        "port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb,
-        dlci);
-    return (NULL);
-  } else
-    return (&rfc_cb.port.port[inx - 1]);
+    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];
 }
 
 /*******************************************************************************
@@ -332,22 +337,17 @@
  *
  ******************************************************************************/
 tPORT* port_find_dlci_port(uint8_t dlci) {
-  uint16_t i;
-  tPORT* p_port;
-
-  for (i = 0; i < MAX_RFC_PORTS; i++) {
-    p_port = &rfc_cb.port.port[i];
-
-    if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
-      if (p_port->dlci == dlci) {
-        return (p_port);
-      } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
-        p_port->dlci++;
-        return (p_port);
+  for (tPORT& port : rfc_cb.port.port) {
+    if (port.in_use && (port.rfc.p_mcb == nullptr)) {
+      if (port.dlci == dlci) {
+        return &port;
+      } else if ((dlci & 0x01) && (port.dlci == (dlci - 1))) {
+        port.dlci++;
+        return &port;
       }
     }
   }
-  return (NULL);
+  return nullptr;
 }
 
 /*******************************************************************************
@@ -360,17 +360,12 @@
  *
  ******************************************************************************/
 tPORT* port_find_port(uint8_t dlci, const RawAddress& bd_addr) {
-  uint16_t i;
-  tPORT* p_port;
-
-  for (i = 0; i < MAX_RFC_PORTS; i++) {
-    p_port = &rfc_cb.port.port[i];
-    if (p_port->in_use && (p_port->dlci == dlci) &&
-        p_port->bd_addr == bd_addr) {
-      return (p_port);
+  for (tPORT& port : rfc_cb.port.port) {
+    if (port.in_use && (port.dlci == dlci) && (port.bd_addr == bd_addr)) {
+      return &port;
     }
   }
-  return (NULL);
+  return nullptr;
 }
 
 /*******************************************************************************
diff --git a/stack/rfcomm/rfc_int.h b/stack/rfcomm/rfc_int.h
index 93da38a..05afa9d 100644
--- a/stack/rfcomm/rfc_int.h
+++ b/stack/rfcomm/rfc_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -62,10 +62,7 @@
 
 extern void RFCOMM_TestReq(uint8_t* p_data, uint16_t len);
 
-#define RFCOMM_FLOW_STATE_DISABLE 0
-#define RFCOMM_FLOW_STATE_ENABLE 1
-
-extern void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t state);
+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);
diff --git a/stack/rfcomm/rfc_l2cap_if.cc b/stack/rfcomm/rfc_l2cap_if.cc
index f90f8da..a20f399 100644
--- a/stack/rfcomm/rfc_l2cap_if.cc
+++ b/stack/rfcomm/rfc_l2cap_if.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -147,9 +147,6 @@
     /* if peer rejects our connect request but peer's connect request is pending
      */
     if (result != L2CAP_CONN_OK) {
-      uint16_t i;
-      uint8_t idx;
-
       RFCOMM_TRACE_DEBUG(
           "RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)",
           p_mcb->pending_lcid);
@@ -165,13 +162,13 @@
       rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
 
       /* update direction bit */
-      for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
-        idx = p_mcb->port_inx[i];
+      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 - DLCI:%d -> %d", i,
+          RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", idx, i,
                              rfc_cb.port.port[idx - 1].dlci);
         }
       }
@@ -268,7 +265,7 @@
     return;
   }
 
-  rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, NULL);
+  rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr);
 }
 
 /*******************************************************************************
@@ -283,24 +280,27 @@
  ******************************************************************************/
 void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) {
   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
-  tPORT* p_port;
-  uint8_t event;
 
   if (!p_mcb) {
-    RFCOMM_TRACE_WARNING("RFCOMM_BufDataInd LCID:0x%x", lcid);
+    LOG(WARNING) << __func__ << ": Cannot find RFCOMM multiplexer for lcid "
+                 << loghex(lcid);
     osi_free(p_buf);
     return;
   }
 
-  event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
+  uint8_t event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
 
   /* If the frame did not pass validation just ignore it */
   if (event == RFC_EVENT_BAD_FRAME) {
+    LOG(WARNING) << __func__ << ": Bad RFCOMM frame from lcid=" << loghex(lcid)
+                 << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
     osi_free(p_buf);
     return;
   }
 
   if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
+    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) {
       rfc_process_mx_message(p_mcb, p_buf);
@@ -308,47 +308,62 @@
     }
 
     /* Other multiplexer events go to state machine */
-    rfc_mx_sm_execute(p_mcb, event, NULL);
+    rfc_mx_sm_execute(p_mcb, event, nullptr);
     osi_free(p_buf);
     return;
   }
 
   /* The frame was received on the data channel DLCI, verify that DLC exists */
-  if (((p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci)) ==
-       NULL) ||
-      (!p_port->rfc.p_mcb)) {
-    /* If this is a SABME on the new port, check if any appl is waiting for it
-     */
+  tPORT* p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci);
+  if (p_port == nullptr || !p_port->rfc.p_mcb) {
+    /* If this is a SABME on new port, check if any app is waiting for it */
     if (event != RFC_EVENT_SABME) {
+      LOG(WARNING) << __func__
+                   << ": no for none-SABME event, lcid=" << loghex(lcid)
+                   << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
       if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) ||
-          (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr))
+          (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) {
+        LOG(ERROR) << __func__
+                   << ": Disconnecting RFCOMM, lcid=" << loghex(lcid)
+                   << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
         rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
+      }
       osi_free(p_buf);
       return;
     }
 
     p_port = port_find_dlci_port(rfc_cb.rfc.rx_frame.dlci);
-    if (p_port == NULL) {
+    if (p_port == nullptr) {
+      LOG(ERROR) << __func__ << ":Disconnecting RFCOMM, no port for dlci "
+                 << +rfc_cb.rfc.rx_frame.dlci << ", lcid=" << loghex(lcid)
+                 << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
       rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true);
       osi_free(p_buf);
       return;
     }
+    RFCOMM_TRACE_DEBUG("%s: port_inx[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_port->rfc.p_mcb = p_mcb;
   }
 
   if (event == RFC_EVENT_UIH) {
-    if (p_buf->len > 0)
+    RFCOMM_TRACE_DEBUG("%s: Handling UIH event, buf_len=%u, credit=%u",
+                       __func__, p_buf->len, rfc_cb.rfc.rx_frame.credit);
+    if (p_buf->len > 0) {
       rfc_port_sm_execute(p_port, event, p_buf);
-    else
+    } else {
       osi_free(p_buf);
+    }
 
-    if (rfc_cb.rfc.rx_frame.credit != 0)
+    if (rfc_cb.rfc.rx_frame.credit != 0) {
       rfc_inc_credit(p_port, rfc_cb.rfc.rx_frame.credit);
+    }
 
     return;
   }
-  rfc_port_sm_execute(p_port, event, NULL);
+  rfc_port_sm_execute(p_port, event, nullptr);
   osi_free(p_buf);
 }
 
@@ -380,23 +395,20 @@
  *
  ******************************************************************************/
 tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid) {
-  tRFC_MCB* p_mcb;
-
   if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) {
     RFCOMM_TRACE_ERROR("rfc_find_lcid_mcb LCID:0x%x", lcid);
-    return (NULL);
+    return nullptr;
   } else {
-    p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID];
-    if (p_mcb != NULL) {
+    tRFC_MCB* p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID];
+    if (p_mcb != nullptr) {
       if (p_mcb->lcid != lcid) {
-        RFCOMM_TRACE_WARNING(
-            "rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid,
-            p_mcb->lcid);
-        return (NULL);
+        LOG(WARNING) << __func__ << "LCID reused lcid=:" << loghex(lcid)
+                     << ", current_lcid=" << loghex(p_mcb->lcid);
+        return nullptr;
       }
     }
+    return p_mcb;
   }
-  return (p_mcb);
 }
 
 /*******************************************************************************
diff --git a/stack/rfcomm/rfc_mx_fsm.cc b/stack/rfcomm/rfc_mx_fsm.cc
index 4f2785e..dfab62f 100644
--- a/stack/rfcomm/rfc_mx_fsm.cc
+++ b/stack/rfcomm/rfc_mx_fsm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/rfcomm/rfc_port_fsm.cc b/stack/rfcomm/rfc_port_fsm.cc
index 5157a75..4ff4628 100644
--- a/stack/rfcomm/rfc_port_fsm.cc
+++ b/stack/rfcomm/rfc_port_fsm.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -554,15 +554,22 @@
       PORT_ParNegInd(p_mcb, dlci, p_frame->u.pn.mtu, p_frame->u.pn.conv_layer,
                      p_frame->u.pn.k);
     } else {
+      LOG(WARNING) << __func__
+                   << ": MX PN while disconnecting, bd_addr=" << p_mcb->bd_addr
+                   << ", p_mcb=" << p_mcb;
       rfc_send_dm(p_mcb, dlci, false);
-      RFCOMM_TRACE_WARNING("***** MX PN while disconnecting *****");
     }
 
     return;
   }
   /* If we are not awaiting response just ignore it */
   p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if ((p_port == NULL) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) return;
+  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
+                 << ", dlci=" << std::to_string(dlci);
+    return;
+  }
 
   p_port->rfc.expected_rsp &= ~RFC_RSP_PN;
 
@@ -586,7 +593,7 @@
   tPORT* p_port;
 
   p_port = port_find_mcb_dlci_port(p_mcb, p_frame->dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     /* This is the first command on the port */
     if (is_command) {
       memset(&port_pars, 0, sizeof(tPORT_STATE));
@@ -600,7 +607,6 @@
 
   if (is_command && is_request) {
     /* This is the special situation when peer just request local pars */
-    port_pars = p_port->peer_port_pars;
     rfc_send_rpn(p_mcb, p_frame->dlci, false, &p_port->peer_port_pars, 0);
     return;
   }
@@ -617,9 +623,12 @@
 
   /* If we are not awaiting response just ignore it */
   p_port = port_find_mcb_dlci_port(p_mcb, p_frame->dlci);
-  if ((p_port == NULL) ||
-      !(p_port->rfc.expected_rsp & (RFC_RSP_RPN | RFC_RSP_RPN_REPLY)))
+  if ((p_port == nullptr) ||
+      !(p_port->rfc.expected_rsp & (RFC_RSP_RPN | RFC_RSP_RPN_REPLY))) {
+    LOG(WARNING) << __func__ << ": ignore DLC parameter negotiation as we are"
+                 << " not waiting for any";
     return;
+  }
 
   /* If we sent a request for port parameters to the peer he is replying with */
   /* mask 0. */
@@ -842,14 +851,11 @@
   p_mcb->l2cap_congested = is_congested;
 
   if (!is_congested) {
-    rfc_check_send_cmd(p_mcb, NULL);
+    rfc_check_send_cmd(p_mcb, nullptr);
   }
 
   if (!rfc_cb.rfc.peer_rx_disabled) {
-    if (!is_congested)
-      PORT_FlowInd(p_mcb, 0, true);
-    else
-      PORT_FlowInd(p_mcb, 0, false);
+    PORT_FlowInd(p_mcb, 0, !is_congested);
   }
 }
 
diff --git a/stack/rfcomm/rfc_port_if.cc b/stack/rfcomm/rfc_port_if.cc
index 4f8f38a..2ce5f9e 100644
--- a/stack/rfcomm/rfc_port_if.cc
+++ b/stack/rfcomm/rfc_port_if.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
  *
  *****************************************************************************/
 
-#include <string.h>
+#include <cstring>
 #include "bt_common.h"
 #include "bt_target.h"
 #include "bt_utils.h"
@@ -47,7 +47,7 @@
  *
  ******************************************************************************/
 void RFCOMM_StartReq(tRFC_MCB* p_mcb) {
-  rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, NULL);
+  rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, nullptr);
 }
 
 /*******************************************************************************
@@ -82,12 +82,12 @@
   }
 
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
 
-  rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
+  rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, nullptr);
 }
 
 /*******************************************************************************
@@ -106,7 +106,7 @@
   }
 
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
@@ -130,7 +130,7 @@
   uint8_t k;
 
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
@@ -193,12 +193,12 @@
  ******************************************************************************/
 void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
-    PORT_PortNegCnf(p_mcb, dlci, NULL, RFCOMM_ERROR);
+    PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
     return;
   }
 
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
@@ -238,7 +238,7 @@
  ******************************************************************************/
 void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
@@ -264,9 +264,9 @@
  *                  port can accept more data.
  *
  ******************************************************************************/
-void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t enable) {
+void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) {
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
@@ -293,7 +293,7 @@
  ******************************************************************************/
 void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  if (p_port == NULL) {
+  if (p_port == nullptr) {
     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     return;
   }
@@ -316,7 +316,8 @@
  *
  ******************************************************************************/
 void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
-  rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_CLOSE, 0);
+  rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_CLOSE,
+                      nullptr);
 }
 
 /*******************************************************************************
diff --git a/stack/rfcomm/rfc_ts_frames.cc b/stack/rfcomm/rfc_ts_frames.cc
index 93a8592..baf5614 100644
--- a/stack/rfcomm/rfc_ts_frames.cc
+++ b/stack/rfcomm/rfc_ts_frames.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -626,7 +626,9 @@
   p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
 
   if (!p_rx_frame->ea || !length) {
-    RFCOMM_TRACE_ERROR("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length);
+    LOG(ERROR) << __func__
+               << ": Invalid MX frame ea=" << std::to_string(p_rx_frame->ea)
+               << ", len=" << length << ", bd_addr=" << p_mcb->bd_addr;
     osi_free(p_buf);
     return;
   }
@@ -646,14 +648,21 @@
   }
 
   if (mx_len != length) {
-    RFCOMM_TRACE_ERROR("Bad MX frame");
+    LOG(ERROR) << __func__ << ": Bad MX frame, p_mcb=" << p_mcb
+               << ", bd_addr=" << p_mcb->bd_addr;
     osi_free(p_buf);
     return;
   }
 
+  RFCOMM_TRACE_DEBUG("%s: type=%d, p_mcb=%p", __func__, p_rx_frame->type,
+                     p_mcb);
   switch (p_rx_frame->type) {
     case RFCOMM_MX_PN:
-      if (length != RFCOMM_MX_PN_LEN) break;
+      if (length != RFCOMM_MX_PN_LEN) {
+        LOG(ERROR) << __func__ << ": Invalid PN length, p_mcb=" << p_mcb
+                   << ", bd_addr=" << p_mcb->bd_addr;
+        break;
+      }
 
       p_rx_frame->dlci = *p_data++ & RFCOMM_PN_DLCI_MASK;
       p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK;
@@ -668,7 +677,8 @@
       if (!p_rx_frame->dlci || !RFCOMM_VALID_DLCI(p_rx_frame->dlci) ||
           (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU) ||
           (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU)) {
-        RFCOMM_TRACE_ERROR("Bad PN frame");
+        LOG(ERROR) << __func__ << ": Bad PN frame, p_mcb=" << p_mcb
+                   << ", bd_addr=" << p_mcb->bd_addr;
         break;
       }
 
diff --git a/stack/rfcomm/rfc_utils.cc b/stack/rfcomm/rfc_utils.cc
index baf9aa0..74e336a 100644
--- a/stack/rfcomm/rfc_utils.cc
+++ b/stack/rfcomm/rfc_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -380,8 +380,7 @@
 
     RFCOMM_TRACE_EVENT("rfc_inc_credit:%d", p_port->credit_tx);
 
-    if (p_port->tx.peer_fc == true)
-      PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, true);
+    if (p_port->tx.peer_fc) PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, true);
   }
 }
 
@@ -426,7 +425,7 @@
   }
 
   /* handle queue if L2CAP not congested */
-  while (p_mcb->l2cap_congested == false) {
+  while (!p_mcb->l2cap_congested) {
     BT_HDR* p = (BT_HDR*)fixed_queue_try_dequeue(p_mcb->cmd_q);
     if (p == NULL) break;
     L2CA_DataWrite(p_mcb->lcid, p);
diff --git a/stack/sdp/sdp_api.cc b/stack/sdp/sdp_api.cc
index c89eca5..6e5f6f1 100644
--- a/stack/sdp/sdp_api.cc
+++ b/stack/sdp/sdp_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,6 +39,8 @@
 
 #include "osi/include/osi.h"
 
+using bluetooth::Uuid;
+
 /**********************************************************************
  *   C L I E N T    F U N C T I O N    P R O T O T Y P E S            *
  **********************************************************************/
@@ -66,7 +68,7 @@
  *
  ******************************************************************************/
 bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
-                         uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+                         uint16_t num_uuid, const Uuid* p_uuid_list,
                          uint16_t num_attr, uint16_t* p_attr_list) {
   uint16_t xx;
 
@@ -289,7 +291,7 @@
  * Returns          true if found, otherwise false.
  *
  ******************************************************************************/
-bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid) {
+bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
   tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
 
   p_attr = p_rec->p_first_attr;
@@ -300,18 +302,14 @@
       for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
            p_sattr = p_sattr->p_next_attr) {
         if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
-          if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16) {
-            p_uuid->len = LEN_UUID_16;
-            p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
+          if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == Uuid::kNumBytes16) {
+            *p_uuid = Uuid::From16Bit(p_sattr->attr_value.v.u16);
           } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
-                     LEN_UUID_128) {
-            p_uuid->len = LEN_UUID_128;
-            for (uint8_t i = 0; i != LEN_UUID_128; ++i)
-              p_uuid->uu.uuid128[i] =
-                  p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
-          } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32) {
-            p_uuid->len = LEN_UUID_32;
-            p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
+                     Uuid::kNumBytes128) {
+            *p_uuid = Uuid::From128BitBE(p_sattr->attr_value.v.array);
+          } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
+                     Uuid::kNumBytes32) {
+            *p_uuid = Uuid::From32Bit(p_sattr->attr_value.v.u32);
           }
 
           return (true);
@@ -332,8 +330,7 @@
                    UUID_DESC_TYPE)
                   /* only support 16 bits UUID for now */
                   && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) {
-                p_uuid->len = 2;
-                p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
+                *p_uuid = Uuid::From16Bit(p_extra_sattr->attr_value.v.u16);
                 return (true);
               }
             }
@@ -345,8 +342,7 @@
       if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
           /* only support 16 bits UUID for now */
           && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) {
-        p_uuid->len = 2;
-        p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
+        *p_uuid = Uuid::From16Bit(p_attr->attr_value.v.u16);
         return (true);
       }
     }
@@ -368,7 +364,7 @@
  * Returns          true if found, otherwise false.
  *
  ******************************************************************************/
-bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid) {
+bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
   tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr;
   while (p_attr) {
     if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
@@ -378,10 +374,7 @@
         if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
           /* only support 128 bits UUID for now */
           if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) {
-            p_uuid->len = LEN_UUID_128;
-            for (uint8_t i = 0; i != LEN_UUID_128; ++i)
-              p_uuid->uu.uuid128[i] =
-                  p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
+            *p_uuid = Uuid::From128BitBE(p_sattr->attr_value.v.array);
           }
           return (true);
         }
@@ -393,10 +386,7 @@
       if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
           /* only support 128 bits UUID for now */
           && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
-        p_uuid->len = LEN_UUID_128;
-        for (uint8_t i = 0; i != LEN_UUID_128; ++i)
-          p_uuid->uu.uuid128[i] =
-              p_attr->attr_value.v.array[LEN_UUID_128 - i - 1];
+        *p_uuid = Uuid::From128BitBE(p_attr->attr_value.v.array);
         return (true);
       }
     }
@@ -573,13 +563,13 @@
  *
  * NOTE             the only difference between this function and the previous
  *                  function "SDP_FindServiceInDb()" is that this function takes
- *                  a tBT_UUID input
+ *                  a Uuid input
  *
  * Returns          Pointer to record containing service class, or NULL
  *
  ******************************************************************************/
 tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
-                                       tBT_UUID* p_uuid,
+                                       const Uuid& uuid,
                                        tSDP_DISC_REC* p_start_rec) {
   tSDP_DISC_REC* p_rec;
   tSDP_DISC_ATTR *p_attr, *p_sattr;
@@ -601,13 +591,13 @@
         for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
              p_sattr = p_sattr->p_next_attr) {
           if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
-            if (sdpu_compare_uuid_with_attr(p_uuid, p_sattr)) return (p_rec);
+            if (sdpu_compare_uuid_with_attr(uuid, p_sattr)) return (p_rec);
           }
         }
         break;
       } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
         if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) {
-          if (sdpu_compare_uuid_with_attr(p_uuid, p_attr)) return (p_rec);
+          if (sdpu_compare_uuid_with_attr(uuid, p_attr)) return (p_rec);
         }
       }
 
@@ -730,7 +720,7 @@
         if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
             DATA_ELE_SEQ_DESC_TYPE) {
           ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem);
-          if (ret == true) break;
+          if (ret) break;
         }
       }
       return ret;
@@ -829,9 +819,7 @@
   uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
 
   /* build uuid for db init */
-  tSDP_UUID init_uuid;
-  init_uuid.len = 2;
-  init_uuid.uu.uuid16 = di_uuid;
+  Uuid init_uuid = Uuid::From16Bit(di_uuid);
 
   if (SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL))
     if (SDP_ServiceSearchRequest(remote_device, p_db, p_cb))
@@ -1011,8 +999,7 @@
   if (p_device_info == NULL) return SDP_ILLEGAL_PARAMETER;
 
   /* if record is to be primary record, get handle to replace old primary */
-  if (p_device_info->primary_record == true &&
-      sdp_cb.server_db.di_primary_handle)
+  if (p_device_info->primary_record && sdp_cb.server_db.di_primary_handle)
     handle = sdp_cb.server_db.di_primary_handle;
   else {
     handle = SDP_CreateRecord();
@@ -1023,7 +1010,7 @@
 
   /* build the SDP entry */
   /* Add the UUID to the Service Class ID List */
-  if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == false)
+  if (!(SDP_AddServiceClassIdList(handle, 1, &di_uuid)))
     result = SDP_DI_REG_FAILED;
 
   /* mandatory */
@@ -1120,7 +1107,7 @@
 
   if (result != SDP_SUCCESS)
     SDP_DeleteRecord(handle);
-  else if (p_device_info->primary_record == true)
+  else if (p_device_info->primary_record)
     sdp_cb.server_db.di_primary_handle = handle;
 
   return result;
diff --git a/stack/sdp/sdp_db.cc b/stack/sdp/sdp_db.cc
index 49f4269..d8cee9a 100644
--- a/stack/sdp/sdp_db.cc
+++ b/stack/sdp/sdp_db.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/sdp/sdp_discovery.cc b/stack/sdp/sdp_discovery.cc
index bf6f43b..365a70c 100644
--- a/stack/sdp/sdp_discovery.cc
+++ b/stack/sdp/sdp_discovery.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -37,6 +37,8 @@
 #include "sdp_api.h"
 #include "sdpint.h"
 
+using bluetooth::Uuid;
+
 #ifndef SDP_DEBUG_RAW
 #define SDP_DEBUG_RAW false
 #endif
@@ -72,7 +74,7 @@
  *
  ******************************************************************************/
 static uint8_t* sdpu_build_uuid_seq(uint8_t* p_out, uint16_t num_uuids,
-                                    tSDP_UUID* p_uuid_list) {
+                                    Uuid* p_uuid_list) {
   uint16_t xx;
   uint8_t* p_len;
 
@@ -85,18 +87,19 @@
 
   /* Now, loop through and put in all the UUID(s) */
   for (xx = 0; xx < num_uuids; xx++, p_uuid_list++) {
-    if (p_uuid_list->len == LEN_UUID_16) {
+    int len = p_uuid_list->GetShortestRepresentationSize();
+    if (len == Uuid::kNumBytes16) {
       UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
-      UINT16_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid16);
-    } else if (p_uuid_list->len == LEN_UUID_32) {
+      UINT16_TO_BE_STREAM(p_out, p_uuid_list->As16Bit());
+    } else if (len == Uuid::kNumBytes32) {
       UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
-      UINT32_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid32);
-    } else if (p_uuid_list->len == LEN_UUID_128) {
+      UINT32_TO_BE_STREAM(p_out, p_uuid_list->As32Bit());
+    } else if (len == Uuid::kNumBytes128) {
       UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
-      ARRAY_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid128, p_uuid_list->len);
+      ARRAY_TO_BE_STREAM(p_out, p_uuid_list->To128BitBE(),
+                         (int)Uuid::kNumBytes128);
     } else {
-      SDP_TRACE_ERROR("SDP: Passed UUID has invalid length %x",
-                      p_uuid_list->len);
+      DCHECK(0) << "SDP: Passed UUID has invalid length " << len;
     }
   }
 
@@ -914,12 +917,12 @@
                   (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2;
               p += 2;
               BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
-              p += MAX_UUID_SIZE - 4;
+              p += Uuid::kNumBytes128 - 4;
             } else {
               p_attr->attr_len_type =
                   (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4;
               BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
-              p += MAX_UUID_SIZE - 4;
+              p += Uuid::kNumBytes128 - 4;
             }
           } else {
             BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array,
diff --git a/stack/sdp/sdp_main.cc b/stack/sdp/sdp_main.cc
index 8f72aaa..3df37c5 100644
--- a/stack/sdp/sdp_main.cc
+++ b/stack/sdp/sdp_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -519,18 +519,19 @@
   /* Allocate a new CCB. Return if none available. */
   p_ccb = sdpu_allocate_ccb();
   if (p_ccb == NULL) {
-    SDP_TRACE_WARNING("SDP - no spare CCB for orig");
+    SDP_TRACE_WARNING("%s: no spare CCB for peer %s", __func__,
+                      p_bd_addr.ToString().c_str());
     return (NULL);
   }
 
-  SDP_TRACE_EVENT("SDP - Originate started");
+  SDP_TRACE_EVENT("%s: SDP - Originate started for peer %s", __func__,
+                  p_bd_addr.ToString().c_str());
 
   /* We are the originator of this connection */
   p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
 
   /* Save the BD Address and Channel ID. */
   p_ccb->device_address = p_bd_addr;
-  ;
 
   /* Transition to the next appropriate state, waiting for connection confirm.
    */
@@ -539,15 +540,14 @@
   cid = L2CA_ConnectReq(SDP_PSM, p_bd_addr);
 
   /* Check if L2CAP started the connection process */
-  if (cid != 0) {
-    p_ccb->connection_id = cid;
-
-    return (p_ccb);
-  } else {
-    SDP_TRACE_WARNING("SDP - Originate failed");
+  if (cid == 0) {
+    SDP_TRACE_WARNING("%s: SDP - Originate failed for peer %s", __func__,
+                      p_bd_addr.ToString().c_str());
     sdpu_release_ccb(p_ccb);
     return (NULL);
   }
+  p_ccb->connection_id = cid;
+  return (p_ccb);
 }
 
 /*******************************************************************************
diff --git a/stack/sdp/sdp_server.cc b/stack/sdp/sdp_server.cc
index 510b8dc..386f62f 100644
--- a/stack/sdp/sdp_server.cc
+++ b/stack/sdp/sdp_server.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -635,7 +635,7 @@
        p_rec; p_rec = sdp_db_service_search(p_rec, &uid_seq)) {
     /* Allow space for attribute sequence type and length */
     p_seq_start = p_rsp;
-    if (p_ccb->cont_info.last_attr_seq_desc_sent == false) {
+    if (!p_ccb->cont_info.last_attr_seq_desc_sent) {
       /* See if there is enough room to include a new service in the current
        * response */
       rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
@@ -717,7 +717,7 @@
     }
 
     /* Go back and put the type and length into the buffer */
-    if (p_ccb->cont_info.last_attr_seq_desc_sent == false) {
+    if (!p_ccb->cont_info.last_attr_seq_desc_sent) {
       seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
       if (seq_len != 0) {
         UINT8_TO_BE_STREAM(p_seq_start,
diff --git a/stack/sdp/sdp_utils.cc b/stack/sdp/sdp_utils.cc
index e6589d4..c57a499 100644
--- a/stack/sdp/sdp_utils.cc
+++ b/stack/sdp/sdp_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
 
 #include "btu.h"
 
+using bluetooth::Uuid;
 static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                         0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
                                         0x5F, 0x9B, 0x34, 0xFB};
@@ -593,7 +594,7 @@
 bool sdpu_is_base_uuid(uint8_t* p_uuid) {
   uint16_t xx;
 
-  for (xx = 4; xx < MAX_UUID_SIZE; xx++)
+  for (xx = 4; xx < Uuid::kNumBytes128; xx++)
     if (p_uuid[xx] != sdp_base_uuid[xx]) return (false);
 
   /* If here, matched */
@@ -614,8 +615,8 @@
  ******************************************************************************/
 bool sdpu_compare_uuid_arrays(uint8_t* p_uuid1, uint32_t len1, uint8_t* p_uuid2,
                               uint16_t len2) {
-  uint8_t nu1[MAX_UUID_SIZE];
-  uint8_t nu2[MAX_UUID_SIZE];
+  uint8_t nu1[Uuid::kNumBytes128];
+  uint8_t nu2[Uuid::kNumBytes128];
 
   if (((len1 != 2) && (len1 != 4) && (len1 != 16)) ||
       ((len2 != 2) && (len2 != 4) && (len2 != 16))) {
@@ -639,15 +640,15 @@
               (p_uuid1[2] == p_uuid2[0]) && (p_uuid1[3] == p_uuid2[1]));
     } else {
       /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
-      memcpy(nu1, p_uuid1, MAX_UUID_SIZE);
-      memcpy(nu2, sdp_base_uuid, MAX_UUID_SIZE);
+      memcpy(nu1, p_uuid1, Uuid::kNumBytes128);
+      memcpy(nu2, sdp_base_uuid, Uuid::kNumBytes128);
 
       if (len2 == 4)
         memcpy(nu2, p_uuid2, len2);
       else if (len2 == 2)
         memcpy(nu2 + 2, p_uuid2, len2);
 
-      return (memcmp(nu1, nu2, MAX_UUID_SIZE) == 0);
+      return (memcmp(nu1, nu2, Uuid::kNumBytes128) == 0);
     }
   } else {
     /* len2 is greater than len1 */
@@ -657,47 +658,21 @@
               (p_uuid2[2] == p_uuid1[0]) && (p_uuid2[3] == p_uuid1[1]));
     } else {
       /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
-      memcpy(nu2, p_uuid2, MAX_UUID_SIZE);
-      memcpy(nu1, sdp_base_uuid, MAX_UUID_SIZE);
+      memcpy(nu2, p_uuid2, Uuid::kNumBytes128);
+      memcpy(nu1, sdp_base_uuid, Uuid::kNumBytes128);
 
       if (len1 == 4)
         memcpy(nu1, p_uuid1, (size_t)len1);
       else if (len1 == 2)
         memcpy(nu1 + 2, p_uuid1, (size_t)len1);
 
-      return (memcmp(nu1, nu2, MAX_UUID_SIZE) == 0);
+      return (memcmp(nu1, nu2, Uuid::kNumBytes128) == 0);
     }
   }
 }
 
 /*******************************************************************************
  *
- * Function         sdpu_compare_bt_uuids
- *
- * Description      This function compares 2 BT UUID structures.
- *
- * NOTE             it is assumed that BT UUID structures are compressed to the
- *                  smallest possible UUIDs (by removing the base SDP UUID)
- *
- * Returns          true if matched, else false
- *
- ******************************************************************************/
-bool sdpu_compare_bt_uuids(tBT_UUID* p_uuid1, tBT_UUID* p_uuid2) {
-  /* Lengths must match for BT UUIDs to match */
-  if (p_uuid1->len == p_uuid2->len) {
-    if (p_uuid1->len == 2)
-      return (p_uuid1->uu.uuid16 == p_uuid2->uu.uuid16);
-    else if (p_uuid1->len == 4)
-      return (p_uuid1->uu.uuid32 == p_uuid2->uu.uuid32);
-    else if (!memcmp(p_uuid1->uu.uuid128, p_uuid2->uu.uuid128, 16))
-      return (true);
-  }
-
-  return (false);
-}
-
-/*******************************************************************************
- *
  * Function         sdpu_compare_uuid_with_attr
  *
  * Description      This function compares a BT UUID structure with the UUID in
@@ -712,18 +687,12 @@
  * Returns          true if matched, else false
  *
  ******************************************************************************/
-bool sdpu_compare_uuid_with_attr(tBT_UUID* p_btuuid, tSDP_DISC_ATTR* p_attr) {
-  uint16_t attr_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
-
-  /* Since both UUIDs are compressed, lengths must match  */
-  if (p_btuuid->len != attr_len) return (false);
-
-  if (p_btuuid->len == 2)
-    return (bool)(p_btuuid->uu.uuid16 == p_attr->attr_value.v.u16);
-  else if (p_btuuid->len == 4)
-    return (bool)(p_btuuid->uu.uuid32 == p_attr->attr_value.v.u32);
-  else if (!memcmp(p_btuuid->uu.uuid128, (void*)p_attr->attr_value.v.array,
-                   MAX_UUID_SIZE))
+bool sdpu_compare_uuid_with_attr(const Uuid& uuid, tSDP_DISC_ATTR* p_attr) {
+  int len = uuid.GetShortestRepresentationSize();
+  if (len == 2) return uuid.As16Bit() == p_attr->attr_value.v.u16;
+  if (len == 4) return uuid.As32Bit() == p_attr->attr_value.v.u32;
+  if (memcmp(uuid.To128BitBE().data(), (void*)p_attr->attr_value.v.array,
+             Uuid::kNumBytes128) == 0)
     return (true);
 
   return (false);
@@ -811,7 +780,7 @@
   uint16_t start_id = 0, end_id = 0;
 
   for (xx = 0; xx < attr_seq->num_attr; xx++) {
-    if (is_range == false) {
+    if (!is_range) {
       start_id = attr_seq->attr_entry[xx].start;
       end_id = attr_seq->attr_entry[xx].end;
     }
@@ -927,25 +896,3 @@
   osi_free(p_attr_buff);
   return p_out;
 }
-
-/*******************************************************************************
- *
- * Function         sdpu_uuid16_to_uuid128
- *
- * Description      This function converts UUID-16 to UUID-128 by including the
- *                  base UUID
- *
- *                  uuid16: 2-byte UUID
- *                  p_uuid128: Expanded 128-bit UUID
- *
- * Returns          None
- *
- ******************************************************************************/
-void sdpu_uuid16_to_uuid128(uint16_t uuid16, uint8_t* p_uuid128) {
-  uint16_t uuid16_bo;
-  memset(p_uuid128, 0, 16);
-
-  memcpy(p_uuid128, sdp_base_uuid, MAX_UUID_SIZE);
-  uuid16_bo = ntohs(uuid16);
-  memcpy(p_uuid128 + 2, &uuid16_bo, sizeof(uint16_t));
-}
diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
index a2d5089..0d44c9d 100644
--- a/stack/sdp/sdpint.h
+++ b/stack/sdp/sdpint.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 #ifndef SDP_INT_H
 #define SDP_INT_H
 
+#include "bluetooth/uuid.h"
 #include "bt_target.h"
 #include "l2c_api.h"
 #include "osi/include/alarm.h"
@@ -65,7 +66,7 @@
 #define SDP_DEVICE_NOTI_FLAG 0x03
 
 /* Define the Protocol Data Unit (PDU) types.
-*/
+ */
 #define SDP_PDU_ERROR_RESPONSE 0x01
 #define SDP_PDU_SERVICE_SEARCH_REQ 0x02
 #define SDP_PDU_SERVICE_SEARCH_RSP 0x03
@@ -88,7 +89,7 @@
 /* Internal UUID sequence representation */
 typedef struct {
   uint16_t len;
-  uint8_t value[MAX_UUID_SIZE];
+  uint8_t value[bluetooth::Uuid::kNumBytes128];
 } tUID_ENT;
 
 typedef struct {
@@ -230,7 +231,7 @@
 #endif
 
 /* Functions provided by sdp_conn.cc
-*/
+ */
 extern void sdp_conn_rcv_l2e_conn_ind(BT_HDR* p_msg);
 extern void sdp_conn_rcv_l2e_conn_cfm(BT_HDR* p_msg);
 extern void sdp_conn_rcv_l2e_disc(BT_HDR* p_msg);
@@ -245,7 +246,7 @@
 extern tCONN_CB* sdp_conn_originate(const RawAddress& p_bd_addr);
 
 /* Functions provided by sdp_utils.cc
-*/
+ */
 extern tCONN_CB* sdpu_find_ccb_by_cid(uint16_t cid);
 extern tCONN_CB* sdpu_find_ccb_by_db(tSDP_DISCOVERY_DB* p_db);
 extern tCONN_CB* sdpu_allocate_ccb(void);
@@ -267,8 +268,7 @@
 extern bool sdpu_is_base_uuid(uint8_t* p_uuid);
 extern bool sdpu_compare_uuid_arrays(uint8_t* p_uuid1, uint32_t len1,
                                      uint8_t* p_uuid2, uint16_t len2);
-extern bool sdpu_compare_bt_uuids(tBT_UUID* p_uuid1, tBT_UUID* p_uuid2);
-extern bool sdpu_compare_uuid_with_attr(tBT_UUID* p_btuuid,
+extern bool sdpu_compare_uuid_with_attr(const bluetooth::Uuid& uuid,
                                         tSDP_DISC_ATTR* p_attr);
 
 extern void sdpu_sort_attr_list(uint16_t num_attr, tSDP_DISCOVERY_DB* p_db);
@@ -282,7 +282,7 @@
                                                 uint16_t len, uint16_t* offset);
 
 /* Functions provided by sdp_db.cc
-*/
+ */
 extern tSDP_RECORD* sdp_db_service_search(tSDP_RECORD* p_rec,
                                           tSDP_UUID_SEQ* p_seq);
 extern tSDP_RECORD* sdp_db_find_record(uint32_t handle);
@@ -291,7 +291,7 @@
                                                uint16_t end_attr);
 
 /* Functions provided by sdp_server.cc
-*/
+ */
 #if (SDP_SERVER_ENABLED == TRUE)
 extern void sdp_server_handle_client_req(tCONN_CB* p_ccb, BT_HDR* p_msg);
 #else
@@ -299,7 +299,7 @@
 #endif
 
 /* Functions provided by sdp_discovery.cc
-*/
+ */
 extern void sdp_disc_connected(tCONN_CB* p_ccb);
 extern void sdp_disc_server_rsp(tCONN_CB* p_ccb, BT_HDR* p_msg);
 
diff --git a/stack/smp/p_256_curvepara.cc b/stack/smp/p_256_curvepara.cc
index d9bee31..5fb71a3 100644
--- a/stack/smp/p_256_curvepara.cc
+++ b/stack/smp/p_256_curvepara.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2015 Broadcom Corporation
+ *  Copyright 2006-2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/smp/p_256_ecc_pp.cc b/stack/smp/p_256_ecc_pp.cc
index b416e1d..ff5dbde 100644
--- a/stack/smp/p_256_ecc_pp.cc
+++ b/stack/smp/p_256_ecc_pp.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2015 Broadcom Corporation
+ *  Copyright 2006-2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -245,3 +245,25 @@
   multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
   multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
 }
+
+bool ECC_ValidatePoint(const Point& pt) {
+  const size_t kl = KEY_LENGTH_DWORDS_P256;
+  p_256_init_curve(kl);
+
+  // Ensure y^2 = x^3 + a*x + b (mod p); a = -3
+
+  // y^2 mod p
+  uint32_t y2_mod[kl] = {0};
+  multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y, kl);
+
+  // Right hand side calculation
+  uint32_t rhs[kl] = {0};
+  multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x, kl);
+  uint32_t three[kl] = {0};
+  three[0] = 3;
+  multiprecision_sub_mod(rhs, rhs, three, kl);
+  multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x, kl);
+  multiprecision_add_mod(rhs, rhs, curve_p256.b, kl);
+
+  return multiprecision_compare(rhs, y2_mod, kl) == 0;
+}
diff --git a/stack/smp/p_256_ecc_pp.h b/stack/smp/p_256_ecc_pp.h
index dcc4211..b49b72a 100644
--- a/stack/smp/p_256_ecc_pp.h
+++ b/stack/smp/p_256_ecc_pp.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2015 Broadcom Corporation
+ *  Copyright 2006-2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include <cstdbool>
 #include "p_256_multprecision.h"
 
 typedef struct {
@@ -55,6 +56,8 @@
 extern elliptic_curve_t curve;
 extern elliptic_curve_t curve_p256;
 
+bool ECC_ValidatePoint(const Point& p);
+
 void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n, uint32_t keyLength);
 
 #define ECC_PointMult(q, p, n, keyLength) \
diff --git a/stack/smp/p_256_multprecision.cc b/stack/smp/p_256_multprecision.cc
index a44ea0c..286aca1 100644
--- a/stack/smp/p_256_multprecision.cc
+++ b/stack/smp/p_256_multprecision.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2015 Broadcom Corporation
+ *  Copyright 2006-2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/smp/p_256_multprecision.h b/stack/smp/p_256_multprecision.h
index ca5311b..fbbd88d 100644
--- a/stack/smp/p_256_multprecision.h
+++ b/stack/smp/p_256_multprecision.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2006-2015 Broadcom Corporation
+ *  Copyright 2006-2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index df9fab9..be340ec 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,17 +19,21 @@
 #include <string.h>
 #include "btif_common.h"
 #include "device/include/interop.h"
-#include "include/bt_target.h"
+#include "internal_include/bt_target.h"
 #include "stack/btm/btm_int.h"
 #include "stack/include/l2c_api.h"
+#include "stack/smp/p_256_ecc_pp.h"
 #include "stack/smp/smp_int.h"
 #include "utils/include/bt_utils.h"
 
 #define SMP_KEY_DIST_TYPE_MAX 4
 
-const tSMP_ACT smp_distribute_act[] = {smp_generate_ltk, smp_send_id_info,
-                                       smp_generate_csrk,
-                                       smp_set_derive_link_key};
+const tSMP_ACT smp_distribute_act[] = {
+    smp_generate_ltk,       /* SMP_SEC_KEY_TYPE_ENC - '1' bit index */
+    smp_send_id_info,       /* SMP_SEC_KEY_TYPE_ID - '1' bit index */
+    smp_generate_csrk,      /* SMP_SEC_KEY_TYPE_CSRK - '1' bit index */
+    smp_set_derive_link_key /* SMP_SEC_KEY_TYPE_LK - '1' bit index */
+};
 
 static bool lmp_version_below(const RawAddress& bda, uint8_t version) {
   tACL_CONN* acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE);
@@ -47,7 +51,9 @@
   if (reason == SMP_PAIR_AUTH_FAIL || reason == SMP_PAIR_FAIL_UNKNOWN ||
       reason == SMP_PAIR_NOT_SUPPORT || reason == SMP_PASSKEY_ENTRY_FAIL ||
       reason == SMP_REPEATED_ATTEMPTS) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = reason;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return true;
   }
   return false;
@@ -160,15 +166,17 @@
 
           p_cb->secure_connections_only_mode_required =
               (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false;
-
+          /* just for PTS, force SC bit */
           if (p_cb->secure_connections_only_mode_required) {
             p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT;
           }
 
-          if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) ||
-              lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2) ||
-              interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
-                                 (const RawAddress*)&p_cb->pairing_bda)) {
+          if (!p_cb->secure_connections_only_mode_required &&
+              (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) ||
+               lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2) ||
+               interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
+                                  (const RawAddress*)&p_cb->pairing_bda))) {
+            p_cb->loc_auth_req &= ~SMP_SC_SUPPORT_BIT;
             p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT;
             p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
             p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
@@ -219,8 +227,8 @@
  * Description  pairing failure to peer device if needed.
  ******************************************************************************/
 void smp_send_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  p_cb->status = *(uint8_t*)p_data;
-  p_cb->failure = *(uint8_t*)p_data;
+  p_cb->status = p_data->status;
+  p_cb->failure = p_data->status;
 
   SMP_TRACE_DEBUG("%s: status=%d failure=%d ", __func__, p_cb->status,
                   p_cb->failure);
@@ -324,7 +332,7 @@
  * Description send Keypress Notification command to the peer
  ******************************************************************************/
 void smp_send_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  p_cb->local_keypress_notification = *(uint8_t*)p_data;
+  p_cb->local_keypress_notification = p_data->status;
   smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb);
 }
 
@@ -415,7 +423,6 @@
 void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
   tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ*)p_data;
   tBTM_BLE_SEC_REQ_ACT sec_req_act;
-  uint8_t reason;
 
   SMP_TRACE_DEBUG("%s: auth_req=0x%x", __func__, auth_req);
 
@@ -438,8 +445,9 @@
       /* respond to non SC pairing request as failure in SC only mode */
       if (p_cb->secure_connections_only_mode_required &&
           (auth_req & SMP_SC_SUPPORT_BIT) == 0) {
-        reason = SMP_PAIR_AUTH_FAIL;
-        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        tSMP_INT_DATA smp_int_data;
+        smp_int_data.status = SMP_PAIR_AUTH_FAIL;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
       } else {
         /* initialize local i/r key to be default keys */
         p_cb->peer_auth_req = auth_req;
@@ -463,7 +471,7 @@
  * Description  process security grant.
  ******************************************************************************/
 void smp_proc_sec_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t res = *(uint8_t*)p_data;
+  uint8_t res = p_data->status;
   SMP_TRACE_DEBUG("%s", __func__);
   if (res != SMP_SUCCESS) {
     smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data);
@@ -480,7 +488,7 @@
  ******************************************************************************/
 void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
   SMP_TRACE_DEBUG("%s", __func__);
-  p_cb->status = *(uint8_t*)p_data;
+  p_cb->status = p_data->status;
 
   /* Cancel pending auth complete timer if set */
   alarm_cancel(p_cb->delayed_auth_timer_ent);
@@ -491,11 +499,12 @@
  * Description  Process the SMP pairing request/response from peer device
  ******************************************************************************/
 void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_ENC_KEY_SIZE;
+  uint8_t* p = p_data->p_data;
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda);
 
-  SMP_TRACE_DEBUG("%s", __func__);
+  SMP_TRACE_DEBUG("%s: pairing_bda=%s", __func__,
+                  p_cb->pairing_bda.ToString().c_str());
+
   /* erase all keys if it is slave proc pairing req */
   if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE))
     btm_sec_clear_ble_keys(p_dev_rec);
@@ -510,8 +519,9 @@
   STREAM_TO_UINT8(p_cb->peer_r_key, p);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    reason = SMP_INVALID_PARAMETERS;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -539,8 +549,9 @@
         SMP_TRACE_ERROR(
             "%s: pairing failed - slave requires secure connection only mode",
             __func__);
-        reason = SMP_PAIR_AUTH_FAIL;
-        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        tSMP_INT_DATA smp_int_data;
+        smp_int_data.status = SMP_PAIR_AUTH_FAIL;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
         return;
       }
 
@@ -560,8 +571,9 @@
       SMP_TRACE_ERROR(
           "Master requires secure connection only mode "
           "but it can't be provided -> Master fails pairing");
-      reason = SMP_PAIR_AUTH_FAIL;
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+      tSMP_INT_DATA smp_int_data;
+      smp_int_data.status = SMP_PAIR_AUTH_FAIL;
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
       return;
     }
 
@@ -578,13 +590,14 @@
  * Description  process pairing confirm from peer device
  ******************************************************************************/
 void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -601,13 +614,14 @@
  * Description  process pairing initializer from peer device
  ******************************************************************************/
 void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -620,13 +634,14 @@
  * Description  process pairing random (nonce) from peer device
  ******************************************************************************/
 void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -643,18 +658,32 @@
  *
  ******************************************************************************/
 void smp_process_pairing_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
   STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
   STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
+
+  Point pt;
+  memcpy(pt.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
+  memcpy(pt.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
+
+  if (!ECC_ValidatePoint(pt)) {
+    android_errorWriteLog(0x534e4554, "72377774");
+    tSMP_INT_DATA smp;
+    smp.status = SMP_PAIR_AUTH_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp);
+    return;
+  }
+
   p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
 
   smp_wait_for_both_public_keys(p_cb, NULL);
@@ -665,13 +694,14 @@
  * Description  process pairing commitment from peer device
  ******************************************************************************/
 void smp_process_pairing_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -687,13 +717,14 @@
  * Description  process DHKey Check from peer device
  ******************************************************************************/
 void smp_process_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -709,14 +740,15 @@
  * Description  process pairing keypress notification from peer device
  ******************************************************************************/
 void smp_process_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_INVALID_PARAMETERS;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
-  p_cb->status = *(uint8_t*)p_data;
+  p_cb->status = p_data->status;
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -734,15 +766,15 @@
  *              BR/EDR transport.
  ******************************************************************************/
 void smp_br_process_pairing_command(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
-  uint8_t reason = SMP_ENC_KEY_SIZE;
+  uint8_t* p = p_data->p_data;
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda);
 
   SMP_TRACE_DEBUG("%s", __func__);
   /* rejecting BR pairing request over non-SC BR link */
   if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) {
-    reason = SMP_XTRANS_DERIVE_NOT_ALLOW;
-    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_XTRANS_DERIVE_NOT_ALLOW;
+    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -760,8 +792,9 @@
   STREAM_TO_UINT8(p_cb->peer_r_key, p);
 
   if (smp_command_has_invalid_parameters(p_cb)) {
-    reason = SMP_INVALID_PARAMETERS;
-    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -793,9 +826,8 @@
  * Description  process security grant in case of pairing over BR/EDR transport.
  ******************************************************************************/
 void smp_br_process_security_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t res = *(uint8_t*)p_data;
   SMP_TRACE_DEBUG("%s", __func__);
-  if (res != SMP_SUCCESS) {
+  if (p_data->status != SMP_SUCCESS) {
     smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data);
   } else {
     /* otherwise, start pairing; send IO request callback */
@@ -809,8 +841,6 @@
  *              before starting the distribution/derivation
  ******************************************************************************/
 void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t reason = SMP_SUCCESS;
-
   SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x (i-initiator r-responder)",
                   __func__, p_cb->local_i_key, p_cb->local_r_key);
 
@@ -844,7 +874,9 @@
     if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0)
       smp_key_distribution_by_transport(p_cb, NULL);
   } else {
-    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_SUCCESS;
+    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
   }
 }
 
@@ -854,7 +886,6 @@
  *              used.
  ******************************************************************************/
 void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t reason = SMP_SUCCESS;
   SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", __func__,
                   p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
 
@@ -866,10 +897,13 @@
   if (!p_cb->local_i_key && !p_cb->local_r_key) {
     /* state check to prevent re-entrance */
     if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) {
-      if (p_cb->total_tx_unacked == 0)
-        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
-      else
+      if (p_cb->total_tx_unacked == 0) {
+        tSMP_INT_DATA smp_int_data;
+        smp_int_data.status = SMP_SUCCESS;
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
+      } else {
         p_cb->wait_for_authorization_complete = true;
+      }
     }
   }
 }
@@ -879,7 +913,7 @@
  * Description  process encryption information from peer device
  ******************************************************************************/
 void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
   STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
@@ -891,7 +925,7 @@
  * Description  process master ID from slave device
  ******************************************************************************/
 void smp_proc_master_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
+  uint8_t* p = p_data->p_data;
   tBTM_LE_PENC_KEYS le_key;
 
   SMP_TRACE_DEBUG("%s", __func__);
@@ -918,7 +952,7 @@
  * Description  process identity information from peer device
  ******************************************************************************/
 void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
+  uint8_t* p = p_data->p_data;
 
   SMP_TRACE_DEBUG("%s", __func__);
   STREAM_TO_ARRAY(p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
@@ -930,7 +964,7 @@
  * Description  process identity address from peer device
  ******************************************************************************/
 void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t* p = (uint8_t*)p_data;
+  uint8_t* p = p_data->p_data;
   tBTM_LE_PID_KEYS pid_key;
 
   SMP_TRACE_DEBUG("%s", __func__);
@@ -967,7 +1001,7 @@
   le_key.sec_level = p_cb->sec_level;
 
   /* get peer CSRK */
-  maybe_non_aligned_memcpy(le_key.csrk, p_data, BT_OCTET16_LEN);
+  maybe_non_aligned_memcpy(le_key.csrk, p_data->p_data, BT_OCTET16_LEN);
 
   /* initialize the peer counter */
   le_key.counter = 0;
@@ -984,8 +1018,6 @@
  * Description  process compare value
  ******************************************************************************/
 void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t reason;
-
   SMP_TRACE_DEBUG("%s", __func__);
   if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) {
     /* compare the max encryption key size, and save the smaller one for the
@@ -1004,8 +1036,10 @@
     }
 
   } else {
-    reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_CONFIRM_VALUE_ERR;
+    p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   }
 }
 
@@ -1033,7 +1067,6 @@
  ******************************************************************************/
 void smp_start_enc(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
   tBTM_STATUS cmd;
-  uint8_t reason = SMP_ENC_FAIL;
 
   SMP_TRACE_DEBUG("%s", __func__);
   if (p_data != NULL)
@@ -1041,8 +1074,11 @@
   else
     cmd = btm_ble_start_encrypt(p_cb->pairing_bda, false, NULL);
 
-  if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY)
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+  if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_ENC_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+  }
 }
 
 /*******************************************************************************
@@ -1060,11 +1096,12 @@
  * Description   encryption success
  ******************************************************************************/
 void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t enc_enable = *(uint8_t*)p_data;
-  uint8_t reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+  uint8_t enc_enable = p_data->status;
 
   SMP_TRACE_DEBUG("%s", __func__);
-  smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.status = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+  smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -1072,8 +1109,7 @@
  * Description  check authentication request
  ******************************************************************************/
 void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t enc_enable = *(uint8_t*)p_data;
-  uint8_t reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+  uint8_t enc_enable = p_data->status;
 
   SMP_TRACE_DEBUG(
       "%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x (i-initiator r-responder)",
@@ -1110,16 +1146,21 @@
          (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
         (p_cb->local_i_key || p_cb->local_r_key)) {
       smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL);
-    } else
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    } else {
+      tSMP_INT_DATA smp_int_data;
+      smp_int_data.status = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+    }
   } else if (enc_enable == 0) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
     /* if failed for encryption after pairing, send callback */
     if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR)
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     /* if enc failed for old security information */
     /* if master device, clean up and abck to idle; slave device do nothing */
     else if (p_cb->role == HCI_ROLE_MASTER) {
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     }
   }
 }
@@ -1194,10 +1235,8 @@
  *
  ******************************************************************************/
 void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t failure = SMP_UNKNOWN_IO_CAP;
   uint8_t int_evt = 0;
-  tSMP_KEY key;
-  tSMP_INT_DATA* p = NULL;
+  tSMP_INT_DATA smp_int_data;
 
   SMP_TRACE_DEBUG("%s Association Model = %d", __func__,
                   p_cb->selected_association_model);
@@ -1209,17 +1248,17 @@
           ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0)) {
         SMP_TRACE_ERROR(
             "IO capability does not meet authentication requirement");
-        failure = SMP_PAIR_AUTH_FAIL;
-        p = (tSMP_INT_DATA*)&failure;
+        smp_int_data.status = SMP_PAIR_AUTH_FAIL;
         int_evt = SMP_AUTH_CMPL_EVT;
       } else {
         p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
         SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ",
                         p_cb->sec_level);
 
+        tSMP_KEY key;
         key.key_type = SMP_KEY_TYPE_TK;
         key.p_data = p_cb->tk;
-        p = (tSMP_INT_DATA*)&key;
+        smp_int_data.key = key;
 
         memset(p_cb->tk, 0, BT_OCTET16_LEN);
         /* TK, ready  */
@@ -1264,7 +1303,7 @@
 
     case SMP_MODEL_OUT_OF_RANGE:
       SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)");
-      p = (tSMP_INT_DATA*)&failure;
+      smp_int_data.status = SMP_UNKNOWN_IO_CAP;
       int_evt = SMP_AUTH_CMPL_EVT;
       break;
 
@@ -1272,12 +1311,12 @@
       SMP_TRACE_ERROR(
           "Association Model = %d (SOMETHING IS WRONG WITH THE CODE)",
           p_cb->selected_association_model);
-      p = (tSMP_INT_DATA*)&failure;
+      smp_int_data.status = SMP_UNKNOWN_IO_CAP;
       int_evt = SMP_AUTH_CMPL_EVT;
   }
 
   SMP_TRACE_EVENT("sec_level=%d ", p_cb->sec_level);
-  if (int_evt) smp_sm_event(p_cb, int_evt, p);
+  if (int_evt) smp_sm_event(p_cb, int_evt, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -1285,7 +1324,6 @@
  * Description  process IO response for a slave device.
  ******************************************************************************/
 void smp_process_io_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t reason = SMP_PAIR_AUTH_FAIL;
 
   SMP_TRACE_DEBUG("%s", __func__);
   if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
@@ -1303,7 +1341,9 @@
       SMP_TRACE_ERROR(
           "Slave requires secure connection only mode "
           "but it can't be provided -> Slave fails pairing");
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+      tSMP_INT_DATA smp_int_data;
+      smp_int_data.status = SMP_PAIR_AUTH_FAIL;
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
       return;
     }
 
@@ -1528,15 +1568,15 @@
  * Note         It is supposed to be called in SC phase1.
  ******************************************************************************/
 void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t reason;
-
   SMP_TRACE_DEBUG("%s start ", __func__);
 
   // PTS Testing failure modes
   if (p_cb->cert_failure == SMP_CONFIRM_VALUE_ERR) {
     SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
-    reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_CONFIRM_VALUE_ERR;
+    p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
   // PTS Testing failure modes (for LT)
@@ -1544,8 +1584,10 @@
       (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) &&
       (p_cb->role == HCI_ROLE_SLAVE)) {
     SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
-    reason = p_cb->failure = SMP_NUMERIC_COMPAR_FAIL;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_NUMERIC_COMPAR_FAIL;
+    p_cb->failure = SMP_NUMERIC_COMPAR_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -1555,8 +1597,10 @@
       /* in these models only master receives commitment */
       if (p_cb->role == HCI_ROLE_MASTER) {
         if (!smp_check_commitment(p_cb)) {
-          reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
-          smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+          tSMP_INT_DATA smp_int_data;
+          smp_int_data.status = SMP_CONFIRM_VALUE_ERR;
+          p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+          smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
           break;
         }
       } else {
@@ -1577,8 +1621,10 @@
     case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
       if (!smp_check_commitment(p_cb) &&
           p_cb->cert_failure != SMP_NUMERIC_COMPAR_FAIL) {
-        reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
-        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        tSMP_INT_DATA smp_int_data;
+        smp_int_data.status = SMP_CONFIRM_VALUE_ERR;
+        p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
         break;
       }
 
@@ -1617,14 +1663,15 @@
  *              received from the peer DHKey check value.
  ******************************************************************************/
 void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-  uint8_t reason = SMP_DHKEY_CHK_FAIL;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
   if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) {
     SMP_TRACE_WARNING("dhkey chcks do no match");
-    p_cb->failure = reason;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_DHKEY_CHK_FAIL;
+    p_cb->failure = SMP_DHKEY_CHK_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -1741,11 +1788,12 @@
     memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment,
            sizeof(p_cb->remote_commitment));
 
-    uint8_t reason = SMP_CONFIRM_VALUE_ERR;
     /* check commitment */
     if (!smp_check_commitment(p_cb)) {
-      p_cb->failure = reason;
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+      tSMP_INT_DATA smp_int_data;
+      smp_int_data.status = SMP_CONFIRM_VALUE_ERR;
+      p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
       return;
     }
 
@@ -1847,7 +1895,9 @@
       btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
     }
 
-    smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = encr_enable;
+    smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &smp_int_data);
   }
 }
 
@@ -1938,7 +1988,9 @@
   SMP_TRACE_DEBUG("%s", __func__);
   if (!smp_calculate_link_key_from_long_term_key(p_cb)) {
     SMP_TRACE_ERROR("%s failed", __func__);
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = status;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 }
@@ -1960,10 +2012,20 @@
   SMP_TRACE_DEBUG("%s", __func__);
   if (!smp_calculate_long_term_key_from_link_key(p_cb)) {
     SMP_TRACE_ERROR("%s: failed", __func__);
-    smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = status;
+    smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+  if (p_dev_rec) {
+    SMP_TRACE_DEBUG("%s: dev_type = %d ", __func__, p_dev_rec->device_type);
+    p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE;
+  } else {
+    SMP_TRACE_ERROR("%s failed to find Security Record", __func__);
+  }
+
   SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed",
                   __func__);
   smp_save_secure_connections_long_term_key(p_cb);
diff --git a/stack/smp/smp_api.cc b/stack/smp/smp_api.cc
index f6a87dd..d096da5 100644
--- a/stack/smp/smp_api.cc
+++ b/stack/smp/smp_api.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -132,10 +132,11 @@
  ******************************************************************************/
 tSMP_STATUS SMP_Pair(const RawAddress& bd_addr) {
   tSMP_CB* p_cb = &smp_cb;
-  uint8_t status = SMP_PAIR_INTERNAL_ERR;
 
-  SMP_TRACE_EVENT("%s state=%d br_state=%d flag=0x%x ", __func__, p_cb->state,
-                  p_cb->br_state, p_cb->flags);
+  SMP_TRACE_EVENT("%s: state=%d br_state=%d flag=0x%x, bd_addr=%s", __func__,
+                  p_cb->state, p_cb->br_state, p_cb->flags,
+                  bd_addr.ToString().c_str());
+
   if (p_cb->state != SMP_STATE_IDLE ||
       p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD || p_cb->smp_over_br) {
     /* pending security on going, reject this one */
@@ -145,9 +146,11 @@
     p_cb->pairing_bda = bd_addr;
 
     if (!L2CA_ConnectFixedChnl(L2CAP_SMP_CID, bd_addr)) {
+      tSMP_INT_DATA smp_int_data;
+      smp_int_data.status = SMP_PAIR_INTERNAL_ERR;
       SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__);
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
-      return status;
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+      return SMP_PAIR_INTERNAL_ERR;
     }
 
     return SMP_STARTED;
@@ -169,10 +172,10 @@
  ******************************************************************************/
 tSMP_STATUS SMP_BR_PairWith(const RawAddress& bd_addr) {
   tSMP_CB* p_cb = &smp_cb;
-  uint8_t status = SMP_PAIR_INTERNAL_ERR;
 
-  SMP_TRACE_EVENT("%s state=%d br_state=%d flag=0x%x ", __func__, p_cb->state,
-                  p_cb->br_state, p_cb->flags);
+  SMP_TRACE_EVENT("%s: state=%d br_state=%d flag=0x%x, bd_addr=%s", __func__,
+                  p_cb->state, p_cb->br_state, p_cb->flags,
+                  bd_addr.ToString().c_str());
 
   if (p_cb->state != SMP_STATE_IDLE || p_cb->smp_over_br ||
       p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
@@ -187,8 +190,10 @@
 
   if (!L2CA_ConnectFixedChnl(L2CAP_SMP_BR_CID, bd_addr)) {
     SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__);
-    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
-    return status;
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_INTERNAL_ERR;
+    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
+    return SMP_PAIR_INTERNAL_ERR;
   }
 
   return SMP_STARTED;
@@ -208,7 +213,6 @@
 bool SMP_PairCancel(const RawAddress& bd_addr) {
   tSMP_CB* p_cb = &smp_cb;
   uint8_t err_code = SMP_PAIR_FAIL_UNKNOWN;
-  bool status = false;
 
   // PTS SMP failure test cases
   if (p_cb->cert_failure == SMP_PASSKEY_ENTRY_FAIL ||
@@ -220,11 +224,13 @@
   if (p_cb->state != SMP_STATE_IDLE && p_cb->pairing_bda == bd_addr) {
     p_cb->is_pair_cancel = true;
     SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown");
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code);
-    status = true;
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+    return true;
   }
 
-  return status;
+  return false;
 }
 /*******************************************************************************
  *
@@ -252,7 +258,10 @@
     /* clear the SMP_SEC_REQUEST_EVT event after get grant */
     /* avoid generating duplicate pair request */
     smp_cb.cb_evt = 0;
-    smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = res;
+    smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT,
+                               &smp_int_data);
     return;
   }
 
@@ -262,7 +271,9 @@
   /* clear the SMP_SEC_REQUEST_EVT event after get grant */
   /* avoid generate duplicate pair request */
   smp_cb.cb_evt = 0;
-  smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.status = res;
+  smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -283,7 +294,6 @@
 void SMP_PasskeyReply(const RawAddress& bd_addr, uint8_t res,
                       uint32_t passkey) {
   tSMP_CB* p_cb = &smp_cb;
-  uint8_t failure = SMP_PASSKEY_ENTRY_FAIL;
 
   SMP_TRACE_EVENT("SMP_PasskeyReply: Key: %d  Result:%d", passkey, res);
 
@@ -308,11 +318,15 @@
         "SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail",
         passkey);
     /* send pairing failure */
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PASSKEY_ENTRY_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
 
   } else if (p_cb->selected_association_model ==
              SMP_MODEL_SEC_CONN_PASSKEY_ENT) {
-    smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.passkey = passkey;
+    smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
   } else {
     smp_convert_string_to_tk(p_cb->tk, passkey);
   }
@@ -334,7 +348,6 @@
  ******************************************************************************/
 void SMP_ConfirmReply(const RawAddress& bd_addr, uint8_t res) {
   tSMP_CB* p_cb = &smp_cb;
-  uint8_t failure = SMP_NUMERIC_COMPAR_FAIL;
 
   SMP_TRACE_EVENT("%s: Result:%d", __func__, res);
 
@@ -357,7 +370,9 @@
   if (res != SMP_SUCCESS) {
     SMP_TRACE_WARNING("%s() - Numeric Comparison fails", __func__);
     /* send pairing failure */
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_NUMERIC_COMPAR_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   } else {
     smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL);
   }
@@ -378,7 +393,6 @@
 void SMP_OobDataReply(const RawAddress& bd_addr, tSMP_STATUS res, uint8_t len,
                       uint8_t* p_data) {
   tSMP_CB* p_cb = &smp_cb;
-  uint8_t failure = SMP_OOB_FAIL;
   tSMP_KEY key;
 
   SMP_TRACE_EVENT("%s State: %d  res:%d", __func__, smp_cb.state, res);
@@ -388,7 +402,9 @@
     return;
 
   if (res != SMP_SUCCESS || len == 0 || !p_data) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_OOB_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   } else {
     if (len > BT_OCTET16_LEN) len = BT_OCTET16_LEN;
 
@@ -397,7 +413,9 @@
     key.key_type = SMP_KEY_TYPE_TK;
     key.p_data = p_cb->tk;
 
-    smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.key = key;
+    smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &smp_int_data);
   }
 }
 
@@ -414,11 +432,12 @@
 void SMP_SecureConnectionOobDataReply(uint8_t* p_data) {
   tSMP_CB* p_cb = &smp_cb;
 
-  uint8_t failure = SMP_OOB_FAIL;
   tSMP_SC_OOB_DATA* p_oob = (tSMP_SC_OOB_DATA*)p_data;
   if (!p_oob) {
     SMP_TRACE_ERROR("%s received no data", __func__);
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_OOB_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -450,14 +469,17 @@
       break;
   }
 
+  tSMP_INT_DATA smp_int_data;
   if (data_missing) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    smp_int_data.status = SMP_OOB_FAIL;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
   p_cb->sc_oob_data = *p_oob;
 
-  smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data);
+  smp_int_data.p_data = p_data;
+  smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -526,7 +548,9 @@
     return;
   }
 
-  smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.status = value;
+  smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &smp_int_data);
 }
 
 /*******************************************************************************
diff --git a/stack/smp/smp_br_main.cc b/stack/smp/smp_br_main.cc
index 55405cc..b06055f 100644
--- a/stack/smp/smp_br_main.cc
+++ b/stack/smp/smp_br_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014-2015 Broadcom Corporation
+ *  Copyright 2014-2015 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -72,23 +72,25 @@
   SMP_BR_SM_NO_ACTION
 };
 
-static const tSMP_ACT smp_br_sm_action[] = {smp_send_pair_req,
-                                            smp_br_send_pair_response,
-                                            smp_send_pair_fail,
-                                            smp_send_id_info,
-                                            smp_br_process_pairing_command,
-                                            smp_proc_pair_fail,
-                                            smp_proc_id_info,
-                                            smp_proc_id_addr,
-                                            smp_proc_srk_info,
-                                            smp_br_process_security_grant,
-                                            smp_br_process_slave_keys_response,
-                                            smp_br_select_next_key,
-                                            smp_br_pairing_complete,
-                                            smp_send_app_cback,
-                                            smp_br_check_authorization_request,
-                                            smp_pair_terminate,
-                                            smp_idle_terminate};
+static const tSMP_ACT smp_br_sm_action[] = {
+    smp_send_pair_req,                  /* SMP_SEND_PAIR_REQ */
+    smp_br_send_pair_response,          /* SMP_BR_SEND_PAIR_RSP */
+    smp_send_pair_fail,                 /* SMP_SEND_PAIR_FAIL */
+    smp_send_id_info,                   /* SMP_SEND_ID_INFO */
+    smp_br_process_pairing_command,     /* SMP_BR_PROC_PAIR_CMD */
+    smp_proc_pair_fail,                 /* SMP_PROC_PAIR_FAIL */
+    smp_proc_id_info,                   /* SMP_PROC_ID_INFO */
+    smp_proc_id_addr,                   /* SMP_PROC_ID_ADDR */
+    smp_proc_srk_info,                  /* SMP_PROC_SRK_INFO */
+    smp_br_process_security_grant,      /* SMP_BR_PROC_SEC_GRANT */
+    smp_br_process_slave_keys_response, /* SMP_BR_PROC_SL_KEYS_RSP */
+    smp_br_select_next_key,             /* SMP_BR_KEY_DISTRIBUTION */
+    smp_br_pairing_complete,            /* SMP_BR_PAIRING_COMPLETE */
+    smp_send_app_cback,                 /* SMP_SEND_APP_CBACK */
+    smp_br_check_authorization_request, /* SMP_BR_CHECK_AUTH_REQ */
+    smp_pair_terminate,                 /* SMP_PAIR_TERMINATE */
+    smp_idle_terminate                  /* SMP_IDLE_TERMINATE */
+};
 
 static const uint8_t smp_br_all_table[][SMP_BR_SM_NUM_COLS] = {
     /* Event              Action                   Next State */
@@ -297,7 +299,7 @@
  *
  ******************************************************************************/
 void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event,
-                                void* p_data) {
+                                tSMP_INT_DATA* p_data) {
   tSMP_BR_STATE curr_state = p_cb->br_state;
   tSMP_BR_SM_TBL state_table;
   uint8_t action, entry;
@@ -350,7 +352,7 @@
   for (uint8_t i = 0; i < SMP_BR_NUM_ACTIONS; i++) {
     action = state_table[entry - 1][i];
     if (action != SMP_BR_SM_NO_ACTION) {
-      (*smp_br_sm_action[action])(p_cb, (tSMP_INT_DATA*)p_data);
+      (*smp_br_sm_action[action])(p_cb, p_data);
     } else {
       break;
     }
diff --git a/stack/smp/smp_cmac.cc b/stack/smp/smp_cmac.cc
index 876c420..42f91a0 100644
--- a/stack/smp/smp_cmac.cc
+++ b/stack/smp/smp_cmac.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2008-2012 Broadcom Corporation
+ *  Copyright 2008-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
index fc8717f..1685ffe 100644
--- a/stack/smp/smp_int.h
+++ b/stack/smp/smp_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -221,6 +221,7 @@
 typedef union {
   uint8_t* p_data; /* uint8_t type data pointer */
   tSMP_KEY key;
+  uint8_t status;
   uint16_t reason;
   uint32_t passkey;
   tSMP_OOB_DATA_TYPE req_oob_type;
@@ -341,7 +342,8 @@
 extern void smp_init(void);
 
 /* smp main */
-extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, void* p_data);
+extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event,
+                         tSMP_INT_DATA* p_data);
 
 extern void smp_proc_sec_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
 extern void smp_set_fail_nc(bool enable);
@@ -366,14 +368,12 @@
 extern void smp_f6_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
                             uint8_t* iocap, uint8_t* a1, uint8_t* a2,
                             uint8_t* mac);
-/* smp_main */
-extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, void* p_data);
 extern tSMP_STATE smp_get_state(void);
 extern void smp_set_state(tSMP_STATE state);
 
 /* smp_br_main */
 extern void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event,
-                                       void* p_data);
+                                       tSMP_INT_DATA* p_data);
 extern tSMP_BR_STATE smp_get_br_state(void);
 extern void smp_set_br_state(tSMP_BR_STATE state);
 
diff --git a/stack/smp/smp_keys.cc b/stack/smp/smp_keys.cc
index 06e4d87..6be1da4 100644
--- a/stack/smp/smp_keys.cc
+++ b/stack/smp/smp_keys.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -172,7 +172,6 @@
  ******************************************************************************/
 void smp_proc_passkey(tSMP_CB* p_cb, BT_OCTET8 rand) {
   uint8_t* tt = p_cb->tk;
-  tSMP_KEY key;
   uint32_t passkey; /* 19655 test number; */
   uint8_t* pp = rand;
 
@@ -187,18 +186,24 @@
   memset(p_cb->tk, 0, BT_OCTET16_LEN);
   UINT32_TO_STREAM(tt, passkey);
 
-  key.key_type = SMP_KEY_TYPE_TK;
-  key.p_data = p_cb->tk;
-
   if (p_cb->p_callback) {
+    tSMP_EVT_DATA smp_evt_data;
+    smp_evt_data.passkey = passkey;
     (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda,
-                        (tSMP_EVT_DATA*)&passkey);
+                        &smp_evt_data);
   }
 
   if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) {
-    smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.passkey = passkey;
+    smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &smp_int_data);
   } else {
-    smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA*)&key);
+    tSMP_KEY key;
+    key.key_type = SMP_KEY_TYPE_TK;
+    key.p_data = p_cb->tk;
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.key = key;
+    smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
   }
 }
 
@@ -230,7 +235,6 @@
  ******************************************************************************/
 void smp_generate_stk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
   tSMP_ENC output;
-  tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
@@ -242,7 +246,9 @@
     memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE);
   } else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) {
     SMP_TRACE_ERROR("%s failed", __func__);
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
@@ -258,7 +264,6 @@
   uint16_t r = 1;
   uint8_t* p = buffer;
   tSMP_ENC output;
-  tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
 
   p_cb->div = div;
 
@@ -270,10 +275,12 @@
 
   if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) {
     SMP_TRACE_ERROR("smp_generate_csrk failed");
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
     if (p_cb->smp_over_br) {
-      smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+      smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
     } else {
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     }
   } else {
     memcpy((void*)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
@@ -481,7 +488,9 @@
   tSMP_ENC output;
   tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rand, &output);
   if (status != SMP_SUCCESS) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = status;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
   tSMP_KEY key;
@@ -490,7 +499,9 @@
                                       16);
   key.key_type = SMP_KEY_TYPE_CFM;
   key.p_data = output.param_buf;
-  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.key = key;
+  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -541,7 +552,9 @@
   tSMP_ENC output;
   tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rrand, &output);
   if (status != SMP_SUCCESS) {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = status;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
   tSMP_KEY key;
@@ -549,7 +562,9 @@
                                       "Remote Confirm generated", 16);
   key.key_type = SMP_KEY_TYPE_CMP;
   key.p_data = output.param_buf;
-  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.key = key;
+  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -574,7 +589,9 @@
   key.key_type = SMP_KEY_TYPE_STK;
   key.p_data = p->param_buf;
 
-  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.key = key;
+  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
 }
 
 /**
@@ -595,7 +612,9 @@
   key.key_type = SMP_KEY_TYPE_LTK;
   key.p_data = p->param_buf;
 
-  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.key = key;
+  smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
 }
 
 /**
@@ -611,8 +630,9 @@
   tSMP_ENC output;
   if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, rand, BT_OCTET8_LEN, &output)) {
     SMP_TRACE_ERROR("%s failed", __func__);
-    tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   } else {
     smp_process_ediv(p_cb, &output);
   }
@@ -633,8 +653,9 @@
   if (!SMP_Encrypt(er, BT_OCTET16_LEN, (uint8_t*)&p_cb->div, sizeof(uint16_t),
                    &output)) {
     SMP_TRACE_ERROR("%s failed", __func__);
-    tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   } else {
     /* mask the LTK */
     smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
@@ -1052,16 +1073,19 @@
   }
 
   if (p_cb->number_to_display >= (BTM_MAX_PASSKEY_VAL + 1)) {
-    uint8_t reason;
-    reason = p_cb->failure = SMP_PAIR_FAIL_UNKNOWN;
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
+    p_cb->failure = SMP_PAIR_FAIL_UNKNOWN;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     return;
   }
 
   SMP_TRACE_EVENT("Number to display in numeric comparison = %d",
                   p_cb->number_to_display);
   p_cb->cb_evt = SMP_NC_REQ_EVT;
-  smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &p_cb->number_to_display);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.passkey = p_cb->number_to_display;
+  smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &smp_int_data);
   return;
 }
 
@@ -1503,7 +1527,6 @@
   BT_OCTET16 param_buf;
   bool ret;
   tSMP_KEY key;
-  tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
 
   SMP_TRACE_DEBUG("%s", __func__);
 
@@ -1522,10 +1545,14 @@
 #endif
     key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
     key.p_data = param_buf;
-    smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &key);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.key = key;
+    smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
   } else {
     SMP_TRACE_EVENT("peer DHKey check calculation failed");
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   }
 }
 
diff --git a/stack/smp/smp_l2c.cc b/stack/smp/smp_l2c.cc
index 6111f10..1e0cb71 100644
--- a/stack/smp/smp_l2c.cc
+++ b/stack/smp/smp_l2c.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -94,7 +94,9 @@
   tSMP_CB* p_cb = &smp_cb;
   tSMP_INT_DATA int_data;
 
-  SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
+  SMP_TRACE_EVENT("%s: SMDBG l2c: bd_addr=%s, p_cb->pairing_bda=%s", __func__,
+                  bd_addr.ToString().c_str(),
+                  p_cb->pairing_bda.ToString().c_str());
 
   if (transport == BT_TRANSPORT_BR_EDR || bd_addr.IsEmpty()) return;
 
@@ -138,10 +140,11 @@
   tSMP_CB* p_cb = &smp_cb;
   uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
   uint8_t cmd;
-  SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
 
   STREAM_TO_UINT8(cmd, p);
 
+  SMP_TRACE_EVENT("%s: SMDBG l2c, cmd=0x%x", __func__, cmd);
+
   /* sanity check */
   if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
     SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
@@ -183,7 +186,9 @@
 
     p_cb->rcvd_cmd_code = cmd;
     p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
-    smp_sm_event(p_cb, cmd, p);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.p_data = p;
+    smp_sm_event(p_cb, cmd, &smp_int_data);
   }
 
   osi_free(p_buf);
@@ -204,12 +209,14 @@
   else
     SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt);
 
-  uint8_t reason = SMP_SUCCESS;
   if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) {
-    if (cid == L2CAP_SMP_CID)
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
-    else
-      smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_SUCCESS;
+    if (cid == L2CAP_SMP_CID) {
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+    } else {
+      smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
+    }
   }
 }
 
@@ -236,11 +243,12 @@
     return;
   }
 
-  if (bd_addr != p_cb->pairing_bda) return;
-
   VLOG(1) << __func__ << " for pairing BDA: " << bd_addr
+          << ", pairing_bda:" << p_cb->pairing_bda
           << " Event: " << ((connected) ? "connected" : "disconnected");
 
+  if (bd_addr != p_cb->pairing_bda) return;
+
   if (connected) {
     if (!p_cb->connect_initialized) {
       p_cb->connect_initialized = true;
@@ -304,7 +312,9 @@
 
     p_cb->rcvd_cmd_code = cmd;
     p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
-    smp_br_state_machine_event(p_cb, cmd, p);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.p_data = p;
+    smp_br_state_machine_event(p_cb, cmd, &smp_int_data);
   }
 
   osi_free(p_buf);
diff --git a/stack/smp/smp_main.cc b/stack/smp/smp_main.cc
index 49e2ece..9c4334a 100644
--- a/stack/smp/smp_main.cc
+++ b/stack/smp/smp_main.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2012 Broadcom Corporation
+ *  Copyright 2003-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -951,7 +951,7 @@
  * Returns      void.
  *
  ******************************************************************************/
-void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, void* p_data) {
+void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, tSMP_INT_DATA* p_data) {
   uint8_t curr_state = p_cb->state;
   tSMP_SM_TBL state_table;
   uint8_t action, entry, i;
@@ -1005,7 +1005,7 @@
   for (i = 0; i < SMP_NUM_ACTIONS; i++) {
     action = state_table[entry - 1][i];
     if (action != SMP_SM_NO_ACTION) {
-      (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA*)p_data);
+      (*smp_sm_action[action])(p_cb, p_data);
     } else {
       break;
     }
diff --git a/stack/smp/smp_utils.cc b/stack/smp/smp_utils.cc
index 8bdce6b..2bd0b24 100644
--- a/stack/smp/smp_utils.cc
+++ b/stack/smp/smp_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -315,8 +315,7 @@
   l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP);
   if (l2cap_ret == L2CAP_DW_FAILED) {
     smp_cb.total_tx_unacked -= 1;
-    SMP_TRACE_ERROR("SMP   failed to pass msg:0x%0x to L2CAP",
-                    *((uint8_t*)(p_toL2CAP + 1) + p_toL2CAP->offset));
+    SMP_TRACE_ERROR("SMP failed to pass msg to L2CAP");
     return false;
   } else
     return true;
@@ -332,8 +331,10 @@
 bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb) {
   BT_HDR* p_buf;
   bool sent = false;
-  uint8_t failure = SMP_PAIR_INTERNAL_ERR;
-  SMP_TRACE_EVENT("smp_send_cmd on l2cap cmd_code=0x%x", cmd_code);
+
+  SMP_TRACE_EVENT("%s: on l2cap cmd_code=0x%x, pairing_bda=%s", __func__,
+                  cmd_code, p_cb->pairing_bda.ToString().c_str());
+
   if (cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) &&
       smp_cmd_build_act[cmd_code] != NULL) {
     p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb);
@@ -346,10 +347,12 @@
   }
 
   if (!sent) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_PAIR_INTERNAL_ERR;
     if (p_cb->smp_over_br) {
-      smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+      smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
     } else {
-      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+      smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
     }
   }
   return sent;
@@ -366,15 +369,16 @@
  ******************************************************************************/
 void smp_rsp_timeout(UNUSED_ATTR void* data) {
   tSMP_CB* p_cb = &smp_cb;
-  uint8_t failure = SMP_RSP_TIMEOUT;
 
   SMP_TRACE_EVENT("%s state:%d br_state:%d", __func__, p_cb->state,
                   p_cb->br_state);
 
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.status = SMP_RSP_TIMEOUT;
   if (p_cb->smp_over_br) {
-    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
   } else {
-    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   }
 }
 
@@ -394,9 +398,10 @@
    * the state is still in bond pending.
    */
   if (smp_get_state() == SMP_STATE_BOND_PENDING) {
-    uint8_t reason = SMP_SUCCESS;
     SMP_TRACE_EVENT("%s sending delayed auth complete.", __func__);
-    smp_sm_event(&smp_cb, SMP_AUTH_CMPL_EVT, &reason);
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_SUCCESS;
+    smp_sm_event(&smp_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
   }
 }
 
@@ -788,7 +793,9 @@
   key.key_type = SMP_KEY_TYPE_TK;
   key.p_data = tk;
 
-  smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.key = key;
+  smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &smp_int_data);
 }
 
 /*******************************************************************************
@@ -916,7 +923,8 @@
   tSMP_EVT_DATA evt_data = {0};
   tSMP_CALLBACK* p_callback = p_cb->p_callback;
 
-  SMP_TRACE_DEBUG("smp_proc_pairing_cmpl ");
+  SMP_TRACE_DEBUG("%s: pairing_bda=%s", __func__,
+                  p_cb->pairing_bda.ToString().c_str());
 
   evt_data.cmplt.reason = p_cb->status;
   evt_data.cmplt.smp_over_br = p_cb->smp_over_br;
@@ -1523,7 +1531,9 @@
 
   p_cb->req_oob_type = req_oob_type;
   p_cb->cb_evt = SMP_SC_OOB_REQ_EVT;
-  smp_sm_event(p_cb, SMP_TK_REQ_EVT, &req_oob_type);
+  tSMP_INT_DATA smp_int_data;
+  smp_int_data.req_oob_type = req_oob_type;
+  smp_sm_event(p_cb, SMP_TK_REQ_EVT, &smp_int_data);
 
   return true;
 }
diff --git a/stack/srvc/srvc_battery.cc b/stack/srvc/srvc_battery.cc
index 2d9fe18..8b5d93e 100644
--- a/stack/srvc/srvc_battery.cc
+++ b/stack/srvc/srvc_battery.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2013 Broadcom Corporation
+ *  Copyright 1999-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
 
 #include "bt_target.h"
 #include "bt_utils.h"
-#include "btcore/include/uuid.h"
 #include "gatt_api.h"
 #include "gatt_int.h"
 #include "osi/include/osi.h"
@@ -185,13 +184,13 @@
 
   btgatt_db_element_t service[BA_MAX_ATTR_NUM] = {};
 
-  bt_uuid_t service_uuid;
-  uuid_128_from_16(&service_uuid, UUID_SERVCLASS_BATTERY);
+  bluetooth::Uuid service_uuid =
+      bluetooth::Uuid::From16Bit(UUID_SERVCLASS_BATTERY);
   service[0].type = /* p_reg_info->is_pri */ BTGATT_DB_PRIMARY_SERVICE;
   service[0].uuid = service_uuid;
 
-  bt_uuid_t char_uuid;
-  uuid_128_from_16(&char_uuid, GATT_UUID_BATTERY_LEVEL);
+  bluetooth::Uuid char_uuid =
+      bluetooth::Uuid::From16Bit(GATT_UUID_BATTERY_LEVEL);
   service[1].type = BTGATT_DB_CHARACTERISTIC;
   service[1].uuid = char_uuid;
   service[1].properties = GATT_CHAR_PROP_BIT_READ;
@@ -200,8 +199,8 @@
 
   int i = 2;
   if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
-    bt_uuid_t desc_uuid;
-    uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_CLIENT_CONFIG);
+    bluetooth::Uuid desc_uuid =
+        bluetooth::Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG);
 
     service[i].type = BTGATT_DB_DESCRIPTOR;
     service[i].uuid = desc_uuid;
@@ -211,8 +210,8 @@
 
   /* need presentation format descriptor? */
   if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
-    bt_uuid_t desc_uuid;
-    uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_PRESENT_FORMAT);
+    bluetooth::Uuid desc_uuid =
+        bluetooth::Uuid::From16Bit(GATT_UUID_CHAR_PRESENT_FORMAT);
 
     service[i].type = BTGATT_DB_DESCRIPTOR;
     service[i].uuid = desc_uuid;
@@ -222,8 +221,8 @@
 
   /* need presentation format descriptor? */
   if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
-    bt_uuid_t desc_uuid;
-    uuid_128_from_16(&desc_uuid, GATT_UUID_RPT_REF_DESCR);
+    bluetooth::Uuid desc_uuid =
+        bluetooth::Uuid::From16Bit(GATT_UUID_RPT_REF_DESCR);
 
     service[i].type = BTGATT_DB_DESCRIPTOR;
     service[i].uuid = desc_uuid;
diff --git a/stack/srvc/srvc_battery_int.h b/stack/srvc/srvc_battery_int.h
index fc191e8..2ffb85a 100644
--- a/stack/srvc/srvc_battery_int.h
+++ b/stack/srvc/srvc_battery_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/srvc/srvc_dis.cc b/stack/srvc/srvc_dis.cc
index 85de4b4..3ca2e33 100644
--- a/stack/srvc/srvc_dis.cc
+++ b/stack/srvc/srvc_dis.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2013 Broadcom Corporation
+ *  Copyright 1999-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
 
 #include "bt_target.h"
 #include "bt_utils.h"
-#include "btcore/include/uuid.h"
 #include "gatt_api.h"
 #include "gatt_int.h"
 #include "osi/include/log.h"
@@ -50,18 +49,6 @@
     *(p)++ = (uint8_t)((u64) >> 56); \
   }
 
-#define STREAM_TO_UINT64(u64, p)                                      \
-  {                                                                   \
-    (u64) = (((uint64_t)(*(p))) + ((((uint64_t)(*((p) + 1)))) << 8) + \
-             ((((uint64_t)(*((p) + 2)))) << 16) +                     \
-             ((((uint64_t)(*((p) + 3)))) << 24) +                     \
-             ((((uint64_t)(*((p) + 4)))) << 32) +                     \
-             ((((uint64_t)(*((p) + 5)))) << 40) +                     \
-             ((((uint64_t)(*((p) + 6)))) << 48) +                     \
-             ((((uint64_t)(*((p) + 7)))) << 56));                     \
-    (p) += 8;                                                         \
-  }
-
 static const uint16_t dis_attr_uuid[DIS_MAX_CHAR_NUM] = {
     GATT_UUID_SYSTEM_ID,
     GATT_UUID_MODEL_NUMBER_STR,
@@ -137,7 +124,7 @@
     if (handle == p_db_attr->handle) {
       if ((p_db_attr->uuid == GATT_UUID_PNP_ID ||
            p_db_attr->uuid == GATT_UUID_SYSTEM_ID) &&
-          is_long == true) {
+          is_long) {
         st = GATT_NOT_LONG;
         break;
       }
@@ -232,7 +219,6 @@
 
   memset(&param, 0, sizeof(tGATT_READ_PARAM));
 
-  param.service.uuid.len = LEN_UUID_16;
   param.service.s_handle = 1;
   param.service.e_handle = 0xFFFF;
   param.service.auth_req = 0;
@@ -240,13 +226,14 @@
   while (dis_cb.dis_read_uuid_idx < DIS_MAX_CHAR_NUM) {
     if (dis_uuid_to_attr(dis_attr_uuid[dis_cb.dis_read_uuid_idx]) &
         dis_cb.request_mask) {
-      param.service.uuid.uu.uuid16 = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+      param.service.uuid =
+          bluetooth::Uuid::From16Bit(dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
 
       if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS)
         return true;
 
-      LOG(ERROR) << "Read DISInfo: 0x" << std::hex
-                 << param.service.uuid.uu.uuid16 << "GATT_Read Failed";
+      LOG(ERROR) << "Read DISInfo: " << param.service.uuid
+                 << " GATT_Read Failed";
     }
 
     dis_cb.dis_read_uuid_idx++;
@@ -350,16 +337,16 @@
 
   btgatt_db_element_t service[DIS_MAX_ATTR_NUM] = {};
 
-  bt_uuid_t svc_uuid;
-  uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_DEVICE_INFO);
+  bluetooth::Uuid svc_uuid =
+      bluetooth::Uuid::From16Bit(UUID_SERVCLASS_DEVICE_INFO);
   service[0].type = BTGATT_DB_PRIMARY_SERVICE;
   service[0].uuid = svc_uuid;
 
   for (int i = 0; dis_attr_mask != 0 && i < DIS_MAX_CHAR_NUM; i++) {
     dis_cb.dis_attr[i].uuid = dis_attr_uuid[i];
 
-    bt_uuid_t char_uuid;
-    uuid_128_from_16(&char_uuid, dis_cb.dis_attr[i].uuid);
+    bluetooth::Uuid char_uuid =
+        bluetooth::Uuid::From16Bit(dis_cb.dis_attr[i].uuid);
     /* index 0 is service, so characteristics start from 1 */
     service[i + 1].type = BTGATT_DB_CHARACTERISTIC;
     service[i + 1].uuid = char_uuid;
diff --git a/stack/srvc/srvc_dis_int.h b/stack/srvc/srvc_dis_int.h
index 880f068..422f649 100644
--- a/stack/srvc/srvc_dis_int.h
+++ b/stack/srvc/srvc_dis_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2012 Broadcom Corporation
+ *  Copyright 1999-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/srvc/srvc_eng.cc b/stack/srvc/srvc_eng.cc
index f054f67..af57ff1 100644
--- a/stack/srvc/srvc_eng.cc
+++ b/stack/srvc/srvc_eng.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2013 Broadcom Corporation
+ *  Copyright 1999-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -402,7 +402,6 @@
  *
  ******************************************************************************/
 tGATT_STATUS srvc_eng_init(void) {
-  tBT_UUID app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
 
   if (srvc_eng_cb.enabled) {
     LOG(ERROR) << "DIS already initalized";
@@ -410,7 +409,9 @@
     memset(&srvc_eng_cb, 0, sizeof(tSRVC_ENG_CB));
 
     /* Create a GATT profile service */
-    srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback);
+    bluetooth::Uuid app_uuid =
+        bluetooth::Uuid::From16Bit(UUID_SERVCLASS_DEVICE_INFO);
+    srvc_eng_cb.gatt_if = GATT_Register(app_uuid, &srvc_gatt_cback);
     GATT_StartIf(srvc_eng_cb.gatt_if);
 
     VLOG(1) << "Srvc_Init:  gatt_if=" << +srvc_eng_cb.gatt_if;
diff --git a/stack/srvc/srvc_eng_int.h b/stack/srvc/srvc_eng_int.h
index 7608355..9ea2d0b 100644
--- a/stack/srvc/srvc_eng_int.h
+++ b/stack/srvc/srvc_eng_int.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 1999-2013 Broadcom Corporation
+ *  Copyright 1999-2013 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/stack/test/ad_parser_unittest.cc b/stack/test/ad_parser_unittest.cc
index 643ed34..36cc7f2 100644
--- a/stack/test/ad_parser_unittest.cc
+++ b/stack/test/ad_parser_unittest.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -137,15 +137,41 @@
       0x02, 0x01, 0x02, 0x11, 0x06, 0x66, 0x9a, 0x0c, 0x20, 0x00, 0x08,
       0x37, 0xa8, 0xe5, 0x11, 0x81, 0x8b, 0xd0, 0xf0, 0xf0, 0xf0, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-  const std::vector<uint8_t> podo_scan_resp{
+  std::vector<uint8_t> podo_scan_resp{
       0x03, 0x19, 0x00, 0x80, 0x09, 0x09, 0x50, 0x6f, 0x64, 0x6f, 0x51,
       0x35, 0x56, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
   AdvertiseDataParser::RemoveTrailingZeros(podo_ad_data);
+  AdvertiseDataParser::RemoveTrailingZeros(podo_scan_resp);
 
   std::vector<uint8_t> glued(podo_ad_data);
-  glued.insert(glued.end(), podo_ad_data.begin(), podo_ad_data.end());
+  glued.insert(glued.end(), podo_scan_resp.begin(), podo_scan_resp.end());
+
+  EXPECT_TRUE(AdvertiseDataParser::IsValid(glued));
+}
+
+// This test makes sure that RemoveTrailingZeros is removing all bytes after
+// first zero length field. It does run the RemoveTrailingZeros for data with
+// non-zero bytes after zero length field, then glue scan response at end of it,
+// and checks that the resulting data is good. Note: specification requires all
+// bytes after zero length field to be zero padding, but many legacy devices got
+// this wrong, causing us to have this workaround.
+TEST(AdvertiseDataParserTest, RemoveTrailingZerosMalformed) {
+  std::vector<uint8_t> ad_data{0x02, 0x01, 0x02, 0x11, 0x06, 0x66, 0x9a, 0x0c,
+                               0x20, 0x00, 0x08, 0x37, 0xa8, 0xe5, 0x11, 0x81,
+                               0x8b, 0xd0, 0xf0, 0xf0, 0xf0, 0x00, 0xFF, 0xFF,
+                               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+  std::vector<uint8_t> scan_resp{0x03, 0x19, 0x00, 0x80, 0x09, 0x09, 0x50, 0x6f,
+                                 0x64, 0x6f, 0x51, 0x35, 0x56, 0x47, 0x00, 0xFF,
+                                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+  AdvertiseDataParser::RemoveTrailingZeros(ad_data);
+  AdvertiseDataParser::RemoveTrailingZeros(scan_resp);
+
+  std::vector<uint8_t> glued(ad_data);
+  glued.insert(glued.end(), scan_resp.begin(), scan_resp.end());
 
   EXPECT_TRUE(AdvertiseDataParser::IsValid(glued));
 }
\ No newline at end of file
diff --git a/stack/test/ble_advertiser_test.cc b/stack/test/ble_advertiser_test.cc
index 4f389e4..65a30d5 100644
--- a/stack/test/ble_advertiser_test.cc
+++ b/stack/test/ble_advertiser_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -1064,6 +1064,53 @@
   remove_cb.Run(0);
 }
 
+/* This test verifies that stack cleanup, and shutdown happening while there is
+ * outstanding HCI command is not triggering the callback */
+TEST_F(BleAdvertisingManagerTest, test_cleanup_during_execution) {
+  std::vector<uint8_t> adv_data;
+  std::vector<uint8_t> scan_resp;
+  tBTM_BLE_ADV_PARAMS params;
+  tBLE_PERIODIC_ADV_PARAMS periodic_params;
+  periodic_params.enable = false;
+  std::vector<uint8_t> periodic_data;
+
+  parameters_cb set_params_cb;
+  status_cb set_address_cb;
+  status_cb set_data_cb;
+  EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<7>(&set_params_cb));
+  EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<2>(&set_address_cb));
+  EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<5>(&set_data_cb));
+
+  BleAdvertisingManager::Get()->StartAdvertisingSet(
+      Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb,
+           base::Unretained(this)),
+      &params, adv_data, scan_resp, &periodic_params, periodic_data,
+      0 /* duration */, 0 /* maxExtAdvEvents */, Bind(DoNothing2));
+
+  // we are a truly gracious fake controller, let the commands succeed!
+  int selected_tx_power = -15;
+  set_params_cb.Run(0, selected_tx_power);
+  set_address_cb.Run(0);
+
+  // Someone shut down the stack in the middle of flow, when the HCI Set
+  // Advertise Data was scheduled!
+  BleAdvertisingManager::Get()->CleanUp();
+
+  // The HCI call returns with status, and tries to execute the callback. This
+  // should just silently drop the call. If it got executed, we would get crash,
+  // because BleAdvertisingManager object was already deleted.
+  set_data_cb.Run(0);
+
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+}
+
 extern void testRecomputeTimeout1();
 extern void testRecomputeTimeout2();
 extern void testRecomputeTimeout3();
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/include/bt_common.h b/stack/test/common/mock_btu_layer.cc
similarity index 81%
copy from include/bt_common.h
copy to stack/test/common/mock_btu_layer.cc
index 9680792..f5bbf7a 100644
--- a/include/bt_common.h
+++ b/stack/test/common/mock_btu_layer.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  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.
@@ -16,9 +16,6 @@
  *
  ******************************************************************************/
 
-#pragma once
+#include <base/message_loop/message_loop.h>
 
-#include "bt_target.h"
-#include "bt_types.h"
-#include "osi/include/allocator.h"
-#include "osi/include/compat.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/stack/test/stack_a2dp_test.cc b/stack/test/stack_a2dp_test.cc
index 3808df4..63dfb28 100644
--- a/stack/test/stack_a2dp_test.cc
+++ b/stack/test/stack_a2dp_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -220,6 +220,9 @@
         case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
           supported = true;
           break;
+        case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+          supported = true;
+          break;
         case BTAV_A2DP_CODEC_INDEX_MAX:
           // Needed to avoid using "default:" case so we can capture when
           // a new codec is added, and it can be included here.
@@ -310,10 +313,10 @@
 TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
   EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
   EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_capability));
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
 
-  EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
+  EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
   EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
 
   // Test with invalid AAC codecs
@@ -349,8 +352,11 @@
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_capability));
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_sink_capability));
 
-  EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac));
-  EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
+  EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac));
+  // NOTE: The test below should be EXPECT_FALSE.
+  // However, codec_info_aac_capability is practically same as codec_info_aac,
+  // therefore we cannot differentiate it as a capability.
+  EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_sink_capability));
 
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
@@ -361,9 +367,9 @@
   EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_capability));
   EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_sink_capability));
 
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
 
   EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
 }
@@ -380,45 +386,6 @@
   }
 }
 
-TEST_F(StackA2dpTest, test_build_src2sink_config) {
-  uint8_t codec_info_result[AVDT_CODEC_SIZE];
-
-  memset(codec_info_result, 0, sizeof(codec_info_result));
-  EXPECT_EQ(A2DP_BuildSrc2SinkConfig(codec_info_sbc, codec_info_result),
-            A2DP_SUCCESS);
-  // Compare the result codec with the local test codec info
-  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
-    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
-  }
-
-  // Include extra (less preferred) capabilities and test again - SBC
-  uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
-  memcpy(codec_info_sbc_test1, codec_info_sbc, sizeof(codec_info_sbc));
-  codec_info_sbc_test1[3] |= (A2DP_SBC_IE_CH_MD_STEREO |
-                              A2DP_SBC_IE_CH_MD_DUAL | A2DP_SBC_IE_CH_MD_MONO);
-  codec_info_sbc_test1[4] |=
-      (A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 | A2DP_SBC_IE_BLOCKS_4);
-  codec_info_sbc_test1[4] |= A2DP_SBC_IE_SUBBAND_4;
-  codec_info_sbc_test1[4] |= A2DP_SBC_IE_ALLOC_MD_S;
-  memset(codec_info_result, 0, sizeof(codec_info_result));
-  EXPECT_EQ(A2DP_BuildSrc2SinkConfig(codec_info_sbc_test1, codec_info_result),
-            A2DP_SUCCESS);
-  // Compare the result codec with the local test codec info
-  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
-    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
-  }
-
-  memset(codec_info_result, 0, sizeof(codec_info_result));
-  EXPECT_NE(A2DP_BuildSrc2SinkConfig(codec_info_aac, codec_info_result),
-            A2DP_SUCCESS);
-
-  // Test invalid codec info
-  memset(codec_info_result, 0, sizeof(codec_info_result));
-  memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
-  EXPECT_NE(A2DP_BuildSrc2SinkConfig(codec_info_sbc_test1, codec_info_result),
-            A2DP_SUCCESS);
-}
-
 TEST_F(StackA2dpTest, test_a2dp_uses_rtp_header) {
   EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_sbc));
   EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_sbc));
@@ -607,16 +574,10 @@
 
 TEST_F(StackA2dpTest, test_a2dp_get_sink_track_channel_type) {
   EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_sbc), 3);
-  EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), -1);
+  EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), 3);
   EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
 }
 
-TEST_F(StackA2dpTest, test_a2dp_get_sink_frames_count_to_process) {
-  EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_sbc), 7);
-  EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_aac), -1);
-  EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_non_a2dp), -1);
-}
-
 TEST_F(StackA2dpTest, test_a2dp_get_object_type_code_aac) {
   EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_sbc), -1);
   EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_aac), 0x80);
@@ -737,7 +698,7 @@
 }
 
 TEST_F(StackA2dpTest, test_a2dp_source_codec_index) {
-  // Explicit tests for known codecs
+  // Explicit tests for known Source codecs
   EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc),
             BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
   EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_capability),
@@ -754,6 +715,24 @@
             BTAV_A2DP_CODEC_INDEX_MAX);
 }
 
+TEST_F(StackA2dpTest, test_a2dp_sink_codec_index) {
+  // Explicit tests for known Sink codecs
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_sbc),
+            BTAV_A2DP_CODEC_INDEX_SINK_SBC);
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_sbc_capability),
+            BTAV_A2DP_CODEC_INDEX_SINK_SBC);
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_sbc_sink_capability),
+            BTAV_A2DP_CODEC_INDEX_SINK_SBC);
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac),
+            BTAV_A2DP_CODEC_INDEX_SINK_AAC);
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac_capability),
+            BTAV_A2DP_CODEC_INDEX_SINK_AAC);
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac_sink_capability),
+            BTAV_A2DP_CODEC_INDEX_SINK_AAC);
+  EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_non_a2dp),
+            BTAV_A2DP_CODEC_INDEX_MAX);
+}
+
 TEST_F(StackA2dpTest, test_a2dp_codec_index_str) {
   // Explicit tests for known codecs
   EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC), "SBC");
@@ -773,7 +752,7 @@
 }
 
 TEST_F(StackA2dpTest, test_a2dp_init_codec_config) {
-  tAVDT_CFG avdt_cfg;
+  AvdtpSepConfig avdt_cfg;
 
   //
   // Test for SBC Source
@@ -917,6 +896,70 @@
   }
   EXPECT_TRUE(codec_config->useRtpHeaderMarkerBit());
 
+  // Create the codec capability - SBC Sink
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  peer_codec_index = A2DP_SinkCodecIndex(codec_info_sbc_capability);
+  EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+  codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_sbc_capability);
+  EXPECT_NE(codec_config, nullptr);
+  EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
+      codec_info_sbc_capability, true /* is_capability */, codec_info_result,
+      true /* select_current_codec */));
+  EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+  }
+  EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
+
+  // Create the codec capability - AAC Sink
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  peer_codec_index = A2DP_SinkCodecIndex(codec_info_aac_capability);
+  EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+  codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_aac_capability);
+  EXPECT_NE(codec_config, nullptr);
+  EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
+      codec_info_aac_capability, true /* is_capability */, codec_info_result,
+      true /* select_current_codec */));
+  EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
+  }
+  EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
+
+  // Create the codec config - SBC Sink
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  peer_codec_index = A2DP_SinkCodecIndex(codec_info_sbc);
+  EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+  codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_sbc);
+  EXPECT_NE(codec_config, nullptr);
+  EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
+      codec_info_sbc, false /* is_capability */, codec_info_result,
+      true /* select_current_codec */));
+  EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+  }
+  EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
+
+  // Create the codec config - AAC Sink
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  peer_codec_index = A2DP_SinkCodecIndex(codec_info_aac);
+  EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+  codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_aac);
+  EXPECT_NE(codec_config, nullptr);
+  EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
+      codec_info_aac, false /* is_capability */, codec_info_result,
+      true /* select_current_codec */));
+  EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
+  }
+  EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
+
   // Test invalid codec info
   uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
   memset(codec_info_result, 0, sizeof(codec_info_result));
diff --git a/stack/test/stack_btu_test.cc b/stack/test/stack_btu_test.cc
index 49dc52e..97e95d2 100644
--- a/stack/test/stack_btu_test.cc
+++ b/stack/test/stack_btu_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
diff --git a/stack/test/stack_smp_test.cc b/stack/test/stack_smp_test.cc
index 2391012..12c10f6 100644
--- a/stack/test/stack_smp_test.cc
+++ b/stack/test/stack_smp_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright 2016 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.
@@ -23,6 +23,7 @@
 #include "bt_trace.h"
 #include "hcidefs.h"
 #include "stack/include/smp_api.h"
+#include "stack/smp/p_256_ecc_pp.h"
 #include "stack/smp/smp_int.h"
 
 /*
@@ -224,4 +225,87 @@
   dump_uint128_reverse(output.param_buf, confirm_str);
   ASSERT_THAT(confirm_str, StrEq(expected_confirm_str));
 }
+
+// Test ECC point validation
+TEST(SmpEccValidationTest, test_valid_points) {
+  Point p;
+
+  // Test data from Bluetooth Core Specification
+  // Version 5.0 | Vol 2, Part G | 7.1.2
+
+  // Sample 1
+  p.x[7] = 0x20b003d2;
+  p.x[6] = 0xf297be2c;
+  p.x[5] = 0x5e2c83a7;
+  p.x[4] = 0xe9f9a5b9;
+  p.x[3] = 0xeff49111;
+  p.x[2] = 0xacf4fddb;
+  p.x[1] = 0xcc030148;
+  p.x[0] = 0x0e359de6;
+
+  p.y[7] = 0xdc809c49;
+  p.y[6] = 0x652aeb6d;
+  p.y[5] = 0x63329abf;
+  p.y[4] = 0x5a52155c;
+  p.y[3] = 0x766345c2;
+  p.y[2] = 0x8fed3024;
+  p.y[1] = 0x741c8ed0;
+  p.y[0] = 0x1589d28b;
+
+  EXPECT_TRUE(ECC_ValidatePoint(p));
+
+  // Sample 2
+  p.x[7] = 0x2c31a47b;
+  p.x[6] = 0x5779809e;
+  p.x[5] = 0xf44cb5ea;
+  p.x[4] = 0xaf5c3e43;
+  p.x[3] = 0xd5f8faad;
+  p.x[2] = 0x4a8794cb;
+  p.x[1] = 0x987e9b03;
+  p.x[0] = 0x745c78dd;
+
+  p.y[7] = 0x91951218;
+  p.y[6] = 0x3898dfbe;
+  p.y[5] = 0xcd52e240;
+  p.y[4] = 0x8e43871f;
+  p.y[3] = 0xd0211091;
+  p.y[2] = 0x17bd3ed4;
+  p.y[1] = 0xeaf84377;
+  p.y[0] = 0x43715d4f;
+
+  EXPECT_TRUE(ECC_ValidatePoint(p));
+}
+
+TEST(SmpEccValidationTest, test_invalid_points) {
+  Point p;
+  multiprecision_init(p.x, 8);
+  multiprecision_init(p.y, 8);
+
+  EXPECT_FALSE(ECC_ValidatePoint(p));
+
+  // Sample 1
+  p.x[7] = 0x20b003d2;
+  p.x[6] = 0xf297be2c;
+  p.x[5] = 0x5e2c83a7;
+  p.x[4] = 0xe9f9a5b9;
+  p.x[3] = 0xeff49111;
+  p.x[2] = 0xacf4fddb;
+  p.x[1] = 0xcc030148;
+  p.x[0] = 0x0e359de6;
+
+  EXPECT_FALSE(ECC_ValidatePoint(p));
+
+  p.y[7] = 0xdc809c49;
+  p.y[6] = 0x652aeb6d;
+  p.y[5] = 0x63329abf;
+  p.y[4] = 0x5a52155c;
+  p.y[3] = 0x766345c2;
+  p.y[2] = 0x8fed3024;
+  p.y[1] = 0x741c8ed0;
+  p.y[0] = 0x1589d28b;
+
+  p.y[0]--;
+
+  EXPECT_FALSE(ECC_ValidatePoint(p));
+}
 }  // namespace testing
diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp
index d5a6b9f..7371c99 100644
--- a/test/rootcanal/Android.bp
+++ b/test/rootcanal/Android.bp
@@ -1,5 +1,5 @@
 //
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright 2017 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.
@@ -22,12 +22,12 @@
         "service.cc",
     ],
 
+    header_libs: ["libbluetooth_headers"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
         "libbase",
         "libchrome",
         "libcutils",
-        "libhardware",
         "libhwbinder",
         "libhidlbase",
         "libhidltransport",
@@ -50,8 +50,47 @@
     include_dirs: [
         "system/bt",
         "system/bt/hci/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/stack/include",
     ],
     init_rc: ["android.hardware.bluetooth@1.0-service.sim.rc"],
 }
+
+cc_library_shared {
+    name: "android.hardware.bluetooth@1.0-impl-sim",
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: [
+        "bluetooth_hci.cc",
+    ],
+
+    header_libs: ["libbluetooth_headers"],
+    shared_libs: [
+        "android.hardware.bluetooth@1.0",
+        "libbase",
+        "libchrome",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-DHAS_NO_BDROID_BUILDCFG",
+    ],
+    static_libs: [
+        "libbluetooth-types",
+        "android.hardware.bluetooth-async",
+        "android.hardware.bluetooth-hci",
+        "libbt-rootcanal",
+    ],
+    include_dirs: [
+        "system/bt",
+        "system/bt/hci/include",
+        "system/bt/internal_include",
+        "system/bt/stack/include",
+    ],
+}
diff --git a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc b/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
index 2f53e5d..9d99c8a 100644
--- a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
+++ b/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
@@ -1,4 +1,4 @@
-service bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.sim
+service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.sim
     class hal
     user bluetooth
     group bluetooth
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index 413b31b..b0281a0 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -22,7 +22,10 @@
 #include <string.h>
 #include <utils/Log.h>
 
+#include "acl_packet.h"
+#include "event_packet.h"
 #include "hci_internals.h"
+#include "sco_packet.h"
 
 namespace android {
 namespace hardware {
@@ -31,11 +34,13 @@
 namespace sim {
 
 using android::hardware::hidl_vec;
+using test_vendor_lib::AclPacket;
 using test_vendor_lib::AsyncManager;
 using test_vendor_lib::AsyncTaskId;
 using test_vendor_lib::CommandPacket;
 using test_vendor_lib::DualModeController;
 using test_vendor_lib::EventPacket;
+using test_vendor_lib::ScoPacket;
 using test_vendor_lib::TaskCallback;
 using test_vendor_lib::TestChannelTransport;
 
@@ -92,10 +97,24 @@
     cb->hciEventReceived(hci_event);
   });
 
-  /* RegisterAcl and RegisterSco
-        cb->aclDataReceived(hci_packet);
-        cb->scoDataReceived(hci_packet);
-  */
+  controller_.RegisterAclChannel([cb](std::unique_ptr<AclPacket> packet) {
+    std::vector<uint8_t> acl_vector = packet->GetPacket();
+    hidl_vec<uint8_t> acl_packet = acl_vector;
+
+    cb->aclDataReceived(acl_packet);
+  });
+
+  controller_.RegisterScoChannel([cb](std::unique_ptr<ScoPacket> packet) {
+    size_t header_bytes = packet->GetHeaderSize();
+    size_t payload_bytes = packet->GetPayloadSize();
+    hidl_vec<uint8_t> sco_packet;
+    sco_packet.resize(header_bytes + payload_bytes);
+    memcpy(sco_packet.data(), packet->GetHeader().data(), header_bytes);
+    memcpy(sco_packet.data() + header_bytes, packet->GetPayload().data(),
+           payload_bytes);
+
+    cb->scoDataReceived(sco_packet);
+  });
 
   controller_.RegisterTaskScheduler(
       [this](std::chrono::milliseconds delay, const TaskCallback& task) {
@@ -142,13 +161,36 @@
   return Void();
 }
 
-Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& /* packet */) {
-  CHECK(false) << __func__ << " not yet implemented";
+Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& packet) {
+  async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
+    uint16_t channel = (packet[0] | (packet[1] << 8)) & 0xfff;
+    AclPacket::PacketBoundaryFlags boundary_flags =
+        static_cast<AclPacket::PacketBoundaryFlags>((packet[1] & 0x30) >> 4);
+    AclPacket::BroadcastFlags broadcast_flags =
+        static_cast<AclPacket::BroadcastFlags>((packet[1] & 0xC0) >> 6);
+
+    std::unique_ptr<AclPacket> acl = std::unique_ptr<AclPacket>(
+        new AclPacket(channel, boundary_flags, broadcast_flags));
+    for (size_t i = 4; i < packet.size(); i++)
+      acl->AddPayloadOctets1(packet[i]);
+
+    controller_.HandleAcl(std::move(acl));
+  });
   return Void();
 }
 
-Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& /* packet */) {
-  CHECK(false) << __func__ << " not yet implemented";
+Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& packet) {
+  async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
+    uint16_t channel = (packet[0] | (packet[1] << 8)) & 0xfff;
+    ScoPacket::PacketStatusFlags packet_status =
+        static_cast<ScoPacket::PacketStatusFlags>((packet[1] & 0x30) >> 4);
+    std::unique_ptr<ScoPacket> sco =
+        std::unique_ptr<ScoPacket>(new ScoPacket(channel, packet_status));
+    for (size_t i = 3; i < packet.size(); i++)
+      sco->AddPayloadOctets1(packet[i]);
+
+    controller_.HandleSco(std::move(sco));
+  });
   return Void();
 }
 
@@ -176,6 +218,11 @@
   });
 }
 
+/* Fallback to shared library if there is no service. */
+IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) {
+  return new BluetoothHci();
+}
+
 }  // namespace gce
 }  // namespace V1_0
 }  // namespace bluetooth
diff --git a/test/rootcanal/bluetooth_hci.h b/test/rootcanal/bluetooth_hci.h
index 2ddf8ee..05ec206 100644
--- a/test/rootcanal/bluetooth_hci.h
+++ b/test/rootcanal/bluetooth_hci.h
@@ -72,6 +72,8 @@
   test_vendor_lib::TestChannelTransport test_channel_transport_;
 };
 
+extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
+
 }  // namespace sim
 }  // namespace V1_0
 }  // namespace bluetooth
diff --git a/test/run_host_unit_tests.py b/test/run_host_unit_tests.py
new file mode 100755
index 0000000..a99140e
--- /dev/null
+++ b/test/run_host_unit_tests.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+#
+# Copyright 2017, 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.
+import sys
+import subprocess
+import os
+import argparse
+
+# Registered host based unit tests
+# Must have 'host_supported: true'
+HOST_TESTS = [
+  'bluetoothtbd_test',
+  'net_test_avrcp',
+  'net_test_btif_state_machine',
+  'net_test_btcore',
+  'net_test_types',
+  'net_test_btpackets',
+]
+
+SOONG_UI_BASH = 'build/soong/soong_ui.bash'
+
+def str2bool(argument, default=False):
+  """ Convert a string to a booleen value. """
+  argument = str(argument)
+  if argument.lower() in ['0', 'f', 'false', 'off', 'no', 'n']:
+    return False
+  elif argument.lower() in ['1', 't', 'true', 'on', 'yes', 'y']:
+    return True
+  return default
+
+
+def check_dir_exists(dir, dirname):
+  if not os.path.isdir(dir):
+    print "Couldn't find %s (%s)!" % (dirname, dir)
+    sys.exit(0)
+
+
+def get_output_from_command(cmd):
+  try:
+    return subprocess.check_output(cmd).strip()
+  except subprocess.CalledProcessError as e:
+    print 'Failed to call {cmd}, return code {code}'.format(cmd=cmd,
+                                                            code=e.returncode)
+    print e
+    return None
+
+
+def get_android_root_or_die():
+  value = os.environ.get('ANDROID_BUILD_TOP')
+  if not value:
+    # Try to find build/soong/soong_ui.bash upwards until root directory
+    current_path = os.path.abspath(os.getcwd())
+    while current_path and os.path.isdir(current_path):
+      soong_ui_bash_path = os.path.join(current_path, SOONG_UI_BASH)
+      if os.path.isfile(soong_ui_bash_path):
+        # Use value returned from Soong UI instead in case definition to TOP
+        # changes in the future
+        value = get_output_from_command((soong_ui_bash_path,
+                                         '--dumpvar-mode',
+                                         '--abs',
+                                         'TOP'))
+        break
+      parent_path = os.path.abspath(os.path.join(current_path, os.pardir))
+      if parent_path == current_path:
+        current_path = None
+      else:
+        current_path = parent_path
+    if not value:
+      print 'Cannot determine ANDROID_BUILD_TOP'
+      sys.exit(1)
+  check_dir_exists(value, '$ANDROID_BUILD_TOP')
+  return value
+
+
+def get_android_host_out_or_die():
+  value = os.environ.get('ANDROID_HOST_OUT')
+  if not value:
+    ANDROID_BUILD_TOP = get_android_root_or_die()
+    value = get_output_from_command((os.path.join(ANDROID_BUILD_TOP,
+                                                  SOONG_UI_BASH),
+                                     '--dumpvar-mode',
+                                     '--abs',
+                                     'HOST_OUT'))
+    if not value:
+      print 'Cannot determine ANDROID_HOST_OUT'
+      sys.exit(1)
+  check_dir_exists(value, '$ANDROID_HOST_OUT')
+  return value
+
+
+def get_android_dist_dir_or_die():
+  # Check if $DIST_DIR is predefined as environment variable
+  value = os.environ.get('DIST_DIR')
+  if not value:
+    # If not use the default path
+    ANDROID_BUILD_TOP = get_android_root_or_die()
+    value = os.path.join(os.path.join(ANDROID_BUILD_TOP, 'out'), 'dist')
+  if not os.path.isdir(value):
+    if os.path.exists(value):
+      print '%s is not a directory!' % (value)
+      sys.exit(1)
+    os.makedirs(value)
+  return value
+
+
+def get_native_test_root_or_die():
+  android_host_out = get_android_host_out_or_die()
+  test_root = os.path.join(android_host_out, 'nativetest64')
+  if not os.path.isdir(test_root):
+    test_root = os.path.join(android_host_out, 'nativetest')
+    if not os.path.isdir(test_root):
+      print 'Neither nativetest64 nor nativetest directory exist,' \
+            ' please compile first'
+      sys.exit(1)
+  return test_root
+
+
+def get_test_cmd_or_die(test_root, test_name, enable_xml, test_filter):
+  test_path = os.path.join(os.path.join(test_root, test_name), test_name)
+  if not os.path.isfile(test_path):
+    print 'Cannot find: ' + test_path
+    sys.exit(1)
+  cmd = [test_path]
+  if enable_xml:
+    dist_dir = get_android_dist_dir_or_die()
+    log_output_path = os.path.join(dist_dir, 'gtest/{0}_test_details.xml'
+                                   .format(test_name))
+    cmd.append('--gtest_output=xml:{0}'.format(log_output_path))
+  if test_filter:
+    cmd.append('--gtest_filter=%s' % test_filter)
+  return cmd
+
+
+# path is relative to Android build top
+def build_target(target, num_tasks):
+  ANDROID_BUILD_TOP = get_android_root_or_die()
+  build_cmd = [SOONG_UI_BASH, '--make-mode']
+  if num_tasks > 1:
+    build_cmd.append('-j' + str(num_tasks))
+  build_cmd.append(target)
+  p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy())
+  return_code = p.wait()
+  if return_code != 0:
+    print 'BUILD FAILED, return code: {0}'.format(str(return_code))
+    sys.exit(1)
+  return
+
+
+def main():
+  """ run_host_unit_tests.py - Run registered host based unit tests
+  """
+  parser = argparse.ArgumentParser(description='Run host based unit tests.')
+  parser.add_argument(
+      '--enable_xml',
+      type=str2bool,
+      dest='enable_xml',
+      nargs='?',
+      const=True,
+      default=False,
+      help=
+      'Whether to output structured XML log output in out/dist/gtest directory')
+  parser.add_argument(
+      '-j',
+      type=int,
+      nargs='?',
+      dest='num_tasks',
+      const=-1,
+      default=-1,
+      help='Number of tasks to run at the same time')
+  parser.add_argument(
+      'rest',
+      nargs=argparse.REMAINDER,
+      help='-- args, other gtest arguments for each individual test')
+  args = parser.parse_args()
+
+  build_target('MODULES-IN-system-bt', args.num_tasks)
+  TEST_ROOT = get_native_test_root_or_die()
+  test_results = []
+  for test in HOST_TESTS:
+    test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest)
+    if subprocess.call(test_cmd) != 0:
+      test_results.append(False)
+    else:
+      test_results.append(True)
+  if not all(test_results):
+    failures = [i for i, x in enumerate(test_results) if not x]
+    for index in failures:
+      print 'TEST FAILLED: ' + HOST_TESTS[index]
+    sys.exit(0)
+  print 'TEST PASSED ' + str(len(test_results)) + ' tests were run'
+  sys.exit(0)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index ab9ecc2..066e8e1 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -3,11 +3,13 @@
 known_tests=(
   bluetoothtbd_test
   net_test_audio_a2dp_hw
+  net_test_avrcp
   net_test_bluetooth
   net_test_btcore
   net_test_bta
   net_test_btif
   net_test_btif_profile_queue
+  net_test_btif_state_machine
   net_test_device
   net_test_hci
   net_test_stack
@@ -17,11 +19,12 @@
   net_test_types
   net_test_btu_message_loop
   net_test_osi
-  performance_test
+  net_test_performance
+  net_test_stack_rfcomm
 )
 
 known_remote_tests=(
-  net_test_rfcomm
+  net_test_rfcomm_suite
 )
 
 
@@ -102,11 +105,18 @@
   adb+=( "-s" "${device}" )
 fi
 
+source ${ANDROID_BUILD_TOP}/build/envsetup.sh
+target_arch=$(gettargetarch)
+
 failed_tests=()
 for spec in "${tests[@]}"
 do
   name="${spec%%.*}"
-  binary="/data/nativetest/${name}/${name}"
+  if [[ $target_arch == *"64"* ]]; then
+    binary="/data/nativetest64/${name}/${name}"
+  else
+    binary="/data/nativetest/${name}/${name}"
+  fi
 
   push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" )
   test_command=( "${adb[@]}" shell "${binary}" )
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index e4d3a2b..ed5b531 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -11,9 +11,9 @@
         "gatt/gatt_test.cc",
         "gatt/gatt_unittest.cc",
     ],
+    header_libs: ["libhardware_headers"],
     shared_libs: [
         "liblog",
-        "libhardware",
         "libcutils",
     ],
     static_libs: [
@@ -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: [
@@ -36,9 +36,9 @@
         "rfcomm/rfcomm_test.cc",
         "rfcomm/rfcomm_unittest.cc",
     ],
+    header_libs: [ "libhardware_headers" ],
     shared_libs: [
         "liblog",
-        "libhardware",
         "libcutils",
     ],
     static_libs: [
@@ -53,7 +53,7 @@
 // Bluetooth test suite for target
 // ========================================================
 cc_test {
-    name: "performance_test",
+    name: "net_test_performance",
     defaults: ["fluoride_defaults"],
     include_dirs: ["system/bt"],
     srcs: [
diff --git a/test/suite/AndroidTest.xml b/test/suite/AndroidTest.xml
index eee642a..d7778e1 100644
--- a/test/suite/AndroidTest.xml
+++ b/test/suite/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright 2017 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.
diff --git a/test/suite/BUILD.gn b/test/suite/BUILD.gn
index d481000..7e68a1a 100644
--- a/test/suite/BUILD.gn
+++ b/test/suite/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
 
   deps = [
     "//btcore",
-    "//main:bluetooth.default",
+    "//main:bluetooth",
     "//service:service",
     "//service:service_unittests",
     "//types:types_unittests",
diff --git a/test/suite/adapter/adapter_unittest.cc b/test/suite/adapter/adapter_unittest.cc
index 730ac5a..24ca3e5 100644
--- a/test/suite/adapter/adapter_unittest.cc
+++ b/test/suite/adapter/adapter_unittest.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -82,7 +82,8 @@
     property_free(new_name);
     new_name = property_new_name("BluetoothTestName2");
   }
-  std::string old_name((const char*)property_as_name(name_property)->name);
+  std::string old_name((const char*)property_as_name(name_property)->name,
+                       name_property->len);
 
   EXPECT_EQ(bt_interface()->set_adapter_property(new_name), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_properties_callback_sem_);
diff --git a/test/suite/adapter/bluetooth_test.cc b/test/suite/adapter/bluetooth_test.cc
index dcb95d1..02132f1 100644
--- a/test/suite/adapter/bluetooth_test.cc
+++ b/test/suite/adapter/bluetooth_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/test/suite/adapter/bluetooth_test.h b/test/suite/adapter/bluetooth_test.h
index 52b8518..e35811d 100644
--- a/test/suite/adapter/bluetooth_test.h
+++ b/test/suite/adapter/bluetooth_test.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@
 #include <hardware/bt_gatt.h>
 #include <hardware/bt_pan.h>
 #include <hardware/bt_sock.h>
-#include <hardware/hardware.h>
 #include <signal.h>
 #include <time.h>
 #include <map>
diff --git a/test/suite/gatt/gatt_test.cc b/test/suite/gatt/gatt_test.cc
index 8f3ff61..e3546d3 100644
--- a/test/suite/gatt/gatt_test.cc
+++ b/test/suite/gatt/gatt_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -91,7 +91,7 @@
 
 void GattTest::RegisterClientCallback(
     bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
-    int clientIf, const bt_uuid_t& app_uuid) {
+    int clientIf, const bluetooth::Uuid& app_uuid) {
   status_ = status;
   client_interface_id_ = clientIf;
   semaphore_post(register_client_callback_sem_);
@@ -106,7 +106,7 @@
 // GATT server callbacks
 void GattTest::RegisterServerCallback(
     bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
-    int server_if, const bt_uuid_t& uuid) {
+    int server_if, const bluetooth::Uuid& uuid) {
   status_ = status;
   server_interface_id_ = server_if;
   semaphore_post(register_server_callback_sem_);
diff --git a/test/suite/gatt/gatt_test.h b/test/suite/gatt/gatt_test.h
index 29e0c24..6005346 100644
--- a/test/suite/gatt/gatt_test.h
+++ b/test/suite/gatt/gatt_test.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@
   // bluetooth::hal::BluetoothGattInterface::ClientObserver overrides
   void RegisterClientCallback(
       bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
-      int clientIf, const bt_uuid_t& app_uuid) override;
+      int clientIf, const bluetooth::Uuid& app_uuid) override;
   void ScanResultCallback(bluetooth::hal::BluetoothGattInterface* /* unused */,
                           const RawAddress& bda, int rssi,
                           std::vector<uint8_t> adv_data) override;
@@ -67,7 +67,7 @@
   // bluetooth::hal::BluetoothGattInterface::ServerObserver overrides
   void RegisterServerCallback(
       bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
-      int server_if, const bt_uuid_t& uuid) override;
+      int server_if, const bluetooth::Uuid& uuid) override;
   void ServiceAddedCallback(
       bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
       int server_if, std::vector<btgatt_db_element_t> service) override;
diff --git a/test/suite/gatt/gatt_unittest.cc b/test/suite/gatt/gatt_unittest.cc
index bc4c29e..26fd850 100644
--- a/test/suite/gatt/gatt_unittest.cc
+++ b/test/suite/gatt/gatt_unittest.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015 Google, Inc.
+ *  Copyright 2015 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,25 +22,11 @@
 
 #include "gatt/gatt_test.h"
 
-#define DEFAULT_RANDOM_SEED 42
-
-namespace {
-
-static void create_random_uuid(bt_uuid_t* uuid, int seed) {
-  srand(seed < 0 ? time(NULL) : seed);
-  for (int i = 0; i < 16; ++i) {
-    uuid->uu[i] = (uint8_t)(rand() % 256);
-  }
-}
-
-}  // namespace
-
 namespace bttest {
 
 TEST_F(GattTest, GattClientRegister) {
   // Registers gatt client.
-  bt_uuid_t gatt_client_uuid;
-  create_random_uuid(&gatt_client_uuid, DEFAULT_RANDOM_SEED);
+  bluetooth::Uuid gatt_client_uuid = bluetooth::Uuid::GetRandom();
   gatt_client_interface()->register_client(gatt_client_uuid);
   semaphore_wait(register_client_callback_sem_);
   EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
@@ -52,8 +38,7 @@
 
 TEST_F(GattTest, GattServerRegister) {
   // Registers gatt server.
-  bt_uuid_t gatt_server_uuid;
-  create_random_uuid(&gatt_server_uuid, DEFAULT_RANDOM_SEED);
+  bluetooth::Uuid gatt_server_uuid = bluetooth::Uuid::GetRandom();
   gatt_server_interface()->register_server(gatt_server_uuid);
   semaphore_wait(register_server_callback_sem_);
   EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
@@ -65,24 +50,20 @@
 
 TEST_F(GattTest, GattServerBuild) {
   // Registers gatt server.
-  bt_uuid_t gatt_server_uuid;
-  create_random_uuid(&gatt_server_uuid, DEFAULT_RANDOM_SEED);
+  bluetooth::Uuid gatt_server_uuid = bluetooth::Uuid::GetRandom();
   gatt_server_interface()->register_server(gatt_server_uuid);
   semaphore_wait(register_server_callback_sem_);
   EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
       << "Error registering GATT server app callback.";
 
   // Service UUID.
-  bt_uuid_t srvc_uuid;
-  create_random_uuid(&srvc_uuid, -1);
+  bluetooth::Uuid srvc_uuid = bluetooth::Uuid::GetRandom();
 
   // Characteristics UUID.
-  bt_uuid_t char_uuid;
-  create_random_uuid(&char_uuid, -1);
+  bluetooth::Uuid char_uuid = bluetooth::Uuid::GetRandom();
 
   // Descriptor UUID.
-  bt_uuid_t desc_uuid;
-  create_random_uuid(&desc_uuid, -1);
+  bluetooth::Uuid desc_uuid = bluetooth::Uuid::GetRandom();
 
   // Adds service.
   int server_if = server_interface_id();
diff --git a/test/suite/rfcomm/rfcomm_test.cc b/test/suite/rfcomm/rfcomm_test.cc
index 194320d..01d9fed 100644
--- a/test/suite/rfcomm/rfcomm_test.cc
+++ b/test/suite/rfcomm/rfcomm_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -19,13 +19,11 @@
 #include "rfcomm/rfcomm_test.h"
 #include "adapter/bluetooth_test.h"
 
-#include "btcore/include/uuid.h"
+using bluetooth::Uuid;
 
 namespace bttest {
 
-const bt_uuid_t RFCommTest::HFP_UUID = {{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00,
-                                         0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
-                                         0x5F, 0x9B, 0x34, 0xFB}};
+const Uuid RFCommTest::HFP_UUID = Uuid::From16Bit(0x111E);
 
 void RFCommTest::SetUp() {
   BluetoothTest::SetUp();
@@ -40,7 +38,6 @@
 
   // Find a bonded device that supports HFP
   bt_remote_bdaddr_ = RawAddress::kEmpty;
-  char value[1280];
 
   bt_property_t* bonded_devices_prop =
       GetProperty(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
@@ -55,12 +52,11 @@
     bt_property_t* uuid_prop =
         GetRemoteDeviceProperty(&devices[i], BT_PROPERTY_UUIDS);
     if (uuid_prop == nullptr) continue;
-    bt_uuid_t* uuids = (bt_uuid_t*)uuid_prop->val;
-    int num_uuids = uuid_prop->len / sizeof(bt_uuid_t);
+    Uuid* uuids = reinterpret_cast<Uuid*>(uuid_prop->val);
+    int num_uuids = uuid_prop->len / sizeof(Uuid);
 
     for (int j = 0; j < num_uuids; j++) {
-      uuid_to_string(&uuids[j], (uuid_string_t*)value);
-      if (!memcmp(uuids + j, &HFP_UUID, sizeof(bt_uuid_t))) {
+      if (!memcmp(uuids + j, &HFP_UUID, sizeof(Uuid))) {
         bt_remote_bdaddr_ = *(devices + i);
         break;
       }
diff --git a/test/suite/rfcomm/rfcomm_test.h b/test/suite/rfcomm/rfcomm_test.h
index 03d2730..52f7f55 100644
--- a/test/suite/rfcomm/rfcomm_test.h
+++ b/test/suite/rfcomm/rfcomm_test.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@
 
   RawAddress bt_remote_bdaddr_;
 
-  static const bt_uuid_t HFP_UUID;
+  static const bluetooth::Uuid HFP_UUID;
 
  private:
   const btsock_interface_t* socket_interface_;
diff --git a/test/suite/rfcomm/rfcomm_unittest.cc b/test/suite/rfcomm/rfcomm_unittest.cc
index eabe73c..357f1aa 100644
--- a/test/suite/rfcomm/rfcomm_unittest.cc
+++ b/test/suite/rfcomm/rfcomm_unittest.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -34,8 +34,7 @@
   size_t len = 0;
 
   error = socket_interface()->connect(&bt_remote_bdaddr_, BTSOCK_RFCOMM,
-                                      (const uint8_t*)&HFP_UUID, 0, &fd, 0,
-                                      getuid());
+                                      &HFP_UUID, 0, &fd, 0, getuid());
   EXPECT_TRUE(error == BT_STATUS_SUCCESS) << "Error creating RFCOMM socket: "
                                           << error;
   EXPECT_TRUE(fd != -1) << "Error creating RFCOMM socket: invalid fd";
@@ -76,8 +75,7 @@
     size_t len = 0;
 
     error = socket_interface()->connect(&bt_remote_bdaddr_, BTSOCK_RFCOMM,
-                                        (const uint8_t*)&HFP_UUID, 0, &fd, 0,
-                                        getuid());
+                                        &HFP_UUID, 0, &fd, 0, getuid());
     ASSERT_TRUE(error == BT_STATUS_SUCCESS) << "Error creating RFCOMM socket: "
                                             << error;
     ASSERT_TRUE(fd != -1) << "Error creating RFCOMM socket: invalid fd";
diff --git a/tools/Android.bp b/tools/Android.bp
index 1357a93..9f75ba7 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/bdtool/Android.mk.disabled b/tools/bdtool/Android.mk.disabled
index fa616e5..4c8321e 100644
--- a/tools/bdtool/Android.mk.disabled
+++ b/tools/bdtool/Android.mk.disabled
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright 2014 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.
diff --git a/tools/bdtool/adapter.c b/tools/bdtool/adapter.c
index c7067fc..a85e3d0 100644
--- a/tools/bdtool/adapter.c
+++ b/tools/bdtool/adapter.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -205,7 +205,7 @@
 
       case BT_PROPERTY_UUIDS: {
         size_t num_uuid;
-        const bt_uuid_t* uuid = property_as_uuids(property, &num_uuid);
+        const Uuid* uuid = property_as_uuids(property, &num_uuid);
         if (uuid) {
           for (size_t i = 0; i < num_uuid; i++) {
             fprintf(stdout, " uuid:%zd: ", i);
diff --git a/tools/bdtool/bdtool.c b/tools/bdtool/bdtool.c
index d37d3d3..44d11ff 100644
--- a/tools/bdtool/bdtool.c
+++ b/tools/bdtool/bdtool.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2014 Google, Inc.
+ *  Copyright 2014 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,12 +26,12 @@
 #include "test/suite/support/callbacks.h"
 #include "test/suite/support/hal.h"
 
-static const bt_uuid_t HFP_UUID = {{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10,
-                                    0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B,
-                                    0x34, 0xFB}};
-static const bt_uuid_t HFP_AG_UUID = {{0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10,
-                                       0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B,
-                                       0x34, 0xFB}};
+static const Uuid HFP_UUID =
+    Uuid::From128BitBE({{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10, 0x00, 0x80,
+                         0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}});
+static const Uuid HFP_AG_UUID =
+    Uuid::From128BitBE({{0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00, 0x80,
+                         0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}});
 
 const bt_interface_t* bt_interface;
 
diff --git a/tools/hci/Android.mk.disabled b/tools/hci/Android.mk.disabled
index 3e2286a..6439dfc 100644
--- a/tools/hci/Android.mk.disabled
+++ b/tools/hci/Android.mk.disabled
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright 2014 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.
diff --git a/tools/mcap_tool/Android.bp b/tools/mcap_tool/Android.bp
index aca07dd..eec750c 100644
--- a/tools/mcap_tool/Android.bp
+++ b/tools/mcap_tool/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
@@ -25,7 +25,7 @@
     ],
     include_dirs: [
       "system/bt",
-      "system/bt/include",
+      "system/bt/internal_include",
       "system/bt/stack/include",
       "system/bt/btcore/include",
     ],
@@ -33,7 +33,6 @@
     shared_libs: [
       "libcutils",
       "libutils",
-      "libhardware",
     ],
     static_libs: [
       "libbtcore",
diff --git a/tools/mcap_tool/BUILD.gn b/tools/mcap_tool/BUILD.gn
index a3f18eb..d41ed56 100644
--- a/tools/mcap_tool/BUILD.gn
+++ b/tools/mcap_tool/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2017 Google, Inc.
+#  Copyright 2017 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
   ]
   include_dirs = [
     "//",
-    "//include",
+    "//internal_include",
     "//stack/include",
     "//btif/include",
     "//btcore/include",
diff --git a/tools/mcap_tool/mcap_test_app.cc b/tools/mcap_tool/mcap_test_app.cc
index f0c1b4f..9515f20 100644
--- a/tools/mcap_tool/mcap_test_app.cc
+++ b/tools/mcap_tool/mcap_test_app.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_app.h b/tools/mcap_tool/mcap_test_app.h
index 691b1f6..db81657 100644
--- a/tools/mcap_tool/mcap_test_app.h
+++ b/tools/mcap_tool/mcap_test_app.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_mcl.cc b/tools/mcap_tool/mcap_test_mcl.cc
index 629350a..53cc329 100644
--- a/tools/mcap_tool/mcap_test_mcl.cc
+++ b/tools/mcap_tool/mcap_test_mcl.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_mcl.h b/tools/mcap_tool/mcap_test_mcl.h
index 01a8aa6..6700fb1 100644
--- a/tools/mcap_tool/mcap_test_mcl.h
+++ b/tools/mcap_tool/mcap_test_mcl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_mdep.cc b/tools/mcap_tool/mcap_test_mdep.cc
index 1fb6412..bd2ce23 100644
--- a/tools/mcap_tool/mcap_test_mdep.cc
+++ b/tools/mcap_tool/mcap_test_mdep.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_mdep.h b/tools/mcap_tool/mcap_test_mdep.h
index a852d52..2278781 100644
--- a/tools/mcap_tool/mcap_test_mdep.h
+++ b/tools/mcap_tool/mcap_test_mdep.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_mdl.cc b/tools/mcap_tool/mcap_test_mdl.cc
index e7b8083..f0cd572 100644
--- a/tools/mcap_tool/mcap_test_mdl.cc
+++ b/tools/mcap_tool/mcap_test_mdl.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_test_mdl.h b/tools/mcap_tool/mcap_test_mdl.h
index 7dadc34..56d8d8c 100644
--- a/tools/mcap_tool/mcap_test_mdl.h
+++ b/tools/mcap_tool/mcap_test_mdl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
diff --git a/tools/mcap_tool/mcap_tool.cc b/tools/mcap_tool/mcap_tool.cc
index fad3378..6ed26aa 100644
--- a/tools/mcap_tool/mcap_tool.cc
+++ b/tools/mcap_tool/mcap_tool.cc
@@ -1,10 +1,10 @@
 /******************************************************************************
  *
- *  Copyright (C) 2015, The linux Foundation. All rights reserved.
+ *  Copyright 2015, The linux Foundation. All rights reserved.
  *
  *  Not a Contribution.
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -42,7 +42,6 @@
 #include <unistd.h>
 
 #include <hardware/bluetooth.h>
-#include <hardware/hardware.h>
 #ifndef OS_GENERIC
 #include <private/android_filesystem_config.h>
 #endif
@@ -53,9 +52,7 @@
 #include "mca_api.h"
 #include "mca_defs.h"
 #include "osi/include/compat.h"
-#if defined(OS_GENERIC)
 #include "hal_util.h"
-#endif
 #include "mcap_test_app.h"
 #include "mcap_test_mcl.h"
 #include "mcap_test_mdep.h"
@@ -98,7 +95,6 @@
 static bool global_strict_mode = false;
 
 /* Device and Profile Interfaces */
-static bluetooth_device_t* sBtDevice = nullptr;
 const bt_interface_t* sBtInterface = nullptr;
 static btmcap_test_interface_t* sMcapTestInterface = nullptr;
 static McapTestApp* sMcapTestApp = nullptr;
@@ -353,23 +349,15 @@
  *******************************************************************************/
 
 int HAL_load(void) {
-  int err = 0;
-  hw_module_t* module;
-  hw_device_t* device;
   LOG(INFO) << "Loading HAL library and extensions";
-#if defined(OS_GENERIC)
-  err = hal_util_load_bt_library((hw_module_t const**)&module);
-#else
-  err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
-#endif
-  if (!err) {
-    err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
-    if (!err) {
-      sBtDevice = (bluetooth_device_t*)device;
-      sBtInterface = sBtDevice->get_bluetooth_interface();
-    }
+  bt_interface_t* interface;
+  int err = hal_util_load_bt_library((const bt_interface_t**)&interface);
+  if (err) {
+    LOG(ERROR) << "Error loading HAL library: " << strerror(err);
+    return err;
   }
-  LOG(INFO) << "HAL library loaded, status: " << strerror(err);
+  sBtInterface = interface;
+  LOG(INFO) << "HAL library loaded";
   return err;
 }
 
diff --git a/types/Android.bp b/types/Android.bp
index cd7d96b..5867d63 100644
--- a/types/Android.bp
+++ b/types/Android.bp
@@ -1,4 +1,11 @@
 // Bluetooth types
+cc_library_headers {
+    name: "libbluetooth-types-header",
+    export_include_dirs: ["./"],
+    vendor_available: true,
+    host_supported: true,
+}
+
 cc_library_static {
     name: "libbluetooth-types",
     vendor_available: true,
@@ -10,8 +17,10 @@
     host_supported: true,
     srcs: [
         "raw_address.cc",
+        "bluetooth/uuid.cc",
     ],
-    export_include_dirs: ["./"],
+    header_libs: ["libbluetooth-types-header"],
+    export_header_lib_headers: ["libbluetooth-types-header"],
 }
 
 // ========================================================
@@ -22,5 +31,6 @@
     host_supported: true,
     srcs: [
         "test/raw_address_unittest.cc",
+        "test/bluetooth/uuid_unittest.cc",
     ],
 }
diff --git a/types/BUILD.gn b/types/BUILD.gn
index 6b18806..617bbb6 100644
--- a/types/BUILD.gn
+++ b/types/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2017 Google, Inc.
+#  Copyright 2017 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 
   sources = [
     "raw_address.cc",
+    "bluetooth/uuid.cc",
   ]
 
   include_dirs = [
@@ -36,6 +37,7 @@
   testonly = true
   sources = [
     "test/raw_address_unittest.cc",
+    "test/bluetooth/uuid_unittest.cc",
   ]
 
   include_dirs = [
diff --git a/types/bluetooth/uuid.cc b/types/bluetooth/uuid.cc
new file mode 100644
index 0000000..4e7d544
--- /dev/null
+++ b/types/bluetooth/uuid.cc
@@ -0,0 +1,172 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2017 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 "uuid.h"
+
+#include <base/rand_util.h>
+#include <base/strings/stringprintf.h>
+#include <algorithm>
+
+namespace bluetooth {
+
+static_assert(sizeof(Uuid) == 16, "Uuid must be 16 bytes long!");
+
+using UUID128Bit = Uuid::UUID128Bit;
+
+const Uuid Uuid::kEmpty = Uuid::From128BitBE(UUID128Bit{{0x00}});
+
+namespace {
+constexpr Uuid kBase = Uuid::From128BitBE(
+    UUID128Bit{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
+                0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}});
+}  // namespace
+
+size_t Uuid::GetShortestRepresentationSize() const {
+  if (memcmp(uu.data() + kNumBytes32, kBase.uu.data() + kNumBytes32,
+             kNumBytes128 - kNumBytes32) != 0) {
+    return kNumBytes128;
+  }
+
+  if (uu[0] == 0 && uu[1] == 0) return kNumBytes16;
+
+  return kNumBytes32;
+}
+
+bool Uuid::Is16Bit() const {
+  return GetShortestRepresentationSize() == kNumBytes16;
+}
+
+uint16_t Uuid::As16Bit() const { return (((uint16_t)uu[2]) << 8) + uu[3]; }
+
+uint32_t Uuid::As32Bit() const {
+  return (((uint32_t)uu[0]) << 24) + (((uint32_t)uu[1]) << 16) +
+         (((uint32_t)uu[2]) << 8) + uu[3];
+}
+
+Uuid Uuid::FromString(const std::string& uuid, bool* is_valid) {
+  if (is_valid) *is_valid = false;
+  Uuid ret = kBase;
+
+  if (uuid.empty()) return ret;
+
+  uint8_t* p = ret.uu.data();
+  if (uuid.size() == kString128BitLen) {
+    if (uuid[8] != '-' || uuid[13] != '-' || uuid[18] != '-' ||
+        uuid[23] != '-') {
+      return ret;
+    }
+
+    int c;
+    int rc =
+        sscanf(uuid.c_str(),
+               "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx"
+               "-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%n",
+               &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6], &p[7], &p[8],
+               &p[9], &p[10], &p[11], &p[12], &p[13], &p[14], &p[15], &c);
+    if (rc != 16) return ret;
+    if (c != kString128BitLen) return ret;
+
+    if (is_valid) *is_valid = true;
+  } else if (uuid.size() == 8) {
+    int c;
+    int rc = sscanf(uuid.c_str(), "%02hhx%02hhx%02hhx%02hhx%n", &p[0], &p[1],
+                    &p[2], &p[3], &c);
+    if (rc != 4) return ret;
+    if (c != 8) return ret;
+
+    if (is_valid) *is_valid = true;
+  } else if (uuid.size() == 4) {
+    int c;
+    int rc = sscanf(uuid.c_str(), "%02hhx%02hhx%n", &p[2], &p[3], &c);
+    if (rc != 2) return ret;
+    if (c != 4) return ret;
+
+    if (is_valid) *is_valid = true;
+  }
+
+  return ret;
+}
+
+Uuid Uuid::From16Bit(uint16_t uuid16) {
+  Uuid u = kBase;
+
+  u.uu[2] = (uint8_t)((0xFF00 & uuid16) >> 8);
+  u.uu[3] = (uint8_t)(0x00FF & uuid16);
+  return u;
+}
+
+Uuid Uuid::From32Bit(uint32_t uuid32) {
+  Uuid u = kBase;
+
+  u.uu[0] = (uint8_t)((0xFF000000 & uuid32) >> 24);
+  u.uu[1] = (uint8_t)((0x00FF0000 & uuid32) >> 16);
+  u.uu[2] = (uint8_t)((0x0000FF00 & uuid32) >> 8);
+  u.uu[3] = (uint8_t)(0x000000FF & uuid32);
+  return u;
+}
+
+Uuid Uuid::From128BitBE(const uint8_t* uuid) {
+  UUID128Bit tmp;
+  memcpy(tmp.data(), uuid, kNumBytes128);
+  return From128BitBE(tmp);
+}
+
+Uuid Uuid::From128BitLE(const UUID128Bit& uuid) {
+  Uuid u;
+  std::reverse_copy(uuid.data(), uuid.data() + kNumBytes128, u.uu.begin());
+  return u;
+}
+
+Uuid Uuid::From128BitLE(const uint8_t* uuid) {
+  UUID128Bit tmp;
+  memcpy(tmp.data(), uuid, kNumBytes128);
+  return From128BitLE(tmp);
+}
+
+const UUID128Bit Uuid::To128BitLE() const {
+  UUID128Bit le;
+  std::reverse_copy(uu.data(), uu.data() + kNumBytes128, le.begin());
+  return le;
+}
+
+const UUID128Bit& Uuid::To128BitBE() const { return uu; }
+
+Uuid Uuid::GetRandom() {
+  Uuid uuid;
+  base::RandBytes(uuid.uu.data(), uuid.uu.size());
+  return uuid;
+}
+
+bool Uuid::IsEmpty() const { return *this == kEmpty; }
+
+bool Uuid::operator<(const Uuid& rhs) const {
+  return std::lexicographical_compare(uu.begin(), uu.end(), rhs.uu.begin(),
+                                      rhs.uu.end());
+}
+
+bool Uuid::operator==(const Uuid& rhs) const { return uu == rhs.uu; }
+
+bool Uuid::operator!=(const Uuid& rhs) const { return uu != rhs.uu; }
+
+std::string Uuid::ToString() const {
+  return base::StringPrintf(
+      "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+      uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], uu[8], uu[9],
+      uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
+}
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/types/bluetooth/uuid.h b/types/bluetooth/uuid.h
new file mode 100644
index 0000000..9fda6b6
--- /dev/null
+++ b/types/bluetooth/uuid.h
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2017 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 <stdint.h>
+#include <array>
+#include <string>
+
+namespace bluetooth {
+
+// This class is representing Bluetooth UUIDs across whole stack.
+// Here are some general endianness rules:
+// 1. UUID is internally kept as as Big Endian.
+// 2. Bytes representing UUID coming from upper layers, Java or Binder, are Big
+//    Endian.
+// 3. Bytes representing UUID coming from lower layer, HCI packets, are Little
+//    Endian.
+// 4. UUID in storage is always string.
+class Uuid final {
+ public:
+  static constexpr size_t kNumBytes128 = 16;
+  static constexpr size_t kNumBytes32 = 4;
+  static constexpr size_t kNumBytes16 = 2;
+
+  static constexpr size_t kString128BitLen = 36;
+
+  static const Uuid kEmpty;  // 00000000-0000-0000-0000-000000000000
+
+  using UUID128Bit = std::array<uint8_t, kNumBytes128>;
+
+  Uuid() = default;
+
+  // Creates and returns a random 128-bit UUID.
+  static Uuid GetRandom();
+
+  // Returns the shortest possible representation of this UUID in bytes. Either
+  // kNumBytes16, kNumBytes32, or kNumBytes128
+  size_t GetShortestRepresentationSize() const;
+
+  // Returns true if this UUID can be represented as 16 bit.
+  bool Is16Bit() const;
+
+  // Returns 16 bit Little Endian representation of this UUID. Use
+  // GetShortestRepresentationSize() or Is16Bit() before using this method.
+  uint16_t As16Bit() const;
+
+  // Returns 32 bit Little Endian representation of this UUID. Use
+  // GetShortestRepresentationSize() before using this method.
+  uint32_t As32Bit() const;
+
+  // Converts string representing 128, 32, or 16 bit UUID in
+  // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, xxxxxxxx, or xxxx format to UUID. If
+  // set, optional is_valid parameter will be set to true if conversion is
+  // successfull, false otherwise.
+  static Uuid FromString(const std::string& uuid, bool* is_valid = nullptr);
+
+  // Converts 16bit Little Endian representation of UUID to UUID
+  static Uuid From16Bit(uint16_t uuid16bit);
+
+  // Converts 32bit Little Endian representation of UUID to UUID
+  static Uuid From32Bit(uint32_t uuid32bit);
+
+  // Converts 128 bit Big Endian array representing UUID to UUID.
+  static constexpr Uuid From128BitBE(const UUID128Bit& uuid) {
+    Uuid u(uuid);
+    return u;
+  }
+
+  // Converts 128 bit Big Endian array representing UUID to UUID. |uuid| points
+  // to beginning of array.
+  static Uuid From128BitBE(const uint8_t* uuid);
+
+  // Converts 128 bit Little Endian array representing UUID to UUID.
+  static Uuid From128BitLE(const UUID128Bit& uuid);
+
+  // Converts 128 bit Little Endian array representing UUID to UUID. |uuid|
+  // points to beginning of array.
+  static Uuid From128BitLE(const uint8_t* uuid);
+
+  // Returns 128 bit Little Endian representation of this UUID
+  const UUID128Bit To128BitLE() const;
+
+  // Returns 128 bit Big Endian representation of this UUID
+  const UUID128Bit& To128BitBE() const;
+
+  // Returns string representing this UUID in
+  // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format, lowercase.
+  std::string ToString() const;
+
+  // Returns true if this UUID is equal to kEmpty
+  bool IsEmpty() const;
+
+  bool operator<(const Uuid& rhs) const;
+  bool operator==(const Uuid& rhs) const;
+  bool operator!=(const Uuid& rhs) const;
+
+ private:
+  constexpr Uuid(const UUID128Bit& val) : uu{val} {};
+
+  // Network-byte-ordered ID (Big Endian).
+  UUID128Bit uu;
+};
+}  // namespace bluetooth
+
+inline std::ostream& operator<<(std::ostream& os, const bluetooth::Uuid& a) {
+  os << a.ToString();
+  return os;
+}
+
+// Custom std::hash specialization so that bluetooth::UUID can be used as a key
+// in std::unordered_map.
+namespace std {
+
+template <>
+struct hash<bluetooth::Uuid> {
+  std::size_t operator()(const bluetooth::Uuid& key) const {
+    const auto& uuid_bytes = key.To128BitBE();
+    std::hash<std::string> hash_fn;
+    return hash_fn(std::string(reinterpret_cast<const char*>(uuid_bytes.data()),
+                               uuid_bytes.size()));
+  }
+};
+
+}  // namespace std
diff --git a/types/raw_address.cc b/types/raw_address.cc
index 22c1081..b39e4552e 100644
--- a/types/raw_address.cc
+++ b/types/raw_address.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -62,6 +62,11 @@
   return true;
 }
 
+size_t RawAddress::FromOctets(const uint8_t* from) {
+  std::copy(from, from + kLength, address);
+  return kLength;
+};
+
 bool RawAddress::IsValidAddress(const std::string& address) {
   RawAddress tmp;
   return RawAddress::FromString(address, tmp);
diff --git a/types/raw_address.h b/types/raw_address.h
index 0b42c04..49443a8 100644
--- a/types/raw_address.h
+++ b/types/raw_address.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -50,6 +50,10 @@
   // returns false. Otherwise, it returns true.
   static bool FromString(const std::string& from, RawAddress& to);
 
+  // Copies |from| raw Bluetooth address octets to the local object.
+  // Returns the number of copied octets - should be always RawAddress::kLength
+  size_t FromOctets(const uint8_t* from);
+
   static bool IsValidAddress(const std::string& address);
 
   static const RawAddress kEmpty;  // 00:00:00:00:00:00
diff --git a/types/test/bluetooth/uuid_unittest.cc b/types/test/bluetooth/uuid_unittest.cc
new file mode 100644
index 0000000..2cdaf54
--- /dev/null
+++ b/types/test/bluetooth/uuid_unittest.cc
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2017 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <bluetooth/uuid.h>
+#include <gtest/gtest.h>
+
+using bluetooth::Uuid;
+
+static const Uuid ONES = Uuid::From128BitBE(
+    Uuid::UUID128Bit{{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+                      0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}});
+
+static const Uuid SEQUENTIAL = Uuid::From128BitBE(
+    Uuid::UUID128Bit{{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xab,
+                      0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89}});
+
+constexpr Uuid kBase = Uuid::From128BitBE(
+    Uuid::UUID128Bit{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80,
+                      0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}});
+
+TEST(UuidTest, IsEmpty) {
+  EXPECT_TRUE(Uuid::kEmpty.IsEmpty());
+  EXPECT_FALSE(kBase.IsEmpty());
+}
+
+TEST(UuidTest, GetShortestRepresentationSize) {
+  EXPECT_TRUE(Uuid::kNumBytes16 == kBase.GetShortestRepresentationSize());
+  EXPECT_TRUE(Uuid::kNumBytes32 ==
+              Uuid::From32Bit(0x01234567).GetShortestRepresentationSize());
+  EXPECT_TRUE(Uuid::kNumBytes128 ==
+              Uuid::kEmpty.GetShortestRepresentationSize());
+}
+
+TEST(UuidTest, As16Bit) {
+  // Even though this is is not 16bit UUID, we should be able to get proper bits
+  EXPECT_EQ((uint16_t)0x1111, ONES.As16Bit());
+  EXPECT_EQ((uint16_t)0x4567, SEQUENTIAL.As16Bit());
+  EXPECT_EQ((uint16_t)0x0000, kBase.As16Bit());
+}
+
+TEST(UuidTest, As32Bit) {
+  // Even though this is is not 32bit UUID, we should be able to get proper bits
+  EXPECT_EQ((uint32_t)0x11111111, ONES.As32Bit());
+  EXPECT_EQ((uint32_t)0x01234567, SEQUENTIAL.As32Bit());
+  EXPECT_EQ((uint32_t)0x00000000, kBase.As32Bit());
+  EXPECT_EQ((uint32_t)0x12345678, Uuid::From32Bit(0x12345678).As32Bit());
+}
+
+TEST(UuidTest, Is16Bit) {
+  EXPECT_FALSE(ONES.Is16Bit());
+  EXPECT_FALSE(SEQUENTIAL.Is16Bit());
+  EXPECT_TRUE(kBase.Is16Bit());
+  EXPECT_TRUE(Uuid::FromString("1ae8").Is16Bit());
+}
+
+TEST(UuidTest, From16Bit) {
+  EXPECT_EQ(Uuid::From16Bit(0x0000), kBase);
+
+  const uint8_t u2[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  Uuid uuid = Uuid::From16Bit(0x0001);
+  EXPECT_TRUE(memcmp(&uuid, u2, sizeof(u2)) == 0);
+
+  const uint8_t u3[] = {0x00, 0x00, 0x55, 0x3e, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  uuid = Uuid::From16Bit(0x553e);
+  EXPECT_TRUE(memcmp(&uuid, u3, sizeof(u3)) == 0);
+
+  const uint8_t u4[] = {0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  uuid = Uuid::From16Bit(0xffff);
+  EXPECT_TRUE(memcmp(&uuid, u4, sizeof(u4)) == 0);
+}
+
+TEST(UuidTest, From32Bit) {
+  EXPECT_EQ(Uuid::From32Bit(0x00000000), kBase);
+
+  const uint8_t u2[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  Uuid uuid = Uuid::From32Bit(0x00000001);
+  EXPECT_TRUE(memcmp(&uuid, u2, sizeof(u2)) == 0);
+
+  const uint8_t u3[] = {0x33, 0x44, 0x55, 0x3e, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  uuid = Uuid::From32Bit(0x3344553e);
+  EXPECT_TRUE(memcmp(&uuid, u3, sizeof(u3)) == 0);
+
+  const uint8_t u4[] = {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  uuid = Uuid::From32Bit(0xffffffff);
+  EXPECT_TRUE(memcmp(&uuid, u4, sizeof(u4)) == 0);
+}
+
+TEST(UuidTest, ToString) {
+  const std::string UUID_BASE_STR = "00000000-0000-1000-8000-00805f9b34fb";
+  const std::string UUID_EMP_STR = "00000000-0000-0000-0000-000000000000";
+  const std::string UUID_ONES_STR = "11111111-1111-1111-1111-111111111111";
+  const std::string UUID_SEQ_STR = "01234567-89ab-cdef-abcd-ef0123456789";
+
+  EXPECT_EQ(UUID_BASE_STR, kBase.ToString());
+  EXPECT_EQ(UUID_EMP_STR, Uuid::kEmpty.ToString());
+  EXPECT_EQ(UUID_ONES_STR, ONES.ToString());
+  EXPECT_EQ(UUID_SEQ_STR, SEQUENTIAL.ToString());
+
+  Uuid uuid = Uuid::From32Bit(0x12345678);
+  EXPECT_EQ("12345678-0000-1000-8000-00805f9b34fb", uuid.ToString());
+}
+
+TEST(BtifStorageTest, test_string_to_uuid) {
+  const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+                        0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
+  bool is_valid = false;
+  Uuid uuid =
+      Uuid::FromString("e39c6285-867f-4b1d-9db0-35fbd9aebf22", &is_valid);
+  EXPECT_TRUE(is_valid);
+  EXPECT_TRUE(memcmp(&uuid, u1, sizeof(u1)) == 0);
+
+  const uint8_t u2[] = {0x00, 0x00, 0x1a, 0xe8, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  is_valid = false;
+  uuid = Uuid::FromString("1Ae8", &is_valid);
+  EXPECT_TRUE(is_valid);
+  EXPECT_TRUE(memcmp(&uuid, u2, sizeof(u2)) == 0);
+
+  const uint8_t u3[] = {0x12, 0x34, 0x11, 0x28, 0x00, 0x00, 0x10, 0x00,
+                        0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+  is_valid = false;
+  uuid = Uuid::FromString("12341128", &is_valid);
+  EXPECT_TRUE(is_valid);
+  EXPECT_TRUE(memcmp(&uuid, u3, sizeof(u3)) == 0);
+}
+
+TEST(BtifStorageTest, test_string_to_uuid_invalid) {
+  bool is_valid = false;
+  Uuid uuid = Uuid::FromString("This is not a UUID", &is_valid);
+  EXPECT_FALSE(is_valid);
+
+  uuid = Uuid::FromString("11212", &is_valid);
+  EXPECT_FALSE(is_valid);
+
+  uuid = Uuid::FromString("1121 ", &is_valid);
+  EXPECT_FALSE(is_valid);
+
+  uuid = Uuid::FromString("AGFE", &is_valid);
+  EXPECT_FALSE(is_valid);
+
+  uuid = Uuid::FromString("ABFG", &is_valid);
+  EXPECT_FALSE(is_valid);
+
+  uuid = Uuid::FromString("e39c6285867f14b1d9db035fbd9aebf22", &is_valid);
+  EXPECT_FALSE(is_valid);
+
+  uuid = Uuid::FromString("12234567-89ab-cdef-abcd-ef01234567ZZ", &is_valid);
+  EXPECT_FALSE(is_valid);
+}
diff --git a/types/test/raw_address_unittest.cc b/types/test/raw_address_unittest.cc
index dcfab85..4ff31e5 100644
--- a/types/test/raw_address_unittest.cc
+++ b/types/test/raw_address_unittest.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 The Android Open Source Project
+ *  Copyright 2017 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.
@@ -23,6 +23,21 @@
 static const char* test_addr = "12:34:56:78:9a:bc";
 static const char* test_addr2 = "cb:a9:87:65:43:21";
 
+TEST(RawAddressUnittest, test_constructor_array) {
+  RawAddress bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+
+  ASSERT_EQ(0x12, bdaddr.address[0]);
+  ASSERT_EQ(0x34, bdaddr.address[1]);
+  ASSERT_EQ(0x56, bdaddr.address[2]);
+  ASSERT_EQ(0x78, bdaddr.address[3]);
+  ASSERT_EQ(0x9A, bdaddr.address[4]);
+  ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+  std::string ret = bdaddr.ToString();
+
+  ASSERT_STREQ(test_addr, ret.c_str());
+}
+
 TEST(RawAddressUnittest, test_is_empty) {
   RawAddress empty;
   RawAddress::FromString("00:00:00:00:00:00", empty);
@@ -49,6 +64,25 @@
   ASSERT_STREQ(test_addr, ret.c_str());
 }
 
+TEST(RawAddressUnittest, test_from_octets) {
+  static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+
+  RawAddress bdaddr;
+  size_t expected_result = RawAddress::kLength;
+  ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
+
+  ASSERT_EQ(0x12, bdaddr.address[0]);
+  ASSERT_EQ(0x34, bdaddr.address[1]);
+  ASSERT_EQ(0x56, bdaddr.address[2]);
+  ASSERT_EQ(0x78, bdaddr.address[3]);
+  ASSERT_EQ(0x9A, bdaddr.address[4]);
+  ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+  std::string ret = bdaddr.ToString();
+
+  ASSERT_STREQ(test_addr, ret.c_str());
+}
+
 TEST(RawAddressTest, test_equals) {
   RawAddress bdaddr1;
   RawAddress bdaddr2;
diff --git a/udrv/Android.bp b/udrv/Android.bp
index a571478..9bf1d83 100644
--- a/udrv/Android.bp
+++ b/udrv/Android.bp
@@ -6,7 +6,7 @@
     ],
     include_dirs: [
       "system/bt",
-      "system/bt/include",
+      "system/bt/internal_include",
       "system/bt/utils/include",
       "system/bt/stack/include",
     ],
diff --git a/udrv/BUILD.gn b/udrv/BUILD.gn
index 679d469..8a0fc92 100644
--- a/udrv/BUILD.gn
+++ b/udrv/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
     "include",
     "uipc",
     "//",
-    "//include",
+    "//internal_include",
     "//stack/include",
     "//utils/include",
   ]
diff --git a/udrv/include/uipc.h b/udrv/include/uipc.h
index 62fadf1..78c6ed3 100644
--- a/udrv/include/uipc.h
+++ b/udrv/include/uipc.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2007-2012 Broadcom Corporation
+ *  Copyright 2007-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
 #ifndef UIPC_H
 #define UIPC_H
 
+#include <mutex>
+
 #define UIPC_CH_ID_AV_CTRL 0
 #define UIPC_CH_ID_AV_AUDIO 1
 #define UIPC_CH_NUM 2
@@ -55,72 +57,85 @@
 
 const char* dump_uipc_event(tUIPC_EVENT event);
 
-/*******************************************************************************
- *
- * Function         UIPC_Init
- *
- * Description      Initialize UIPC module
- *
- * Returns          void
- *
- ******************************************************************************/
-void UIPC_Init(void*);
+typedef struct {
+  int srvfd;
+  int fd;
+  int read_poll_tmo_ms;
+  int task_evt_flags; /* event flags pending to be processed in read task */
+  tUIPC_RCV_CBACK* cback;
+} tUIPC_CHAN;
 
-/*******************************************************************************
- *
- * Function         UIPC_Open
- *
- * Description      Open UIPC interface
- *
- * Returns          void
- *
- ******************************************************************************/
-bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback);
+struct tUIPC_STATE {
+  pthread_t tid; /* main thread id */
+  int running;
+  std::recursive_mutex mutex;
 
-/*******************************************************************************
- *
- * Function         UIPC_Close
- *
- * Description      Close UIPC interface
- *
- * Returns          void
- *
- ******************************************************************************/
-void UIPC_Close(tUIPC_CH_ID ch_id);
+  fd_set active_set;
+  fd_set read_set;
+  int max_fd;
+  int signal_fds[2];
 
-/*******************************************************************************
- *
- * Function         UIPC_Send
- *
- * Description      Called to transmit a message over UIPC.
- *
- * Returns          void
- *
- ******************************************************************************/
-bool UIPC_Send(tUIPC_CH_ID ch_id, uint16_t msg_evt, const uint8_t* p_buf,
-               uint16_t msglen);
+  tUIPC_CHAN ch[UIPC_CH_NUM];
+};
 
-/*******************************************************************************
+/**
+ * Initialize UIPC module
  *
- * Function         UIPC_Read
- *
- * Description      Called to read a message from UIPC.
- *
- * Returns          void
- *
- ******************************************************************************/
-uint32_t UIPC_Read(tUIPC_CH_ID ch_id, uint16_t* p_msg_evt, uint8_t* p_buf,
-                   uint32_t len);
+ * @param user User ID who uses UIPC
+ */
+std::unique_ptr<tUIPC_STATE> UIPC_Init();
 
-/*******************************************************************************
+/**
+ * Open a UIPC channel
  *
- * Function         UIPC_Ioctl
+ * @param ch_id Channel ID
+ * @param p_cback Callback handler
+ * @param socket_path Path to the socket
+ * @return true on success, otherwise false
+ */
+bool UIPC_Open(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback,
+               const char* socket_path);
+
+/**
+ * Closes a channel in UIPC or the entire UIPC module
  *
- * Description      Called to control UIPC.
+ * @param ch_id Channel ID; if ch_id is UIPC_CH_ID_ALL, then cleanup UIPC
+ */
+void UIPC_Close(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id);
+
+/**
+ * Send a message over UIPC
  *
- * Returns          void
+ * @param ch_id Channel ID
+ * @param msg_evt Message event type
+ * @param p_buf Buffer for the message
+ * @param msglen Message length
+ * @return true on success, otherwise false
+ */
+bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint16_t msg_evt,
+               const uint8_t* p_buf, uint16_t msglen);
+
+/**
+ * Read a message from UIPC
  *
- ******************************************************************************/
-bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param);
+ * @param ch_id Channel ID
+ * @param p_msg_evt Message event type
+ * @param p_buf Buffer for the message
+ * @param len Bytes to read
+ * @return true on success, otherwise false
+ */
+uint32_t UIPC_Read(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint16_t* p_msg_evt,
+                   uint8_t* p_buf, uint32_t len);
+
+/**
+ * Control the UIPC parameter
+ *
+ * @param ch_id Channel ID
+ * @param request Request type
+ * @param param Optional parameters
+ * @return true on success, otherwise false
+ */
+bool UIPC_Ioctl(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint32_t request,
+                void* param);
 
 #endif /* UIPC_H */
diff --git a/udrv/ulinux/uipc.cc b/udrv/ulinux/uipc.cc
index 4f7d126..e2f2950 100644
--- a/udrv/ulinux/uipc.cc
+++ b/udrv/ulinux/uipc.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
 #include <sys/un.h>
 #include <unistd.h>
 #include <mutex>
+#include <set>
 
 #include "audio_a2dp_hw/include/audio_a2dp_hw.h"
 #include "bt_common.h"
@@ -74,38 +75,10 @@
   UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
 } tUIPC_TASK_FLAGS;
 
-typedef struct {
-  int srvfd;
-  int fd;
-  int read_poll_tmo_ms;
-  int task_evt_flags; /* event flags pending to be processed in read task */
-  tUIPC_RCV_CBACK* cback;
-} tUIPC_CHAN;
-
-typedef struct {
-  pthread_t tid; /* main thread id */
-  int running;
-  std::recursive_mutex mutex;
-
-  fd_set active_set;
-  fd_set read_set;
-  int max_fd;
-  int signal_fds[2];
-
-  tUIPC_CHAN ch[UIPC_CH_NUM];
-} tUIPC_MAIN;
-
-/*****************************************************************************
- *  Static variables
- *****************************************************************************/
-
-static tUIPC_MAIN uipc_main;
-
 /*****************************************************************************
  *  Static functions
  *****************************************************************************/
-
-static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
+static int uipc_close_ch_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id);
 
 /*****************************************************************************
  *  Externs
@@ -205,29 +178,29 @@
  *
  ****************************************************************************/
 
-static int uipc_main_init(void) {
+static int uipc_main_init(tUIPC_STATE& uipc) {
   int i;
 
   BTIF_TRACE_EVENT("### uipc_main_init ###");
 
-  uipc_main.tid = 0;
-  uipc_main.running = 0;
-  memset(&uipc_main.active_set, 0, sizeof(uipc_main.active_set));
-  memset(&uipc_main.read_set, 0, sizeof(uipc_main.read_set));
-  uipc_main.max_fd = 0;
-  memset(&uipc_main.signal_fds, 0, sizeof(uipc_main.signal_fds));
-  memset(&uipc_main.ch, 0, sizeof(uipc_main.ch));
+  uipc.tid = 0;
+  uipc.running = 0;
+  memset(&uipc.active_set, 0, sizeof(uipc.active_set));
+  memset(&uipc.read_set, 0, sizeof(uipc.read_set));
+  uipc.max_fd = 0;
+  memset(&uipc.signal_fds, 0, sizeof(uipc.signal_fds));
+  memset(&uipc.ch, 0, sizeof(uipc.ch));
 
   /* setup interrupt socket pair */
-  if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc_main.signal_fds) < 0) {
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc.signal_fds) < 0) {
     return -1;
   }
 
-  FD_SET(uipc_main.signal_fds[0], &uipc_main.active_set);
-  uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.signal_fds[0]);
+  FD_SET(uipc.signal_fds[0], &uipc.active_set);
+  uipc.max_fd = MAX(uipc.max_fd, uipc.signal_fds[0]);
 
   for (i = 0; i < UIPC_CH_NUM; i++) {
-    tUIPC_CHAN* p = &uipc_main.ch[i];
+    tUIPC_CHAN* p = &uipc.ch[i];
     p->srvfd = UIPC_DISCONNECTED;
     p->fd = UIPC_DISCONNECTED;
     p->task_evt_flags = 0;
@@ -237,105 +210,104 @@
   return 0;
 }
 
-void uipc_main_cleanup(void) {
+void uipc_main_cleanup(tUIPC_STATE& uipc) {
   int i;
 
   BTIF_TRACE_EVENT("uipc_main_cleanup");
 
-  close(uipc_main.signal_fds[0]);
-  close(uipc_main.signal_fds[1]);
+  close(uipc.signal_fds[0]);
+  close(uipc.signal_fds[1]);
 
   /* close any open channels */
-  for (i = 0; i < UIPC_CH_NUM; i++) uipc_close_ch_locked(i);
+  for (i = 0; i < UIPC_CH_NUM; i++) uipc_close_ch_locked(uipc, i);
 }
 
 /* check pending events in read task */
-static void uipc_check_task_flags_locked(void) {
+static void uipc_check_task_flags_locked(tUIPC_STATE& uipc) {
   int i;
 
   for (i = 0; i < UIPC_CH_NUM; i++) {
-    if (uipc_main.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) {
-      uipc_main.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
-      uipc_close_ch_locked(i);
+    if (uipc.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) {
+      uipc.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
+      uipc_close_ch_locked(uipc, i);
     }
 
     /* add here */
   }
 }
 
-static int uipc_check_fd_locked(tUIPC_CH_ID ch_id) {
+static int uipc_check_fd_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
   if (ch_id >= UIPC_CH_NUM) return -1;
 
-  // BTIF_TRACE_EVENT("CHECK SRVFD %d (ch %d)", uipc_main.ch[ch_id].srvfd,
+  // BTIF_TRACE_EVENT("CHECK SRVFD %d (ch %d)", uipc.ch[ch_id].srvfd,
   // ch_id);
 
-  if (SAFE_FD_ISSET(uipc_main.ch[ch_id].srvfd, &uipc_main.read_set)) {
+  if (SAFE_FD_ISSET(uipc.ch[ch_id].srvfd, &uipc.read_set)) {
     BTIF_TRACE_EVENT("INCOMING CONNECTION ON CH %d", ch_id);
 
     // Close the previous connection
-    if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
-      BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
-      close(uipc_main.ch[ch_id].fd);
-      FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
-      uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
+    if (uipc.ch[ch_id].fd != UIPC_DISCONNECTED) {
+      BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc.ch[ch_id].fd);
+      close(uipc.ch[ch_id].fd);
+      FD_CLR(uipc.ch[ch_id].fd, &uipc.active_set);
+      uipc.ch[ch_id].fd = UIPC_DISCONNECTED;
     }
 
-    uipc_main.ch[ch_id].fd = accept_server_socket(uipc_main.ch[ch_id].srvfd);
+    uipc.ch[ch_id].fd = accept_server_socket(uipc.ch[ch_id].srvfd);
 
-    BTIF_TRACE_EVENT("NEW FD %d", uipc_main.ch[ch_id].fd);
+    BTIF_TRACE_EVENT("NEW FD %d", uipc.ch[ch_id].fd);
 
-    if ((uipc_main.ch[ch_id].fd >= 0) && uipc_main.ch[ch_id].cback) {
+    if ((uipc.ch[ch_id].fd >= 0) && uipc.ch[ch_id].cback) {
       /*  if we have a callback we should add this fd to the active set
           and notify user with callback event */
-      BTIF_TRACE_EVENT("ADD FD %d TO ACTIVE SET", uipc_main.ch[ch_id].fd);
-      FD_SET(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
-      uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.ch[ch_id].fd);
+      BTIF_TRACE_EVENT("ADD FD %d TO ACTIVE SET", uipc.ch[ch_id].fd);
+      FD_SET(uipc.ch[ch_id].fd, &uipc.active_set);
+      uipc.max_fd = MAX(uipc.max_fd, uipc.ch[ch_id].fd);
     }
 
-    if (uipc_main.ch[ch_id].fd < 0) {
+    if (uipc.ch[ch_id].fd < 0) {
       BTIF_TRACE_ERROR("FAILED TO ACCEPT CH %d", ch_id);
       return -1;
     }
 
-    if (uipc_main.ch[ch_id].cback)
-      uipc_main.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
+    if (uipc.ch[ch_id].cback) uipc.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
   }
 
-  // BTIF_TRACE_EVENT("CHECK FD %d (ch %d)", uipc_main.ch[ch_id].fd, ch_id);
+  // BTIF_TRACE_EVENT("CHECK FD %d (ch %d)", uipc.ch[ch_id].fd, ch_id);
 
-  if (SAFE_FD_ISSET(uipc_main.ch[ch_id].fd, &uipc_main.read_set)) {
+  if (SAFE_FD_ISSET(uipc.ch[ch_id].fd, &uipc.read_set)) {
     // BTIF_TRACE_EVENT("INCOMING DATA ON CH %d", ch_id);
 
-    if (uipc_main.ch[ch_id].cback)
-      uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
+    if (uipc.ch[ch_id].cback)
+      uipc.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
   }
   return 0;
 }
 
-static void uipc_check_interrupt_locked(void) {
-  if (SAFE_FD_ISSET(uipc_main.signal_fds[0], &uipc_main.read_set)) {
+static void uipc_check_interrupt_locked(tUIPC_STATE& uipc) {
+  if (SAFE_FD_ISSET(uipc.signal_fds[0], &uipc.read_set)) {
     char sig_recv = 0;
-    OSI_NO_INTR(recv(uipc_main.signal_fds[0], &sig_recv, sizeof(sig_recv),
-                     MSG_WAITALL));
+    OSI_NO_INTR(
+        recv(uipc.signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL));
   }
 }
 
-static inline void uipc_wakeup_locked(void) {
+static inline void uipc_wakeup_locked(tUIPC_STATE& uipc) {
   char sig_on = 1;
   BTIF_TRACE_EVENT("UIPC SEND WAKE UP");
 
-  OSI_NO_INTR(send(uipc_main.signal_fds[1], &sig_on, sizeof(sig_on), 0));
+  OSI_NO_INTR(send(uipc.signal_fds[1], &sig_on, sizeof(sig_on), 0));
 }
 
-static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, const char* name,
-                                    tUIPC_RCV_CBACK* cback) {
+static int uipc_setup_server_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id,
+                                    const char* name, tUIPC_RCV_CBACK* cback) {
   int fd;
 
   BTIF_TRACE_EVENT("SETUP CHANNEL SERVER %d", ch_id);
 
   if (ch_id >= UIPC_CH_NUM) return -1;
 
-  std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
+  std::lock_guard<std::recursive_mutex> guard(uipc.mutex);
 
   fd = create_server_socket(name);
 
@@ -345,27 +317,27 @@
   }
 
   BTIF_TRACE_EVENT("ADD SERVER FD TO ACTIVE SET %d", fd);
-  FD_SET(fd, &uipc_main.active_set);
-  uipc_main.max_fd = MAX(uipc_main.max_fd, fd);
+  FD_SET(fd, &uipc.active_set);
+  uipc.max_fd = MAX(uipc.max_fd, fd);
 
-  uipc_main.ch[ch_id].srvfd = fd;
-  uipc_main.ch[ch_id].cback = cback;
-  uipc_main.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
+  uipc.ch[ch_id].srvfd = fd;
+  uipc.ch[ch_id].cback = cback;
+  uipc.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
 
   /* trigger main thread to update read set */
-  uipc_wakeup_locked();
+  uipc_wakeup_locked(uipc);
 
   return 0;
 }
 
-static void uipc_flush_ch_locked(tUIPC_CH_ID ch_id) {
+static void uipc_flush_ch_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
   char buf[UIPC_FLUSH_BUFFER_SIZE];
   struct pollfd pfd;
 
   pfd.events = POLLIN;
-  pfd.fd = uipc_main.ch[ch_id].fd;
+  pfd.fd = uipc.ch[ch_id].fd;
 
-  if (uipc_main.ch[ch_id].fd == UIPC_DISCONNECTED) {
+  if (uipc.ch[ch_id].fd == UIPC_DISCONNECTED) {
     BTIF_TRACE_EVENT("%s() - fd disconnected. Exiting", __func__);
     return;
   }
@@ -397,65 +369,65 @@
   }
 }
 
-static void uipc_flush_locked(tUIPC_CH_ID ch_id) {
+static void uipc_flush_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
   if (ch_id >= UIPC_CH_NUM) return;
 
   switch (ch_id) {
     case UIPC_CH_ID_AV_CTRL:
-      uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL);
+      uipc_flush_ch_locked(uipc, UIPC_CH_ID_AV_CTRL);
       break;
 
     case UIPC_CH_ID_AV_AUDIO:
-      uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO);
+      uipc_flush_ch_locked(uipc, UIPC_CH_ID_AV_AUDIO);
       break;
   }
 }
 
-static int uipc_close_ch_locked(tUIPC_CH_ID ch_id) {
+static int uipc_close_ch_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
   int wakeup = 0;
 
   BTIF_TRACE_EVENT("CLOSE CHANNEL %d", ch_id);
 
   if (ch_id >= UIPC_CH_NUM) return -1;
 
-  if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
-    BTIF_TRACE_EVENT("CLOSE SERVER (FD %d)", uipc_main.ch[ch_id].srvfd);
-    close(uipc_main.ch[ch_id].srvfd);
-    FD_CLR(uipc_main.ch[ch_id].srvfd, &uipc_main.active_set);
-    uipc_main.ch[ch_id].srvfd = UIPC_DISCONNECTED;
+  if (uipc.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
+    BTIF_TRACE_EVENT("CLOSE SERVER (FD %d)", uipc.ch[ch_id].srvfd);
+    close(uipc.ch[ch_id].srvfd);
+    FD_CLR(uipc.ch[ch_id].srvfd, &uipc.active_set);
+    uipc.ch[ch_id].srvfd = UIPC_DISCONNECTED;
     wakeup = 1;
   }
 
-  if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
-    BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
-    close(uipc_main.ch[ch_id].fd);
-    FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
-    uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
+  if (uipc.ch[ch_id].fd != UIPC_DISCONNECTED) {
+    BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc.ch[ch_id].fd);
+    close(uipc.ch[ch_id].fd);
+    FD_CLR(uipc.ch[ch_id].fd, &uipc.active_set);
+    uipc.ch[ch_id].fd = UIPC_DISCONNECTED;
     wakeup = 1;
   }
 
   /* notify this connection is closed */
-  if (uipc_main.ch[ch_id].cback)
-    uipc_main.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
+  if (uipc.ch[ch_id].cback) uipc.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
 
   /* trigger main thread update if something was updated */
-  if (wakeup) uipc_wakeup_locked();
+  if (wakeup) uipc_wakeup_locked(uipc);
 
   return 0;
 }
 
-void uipc_close_locked(tUIPC_CH_ID ch_id) {
-  if (uipc_main.ch[ch_id].srvfd == UIPC_DISCONNECTED) {
+void uipc_close_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
+  if (uipc.ch[ch_id].srvfd == UIPC_DISCONNECTED) {
     BTIF_TRACE_EVENT("CHANNEL %d ALREADY CLOSED", ch_id);
     return;
   }
 
   /* schedule close on this channel */
-  uipc_main.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
-  uipc_wakeup_locked();
+  uipc.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
+  uipc_wakeup_locked(uipc);
 }
 
-static void* uipc_read_task(UNUSED_ATTR void* arg) {
+static void* uipc_read_task(void* arg) {
+  tUIPC_STATE& uipc = *((tUIPC_STATE*)arg);
   int ch_id;
   int result;
 
@@ -463,11 +435,10 @@
 
   raise_priority_a2dp(TASK_UIPC_READ);
 
-  while (uipc_main.running) {
-    uipc_main.read_set = uipc_main.active_set;
+  while (uipc.running) {
+    uipc.read_set = uipc.active_set;
 
-    result =
-        select(uipc_main.max_fd + 1, &uipc_main.read_set, NULL, NULL, NULL);
+    result = select(uipc.max_fd + 1, &uipc.read_set, NULL, NULL, NULL);
 
     if (result == 0) {
       BTIF_TRACE_EVENT("select timeout");
@@ -481,40 +452,40 @@
     }
 
     {
-      std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
+      std::lock_guard<std::recursive_mutex> guard(uipc.mutex);
 
       /* clear any wakeup interrupt */
-      uipc_check_interrupt_locked();
+      uipc_check_interrupt_locked(uipc);
 
       /* check pending task events */
-      uipc_check_task_flags_locked();
+      uipc_check_task_flags_locked(uipc);
 
       /* make sure we service audio channel first */
-      uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);
+      uipc_check_fd_locked(uipc, UIPC_CH_ID_AV_AUDIO);
 
       /* check for other connections */
       for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
-        if (ch_id != UIPC_CH_ID_AV_AUDIO) uipc_check_fd_locked(ch_id);
+        if (ch_id != UIPC_CH_ID_AV_AUDIO) uipc_check_fd_locked(uipc, ch_id);
       }
     }
   }
 
   BTIF_TRACE_EVENT("UIPC READ THREAD EXITING");
 
-  uipc_main_cleanup();
+  uipc_main_cleanup(uipc);
 
-  uipc_main.tid = 0;
+  uipc.tid = 0;
 
   BTIF_TRACE_EVENT("UIPC READ THREAD DONE");
 
   return nullptr;
 }
 
-int uipc_start_main_server_thread(void) {
-  uipc_main.running = 1;
+int uipc_start_main_server_thread(tUIPC_STATE& uipc) {
+  uipc.running = 1;
 
-  if (pthread_create(&uipc_main.tid, (const pthread_attr_t*)NULL,
-                     uipc_read_task, nullptr) < 0) {
+  if (pthread_create(&uipc.tid, (const pthread_attr_t*)NULL, uipc_read_task,
+                     &uipc) < 0) {
     BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
     return -1;
   }
@@ -523,19 +494,19 @@
 }
 
 /* blocking call */
-void uipc_stop_main_server_thread(void) {
+void uipc_stop_main_server_thread(tUIPC_STATE& uipc) {
   /* request shutdown of read thread */
   {
-    std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
-    uipc_main.running = 0;
-    uipc_wakeup_locked();
+    std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
+    uipc.running = 0;
+    uipc_wakeup_locked(uipc);
   }
 
   /* wait until read thread is fully terminated */
   /* tid might hold pointer value where it's value
      is negative vaule with singed bit is set, so
      corrected the logic to check zero or non zero */
-  if (uipc_main.tid) pthread_join(uipc_main.tid, NULL);
+  if (uipc.tid) pthread_join(uipc.tid, NULL);
 }
 
 /*******************************************************************************
@@ -547,12 +518,16 @@
  ** Returns          void
  **
  ******************************************************************************/
-
-void UIPC_Init(UNUSED_ATTR void* p_data) {
+std::unique_ptr<tUIPC_STATE> UIPC_Init() {
+  std::unique_ptr<tUIPC_STATE> uipc = std::make_unique<tUIPC_STATE>();
   BTIF_TRACE_DEBUG("UIPC_Init");
 
-  uipc_main_init();
-  uipc_start_main_server_thread();
+  std::lock_guard<std::recursive_mutex> lock(uipc->mutex);
+
+  uipc_main_init(*uipc);
+  uipc_start_main_server_thread(*uipc);
+
+  return uipc;
 }
 
 /*******************************************************************************
@@ -564,29 +539,22 @@
  ** Returns          true in case of success, false in case of failure.
  **
  ******************************************************************************/
-bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback) {
+bool UIPC_Open(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback,
+               const char* socket_path) {
   BTIF_TRACE_DEBUG("UIPC_Open : ch_id %d, p_cback %x", ch_id, p_cback);
 
-  std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+  std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
 
   if (ch_id >= UIPC_CH_NUM) {
     return false;
   }
 
-  if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
+  if (uipc.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
     BTIF_TRACE_EVENT("CHANNEL %d ALREADY OPEN", ch_id);
     return 0;
   }
 
-  switch (ch_id) {
-    case UIPC_CH_ID_AV_CTRL:
-      uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback);
-      break;
-
-    case UIPC_CH_ID_AV_AUDIO:
-      uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback);
-      break;
-  }
+  uipc_setup_server_locked(uipc, ch_id, socket_path, p_cback);
 
   return true;
 }
@@ -600,18 +568,18 @@
  ** Returns          void
  **
  ******************************************************************************/
-
-void UIPC_Close(tUIPC_CH_ID ch_id) {
+void UIPC_Close(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
   BTIF_TRACE_DEBUG("UIPC_Close : ch_id %d", ch_id);
 
   /* special case handling uipc shutdown */
   if (ch_id != UIPC_CH_ID_ALL) {
-    std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
-    uipc_close_locked(ch_id);
+    std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
+    uipc_close_locked(uipc, ch_id);
     return;
   }
+
   BTIF_TRACE_DEBUG("UIPC_Close : waiting for shutdown to complete");
-  uipc_stop_main_server_thread();
+  uipc_stop_main_server_thread(uipc);
   BTIF_TRACE_DEBUG("UIPC_Close : shutdown complete");
 }
 
@@ -624,14 +592,15 @@
  ** Returns          true in case of success, false in case of failure.
  **
  ******************************************************************************/
-bool UIPC_Send(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t msg_evt,
-               const uint8_t* p_buf, uint16_t msglen) {
+bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id,
+               UNUSED_ATTR uint16_t msg_evt, const uint8_t* p_buf,
+               uint16_t msglen) {
   BTIF_TRACE_DEBUG("UIPC_Send : ch_id:%d %d bytes", ch_id, msglen);
 
-  std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+  std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
 
   ssize_t ret;
-  OSI_NO_INTR(ret = write(uipc_main.ch[ch_id].fd, p_buf, msglen));
+  OSI_NO_INTR(ret = write(uipc.ch[ch_id].fd, p_buf, msglen));
   if (ret < 0) {
     BTIF_TRACE_ERROR("failed to write (%s)", strerror(errno));
   }
@@ -649,10 +618,11 @@
  **
  ******************************************************************************/
 
-uint32_t UIPC_Read(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t* p_msg_evt,
-                   uint8_t* p_buf, uint32_t len) {
+uint32_t UIPC_Read(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id,
+                   UNUSED_ATTR uint16_t* p_msg_evt, uint8_t* p_buf,
+                   uint32_t len) {
   int n_read = 0;
-  int fd = uipc_main.ch[ch_id].fd;
+  int fd = uipc.ch[ch_id].fd;
   struct pollfd pfd;
 
   if (ch_id >= UIPC_CH_NUM) {
@@ -673,10 +643,10 @@
        a read for more than poll timeout */
 
     int poll_ret;
-    OSI_NO_INTR(poll_ret = poll(&pfd, 1, uipc_main.ch[ch_id].read_poll_tmo_ms));
+    OSI_NO_INTR(poll_ret = poll(&pfd, 1, uipc.ch[ch_id].read_poll_tmo_ms));
     if (poll_ret == 0) {
       BTIF_TRACE_WARNING("poll timeout (%d ms)",
-                         uipc_main.ch[ch_id].read_poll_tmo_ms);
+                         uipc.ch[ch_id].read_poll_tmo_ms);
       break;
     }
     if (poll_ret < 0) {
@@ -689,8 +659,8 @@
 
     if (pfd.revents & (POLLHUP | POLLNVAL)) {
       BTIF_TRACE_WARNING("poll : channel detached remotely");
-      std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
-      uipc_close_locked(ch_id);
+      std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
+      uipc_close_locked(uipc, ch_id);
       return 0;
     }
 
@@ -701,8 +671,8 @@
 
     if (n == 0) {
       BTIF_TRACE_WARNING("UIPC_Read : channel detached remotely");
-      std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
-      uipc_close_locked(ch_id);
+      std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
+      uipc_close_locked(uipc, ch_id);
       return 0;
     }
 
@@ -727,37 +697,38 @@
  *
  ******************************************************************************/
 
-extern bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param) {
+extern bool UIPC_Ioctl(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint32_t request,
+                       void* param) {
   BTIF_TRACE_DEBUG("#### UIPC_Ioctl : ch_id %d, request %d ####", ch_id,
                    request);
-  std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+  std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
 
   switch (request) {
     case UIPC_REQ_RX_FLUSH:
-      uipc_flush_locked(ch_id);
+      uipc_flush_locked(uipc, ch_id);
       break;
 
     case UIPC_REG_CBACK:
       // BTIF_TRACE_EVENT("register callback ch %d srvfd %d, fd %d", ch_id,
-      // uipc_main.ch[ch_id].srvfd, uipc_main.ch[ch_id].fd);
-      uipc_main.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param;
+      // uipc.ch[ch_id].srvfd, uipc.ch[ch_id].fd);
+      uipc.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param;
       break;
 
     case UIPC_REG_REMOVE_ACTIVE_READSET:
       /* user will read data directly and not use select loop */
-      if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
+      if (uipc.ch[ch_id].fd != UIPC_DISCONNECTED) {
         /* remove this channel from active set */
-        FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+        FD_CLR(uipc.ch[ch_id].fd, &uipc.active_set);
 
         /* refresh active set */
-        uipc_wakeup_locked();
+        uipc_wakeup_locked(uipc);
       }
       break;
 
     case UIPC_SET_READ_POLL_TMO:
-      uipc_main.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
+      uipc.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
       BTIF_TRACE_EVENT("UIPC_SET_READ_POLL_TMO : CH %d, TMO %d ms", ch_id,
-                       uipc_main.ch[ch_id].read_poll_tmo_ms);
+                       uipc.ch[ch_id].read_poll_tmo_ms);
       break;
 
     default:
diff --git a/utils/BUILD.gn b/utils/BUILD.gn
index 13d57a1..c6e7dab 100644
--- a/utils/BUILD.gn
+++ b/utils/BUILD.gn
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2015 Google, Inc.
+#  Copyright 2015 Google, Inc.
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
diff --git a/utils/include/bt_utils.h b/utils/include/bt_utils.h
index 2b1a7b1..821e51c 100644
--- a/utils/include/bt_utils.h
+++ b/utils/include/bt_utils.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2009-2012 Broadcom Corporation
+ *  Copyright 2009-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/utils/src/bt_utils.cc b/utils/src/bt_utils.cc
index 65bd7af..6d93ac4 100644
--- a/utils/src/bt_utils.cc
+++ b/utils/src/bt_utils.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2012 Broadcom Corporation
+ *  Copyright 2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/vendor_libs/Android.mk b/vendor_libs/Android.mk
deleted file mode 100644
index 31d6e6b..0000000
--- a/vendor_libs/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-# Common C/C++ compiler flags for test-vendor lib
-#
-# -Wno-gnu-variable-sized-type-not-at-end is needed, because struct BT_HDR
-#  is defined as a variable-size header in a struct.
-# -Wno-typedef-redefinition is needed because of the way the struct typedef
-#  is done in osi/include header files. This issue can be obsoleted by
-#  switching to C11 or C++.
-# -Wno-unused-parameter is needed, because there are too many unused
-#  parameters in all the code.
-#
-test-vendor_CFLAGS += \
-  -fvisibility=hidden \
-  -Wall \
-  -Wextra \
-  -Werror \
-  -Wno-gnu-variable-sized-type-not-at-end \
-  -Wno-typedef-redefinition \
-  -Wno-unused-parameter \
-  -DLOG_NDEBUG=1 \
-  -DEXPORT_SYMBOL="__attribute__((visibility(\"default\")))"
-
-test-vendor_CONLYFLAGS += -std=c99
-
-include $(call all-subdir-makefiles)
-
-# Cleanup our locals
-test-vendor_CFLAGS :=
-test-vendor_CONLYFLAGS :=
diff --git a/vendor_libs/linux/interface/Android.bp b/vendor_libs/linux/interface/Android.bp
index 56baf9e..8d6caa4 100644
--- a/vendor_libs/linux/interface/Android.bp
+++ b/vendor_libs/linux/interface/Android.bp
@@ -1,5 +1,5 @@
 //
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright 2017 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.
@@ -24,11 +24,12 @@
         "async_fd_watcher.cc",
         "service.cc"
     ],
+    cflags: ["-Wall", "-Werror"],
+    header_libs: ["libbluetooth_headers"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
         "libbase",
         "libcutils",
-        "libhardware",
         "libhidlbase",
         "libhidltransport",
         "liblog",
diff --git a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te b/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
index 32349b9..22d9cf0 100644
--- a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
+++ b/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
@@ -1,5 +1,5 @@
 type hal_bluetooth_btlinux, domain;
-type hal_bluetooth_btlinux_exec, exec_type, file_type;
+type hal_bluetooth_btlinux_exec, exec_type, file_type, vendor_file_type;
 
 hal_server_domain(hal_bluetooth_btlinux, hal_bluetooth)
 init_daemon_domain(hal_bluetooth_btlinux)
diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp
index 18498ed..ef927f4 100644
--- a/vendor_libs/test_vendor_lib/Android.bp
+++ b/vendor_libs/test_vendor_lib/Android.bp
@@ -2,22 +2,34 @@
 // ========================================================
 cc_library_static {
     name: "libbt-rootcanal",
+    defaults: ["libchrome_support_defaults"],
     proprietary: true,
     srcs: [
+        "src/acl_packet.cc",
         "src/async_manager.cc",
+        "src/beacon.cc",
+        "src/beacon_swarm.cc",
+        "src/broken_adv.cc",
         "src/bt_address.cc",
+        "src/classic.cc",
         "src/command_packet.cc",
+        "src/connection.cc",
+        "src/device.cc",
+        "src/device_factory.cc",
+        "src/device_properties.cc",
         "src/dual_mode_controller.cc",
         "src/event_packet.cc",
+        "src/hci_packet.cc",
+        "src/keyboard.cc",
+        "src/l2cap_packet.cc",
+        "src/l2cap_sdu.cc",
         "src/packet.cc",
         "src/packet_stream.cc",
+        "src/sco_packet.cc",
         "src/test_channel_transport.cc",
     ],
     cflags: [
         "-fvisibility=hidden",
-        "-Wall",
-        "-Wextra",
-        "-Werror",
         "-DHAS_NO_BDROID_BUILDCFG",
     ],
     local_include_dirs: [
@@ -25,18 +37,17 @@
     ],
     export_include_dirs: ["include"],
     header_libs: [
-        "libhardware_headers",
+        "libbluetooth_headers",
     ],
     include_dirs: [
         "system/bt",
         "system/bt/utils/include",
         "system/bt/hci/include",
-        "system/bt/include",
+        "system/bt/internal_include",
         "system/bt/stack/include",
     ],
     shared_libs: [
         "libbase",
-        "libchrome",
         "liblog",
     ],
     static_libs: [
@@ -48,9 +59,11 @@
 // ========================================================
 cc_test_host {
     name: "test-vendor_test_host",
+    defaults: ["libchrome_support_defaults"],
     srcs: [
         "src/async_manager.cc",
         "src/bt_address.cc",
+        "src/hci_packet.cc",
         "src/command_packet.cc",
         "src/event_packet.cc",
         "src/packet.cc",
@@ -60,9 +73,13 @@
         "test/async_manager_unittest.cc",
         "test/bt_address_unittest.cc",
         "test/packet_stream_unittest.cc",
+        "test/iterator_test.cc",
         "test/l2cap_test.cc",
         "test/l2cap_sdu_test.cc",
     ],
+    header_libs: [
+        "libbluetooth_headers",
+    ],
     local_include_dirs: [
         "include",
     ],
@@ -74,21 +91,12 @@
     ],
     shared_libs: [
         "liblog",
-        "libchrome",
     ],
     static_libs: [
         "libbluetooth-types",
     ],
     cflags: [
         "-fvisibility=hidden",
-        "-Wall",
-        "-Wextra",
-        "-Werror",
         "-DLOG_NDEBUG=1",
     ],
-    target: {
-        darwin: {
-            enabled: false,
-        }
-    },
 }
diff --git a/vendor_libs/test_vendor_lib/include/acl_packet.h b/vendor_libs/test_vendor_lib/include/acl_packet.h
new file mode 100644
index 0000000..30f3389
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/acl_packet.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017 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 <cstdint>
+#include <string>
+#include <vector>
+
+namespace test_vendor_lib {
+
+// ACL data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.2
+class AclPacket {
+ public:
+  typedef enum {
+    FirstNonAutomaticallyFlushable,
+    Continuing,
+    FirstAutomaticallyFlushable,
+    Complete
+  } PacketBoundaryFlags;
+  typedef enum {
+    PointToPoint,
+    ActiveSlaveBroadcast,
+    ParkedSlaveBroadcast,
+    Reserved
+  } BroadcastFlags;
+
+  virtual ~AclPacket() = default;
+
+  uint16_t GetChannel() const {
+    return (raw_packet_[0] | (raw_packet_[1] << 8)) & 0xfff;
+  }
+
+  PacketBoundaryFlags GetPacketBoundaryFlags() const {
+    return static_cast<PacketBoundaryFlags>((raw_packet_[1] & 0x30) >> 4);
+  }
+
+  BroadcastFlags GetBroadcastFlags() const {
+    return static_cast<BroadcastFlags>((raw_packet_[1] & 0xC0) >> 6);
+  }
+
+  explicit AclPacket(uint16_t channel,
+                     AclPacket::PacketBoundaryFlags boundary_flags,
+                     AclPacket::BroadcastFlags broadcast);
+
+  size_t GetPacketSize() const;
+
+  const std::vector<uint8_t>& GetPacket() const;
+
+  void AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ private:
+  // Add |octets| bytes to the payload.
+  void AddPayloadOctets(size_t octets, uint64_t value);
+
+  static const size_t kHeaderSize = 4;
+
+ public:
+  // Add type-checking versions
+  void AddPayloadOctets1(uint8_t value) { AddPayloadOctets(1, value); }
+  void AddPayloadOctets2(uint16_t value) { AddPayloadOctets(2, value); }
+  void AddPayloadOctets3(uint32_t value) { AddPayloadOctets(3, value); }
+  void AddPayloadOctets4(uint32_t value) { AddPayloadOctets(4, value); }
+  void AddPayloadOctets6(uint64_t value) { AddPayloadOctets(6, value); }
+  void AddPayloadOctets8(uint64_t value) { AddPayloadOctets(8, value); }
+
+ private:
+  std::vector<uint8_t> raw_packet_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/async_manager.h b/vendor_libs/test_vendor_lib/include/async_manager.h
index 6eaddcd..1e94edf 100644
--- a/vendor_libs/test_vendor_lib/include/async_manager.h
+++ b/vendor_libs/test_vendor_lib/include/async_manager.h
@@ -109,5 +109,5 @@
 
   std::mutex synchronization_mutex_;
 };
-}
+}  // namespace test_vendor_lib
 #endif  // TEST_VENDOR_LIB_ASYNC_MANAGER_H_
diff --git a/vendor_libs/test_vendor_lib/include/beacon.h b/vendor_libs/test_vendor_lib/include/beacon.h
new file mode 100644
index 0000000..8943b96
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/beacon.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <vector>
+
+#include "bt_address.h"
+#include "device.h"
+#include "stack/include/btm_ble_api.h"
+
+namespace test_vendor_lib {
+
+// A simple device that advertises periodically and is not connectable.
+class Beacon : public Device {
+ public:
+  Beacon();
+  virtual ~Beacon() = default;
+
+  // Return a string representation of the type of device.
+  virtual std::string GetTypeString() const override { return "beacon"; }
+
+  // Set the address and advertising interval from string args.
+  virtual void Initialize(const std::vector<std::string>& args) override;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/beacon_swarm.h b/vendor_libs/test_vendor_lib/include/beacon_swarm.h
new file mode 100644
index 0000000..e07ae55
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/beacon_swarm.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <vector>
+
+#include "bt_address.h"
+#include "device.h"
+#include "stack/include/btm_ble_api.h"
+
+namespace test_vendor_lib {
+
+// Pretend to be a lot of beacons by changing the advertising address.
+class BeaconSwarm : public Device {
+ public:
+  BeaconSwarm();
+  virtual ~BeaconSwarm() = default;
+
+  // Set the address and advertising interval from string args.
+  virtual void Initialize(const std::vector<std::string>& args) override;
+
+  // Return a string representation of the type of device.
+  virtual std::string GetTypeString() const override { return "beacon_swarm"; }
+
+  void TimerTick() override;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/broken_adv.h b/vendor_libs/test_vendor_lib/include/broken_adv.h
new file mode 100644
index 0000000..9f7cd87
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/broken_adv.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <vector>
+
+#include "bt_address.h"
+#include "device.h"
+
+namespace test_vendor_lib {
+
+class BrokenAdv : public Device {
+ public:
+  BrokenAdv();
+  ~BrokenAdv() = default;
+
+  // Initialize the device based on the values of |args|.
+  virtual void Initialize(const std::vector<std::string>& args) override;
+
+  // Return a string representation of the type of device.
+  virtual std::string GetTypeString() const override { return "broken_adv"; }
+
+  // Return the string representation of the device.
+  virtual std::string ToString() const override;
+
+  // Use the timer tick to update advertisements.
+  void TimerTick() override;
+
+  // Change which advertisements are broken and the address of the device.
+  void UpdateAdvertisement();
+
+  // Change which data is broken and the address of the device.
+  void UpdatePageScan();
+
+ private:
+  std::vector<uint8_t> constant_adv_data_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/bt_address.h b/vendor_libs/test_vendor_lib/include/bt_address.h
index c37624f..d656c34 100644
--- a/vendor_libs/test_vendor_lib/include/bt_address.h
+++ b/vendor_libs/test_vendor_lib/include/bt_address.h
@@ -1,18 +1,18 @@
-//
-// Copyright 2016 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.
-//
+/*
+ * Copyright 2016 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
 
@@ -41,22 +41,22 @@
   // - each remaining character is a hexadecimal digit
   static bool IsValid(const std::string& addr);
 
-  inline bool operator==(const BtAddress& right) {
+  inline bool operator==(const BtAddress& right) const {
     return address_ == right.address_;
   }
-  inline bool operator!=(const BtAddress& right) {
+  inline bool operator!=(const BtAddress& right) const {
     return address_ != right.address_;
   }
-  inline bool operator<(const BtAddress& right) {
+  inline bool operator<(const BtAddress& right) const {
     return address_ < right.address_;
   }
-  inline bool operator>(const BtAddress& right) {
+  inline bool operator>(const BtAddress& right) const {
     return address_ > right.address_;
   }
-  inline bool operator<=(const BtAddress& right) {
+  inline bool operator<=(const BtAddress& right) const {
     return address_ <= right.address_;
   }
-  inline bool operator>=(const BtAddress& right) {
+  inline bool operator>=(const BtAddress& right) const {
     return address_ >= right.address_;
   }
 
diff --git a/vendor_libs/test_vendor_lib/include/classic.h b/vendor_libs/test_vendor_lib/include/classic.h
new file mode 100644
index 0000000..0aeba2f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/classic.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <vector>
+
+#include "bt_address.h"
+#include "device.h"
+
+namespace test_vendor_lib {
+
+class Classic : public Device {
+ public:
+  Classic();
+  ~Classic() = default;
+
+  // Initialize the device based on the values of |args|.
+  virtual void Initialize(const std::vector<std::string>& args) override;
+
+  // Return a string representation of the type of device.
+  virtual std::string GetTypeString() const override { return "classic"; }
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/command_packet.h b/vendor_libs/test_vendor_lib/include/command_packet.h
index 3f7debb..36ab8d2 100644
--- a/vendor_libs/test_vendor_lib/include/command_packet.h
+++ b/vendor_libs/test_vendor_lib/include/command_packet.h
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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
 
diff --git a/vendor_libs/test_vendor_lib/include/connection.h b/vendor_libs/test_vendor_lib/include/connection.h
new file mode 100644
index 0000000..2a4f662
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/connection.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "async_manager.h"
+#include "device.h"
+
+#include "hci/include/hci_hal.h"
+
+namespace test_vendor_lib {
+
+// Model the connection of a device to the controller.
+class Connection {
+ public:
+  Connection(std::shared_ptr<Device> dev, uint16_t handle)
+      : dev_(dev), handle_(handle), connected_(true), encrypted_(false) {}
+
+  virtual ~Connection() = default;
+
+  // Return a string representing the connection for logging.
+  const std::string ToString();
+
+  // Return a pointer to the device in the connection.
+  std::shared_ptr<Device> GetDevice() { return dev_; }
+
+  // Return true if the handle matches and the device is connected.
+  inline bool operator==(uint16_t handle) {
+    return (handle_ == handle) && connected_;
+  }
+
+  // Return true if the handle doesn't match or the device is not connected.
+  inline bool operator!=(uint16_t handle) {
+    return (handle_ != handle) || !connected_;
+  }
+
+  void Disconnect() { connected_ = false; };
+  bool Connected() { return connected_; };
+
+  void Encrypt() { encrypted_ = true; };
+  bool Encrypted() { return encrypted_; };
+
+  // Add an action to the connection queue.
+  void AddAction(const TaskCallback& task);
+
+  // Execute the next action in the connection queue to simulate packet
+  // exchange.
+  void SendToDevice();
+
+  // Add a message from the device.
+  void AddMessage(const std::vector<uint8_t>& message);
+
+  // Receive data from the device to simulate packet exchange.
+  bool ReceiveFromDevice(std::vector<uint8_t>& data);
+
+ private:
+  // A shared pointer to the connected device
+  std::shared_ptr<Device> dev_;
+
+  // The connection handle
+  uint16_t handle_;
+
+  // State variables
+  bool connected_;
+  bool encrypted_;
+
+  // Actions for the next packet exchange.
+  std::queue<TaskCallback> actions_;
+
+  // Messages from the device for the next packet exchange.
+  std::queue<std::vector<uint8_t>> messages_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/device.h b/vendor_libs/test_vendor_lib/include/device.h
new file mode 100644
index 0000000..e2924c4
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/device.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2016 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 <chrono>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "bt_address.h"
+
+#include "hci/include/hci_hal.h"
+#include "stack/include/btm_ble_api.h"
+
+namespace test_vendor_lib {
+
+// Represent a Bluetooth Device
+//  - Provide Get*() and Set*() functions for device attributes.
+class Device {
+ public:
+  Device() : time_stamp_(std::chrono::steady_clock::now()) {}
+  virtual ~Device() = default;
+
+  // Initialize the device based on the values of |args|.
+  virtual void Initialize(const std::vector<std::string>& args) = 0;
+
+  // Return a string representation of the type of device.
+  virtual std::string GetTypeString() const = 0;
+
+  // Return the string representation of the device.
+  virtual std::string ToString() const;
+
+  // Return a reference to the address.
+  const BtAddress& GetBtAddress() const { return address_; }
+
+  // Set the address to the |addr|.
+  void SetBtAddress(const BtAddress& addr) { address_ = addr; }
+
+  // Return the address type.
+  uint8_t GetAddressType() const { return address_type_; }
+
+  // Decide whether to accept a connection request
+  // May need to be extended to check peer address & type, and other
+  // connection parameters.
+  // Return true if the device accepts the connection request.
+  virtual bool LeConnect() { return false; }
+
+  // Return the advertisement data.
+  const std::vector<uint8_t>& GetAdvertisement() const { return adv_data_; }
+
+  // Return the advertisement type.
+  uint8_t GetAdvertisementType() const { return advertising_type_; }
+
+  // Set the advertisement interval in milliseconds.
+  void SetAdvertisementInterval(std::chrono::milliseconds ms) {
+    advertising_interval_ms_ = ms;
+  }
+
+  // Return true if there is a scan response (allows for empty responses).
+  bool HasScanResponse() const { return scan_response_present_; }
+
+  // Return the scan response data.
+  const std::vector<uint8_t>& GetScanResponse() const { return scan_data_; }
+
+  // Returns true if the host could see an advertisement in the next
+  // |scan_time| milliseconds.
+  virtual bool IsAdvertisementAvailable(
+      std::chrono::milliseconds scan_time) const;
+
+  // Returns true if the host could see a page scan now.
+  virtual bool IsPageScanAvailable() const;
+
+  // Return the device class.
+  // The device class is a 3-byte value.  Look for DEV_CLASS in
+  // stack/include/bt_types.h
+  uint32_t GetDeviceClass() const { return device_class_; }
+
+  // Return the clock offset, which is a defined in the Spec as:
+  // (CLKN_16-2 slave - CLKN_16-2 master ) mod 2**15.
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part C, Section 4.3.2
+  uint16_t GetClockOffset() const { return clock_offset_; }
+
+  // Set the clock offset.
+  void SetClockOffset(uint16_t offset) { clock_offset_ = offset; }
+
+  // Return the page scan repetition mode.
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part B, Section 8.3.1
+  // The values are:
+  // 0 - R0 T_page_scan <= 1.28s and T_page_scan == T_window and
+  // 1 - R1 T_page_scan <= 1.28s
+  // 2 - R2 T_page_scan <= 2.56s
+  uint8_t GetPageScanRepetitionMode() const {
+    return page_scan_repetition_mode_;
+  }
+
+  // Return the extended inquiry data.
+  const std::vector<uint8_t>& GetExtendedInquiryData() const {
+    return extended_inquiry_data_;
+  }
+
+  // Let the device know that time has passed.
+  virtual void TimerTick() {}
+
+ protected:
+  BtAddress address_;
+
+  // Address type is defined in the spec:
+  // 0x00 Public Device Address
+  // 0x01 Random Device Address
+  // 0x02 Public Identity Address
+  // 0x03 Random (static) Identity Address
+  // 0x04 – 0xFF Reserved for future use
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.12
+  uint8_t address_type_;
+
+  std::chrono::steady_clock::time_point time_stamp_;
+
+  // Return the device class.
+  // The device class is a 3-byte value.  Look for DEV_CLASS in
+  // stack/include/bt_types.h
+  uint32_t device_class_;
+
+  // Return the page scan repetition mode.
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part B, Section 8.3.1
+  // The values are:
+  // 0 - R0 T_page_scan <= 1.28s and T_page_scan == T_window and
+  // 1 - R1 T_page_scan <= 1.28s
+  // 2 - R2 T_page_scan <= 2.56s
+  uint8_t page_scan_repetition_mode_;
+
+  // The time between page scans.
+  std::chrono::milliseconds page_scan_delay_ms_;
+
+  std::vector<uint8_t> extended_inquiry_data_;
+
+  // Classic Bluetooth CLKN_slave[16..2] - CLKN_master[16..2]
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part C, Section 4.3.2
+  uint16_t clock_offset_;
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.5
+  uint8_t advertising_type_;
+
+  // The spec defines the advertising interval as a 16-bit value, but since it
+  // is never sent in packets, we use std::chrono::milliseconds.
+  std::chrono::milliseconds advertising_interval_ms_;
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.7
+
+  // Bluetooth Core Specification Version 4.2, Volume 3, Part C, Section
+  // 11.1
+  // https://www.bluetooth.com/specifications/assigned-numbers
+  // Supplement to Bluetooth Core Specification | CSSv6, Part A
+  std::vector<uint8_t> adv_data_ = {0x07,  // Length
+                                    BTM_BLE_AD_TYPE_NAME_CMPL,
+                                    'd',
+                                    'e',
+                                    'v',
+                                    'i',
+                                    'c',
+                                    'e'};
+
+  bool scan_response_present_ = true;
+  std::vector<uint8_t> scan_data_ = {0x04,  // Length
+                                     BTM_BLE_AD_TYPE_NAME_SHORT, 'd', 'e', 'v'};
+
+ public:
+  static const uint8_t kBtAddressTypePublic = 0x00;
+  static const uint8_t kBtAddressTypeRandom = 0x01;
+  static const uint8_t kBtAddressTypePublicIdentity = 0x02;
+  static const uint8_t kBtAddressTypeRandomIdentity = 0x03;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/device_factory.h b/vendor_libs/test_vendor_lib/include/device_factory.h
new file mode 100644
index 0000000..a66a2e0
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/device_factory.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <string>
+#include <vector>
+
+#include "device.h"
+
+namespace test_vendor_lib {
+
+// Encapsulate the details of supported devices to hide them from the
+// Controller.
+class DeviceFactory {
+ public:
+  DeviceFactory();
+  virtual ~DeviceFactory() = default;
+
+  // Call the constructor for the matching device type (arg[0]) and then call
+  // the matching Initialize() function with args.
+  static std::shared_ptr<Device> Create(const std::vector<std::string>& args);
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/device_properties.h b/vendor_libs/test_vendor_lib/include/device_properties.h
new file mode 100644
index 0000000..98876d5
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/device_properties.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2015 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 <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "acl_packet.h"
+#include "async_manager.h"
+#include "base/json/json_value_converter.h"
+#include "base/time/time.h"
+#include "bt_address.h"
+
+namespace test_vendor_lib {
+
+// Emulates a dual mode BR/EDR + LE controller by maintaining the link layer
+// state machine detailed in the Bluetooth Core Specification Version 4.2,
+// Volume 6, Part B, Section 1.1 (page 30). Provides methods corresponding to
+// commands sent by the HCI. These methods will be registered as callbacks from
+// a controller instance with the HciHandler. To implement a new Bluetooth
+// command, simply add the method declaration below, with return type void and a
+// single const std::vector<uint8_t>& argument. After implementing the
+// method, simply register it with the HciHandler using the SET_HANDLER macro in
+// the controller's default constructor. Be sure to name your method after the
+// corresponding Bluetooth command in the Core Specification with the prefix
+// "Hci" to distinguish it as a controller command.
+class DeviceProperties {
+ public:
+  explicit DeviceProperties(const std::string& file_name);
+
+  // Access private configuration data
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+  const std::vector<uint8_t>& GetLocalVersionInformation() const;
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+  const std::vector<uint8_t>& GetLocalSupportedCommands() const {
+    return local_supported_commands_;
+  }
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.4.3
+  uint64_t GetLocalSupportedFeatures() const {
+    return local_extended_features_[0];
+  };
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+  uint8_t GetLocalExtendedFeaturesMaximumPageNumber() const {
+    return local_extended_features_.size() - 1;
+  };
+
+  uint64_t GetLocalExtendedFeatures(uint8_t page_number) const {
+    CHECK(page_number < local_extended_features_.size());
+    return local_extended_features_[page_number];
+  };
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+  uint16_t GetAclDataPacketSize() const { return acl_data_packet_size_; }
+
+  uint8_t GetSynchronousDataPacketSize() const { return sco_data_packet_size_; }
+
+  uint16_t GetTotalNumAclDataPackets() const { return num_acl_data_packets_; }
+
+  uint16_t GetTotalNumSynchronousDataPackets() const {
+    return num_sco_data_packets_;
+  }
+
+  const BtAddress& GetAddress() const { return address_; }
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+  const std::vector<uint8_t>& GetSupportedCodecs() const {
+    return supported_codecs_;
+  }
+
+  const std::vector<uint32_t>& GetVendorSpecificCodecs() const {
+    return vendor_specific_codecs_;
+  }
+
+  const std::string& GetLocalName() const { return local_name_; }
+
+  uint8_t GetVersion() const { return version_; }
+
+  uint16_t GetRevision() const { return revision_; }
+
+  uint8_t GetLmpPalVersion() const { return lmp_pal_version_; }
+
+  uint16_t GetLmpPalSubversion() const { return lmp_pal_subversion_; }
+
+  uint16_t GetManufacturerName() const { return manufacturer_name_; }
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+  uint16_t GetLeDataPacketLength() const { return le_data_packet_length_; }
+
+  uint8_t GetTotalNumLeDataPackets() const { return num_le_data_packets_; }
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+  uint64_t GetLeLocalSupportedFeatures() const {
+    return le_supported_features_;
+  }
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+  uint8_t GetLeWhiteListSize() const { return le_white_list_size_; }
+
+  // Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+  uint64_t GetLeSupportedStates() const { return le_supported_states_; }
+
+  // Vendor-specific commands (see hcidefs.h)
+  const std::vector<uint8_t>& GetLeVendorCap() const { return le_vendor_cap_; }
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<DeviceProperties>* converter);
+
+ private:
+  uint16_t acl_data_packet_size_;
+  uint8_t sco_data_packet_size_;
+  uint16_t num_acl_data_packets_;
+  uint16_t num_sco_data_packets_;
+  uint8_t version_;
+  uint16_t revision_;
+  uint8_t lmp_pal_version_;
+  uint16_t manufacturer_name_;
+  uint16_t lmp_pal_subversion_;
+  std::vector<uint8_t> supported_codecs_;
+  std::vector<uint32_t> vendor_specific_codecs_;
+  std::vector<uint8_t> local_supported_commands_;
+  std::string local_name_;
+  std::vector<uint64_t> local_extended_features_;
+  BtAddress address_;
+
+  uint16_t le_data_packet_length_;
+  uint8_t num_le_data_packets_;
+  uint8_t le_white_list_size_;
+  uint64_t le_supported_features_;
+  uint64_t le_supported_states_;
+  std::vector<uint8_t> le_vendor_cap_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/dual_mode_controller.h b/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
index bf861b7..4f7041c 100644
--- a/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
+++ b/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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
 
@@ -22,12 +22,16 @@
 #include <unordered_map>
 #include <vector>
 
+#include "acl_packet.h"
 #include "async_manager.h"
-#include "base/json/json_value_converter.h"
 #include "base/time/time.h"
 #include "bt_address.h"
 #include "command_packet.h"
+#include "connection.h"
+#include "device.h"
+#include "device_properties.h"
 #include "event_packet.h"
+#include "sco_packet.h"
 #include "test_channel_transport.h"
 
 namespace test_vendor_lib {
@@ -45,129 +49,15 @@
 // "Hci" to distinguish it as a controller command.
 class DualModeController {
  public:
-  class Properties {
-   public:
-    explicit Properties(const std::string& file_name);
-
-    // Access private configuration data
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.4.1
-    const std::vector<uint8_t>& GetLocalVersionInformation() const;
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.4.2
-    const std::vector<uint8_t>& GetLocalSupportedCommands() const {
-      return local_supported_commands_;
-    }
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.4.3
-    uint64_t GetLocalSupportedFeatures() const {
-      return local_extended_features_[0];
-    };
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
-    uint8_t GetLocalExtendedFeaturesMaximumPageNumber() const {
-      return local_extended_features_.size() - 1;
-    };
-
-    uint64_t GetLocalExtendedFeatures(uint8_t page_number) const {
-      CHECK(page_number < local_extended_features_.size());
-      return local_extended_features_[page_number];
-    };
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.4.5
-    uint16_t GetAclDataPacketSize() const { return acl_data_packet_size_; }
-
-    uint8_t GetSynchronousDataPacketSize() const {
-      return sco_data_packet_size_;
-    }
-
-    uint16_t GetTotalNumAclDataPackets() const { return num_acl_data_packets_; }
-
-    uint16_t GetTotalNumSynchronousDataPackets() const {
-      return num_sco_data_packets_;
-    }
-
-    const BtAddress& GetAddress() const { return address_; }
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.4.8
-    const std::vector<uint8_t>& GetSupportedCodecs() const {
-      return supported_codecs_;
-    }
-
-    const std::vector<uint32_t>& GetVendorSpecificCodecs() const {
-      return vendor_specific_codecs_;
-    }
-
-    const std::string& GetLocalName() const { return local_name_; }
-
-    uint8_t GetVersion() const { return version_; }
-
-    uint16_t GetRevision() const { return revision_; }
-
-    uint8_t GetLmpPalVersion() const { return lmp_pal_version_; }
-
-    uint16_t GetLmpPalSubversion() const { return lmp_pal_subversion_; }
-
-    uint16_t GetManufacturerName() const { return manufacturer_name_; }
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.8.2
-    uint16_t GetLeDataPacketLength() const { return le_data_packet_length_; }
-
-    uint8_t GetTotalNumLeDataPackets() const { return num_le_data_packets_; }
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.8.3
-    uint64_t GetLeLocalSupportedFeatures() const {
-      return le_supported_features_;
-    }
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.8.14
-    uint8_t GetLeWhiteListSize() const { return le_white_list_size_; }
-
-    // Specification Version 4.2, Volume 2, Part E, Section 7.8.27
-    uint64_t GetLeSupportedStates() const { return le_supported_states_; }
-
-    // Vendor-specific commands (see hcidefs.h)
-    const std::vector<uint8_t>& GetLeVendorCap() const {
-      return le_vendor_cap_;
-    }
-
-    static void RegisterJSONConverter(
-        base::JSONValueConverter<Properties>* converter);
-
-   private:
-    uint16_t acl_data_packet_size_;
-    uint8_t sco_data_packet_size_;
-    uint16_t num_acl_data_packets_;
-    uint16_t num_sco_data_packets_;
-    uint8_t version_;
-    uint16_t revision_;
-    uint8_t lmp_pal_version_;
-    uint16_t manufacturer_name_;
-    uint16_t lmp_pal_subversion_;
-    std::vector<uint8_t> supported_codecs_;
-    std::vector<uint32_t> vendor_specific_codecs_;
-    std::vector<uint8_t> local_supported_commands_;
-    std::string local_name_;
-    std::vector<uint64_t> local_extended_features_;
-    BtAddress address_;
-
-    uint16_t le_data_packet_length_;
-    uint8_t num_le_data_packets_;
-    uint8_t le_white_list_size_;
-    uint64_t le_supported_features_;
-    uint64_t le_supported_states_;
-    std::vector<uint8_t> le_vendor_cap_;
-  };
-
   // Sets all of the methods to be used as callbacks in the HciHandler.
   DualModeController();
 
   ~DualModeController() = default;
 
-  // Preprocesses the command, primarily checking testh channel hooks. If
-  // possible, dispatches the corresponding controller method corresponding to
-  // carry out the command.
+  // Route commands and data from the stack.
+  void HandleAcl(std::unique_ptr<AclPacket> acl_packet);
   void HandleCommand(std::unique_ptr<CommandPacket> command_packet);
+  void HandleSco(std::unique_ptr<ScoPacket> sco_packet);
 
   // Dispatches the test channel action corresponding to the command specified
   // by |name|.
@@ -186,10 +76,16 @@
 
   void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
 
-  // Sets the callback to be used for sending events back to the HCI.
+  // Set the callbacks for sending packets to the HCI.
   void RegisterEventChannel(
       const std::function<void(std::unique_ptr<EventPacket>)>& send_event);
 
+  void RegisterAclChannel(
+      const std::function<void(std::unique_ptr<AclPacket>)>& send_acl);
+
+  void RegisterScoChannel(
+      const std::function<void(std::unique_ptr<ScoPacket>)>& send_sco);
+
   // Controller commands. For error codes, see the Bluetooth Core Specification,
   // Version 4.2, Volume 2, Part D (page 370).
 
@@ -340,6 +236,14 @@
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.19
   void HciRemoteNameRequest(const std::vector<uint8_t>& args);
 
+  // Test Commands
+
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7.1
+  void HciReadLoopbackMode(const std::vector<uint8_t>& args);
+
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7.2
+  void HciWriteLoopbackMode(const std::vector<uint8_t>& args);
+
   // LE Controller Commands
 
   // OGF: 0x0008
@@ -383,11 +287,27 @@
   void HciLeSetScanEnable(const std::vector<uint8_t>& args);
 
   // OGF: 0x0008
+  // OCF: 0x000D
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.12
+  void HciLeCreateConnection(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x000E
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.13
+  void HciLeConnectionCancel(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
   // OCF: 0x000F
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.14
   void HciLeReadWhiteListSize(const std::vector<uint8_t>& args);
 
   // OGF: 0x0008
+  // OCF: 0x0016
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.21
+  void HciLeReadRemoteUsedFeatures(const std::vector<uint8_t>& args);
+  void HciLeReadRemoteUsedFeaturesB(uint16_t handle);
+
+  // OGF: 0x0008
   // OCF: 0x0018
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.23
   void HciLeRand(const std::vector<uint8_t>& args);
@@ -423,26 +343,29 @@
   // OCF: 0x0159
   void HciBleEnergyInfo(const std::vector<uint8_t>& args);
 
+  // Test
+  void HciBleAdvertisingFilter(const std::vector<uint8_t>& args);
+
   // OGF: 0x00FC
   // OCF: 0x015A
   void HciBleExtendedScanParams(const std::vector<uint8_t>& args);
 
   // Test Channel commands:
 
-  // Clears all test channel modifications.
-  void TestChannelClear(const std::vector<std::string>& args);
+  // Add devices
+  void TestChannelAdd(const std::vector<std::string>& args);
 
-  // Sets the response delay for events to 0.
-  void TestChannelClearEventDelay(const std::vector<std::string>& args);
+  // Remove devices by index
+  void TestChannelDel(const std::vector<std::string>& args);
 
-  // Discovers a fake device.
-  void TestChannelDiscover(const std::vector<std::string>& args);
+  // List the devices that the controller knows about
+  void TestChannelList(const std::vector<std::string>& args) const;
 
-  // Causes events to be sent after a delay.
-  void TestChannelSetEventDelay(const std::vector<std::string>& args);
+  void Connections();
 
-  // Causes all future HCI commands to timeout.
-  void TestChannelTimeoutAll(const std::vector<std::string>& args);
+  void LeScan();
+
+  void PageScan();
 
   void HandleTimerTick();
   void SetTimerPeriod(std::chrono::milliseconds new_period);
@@ -456,16 +379,12 @@
     kInquiry,  // The controller is discovering other nearby devices.
   };
 
-  enum TestChannelState {
-    kNone,             // The controller is running normally.
-    kTimeoutAll,       // All commands should time out, i.e. send no response.
-    kDelayedResponse,  // Event responses are sent after a delay.
-  };
-
   // Set a timer for a future action
   void AddControllerEvent(std::chrono::milliseconds,
                           const TaskCallback& callback);
 
+  void AddConnectionAction(const TaskCallback& callback, uint16_t handle);
+
   // Creates a command complete event and sends it back to the HCI.
   void SendCommandComplete(uint16_t command_opcode,
                            const std::vector<uint8_t>& return_parameters) const;
@@ -496,8 +415,10 @@
 
   std::function<void(AsyncTaskId)> cancel_task_;
 
-  // Callback provided to send events from the controller back to the HCI.
+  // Callbacks to send packets back to the HCI.
+  std::function<void(std::unique_ptr<AclPacket>)> send_acl_;
   std::function<void(std::unique_ptr<EventPacket>)> send_event_;
+  std::function<void(std::unique_ptr<ScoPacket>)> send_sco_;
 
   // Maintains the commands to be registered and used in the HciHandler object.
   // Keys are command opcodes and values are the callbacks to handle each
@@ -517,6 +438,10 @@
   // 0x03-0xFF: Reserved.
   uint8_t inquiry_mode_;
 
+  bool inquiry_responses_limited_;
+  uint8_t inquiry_num_responses_;
+  uint8_t inquiry_lap_[3];
+
   std::vector<uint8_t> le_event_mask_;
 
   BtAddress le_random_address_;
@@ -530,15 +455,26 @@
   uint8_t le_scan_enable_;
   uint8_t filter_duplicates_;
 
+  bool le_connect_;
+  uint8_t initiator_filter_policy_;
+
+  BtAddress peer_address_;
+  uint8_t peer_address_type_;
+
+  uint8_t loopback_mode_;
+
   State state_;
 
-  Properties properties_;
+  DeviceProperties properties_;
 
-  TestChannelState test_channel_state_;
+  std::vector<std::shared_ptr<Device>> devices_;
 
   std::vector<AsyncTaskId> controller_events_;
+
+  std::vector<std::shared_ptr<Connection>> connections_;
+
   AsyncTaskId timer_tick_task_;
-  std::chrono::milliseconds timer_period_ = std::chrono::milliseconds(1000);
+  std::chrono::milliseconds timer_period_ = std::chrono::milliseconds(100);
 
   DualModeController(const DualModeController& cmdPckt) = delete;
   DualModeController& operator=(const DualModeController& cmdPckt) = delete;
diff --git a/vendor_libs/test_vendor_lib/include/event_packet.h b/vendor_libs/test_vendor_lib/include/event_packet.h
index d7c8268..f861c07 100644
--- a/vendor_libs/test_vendor_lib/include/event_packet.h
+++ b/vendor_libs/test_vendor_lib/include/event_packet.h
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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
 
@@ -55,6 +55,16 @@
   static std::unique_ptr<EventPacket> CreateCommandStatusEvent(
       uint8_t status, uint16_t command_opcode);
 
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
+  static std::unique_ptr<EventPacket> CreateNumberOfCompletedPacketsEvent(
+      uint16_t handle, uint16_t num_completed_packets);
+
+  void AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
+  static std::unique_ptr<EventPacket> CreateCommandCompleteDeleteStoredLinkKey(
+      uint8_t status, uint16_t num_keys_deleted);
+
   // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
   static std::unique_ptr<EventPacket> CreateCommandCompleteReadLocalName(
       uint8_t status, const std::string& local_name);
@@ -96,29 +106,54 @@
       uint8_t status, const std::vector<uint8_t>& supported_codecs,
       const std::vector<uint32_t>& vendor_specific_codecs);
 
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
+  static std::unique_ptr<EventPacket> CreateCommandCompleteReadLoopbackMode(
+      uint8_t status, uint8_t mode);
+
   // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
-  enum PageScanRepetitionMode {
-    kR0 = 0,
-    kR1 = 1,
-    kR2 = 2,
-  };
+  static std::unique_ptr<EventPacket> CreateInquiryResultEvent();
 
-  static std::unique_ptr<EventPacket> CreateInquiryResultEvent(
-      const BtAddress& bt_address,
-      const PageScanRepetitionMode page_scan_repetition_mode,
-      uint32_t class_of_device, uint16_t clock_offset);
-
-  void AddInquiryResult(const BtAddress& bt_address,
-                        const PageScanRepetitionMode page_scan_repetition_mode,
+  // Returns true if the result can be added to the event packet.
+  bool AddInquiryResult(const BtAddress& bt_address,
+                        uint8_t page_scan_repetition_mode,
                         uint32_t class_of_device, uint16_t clock_offset);
 
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
+  static std::unique_ptr<EventPacket> CreateConnectionCompleteEvent(
+      uint8_t status, uint16_t handle, const BtAddress& address,
+      uint8_t link_type, bool encryption_enabled);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
+  static std::unique_ptr<EventPacket> CreateLoopbackCommandEvent(
+      uint16_t opcode, const std::vector<uint8_t>& payload);
+
   // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
   static std::unique_ptr<EventPacket> CreateExtendedInquiryResultEvent(
-      const BtAddress& bt_address,
-      const PageScanRepetitionMode page_scan_repetition_mode,
+      const BtAddress& bt_address, uint8_t page_scan_repetition_mode,
       uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
       const std::vector<uint8_t>& extended_inquiry_response);
 
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+  // 7.7.65.1
+  static std::unique_ptr<EventPacket> CreateLeConnectionCompleteEvent(
+      uint8_t status, uint16_t handle, uint8_t role, uint8_t peer_address_type,
+      const BtAddress& peer, uint16_t interval, uint16_t latency,
+      uint16_t supervision_timeout);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+  // 7.7.65.2
+  static std::unique_ptr<EventPacket> CreateLeAdvertisingReportEvent();
+
+  // Returns true if the report can be added to the event packet.
+  bool AddLeAdvertisingReport(uint8_t event_type, uint8_t addr_type,
+                              const BtAddress& addr,
+                              const std::vector<uint8_t>& data, uint8_t rssi);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+  // 7.7.65.4
+  static std::unique_ptr<EventPacket> CreateLeRemoteUsedFeaturesEvent(
+      uint8_t status, uint16_t handle, uint64_t features);
+
   // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
   static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadBufferSize(
       uint8_t status, uint16_t hc_le_data_packet_length,
diff --git a/vendor_libs/test_vendor_lib/include/hci_packet.h b/vendor_libs/test_vendor_lib/include/hci_packet.h
new file mode 100644
index 0000000..f7be08e
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/hci_packet.h
@@ -0,0 +1,86 @@
+#pragma once
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include "base/logging.h"
+
+namespace test_vendor_lib {
+
+// Iterator is a custom iterator class for HciPackets.
+class Iterator
+    : public std::iterator<std::random_access_iterator_tag, uint8_t> {
+ public:
+  Iterator(std::shared_ptr<class HciPacket> packet, size_t i);
+  Iterator(const Iterator& itr);
+
+  ~Iterator() {}
+
+  operator bool() const;
+
+  // All addition and subtraction operators are bounded from 0 to the length of
+  // the packet.
+  Iterator operator+(size_t offset);
+  Iterator& operator+=(size_t offset);
+  Iterator operator++(int);
+  Iterator& operator++();
+
+  Iterator operator-(size_t offset);
+  int operator-(Iterator& itr);
+  Iterator& operator-=(size_t offset);
+  Iterator operator--(int);
+  Iterator& operator--();
+
+  Iterator& operator=(const Iterator& itr);
+
+  bool operator!=(Iterator& itr);
+  bool operator==(Iterator& itr);
+
+  bool operator<(Iterator& itr);
+  bool operator>(Iterator& itr);
+
+  bool operator<=(Iterator& itr);
+  bool operator>=(Iterator& itr);
+
+  uint8_t& operator*() const;
+  uint8_t* operator->() const;
+
+  // Get the next sizeof(FixedWidthIntegerType) bytes and return the filled type
+  template <typename FixedWidthIntegerType>
+  FixedWidthIntegerType extract() {
+    static_assert(std::is_integral<FixedWidthIntegerType>::value,
+                  "Iterator::extract requires an integral type.");
+    FixedWidthIntegerType extracted_value = 0;
+
+    for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
+      extracted_value |= static_cast<FixedWidthIntegerType>(**this) << i * 8;
+      (*this)++;
+    }
+
+    return extracted_value;
+  }
+
+ private:
+  std::shared_ptr<class HciPacket> hci_packet_;
+  size_t index_;
+
+};  // Iterator
+
+// HciPacket is an abstract class that will serve as the base class for all
+// packet types.
+class HciPacket : public std::enable_shared_from_this<HciPacket> {
+ public:
+  virtual ~HciPacket() = default;
+
+  Iterator get_begin();
+  Iterator get_end();
+
+  uint8_t operator[](size_t i);
+
+  virtual size_t get_length() = 0;
+
+  virtual uint8_t& get_at_index(size_t index) = 0;
+
+};  // HciPacket
+
+};  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/keyboard.h b/vendor_libs/test_vendor_lib/include/keyboard.h
new file mode 100644
index 0000000..9d1cfbf
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/keyboard.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 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 <cstdint>
+#include <vector>
+
+#include "bt_address.h"
+#include "device.h"
+
+namespace test_vendor_lib {
+
+class Keyboard : public Device {
+ public:
+  Keyboard();
+  virtual ~Keyboard() = default;
+
+  // Initialize the device based on the values of |args|.
+  virtual void Initialize(const std::vector<std::string>& args) override;
+
+  // Return a string representation of the type of device.
+  virtual std::string GetTypeString() const override;
+
+  virtual bool LeConnect();
+
+  virtual bool IsPageScanAvailable() const override;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/l2cap_packet.h b/vendor_libs/test_vendor_lib/include/l2cap_packet.h
index 6c95539..1205ee1 100644
--- a/vendor_libs/test_vendor_lib/include/l2cap_packet.h
+++ b/vendor_libs/test_vendor_lib/include/l2cap_packet.h
@@ -1,20 +1,19 @@
-/******************************************************************************
+/*
+ * Copyright 2017 The Android Open Source Project
  *
- *  Copyright (C) 2017 Google, Inc.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *  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
  *
- *  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.
- *
- ******************************************************************************/
+ * 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 <cmath>
@@ -24,29 +23,30 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "hci_packet.h"
 #include "l2cap_sdu.h"
 
 namespace test_vendor_lib {
 
 const int kSduHeaderLength = 4;
 
-class L2capPacket {
+class L2capPacket : public HciPacket {
  public:
   // Returns an assembled L2cap object if successful, nullptr if failure.
-  static std::unique_ptr<L2capPacket> assemble(
-      const std::vector<L2capSdu>& sdu_packet);
-
-  // Construct a vector of just the L2CAP payload. This essentially
-  // will remove the L2CAP header from the private member variable.
-  // TODO: Remove this in favor of custom iterators.
-  std::vector<uint8_t> get_l2cap_payload() const;
-
-  uint16_t get_l2cap_cid() const;
+  static std::shared_ptr<L2capPacket> assemble(
+      const std::vector<std::shared_ptr<L2capSdu> >& sdu_packet);
 
   // Returns a fragmented vector of L2capSdu objects if successful
   // Returns an empty vector of L2capSdu objects if unsuccessful
-  std::vector<L2capSdu> fragment(uint16_t maximum_sdu_size, uint8_t txseq,
-                                 uint8_t reqseq) const;
+  std::vector<std::shared_ptr<L2capSdu> > fragment(uint16_t maximum_sdu_size,
+                                                   uint8_t txseq,
+                                                   uint8_t reqseq);
+
+  uint16_t get_l2cap_cid() const;
+
+  // HciPacket Functions
+  size_t get_length();
+  uint8_t& get_at_index(size_t index);
 
  private:
   L2capPacket() = default;
@@ -54,14 +54,8 @@
   // Entire L2CAP packet: length, CID, and payload in that order.
   std::vector<uint8_t> l2cap_packet_;
 
-  // Returns an iterator to the beginning of the L2CAP payload on success.
-  std::vector<uint8_t>::const_iterator get_l2cap_payload_begin() const;
-
   DISALLOW_COPY_AND_ASSIGN(L2capPacket);
 
-  // Returns an iterator to the end of the L2CAP payload.
-  std::vector<uint8_t>::const_iterator get_l2cap_payload_end() const;
-
   // Helper functions for fragmenting.
   static void set_sdu_header_length(std::vector<uint8_t>& sdu, uint16_t length);
 
diff --git a/vendor_libs/test_vendor_lib/include/l2cap_sdu.h b/vendor_libs/test_vendor_lib/include/l2cap_sdu.h
index 8a8c591..489f001 100644
--- a/vendor_libs/test_vendor_lib/include/l2cap_sdu.h
+++ b/vendor_libs/test_vendor_lib/include/l2cap_sdu.h
@@ -1,25 +1,26 @@
-/******************************************************************************
+/*
+ * Copyright 2017 The Android Open Source Project
  *
- *  Copyright (C) 2017 Google, Inc.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *  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
  *
- *  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.
- *
- ******************************************************************************/
+ * 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 <cstdint>
 #include <iterator>
 #include <vector>
 
+#include "hci_packet.h"
+
 namespace test_vendor_lib {
 
 // Abstract representation of an SDU packet that contains an L2CAP
@@ -57,36 +58,16 @@
 // L2CAP packet will not include either of the control or FCS
 // bytes.
 //
-class L2capSdu {
+class L2capSdu : public HciPacket {
  public:
-  // Returns a completed L2capSdu object.
-  L2capSdu(std::vector<uint8_t> create_from);
+  // Returns a unique_ptr to an L2capSdu object that is constructed with the
+  // assumption that the SDU packet is complete and correct.
+  static std::shared_ptr<L2capSdu> L2capSduConstructor(
+      std::vector<uint8_t> create_from);
 
-  static L2capSdu L2capSduBuilder(std::vector<uint8_t> create_from);
-
-  // TODO: Remove this when the move to L2capSdu* is done
-  L2capSdu& operator=(L2capSdu obj1) {
-    sdu_data_.clear();
-
-    sdu_data_ = obj1.sdu_data_;
-
-    return *this;
-  }
-
-  // Get a vector iterator that points to the first byte of the
-  // L2CAP payload within an SDU. The offset parameter will be the
-  // number of bytes that are in the SDU header. This should always
-  // be 6 bytes with the exception being the first SDU of a stream
-  // of SDU packets where the first SDU packet will have an extra
-  // two bytes and the offset should be 8 bytes.
-  std::vector<uint8_t>::const_iterator get_payload_begin(
-      const unsigned int offset) const;
-
-  // Get a vector iterator that points to the last bytes of the
-  // L2CAP payload within an SDU packet. There is no offset
-  // parameter for this function because there will always be two
-  // FCS bytes and nothing else at the end of each SDU.
-  std::vector<uint8_t>::const_iterator get_payload_end() const;
+  // Adds an FCS to create_from and returns a unique_ptr to an L2capSdu object.
+  static std::shared_ptr<L2capSdu> L2capSduBuilder(
+      std::vector<uint8_t> create_from);
 
   // Get the FCS bytes from the end of the L2CAP payload of an SDU
   // packet.
@@ -119,10 +100,17 @@
   // Reasembly is 10b, false otherwise.
   static bool is_ending_sdu(const L2capSdu& sdu);
 
+  // HciPacket functions
+  size_t get_length();
+  uint8_t& get_at_index(size_t index);
+
  private:
   // This is the SDU packet in bytes.
   std::vector<uint8_t> sdu_data_;
 
+  // Returns a completed L2capSdu object.
+  L2capSdu(std::vector<uint8_t>&& create_from);
+
   // Table for precalculated lfsr values.
   static const uint16_t lfsr_table_[256];
 
diff --git a/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h b/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h
index b0d5238..652ad34 100644
--- a/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h
+++ b/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 Google, Inc.
+ *  Copyright 2017 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/vendor_libs/test_vendor_lib/include/packet.h b/vendor_libs/test_vendor_lib/include/packet.h
index 0feeb58..8bad493 100644
--- a/vendor_libs/test_vendor_lib/include/packet.h
+++ b/vendor_libs/test_vendor_lib/include/packet.h
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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
 
@@ -49,13 +49,13 @@
 
   // Add |octets| bytes to the payload.  Return true if:
   // - the size of |bytes| is equal to |octets| and
-  // - the new size of the payload is still < |kMaxPacketOctets|
+  // - the new size of the payload is still < |kMaxPayloadOctets|
   bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
 
  private:
   // Add |octets| bytes to the payload.  Return true if:
   // - the value of |value| fits in |octets| bytes and
-  // - the new size of the payload is still < |kMaxPacketOctets|
+  // - the new size of the payload is still < |kMaxPayloadOctets|
   bool AddPayloadOctets(size_t octets, uint64_t value);
 
  public:
@@ -68,9 +68,14 @@
   bool AddPayloadOctets8(uint64_t value) { return AddPayloadOctets(8, value); }
 
   // Add |address| to the payload.  Return true if:
-  // - the new size of the payload is still < |kMaxPacketOctets|
+  // - the new size of the payload is still < |kMaxPayloadOctets|
   bool AddPayloadBtAddress(const BtAddress& address);
 
+  // Return true if |num_bytes| can be added to the payload.
+  bool CanAddPayloadOctets(size_t num_bytes) const {
+    return GetPayloadSize() + num_bytes <= kMaxPayloadOctets;
+  }
+
  protected:
   // Constructs an empty packet of type |type| and header |header|
   Packet(serial_data_type_t type, std::vector<uint8_t> header);
@@ -79,7 +84,7 @@
   bool IncrementPayloadCounter(size_t index, uint8_t max_val);
 
  private:
-  const size_t kMaxPacketOctets = 256;  // Includes the Octet count
+  const size_t kMaxPayloadOctets = 256;  // Includes the size byte.
 
   // Underlying containers for storing the actual packet
 
diff --git a/vendor_libs/test_vendor_lib/include/sco_packet.h b/vendor_libs/test_vendor_lib/include/sco_packet.h
new file mode 100644
index 0000000..7b95063
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/sco_packet.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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 <cstdint>
+#include <string>
+#include <vector>
+
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// SCO data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.3
+class ScoPacket : public Packet {
+ public:
+  virtual ~ScoPacket() override = default;
+  typedef enum {
+    CorrectlyReceived,
+    PossiblyIncomplete,
+    NoData,
+    PartiallyLost
+  } PacketStatusFlags;
+
+  uint16_t GetChannel() const;
+
+  PacketStatusFlags GetPacketStatusFlags() const;
+
+  explicit ScoPacket(uint16_t channel, PacketStatusFlags status_flags);
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/test_channel_transport.h b/vendor_libs/test_vendor_lib/include/test_channel_transport.h
index b38a8ce..069f91e 100644
--- a/vendor_libs/test_vendor_lib/include/test_channel_transport.h
+++ b/vendor_libs/test_vendor_lib/include/test_channel_transport.h
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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
 
diff --git a/vendor_libs/test_vendor_lib/scripts/test_channel.py b/vendor_libs/test_vendor_lib/scripts/test_channel.py
index cf470f9..06b0410 100644
--- a/vendor_libs/test_vendor_lib/scripts/test_channel.py
+++ b/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -168,50 +168,40 @@
     cmd.Cmd.__init__(self)
     self._test_channel = test_channel
 
-  def do_clear(self, args):
+  def do_add(self, args):
     """
-    Arguments: None.
-    Resets the controller to its original, unmodified state.
+    Arguments: dev_type_str
+    Add a new device of type dev_type_str.
     """
-    self._test_channel.send_command('CLEAR', [])
+    self._test_channel.send_command('add', args.split())
 
-  def do_clear_event_delay(self, args):
+  def do_del(self, args):
     """
-    Arguments: None.
-    Clears the response delay set by set_event_delay.
+    Arguments: device index
+    Delete the device with the specified index.
     """
-    self._test_channel.send_command('CLEAR_EVENT_DELAY', args.split())
+    self._test_channel.send_command('del', args.split())
 
-  def do_discover(self, args):
+  def do_get(self, args):
     """
-    Arguments: name_1 name_2 ...
-    Sends an inquiry result for named device(s). If no names are provided, a
-    random name is used instead.
+    Arguments: dev_num attr_str
+    Get the value of the attribute attr_str from device dev_num.
     """
-    if len(args) == 0:
-      args = generate_random_name()
-    device_list = [self._test_channel.discover_new_device(arg) for arg in \
-                   args.split()]
-    device_names_and_addresses = []
-    for device in device_list:
-      device_names_and_addresses.append(device.get_name())
-      device_names_and_addresses.append(device.get_address())
-    self._test_channel.send_command('DISCOVER', device_names_and_addresses)
+    self._test_channel.send_command('get', args.split())
 
-  def do_set_event_delay(self, args):
+  def do_set(self, args):
     """
-    Arguments: interval_in_ms
-    Sets the response delay for all event packets sent from the controller back
-    to the HCI.
+    Arguments: dev_num attr_str val
+    Set the value of the attribute attr_str from device dev_num equal to val.
     """
-    self._test_channel.send_command('SET_EVENT_DELAY', args.split())
+    self._test_channel.send_command('set', args.split())
 
-  def do_timeout_all(self, args):
+  def do_list(self, args):
     """
-    Arguments: None.
-    Causes all HCI commands to timeout.
+    Arguments: [dev_num [attr]]
+    List the devices from the controller, optionally filtered by device and attr.
     """
-    self._test_channel.send_command('TIMEOUT_ALL', [])
+    self._test_channel.send_command('list', args.split())
 
   def do_quit(self, args):
     """
@@ -223,6 +213,15 @@
     print 'Goodbye.'
     return True
 
+  def do_help(self, args):
+    """
+    Arguments: [dev_num [attr]]
+    List the commands available, optionally filtered by device and attr.
+    """
+    self._test_channel.send_command('help', args.split())
+    if (len(args) == 0):
+      cmd.Cmd.do_help(self, args)
+
 def main(argv):
   if len(argv) != 2:
     print 'Usage: python test_channel.py [port]'
diff --git a/vendor_libs/test_vendor_lib/src/acl_packet.cc b/vendor_libs/test_vendor_lib/src/acl_packet.cc
new file mode 100644
index 0000000..47aa8be
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/acl_packet.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#define LOG_TAG "acl_packet"
+
+#include "acl_packet.h"
+
+#include "base/logging.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+AclPacket::AclPacket(uint16_t channel,
+                     AclPacket::PacketBoundaryFlags packet_boundary,
+                     AclPacket::BroadcastFlags broadcast)
+    : raw_packet_({static_cast<uint8_t>(channel & 0xff),
+                   static_cast<uint8_t>(((channel >> 8) & 0x0f) |
+                                        ((packet_boundary & 0x3) << 4) |
+                                        (broadcast & 0x3) << 6),
+                   0x00, 0x00}) {}
+
+void AclPacket::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
+  CHECK(bytes.size() == octets);
+
+  raw_packet_.insert(raw_packet_.end(), bytes.begin(), bytes.end());
+
+  raw_packet_[2] =
+      static_cast<uint8_t>((raw_packet_.size() - kHeaderSize) & 0xff);
+  raw_packet_[3] =
+      static_cast<uint8_t>(((raw_packet_.size() - kHeaderSize) >> 8) & 0xff);
+}
+
+void AclPacket::AddPayloadOctets(size_t octets, uint64_t value) {
+  vector<uint8_t> val_vector;
+
+  uint64_t v = value;
+
+  CHECK(octets <= sizeof(uint64_t));
+
+  for (size_t i = 0; i < octets; i++) {
+    val_vector.push_back(v & 0xff);
+    v = v >> 8;
+  }
+
+  CHECK(v == 0);
+
+  AddPayloadOctets(octets, val_vector);
+}
+
+size_t AclPacket::GetPacketSize() const { return raw_packet_.size(); }
+
+const std::vector<uint8_t>& AclPacket::GetPacket() const { return raw_packet_; }
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/async_manager.cc b/vendor_libs/test_vendor_lib/src/async_manager.cc
index 355f647..0e30af7 100644
--- a/vendor_libs/test_vendor_lib/src/async_manager.cc
+++ b/vendor_libs/test_vendor_lib/src/async_manager.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2016 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.
-//
+/*
+ * Copyright 2016 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.
+ */
 
 #define LOG_TAG "async_manager"
 
@@ -517,4 +517,4 @@
   std::unique_lock<std::mutex> guard(synchronization_mutex_);
   critical();
 }
-}
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/beacon.cc b/vendor_libs/test_vendor_lib/src/beacon.cc
new file mode 100644
index 0000000..0ca4507
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/beacon.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "beacon"
+
+#include "beacon.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+Beacon::Beacon() {
+  advertising_interval_ms_ = std::chrono::milliseconds(1280);
+  advertising_type_ = BTM_BLE_NON_CONNECT_EVT;
+  adv_data_ = {0x0F,  // Length
+               BTM_BLE_AD_TYPE_NAME_CMPL,
+               'g',
+               'D',
+               'e',
+               'v',
+               'i',
+               'c',
+               'e',
+               '-',
+               'b',
+               'e',
+               'a',
+               'c',
+               'o',
+               'n',
+               0x02,  // Length
+               BTM_BLE_AD_TYPE_FLAG,
+               BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG};
+
+  scan_data_ = {0x05,  // Length
+                BTM_BLE_AD_TYPE_NAME_SHORT,
+                'b',
+                'e',
+                'a',
+                'c'};
+}
+
+void Beacon::Initialize(const vector<std::string>& args) {
+  if (args.size() < 2) return;
+
+  BtAddress addr;
+  if (addr.FromString(args[1])) SetBtAddress(addr);
+
+  if (args.size() < 3) return;
+
+  SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/beacon_swarm.cc b/vendor_libs/test_vendor_lib/src/beacon_swarm.cc
new file mode 100644
index 0000000..2f4eed1
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/beacon_swarm.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "beacon_swarm"
+
+#include "beacon_swarm.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+BeaconSwarm::BeaconSwarm() {
+  advertising_interval_ms_ = std::chrono::milliseconds(1280);
+  advertising_type_ = BTM_BLE_NON_CONNECT_EVT;
+  adv_data_ = {0x02,  // Length
+               BTM_BLE_AD_TYPE_FLAG,
+               BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
+               0x15,
+               BTM_BLE_AD_TYPE_NAME_CMPL,
+               'g',
+               'D',
+               'e',
+               'v',
+               'i',
+               'c',
+               'e',
+               '-',
+               'b',
+               'e',
+               'a',
+               'c',
+               'o',
+               'n',
+               '_',
+               's',
+               'w',
+               'a',
+               'r',
+               'm'};
+
+  scan_response_present_ = true;
+  scan_data_ = {0x06,  // Length
+                BTM_BLE_AD_TYPE_NAME_SHORT,
+                'c',
+                'b',
+                'e',
+                'a',
+                'c'};
+}
+
+void BeaconSwarm::Initialize(const vector<std::string>& args) {
+  if (args.size() < 2) return;
+
+  BtAddress addr;
+  if (addr.FromString(args[1])) SetBtAddress(addr);
+
+  if (args.size() < 3) return;
+
+  SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+void BeaconSwarm::TimerTick() {
+  std::vector<uint8_t> beacon_addr;
+  GetBtAddress().ToVector(beacon_addr);
+  beacon_addr[0]++;
+  BtAddress next_addr;
+  next_addr.FromVector(beacon_addr);
+
+  SetBtAddress(next_addr);
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/broken_adv.cc b/vendor_libs/test_vendor_lib/src/broken_adv.cc
new file mode 100644
index 0000000..92f47fa
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/broken_adv.cc
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "broken_adv"
+
+#include "broken_adv.h"
+
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+BrokenAdv::BrokenAdv() {
+  advertising_interval_ms_ = std::chrono::milliseconds(1280);
+  advertising_type_ = BTM_BLE_NON_CONNECT_EVT;
+  adv_data_ = {
+      0x02,  // Length
+      BTM_BLE_AD_TYPE_FLAG,
+      BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
+      0x13,  // Length
+      BTM_BLE_AD_TYPE_NAME_CMPL,
+      'g',
+      'D',
+      'e',
+      'v',
+      'i',
+      'c',
+      'e',
+      '-',
+      'b',
+      'r',
+      'o',
+      'k',
+      'e',
+      'n',
+      '_',
+      'a',
+      'd',
+      'v',
+  };
+
+  constant_adv_data_ = adv_data_;
+
+  scan_response_present_ = true;
+  scan_data_ = {0x0b,  // Length
+                BTM_BLE_AD_TYPE_NAME_SHORT,
+                'b',
+                'r',
+                'o',
+                'k',
+                'e',
+                'n',
+                'n',
+                'e',
+                's',
+                's'};
+
+  extended_inquiry_data_ = {0x07,  // Length
+                            BT_EIR_COMPLETE_LOCAL_NAME_TYPE,
+                            'B',
+                            'R',
+                            '0',
+                            'K',
+                            '3',
+                            'N'};
+  page_scan_repetition_mode_ = 0;
+  page_scan_delay_ms_ = std::chrono::milliseconds(600);
+}
+
+void BrokenAdv::Initialize(const vector<std::string>& args) {
+  if (args.size() < 2) return;
+
+  BtAddress addr;
+  if (addr.FromString(args[1])) SetBtAddress(addr);
+
+  if (args.size() < 3) return;
+
+  SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+// Mostly return the correct length
+static uint8_t random_length(size_t bytes_remaining) {
+  uint32_t randomness = rand();
+
+  switch ((randomness & 0xf000000) >> 24) {
+    case (0):
+      return bytes_remaining + (randomness & 0xff);
+    case (1):
+      return bytes_remaining - (randomness & 0xff);
+    case (2):
+      return bytes_remaining + (randomness & 0xf);
+    case (3):
+      return bytes_remaining - (randomness & 0xf);
+    case (5):
+    case (6):
+      return bytes_remaining + (randomness & 0x3);
+    case (7):
+    case (8):
+      return bytes_remaining - (randomness & 0x3);
+    default:
+      return bytes_remaining;
+  }
+}
+
+static size_t random_adv_type() {
+  uint32_t randomness = rand();
+
+  switch ((randomness & 0xf000000) >> 24) {
+    case (0):
+      return BTM_EIR_MANUFACTURER_SPECIFIC_TYPE;
+    case (1):
+      return (randomness & 0xff);
+    default:
+      return (randomness & 0x1f);
+  }
+}
+
+static size_t random_data_length(size_t length, size_t bytes_remaining) {
+  uint32_t randomness = rand();
+
+  switch ((randomness & 0xf000000) >> 24) {
+    case (0):
+      return bytes_remaining;
+    case (1):
+      return (length + (randomness & 0xff)) % bytes_remaining;
+    default:
+      return (length <= bytes_remaining ? length : bytes_remaining);
+  }
+}
+
+static void RandomizeAdvertisement(vector<uint8_t>& ad, size_t max) {
+  uint8_t length = random_length(max);
+  uint8_t data_length = random_data_length(length, max);
+
+  ad.push_back(random_adv_type());
+  ad.push_back(length);
+  for (size_t i = 0; i < data_length; i++) ad.push_back(rand() & 0xff);
+}
+
+void BrokenAdv::UpdateAdvertisement() {
+  adv_data_.clear();
+  for (size_t i = 0; i < constant_adv_data_.size(); i++)
+    adv_data_.push_back(constant_adv_data_[i]);
+
+  RandomizeAdvertisement(adv_data_, 31 - adv_data_.size());
+
+  RandomizeAdvertisement(scan_data_, 31);
+
+  std::vector<uint8_t> curr_addr;
+  BtAddress next_addr;
+  GetBtAddress().ToVector(curr_addr);
+  curr_addr[0]++;
+  next_addr.FromVector(curr_addr);
+
+  SetBtAddress(next_addr);
+}
+
+std::string BrokenAdv::ToString() const {
+  std::string str = Device::ToString() + std::string(": Interval = ") +
+                    std::to_string(advertising_interval_ms_.count());
+  return str;
+}
+
+void BrokenAdv::UpdatePageScan() {
+  std::vector<uint8_t> broken_addr;
+  RandomizeAdvertisement(scan_data_, 31);
+
+  BtAddress next_addr;
+  GetBtAddress().ToVector(broken_addr);
+  broken_addr[1]++;
+  next_addr.FromVector(broken_addr);
+
+  SetBtAddress(next_addr);
+}
+
+void BrokenAdv::TimerTick() {
+  UpdatePageScan();
+  UpdateAdvertisement();
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/bt_address.cc b/vendor_libs/test_vendor_lib/src/bt_address.cc
index 4deffb3..e9d6790 100644
--- a/vendor_libs/test_vendor_lib/src/bt_address.cc
+++ b/vendor_libs/test_vendor_lib/src/bt_address.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2016 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.
-//
+/*
+ * Copyright 2016 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 "bt_address.h"
 #include <iomanip>
@@ -40,7 +40,7 @@
   std::string tok;
   std::istringstream iss(str);
 
-  if (IsValid(str) == false) return false;
+  if (!IsValid(str)) return false;
 
   address_ = 0;
   for (size_t i = 0; i < kOctets; i++) {
diff --git a/vendor_libs/test_vendor_lib/src/classic.cc b/vendor_libs/test_vendor_lib/src/classic.cc
new file mode 100644
index 0000000..b878b5f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/classic.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "classic"
+
+#include "classic.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+Classic::Classic() {
+  advertising_interval_ms_ = std::chrono::milliseconds(0);
+  device_class_ = 0x30201;
+
+  extended_inquiry_data_ = {0x10,  // Length
+                            BT_EIR_COMPLETE_LOCAL_NAME_TYPE,
+                            'g',
+                            'D',
+                            'e',
+                            'v',
+                            'i',
+                            'c',
+                            'e',
+                            '-',
+                            'c',
+                            'l',
+                            'a',
+                            's',
+                            's',
+                            'i',
+                            'c'};
+  page_scan_repetition_mode_ = 0;
+  page_scan_delay_ms_ = std::chrono::milliseconds(600);
+}
+
+void Classic::Initialize(const vector<std::string>& args) {
+  if (args.size() < 2) return;
+
+  BtAddress addr;
+  if (addr.FromString(args[1])) SetBtAddress(addr);
+
+  if (args.size() < 3) return;
+
+  SetClockOffset(std::stoi(args[2]));
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/command_packet.cc b/vendor_libs/test_vendor_lib/src/command_packet.cc
index 79935dc..9b44c98 100644
--- a/vendor_libs/test_vendor_lib/src/command_packet.cc
+++ b/vendor_libs/test_vendor_lib/src/command_packet.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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.
+ */
 
 #define LOG_TAG "command_packet"
 
diff --git a/vendor_libs/test_vendor_lib/src/connection.cc b/vendor_libs/test_vendor_lib/src/connection.cc
new file mode 100644
index 0000000..5bdc20f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/connection.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "connection"
+
+#include "connection.h"
+
+#include "base/logging.h"
+
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+// Add an action from the controller.
+void Connection::AddAction(const TaskCallback& task) { actions_.push(task); }
+
+// Model the quality of the downstream connection
+void Connection::SendToDevice() {
+  while (actions_.size() > 0) {
+    // Execute the first action
+    actions_.front()();
+    actions_.pop();
+  }
+}
+
+// Add a message from the device to the controller.
+void Connection::AddMessage(const vector<uint8_t>& data) {
+  messages_.push(data);
+}
+
+// Model the quality of the upstream connection
+bool Connection::ReceiveFromDevice(vector<uint8_t>& data) {
+  if (messages_.size() > 0) {
+    data = messages_.front();
+    messages_.pop();
+
+    return true;
+  }
+  return false;
+}
+
+const std::string Connection::ToString() {
+  return "connection " + std::to_string(handle_) + " to " + dev_->ToString();
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/device.cc b/vendor_libs/test_vendor_lib/src/device.cc
new file mode 100644
index 0000000..86d18c0
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/device.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "device"
+
+#include <vector>
+
+#include "device.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+std::string Device::ToString() const {
+  std::string dev = "(" + GetTypeString() + ")" + "@" + address_.ToString();
+
+  return dev;
+}
+
+bool Device::IsAdvertisementAvailable(
+    std::chrono::milliseconds scan_time) const {
+  if (advertising_interval_ms_ == std::chrono::milliseconds(0)) return false;
+
+  std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+
+  std::chrono::steady_clock::time_point last_interval =
+      ((now - time_stamp_) / advertising_interval_ms_) *
+          advertising_interval_ms_ +
+      time_stamp_;
+
+  std::chrono::steady_clock::time_point next_interval =
+      last_interval + advertising_interval_ms_;
+
+  return ((now + scan_time) >= next_interval);
+}
+
+bool Device::IsPageScanAvailable() const { return true; }
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/device_factory.cc b/vendor_libs/test_vendor_lib/src/device_factory.cc
new file mode 100644
index 0000000..3e23dee
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/device_factory.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "device_factory"
+
+#include "device_factory.h"
+#include "beacon.h"
+#include "beacon_swarm.h"
+#include "broken_adv.h"
+#include "classic.h"
+#include "device.h"
+#include "keyboard.h"
+
+#include "base/logging.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+std::shared_ptr<Device> DeviceFactory::Create(const vector<std::string>& args) {
+  CHECK(!args.empty());
+
+  std::shared_ptr<Device> new_device = nullptr;
+
+  if (args[0] == "beacon") new_device = std::make_shared<Beacon>();
+  if (args[0] == "beacon_swarm") new_device = std::make_shared<BeaconSwarm>();
+  if (args[0] == "broken_adv") new_device = std::make_shared<BrokenAdv>();
+  if (args[0] == "classic") new_device = std::make_shared<Classic>();
+  if (args[0] == "keyboard") new_device = std::make_shared<Keyboard>();
+
+  if (new_device != nullptr) new_device->Initialize(args);
+
+  return new_device;
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/device_properties.cc b/vendor_libs/test_vendor_lib/src/device_properties.cc
new file mode 100644
index 0000000..672dd65
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/device_properties.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#define LOG_TAG "device_properties"
+
+#include "device_properties.h"
+
+#include <memory>
+
+#include <base/logging.h>
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace {
+// Functions used by JSONValueConverter to read stringified JSON.
+bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
+  *field = std::stoi(value.as_string());
+  return true;
+}
+
+bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
+  *field = std::stoi(value.as_string());
+  return true;
+}
+
+}  // namespace
+
+namespace test_vendor_lib {
+
+DeviceProperties::DeviceProperties(const std::string& file_name)
+    : acl_data_packet_size_(1024),
+      sco_data_packet_size_(255),
+      num_acl_data_packets_(10),
+      num_sco_data_packets_(10),
+      version_(HCI_PROTO_VERSION_4_1),
+      revision_(0),
+      lmp_pal_version_(7), /* 4.1 */
+      manufacturer_name_(0),
+      lmp_pal_subversion_(0),
+      le_data_packet_length_(27),
+      num_le_data_packets_(15),
+      le_white_list_size_(15) {
+  std::string properties_raw;
+
+  local_extended_features_ = {0xffffffffffffffff, 0x7};
+
+  CHECK(address_.FromString("01:02:03:04:05:06"));
+  local_name_ = "DefaultName";
+
+  supported_codecs_ = {1};
+  vendor_specific_codecs_ = {};
+
+  for (int i = 0; i < 64; i++) local_supported_commands_.push_back(0xff);
+
+  le_supported_features_ = 0x1f;
+  le_supported_states_ = 0x3ffffffffff;
+  le_vendor_cap_ = {};
+
+  LOG_INFO(LOG_TAG, "Reading controller properties from %s.",
+           file_name.c_str());
+  if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
+    LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
+    return;
+  }
+
+  std::unique_ptr<base::Value> properties_value_ptr =
+      base::JSONReader::Read(properties_raw);
+  if (properties_value_ptr.get() == nullptr)
+    LOG_INFO(LOG_TAG,
+             "Error controller properties may consist of ill-formed JSON.");
+
+  // Get the underlying base::Value object, which is of type
+  // base::Value::TYPE_DICTIONARY, and read it into member variables.
+  base::Value& properties_dictionary = *(properties_value_ptr.get());
+  base::JSONValueConverter<DeviceProperties> converter;
+
+  if (!converter.Convert(properties_dictionary, this))
+    LOG_INFO(LOG_TAG,
+             "Error converting JSON properties into Properties object.");
+}
+
+// static
+void DeviceProperties::RegisterJSONConverter(
+    base::JSONValueConverter<DeviceProperties>* converter) {
+// TODO(dennischeng): Use RegisterIntField() here?
+#define REGISTER_UINT8_T(field_name, field) \
+  converter->RegisterCustomField<uint8_t>(  \
+      field_name, &DeviceProperties::field, &ParseUint8t);
+#define REGISTER_UINT16_T(field_name, field) \
+  converter->RegisterCustomField<uint16_t>(  \
+      field_name, &DeviceProperties::field, &ParseUint16t);
+  REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
+  REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
+  REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
+  REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
+  REGISTER_UINT8_T("Version", version_);
+  REGISTER_UINT16_T("Revision", revision_);
+  REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
+  REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
+  REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
+#undef REGISTER_UINT8_T
+#undef REGISTER_UINT16_T
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
index 86f920b..bc80866 100644
--- a/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
+++ b/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
@@ -1,22 +1,23 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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.
+ */
 
 #define LOG_TAG "dual_mode_controller"
 
 #include "dual_mode_controller.h"
+#include "device_factory.h"
 
 #include <memory>
 
@@ -24,7 +25,6 @@
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
-#include "event_packet.h"
 
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
@@ -44,30 +44,10 @@
 const std::string kControllerPropertiesFile =
     "/etc/bluetooth/controller_properties.json";
 
-// Inquiry modes for specifiying inquiry result formats.
-const uint8_t kStandardInquiry = 0x00;
-const uint8_t kRssiInquiry = 0x01;
-const uint8_t kExtendedOrRssiInquiry = 0x02;
-
-// The bd address of another (fake) device.
-const vector<uint8_t> kOtherDeviceBdAddress = {6, 5, 4, 3, 2, 1};
-
 void LogCommand(const char* command) {
   LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
 }
 
-// Functions used by JSONValueConverter to read stringified JSON into Properties
-// object.
-bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
-  *field = std::stoi(value.as_string());
-  return true;
-}
-
-bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
-  *field = std::stoi(value.as_string());
-  return true;
-}
-
 }  // namespace
 
 namespace test_vendor_lib {
@@ -77,6 +57,12 @@
   controller_events_.push_back(schedule_task_(delay, task));
 }
 
+void DualModeController::AddConnectionAction(const TaskCallback& task,
+                                             uint16_t handle) {
+  for (size_t i = 0; i < connections_.size(); i++)
+    if (*connections_[i] == handle) connections_[i]->AddAction(task);
+}
+
 void DualModeController::SendCommandCompleteSuccess(
     uint16_t command_opcode) const {
   send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(
@@ -100,9 +86,26 @@
 }
 
 DualModeController::DualModeController()
-    : state_(kStandby),
-      properties_(kControllerPropertiesFile),
-      test_channel_state_(kNone) {
+    : state_(kStandby), properties_(kControllerPropertiesFile) {
+  devices_ = {};
+
+  vector<std::string> beacon = {"beacon", "be:ac:10:00:00:01", "1000"};
+  TestChannelAdd(beacon);
+
+  vector<std::string> classic = {std::string("classic"),
+                                 std::string("c1:a5:51:c0:00:01")};
+  TestChannelAdd(classic);
+
+  vector<std::string> keyboard = {std::string("keyboard"),
+                                  std::string("cc:1c:eb:0a:12:d1"),
+                                  std::string("500")};
+  TestChannelAdd(keyboard);
+
+  le_scan_enable_ = 0;
+  le_connect_ = false;
+
+  loopback_mode_ = 0;
+
 #define SET_HANDLER(opcode, method)                                     \
   active_hci_commands_[opcode] = [this](const vector<uint8_t>& param) { \
     method(param);                                                      \
@@ -144,6 +147,8 @@
   SET_HANDLER(HCI_BLE_WRITE_ADV_PARAMS, HciLeSetAdvertisingParameters);
   SET_HANDLER(HCI_BLE_WRITE_SCAN_PARAMS, HciLeSetScanParameters);
   SET_HANDLER(HCI_BLE_WRITE_SCAN_ENABLE, HciLeSetScanEnable);
+  SET_HANDLER(HCI_BLE_CREATE_LL_CONN, HciLeCreateConnection);
+  SET_HANDLER(HCI_BLE_CREATE_CONN_CANCEL, HciLeConnectionCancel);
   SET_HANDLER(HCI_BLE_READ_WHITE_LIST_SIZE, HciLeReadWhiteListSize);
   SET_HANDLER(HCI_BLE_RAND, HciLeRand);
   SET_HANDLER(HCI_BLE_READ_SUPPORTED_STATES, HciLeReadSupportedStates);
@@ -151,19 +156,20 @@
   SET_HANDLER(HCI_BLE_VENDOR_CAP_OCF, HciBleVendorCap);
   SET_HANDLER(HCI_BLE_MULTI_ADV_OCF, HciBleVendorMultiAdv);
   SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x155), HciBleVendor155);
-  SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x157), HciBleVendor157);
+  SET_HANDLER(HCI_BLE_ADV_FILTER_OCF, HciBleAdvertisingFilter);
   SET_HANDLER(HCI_BLE_ENERGY_INFO_OCF, HciBleEnergyInfo);
   SET_HANDLER(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF, HciBleExtendedScanParams);
+  // Testing Commands
+  SET_HANDLER(HCI_READ_LOOPBACK_MODE, HciReadLoopbackMode);
+  SET_HANDLER(HCI_WRITE_LOOPBACK_MODE, HciWriteLoopbackMode);
 #undef SET_HANDLER
 
 #define SET_TEST_HANDLER(command_name, method)  \
   active_test_channel_commands_[command_name] = \
       [this](const vector<std::string>& param) { method(param); };
-  SET_TEST_HANDLER("CLEAR", TestChannelClear);
-  SET_TEST_HANDLER("CLEAR_EVENT_DELAY", TestChannelClearEventDelay);
-  SET_TEST_HANDLER("DISCOVER", TestChannelDiscover);
-  SET_TEST_HANDLER("SET_EVENT_DELAY", TestChannelSetEventDelay);
-  SET_TEST_HANDLER("TIMEOUT_ALL", TestChannelTimeoutAll);
+  SET_TEST_HANDLER("add", TestChannelAdd);
+  SET_TEST_HANDLER("del", TestChannelDel);
+  SET_TEST_HANDLER("list", TestChannelList);
 #undef SET_TEST_HANDLER
 }
 
@@ -191,19 +197,43 @@
   active_test_channel_commands_[name](args);
 }
 
+void DualModeController::HandleAcl(std::unique_ptr<AclPacket> acl_packet) {
+  if (loopback_mode_ == HCI_LOOPBACK_MODE_LOCAL) {
+    uint16_t channel = acl_packet->GetChannel();
+    send_acl_(std::move(acl_packet));
+    send_event_(EventPacket::CreateNumberOfCompletedPacketsEvent(channel, 1));
+    return;
+  }
+}
+
+void DualModeController::HandleSco(std::unique_ptr<ScoPacket> sco_packet) {
+  if (loopback_mode_ == HCI_LOOPBACK_MODE_LOCAL) {
+    uint16_t channel = sco_packet->GetChannel();
+    send_sco_(std::move(sco_packet));
+    send_event_(EventPacket::CreateNumberOfCompletedPacketsEvent(channel, 1));
+    return;
+  }
+}
+
 void DualModeController::HandleCommand(
     std::unique_ptr<CommandPacket> command_packet) {
   uint16_t opcode = command_packet->GetOpcode();
   LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
            command_packet->GetOGF(), command_packet->GetOCF());
 
-  // The command hasn't been registered with the handler yet. There is nothing
-  // to do.
-  if (active_hci_commands_.count(opcode) == 0)
-    return;
-  else if (test_channel_state_ == kTimeoutAll)
-    return;
-  active_hci_commands_[opcode](command_packet->GetPayload());
+  if (loopback_mode_ == HCI_LOOPBACK_MODE_LOCAL &&
+      // Loopback exceptions.
+      opcode != HCI_RESET && opcode != HCI_SET_HC_TO_HOST_FLOW_CTRL &&
+      opcode != HCI_HOST_BUFFER_SIZE && opcode != HCI_HOST_NUM_PACKETS_DONE &&
+      opcode != HCI_READ_BUFFER_SIZE && opcode != HCI_READ_LOOPBACK_MODE &&
+      opcode != HCI_WRITE_LOOPBACK_MODE) {
+    send_event_(EventPacket::CreateLoopbackCommandEvent(
+        opcode, command_packet->GetPayload()));
+  } else if (active_hci_commands_.count(opcode) > 0) {
+    active_hci_commands_[opcode](command_packet->GetPayload());
+  } else {
+    SendCommandCompleteOnlyStatus(opcode, kUnknownHciCommand);
+  }
 }
 
 void DualModeController::RegisterEventChannel(
@@ -211,10 +241,21 @@
   send_event_ = callback;
 }
 
+void DualModeController::RegisterAclChannel(
+    const std::function<void(std::unique_ptr<AclPacket>)>& callback) {
+  send_acl_ = callback;
+}
+
+void DualModeController::RegisterScoChannel(
+    const std::function<void(std::unique_ptr<ScoPacket>)>& callback) {
+  send_sco_ = callback;
+}
+
 void DualModeController::HandleTimerTick() {
-  // PageScan();
-  if (le_scan_enable_) LOG_ERROR(LOG_TAG, "LE scan");
-  // LeScan();
+  if (state_ == kInquiry) PageScan();
+  if (le_scan_enable_ || le_connect_) LeScan();
+  Connections();
+  for (size_t dev = 0; dev < devices_.size(); dev++) devices_[dev]->TimerTick();
 }
 
 void DualModeController::SetTimerPeriod(std::chrono::milliseconds new_period) {
@@ -227,6 +268,145 @@
   StartTimer();
 }
 
+static uint8_t GetRssi(size_t dev) {
+  // TODO: Model rssi somehow
+  return -((dev * 16) % 127);
+}
+
+static uint8_t LeGetHandle() {
+  static int handle = 0;
+  return handle++;
+}
+
+static uint8_t LeGetConnInterval() { return 1; }
+
+static uint8_t LeGetConnLatency() { return 2; }
+
+static uint8_t LeGetSupervisionTimeout() { return 3; }
+
+void DualModeController::Connections() {
+  for (size_t i = 0; i < connections_.size(); i++) {
+    if (connections_[i]->Connected()) {
+      connections_[i]->SendToDevice();
+      vector<uint8_t> data;
+      connections_[i]->ReceiveFromDevice(data);
+      // HandleConnectionData(data);
+    }
+  }
+}
+
+void DualModeController::LeScan() {
+  std::unique_ptr<EventPacket> le_adverts =
+      EventPacket::CreateLeAdvertisingReportEvent();
+  vector<uint8_t> ad;
+  for (size_t dev = 0; dev < devices_.size(); dev++) {
+    uint8_t adv_type;
+    const BtAddress addr = devices_[dev]->GetBtAddress();
+    uint8_t addr_type = devices_[dev]->GetAddressType();
+    ad.clear();
+
+    // Listen for Advertisements
+    if (devices_[dev]->IsAdvertisementAvailable(
+            std::chrono::milliseconds(le_scan_window_))) {
+      ad = devices_[dev]->GetAdvertisement();
+      adv_type = devices_[dev]->GetAdvertisementType();
+      if (le_scan_enable_ && !le_adverts->AddLeAdvertisingReport(
+                                 adv_type, addr_type, addr, ad, GetRssi(dev))) {
+        send_event_(std::move(le_adverts));
+        le_adverts = EventPacket::CreateLeAdvertisingReportEvent();
+        CHECK(le_adverts->AddLeAdvertisingReport(adv_type, addr_type, addr, ad,
+                                                 GetRssi(dev)));
+      }
+
+      // Connect
+      if (le_connect_ && (adv_type == BTM_BLE_CONNECT_EVT ||
+                          adv_type == BTM_BLE_CONNECT_DIR_EVT)) {
+        LOG_INFO(LOG_TAG, "Connecting to device %d", static_cast<int>(dev));
+        if (peer_address_ == addr && peer_address_type_ == addr_type &&
+            devices_[dev]->LeConnect()) {
+          uint16_t handle = LeGetHandle();
+          std::unique_ptr<EventPacket> event =
+              EventPacket::CreateLeConnectionCompleteEvent(
+                  kSuccessStatus, handle, HCI_ROLE_MASTER, addr_type, addr,
+                  LeGetConnInterval(), LeGetConnLatency(),
+                  LeGetSupervisionTimeout());
+          send_event_(std::move(event));
+          le_connect_ = false;
+
+          connections_.push_back(
+              std::make_shared<Connection>(devices_[dev], handle));
+        }
+
+        // TODO: Handle the white list (if (InWhiteList(dev)))
+      }
+
+      // Active scanning
+      if (le_scan_enable_ && le_scan_type_ == 1) {
+        ad.clear();
+        if (devices_[dev]->HasScanResponse()) {
+          ad = devices_[dev]->GetScanResponse();
+          if (!le_adverts->AddLeAdvertisingReport(
+                  BTM_BLE_SCAN_RSP_EVT, addr_type, addr, ad, GetRssi(dev))) {
+            send_event_(std::move(le_adverts));
+            le_adverts = EventPacket::CreateLeAdvertisingReportEvent();
+            CHECK(le_adverts->AddLeAdvertisingReport(
+                BTM_BLE_SCAN_RSP_EVT, addr_type, addr, ad, GetRssi(dev)));
+          }
+        }
+      }
+    }
+  }
+
+  if (le_scan_enable_) send_event_(std::move(le_adverts));
+}
+
+void DualModeController::PageScan() {
+  // Inquiry modes for specifiying inquiry result formats.
+  static const uint8_t kStandardInquiry = 0x00;
+  static const uint8_t kRssiInquiry = 0x01;
+  static const uint8_t kExtendedOrRssiInquiry = 0x02;
+
+  switch (inquiry_mode_) {
+    case (kStandardInquiry): {
+      std::unique_ptr<EventPacket> inquiry_result =
+          EventPacket::CreateInquiryResultEvent();
+      for (size_t dev = 0; dev < devices_.size(); dev++)
+        // Scan for devices
+        if (devices_[dev]->IsPageScanAvailable()) {
+          bool result_added = inquiry_result->AddInquiryResult(
+              devices_[dev]->GetBtAddress(),
+              devices_[dev]->GetPageScanRepetitionMode(),
+              devices_[dev]->GetDeviceClass(), devices_[dev]->GetClockOffset());
+          if (!result_added) {
+            send_event_(std::move(inquiry_result));
+            inquiry_result = EventPacket::CreateInquiryResultEvent();
+            result_added = inquiry_result->AddInquiryResult(
+                devices_[dev]->GetBtAddress(),
+                devices_[dev]->GetPageScanRepetitionMode(),
+                devices_[dev]->GetDeviceClass(),
+                devices_[dev]->GetClockOffset());
+            CHECK(result_added);
+          }
+        }
+    } break;
+
+    case (kRssiInquiry):
+      LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
+      break;
+
+    case (kExtendedOrRssiInquiry):
+      for (size_t dev = 0; dev < devices_.size(); dev++)
+        if (devices_[dev]->IsPageScanAvailable()) {
+          send_event_(EventPacket::CreateExtendedInquiryResultEvent(
+              devices_[dev]->GetBtAddress(),
+              devices_[dev]->GetPageScanRepetitionMode(),
+              devices_[dev]->GetDeviceClass(), devices_[dev]->GetClockOffset(),
+              GetRssi(dev), devices_[dev]->GetExtendedInquiryData()));
+        }
+      break;
+  }
+}
+
 void DualModeController::StartTimer() {
   LOG_ERROR(LOG_TAG, "StartTimer");
   timer_tick_task_ = schedule_periodic_task_(
@@ -240,43 +420,49 @@
   timer_tick_task_ = kInvalidTaskId;
 }
 
-void DualModeController::TestChannelClear(
-    UNUSED_ATTR const vector<std::string>& args) {
-  LogCommand("TestChannel Clear");
-  test_channel_state_ = kNone;
+void DualModeController::SetEventDelay(int64_t delay) {
+  if (delay < 0) delay = 0;
 }
 
-void DualModeController::TestChannelDiscover(
-    UNUSED_ATTR const vector<std::string>& args) {
-  LogCommand("TestChannel Discover");
-  /* TODO: Replace with adding devices */
-  /*
+void DualModeController::TestChannelAdd(const vector<std::string>& args) {
+  LogCommand("TestChannel 'add'");
 
-    for (size_t i = 0; i < args.size() - 1; i += 2)
-      SendExtendedInquiryResult(args[i], args[i + 1]);
-  */
+  std::shared_ptr<Device> new_dev = DeviceFactory::Create(args);
+
+  if (new_dev == NULL) {
+    LOG_ERROR(LOG_TAG, "TestChannel 'add' failed!");
+    return;
+  }
+
+  devices_.push_back(new_dev);
 }
 
-void DualModeController::TestChannelTimeoutAll(
-    UNUSED_ATTR const vector<std::string>& args) {
-  LogCommand("TestChannel Timeout All");
-  test_channel_state_ = kTimeoutAll;
+void DualModeController::TestChannelDel(const vector<std::string>& args) {
+  LogCommand("TestChannel 'del'");
+
+  size_t dev_index = std::stoi(args[0]);
+
+  if (dev_index >= devices_.size()) {
+    LOG_INFO(LOG_TAG, "TestChannel 'del': index %d out of range!",
+             static_cast<int>(dev_index));
+  } else {
+    devices_.erase(devices_.begin() + dev_index);
+  }
 }
 
-void DualModeController::TestChannelSetEventDelay(
-    const vector<std::string>& args UNUSED_ATTR) {
-  LogCommand("TestChannel Set Event Delay");
-  test_channel_state_ = kDelayedResponse;
+void DualModeController::TestChannelList(
+    UNUSED_ATTR const vector<std::string>& args) const {
+  LogCommand("TestChannel 'list'");
+  LOG_INFO(LOG_TAG, "Devices:");
+  for (size_t dev = 0; dev < devices_.size(); dev++) {
+    LOG_INFO(LOG_TAG, "%d:", static_cast<int>(dev));
+    devices_[dev]->ToString();
+  }
 }
 
-void DualModeController::TestChannelClearEventDelay(
-    UNUSED_ATTR const vector<std::string>& args) {
-  LogCommand("TestChannel Clear Event Delay");
-  test_channel_state_ = kNone;
-}
-
-void DualModeController::HciReset(UNUSED_ATTR const vector<uint8_t>& args) {
+void DualModeController::HciReset(const vector<uint8_t>& args) {
   LogCommand("Reset");
+  CHECK(args[0] == 0);  // No arguments
   state_ = kStandby;
   if (timer_tick_task_ != kInvalidTaskId) {
     LOG_INFO(LOG_TAG, "The timer was already running!");
@@ -288,9 +474,9 @@
   SendCommandCompleteSuccess(HCI_RESET);
 }
 
-void DualModeController::HciReadBufferSize(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+void DualModeController::HciReadBufferSize(const vector<uint8_t>& args) {
   LogCommand("Read Buffer Size");
+  CHECK(args[0] == 0);  // No arguments
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteReadBufferSize(
           kSuccessStatus, properties_.GetAclDataPacketSize(),
@@ -301,15 +487,16 @@
   send_event_(std::move(command_complete));
 }
 
-void DualModeController::HciHostBufferSize(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+void DualModeController::HciHostBufferSize(const vector<uint8_t>& args) {
   LogCommand("Host Buffer Size");
+  CHECK(args[0] == 7);  // No arguments
   SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
 }
 
 void DualModeController::HciReadLocalVersionInformation(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+    const vector<uint8_t>& args) {
   LogCommand("Read Local Version Information");
+  CHECK(args[0] == 0);  // No arguments
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteReadLocalVersionInformation(
           kSuccessStatus, properties_.GetVersion(), properties_.GetRevision(),
@@ -318,8 +505,8 @@
   send_event_(std::move(command_complete));
 }
 
-void DualModeController::HciReadBdAddr(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+void DualModeController::HciReadBdAddr(const vector<uint8_t>& args) {
+  CHECK(args[0] == 0);  // No arguments
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteReadBdAddr(kSuccessStatus,
                                                    properties_.GetAddress());
@@ -327,8 +514,9 @@
 }
 
 void DualModeController::HciReadLocalSupportedCommands(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+    const vector<uint8_t>& args) {
   LogCommand("Read Local Supported Commands");
+  CHECK(args[0] == 0);  // No arguments
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
           kSuccessStatus, properties_.GetLocalSupportedCommands());
@@ -336,8 +524,9 @@
 }
 
 void DualModeController::HciReadLocalSupportedCodecs(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+    const vector<uint8_t>& args) {
   LogCommand("Read Local Supported Codecs");
+  CHECK(args[0] == 0);  // No arguments
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
           kSuccessStatus, properties_.GetSupportedCodecs(),
@@ -464,49 +653,21 @@
 }
 
 void DualModeController::HciInquiry(const vector<uint8_t>& args) {
-  // Fake inquiry response for a fake device.
-  const EventPacket::PageScanRepetitionMode kPageScanRepetitionMode =
-      EventPacket::kR0;
-  const uint32_t kClassOfDevice = 0x030201;
-  const uint16_t kClockOffset = 513;
-  BtAddress other_addr;
-  other_addr.FromVector(kOtherDeviceBdAddress);
-
   LogCommand("Inquiry");
+  CHECK(args.size() == 6);
   state_ = kInquiry;
   SendCommandStatusSuccess(HCI_INQUIRY);
-  switch (inquiry_mode_) {
-    case (kStandardInquiry): {
-      std::unique_ptr<EventPacket> inquiry_result_evt =
-          EventPacket::CreateInquiryResultEvent(other_addr,
-                                                kPageScanRepetitionMode,
-                                                kClassOfDevice, kClockOffset);
-      send_event_(std::move(inquiry_result_evt));
-      /* TODO: Return responses from modeled devices */
-    } break;
+  inquiry_lap_[0] = args[1];
+  inquiry_lap_[1] = args[2];
+  inquiry_lap_[2] = args[3];
 
-    case (kRssiInquiry):
-      LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
-      break;
-
-    case (kExtendedOrRssiInquiry): {
-      const std::string name = "Foobar";
-      vector<uint8_t> extended_inquiry_data = {
-          static_cast<uint8_t>(name.length() + 1), 0x09};
-
-      for (size_t i = 0; i < name.length(); i++)
-        extended_inquiry_data.push_back(name[i]);
-      extended_inquiry_data.push_back('\0');
-
-      uint8_t rssi = static_cast<uint8_t>(-20);
-      send_event_(EventPacket::CreateExtendedInquiryResultEvent(
-          other_addr, kPageScanRepetitionMode, kClassOfDevice, kClockOffset,
-          rssi, extended_inquiry_data));
-      /* TODO: Return responses from modeled devices */
-    } break;
-  }
   AddControllerEvent(std::chrono::milliseconds(args[4] * 1280),
                      [this]() { DualModeController::InquiryTimeout(); });
+
+  if (args[5] > 0) {
+    inquiry_responses_limited_ = true;
+    inquiry_num_responses_ = args[5];
+  }
 }
 
 void DualModeController::HciInquiryCancel(
@@ -521,6 +682,7 @@
   LOG_INFO(LOG_TAG, "InquiryTimer fired");
   if (state_ == kInquiry) {
     state_ = kStandby;
+    inquiry_responses_limited_ = false;
     send_event_(EventPacket::CreateInquiryCompleteEvent(kSuccessStatus));
   }
 }
@@ -530,7 +692,10 @@
   LogCommand("Delete Stored Link Key");
   /* Check the last octect in |args|. If it is 0, delete only the link key for
    * the given BD_ADDR. If is is 1, delete all stored link keys. */
-  SendCommandCompleteOnlyStatus(HCI_INQUIRY_CANCEL, kUnknownHciCommand);
+  uint16_t deleted_keys = 1;
+
+  send_event_(EventPacket::CreateCommandCompleteDeleteStoredLinkKey(
+      kSuccessStatus, deleted_keys));
 }
 
 void DualModeController::HciRemoteNameRequest(
@@ -597,20 +762,76 @@
 void DualModeController::HciLeSetScanEnable(const vector<uint8_t>& args) {
   LogCommand("LE SetScanEnable");
   CHECK(args.size() == 3);
-  CHECK(args[0] == 2);
   le_scan_enable_ = args[1];
   filter_duplicates_ = args[2];
   SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_ENABLE);
 }
 
-void DualModeController::HciLeReadWhiteListSize(
-    UNUSED_ATTR const vector<uint8_t>& args) {
+void DualModeController::HciLeCreateConnection(const vector<uint8_t>& args) {
+  LogCommand("LE CreateConnection");
+  le_connect_ = true;
+  le_scan_interval_ = args[1] | (args[2] << 8);
+  le_scan_window_ = args[3] | (args[4] << 8);
+  initiator_filter_policy_ = args[5];
+
+  if (initiator_filter_policy_ == 0) {  // White list not used
+    peer_address_type_ = args[6];
+    vector<uint8_t> peer_addr = {args[7],  args[8],  args[9],
+                                 args[10], args[11], args[12]};
+    peer_address_.FromVector(peer_addr);
+  }
+
+  SendCommandStatusSuccess(HCI_BLE_CREATE_LL_CONN);
+}
+
+void DualModeController::HciLeConnectionCancel(const vector<uint8_t>& args) {
+  LogCommand("LE ConnectionCancel");
+  CHECK(args[0] == 0);  // No arguments
+  le_connect_ = false;
+  SendCommandStatusSuccess(HCI_BLE_CREATE_CONN_CANCEL);
+}
+
+void DualModeController::HciLeReadWhiteListSize(const vector<uint8_t>& args) {
+  LogCommand("LE ReadWhiteListSize");
+  CHECK(args[0] == 0);  // No arguments
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteLeReadWhiteListSize(
           kSuccessStatus, properties_.GetLeWhiteListSize());
   send_event_(std::move(command_complete));
 }
 
+void DualModeController::HciLeReadRemoteUsedFeaturesB(uint16_t handle) {
+  uint64_t features;
+  LogCommand("LE ReadRemoteUsedFeatures Bottom half");
+
+  for (size_t i = 0; i < connections_.size(); i++)
+    if (*connections_[i] == handle)
+      // TODO:
+      // features = connections_[i]->GetDevice()->GetUsedFeatures();
+      features = 0xffffffffffffffff;
+
+  std::unique_ptr<EventPacket> event =
+      EventPacket::CreateLeRemoteUsedFeaturesEvent(kSuccessStatus, handle,
+                                                   features);
+  send_event_(std::move(event));
+}
+
+void DualModeController::HciLeReadRemoteUsedFeatures(
+    const vector<uint8_t>& args) {
+  LogCommand("LE ReadRemoteUsedFeatures");
+  CHECK(args.size() == 3);
+
+  uint16_t handle = args[1] | (args[2] << 8);
+
+  AddConnectionAction(
+      [this, handle]() {
+        DualModeController::HciLeReadRemoteUsedFeaturesB(handle);
+      },
+      handle);
+
+  SendCommandStatusSuccess(HCI_BLE_READ_REMOTE_FEAT);
+}
+
 void DualModeController::HciLeRand(UNUSED_ATTR const vector<uint8_t>& args) {
   uint64_t random_val = rand();
   std::unique_ptr<EventPacket> command_complete =
@@ -634,6 +855,12 @@
 
 void DualModeController::HciBleVendorCap(
     UNUSED_ATTR const vector<uint8_t>& args) {
+  vector<uint8_t> caps = properties_.GetLeVendorCap();
+  if (caps.size() == 0) {
+    SendCommandCompleteOnlyStatus(HCI_BLE_VENDOR_CAP_OCF, kUnknownHciCommand);
+    return;
+  }
+
   std::unique_ptr<EventPacket> command_complete =
       EventPacket::CreateCommandCompleteLeVendorCap(
           kSuccessStatus, properties_.GetLeVendorCap());
@@ -651,10 +878,9 @@
                                 kUnknownHciCommand);
 }
 
-void DualModeController::HciBleVendor157(
+void DualModeController::HciBleAdvertisingFilter(
     UNUSED_ATTR const vector<uint8_t>& args) {
-  SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x157,
-                                kUnknownHciCommand);
+  SendCommandCompleteOnlyStatus(HCI_BLE_ADV_FILTER_OCF, kUnknownHciCommand);
 }
 
 void DualModeController::HciBleEnergyInfo(
@@ -668,80 +894,28 @@
                                 kUnknownHciCommand);
 }
 
-DualModeController::Properties::Properties(const std::string& file_name)
-    : acl_data_packet_size_(1024),
-      sco_data_packet_size_(255),
-      num_acl_data_packets_(10),
-      num_sco_data_packets_(10),
-      version_(4),
-      revision_(1),
-      lmp_pal_version_(0),
-      manufacturer_name_(0),
-      lmp_pal_subversion_(0),
-      le_data_packet_length_(27),
-      num_le_data_packets_(15),
-      le_white_list_size_(15) {
-  std::string properties_raw;
-
-  local_extended_features_ = {0xffffffffffffffff, 0x7};
-
-  CHECK(address_.FromString("01:02:03:04:05:06"));
-  local_name_ = "DefaultName";
-
-  supported_codecs_ = {1};
-  vendor_specific_codecs_ = {};
-
-  for (int i = 0; i < 64; i++) local_supported_commands_.push_back(0xff);
-
-  le_supported_features_ = 0x1f;
-  le_supported_states_ = 0x3ffffffffff;
-  le_vendor_cap_ = {0x05, 0x01, 0x00, 0x04, 0x80, 0x01, 0x10,
-                    0x01, 0x60, 0x00, 0x0a, 0x00, 0x01, 0x01};
-
-  LOG_INFO(LOG_TAG, "Reading controller properties from %s.",
-           file_name.c_str());
-  if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
-    LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
-    return;
-  }
-
-  std::unique_ptr<base::Value> properties_value_ptr =
-      base::JSONReader::Read(properties_raw);
-  if (properties_value_ptr.get() == nullptr)
-    LOG_INFO(LOG_TAG,
-             "Error controller properties may consist of ill-formed JSON.");
-
-  // Get the underlying base::Value object, which is of type
-  // base::Value::TYPE_DICTIONARY, and read it into member variables.
-  base::Value& properties_dictionary = *(properties_value_ptr.get());
-  base::JSONValueConverter<DualModeController::Properties> converter;
-
-  if (!converter.Convert(properties_dictionary, this))
-    LOG_INFO(LOG_TAG,
-             "Error converting JSON properties into Properties object.");
+void DualModeController::HciReadLoopbackMode(const vector<uint8_t>& args) {
+  CHECK(args[0] == 0);  // No arguments
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadLoopbackMode(kSuccessStatus,
+                                                         loopback_mode_);
+  send_event_(std::move(command_complete));
 }
 
-// static
-void DualModeController::Properties::RegisterJSONConverter(
-    base::JSONValueConverter<DualModeController::Properties>* converter) {
-// TODO(dennischeng): Use RegisterIntField() here?
-#define REGISTER_UINT8_T(field_name, field) \
-  converter->RegisterCustomField<uint8_t>(  \
-      field_name, &DualModeController::Properties::field, &ParseUint8t);
-#define REGISTER_UINT16_T(field_name, field) \
-  converter->RegisterCustomField<uint16_t>(  \
-      field_name, &DualModeController::Properties::field, &ParseUint16t);
-  REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
-  REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
-  REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
-  REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
-  REGISTER_UINT8_T("Version", version_);
-  REGISTER_UINT16_T("Revision", revision_);
-  REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
-  REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
-  REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
-#undef REGISTER_UINT8_T
-#undef REGISTER_UINT16_T
+void DualModeController::HciWriteLoopbackMode(const vector<uint8_t>& args) {
+  CHECK(args[0] == 1);
+  loopback_mode_ = args[1];
+  // ACL channel
+  uint16_t acl_handle = 0x123;
+  send_event_(EventPacket::CreateConnectionCompleteEvent(
+      kSuccessStatus, acl_handle, properties_.GetAddress(), HCI_LINK_TYPE_ACL,
+      false));
+  // SCO channel
+  uint16_t sco_handle = 0x345;
+  send_event_(EventPacket::CreateConnectionCompleteEvent(
+      kSuccessStatus, sco_handle, properties_.GetAddress(), HCI_LINK_TYPE_SCO,
+      false));
+  SendCommandCompleteSuccess(HCI_WRITE_LOOPBACK_MODE);
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/event_packet.cc b/vendor_libs/test_vendor_lib/src/event_packet.cc
index 78a0435..482b47f 100644
--- a/vendor_libs/test_vendor_lib/src/event_packet.cc
+++ b/vendor_libs/test_vendor_lib/src/event_packet.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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.
+ */
 
 #define LOG_TAG "event_packet"
 
@@ -79,6 +79,38 @@
   return evt_ptr;
 }
 
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
+std::unique_ptr<EventPacket> EventPacket::CreateNumberOfCompletedPacketsEvent(
+    uint16_t handle, uint16_t num_completed_packets) {
+  std::unique_ptr<EventPacket> evt_ptr = std::unique_ptr<EventPacket>(
+      new EventPacket(HCI_NUM_COMPL_DATA_PKTS_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(0));  // Number of handles.
+  evt_ptr->AddCompletedPackets(handle, num_completed_packets);
+
+  return evt_ptr;
+}
+
+void EventPacket::AddCompletedPackets(uint16_t handle,
+                                      uint16_t num_completed_packets) {
+  CHECK(AddPayloadOctets2(handle));
+  CHECK(AddPayloadOctets2(num_completed_packets));
+  CHECK(IncrementPayloadCounter(1));  // Increment the number of handles.
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteDeleteStoredLinkKey(
+    uint8_t status, uint16_t num_keys_deleted) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_DELETE_STORED_LINK_KEY, status);
+
+  CHECK(evt_ptr->AddPayloadOctets2(num_keys_deleted));
+
+  return evt_ptr;
+}
+
 // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
 std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadLocalName(
     uint8_t status, const std::string& local_name) {
@@ -189,31 +221,34 @@
   return evt_ptr;
 }
 
-std::unique_ptr<EventPacket> EventPacket::CreateInquiryResultEvent(
-    const BtAddress& address,
-    const PageScanRepetitionMode page_scan_repetition_mode,
-    uint32_t class_of_device, uint16_t clock_offset) {
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadLoopbackMode(
+    uint8_t status, uint8_t mode) {
   std::unique_ptr<EventPacket> evt_ptr =
-      std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_RESULT_EVT));
-
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // Start with a single response
-
-  CHECK(evt_ptr->AddPayloadBtAddress(address));
-  CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
-  CHECK(evt_ptr->AddPayloadOctets2(kReservedZero));
-  CHECK(evt_ptr->AddPayloadOctets3(class_of_device));
-  CHECK(!(clock_offset & 0x8000));
-  CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_LOOPBACK_MODE,
+                                                        status);
+  CHECK(evt_ptr->AddPayloadOctets1(mode));
 
   return evt_ptr;
 }
 
-void EventPacket::AddInquiryResult(
-    const BtAddress& address,
-    const PageScanRepetitionMode page_scan_repetition_mode,
-    uint32_t class_of_device, uint16_t clock_offset) {
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
+std::unique_ptr<EventPacket> EventPacket::CreateInquiryResultEvent() {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_RESULT_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(0));  // Start with no responses
+  return evt_ptr;
+}
+
+bool EventPacket::AddInquiryResult(const BtAddress& address,
+                                   uint8_t page_scan_repetition_mode,
+                                   uint32_t class_of_device,
+                                   uint16_t clock_offset) {
   CHECK(GetEventCode() == HCI_INQUIRY_RESULT_EVT);
 
+  if (!CanAddPayloadOctets(14)) return false;
+
   CHECK(IncrementPayloadCounter(1));  // Increment the number of responses
 
   CHECK(AddPayloadBtAddress(address));
@@ -222,11 +257,40 @@
   CHECK(AddPayloadOctets3(class_of_device));
   CHECK(!(clock_offset & 0x8000));
   CHECK(AddPayloadOctets2(clock_offset));
+  return true;
 }
 
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
+std::unique_ptr<EventPacket> EventPacket::CreateConnectionCompleteEvent(
+    uint8_t status, uint16_t handle, const BtAddress& address,
+    uint8_t link_type, bool encryption_enabled) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_CONNECTION_COMP_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(status));
+  CHECK((handle & 0xf000) == 0);  // Handles are 12-bit values.
+  CHECK(evt_ptr->AddPayloadOctets2(handle));
+  CHECK(evt_ptr->AddPayloadBtAddress(address));
+  CHECK(evt_ptr->AddPayloadOctets1(link_type));
+  CHECK(evt_ptr->AddPayloadOctets1(encryption_enabled ? 1 : 0));
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
+std::unique_ptr<EventPacket> EventPacket::CreateLoopbackCommandEvent(
+    uint16_t opcode, const vector<uint8_t>& payload) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_LOOPBACK_COMMAND_EVT));
+  CHECK(evt_ptr->AddPayloadOctets2(opcode));
+  for (const auto& payload_byte : payload)  // Fill the packet.
+    evt_ptr->AddPayloadOctets1(payload_byte);
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
 std::unique_ptr<EventPacket> EventPacket::CreateExtendedInquiryResultEvent(
-    const BtAddress& address,
-    const PageScanRepetitionMode page_scan_repetition_mode,
+    const BtAddress& address, uint8_t page_scan_repetition_mode,
     uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
     const vector<uint8_t>& extended_inquiry_response) {
   std::unique_ptr<EventPacket> evt_ptr = std::unique_ptr<EventPacket>(
@@ -248,6 +312,75 @@
   return evt_ptr;
 }
 
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
+std::unique_ptr<EventPacket> EventPacket::CreateLeConnectionCompleteEvent(
+    uint8_t status, uint16_t handle, uint8_t role, uint8_t peer_address_type,
+    const BtAddress& peer, uint16_t interval, uint16_t latency,
+    uint16_t supervision_timeout) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_BLE_EVENT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(HCI_BLE_CONN_COMPLETE_EVT));
+  CHECK(evt_ptr->AddPayloadOctets1(status));
+  CHECK(evt_ptr->AddPayloadOctets2(handle));
+  CHECK(evt_ptr->AddPayloadOctets1(role));
+  CHECK(evt_ptr->AddPayloadOctets1(peer_address_type));
+  CHECK(evt_ptr->AddPayloadBtAddress(peer));
+  CHECK(evt_ptr->AddPayloadOctets2(interval));
+  CHECK(evt_ptr->AddPayloadOctets2(latency));
+  CHECK(evt_ptr->AddPayloadOctets2(supervision_timeout));
+  CHECK(evt_ptr->AddPayloadOctets1(
+      0x00));  // Master Clock Accuracy (unused for master)
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
+std::unique_ptr<EventPacket> EventPacket::CreateLeAdvertisingReportEvent() {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_BLE_EVENT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(HCI_BLE_ADV_PKT_RPT_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(0));  // Start with an empty report
+
+  return evt_ptr;
+}
+
+bool EventPacket::AddLeAdvertisingReport(uint8_t event_type, uint8_t addr_type,
+                                         const BtAddress& addr,
+                                         const vector<uint8_t>& data,
+                                         uint8_t rssi) {
+  if (!CanAddPayloadOctets(10 + data.size())) return false;
+
+  CHECK(GetEventCode() == HCI_BLE_EVENT);
+
+  CHECK(IncrementPayloadCounter(2));  // Increment the number of responses
+
+  CHECK(AddPayloadOctets1(event_type));
+  CHECK(AddPayloadOctets1(addr_type));
+  CHECK(AddPayloadBtAddress(addr));
+  CHECK(AddPayloadOctets1(data.size()));
+  CHECK(AddPayloadOctets(data.size(), data));
+  CHECK(AddPayloadOctets1(rssi));
+  return true;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
+std::unique_ptr<EventPacket> EventPacket::CreateLeRemoteUsedFeaturesEvent(
+    uint8_t status, uint16_t handle, uint64_t features) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_BLE_EVENT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(status));
+  CHECK(evt_ptr->AddPayloadOctets2(handle));
+  CHECK(evt_ptr->AddPayloadOctets8(features));
+
+  return evt_ptr;
+}
+
 // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
 std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeReadBufferSize(
     uint8_t status, uint16_t hc_le_data_packet_length,
diff --git a/vendor_libs/test_vendor_lib/src/hci_packet.cc b/vendor_libs/test_vendor_lib/src/hci_packet.cc
new file mode 100644
index 0000000..219c187
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/hci_packet.cc
@@ -0,0 +1,125 @@
+#include "hci_packet.h"
+
+namespace test_vendor_lib {
+
+// Iterator Functions
+Iterator::Iterator(std::shared_ptr<HciPacket> packet, size_t i) {
+  hci_packet_ = packet;
+  index_ = i;
+}
+
+Iterator::Iterator(const Iterator& itr) { *this = itr; }
+
+Iterator::operator bool() const { return hci_packet_ != nullptr; }
+
+Iterator Iterator::operator+(size_t offset) {
+  auto itr(*this);
+
+  return itr += offset;
+}
+
+Iterator& Iterator::operator+=(size_t offset) {
+  size_t new_offset = index_ + offset;
+  index_ = new_offset >= hci_packet_->get_length() ? hci_packet_->get_length()
+                                                   : new_offset;
+  return *this;
+}
+
+Iterator Iterator::operator++(int) {
+  auto itr(*this);
+  index_++;
+
+  if (index_ >= hci_packet_->get_length()) index_ = hci_packet_->get_length();
+
+  return itr;
+}
+
+Iterator& Iterator::operator++() {
+  index_++;
+
+  if (index_ >= hci_packet_->get_length()) index_ = hci_packet_->get_length();
+
+  return *this;
+}
+
+Iterator Iterator::operator-(size_t offset) {
+  auto itr(*this);
+
+  return itr -= offset;
+}
+
+int Iterator::operator-(Iterator& itr) { return index_ - itr.index_; }
+
+Iterator& Iterator::operator-=(size_t offset) {
+  index_ = offset > index_ ? 0 : index_ - offset;
+
+  return *this;
+}
+
+Iterator Iterator::operator--(int) {
+  auto itr(*this);
+  if (index_ != 0) index_--;
+
+  return itr;
+}
+
+Iterator& Iterator::operator--() {
+  if (index_ != 0) index_--;
+
+  return *this;
+}
+
+Iterator& Iterator::operator=(const Iterator& itr) {
+  hci_packet_ = itr.hci_packet_;
+  index_ = itr.index_;
+
+  return *this;
+}
+
+bool Iterator::operator==(Iterator& itr) {
+  return ((hci_packet_ == itr.hci_packet_) && (index_ == itr.index_));
+}
+
+bool Iterator::operator!=(Iterator& itr) { return !(*this == itr); }
+
+bool Iterator::operator<(Iterator& itr) {
+  return ((hci_packet_ == itr.hci_packet_) && (index_ < itr.index_));
+}
+
+bool Iterator::operator>(Iterator& itr) {
+  return ((hci_packet_ == itr.hci_packet_) && (index_ > itr.index_));
+}
+
+bool Iterator::operator<=(Iterator& itr) {
+  return ((hci_packet_ == itr.hci_packet_) && (index_ <= itr.index_));
+}
+
+bool Iterator::operator>=(Iterator& itr) {
+  return ((hci_packet_ == itr.hci_packet_) && (index_ >= itr.index_));
+}
+
+uint8_t& Iterator::operator*() const {
+  CHECK(index_ != hci_packet_->get_length());
+
+  return hci_packet_->get_at_index(index_);
+}
+
+uint8_t* Iterator::operator->() const {
+  return &hci_packet_->get_at_index(index_);
+}
+
+// BtPacket Functions
+Iterator HciPacket::get_begin() {
+  Iterator itr(shared_from_this(), 0);
+
+  return itr;
+}
+
+Iterator HciPacket::get_end() {
+  Iterator itr(shared_from_this(), get_length());
+
+  return itr;
+}
+
+uint8_t HciPacket::operator[](size_t i) { return get_at_index(i); }
+};  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/keyboard.cc b/vendor_libs/test_vendor_lib/src/keyboard.cc
new file mode 100644
index 0000000..74caf41
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/keyboard.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "keyboard"
+
+#include "keyboard.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+Keyboard::Keyboard() {
+  advertising_type_ = BTM_BLE_CONNECT_EVT;
+  adv_data_ = {0x11,  // Length
+               BTM_BLE_AD_TYPE_NAME_CMPL,
+               'g',
+               'D',
+               'e',
+               'v',
+               'i',
+               'c',
+               'e',
+               '-',
+               'k',
+               'e',
+               'y',
+               'b',
+               'o',
+               'a',
+               'r',
+               'd',
+               0x03,  // Length
+               0x19,
+               0xC1,
+               0x03,
+               0x03,  // Length
+               0x03,
+               0x12,
+               0x18,
+               0x02,  // Length
+               BTM_BLE_AD_TYPE_FLAG,
+               BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG};
+
+  scan_data_ = {0x04,  // Length
+                BTM_BLE_AD_TYPE_NAME_SHORT, 'k', 'e', 'y'};
+}
+
+std::string Keyboard::GetTypeString() const { return "keyboard"; }
+
+void Keyboard::Initialize(const vector<std::string>& args) {
+  if (args.size() < 2) return;
+
+  BtAddress addr;
+  if (addr.FromString(args[1])) SetBtAddress(addr);
+
+  if (args.size() < 3) return;
+
+  SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+bool Keyboard::LeConnect() { return true; }
+
+bool Keyboard::IsPageScanAvailable() const { return false; }
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/l2cap_packet.cc b/vendor_libs/test_vendor_lib/src/l2cap_packet.cc
index 652f3c0..ad17b48 100644
--- a/vendor_libs/test_vendor_lib/src/l2cap_packet.cc
+++ b/vendor_libs/test_vendor_lib/src/l2cap_packet.cc
@@ -1,20 +1,19 @@
-/******************************************************************************
+/*
+ * Copyright 2017 The Android Open Source Project
  *
- *  Copyright (C) 2017 Google, Inc.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *  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
  *
- *  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.
- *
- ******************************************************************************/
+ * 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.
+ */
+
 #define LOG_TAG "l2cap_packet"
 
 #include "l2cap_packet.h"
@@ -25,17 +24,18 @@
 
 namespace test_vendor_lib {
 
-const int kL2capHeaderLength = 4;
+const size_t kL2capHeaderLength = 4;
+const size_t kSduFirstHeaderLength = 8;
+const size_t kSduStandardHeaderLength = 6;
+const size_t kFcsBytes = 2;
 const uint16_t kSduTxSeqBits = 0x007E;
-const int kSduStandardHeaderLength = 6;
-const int kSduFirstHeaderLength = 8;
 const uint8_t kSduFirstReqseq = 0x40;
 const uint8_t kSduContinuationReqseq = 0xC0;
 const uint8_t kSduEndReqseq = 0x80;
 
-std::unique_ptr<L2capPacket> L2capPacket::assemble(
-    const std::vector<L2capSdu>& sdu_packets) {
-  std::unique_ptr<L2capPacket> built_l2cap_packet(new L2capPacket());
+std::shared_ptr<L2capPacket> L2capPacket::assemble(
+    const std::vector<std::shared_ptr<L2capSdu> >& sdu_packets) {
+  std::shared_ptr<L2capPacket> built_l2cap_packet(new L2capPacket());
   uint16_t l2cap_payload_length = 0;
   uint16_t first_packet_channel_id = 0;
   uint16_t total_expected_l2cap_length;
@@ -45,17 +45,18 @@
     LOG_DEBUG(LOG_TAG, "%s: No SDU received.", __func__);
     return nullptr;
   }
-  if (sdu_packets.size() == 1 && !L2capSdu::is_complete_l2cap(sdu_packets[0])) {
+  if (sdu_packets.size() == 1 &&
+      !L2capSdu::is_complete_l2cap(*sdu_packets[0])) {
     LOG_DEBUG(LOG_TAG, "%s: Unsegmented SDU has incorrect SAR bits.", __func__);
     return nullptr;
   }
 
-  first_packet_channel_id = sdu_packets[0].get_channel_id();
+  first_packet_channel_id = sdu_packets[0]->get_channel_id();
 
   built_l2cap_packet->l2cap_packet_.resize(kL2capHeaderLength);
 
   for (size_t i = 0; i < sdu_packets.size(); i++) {
-    uint16_t payload_length = sdu_packets[i].get_payload_length();
+    uint16_t payload_length = sdu_packets[i]->get_payload_length();
 
     // TODO(jruthe): Remove these checks when ACL packets have been
     // implemented. Once those are done, that will be the only way to create
@@ -64,21 +65,21 @@
     // Check the integrity of the packet length, if it is zero, it is invalid.
     // The maximum size of a single, segmented L2CAP payload is 1016 bytes.
     if ((payload_length <= 0) ||
-        (payload_length != sdu_packets[i].get_vector_size() - 4)) {
+        (payload_length != sdu_packets[i]->get_vector_size() - 4)) {
       LOG_DEBUG(LOG_TAG, "%s: SDU payload length incorrect.", __func__);
       return nullptr;
     }
 
-    uint16_t fcs_check = sdu_packets[i].get_fcs();
+    uint16_t fcs_check = sdu_packets[i]->get_fcs();
 
-    if (sdu_packets[i].calculate_fcs() != fcs_check) {
+    if (sdu_packets[i]->calculate_fcs() != fcs_check) {
       LOG_DEBUG(LOG_TAG, "%s: SDU fcs is incorrect.", __func__);
       return nullptr;
     }
 
-    uint16_t controls = sdu_packets[i].get_controls();
+    uint16_t controls = sdu_packets[i]->get_controls();
 
-    if (sdu_packets[i].get_channel_id() != first_packet_channel_id) {
+    if (sdu_packets[i]->get_channel_id() != first_packet_channel_id) {
       LOG_DEBUG(LOG_TAG, "%s: SDU CID does not match expected.", __func__);
       return nullptr;
     }
@@ -92,15 +93,15 @@
     // control bits set to 01b and the ending segment must have them set to 10b.
     // Meanwhile all segments in between the start and end must have the bits
     // set to 11b.
-    uint16_t starting_index;
+    size_t starting_index;
     uint8_t txseq = controls & kSduTxSeqBits;
     if (sdu_packets.size() > 1 && i == 0 &&
-        !L2capSdu::is_starting_sdu(sdu_packets[i])) {
+        !L2capSdu::is_starting_sdu(*sdu_packets[i])) {
       LOG_DEBUG(LOG_TAG, "%s: First segmented SDU has incorrect SAR bits.",
                 __func__);
       return nullptr;
     }
-    if (i != 0 && L2capSdu::is_starting_sdu(sdu_packets[i])) {
+    if (i != 0 && L2capSdu::is_starting_sdu(*sdu_packets[i])) {
       LOG_DEBUG(LOG_TAG,
                 "%s: SAR bits set to first segmented SDU on "
                 "non-starting SDU.",
@@ -112,7 +113,7 @@
       return nullptr;
     }
     if (sdu_packets.size() > 1 && i == sdu_packets.size() - 1 &&
-        !L2capSdu::is_ending_sdu(sdu_packets[i])) {
+        !L2capSdu::is_ending_sdu(*sdu_packets[i])) {
       LOG_DEBUG(LOG_TAG, "%s: Final segmented SDU has incorrect SAR bits.",
                 __func__);
       return nullptr;
@@ -121,9 +122,9 @@
     // Subtract the control and fcs from every SDU payload length.
     l2cap_payload_length += (payload_length - 4);
 
-    if (L2capSdu::is_starting_sdu(sdu_packets[i])) {
+    if (L2capSdu::is_starting_sdu(*sdu_packets[i])) {
       starting_index = kSduFirstHeaderLength;
-      total_expected_l2cap_length = sdu_packets[i].get_total_l2cap_length();
+      total_expected_l2cap_length = sdu_packets[i]->get_total_l2cap_length();
 
       // Subtract the additional two bytes from the first packet of a segmented
       // SDU.
@@ -132,8 +133,8 @@
       starting_index = kSduStandardHeaderLength;
     }
 
-    auto payload_begin = sdu_packets[i].get_payload_begin(starting_index);
-    auto payload_end = sdu_packets[i].get_payload_end();
+    Iterator payload_begin = sdu_packets[i]->get_begin() + starting_index;
+    Iterator payload_end = sdu_packets[i]->get_end() - kFcsBytes;
 
     built_l2cap_packet->l2cap_packet_.insert(
         built_l2cap_packet->l2cap_packet_.end(), payload_begin, payload_end);
@@ -155,41 +156,19 @@
   return built_l2cap_packet;
 }  // Assemble
 
-std::vector<uint8_t> L2capPacket::get_l2cap_payload() const {
-  std::vector<uint8_t> payload_sub_vector;
-  payload_sub_vector.clear();
-
-  auto begin_payload_iter = get_l2cap_payload_begin();
-  payload_sub_vector.insert(payload_sub_vector.end(), begin_payload_iter,
-                            l2cap_packet_.end());
-
-  return payload_sub_vector;
-}
-
 uint16_t L2capPacket::get_l2cap_cid() const {
   return ((l2cap_packet_[3] << 8) | l2cap_packet_[2]);
 }
 
-std::vector<uint8_t>::const_iterator L2capPacket::get_l2cap_payload_begin()
-    const {
-  return std::next(l2cap_packet_.begin(), kSduHeaderLength);
-}
-
-std::vector<uint8_t>::const_iterator L2capPacket::get_l2cap_payload_end()
-    const {
-  return l2cap_packet_.end();
-}
-
-std::vector<L2capSdu> L2capPacket::fragment(uint16_t maximum_sdu_size,
-                                            uint8_t txseq,
-                                            uint8_t reqseq) const {
-  std::vector<L2capSdu> sdu;
+std::vector<std::shared_ptr<L2capSdu> > L2capPacket::fragment(
+    uint16_t maximum_sdu_size, uint8_t txseq, uint8_t reqseq) {
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
   if (!check_l2cap_packet()) return sdu;
 
   std::vector<uint8_t> current_sdu;
 
-  auto current_iter = get_l2cap_payload_begin();
-  auto end_iter = get_l2cap_payload_end();
+  Iterator current_iter = get_begin() + kL2capHeaderLength;
+  Iterator end_iter = get_end();
 
   size_t number_of_packets = ceil((l2cap_packet_.size() - kL2capHeaderLength) /
                                   static_cast<float>(maximum_sdu_size));
@@ -230,8 +209,8 @@
     return sdu;
   }
 
-  auto next_iter =
-      std::next(current_iter, maximum_sdu_size - (kSduFirstHeaderLength + 2));
+  Iterator next_iter =
+      current_iter + (maximum_sdu_size - (kSduFirstHeaderLength + 2));
 
   sdu.reserve(number_of_packets);
   sdu.clear();
@@ -269,15 +248,9 @@
     if (txseq > 0x3F) txseq = 0x00;
 
     current_sdu.insert(current_sdu.end(), current_iter, next_iter);
-
     current_iter = next_iter;
 
-    next_iter =
-        std::next(current_iter, maximum_sdu_size - kSduFirstHeaderLength);
-
-    if (next_iter > end_iter) {
-      next_iter = end_iter;
-    }
+    next_iter = current_iter + (maximum_sdu_size - kSduFirstHeaderLength);
 
     sdu.push_back(L2capSdu::L2capSduBuilder(std::move(current_sdu)));
   }
@@ -317,4 +290,11 @@
   return true;
 }
 
+// HciPacket Functions
+size_t L2capPacket::get_length() { return l2cap_packet_.size(); }
+
+uint8_t& L2capPacket::get_at_index(size_t index) {
+  return l2cap_packet_[index];
+}
+
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc b/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc
index e44d241..a93c1ad 100644
--- a/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc
+++ b/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc
@@ -1,20 +1,19 @@
-/******************************************************************************
+/*
+ * Copyright 2017 The Android Open Source Project
  *
- *  Copyright (C) 2017 Google, Inc.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *  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
  *
- *  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.
- *
- ******************************************************************************/
+ * 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 "l2cap_sdu.h"
 
 #include <base/logging.h>
@@ -57,11 +56,19 @@
     0x4100, 0x81c1, 0x8081, 0x4040,
 };  // lfsr_table
 
-L2capSdu::L2capSdu(std::vector<uint8_t> create_from) {
-  sdu_data_ = std::move(create_from);
+L2capSdu::L2capSdu(std::vector<uint8_t>&& create_from) {
+  sdu_data_ = create_from;
 }
 
-L2capSdu L2capSdu::L2capSduBuilder(std::vector<uint8_t> create_from) {
+std::shared_ptr<L2capSdu> L2capSdu::L2capSduConstructor(
+    std::vector<uint8_t> create_from) {
+  L2capSdu packet(std::move(create_from));
+
+  return std::make_shared<L2capSdu>(packet);
+}
+
+std::shared_ptr<L2capSdu> L2capSdu::L2capSduBuilder(
+    std::vector<uint8_t> create_from) {
   L2capSdu packet(std::move(create_from));
 
   packet.sdu_data_.resize(packet.sdu_data_.size() + 2, 0x00);
@@ -71,16 +78,7 @@
   packet.sdu_data_[packet.sdu_data_.size() - 2] = fcs & 0xFF;
   packet.sdu_data_[packet.sdu_data_.size() - 1] = (fcs & 0xFF00) >> 8;
 
-  return packet;
-}
-
-std::vector<uint8_t>::const_iterator L2capSdu::get_payload_begin(
-    const unsigned int offset) const {
-  return std::next(sdu_data_.begin(), offset);
-}
-
-std::vector<uint8_t>::const_iterator L2capSdu::get_payload_end() const {
-  return std::prev(sdu_data_.end(), 2);
+  return std::make_shared<L2capSdu>(packet);
 }
 
 uint16_t L2capSdu::convert_from_little_endian(
@@ -144,4 +142,8 @@
   return (sar_bits == 0x8000);
 }
 
+// HciPacket functions.
+size_t L2capSdu::get_length() { return sdu_data_.size(); }
+uint8_t& L2capSdu::get_at_index(size_t index) { return sdu_data_[index]; }
+
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/packet.cc b/vendor_libs/test_vendor_lib/src/packet.cc
index a622a5f..49f7272 100644
--- a/vendor_libs/test_vendor_lib/src/packet.cc
+++ b/vendor_libs/test_vendor_lib/src/packet.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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.
+ */
 
 #define LOG_TAG "packet"
 
@@ -33,7 +33,7 @@
 }
 
 bool Packet::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
-  if (octets + payload_.size() > kMaxPacketOctets) return false;
+  if (GetPayloadSize() + octets > kMaxPayloadOctets) return false;
 
   if (octets != bytes.size()) return false;
 
@@ -61,7 +61,7 @@
 }
 
 bool Packet::AddPayloadBtAddress(const BtAddress& address) {
-  if (BtAddress::kOctets + payload_.size() > kMaxPacketOctets) return false;
+  if (GetPayloadSize() + BtAddress::kOctets > kMaxPayloadOctets) return false;
 
   address.ToVector(payload_);
 
diff --git a/vendor_libs/test_vendor_lib/src/sco_packet.cc b/vendor_libs/test_vendor_lib/src/sco_packet.cc
new file mode 100644
index 0000000..465d8ff
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/src/sco_packet.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#define LOG_TAG "sco_packet"
+
+#include "sco_packet.h"
+
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+ScoPacket::ScoPacket(uint16_t channel,
+                     ScoPacket::PacketStatusFlags packet_status)
+    : Packet(DATA_TYPE_SCO,
+             {static_cast<uint8_t>(channel & 0xff),
+              static_cast<uint8_t>(((channel >> 8) & 0x0f) |
+                                   (packet_status & 0x3 << 4))}) {}
+
+uint16_t ScoPacket::GetChannel() const {
+  return (GetHeader()[0] | (GetHeader()[1] << 8)) & 0xfff;
+}
+
+ScoPacket::PacketStatusFlags ScoPacket::GetPacketStatusFlags() const {
+  return static_cast<ScoPacket::PacketStatusFlags>((GetHeader()[1] >> 4) & 0x3);
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/test_channel_transport.cc b/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
index adb3f7b..0d9bc2e 100644
--- a/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
+++ b/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2015 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.
-//
+/*
+ * Copyright 2015 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.
+ */
 
 #define LOG_TAG "test_channel_transport"
 
@@ -77,9 +77,10 @@
   socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
   memset(&test_channel_address, 0, sockaddr_in_size);
 
-  OSI_NO_INTR(accept_fd = accept(listen_fd_, reinterpret_cast<sockaddr*>(
-                                                 &test_channel_address),
-                                 &sockaddr_in_size));
+  OSI_NO_INTR(accept_fd =
+                  accept(listen_fd_,
+                         reinterpret_cast<sockaddr*>(&test_channel_address),
+                         &sockaddr_in_size));
   if (accept_fd < 0) {
     LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).",
              errno, strerror(errno));
@@ -139,4 +140,4 @@
   command_handler_ = callback;
 }
 
-}  // namespace test_vendor_lib {
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc b/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
index 816a19b..97b7331 100644
--- a/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
@@ -1,18 +1,18 @@
-//
-// Copyright 2016 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.
-//
+/*
+ * Copyright 2016 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 "async_manager.h"
 #include <gtest/gtest.h>
diff --git a/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc b/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
index d998179..0cf3760 100644
--- a/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2016 Google, Inc.
+ *  Copyright 2016 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
 const std::string kZeros = "00:00:00:00:00:00";
 const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
-}
+}  // namespace
 
 namespace test_vendor_lib {
 
diff --git a/vendor_libs/test_vendor_lib/test/iterator_test.cc b/vendor_libs/test_vendor_lib/test/iterator_test.cc
new file mode 100644
index 0000000..92a6d70
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/test/iterator_test.cc
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2017 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_packet.h"
+#include "l2cap_test_packets.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+using std::unique_ptr;
+using std::vector;
+namespace test_vendor_lib {
+
+class TestPacket : public HciPacket {
+ public:
+  static std::shared_ptr<TestPacket> make_new_packet(vector<uint8_t> v) {
+    return std::shared_ptr<TestPacket>(new TestPacket(v));
+  }
+  size_t get_length() { return test_vector_.size(); }
+  uint8_t& get_at_index(size_t index) { return test_vector_[index]; }
+
+ private:
+  TestPacket(vector<uint8_t> v) { test_vector_ = v; }
+  vector<uint8_t> test_vector_;
+};
+
+class IteratorTest : public ::testing::Test {
+ public:
+  IteratorTest() = default;
+  ~IteratorTest() = default;
+
+  void SetUp() { packet = TestPacket::make_new_packet(complete_l2cap_packet); }
+
+  void TearDown() { packet.reset(); }
+
+  std::shared_ptr<TestPacket> packet;
+};
+
+TEST_F(IteratorTest, extractTest) {
+  Iterator general_case = packet->get_begin();
+
+  ASSERT_EQ(0x95, general_case.extract<uint8_t>());
+  ASSERT_EQ(0x471f, general_case.extract<uint16_t>());
+  ASSERT_EQ(0x951f0200u, general_case.extract<uint32_t>());
+  ASSERT_EQ(0x33000101000000cbu, general_case.extract<uint64_t>());
+}
+
+TEST_F(IteratorTest, extractBoundsDeathTest) {
+  Iterator bounds_test = packet->get_end();
+
+  ASSERT_DEATH(bounds_test.extract<uint8_t>(), "");
+  ASSERT_DEATH(bounds_test.extract<uint16_t>(), "");
+  ASSERT_DEATH(bounds_test.extract<uint32_t>(), "");
+  ASSERT_DEATH(bounds_test.extract<uint64_t>(), "");
+}
+
+TEST_F(IteratorTest, dereferenceDeathTest) {
+  Iterator dereference_test = packet->get_end();
+
+  ASSERT_EQ(0x45, *(dereference_test - static_cast<size_t>(1)));
+  ASSERT_DEATH(*dereference_test, "");
+}
+TEST_F(IteratorTest, plusEqTest) {
+  Iterator plus_eq = packet->get_begin();
+  for (size_t i = 0; i < complete_l2cap_packet.size(); i += 2) {
+    ASSERT_EQ(complete_l2cap_packet[i], *plus_eq)
+        << "+= test: Dereferenced iterator does not equal expected at index "
+        << i;
+    plus_eq += 2;
+  }
+}
+
+TEST_F(IteratorTest, preIncrementTest) {
+  Iterator plus_plus = packet->get_begin();
+  for (size_t i = 0; i < complete_l2cap_packet.size() - 1; i++) {
+    ASSERT_EQ(complete_l2cap_packet[i + 1], *(++plus_plus))
+        << "Pre-increment test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_F(IteratorTest, postIncrementTest) {
+  Iterator plus_plus = packet->get_begin();
+  for (size_t i = 0; i < complete_l2cap_packet.size(); i++) {
+    ASSERT_EQ(complete_l2cap_packet[i], *(plus_plus++))
+        << "Post-increment test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_F(IteratorTest, additionTest) {
+  Iterator plus = packet->get_begin();
+  for (size_t i = 0; i < complete_l2cap_packet.size(); i++) {
+    ASSERT_EQ(complete_l2cap_packet[i], *plus)
+        << "+ test: Dereferenced iterator does not equal expected at index "
+        << i;
+    plus = plus + static_cast<size_t>(1);
+  }
+}
+
+TEST_F(IteratorTest, minusEqTest) {
+  Iterator minus_eq = packet->get_end();
+  minus_eq -= 1;
+  for (size_t i = complete_l2cap_packet.size() - 1; i > 0; i -= 2) {
+    ASSERT_EQ(complete_l2cap_packet[i], *minus_eq)
+        << "-= test: Dereferenced iterator does not equal expected at index "
+        << i;
+    minus_eq -= 2;
+  }
+}
+
+TEST_F(IteratorTest, preDecrementTest) {
+  Iterator minus_minus = packet->get_end();
+  for (size_t i = complete_l2cap_packet.size(); i > 0; i--) {
+    ASSERT_EQ(complete_l2cap_packet[i - 1], *(--minus_minus))
+        << "Pre-decrement test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_F(IteratorTest, postDecrementTest) {
+  Iterator minus_minus = packet->get_end();
+  minus_minus--;
+  for (size_t i = complete_l2cap_packet.size() - 1; i > 0; i--) {
+    ASSERT_EQ(complete_l2cap_packet[i], *(minus_minus--))
+        << "Post-decrement test: Dereferenced iterator does not equal expected "
+        << "at index " << i;
+  }
+}
+
+TEST_F(IteratorTest, subtractionTest) {
+  Iterator minus = packet->get_end();
+  minus = minus - static_cast<size_t>(1);
+  for (size_t i = complete_l2cap_packet.size() - 1; i > 0; i--) {
+    ASSERT_EQ(complete_l2cap_packet[i], *minus)
+        << "- test: Dereferenced iterator does not equal expected at index "
+        << i;
+    minus = minus - static_cast<size_t>(1);
+  }
+}
+
+TEST_F(IteratorTest, plusEqBoundsTest) {
+  Iterator plus_eq = packet->get_end();
+  plus_eq--;
+  for (size_t i = 0; i < 100; i++) {
+    plus_eq += i;
+    ASSERT_EQ(packet->get_end(), plus_eq)
+        << "+= test: Iterator exceeded the upper bound set by get_length()";
+  }
+}
+
+TEST_F(IteratorTest, preIncrementBoundsTest) {
+  Iterator plus_plus = packet->get_end();
+  plus_plus--;
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(packet->get_end(), ++plus_plus)
+        << "Pre-increment test: Iterator exceeded the upper bound set "
+           "by get_length()";
+  }
+}
+
+TEST_F(IteratorTest, postIncrementBoundsTest) {
+  Iterator plus_plus = packet->get_end();
+  plus_plus--;
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(packet->get_end(), plus_plus++)
+        << "Post-increment test: Iterator exceeded the upper bound set "
+           "by get_length()";
+  }
+}
+
+TEST_F(IteratorTest, additionBoundsTest) {
+  Iterator plus = packet->get_end();
+  plus--;
+  for (size_t i = 0; i < 100; i++) {
+    plus = plus + static_cast<size_t>(i);
+    ASSERT_EQ(packet->get_end(), plus)
+        << "+ test: Iterator exceeded the upper bound set by get_length()";
+  }
+}
+
+TEST_F(IteratorTest, minusEqBoundsTest) {
+  Iterator minus_eq = packet->get_begin();
+  for (size_t i = 0; i < 100; i++) {
+    minus_eq -= i;
+    ASSERT_EQ(complete_l2cap_packet[0], *minus_eq)
+        << "-= test: Iterator is less than the lower bound set by "
+           "packet->get_begin()";
+  }
+}
+
+TEST_F(IteratorTest, preDecrementBoundsTest) {
+  Iterator minus_minus = packet->get_begin();
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(complete_l2cap_packet[0], *(--minus_minus))
+        << "Pre-decrement test: Iterator is less than the lower bound set by "
+           "packet->get_begin()";
+  }
+}
+
+TEST_F(IteratorTest, postDecrementBoundsTest) {
+  Iterator minus_minus = packet->get_begin();
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(complete_l2cap_packet[0], *(minus_minus--))
+        << "Post-decrement test: Iterator is less than the lower bound set by "
+           "packet->get_begin()";
+  }
+}
+
+TEST_F(IteratorTest, subtractionBoundsTest) {
+  Iterator minus = packet->get_begin();
+  for (size_t i = 0; i < 100; i++) {
+    minus = minus - static_cast<size_t>(i);
+    ASSERT_EQ(complete_l2cap_packet[0], *minus)
+        << "- test: Iterator is less than the lower bound set "
+           "by packet->get_begin()";
+  }
+}
+};  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc b/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
index 7d63f45..2e6df2c 100644
--- a/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
+++ b/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
@@ -1,36 +1,48 @@
-/******************************************************************************
+/*
+ * Copyright 2017 The Android Open Source Project
  *
- *  Copyright (C) 2017 Google, Inc.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *  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
  *
- *  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.
- *
- ******************************************************************************/
+ * 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 "l2cap_sdu.h"
+
 #include <gtest/gtest.h>
+#include <memory>
+
 #include "l2cap_test_packets.h"
+
 using std::vector;
 
 namespace test_vendor_lib {
 
-L2capSdu packet_1(l2cap_test_packet_1);
-L2capSdu packet_2(l2cap_test_packet_2);
-L2capSdu packet_3(l2cap_test_packet_3);
-L2capSdu packet_4(l2cap_test_packet_4);
-L2capSdu packet_5(l2cap_test_packet_5);
-L2capSdu packet_6(l2cap_test_packet_6);
-L2capSdu packet_7(l2cap_test_packet_7);
-L2capSdu packet_8(l2cap_test_packet_8);
-L2capSdu packet_9(l2cap_test_packet_9);
+std::shared_ptr<L2capSdu> packet_1 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_1);
+std::shared_ptr<L2capSdu> packet_2 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_2);
+std::shared_ptr<L2capSdu> packet_3 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_3);
+std::shared_ptr<L2capSdu> packet_4 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_4);
+std::shared_ptr<L2capSdu> packet_5 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_5);
+std::shared_ptr<L2capSdu> packet_6 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_6);
+std::shared_ptr<L2capSdu> packet_7 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_7);
+std::shared_ptr<L2capSdu> packet_8 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_8);
+std::shared_ptr<L2capSdu> packet_9 =
+    L2capSdu::L2capSduConstructor(l2cap_test_packet_9);
 
 class L2capSduTest : public ::testing::Test {
  public:
@@ -41,79 +53,79 @@
 };  // L2capSduTest
 
 TEST_F(L2capSduTest, getFcsTest) {
-  EXPECT_EQ(0x72aa, packet_1.get_fcs());
-  EXPECT_EQ(0x5b57, packet_2.get_fcs());
-  EXPECT_EQ(0xe644, packet_3.get_fcs());
-  EXPECT_EQ(0x21b0, packet_4.get_fcs());
-  EXPECT_EQ(0xae96, packet_5.get_fcs());
-  EXPECT_EQ(0x9254, packet_6.get_fcs());
-  EXPECT_EQ(0xf6fa, packet_7.get_fcs());
-  EXPECT_EQ(0x1da4, packet_8.get_fcs());
-  EXPECT_EQ(0x781a, packet_9.get_fcs());
+  EXPECT_EQ(0x72aa, packet_1->get_fcs());
+  EXPECT_EQ(0x5b57, packet_2->get_fcs());
+  EXPECT_EQ(0xe644, packet_3->get_fcs());
+  EXPECT_EQ(0x21b0, packet_4->get_fcs());
+  EXPECT_EQ(0xae96, packet_5->get_fcs());
+  EXPECT_EQ(0x9254, packet_6->get_fcs());
+  EXPECT_EQ(0xf6fa, packet_7->get_fcs());
+  EXPECT_EQ(0x1da4, packet_8->get_fcs());
+  EXPECT_EQ(0x781a, packet_9->get_fcs());
 }
 
 TEST_F(L2capSduTest, getPayloadLengthTest) {
-  EXPECT_EQ(l2cap_test_packet_1.size() - 4, packet_1.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_2.size() - 4, packet_2.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_3.size() - 4, packet_3.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_4.size() - 4, packet_4.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_5.size() - 4, packet_5.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_6.size() - 4, packet_6.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_7.size() - 4, packet_7.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_8.size() - 4, packet_8.get_payload_length());
-  EXPECT_EQ(l2cap_test_packet_9.size() - 4, packet_9.get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_1.size() - 4, packet_1->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_2.size() - 4, packet_2->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_3.size() - 4, packet_3->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_4.size() - 4, packet_4->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_5.size() - 4, packet_5->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_6.size() - 4, packet_6->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_7.size() - 4, packet_7->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_8.size() - 4, packet_8->get_payload_length());
+  EXPECT_EQ(l2cap_test_packet_9.size() - 4, packet_9->get_payload_length());
 }
 
 TEST_F(L2capSduTest, calculateFcsTest) {
-  EXPECT_EQ(0x72aa, packet_1.calculate_fcs());
-  EXPECT_EQ(0x5b57, packet_2.calculate_fcs());
-  EXPECT_EQ(0xe644, packet_3.calculate_fcs());
-  EXPECT_EQ(0x21b0, packet_4.calculate_fcs());
-  EXPECT_EQ(0xae96, packet_5.calculate_fcs());
-  EXPECT_EQ(0x9254, packet_6.calculate_fcs());
-  EXPECT_EQ(0xf6fa, packet_7.calculate_fcs());
-  EXPECT_EQ(0x1da4, packet_8.calculate_fcs());
-  EXPECT_EQ(0x781a, packet_9.calculate_fcs());
+  EXPECT_EQ(0x72aa, packet_1->calculate_fcs());
+  EXPECT_EQ(0x5b57, packet_2->calculate_fcs());
+  EXPECT_EQ(0xe644, packet_3->calculate_fcs());
+  EXPECT_EQ(0x21b0, packet_4->calculate_fcs());
+  EXPECT_EQ(0xae96, packet_5->calculate_fcs());
+  EXPECT_EQ(0x9254, packet_6->calculate_fcs());
+  EXPECT_EQ(0xf6fa, packet_7->calculate_fcs());
+  EXPECT_EQ(0x1da4, packet_8->calculate_fcs());
+  EXPECT_EQ(0x781a, packet_9->calculate_fcs());
 }
 
 TEST_F(L2capSduTest, getControlsTest) {
-  EXPECT_EQ(0x4102, packet_1.get_controls());
-  EXPECT_EQ(0xc104, packet_2.get_controls());
-  EXPECT_EQ(0xc106, packet_3.get_controls());
-  EXPECT_EQ(0xc108, packet_4.get_controls());
-  EXPECT_EQ(0xc10a, packet_5.get_controls());
-  EXPECT_EQ(0xc10c, packet_6.get_controls());
-  EXPECT_EQ(0xc10e, packet_7.get_controls());
-  EXPECT_EQ(0xc110, packet_8.get_controls());
-  EXPECT_EQ(0x8112, packet_9.get_controls());
+  EXPECT_EQ(0x4102, packet_1->get_controls());
+  EXPECT_EQ(0xc104, packet_2->get_controls());
+  EXPECT_EQ(0xc106, packet_3->get_controls());
+  EXPECT_EQ(0xc108, packet_4->get_controls());
+  EXPECT_EQ(0xc10a, packet_5->get_controls());
+  EXPECT_EQ(0xc10c, packet_6->get_controls());
+  EXPECT_EQ(0xc10e, packet_7->get_controls());
+  EXPECT_EQ(0xc110, packet_8->get_controls());
+  EXPECT_EQ(0x8112, packet_9->get_controls());
 }
 
 TEST_F(L2capSduTest, getTotalLengthTest) {
-  EXPECT_EQ(0x1f95, packet_1.get_total_l2cap_length());
+  EXPECT_EQ(0x1f95, packet_1->get_total_l2cap_length());
 }
 
 TEST_F(L2capSduTest, getVectorSizeTest) {
-  EXPECT_EQ(l2cap_test_packet_1.size(), packet_1.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_2.size(), packet_2.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_3.size(), packet_3.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_4.size(), packet_4.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_5.size(), packet_5.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_6.size(), packet_6.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_7.size(), packet_7.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_8.size(), packet_8.get_vector_size());
-  EXPECT_EQ(l2cap_test_packet_9.size(), packet_9.get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_1.size(), packet_1->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_2.size(), packet_2->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_3.size(), packet_3->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_4.size(), packet_4->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_5.size(), packet_5->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_6.size(), packet_6->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_7.size(), packet_7->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_8.size(), packet_8->get_vector_size());
+  EXPECT_EQ(l2cap_test_packet_9.size(), packet_9->get_vector_size());
 }
 
 TEST_F(L2capSduTest, getCidTest) {
-  EXPECT_EQ(0x0047, packet_1.get_channel_id());
-  EXPECT_EQ(0x0047, packet_2.get_channel_id());
-  EXPECT_EQ(0x0047, packet_3.get_channel_id());
-  EXPECT_EQ(0x0047, packet_4.get_channel_id());
-  EXPECT_EQ(0x0047, packet_5.get_channel_id());
-  EXPECT_EQ(0x0047, packet_6.get_channel_id());
-  EXPECT_EQ(0x0047, packet_7.get_channel_id());
-  EXPECT_EQ(0x0047, packet_8.get_channel_id());
-  EXPECT_EQ(0x0047, packet_9.get_channel_id());
+  EXPECT_EQ(0x0047, packet_1->get_channel_id());
+  EXPECT_EQ(0x0047, packet_2->get_channel_id());
+  EXPECT_EQ(0x0047, packet_3->get_channel_id());
+  EXPECT_EQ(0x0047, packet_4->get_channel_id());
+  EXPECT_EQ(0x0047, packet_5->get_channel_id());
+  EXPECT_EQ(0x0047, packet_6->get_channel_id());
+  EXPECT_EQ(0x0047, packet_7->get_channel_id());
+  EXPECT_EQ(0x0047, packet_8->get_channel_id());
+  EXPECT_EQ(0x0047, packet_9->get_channel_id());
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/l2cap_test.cc b/vendor_libs/test_vendor_lib/test/l2cap_test.cc
index d35e78f..f4eea71 100644
--- a/vendor_libs/test_vendor_lib/test/l2cap_test.cc
+++ b/vendor_libs/test_vendor_lib/test/l2cap_test.cc
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2017 Google, Inc.
+ *  Copyright 2017 Google, Inc.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,109 +16,113 @@
  *
  ******************************************************************************/
 
+#include "hci_packet.h"
 #include "l2cap_packet.h"
 #include "l2cap_test_packets.h"
 
 #include <gtest/gtest.h>
 #include <memory>
 
-using std::unique_ptr;
+using std::shared_ptr;
 using std::vector;
 
 namespace test_vendor_lib {
 
+class TestPacket : public HciPacket {
+ public:
+  TestPacket(const std::vector<uint8_t>& packet) { complete_packet_ = packet; }
+  TestPacket() = default;
+
+ private:
+  std::vector<uint8_t> complete_packet_;
+  size_t get_length() { return complete_packet_.size(); }
+  uint8_t& get_at_index(size_t index) { return complete_packet_[index]; }
+};
+
 class L2capTest : public ::testing::Test {
  public:
-  L2capTest() {}
-
-  void compare_packets(vector<uint8_t>& complete_packet,
-                       vector<uint8_t>& assembled_packet) {
-    ASSERT_EQ(complete_packet.size() - 4, assembled_packet.size());
-
-    for (size_t i = 0; i < assembled_packet.size(); i++) {
-      ASSERT_EQ(complete_packet[i + 4], assembled_packet[i]);
-    }
-  }
-
-  L2capSdu update_fcs(vector<uint8_t> sdu) {
+  std::shared_ptr<L2capSdu> update_fcs(vector<uint8_t> sdu) {
     sdu.resize(sdu.size() - 2);
 
     return L2capSdu::L2capSduBuilder(sdu);
   }
 
-  void compare_fragmented_packets(vector<uint8_t>& expected,
-                                  vector<uint8_t>& received) {
-    ASSERT_EQ(expected.size(), received.size());
+  void compare_packets(shared_ptr<HciPacket> expected,
+                       shared_ptr<HciPacket> received) {
+    Iterator expected_begin = expected->get_begin();
+    Iterator expected_end = expected->get_end();
 
-    for (size_t i = 0; i < expected.size(); i++) {
-      ASSERT_EQ(expected[i], received[i]);
+    Iterator received_begin = received->get_begin();
+    Iterator received_end = received->get_end();
+
+    ASSERT_EQ(expected_end - expected_begin, received_end - received_begin);
+
+    while (expected_begin < expected_end) {
+      ASSERT_EQ(*expected_begin, *received_begin);
+      expected_begin++;
+      received_begin++;
     }
   }
-
-  ~L2capTest() = default;
 };
 
 TEST_F(L2capTest, assembleGoodPackets) {
-  vector<L2capSdu> test_packet;
-  vector<uint8_t> assembled_payload;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 1: Pass correct packets.
-  test_packet.push_back(L2capSdu(good_sdu[0]));
-  test_packet.push_back(L2capSdu(good_sdu[1]));
-  test_packet.push_back(L2capSdu(good_sdu[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
-  unique_ptr<L2capPacket> test_1 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_1 = L2capPacket::assemble(test_packet);
   ASSERT_NE(test_1, nullptr);
 
-  assembled_payload = test_1->get_l2cap_payload();
+  shared_ptr<TestPacket> expected(new TestPacket(good_l2cap_packet));
 
-  compare_packets(good_l2cap_packet, assembled_payload);
+  compare_packets(expected, test_1);
 
-  assembled_payload.clear();
   test_packet.clear();
 
-  test_packet.push_back(L2capSdu(l2cap_test_packet_1));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_2));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_3));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_4));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_5));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_6));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_7));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_8));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_9));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   test_1 = L2capPacket::assemble(test_packet);
   ASSERT_NE(test_1, nullptr);
 
-  assembled_payload = test_1->get_l2cap_payload();
-  compare_packets(complete_l2cap_packet, assembled_payload);
+  expected.reset(new TestPacket(complete_l2cap_packet));
+  compare_packets(expected, test_1);
 
-  assembled_payload.clear();
   test_packet.clear();
 }
 
 TEST_F(L2capTest, assembleOutofOrderPackets) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 2: Pass out of order packets.
-  test_packet.push_back(L2capSdu(good_sdu[1]));
-  test_packet.push_back(L2capSdu(good_sdu[0]));
-  test_packet.push_back(L2capSdu(good_sdu[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
-  unique_ptr<L2capPacket> test_2 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_2 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_2, nullptr);
 
   test_packet.clear();
 
-  test_packet.push_back(L2capSdu(l2cap_test_packet_1));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_3));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_2));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_6));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_5));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_4));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_8));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_7));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_9));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   test_2 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_2, nullptr);
@@ -127,25 +131,25 @@
 }
 
 TEST_F(L2capTest, assembleBadControlBytes) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 3: Pass packets missing the finished control bytes.
-  test_packet.push_back(L2capSdu(good_sdu[0]));
-  test_packet.push_back(L2capSdu(good_sdu[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
 
-  unique_ptr<L2capPacket> test_3 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_3 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_3, nullptr);
 
   test_packet.clear();
 
-  test_packet.push_back(L2capSdu(l2cap_test_packet_1));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_2));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_3));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_4));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_5));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_6));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_7));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_8));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
 
   test_3 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_3, nullptr);
@@ -154,31 +158,31 @@
 }
 
 TEST_F(L2capTest, assembleBadFCS) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 4: Pass packets with incorrect frame check sequences.
-  test_packet.push_back(L2capSdu(good_sdu[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
   good_sdu[1][good_sdu[1].size() - 1]++;
-  test_packet.push_back(L2capSdu(good_sdu[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
   good_sdu[1][good_sdu[1].size() - 1]--;
-  test_packet.push_back(L2capSdu(good_sdu[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
-  unique_ptr<L2capPacket> test_4 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_4 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_4, nullptr);
 
   test_packet.clear();
 
-  test_packet.push_back(L2capSdu(l2cap_test_packet_1));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_2));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_3));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_4));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
   l2cap_test_packet_5[l2cap_test_packet_5.size() - 1]++;
-  test_packet.push_back(L2capSdu(l2cap_test_packet_5));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
   l2cap_test_packet_5[l2cap_test_packet_5.size() - 1]--;
-  test_packet.push_back(L2capSdu(l2cap_test_packet_6));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_7));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_8));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_9));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   test_4 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_4, nullptr);
@@ -187,68 +191,65 @@
 }
 
 TEST_F(L2capTest, assembleEmptyPayload) {
-  vector<L2capSdu> test_packet;
-  vector<uint8_t> assembled_payload;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 5: Pass a packet with an empty payload.
-  test_packet.push_back(L2capSdu(empty_sdu_payload[0]));
-  test_packet.push_back(L2capSdu(empty_sdu_payload[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(empty_sdu_payload[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(empty_sdu_payload[1]));
 
-  unique_ptr<L2capPacket> test_5 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_5 = L2capPacket::assemble(test_packet);
   ASSERT_NE(test_5, nullptr);
 
-  EXPECT_EQ(test_5->get_l2cap_cid(), 0x0047);
-  assembled_payload = test_5->get_l2cap_payload();
-  compare_packets(empty_l2cap_payload, assembled_payload);
+  shared_ptr<TestPacket> expected(new TestPacket(empty_l2cap_payload));
+  compare_packets(expected, test_5);
 
-  assembled_payload.clear();
   test_packet.clear();
 }
 
 TEST_F(L2capTest, assembleAllStartingControlError) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 6: Pass a SDU with all the control bytes set to as the starting bytes.
-  test_packet.push_back(L2capSdu(all_first_packet[0]));
-  test_packet.push_back(L2capSdu(all_first_packet[1]));
-  test_packet.push_back(L2capSdu(all_first_packet[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(all_first_packet[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(all_first_packet[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(all_first_packet[2]));
 
-  unique_ptr<L2capPacket> test_6 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_6 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_6, nullptr);
 
   test_packet.clear();
 }
 
 TEST_F(L2capTest, assembleBadCID) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 7: Pass SDUs with mixed channel ids.
-  test_packet.push_back(L2capSdu(good_sdu[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
   good_sdu[1][2]++;
   test_packet.push_back(update_fcs(good_sdu[1]));
   good_sdu[1][2]--;
-  test_packet.push_back(L2capSdu(good_sdu[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
-  unique_ptr<L2capPacket> test_7 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_7 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_7, nullptr);
 
   test_packet.clear();
 
-  test_packet.push_back(L2capSdu(l2cap_test_packet_1));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
   l2cap_test_packet_2[2]++;
-  test_packet.push_back(update_fcs(l2cap_test_packet_2));
+  test_packet.push_back((update_fcs(l2cap_test_packet_2)));
   l2cap_test_packet_2[2]--;
-  test_packet.push_back(L2capSdu(l2cap_test_packet_3));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_4));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
   l2cap_test_packet_5[2]++;
-  test_packet.push_back(update_fcs(l2cap_test_packet_5));
+  test_packet.push_back((update_fcs(l2cap_test_packet_5)));
   l2cap_test_packet_5[2]--;
-  test_packet.push_back(L2capSdu(l2cap_test_packet_6));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_7));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
   l2cap_test_packet_8[2]--;
-  test_packet.push_back(update_fcs(l2cap_test_packet_8));
+  test_packet.push_back((update_fcs(l2cap_test_packet_8)));
   l2cap_test_packet_8[2]++;
-  test_packet.push_back(L2capSdu(l2cap_test_packet_9));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   test_7 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_7, nullptr);
@@ -257,59 +258,59 @@
 }
 
 TEST_F(L2capTest, assembleUnsegmentedSDU) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 8: Pass a complete l2cap packet.
-  test_packet.push_back(L2capSdu(one_sdu[0]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(one_sdu[0]));
 
-  unique_ptr<L2capPacket> test_8 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_8 = L2capPacket::assemble(test_packet);
   EXPECT_NE(test_8, nullptr);
 
   test_packet.clear();
 }
 
 TEST_F(L2capTest, assembleBadTxSeq) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 9: Pass SDUs with incorrect TxSeq.
   good_sdu[0][4] += 4;
-  test_packet.push_back(update_fcs(good_sdu[0]));
+  test_packet.push_back((update_fcs(good_sdu[0])));
   good_sdu[0][4] -= 4;
-  test_packet.push_back(L2capSdu(good_sdu[1]));
-  test_packet.push_back(L2capSdu(good_sdu[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
-  unique_ptr<L2capPacket> test_9 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_9 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_9, nullptr);
 
   test_packet.clear();
 }
 
 TEST_F(L2capTest, assembleBadTotalSDULength) {
-  vector<L2capSdu> test_packet;
+  vector<std::shared_ptr<L2capSdu> > test_packet;
 
   // Test 10: Pass SDUs with an incorrect total SDU length
   good_sdu[0][7]++;
-  test_packet.push_back(update_fcs(good_sdu[0]));
+  test_packet.push_back((update_fcs(good_sdu[0])));
   good_sdu[0][7]--;
-  test_packet.push_back(L2capSdu(good_sdu[1]));
-  test_packet.push_back(L2capSdu(good_sdu[2]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
-  unique_ptr<L2capPacket> test_10 = L2capPacket::assemble(test_packet);
+  shared_ptr<L2capPacket> test_10 = L2capPacket::assemble(test_packet);
   EXPECT_EQ(test_10, nullptr);
 
   test_packet.clear();
 
   l2cap_test_packet_1[6]++;
-  test_packet.push_back(update_fcs(l2cap_test_packet_1));
+  test_packet.push_back((update_fcs(l2cap_test_packet_1)));
   l2cap_test_packet_1[6]--;
-  test_packet.push_back(L2capSdu(l2cap_test_packet_2));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_3));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_4));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_5));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_6));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_7));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_8));
-  test_packet.push_back(L2capSdu(l2cap_test_packet_9));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
+  test_packet.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   test_10 = L2capPacket::assemble(test_packet);
 
@@ -320,13 +321,13 @@
 
 // Begin Fragment Test1
 TEST_F(L2capTest, fragmentSmallSegmentTest) {
-  std::vector<L2capSdu> sdu;
-  std::unique_ptr<L2capPacket> l2cap_expected;
-  std::unique_ptr<L2capPacket> l2cap_received;
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
+  std::shared_ptr<L2capPacket> l2cap_expected;
+  std::shared_ptr<L2capPacket> l2cap_received;
 
-  sdu.push_back(L2capSdu(good_sdu[0]));
-  sdu.push_back(L2capSdu(good_sdu[1]));
-  sdu.push_back(L2capSdu(good_sdu[2]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
   l2cap_expected = L2capPacket::assemble(sdu);
 
@@ -342,31 +343,28 @@
       << "sdu used: good_sdu" << std::endl
       << "function call: fragment(16, 0x02, 0x41)" << std::endl;
 
-  std::vector<uint8_t> small_seg_expected = l2cap_expected->get_l2cap_payload();
-  std::vector<uint8_t> small_seg_received = l2cap_received->get_l2cap_payload();
-
-  compare_fragmented_packets(small_seg_expected, small_seg_received);
+  compare_packets(l2cap_expected, l2cap_received);
 
   sdu.clear();
-  l2cap_expected.reset(nullptr);
-  l2cap_received.reset(nullptr);
+  l2cap_expected.reset();
+  l2cap_received.reset();
 }  // End Fragment Test1
 
 // Begin Fragment Test2
 TEST_F(L2capTest, fragmentLargeSegmentTest) {
-  std::vector<L2capSdu> sdu;
-  std::unique_ptr<L2capPacket> l2cap_expected;
-  std::unique_ptr<L2capPacket> l2cap_received;
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
+  std::shared_ptr<L2capPacket> l2cap_expected;
+  std::shared_ptr<L2capPacket> l2cap_received;
 
-  sdu.push_back(L2capSdu(l2cap_test_packet_1));
-  sdu.push_back(L2capSdu(l2cap_test_packet_2));
-  sdu.push_back(L2capSdu(l2cap_test_packet_3));
-  sdu.push_back(L2capSdu(l2cap_test_packet_4));
-  sdu.push_back(L2capSdu(l2cap_test_packet_5));
-  sdu.push_back(L2capSdu(l2cap_test_packet_6));
-  sdu.push_back(L2capSdu(l2cap_test_packet_7));
-  sdu.push_back(L2capSdu(l2cap_test_packet_8));
-  sdu.push_back(L2capSdu(l2cap_test_packet_9));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   l2cap_expected = L2capPacket::assemble(sdu);
 
@@ -382,25 +380,22 @@
       << "sdu used: l2cap_test_packet[1-9]" << std::endl
       << "function call: fragment(1024, 0x02, 0x41)" << std::endl;
 
-  std::vector<uint8_t> large_seg_expected = l2cap_expected->get_l2cap_payload();
-  std::vector<uint8_t> large_seg_received = l2cap_received->get_l2cap_payload();
-
-  compare_fragmented_packets(large_seg_expected, large_seg_received);
+  compare_packets(l2cap_expected, l2cap_received);
 
   sdu.clear();
-  l2cap_expected.reset(nullptr);
-  l2cap_received.reset(nullptr);
+  l2cap_expected.reset();
+  l2cap_received.reset();
 }  // End Fragment Test2
 
 // Begin Fragment Test3
 TEST_F(L2capTest, fragmentTxSeqTest) {
-  std::vector<L2capSdu> sdu;
-  std::unique_ptr<L2capPacket> l2cap_expected;
-  std::unique_ptr<L2capPacket> l2cap_received;
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
+  std::shared_ptr<L2capPacket> l2cap_expected;
+  std::shared_ptr<L2capPacket> l2cap_received;
 
-  sdu.push_back(L2capSdu(good_sdu[0]));
-  sdu.push_back(L2capSdu(good_sdu[1]));
-  sdu.push_back(L2capSdu(good_sdu[2]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
   l2cap_expected = L2capPacket::assemble(sdu);
 
@@ -416,24 +411,21 @@
       << "sdu used: good_sdu" << std::endl
       << "function call: fragment(24, 0x08, 0x41)" << std::endl;
 
-  std::vector<uint8_t> txseq_expected = l2cap_expected->get_l2cap_payload();
-  std::vector<uint8_t> txseq_received = l2cap_received->get_l2cap_payload();
-
-  compare_fragmented_packets(txseq_expected, txseq_received);
+  compare_packets(l2cap_expected, l2cap_received);
 
   sdu.clear();
-  l2cap_expected.reset(nullptr);
-  l2cap_received.reset(nullptr);
+  l2cap_expected.reset();
+  l2cap_received.reset();
 }  // End Fragment Test3
 
 // Begin Fragment Test4
 TEST_F(L2capTest, fragmentPayloadTest) {
-  std::vector<L2capSdu> sdu;
-  std::unique_ptr<L2capPacket> l2cap_expected;
-  std::unique_ptr<L2capPacket> l2cap_received;
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
+  std::shared_ptr<L2capPacket> l2cap_expected;
+  std::shared_ptr<L2capPacket> l2cap_received;
 
-  sdu.push_back(L2capSdu(empty_sdu_payload[0]));
-  sdu.push_back(L2capSdu(empty_sdu_payload[1]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(empty_sdu_payload[0]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(empty_sdu_payload[1]));
 
   l2cap_expected = L2capPacket::assemble(sdu);
 
@@ -449,25 +441,22 @@
       << "sdu used: empty_sdu_payload" << std::endl
       << "function call: fragment(16, 0x02, 0x41)" << std::endl;
 
-  std::vector<uint8_t> empty_expected = l2cap_expected->get_l2cap_payload();
-  std::vector<uint8_t> empty_received = l2cap_received->get_l2cap_payload();
-
-  compare_fragmented_packets(empty_expected, empty_received);
+  compare_packets(l2cap_expected, l2cap_received);
 
   sdu.clear();
-  l2cap_expected.reset(nullptr);
-  l2cap_received.reset(nullptr);
+  l2cap_expected.reset();
+  l2cap_received.reset();
 }  // End Fragment Test4
 
 // Begin Fragment Test5
 TEST_F(L2capTest, fragmentSegmentSizeTest) {
-  std::vector<L2capSdu> sdu;
-  std::unique_ptr<L2capPacket> l2cap_expected;
-  std::unique_ptr<L2capPacket> l2cap_received;
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
+  std::shared_ptr<L2capPacket> l2cap_expected;
+  std::shared_ptr<L2capPacket> l2cap_received;
 
-  sdu.push_back(L2capSdu(good_sdu[0]));
-  sdu.push_back(L2capSdu(good_sdu[1]));
-  sdu.push_back(L2capSdu(good_sdu[2]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[0]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[1]));
+  sdu.push_back(L2capSdu::L2capSduConstructor(good_sdu[2]));
 
   l2cap_expected = L2capPacket::assemble(sdu);
 
@@ -483,31 +472,28 @@
       << "sdu used: good_sdu" << std::endl
       << "function call: fragment(256, 0x02, 0x41)" << std::endl;
 
-  std::vector<uint8_t> big_segs_exp = l2cap_expected->get_l2cap_payload();
-  std::vector<uint8_t> big_segs_rcvd = l2cap_received->get_l2cap_payload();
-
-  compare_fragmented_packets(big_segs_exp, big_segs_rcvd);
+  compare_packets(l2cap_expected, l2cap_received);
 
   sdu.clear();
-  l2cap_expected.reset(nullptr);
-  l2cap_received.reset(nullptr);
+  l2cap_expected.reset();
+  l2cap_received.reset();
 }  // End Fragment Test5
 
 // Begin Fragment Test6
 TEST_F(L2capTest, fragmentSegmentSizeTest2) {
-  std::vector<L2capSdu> sdu;
-  std::unique_ptr<L2capPacket> l2cap_expected;
-  std::unique_ptr<L2capPacket> l2cap_received;
+  std::vector<std::shared_ptr<L2capSdu> > sdu;
+  std::shared_ptr<L2capPacket> l2cap_expected;
+  std::shared_ptr<L2capPacket> l2cap_received;
 
-  sdu.push_back(L2capSdu(l2cap_test_packet_1));
-  sdu.push_back(L2capSdu(l2cap_test_packet_2));
-  sdu.push_back(L2capSdu(l2cap_test_packet_3));
-  sdu.push_back(L2capSdu(l2cap_test_packet_4));
-  sdu.push_back(L2capSdu(l2cap_test_packet_5));
-  sdu.push_back(L2capSdu(l2cap_test_packet_6));
-  sdu.push_back(L2capSdu(l2cap_test_packet_7));
-  sdu.push_back(L2capSdu(l2cap_test_packet_8));
-  sdu.push_back(L2capSdu(l2cap_test_packet_9));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_1));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_2));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_3));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_4));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_5));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_6));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_7));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_8));
+  sdu.push_back(L2capSdu::L2capSduConstructor(l2cap_test_packet_9));
 
   l2cap_expected = L2capPacket::assemble(sdu);
   sdu.clear();
@@ -522,14 +508,11 @@
       << "sdu used: l2cap_test_packet_[1-9]" << std::endl
       << "function call: fragment(64, 0x02, 0x41)" << std::endl;
 
-  std::vector<uint8_t> small_segs_exp = l2cap_expected->get_l2cap_payload();
-  std::vector<uint8_t> small_segs_rcvd = l2cap_received->get_l2cap_payload();
-
-  compare_fragmented_packets(small_segs_exp, small_segs_rcvd);
+  compare_packets(l2cap_expected, l2cap_received);
 
   sdu.clear();
-  l2cap_expected.reset(nullptr);
-  l2cap_received.reset(nullptr);
+  l2cap_expected.reset();
+  l2cap_received.reset();
 }  // End Fragment Test6
 
 }  // namespace test_vendor_lib
diff --git a/vnd/ble/vendor_hcidefs.h b/vnd/ble/vendor_hcidefs.h
index d0bbaf3..b6782af 100644
--- a/vnd/ble/vendor_hcidefs.h
+++ b/vnd/ble/vendor_hcidefs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2003-2014 Broadcom Corporation
+ *  Copyright 2003-2014 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.