Merge "Add 5G cellInfo & signal strength"
diff --git a/audio/core/2.0/vts/functional/Android.bp b/audio/core/2.0/vts/functional/Android.bp
index c8441cf..2cfba21 100644
--- a/audio/core/2.0/vts/functional/Android.bp
+++ b/audio/core/2.0/vts/functional/Android.bp
@@ -25,9 +25,6 @@
         "android.hardware.audio.common.test.utility",
         "android.hardware.audio@2.0",
         "android.hardware.audio.common@2.0",
-        "libicuuc",
-        "libicuuc_stubdata",
-        "libandroidicu",
         "libxml2",
     ],
     test_suites: ["general-tests"],
diff --git a/audio/core/4.0/vts/functional/Android.bp b/audio/core/4.0/vts/functional/Android.bp
index 7ebb688..b2d9af4 100644
--- a/audio/core/4.0/vts/functional/Android.bp
+++ b/audio/core/4.0/vts/functional/Android.bp
@@ -25,9 +25,6 @@
         "android.hardware.audio.common.test.utility",
         "android.hardware.audio@4.0",
         "android.hardware.audio.common@4.0",
-        "libicuuc",
-        "libicuuc_stubdata",
-        "libandroidicu",
         "libxml2",
     ],
     shared_libs: [
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
index 068314f..5788720 100644
--- a/audio/effect/2.0/vts/functional/Android.bp
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -28,9 +28,6 @@
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libeffectsconfig",
-        "libicuuc",
-        "libicuuc_stubdata",
-        "libandroidicu",
         "libxml2",
     ],
     test_suites: ["general-tests"],
diff --git a/audio/effect/4.0/vts/functional/Android.bp b/audio/effect/4.0/vts/functional/Android.bp
index 886f92d..f1a3f0a 100644
--- a/audio/effect/4.0/vts/functional/Android.bp
+++ b/audio/effect/4.0/vts/functional/Android.bp
@@ -28,9 +28,6 @@
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libeffectsconfig",
-        "libicuuc",
-        "libicuuc_stubdata",
-        "libandroidicu",
         "libxml2",
     ],
     header_libs: [
diff --git a/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..84fba34
--- /dev/null
+++ b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.cpp
@@ -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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpOffload"
+
+#include <android-base/logging.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "A2dpOffloadAudioProvider.h"
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Void;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+A2dpOffloadAudioProvider::A2dpOffloadAudioProvider()
+    : BluetoothAudioProvider() {
+  session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH;
+}
+
+bool A2dpOffloadAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+Return<void> A2dpOffloadAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::codecConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsOffloadCodecConfigurationValid(
+                 session_type_, audioConfig.codecConfig())) {
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> A2dpOffloadAudioProvider::onSessionReady(
+    startSession_cb _hidl_cb) {
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                nullptr, audio_config_);
+  _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.h
new file mode 100644
index 0000000..9f40278
--- /dev/null
+++ b/bluetooth/audio/2.0/default/A2dpOffloadAudioProvider.h
@@ -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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  A2dpOffloadAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+
+ private:
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..f71a73e
--- /dev/null
+++ b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpSoftware"
+
+#include <android-base/logging.h>
+
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::Void;
+
+static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7;  // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 2;  // double buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
+    : BluetoothAudioProvider(), mDataMQ(nullptr) {
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+  std::unique_ptr<DataMQ> tempDataMQ(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (tempDataMQ && tempDataMQ->isValid()) {
+    mDataMQ = std::move(tempDataMQ);
+    session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+  } else {
+    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+  }
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
+}
+
+Return<void> A2dpSoftwareAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::pcmConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
+                 audioConfig.pcmConfig())) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << toString(audioConfig.pcmConfig());
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> A2dpSoftwareAudioProvider::onSessionReady(
+    startSession_cb _hidl_cb) {
+  if (mDataMQ && mDataMQ->isValid()) {
+    BluetoothAudioSessionReport::OnSessionStarted(
+        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+  } else {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+  }
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.h
new file mode 100644
index 0000000..228a928
--- /dev/null
+++ b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+  A2dpSoftwareAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> mDataMQ;
+
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/Android.bp b/bluetooth/audio/2.0/default/Android.bp
new file mode 100644
index 0000000..1dfc05d
--- /dev/null
+++ b/bluetooth/audio/2.0/default/Android.bp
@@ -0,0 +1,48 @@
+cc_library_shared {
+    name: "android.hardware.bluetooth.audio@2.0-impl",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "BluetoothAudioProvidersFactory.cpp",
+        "BluetoothAudioProvider.cpp",
+        "A2dpOffloadAudioProvider.cpp",
+        "A2dpSoftwareAudioProvider.cpp",
+        "HearingAidAudioProvider.cpp",
+    ],
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "android.hardware.audio.common@5.0",
+        "android.hardware.bluetooth.audio@2.0",
+        "libbase",
+        "libbluetooth_audio_session",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_library_shared {
+    name: "libbluetooth_audio_session",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    srcs: [
+        "session/BluetoothAudioSession.cpp",
+        "session/BluetoothAudioSupportedCodecsDB.cpp",
+    ],
+    export_include_dirs: ["session/"],
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "android.hardware.bluetooth.audio@2.0",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.0/default/BluetoothAudioProvider.cpp
new file mode 100644
index 0000000..ab8973e
--- /dev/null
+++ b/bluetooth/audio/2.0/default/BluetoothAudioProvider.cpp
@@ -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.
+ */
+
+#define LOG_TAG "BTAudioProviderStub"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioProvider.h"
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Void;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+void BluetoothAudioDeathRecipient::serviceDied(
+    uint64_t cookie __unused,
+    const wp<::android::hidl::base::V1_0::IBase>& who __unused) {
+  LOG(ERROR) << "BluetoothAudioDeathRecipient::" << __func__
+             << " - BluetoothAudio Service died";
+  provider_->endSession();
+}
+
+BluetoothAudioProvider::BluetoothAudioProvider()
+    : death_recipient_(new BluetoothAudioDeathRecipient(this)),
+      session_type_(SessionType::UNKNOWN),
+      audio_config_({}) {}
+
+Return<void> BluetoothAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  if (hostIf == nullptr) {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+    return Void();
+  }
+
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  audio_config_ = audioConfig;
+  stack_iface_ = hostIf;
+  stack_iface_->linkToDeath(death_recipient_, 0);
+
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", AudioConfiguration=[" << toString(audio_config_) << "]";
+
+  onSessionReady(_hidl_cb);
+  return Void();
+}
+
+Return<void> BluetoothAudioProvider::streamStarted(
+    BluetoothAudioStatus status) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", status=" << toString(status);
+
+  /**
+   * Streaming on control path has started,
+   * HAL server should start the streaming on data path.
+   */
+  if (stack_iface_) {
+    BluetoothAudioSessionReport::ReportControlStatus(session_type_, true,
+                                                     status);
+  } else {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", status=" << toString(status) << " has NO session";
+  }
+
+  return Void();
+}
+
+Return<void> BluetoothAudioProvider::streamSuspended(
+    BluetoothAudioStatus status) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", status=" << toString(status);
+
+  /**
+   * Streaming on control path has suspend,
+   * HAL server should suspend the streaming on data path.
+   */
+  if (stack_iface_) {
+    BluetoothAudioSessionReport::ReportControlStatus(session_type_, false,
+                                                     status);
+  } else {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", status=" << toString(status) << " has NO session";
+  }
+
+  return Void();
+}
+
+Return<void> BluetoothAudioProvider::endSession() {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+  if (stack_iface_) {
+    BluetoothAudioSessionReport::OnSessionEnded(session_type_);
+    stack_iface_->unlinkToDeath(death_recipient_);
+  } else {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO session";
+  }
+
+  /**
+   * Clean up the audio platform as remote audio device is no
+   * longer active
+   */
+  stack_iface_ = nullptr;
+  audio_config_ = {};
+
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvider.h b/bluetooth/audio/2.0/default/BluetoothAudioProvider.h
new file mode 100644
index 0000000..02bf2b9
--- /dev/null
+++ b/bluetooth/audio/2.0/default/BluetoothAudioProvider.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+
+using BluetoothAudioStatus =
+    ::android::hardware::bluetooth::audio::V2_0::Status;
+
+class BluetoothAudioDeathRecipient;
+
+class BluetoothAudioProvider : public IBluetoothAudioProvider {
+ public:
+  BluetoothAudioProvider();
+  ~BluetoothAudioProvider() = default;
+
+  virtual bool isValid(const SessionType& sessionType) = 0;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+  Return<void> streamStarted(BluetoothAudioStatus status) override;
+  Return<void> streamSuspended(BluetoothAudioStatus status) override;
+  Return<void> endSession() override;
+
+ protected:
+  sp<BluetoothAudioDeathRecipient> death_recipient_;
+
+  SessionType session_type_;
+  AudioConfiguration audio_config_;
+  sp<IBluetoothAudioPort> stack_iface_;
+
+  virtual Return<void> onSessionReady(startSession_cb _hidl_cb) = 0;
+};
+
+class BluetoothAudioDeathRecipient : public hidl_death_recipient {
+ public:
+  BluetoothAudioDeathRecipient(const sp<BluetoothAudioProvider> provider)
+      : provider_(provider) {}
+
+  virtual void serviceDied(
+      uint64_t cookie,
+      const wp<::android::hidl::base::V1_0::IBase>& who) override;
+
+ private:
+  sp<BluetoothAudioProvider> provider_;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.cpp
new file mode 100644
index 0000000..df89cc8
--- /dev/null
+++ b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.cpp
@@ -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.
+ */
+
+#define LOG_TAG "BTAudioProvidersFactory"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioProvidersFactory.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Void;
+
+A2dpSoftwareAudioProvider
+    BluetoothAudioProvidersFactory::a2dp_software_provider_instance_;
+A2dpOffloadAudioProvider
+    BluetoothAudioProvidersFactory::a2dp_offload_provider_instance_;
+HearingAidAudioProvider
+    BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
+
+Return<void> BluetoothAudioProvidersFactory::openProvider(
+    const SessionType sessionType, openProvider_cb _hidl_cb) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
+  BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
+  BluetoothAudioProvider* provider = nullptr;
+  switch (sessionType) {
+    case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+      provider = &a2dp_software_provider_instance_;
+      break;
+    case SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
+      provider = &a2dp_offload_provider_instance_;
+      break;
+    case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+      provider = &hearing_aid_provider_instance_;
+      break;
+    default:
+      status = BluetoothAudioStatus::FAILURE;
+  }
+  if (provider == nullptr || !provider->isValid(sessionType)) {
+    provider = nullptr;
+    status = BluetoothAudioStatus::FAILURE;
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
+               << ", status=" << toString(status);
+  }
+  _hidl_cb(status, provider);
+  return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities(
+    const SessionType sessionType, getProviderCapabilities_cb _hidl_cb) {
+  hidl_vec<AudioCapabilities> audio_capabilities =
+      hidl_vec<AudioCapabilities>(0);
+  if (sessionType == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    std::vector<CodecCapabilities> db_codec_capabilities =
+        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
+    if (db_codec_capabilities.size()) {
+      audio_capabilities.resize(db_codec_capabilities.size());
+      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
+      }
+    }
+  } else if (sessionType != SessionType::UNKNOWN) {
+    std::vector<PcmParameters> db_pcm_capabilities =
+        android::bluetooth::audio::GetSoftwarePcmCapabilities();
+    if (db_pcm_capabilities.size() == 1) {
+      audio_capabilities.resize(1);
+      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
+    }
+  }
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
+            << " supports " << audio_capabilities.size() << " codecs";
+  _hidl_cb(audio_capabilities);
+  return Void();
+}
+
+IBluetoothAudioProvidersFactory* HIDL_FETCH_IBluetoothAudioProvidersFactory(
+    const char* /* name */) {
+  return new BluetoothAudioProvidersFactory();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.h
new file mode 100644
index 0000000..0b51536
--- /dev/null
+++ b/bluetooth/audio/2.0/default/BluetoothAudioProvidersFactory.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
+
+#include "A2dpOffloadAudioProvider.h"
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioProvider.h"
+#include "HearingAidAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+class BluetoothAudioProvidersFactory : public IBluetoothAudioProvidersFactory {
+ public:
+  BluetoothAudioProvidersFactory() {}
+
+  Return<void> openProvider(const SessionType sessionType,
+                            openProvider_cb _hidl_cb) override;
+
+  Return<void> getProviderCapabilities(
+      const SessionType sessionType,
+      getProviderCapabilities_cb _hidl_cb) override;
+
+ private:
+  static A2dpSoftwareAudioProvider a2dp_software_provider_instance_;
+  static A2dpOffloadAudioProvider a2dp_offload_provider_instance_;
+  static HearingAidAudioProvider hearing_aid_provider_instance_;
+};
+
+extern "C" IBluetoothAudioProvidersFactory*
+HIDL_FETCH_IBluetoothAudioProvidersFactory(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/HearingAidAudioProvider.cpp b/bluetooth/audio/2.0/default/HearingAidAudioProvider.cpp
new file mode 100644
index 0000000..e91cf8a
--- /dev/null
+++ b/bluetooth/audio/2.0/default/HearingAidAudioProvider.cpp
@@ -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.
+ */
+
+#define LOG_TAG "BTAudioProviderHearingAid"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+#include "HearingAidAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::Void;
+
+static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7;  // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 1;  // single buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+HearingAidAudioProvider::HearingAidAudioProvider()
+    : BluetoothAudioProvider(), mDataMQ(nullptr) {
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+  std::unique_ptr<DataMQ> tempDataMQ(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (tempDataMQ && tempDataMQ->isValid()) {
+    mDataMQ = std::move(tempDataMQ);
+    session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+  } else {
+    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+  }
+}
+
+bool HearingAidAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
+}
+
+Return<void> HearingAidAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::pcmConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
+                 audioConfig.pcmConfig())) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << toString(audioConfig.pcmConfig());
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> HearingAidAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+  if (mDataMQ && mDataMQ->isValid()) {
+    BluetoothAudioSessionReport::OnSessionStarted(
+        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+  } else {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+  }
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/HearingAidAudioProvider.h b/bluetooth/audio/2.0/default/HearingAidAudioProvider.h
new file mode 100644
index 0000000..117eb32
--- /dev/null
+++ b/bluetooth/audio/2.0/default/HearingAidAudioProvider.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class HearingAidAudioProvider : public BluetoothAudioProvider {
+ public:
+  HearingAidAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> mDataMQ;
+
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.cpp
new file mode 100644
index 0000000..d60e732
--- /dev/null
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.cpp
@@ -0,0 +1,427 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderSession"
+
+#include "BluetoothAudioSession.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::audio::common::V5_0::AudioContentType;
+using ::android::hardware::audio::common::V5_0::AudioUsage;
+using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::TimeSpec;
+
+const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = {
+    .codecType = CodecType::UNKNOWN,
+    .encodedAudioBitrate = 0x00000000,
+    .peerMtu = 0xffff,
+    .isScmstEnabled = false,
+    .config = {}};
+AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration =
+    {};
+AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {};
+
+static constexpr int kFmqSendTimeoutMs = 1000;  // 1000 ms timeout for sending
+static constexpr int kWritePollMs = 1;          // polled non-blocking interval
+
+static inline timespec timespec_convert_from_hal(const TimeSpec& TS) {
+  return {.tv_sec = static_cast<long>(TS.tvSec),
+          .tv_nsec = static_cast<long>(TS.tvNSec)};
+}
+
+BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
+    : session_type_(session_type), stack_iface_(nullptr), mDataMQ(nullptr) {
+  invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
+  invalidOffloadAudioConfiguration.codecConfig(kInvalidCodecConfiguration);
+}
+
+// The report function is used to report that the Bluetooth stack has started
+// this session without any failure, and will invoke session_changed_cb_ to
+// notify those registered bluetooth_audio outputs
+void BluetoothAudioSession::OnSessionStarted(
+    const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ,
+    const AudioConfiguration& audio_config) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (stack_iface == nullptr) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << ", IBluetoothAudioPort Invalid";
+  } else if (!UpdateAudioConfig(audio_config)) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << ", AudioConfiguration=" << toString(audio_config)
+               << " Invalid";
+  } else if (!UpdateDataPath(dataMQ)) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << " DataMQ Invalid";
+    audio_config_ =
+        (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH
+             ? kInvalidOffloadAudioConfiguration
+             : kInvalidSoftwareAudioConfiguration);
+  } else {
+    stack_iface_ = stack_iface;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << ", AudioConfiguration=" << toString(audio_config);
+    ReportSessionStatus();
+  }
+}
+
+// The report function is used to report that the Bluetooth stack has ended the
+// session, and will invoke session_changed_cb_ to notify registered
+// bluetooth_audio outputs
+void BluetoothAudioSession::OnSessionEnded() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (IsSessionReady()) {
+    ReportSessionStatus();
+  }
+  audio_config_ = (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH
+                       ? kInvalidOffloadAudioConfiguration
+                       : kInvalidSoftwareAudioConfiguration);
+  stack_iface_ = nullptr;
+  UpdateDataPath(nullptr);
+}
+
+// invoking the registered session_changed_cb_
+void BluetoothAudioSession::ReportSessionStatus() {
+  // This is locked already by OnSessionStarted / OnSessionEnded
+  if (observers_.empty()) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " notify to bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie);
+    cb->session_changed_cb_(cookie);
+  }
+}
+
+// The report function is used to report that the Bluetooth stack has notified
+// the result of startStream or suspendStream, and will invoke
+// control_result_cb_ to notify registered bluetooth_audio outputs
+void BluetoothAudioSession::ReportControlStatus(
+    bool start_resp, const BluetoothAudioStatus& status) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (observers_.empty()) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+    LOG(INFO) << __func__ << " - status=" << toString(status)
+              << " for SessionType=" << toString(session_type_)
+              << ", bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie)
+              << (start_resp ? " started" : " suspended");
+    cb->control_result_cb_(cookie, start_resp, status);
+  }
+}
+
+// The function helps to check if this session is ready or not
+// @return: true if the Bluetooth stack has started the specified session
+bool BluetoothAudioSession::IsSessionReady() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  bool dataMQ_valid =
+      (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
+       (mDataMQ != nullptr && mDataMQ->isValid()));
+  return stack_iface_ != nullptr && dataMQ_valid;
+}
+
+bool BluetoothAudioSession::UpdateDataPath(const DataMQ::Descriptor* dataMQ) {
+  if (dataMQ == nullptr) {
+    // usecase of reset by nullptr
+    mDataMQ = nullptr;
+    return true;
+  }
+  std::unique_ptr<DataMQ> tempDataMQ;
+  tempDataMQ.reset(new DataMQ(*dataMQ));
+  if (!tempDataMQ || !tempDataMQ->isValid()) {
+    mDataMQ = nullptr;
+    return false;
+  }
+  mDataMQ = std::move(tempDataMQ);
+  return true;
+}
+
+bool BluetoothAudioSession::UpdateAudioConfig(
+    const AudioConfiguration& audio_config) {
+  bool is_software_session =
+      (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+  bool is_offload_session =
+      (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+  auto audio_config_discriminator = audio_config.getDiscriminator();
+  bool is_software_audio_config =
+      (is_software_session &&
+       audio_config_discriminator ==
+           AudioConfiguration::hidl_discriminator::pcmConfig);
+  bool is_offload_audio_config =
+      (is_offload_session &&
+       audio_config_discriminator ==
+           AudioConfiguration::hidl_discriminator::codecConfig);
+  if (!is_software_audio_config && !is_offload_audio_config) {
+    return false;
+  }
+  audio_config_ = audio_config;
+  return true;
+}
+
+// The control function helps the bluetooth_audio module to register
+// PortStatusCallbacks
+// @return: cookie - the assigned number to this bluetooth_audio output
+uint16_t BluetoothAudioSession::RegisterStatusCback(
+    const PortStatusCallbacks& cbacks) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  uint16_t cookie = ObserversCookieGetInitValue(session_type_);
+  uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
+
+  while (cookie < cookie_upper_bound) {
+    if (observers_.find(cookie) == observers_.end()) {
+      break;
+    }
+    ++cookie;
+  }
+  if (cookie >= cookie_upper_bound) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has " << observers_.size()
+               << " observers already (No Resource)";
+    return kObserversCookieUndefined;
+  }
+  std::shared_ptr<struct PortStatusCallbacks> cb =
+      std::make_shared<struct PortStatusCallbacks>();
+  *cb = cbacks;
+  observers_[cookie] = cb;
+  return cookie;
+}
+
+// The control function helps the bluetooth_audio module to unregister
+// PortStatusCallbacks
+// @param: cookie - indicates which bluetooth_audio output is
+void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (observers_.erase(cookie) != 1) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " no such provider=0x"
+                 << android::base::StringPrintf("%04x", cookie);
+  }
+}
+
+// The control function is for the bluetooth_audio module to get the current
+// AudioConfiguration
+const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (IsSessionReady()) {
+    return audio_config_;
+  } else if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return kInvalidOffloadAudioConfiguration;
+  } else {
+    return kInvalidSoftwareAudioConfiguration;
+  }
+}
+
+// Those control functions are for the bluetooth_audio module to start, suspend,
+// stop stream, to check position, and to update metadata.
+bool BluetoothAudioSession::StartStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = stack_iface_->startStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+bool BluetoothAudioSession::SuspendStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = stack_iface_->suspendStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+void BluetoothAudioSession::StopStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    return;
+  }
+  auto hal_retval = stack_iface_->stopStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+bool BluetoothAudioSession::GetPresentationPosition(
+    uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
+    timespec* data_position) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  bool retval = false;
+  auto hal_retval = stack_iface_->getPresentationPosition(
+      [&retval, &remote_delay_report_ns, &total_bytes_readed, &data_position](
+          BluetoothAudioStatus status,
+          const uint64_t& remoteDeviceAudioDelayNanos,
+          uint64_t transmittedOctets,
+          const TimeSpec& transmittedOctetsTimeStamp) {
+        if (status == BluetoothAudioStatus::SUCCESS) {
+          if (remote_delay_report_ns)
+            *remote_delay_report_ns = remoteDeviceAudioDelayNanos;
+          if (total_bytes_readed) *total_bytes_readed = transmittedOctets;
+          if (data_position)
+            *data_position =
+                timespec_convert_from_hal(transmittedOctetsTimeStamp);
+          retval = true;
+        }
+      });
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return retval;
+}
+
+void BluetoothAudioSession::UpdateTracksMetadata(
+    const struct source_metadata* source_metadata) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return;
+  }
+
+  ssize_t track_count = source_metadata->track_count;
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ", "
+            << track_count << " track(s)";
+  if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return;
+  }
+
+  struct playback_track_metadata* track = source_metadata->tracks;
+  SourceMetadata sourceMetadata;
+  PlaybackTrackMetadata* halMetadata;
+
+  sourceMetadata.tracks.resize(track_count);
+  halMetadata = sourceMetadata.tracks.data();
+  while (track_count && track) {
+    halMetadata->usage = static_cast<AudioUsage>(track->usage);
+    halMetadata->contentType =
+        static_cast<AudioContentType>(track->content_type);
+    halMetadata->gain = track->gain;
+    LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", usage=" << toString(halMetadata->usage)
+                 << ", content=" << toString(halMetadata->contentType)
+                 << ", gain=" << halMetadata->gain;
+    --track_count;
+    ++track;
+    ++halMetadata;
+  }
+  auto hal_retval = stack_iface_->updateMetadata(sourceMetadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+// The control function writes stream to FMQ
+size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
+                                              size_t bytes) {
+  if (buffer == nullptr || !bytes) return 0;
+  size_t totalWritten = 0;
+  int ms_timeout = kFmqSendTimeoutMs;
+  do {
+    std::unique_lock<std::recursive_mutex> lock(mutex_);
+    if (!IsSessionReady()) break;
+    size_t availableToWrite = mDataMQ->availableToWrite();
+    if (availableToWrite) {
+      if (availableToWrite > (bytes - totalWritten)) {
+        availableToWrite = bytes - totalWritten;
+      }
+
+      if (!mDataMQ->write(static_cast<const uint8_t*>(buffer) + totalWritten,
+                          availableToWrite)) {
+        ALOGE("FMQ datapath writting %zu/%zu failed", totalWritten, bytes);
+        return totalWritten;
+      }
+      totalWritten += availableToWrite;
+    } else if (ms_timeout >= kWritePollMs) {
+      lock.unlock();
+      usleep(kWritePollMs * 1000);
+      ms_timeout -= kWritePollMs;
+    } else {
+      ALOGD("data %zu/%zu overflow %d ms", totalWritten, bytes,
+            (kFmqSendTimeoutMs - ms_timeout));
+      return totalWritten;
+    }
+  } while (totalWritten < bytes);
+  return totalWritten;
+}
+
+std::unique_ptr<BluetoothAudioSessionInstance>
+    BluetoothAudioSessionInstance::instance_ptr =
+        std::unique_ptr<BluetoothAudioSessionInstance>(
+            new BluetoothAudioSessionInstance());
+
+// API to fetch the session of A2DP / Hearing Aid
+std::shared_ptr<BluetoothAudioSession>
+BluetoothAudioSessionInstance::GetSessionInstance(
+    const SessionType& session_type) {
+  std::lock_guard<std::mutex> guard(instance_ptr->mutex_);
+  if (!instance_ptr->sessions_map_.empty()) {
+    auto entry = instance_ptr->sessions_map_.find(session_type);
+    if (entry != instance_ptr->sessions_map_.end()) {
+      return entry->second;
+    }
+  }
+  std::shared_ptr<BluetoothAudioSession> session_ptr =
+      std::make_shared<BluetoothAudioSession>(session_type);
+  instance_ptr->sessions_map_[session_type] = session_ptr;
+  return session_ptr;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
new file mode 100644
index 0000000..85e8742
--- /dev/null
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSession.h
@@ -0,0 +1,185 @@
+/*
+ * 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 <mutex>
+#include <unordered_map>
+
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
+#include <fmq/MessageQueue.h>
+#include <hardware/audio.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::sp;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+
+using BluetoothAudioStatus =
+    ::android::hardware::bluetooth::audio::V2_0::Status;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+static constexpr uint16_t kObserversCookieSize = 0x0010;  // 0x0000 ~ 0x000f
+constexpr uint16_t kObserversCookieUndefined =
+    (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
+inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
+  return static_cast<SessionType>(cookie >> 8 & 0x00ff);
+}
+inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
+}
+inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
+         kObserversCookieSize;
+}
+
+// This presents the callbacks of started / suspended and session changed,
+// and the bluetooth_audio module uses to receive the status notification
+struct PortStatusCallbacks {
+  // control_result_cb_ - when the Bluetooth stack reports results of
+  // streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
+  // this callback to report to the bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  // @param: start_resp - this report is for startStream or not
+  // @param: status - the result of startStream
+  std::function<void(uint16_t cookie, bool start_resp,
+                     const BluetoothAudioStatus& status)>
+      control_result_cb_;
+  // session_changed_cb_ - when the Bluetooth stack start / end session, the
+  // BluetoothAudioProvider will invoke this callback to notify to the
+  // bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  std::function<void(uint16_t cookie)> session_changed_cb_;
+};
+
+class BluetoothAudioSession {
+ private:
+  // using recursive_mutex to allow hwbinder to re-enter agian.
+  std::recursive_mutex mutex_;
+  SessionType session_type_;
+
+  // audio control path to use for both software and offloading
+  sp<IBluetoothAudioPort> stack_iface_;
+  // audio data path (FMQ) for software encoding
+  std::unique_ptr<DataMQ> mDataMQ;
+  // audio data configuration for both software and offloading
+  AudioConfiguration audio_config_;
+
+  static AudioConfiguration invalidSoftwareAudioConfiguration;
+  static AudioConfiguration invalidOffloadAudioConfiguration;
+
+  // saving those registered bluetooth_audio's callbacks
+  std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
+      observers_;
+
+  bool UpdateDataPath(const DataMQ::Descriptor* dataMQ);
+  bool UpdateAudioConfig(const AudioConfiguration& audio_config);
+  // invoking the registered session_changed_cb_
+  void ReportSessionStatus();
+
+ public:
+  BluetoothAudioSession(const SessionType& session_type);
+
+  // The function helps to check if this session is ready or not
+  // @return: true if the Bluetooth stack has started the specified session
+  bool IsSessionReady();
+
+  // The report function is used to report that the Bluetooth stack has started
+  // this session without any failure, and will invoke session_changed_cb_ to
+  // notify those registered bluetooth_audio outputs
+  void OnSessionStarted(const sp<IBluetoothAudioPort> stack_iface,
+                        const DataMQ::Descriptor* dataMQ,
+                        const AudioConfiguration& audio_config);
+
+  // The report function is used to report that the Bluetooth stack has ended
+  // the session, and will invoke session_changed_cb_ to notify registered
+  // bluetooth_audio outputs
+  void OnSessionEnded();
+
+  // The report function is used to report that the Bluetooth stack has notified
+  // the result of startStream or suspendStream, and will invoke
+  // control_result_cb_ to notify registered bluetooth_audio outputs
+  void ReportControlStatus(bool start_resp, const BluetoothAudioStatus& status);
+
+  // The control function helps the bluetooth_audio module to register
+  // PortStatusCallbacks
+  // @return: cookie - the assigned number to this bluetooth_audio output
+  uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
+
+  // The control function helps the bluetooth_audio module to unregister
+  // PortStatusCallbacks
+  // @param: cookie - indicates which bluetooth_audio output is
+  void UnregisterStatusCback(uint16_t cookie);
+
+  // The control function is for the bluetooth_audio module to get the current
+  // AudioConfiguration
+  const AudioConfiguration& GetAudioConfig();
+
+  // Those control functions are for the bluetooth_audio module to start,
+  // suspend, stop stream, to check position, and to update metadata.
+  bool StartStream();
+  bool SuspendStream();
+  void StopStream();
+  bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
+                               uint64_t* total_bytes_readed,
+                               timespec* data_position);
+  void UpdateTracksMetadata(const struct source_metadata* source_metadata);
+
+  // The control function writes stream to FMQ
+  size_t OutWritePcmData(const void* buffer, size_t bytes);
+
+  static constexpr PcmParameters kInvalidPcmParameters = {
+      .sampleRate = SampleRate::RATE_UNKNOWN,
+      .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
+      .channelMode = ChannelMode::UNKNOWN};
+  // can't be constexpr because of non-literal type
+  static const CodecConfiguration kInvalidCodecConfiguration;
+
+  static constexpr AudioConfiguration& kInvalidSoftwareAudioConfiguration =
+      invalidSoftwareAudioConfiguration;
+  static constexpr AudioConfiguration& kInvalidOffloadAudioConfiguration =
+      invalidOffloadAudioConfiguration;
+};
+
+class BluetoothAudioSessionInstance {
+ public:
+  // The API is to fetch the specified session of A2DP / Hearing Aid
+  static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
+      const SessionType& session_type);
+
+ private:
+  static std::unique_ptr<BluetoothAudioSessionInstance> instance_ptr;
+  std::mutex mutex_;
+  std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+      sessions_map_;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSessionControl.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionControl.h
new file mode 100644
index 0000000..6707765
--- /dev/null
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionControl.h
@@ -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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioSession.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionControl {
+ public:
+  // The control API helps to check if session is ready or not
+  // @return: true if the Bluetooth stack has started th specified session
+  static bool IsSessionReady(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->IsSessionReady();
+    }
+    return false;
+  }
+
+  // The control API helps the bluetooth_audio module to register
+  // PortStatusCallbacks
+  // @return: cookie - the assigned number to this bluetooth_audio output
+  static uint16_t RegisterControlResultCback(
+      const SessionType& session_type, const PortStatusCallbacks& cbacks) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->RegisterStatusCback(cbacks);
+    }
+    return kObserversCookieUndefined;
+  }
+
+  // The control API helps the bluetooth_audio module to unregister
+  // PortStatusCallbacks
+  // @param: cookie - indicates which bluetooth_audio output is
+  static void UnregisterControlResultCback(const SessionType& session_type,
+                                           uint16_t cookie) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UnregisterStatusCback(cookie);
+    }
+  }
+
+  // The control API for the bluetooth_audio module to get current
+  // AudioConfiguration
+  static const AudioConfiguration& GetAudioConfig(
+      const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetAudioConfig();
+    } else if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+      return BluetoothAudioSession::kInvalidOffloadAudioConfiguration;
+    } else {
+      return BluetoothAudioSession::kInvalidSoftwareAudioConfiguration;
+    }
+  }
+
+  // Those control APIs for the bluetooth_audio module to start / suspend / stop
+  // stream, to check position, and to update metadata.
+  static bool StartStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->StartStream();
+    }
+    return false;
+  }
+
+  static bool SuspendStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->SuspendStream();
+    }
+    return false;
+  }
+
+  static void StopStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->StopStream();
+    }
+  }
+
+  static bool GetPresentationPosition(const SessionType& session_type,
+                                      uint64_t* remote_delay_report_ns,
+                                      uint64_t* total_bytes_readed,
+                                      timespec* data_position) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetPresentationPosition(
+          remote_delay_report_ns, total_bytes_readed, data_position);
+    }
+    return false;
+  }
+
+  static void UpdateTracksMetadata(
+      const SessionType& session_type,
+      const struct source_metadata* source_metadata) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UpdateTracksMetadata(source_metadata);
+    }
+  }
+
+  // The control API writes stream to FMQ
+  static size_t OutWritePcmData(const SessionType& session_type,
+                                const void* buffer, size_t bytes) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->OutWritePcmData(buffer, bytes);
+    }
+    return 0;
+  }
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSessionReport.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionReport.h
new file mode 100644
index 0000000..5a83ae2
--- /dev/null
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSessionReport.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 "BluetoothAudioSession.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionReport {
+ public:
+  // The API reports the Bluetooth stack has started the session, and will
+  // inform registered bluetooth_audio outputs
+  static void OnSessionStarted(const SessionType& session_type,
+                               const sp<IBluetoothAudioPort> host_iface,
+                               const DataMQ::Descriptor* dataMQ,
+                               const AudioConfiguration& audio_config) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->OnSessionStarted(host_iface, dataMQ, audio_config);
+    }
+  }
+  // The API reports the Bluetooth stack has ended the session, and will
+  // inform registered bluetooth_audio outputs
+  static void OnSessionEnded(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->OnSessionEnded();
+    }
+  }
+  // The API reports the Bluetooth stack has replied the result of startStream
+  // or suspendStream, and will inform registered bluetooth_audio outputs
+  static void ReportControlStatus(const SessionType& session_type,
+                                  const bool& start_resp,
+                                  const BluetoothAudioStatus& status) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->ReportControlStatus(start_resp, status);
+    }
+  }
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
new file mode 100644
index 0000000..292e28b
--- /dev/null
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.cpp
@@ -0,0 +1,413 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BTAudioProviderSessionCodecsDB"
+
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+
+// Default Supported PCM Parameters
+static const PcmParameters kDefaultSoftwarePcmCapabilities = {
+    .sampleRate = static_cast<SampleRate>(
+        SampleRate::RATE_44100 | SampleRate::RATE_48000 |
+        SampleRate::RATE_88200 | SampleRate::RATE_96000 |
+        SampleRate::RATE_16000 | SampleRate::RATE_24000),
+    .channelMode =
+        static_cast<ChannelMode>(ChannelMode::MONO | ChannelMode::STEREO),
+    .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 |
+                                                BitsPerSample::BITS_24 |
+                                                BitsPerSample::BITS_32)};
+
+// Default Supported Codecs
+// SBC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(MONO|STEREO)
+//      all blocks | subbands 8 | Loudness
+static const SbcParameters kDefaultOffloadSbcCapability = {
+    .sampleRate = SampleRate::RATE_44100,
+    .channelMode = static_cast<SbcChannelMode>(SbcChannelMode::MONO |
+                                               SbcChannelMode::JOINT_STEREO),
+    .blockLength = static_cast<SbcBlockLength>(
+        SbcBlockLength::BLOCKS_4 | SbcBlockLength::BLOCKS_8 |
+        SbcBlockLength::BLOCKS_12 | SbcBlockLength::BLOCKS_16),
+    .numSubbands = SbcNumSubbands::SUBBAND_8,
+    .allocMethod = SbcAllocMethod::ALLOC_MD_L,
+    .bitsPerSample = BitsPerSample::BITS_16,
+    .minBitpool = 2,
+    .maxBitpool = 53};
+
+// AAC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(STEREO)
+static const AacParameters kDefaultOffloadAacCapability = {
+    .objectType = AacObjectType::MPEG2_LC,
+    .sampleRate = SampleRate::RATE_44100,
+    .channelMode = ChannelMode::STEREO,
+    .variableBitRateEnabled = AacVariableBitRate::DISABLED,
+    .bitsPerSample = BitsPerSample::BITS_16};
+
+// LDAC: mSampleRate:(44100|48000|88200|96000), mBitsPerSample:(16|24|32),
+//       mChannelMode:(DUAL|STEREO)
+static const LdacParameters kDefaultOffloadLdacCapability = {
+    .sampleRate = static_cast<SampleRate>(
+        SampleRate::RATE_44100 | SampleRate::RATE_48000 |
+        SampleRate::RATE_88200 | SampleRate::RATE_96000),
+    .channelMode = static_cast<LdacChannelMode>(LdacChannelMode::DUAL |
+                                                LdacChannelMode::STEREO),
+    .qualityIndex = LdacQualityIndex::QUALITY_HIGH,
+    .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 |
+                                                BitsPerSample::BITS_24 |
+                                                BitsPerSample::BITS_32)};
+
+// aptX: mSampleRate:(44100|48000), mBitsPerSample:(16), mChannelMode:(STEREO)
+static const AptxParameters kDefaultOffloadAptxCapability = {
+    .sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
+                                          SampleRate::RATE_48000),
+    .bitsPerSample = BitsPerSample::BITS_16,
+    .channelMode = ChannelMode::STEREO};
+
+// aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24),
+//          mChannelMode:(STEREO)
+static const AptxParameters kDefaultOffloadAptxHdCapability = {
+    .sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
+                                          SampleRate::RATE_48000),
+    .bitsPerSample = BitsPerSample::BITS_24,
+    .channelMode = ChannelMode::STEREO};
+
+const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
+    {.codecType = CodecType::SBC, .capabilities = {}},
+    {.codecType = CodecType::AAC, .capabilities = {}},
+    {.codecType = CodecType::LDAC, .capabilities = {}},
+    {.codecType = CodecType::APTX, .capabilities = {}},
+    {.codecType = CodecType::APTX_HD, .capabilities = {}}};
+
+static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield) {
+  bool single = false;
+  uint32_t test_bit = 0x00000001;
+  while (test_bit <= bitmasks && test_bit <= bitfield) {
+    if (bitfield & test_bit && bitmasks & test_bit) {
+      if (single) return false;
+      single = true;
+    }
+    if (test_bit == 0x80000000) break;
+    test_bit <<= 1;
+  }
+  return single;
+}
+
+static bool IsOffloadSbcConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadAacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadLdacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadAptxConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadAptxHdConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+
+static bool IsOffloadSbcConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::sbcConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const SbcParameters sbc_data = codec_specific.sbcConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(sbc_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.channelMode), 0x0f) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.blockLength), 0xf0) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.numSubbands), 0x0c) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.allocMethod), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.bitsPerSample), 0x07) ||
+      sbc_data.minBitpool > sbc_data.maxBitpool) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((sbc_data.sampleRate & kDefaultOffloadSbcCapability.sampleRate) &&
+             (sbc_data.channelMode &
+              kDefaultOffloadSbcCapability.channelMode) &&
+             (sbc_data.blockLength &
+              kDefaultOffloadSbcCapability.blockLength) &&
+             (sbc_data.numSubbands &
+              kDefaultOffloadSbcCapability.numSubbands) &&
+             (sbc_data.allocMethod &
+              kDefaultOffloadSbcCapability.allocMethod) &&
+             (sbc_data.bitsPerSample &
+              kDefaultOffloadSbcCapability.bitsPerSample) &&
+             (kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
+              sbc_data.maxBitpool <= kDefaultOffloadSbcCapability.maxBitpool)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadAacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::aacConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const AacParameters aac_data = codec_specific.aacConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(aac_data.objectType), 0xf0) ||
+      !IsSingleBit(static_cast<uint32_t>(aac_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(aac_data.channelMode), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(aac_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((aac_data.objectType & kDefaultOffloadAacCapability.objectType) &&
+             (aac_data.sampleRate & kDefaultOffloadAacCapability.sampleRate) &&
+             (aac_data.channelMode &
+              kDefaultOffloadAacCapability.channelMode) &&
+             (aac_data.variableBitRateEnabled == AacVariableBitRate::DISABLED ||
+              kDefaultOffloadAacCapability.variableBitRateEnabled ==
+                  AacVariableBitRate::ENABLED) &&
+             (aac_data.bitsPerSample &
+              kDefaultOffloadAacCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadLdacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::ldacConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const LdacParameters ldac_data = codec_specific.ldacConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(ldac_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(ldac_data.channelMode), 0x07) ||
+      (ldac_data.qualityIndex > LdacQualityIndex::QUALITY_LOW &&
+       ldac_data.qualityIndex != LdacQualityIndex::QUALITY_ABR) ||
+      !IsSingleBit(static_cast<uint32_t>(ldac_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((ldac_data.sampleRate &
+              kDefaultOffloadLdacCapability.sampleRate) &&
+             (ldac_data.channelMode &
+              kDefaultOffloadLdacCapability.channelMode) &&
+             (ldac_data.bitsPerSample &
+              kDefaultOffloadLdacCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadAptxConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const AptxParameters aptx_data = codec_specific.aptxConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((aptx_data.sampleRate &
+              kDefaultOffloadAptxCapability.sampleRate) &&
+             (aptx_data.channelMode &
+              kDefaultOffloadAptxCapability.channelMode) &&
+             (aptx_data.bitsPerSample &
+              kDefaultOffloadAptxCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadAptxHdConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const AptxParameters aptx_data = codec_specific.aptxConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((aptx_data.sampleRate &
+              kDefaultOffloadAptxHdCapability.sampleRate) &&
+             (aptx_data.channelMode &
+              kDefaultOffloadAptxHdCapability.channelMode) &&
+             (aptx_data.bitsPerSample &
+              kDefaultOffloadAptxHdCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+std::vector<PcmParameters> GetSoftwarePcmCapabilities() {
+  return std::vector<PcmParameters>(1, kDefaultSoftwarePcmCapabilities);
+}
+
+std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
+    const SessionType& session_type) {
+  if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return std::vector<CodecCapabilities>(0);
+  }
+  std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
+      kDefaultOffloadA2dpCodecCapabilities;
+  for (auto& codec_capability : offload_a2dp_codec_capabilities) {
+    switch (codec_capability.codecType) {
+      case CodecType::SBC:
+        codec_capability.capabilities.sbcCapabilities(
+            kDefaultOffloadSbcCapability);
+        break;
+      case CodecType::AAC:
+        codec_capability.capabilities.aacCapabilities(
+            kDefaultOffloadAacCapability);
+        break;
+      case CodecType::LDAC:
+        codec_capability.capabilities.ldacCapabilities(
+            kDefaultOffloadLdacCapability);
+        break;
+      case CodecType::APTX:
+        codec_capability.capabilities.aptxCapabilities(
+            kDefaultOffloadAptxCapability);
+        break;
+      case CodecType::APTX_HD:
+        codec_capability.capabilities.aptxCapabilities(
+            kDefaultOffloadAptxHdCapability);
+        break;
+      case CodecType::UNKNOWN:
+        codec_capability = {};
+        break;
+    }
+  }
+  return offload_a2dp_codec_capabilities;
+}
+
+bool IsSoftwarePcmConfigurationValid(const PcmParameters& pcm_config) {
+  if ((pcm_config.sampleRate != SampleRate::RATE_44100 &&
+       pcm_config.sampleRate != SampleRate::RATE_48000 &&
+       pcm_config.sampleRate != SampleRate::RATE_88200 &&
+       pcm_config.sampleRate != SampleRate::RATE_96000 &&
+       pcm_config.sampleRate != SampleRate::RATE_16000 &&
+       pcm_config.sampleRate != SampleRate::RATE_24000) ||
+      (pcm_config.bitsPerSample != BitsPerSample::BITS_16 &&
+       pcm_config.bitsPerSample != BitsPerSample::BITS_24 &&
+       pcm_config.bitsPerSample != BitsPerSample::BITS_32) ||
+      (pcm_config.channelMode != ChannelMode::MONO &&
+       pcm_config.channelMode != ChannelMode::STEREO)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid PCM Configuration=" << toString(pcm_config);
+    return false;
+  } else if (pcm_config.sampleRate &
+                 kDefaultSoftwarePcmCapabilities.sampleRate &&
+             pcm_config.bitsPerSample &
+                 kDefaultSoftwarePcmCapabilities.bitsPerSample &&
+             pcm_config.channelMode &
+                 kDefaultSoftwarePcmCapabilities.channelMode) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported PCM Configuration=" << toString(pcm_config);
+  return false;
+}
+
+bool IsOffloadCodecConfigurationValid(const SessionType& session_type,
+                                      const CodecConfiguration& codec_config) {
+  if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    LOG(ERROR) << __func__
+               << ": Invalid SessionType=" << toString(session_type);
+    return false;
+  } else if (codec_config.encodedAudioBitrate < 0x00000001 ||
+             0x00ffffff < codec_config.encodedAudioBitrate) {
+    LOG(ERROR) << __func__ << ": Unsupported Codec Configuration="
+               << toString(codec_config);
+    return false;
+  }
+  const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
+  switch (codec_config.codecType) {
+    case CodecType::SBC:
+      if (IsOffloadSbcConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::AAC:
+      if (IsOffloadAacConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::LDAC:
+      if (IsOffloadLdacConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::APTX:
+      if (IsOffloadAptxConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::APTX_HD:
+      if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::UNKNOWN:
+      return false;
+  }
+  return false;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.h b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.h
new file mode 100644
index 0000000..e71dc8a
--- /dev/null
+++ b/bluetooth/audio/2.0/default/session/BluetoothAudioSupportedCodecsDB.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+
+std::vector<PcmParameters> GetSoftwarePcmCapabilities();
+std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
+    const SessionType& session_type);
+
+bool IsSoftwarePcmConfigurationValid(const PcmParameters& pcm_config);
+bool IsOffloadCodecConfigurationValid(const SessionType& session_type,
+                                      const CodecConfiguration& codec_config);
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.0/vts/OWNERS b/bluetooth/audio/2.0/vts/OWNERS
new file mode 100644
index 0000000..b6c0813
--- /dev/null
+++ b/bluetooth/audio/2.0/vts/OWNERS
@@ -0,0 +1,3 @@
+include platform/system/bt:/OWNERS
+
+cheneyni@google.com
diff --git a/bluetooth/audio/2.0/vts/functional/Android.bp b/bluetooth/audio/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..b672fe4
--- /dev/null
+++ b/bluetooth/audio/2.0/vts/functional/Android.bp
@@ -0,0 +1,12 @@
+cc_test {
+    name: "VtsHalBluetoothAudioV2_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBluetoothAudioV2_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.audio.common@5.0",
+        "android.hardware.bluetooth.audio@2.0",
+    ],
+    shared_libs: [
+        "libfmq",
+    ],
+}
diff --git a/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
new file mode 100644
index 0000000..9572d3f
--- /dev/null
+++ b/bluetooth/audio/2.0/vts/functional/VtsHalBluetoothAudioV2_0TargetTest.cpp
@@ -0,0 +1,915 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bluetooth_audio_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <utils/Log.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioProvider;
+using ::android::hardware::bluetooth::audio::V2_0::
+    IBluetoothAudioProvidersFactory;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using BluetoothAudioStatus =
+    ::android::hardware::bluetooth::audio::V2_0::Status;
+using CodecSpecificConfig = ::android::hardware::bluetooth::audio::V2_0::
+    CodecConfiguration::CodecSpecific;
+
+namespace {
+constexpr SampleRate a2dp_sample_rates[5] = {
+    SampleRate::RATE_UNKNOWN, SampleRate::RATE_44100, SampleRate::RATE_48000,
+    SampleRate::RATE_88200, SampleRate::RATE_96000};
+constexpr BitsPerSample a2dp_bits_per_samples[4] = {
+    BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24,
+    BitsPerSample::BITS_32};
+constexpr ChannelMode a2dp_channel_modes[3] = {
+    ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+constexpr CodecType a2dp_codec_types[6] = {CodecType::UNKNOWN, CodecType::SBC,
+                                           CodecType::AAC,     CodecType::APTX,
+                                           CodecType::APTX_HD, CodecType::LDAC};
+
+template <typename T>
+std::vector<T> ExtractValuesFromBitmask(T bitmasks, uint32_t bitfield,
+                                        bool supported) {
+  std::vector<T> retval;
+  if (!supported) {
+    retval.push_back(static_cast<T>(bitfield));
+  }
+  uint32_t test_bit = 0x00000001;
+  while (test_bit <= static_cast<uint32_t>(bitmasks) && test_bit <= bitfield) {
+    if ((bitfield & test_bit)) {
+      if ((!(bitmasks & test_bit) && !supported) ||
+          ((bitmasks & test_bit) && supported)) {
+        retval.push_back(static_cast<T>(test_bit));
+      }
+    }
+    if (test_bit == 0x80000000) {
+      break;
+    }
+    test_bit <<= 1;
+  }
+  return retval;
+}
+}  // namespace
+
+// Test environment for Bluetooth Audio HAL.
+class BluetoothAudioHidlEnvironment
+    : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+  // get the test environment singleton
+  static BluetoothAudioHidlEnvironment* Instance() {
+    static BluetoothAudioHidlEnvironment* instance =
+        new BluetoothAudioHidlEnvironment;
+    return instance;
+  }
+
+  virtual void registerTestServices() override {
+    registerTestService<IBluetoothAudioProvidersFactory>();
+  }
+
+ private:
+  BluetoothAudioHidlEnvironment() {}
+};
+
+// The base test class for Bluetooth Audio HAL.
+class BluetoothAudioProvidersFactoryHidlTest
+    : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+  virtual void SetUp() override {
+    providers_factory_ = ::testing::VtsHalHidlTargetTestBase::getService<
+        IBluetoothAudioProvidersFactory>(
+        BluetoothAudioHidlEnvironment::Instance()
+            ->getServiceName<IBluetoothAudioProvidersFactory>());
+    ASSERT_NE(providers_factory_, nullptr);
+  }
+
+  virtual void TearDown() override { providers_factory_ = nullptr; }
+
+  // A simple test implementation of IBluetoothAudioPort.
+  class BluetoothAudioPort : public ::testing::VtsHalHidlTargetCallbackBase<
+                                 BluetoothAudioProvidersFactoryHidlTest>,
+                             public IBluetoothAudioPort {
+    BluetoothAudioProvidersFactoryHidlTest& parent_;
+
+   public:
+    BluetoothAudioPort(BluetoothAudioProvidersFactoryHidlTest& parent)
+        : parent_(parent) {}
+    virtual ~BluetoothAudioPort() = default;
+
+    Return<void> startStream() override {
+      parent_.audio_provider_->streamStarted(BluetoothAudioStatus::SUCCESS);
+      return Void();
+    }
+
+    Return<void> suspendStream() override {
+      parent_.audio_provider_->streamSuspended(BluetoothAudioStatus::SUCCESS);
+      return Void();
+    }
+
+    Return<void> stopStream() override { return Void(); }
+
+    Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
+      _hidl_cb(BluetoothAudioStatus::SUCCESS, 0, 0, {.tvSec = 0, .tvNSec = 0});
+      return Void();
+    }
+
+    Return<void> updateMetadata(const SourceMetadata& sourceMetadata __unused) {
+      return Void();
+    }
+  };
+
+  void GetProviderCapabilitiesHelper(const SessionType& session_type) {
+    temp_provider_capabilities_.clear();
+    auto hidl_cb = [& temp_capabilities = this->temp_provider_capabilities_](
+                       const hidl_vec<AudioCapabilities>& audioCapabilities) {
+      for (auto audioCapability : audioCapabilities)
+        temp_capabilities.push_back(audioCapability);
+    };
+    auto hidl_retval =
+        providers_factory_->getProviderCapabilities(session_type, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    if (session_type == SessionType::UNKNOWN) {
+      ASSERT_TRUE(temp_provider_capabilities_.empty());
+    } else if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+      // All software paths are mandatory and must have exact 1 "PcmParameters"
+      ASSERT_EQ(temp_provider_capabilities_.size(), 1);
+      ASSERT_EQ(temp_provider_capabilities_[0].getDiscriminator(),
+                AudioCapabilities::hidl_discriminator::pcmCapabilities);
+    } else {
+      uint32_t codec_type_bitmask = 0x00000000;
+      // empty capability means offload is unsupported
+      for (auto audio_capability : temp_provider_capabilities_) {
+        ASSERT_EQ(audio_capability.getDiscriminator(),
+                  AudioCapabilities::hidl_discriminator::codecCapabilities);
+        const CodecCapabilities& codec_capabilities =
+            audio_capability.codecCapabilities();
+        // Every codec can present once at most
+        ASSERT_EQ(codec_type_bitmask &
+                      static_cast<uint32_t>(codec_capabilities.codecType),
+                  0);
+        switch (codec_capabilities.codecType) {
+          case CodecType::SBC:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          sbcCapabilities);
+            break;
+          case CodecType::AAC:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          aacCapabilities);
+            break;
+          case CodecType::APTX:
+            FALLTHROUGH_INTENDED;
+          case CodecType::APTX_HD:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          aptxCapabilities);
+            break;
+          case CodecType::LDAC:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          ldacCapabilities);
+            break;
+          case CodecType::UNKNOWN:
+            break;
+        }
+        codec_type_bitmask |= codec_capabilities.codecType;
+      }
+    }
+  }
+
+  // This helps to open the specified provider and check the openProvider()
+  // has corruct return values. BUT, to keep it simple, it does not consider
+  // the capability, and please do so at the SetUp of each session's test.
+  void OpenProviderHelper(const SessionType& session_type) {
+    BluetoothAudioStatus cb_status;
+    auto hidl_cb = [&cb_status, &local_provider = this->audio_provider_](
+                       BluetoothAudioStatus status,
+                       const sp<IBluetoothAudioProvider>& provider) {
+      cb_status = status;
+      local_provider = provider;
+    };
+    auto hidl_retval = providers_factory_->openProvider(session_type, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    if (cb_status == BluetoothAudioStatus::SUCCESS) {
+      ASSERT_NE(session_type, SessionType::UNKNOWN);
+      ASSERT_NE(audio_provider_, nullptr);
+      audio_port_ = new BluetoothAudioPort(*this);
+    } else {
+      // A2DP_HARDWARE_OFFLOAD_DATAPATH is optional
+      ASSERT_TRUE(session_type == SessionType::UNKNOWN ||
+                  session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+      ASSERT_EQ(cb_status, BluetoothAudioStatus::FAILURE);
+      ASSERT_EQ(audio_provider_, nullptr);
+    }
+  }
+
+  bool IsPcmParametersSupported(const PcmParameters& pcm_parameters) {
+    if (temp_provider_capabilities_.size() != 1 ||
+        temp_provider_capabilities_[0].getDiscriminator() !=
+            AudioCapabilities::hidl_discriminator::pcmCapabilities) {
+      return false;
+    }
+    auto pcm_capability = temp_provider_capabilities_[0].pcmCapabilities();
+    bool is_parameter_valid =
+        (pcm_parameters.sampleRate != SampleRate::RATE_UNKNOWN &&
+         pcm_parameters.channelMode != ChannelMode::UNKNOWN &&
+         pcm_parameters.bitsPerSample != BitsPerSample::BITS_UNKNOWN);
+    bool is_parameter_in_capability =
+        (pcm_capability.sampleRate & pcm_parameters.sampleRate &&
+         pcm_capability.channelMode & pcm_parameters.channelMode &&
+         pcm_capability.bitsPerSample & pcm_parameters.bitsPerSample);
+    return is_parameter_valid && is_parameter_in_capability;
+  }
+
+  sp<IBluetoothAudioProvidersFactory> providers_factory_;
+
+  // temp storage saves the specified provider capability by
+  // GetProviderCapabilitiesHelper()
+  std::vector<AudioCapabilities> temp_provider_capabilities_;
+
+  // audio_provider_ is for the Bluetooth stack to report session started/ended
+  // and handled audio stream started / suspended
+  sp<IBluetoothAudioProvider> audio_provider_;
+
+  // audio_port_ is for the Audio HAL to send stream start/suspend/stop commands
+  // to Bluetooth stack
+  sp<IBluetoothAudioPort> audio_port_;
+
+  static constexpr SessionType session_types_[4] = {
+      SessionType::UNKNOWN, SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH};
+};
+
+/**
+ * Test whether we can get the FactoryService from HIDL
+ */
+TEST_F(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
+
+/**
+ * Test whether we can open a provider for each provider returned by
+ * getProviderCapabilities() with non-empty capabalities
+ */
+TEST_F(BluetoothAudioProvidersFactoryHidlTest,
+       OpenProviderAndCheckCapabilitiesBySession) {
+  for (auto session_type : session_types_) {
+    GetProviderCapabilitiesHelper(session_type);
+    OpenProviderHelper(session_type);
+    // We must be able to open a provider if its getProviderCapabilities()
+    // returns non-empty list.
+    EXPECT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+}
+
+/**
+ * openProvider A2DP_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderA2dpSoftwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest,
+       StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) {
+  bool is_codec_config_valid;
+  std::unique_ptr<DataMQ> tempDataMQ;
+  auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
+                     BluetoothAudioStatus status,
+                     const DataMQ::Descriptor& dataMQ) {
+    if (is_codec_config_valid) {
+      ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      ASSERT_TRUE(dataMQ.isHandleValid());
+      tempDataMQ.reset(new DataMQ(dataMQ));
+    } else {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    }
+  };
+  AudioConfiguration audio_config = {};
+  PcmParameters pcm_parameters = {};
+  for (auto sample_rate : a2dp_sample_rates) {
+    pcm_parameters.sampleRate = sample_rate;
+    for (auto bits_per_sample : a2dp_bits_per_samples) {
+      pcm_parameters.bitsPerSample = bits_per_sample;
+      for (auto channel_mode : a2dp_channel_modes) {
+        pcm_parameters.channelMode = channel_mode;
+        is_codec_config_valid = IsPcmParametersSupported(pcm_parameters);
+        audio_config.pcmConfig(pcm_parameters);
+        auto hidl_retval =
+            audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+        // HIDL calls should not be failed and callback has to be executed
+        ASSERT_TRUE(hidl_retval.isOk());
+        if (is_codec_config_valid) {
+          EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+        }
+        EXPECT_TRUE(audio_provider_->endSession().isOk());
+      }  // ChannelMode
+    }    // BitsPerSampple
+  }      // SampleRate
+}
+
+/**
+ * openProvider A2DP_HARDWARE_OFFLOAD_DATAPATH
+ */
+class BluetoothAudioProviderA2dpHardwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+    OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+
+  bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); }
+
+  void GetOffloadCodecCapabilityHelper(const CodecType& codec_type) {
+    temp_codec_capabilities_ = {};
+    for (auto codec_capability : temp_provider_capabilities_) {
+      if (codec_capability.codecCapabilities().codecType != codec_type) {
+        continue;
+      }
+      temp_codec_capabilities_ = codec_capability.codecCapabilities();
+    }
+  }
+
+  std::vector<CodecSpecificConfig> GetSbcCodecSpecificSupportedList(
+      bool supported) {
+    std::vector<CodecSpecificConfig> sbc_codec_specifics;
+    GetOffloadCodecCapabilityHelper(CodecType::SBC);
+    if (temp_codec_capabilities_.codecType != CodecType::SBC) {
+      return sbc_codec_specifics;
+    }
+    // parse the capability
+    SbcParameters sbc_capability =
+        temp_codec_capabilities_.capabilities.sbcCapabilities();
+    if (sbc_capability.minBitpool > sbc_capability.maxBitpool) {
+      return sbc_codec_specifics;
+    }
+    std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
+        sbc_capability.sampleRate, 0xff, supported);
+    std::vector<SbcChannelMode> channel_modes =
+        ExtractValuesFromBitmask<SbcChannelMode>(sbc_capability.channelMode,
+                                                 0x0f, supported);
+    std::vector<SbcBlockLength> block_lengths =
+        ExtractValuesFromBitmask<SbcBlockLength>(sbc_capability.blockLength,
+                                                 0xf0, supported);
+    std::vector<SbcNumSubbands> num_subbandss =
+        ExtractValuesFromBitmask<SbcNumSubbands>(sbc_capability.numSubbands,
+                                                 0x0c, supported);
+    std::vector<SbcAllocMethod> alloc_methods =
+        ExtractValuesFromBitmask<SbcAllocMethod>(sbc_capability.allocMethod,
+                                                 0x03, supported);
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(sbc_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    SbcParameters sbc_data;
+    for (auto sample_rate : sample_rates) {
+      for (auto channel_mode : channel_modes) {
+        for (auto block_length : block_lengths) {
+          for (auto num_subbands : num_subbandss) {
+            for (auto alloc_method : alloc_methods) {
+              for (auto bits_per_sample : bits_per_samples) {
+                sbc_data = {.sampleRate = sample_rate,
+                            .channelMode = channel_mode,
+                            .blockLength = block_length,
+                            .numSubbands = num_subbands,
+                            .allocMethod = alloc_method,
+                            .bitsPerSample = bits_per_sample,
+                            .minBitpool = sbc_capability.minBitpool,
+                            .maxBitpool = sbc_capability.maxBitpool};
+                codec_specific.sbcConfig(sbc_data);
+                sbc_codec_specifics.push_back(codec_specific);
+              }
+            }
+          }
+        }
+      }
+    }
+    return sbc_codec_specifics;
+  }
+
+  std::vector<CodecSpecificConfig> GetAacCodecSpecificSupportedList(
+      bool supported) {
+    std::vector<CodecSpecificConfig> aac_codec_specifics;
+    GetOffloadCodecCapabilityHelper(CodecType::AAC);
+    if (temp_codec_capabilities_.codecType != CodecType::AAC) {
+      return aac_codec_specifics;
+    }
+    // parse the capability
+    AacParameters aac_capability =
+        temp_codec_capabilities_.capabilities.aacCapabilities();
+    std::vector<AacObjectType> object_types =
+        ExtractValuesFromBitmask<AacObjectType>(aac_capability.objectType, 0xf0,
+                                                supported);
+    std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
+        aac_capability.sampleRate, 0xff, supported);
+    std::vector<ChannelMode> channel_modes =
+        ExtractValuesFromBitmask<ChannelMode>(aac_capability.channelMode, 0x03,
+                                              supported);
+    std::vector<AacVariableBitRate> variable_bit_rate_enableds = {
+        AacVariableBitRate::DISABLED};
+    if (aac_capability.variableBitRateEnabled == AacVariableBitRate::ENABLED) {
+      variable_bit_rate_enableds.push_back(AacVariableBitRate::ENABLED);
+    }
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(aac_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    AacParameters aac_data;
+    for (auto object_type : object_types) {
+      for (auto sample_rate : sample_rates) {
+        for (auto channel_mode : channel_modes) {
+          for (auto variable_bit_rate_enabled : variable_bit_rate_enableds) {
+            for (auto bits_per_sample : bits_per_samples) {
+              aac_data = {.objectType = object_type,
+                          .sampleRate = sample_rate,
+                          .channelMode = channel_mode,
+                          .variableBitRateEnabled = variable_bit_rate_enabled,
+                          .bitsPerSample = bits_per_sample};
+              codec_specific.aacConfig(aac_data);
+              aac_codec_specifics.push_back(codec_specific);
+            }
+          }
+        }
+      }
+    }
+    return aac_codec_specifics;
+  }
+
+  std::vector<CodecSpecificConfig> GetLdacCodecSpecificSupportedList(
+      bool supported) {
+    std::vector<CodecSpecificConfig> ldac_codec_specifics;
+    GetOffloadCodecCapabilityHelper(CodecType::LDAC);
+    if (temp_codec_capabilities_.codecType != CodecType::LDAC) {
+      return ldac_codec_specifics;
+    }
+    // parse the capability
+    LdacParameters ldac_capability =
+        temp_codec_capabilities_.capabilities.ldacCapabilities();
+    std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
+        ldac_capability.sampleRate, 0xff, supported);
+    std::vector<LdacChannelMode> channel_modes =
+        ExtractValuesFromBitmask<LdacChannelMode>(ldac_capability.channelMode,
+                                                  0x07, supported);
+    std::vector<LdacQualityIndex> quality_indexes = {
+        LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID,
+        LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR};
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(ldac_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    LdacParameters ldac_data;
+    for (auto sample_rate : sample_rates) {
+      for (auto channel_mode : channel_modes) {
+        for (auto quality_index : quality_indexes) {
+          for (auto bits_per_sample : bits_per_samples) {
+            ldac_data = {.sampleRate = sample_rate,
+                         .channelMode = channel_mode,
+                         .qualityIndex = quality_index,
+                         .bitsPerSample = bits_per_sample};
+            codec_specific.ldacConfig(ldac_data);
+            ldac_codec_specifics.push_back(codec_specific);
+          }
+        }
+      }
+    }
+    return ldac_codec_specifics;
+  }
+
+  std::vector<CodecSpecificConfig> GetAptxCodecSpecificSupportedList(
+      bool is_hd, bool supported) {
+    std::vector<CodecSpecificConfig> aptx_codec_specifics;
+    GetOffloadCodecCapabilityHelper(
+        (is_hd ? CodecType::APTX_HD : CodecType::APTX));
+    if ((is_hd && temp_codec_capabilities_.codecType != CodecType::APTX_HD) ||
+        (!is_hd && temp_codec_capabilities_.codecType != CodecType::APTX)) {
+      return aptx_codec_specifics;
+    }
+    // parse the capability
+    AptxParameters aptx_capability =
+        temp_codec_capabilities_.capabilities.aptxCapabilities();
+    std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
+        aptx_capability.sampleRate, 0xff, supported);
+    std::vector<ChannelMode> channel_modes =
+        ExtractValuesFromBitmask<ChannelMode>(aptx_capability.channelMode, 0x03,
+                                              supported);
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(aptx_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    AptxParameters aptx_data;
+    for (auto sample_rate : sample_rates) {
+      for (auto channel_mode : channel_modes) {
+        for (auto bits_per_sample : bits_per_samples) {
+          aptx_data = {.sampleRate = sample_rate,
+                       .channelMode = channel_mode,
+                       .bitsPerSample = bits_per_sample};
+          codec_specific.aptxConfig(aptx_data);
+          aptx_codec_specifics.push_back(codec_specific);
+        }
+      }
+    }
+    return aptx_codec_specifics;
+  }
+
+  // temp storage saves the specified codec capability by
+  // GetOffloadCodecCapabilityHelper()
+  CodecCapabilities temp_codec_capabilities_;
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * SBC hardware encoding config
+ */
+TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpSbcHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {};
+  codec_config.codecType = CodecType::SBC;
+  codec_config.encodedAudioBitrate = 328000;
+  codec_config.peerMtu = 1005;
+  codec_config.isScmstEnabled = false;
+  AudioConfiguration audio_config = {};
+  std::vector<CodecSpecificConfig> sbc_codec_specifics =
+      GetSbcCodecSpecificSupportedList(true);
+  auto hidl_cb = [](BluetoothAudioStatus status,
+                    const DataMQ::Descriptor& dataMQ) {
+    EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+    EXPECT_FALSE(dataMQ.isHandleValid());
+  };
+  for (auto codec_specific : sbc_codec_specifics) {
+    codec_config.config = codec_specific;
+    audio_config.codecConfig(codec_config);
+    auto hidl_retval =
+        audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * AAC hardware encoding config
+ */
+TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpAacHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {};
+  codec_config.codecType = CodecType::AAC;
+  codec_config.encodedAudioBitrate = 320000;
+  codec_config.peerMtu = 1005;
+  codec_config.isScmstEnabled = false;
+  AudioConfiguration audio_config = {};
+  std::vector<CodecSpecificConfig> aac_codec_specifics =
+      GetAacCodecSpecificSupportedList(true);
+  auto hidl_cb = [](BluetoothAudioStatus status,
+                    const DataMQ::Descriptor& dataMQ) {
+    EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+    EXPECT_FALSE(dataMQ.isHandleValid());
+  };
+  for (auto codec_specific : aac_codec_specifics) {
+    codec_config.config = codec_specific;
+    audio_config.codecConfig(codec_config);
+    auto hidl_retval =
+        audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * LDAC hardware encoding config
+ */
+TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpLdacHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {};
+  codec_config.codecType = CodecType::LDAC;
+  codec_config.encodedAudioBitrate = 990000;
+  codec_config.peerMtu = 1005;
+  codec_config.isScmstEnabled = false;
+  AudioConfiguration audio_config = {};
+  std::vector<CodecSpecificConfig> ldac_codec_specifics =
+      GetLdacCodecSpecificSupportedList(true);
+  auto hidl_cb = [](BluetoothAudioStatus status,
+                    const DataMQ::Descriptor& dataMQ) {
+    EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+    EXPECT_FALSE(dataMQ.isHandleValid());
+  };
+  for (auto codec_specific : ldac_codec_specifics) {
+    codec_config.config = codec_specific;
+    audio_config.codecConfig(codec_config);
+    auto hidl_retval =
+        audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * AptX hardware encoding config
+ */
+TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpAptxHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
+    CodecConfiguration codec_config = {};
+    codec_config.codecType = codec_type;
+    codec_config.encodedAudioBitrate =
+        (codec_type == CodecType::APTX ? 352000 : 576000);
+    codec_config.peerMtu = 1005;
+    codec_config.isScmstEnabled = false;
+    AudioConfiguration audio_config = {};
+    std::vector<CodecSpecificConfig> aptx_codec_specifics =
+        GetAptxCodecSpecificSupportedList(
+            (codec_type == CodecType::APTX_HD ? true : false), true);
+    auto hidl_cb = [](BluetoothAudioStatus status,
+                      const DataMQ::Descriptor& dataMQ) {
+      EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    };
+    for (auto codec_specific : aptx_codec_specifics) {
+      codec_config.config = codec_specific;
+      audio_config.codecConfig(codec_config);
+      auto hidl_retval =
+          audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+      // HIDL calls should not be failed and callback has to be executed
+      ASSERT_TRUE(hidl_retval.isOk());
+      EXPECT_TRUE(audio_provider_->endSession().isOk());
+    }
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * an invalid codec config
+ */
+TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpHardwareSessionInvalidCodecConfig) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+  ASSERT_NE(audio_provider_, nullptr);
+
+  std::vector<CodecSpecificConfig> codec_specifics;
+  for (auto codec_type : a2dp_codec_types) {
+    switch (codec_type) {
+      case CodecType::SBC:
+        codec_specifics = GetSbcCodecSpecificSupportedList(false);
+        break;
+      case CodecType::AAC:
+        codec_specifics = GetAacCodecSpecificSupportedList(false);
+        break;
+      case CodecType::LDAC:
+        codec_specifics = GetLdacCodecSpecificSupportedList(false);
+        break;
+      case CodecType::APTX:
+        codec_specifics = GetAptxCodecSpecificSupportedList(false, false);
+        break;
+      case CodecType::APTX_HD:
+        codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
+        break;
+      case CodecType::UNKNOWN:
+        codec_specifics.clear();
+        break;
+    }
+    if (codec_specifics.empty()) {
+      continue;
+    }
+
+    CodecConfiguration codec_config = {};
+    codec_config.codecType = codec_type;
+    codec_config.encodedAudioBitrate = 328000;
+    codec_config.peerMtu = 1005;
+    codec_config.isScmstEnabled = false;
+    AudioConfiguration audio_config = {};
+    auto hidl_cb = [](BluetoothAudioStatus status,
+                      const DataMQ::Descriptor& dataMQ) {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    };
+    for (auto codec_specific : codec_specifics) {
+      codec_config.config = codec_specific;
+      audio_config.codecConfig(codec_config);
+      auto hidl_retval =
+          audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+      // HIDL calls should not be failed and callback has to be executed
+      ASSERT_TRUE(hidl_retval.isOk());
+      EXPECT_TRUE(audio_provider_->endSession().isOk());
+    }
+  }
+}
+
+/**
+ * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderHearingAidSoftwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+
+  static constexpr SampleRate hearing_aid_sample_rates_[3] = {
+      SampleRate::RATE_UNKNOWN, SampleRate::RATE_16000, SampleRate::RATE_24000};
+  static constexpr BitsPerSample hearing_aid_bits_per_samples_[3] = {
+      BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16,
+      BitsPerSample::BITS_24};
+  static constexpr ChannelMode hearing_aid_channel_modes_[3] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::HEARING_AID_HARDWARE_ENCODING_DATAPATH can be started and
+ * stopped with SBC hardware encoding config
+ */
+TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+       OpenHearingAidSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+       StartAndEndHearingAidSessionWithPossiblePcmConfig) {
+  bool is_codec_config_valid;
+  std::unique_ptr<DataMQ> tempDataMQ;
+  auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
+                     BluetoothAudioStatus status,
+                     const DataMQ::Descriptor& dataMQ) {
+    if (is_codec_config_valid) {
+      ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      ASSERT_TRUE(dataMQ.isHandleValid());
+      tempDataMQ.reset(new DataMQ(dataMQ));
+    } else {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    }
+  };
+  AudioConfiguration audio_config = {};
+  PcmParameters pcm_parameters = {};
+  for (auto sample_rate : hearing_aid_sample_rates_) {
+    pcm_parameters.sampleRate = sample_rate;
+    for (auto bits_per_sample : hearing_aid_bits_per_samples_) {
+      pcm_parameters.bitsPerSample = bits_per_sample;
+      for (auto channel_mode : hearing_aid_channel_modes_) {
+        pcm_parameters.channelMode = channel_mode;
+        is_codec_config_valid = IsPcmParametersSupported(pcm_parameters);
+        audio_config.pcmConfig(pcm_parameters);
+        auto hidl_retval =
+            audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+        // HIDL calls should not be failed and callback has to be executed
+        ASSERT_TRUE(hidl_retval.isOk());
+        if (is_codec_config_valid) {
+          EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+        }
+        EXPECT_TRUE(audio_provider_->endSession().isOk());
+      }  // ChannelMode
+    }    // BitsPerSampple
+  }      // SampleRate
+}
+
+int main(int argc, char** argv) {
+  ::testing::AddGlobalTestEnvironment(
+      BluetoothAudioHidlEnvironment::Instance());
+  ::testing::InitGoogleTest(&argc, argv);
+  BluetoothAudioHidlEnvironment::Instance()->init(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
index 6054999..4de05c5 100644
--- a/camera/common/1.0/default/Exif.cpp
+++ b/camera/common/1.0/default/Exif.cpp
@@ -18,7 +18,7 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include <inttypes.h>
 #include <math.h>
diff --git a/current.txt b/current.txt
index 5dba85b..37de397 100644
--- a/current.txt
+++ b/current.txt
@@ -395,8 +395,9 @@
 1fb32361286b938d48a55c2539c846732afce0b99fe08590f556643125bc13d3 android.hardware.neuralnetworks@1.0::types
 e22e8135d061d0e9c4c1a70c25c19fdba10f4d3cda9795ef25b6392fc520317c android.hardware.neuralnetworks@1.1::types
 1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse
-271187e261b30c01a33011aea257c07a2d2f05b72943ebee89e973e997849973 android.hardware.radio@1.0::types
+ed9da80ec0c96991fd03f0a46107815d0e50f764656e49dba4980fa5c31d5bc3 android.hardware.radio@1.0::types
 1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio
+cd1757867a5e3a3faa362e785239515870d1a3c9ce756c6f0cf0f0fd8aac2547 android.hardware.radio@1.2::types
 e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types
 1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types
 29c8da7a13c40d488f569c812441d5754ee45bdcdb8ce6564f524b708d10a057 android.hardware.vibrator@1.1::types
diff --git a/gnss/1.0/default/GnssBatching.cpp b/gnss/1.0/default/GnssBatching.cpp
index 02b38cb..f2e2e45 100644
--- a/gnss/1.0/default/GnssBatching.cpp
+++ b/gnss/1.0/default/GnssBatching.cpp
@@ -20,7 +20,7 @@
 #include <Gnss.h> // for wakelock consolidation
 #include <GnssUtils.h>
 
-#include <cutils/log.h>  // for ALOGE
+#include <android/log.h>  // for ALOGE
 #include <vector>
 
 namespace android {
diff --git a/gnss/1.0/default/ThreadCreationWrapper.h b/gnss/1.0/default/ThreadCreationWrapper.h
index df0a9e4..f401ce2 100644
--- a/gnss/1.0/default/ThreadCreationWrapper.h
+++ b/gnss/1.0/default/ThreadCreationWrapper.h
@@ -17,9 +17,9 @@
 #ifndef ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H
 #define ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H
 
+#include <log/log.h>
 #include <pthread.h>
 #include <vector>
-#include <cutils/log.h>
 
 typedef void (*threadEntryFunc)(void* ret);
 
diff --git a/health/storage/1.0/default/Storage.cpp b/health/storage/1.0/default/Storage.cpp
index 2e53c50..561deaa 100644
--- a/health/storage/1.0/default/Storage.cpp
+++ b/health/storage/1.0/default/Storage.cpp
@@ -36,27 +36,20 @@
 using base::Trim;
 using base::WriteStringToFd;
 using base::WriteStringToFile;
+using fs_mgr::Fstab;
+using fs_mgr::ReadDefaultFstab;
 
 std::string getGarbageCollectPath() {
-    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
-                                                               fs_mgr_free_fstab);
-    struct fstab_rec* rec = NULL;
+    Fstab fstab;
+    ReadDefaultFstab(&fstab);
 
-    for (int i = 0; i < fstab->num_entries; i++) {
-        if (fs_mgr_has_sysfs_path(&fstab->recs[i])) {
-            rec = &fstab->recs[i];
-            break;
+    for (const auto& entry : fstab) {
+        if (!entry.sysfs_path.empty()) {
+            return entry.sysfs_path + "/manual_gc";
         }
     }
-    if (!rec) {
-        return "";
-    }
 
-    std::string path;
-    path.append(rec->sysfs_path);
-    path = path + "/manual_gc";
-
-    return path;
+    return "";
 }
 
 Return<void> Storage::garbageCollect(uint64_t timeoutSeconds,
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp
index 6fabbde..7d3e6f2 100644
--- a/keymaster/3.0/default/KeymasterDevice.cpp
+++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -19,7 +19,7 @@
 
 #include "KeymasterDevice.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include <AndroidKeymaster3Device.h>
 #include <hardware/keymaster0.h>
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 2920cec..52d6328 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -23,6 +23,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     export_include_dirs: ["."],
     shared_libs: [
+        "libfmq",
         "libnativewindow",
     ],
     static_libs: [
@@ -51,6 +52,7 @@
         "VtsHalNeuralnetworks.cpp",
     ],
     shared_libs: [
+        "libfmq",
         "libnativewindow",
     ],
     static_libs: [
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 65c425e..c2ecd9a 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "Callbacks.h"
+#include "ExecutionBurstController.h"
 #include "TestHarness.h"
 #include "Utils.h"
 
@@ -109,14 +110,24 @@
     }
     return result;
 }
-enum class Synchronously { NO, YES };
+static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+        const sp<V1_0::IPreparedModel>&) {
+    ADD_FAILURE() << "asking for burst execution at V1_0";
+    return nullptr;
+}
+static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+        const sp<V1_2::IPreparedModel>& preparedModel) {
+    return ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
+}
+enum class Executor { ASYNC, SYNC, BURST };
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
 const float kDefaultAtol = 1e-5f;
 const float kDefaultRtol = 1e-5f;
 template <typename T_IPreparedModel>
 void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
                            const std::vector<MixedTypedExample>& examples,
                            bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
-                           Synchronously sync, MeasureTiming measure, bool testDynamicOutputShape) {
+                           Executor executor, MeasureTiming measure, OutputType outputType) {
     const uint32_t INPUT = 0;
     const uint32_t OUTPUT = 1;
 
@@ -164,8 +175,20 @@
 
         // Go through all outputs, initialize RequestArgument descriptors
         resize_accordingly(golden, test);
-        for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) {
+        bool sizeLargerThanOne = true;
+        for_all(golden, [&outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
+                                int index, auto, auto s) {
             if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+            if (index == 0) {
+                // On OutputType::INSUFFICIENT, set the output operand with index 0 with
+                // buffer size one byte less than needed.
+                if (outputType == OutputType::INSUFFICIENT) {
+                    if (s > 1)
+                        s -= 1;
+                    else
+                        sizeLargerThanOne = false;
+                }
+            }
             RequestArgument arg = {
                 .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
                 .dimensions = {},
@@ -173,6 +196,9 @@
             outputs_info[index] = arg;
             outputSize += s;
         });
+        // If output0 does not have size larger than one byte,
+        // we can not provide an insufficient buffer
+        if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return;
         // Compute offset for outputs 1 and so on
         {
             size_t offset = 0;
@@ -209,46 +235,73 @@
         inputMemory->commit();
         outputMemory->commit();
 
+        const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
+
         ErrorStatus executionStatus;
         hidl_vec<OutputShape> outputShapes;
         Timing timing;
-        if (sync == Synchronously::NO) {
-            SCOPED_TRACE("asynchronous");
+        switch (executor) {
+            case Executor::ASYNC: {
+                SCOPED_TRACE("asynchronous");
 
-            // launch execution
-            sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-            ASSERT_NE(nullptr, executionCallback.get());
-            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
-                    preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools},
-                    measure, executionCallback);
-            ASSERT_TRUE(executionLaunchStatus.isOk());
-            EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+                // launch execution
+                sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+                ASSERT_NE(nullptr, executionCallback.get());
+                Return<ErrorStatus> executionLaunchStatus =
+                        ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+                ASSERT_TRUE(executionLaunchStatus.isOk());
+                EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
-            // retrieve execution status
-            executionCallback->wait();
-            executionStatus = executionCallback->getStatus();
-            outputShapes = executionCallback->getOutputShapes();
-            timing = executionCallback->getTiming();
-        } else {
-            SCOPED_TRACE("synchronous");
+                // retrieve execution status
+                executionCallback->wait();
+                executionStatus = executionCallback->getStatus();
+                outputShapes = executionCallback->getOutputShapes();
+                timing = executionCallback->getTiming();
 
-            // execute
-            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
-                    preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools},
-                    measure, &outputShapes, &timing);
-            ASSERT_TRUE(executionReturnStatus.isOk());
-            executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
+                break;
+            }
+            case Executor::SYNC: {
+                SCOPED_TRACE("synchronous");
+
+                // execute
+                Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                        preparedModel, request, measure, &outputShapes, &timing);
+                ASSERT_TRUE(executionReturnStatus.isOk());
+                executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
+
+                break;
+            }
+            case Executor::BURST: {
+                SCOPED_TRACE("burst");
+
+                // create burst
+                const std::unique_ptr<::android::nn::ExecutionBurstController> controller =
+                        CreateBurst(preparedModel);
+                ASSERT_NE(nullptr, controller.get());
+
+                // create memory keys
+                std::vector<intptr_t> keys(request.pools.size());
+                for (size_t i = 0; i < keys.size(); ++i) {
+                    keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+                }
+
+                // execute burst
+                std::tie(executionStatus, outputShapes, timing) =
+                        controller->compute(request, measure, keys);
+
+                break;
+            }
         }
 
-        if (testDynamicOutputShape && executionStatus != ErrorStatus::NONE) {
+        if (outputType != OutputType::FULLY_SPECIFIED &&
+            executionStatus == ErrorStatus::GENERAL_FAILURE) {
             LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
                          "execute model that it does not support.";
             std::cout << "[          ]   Early termination of test because vendor service cannot "
                          "execute model that it does not support."
                       << std::endl;
-            return;
+            GTEST_SKIP();
         }
-        ASSERT_EQ(ErrorStatus::NONE, executionStatus);
         if (measure == MeasureTiming::NO) {
             EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
             EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
@@ -258,9 +311,28 @@
             }
         }
 
+        switch (outputType) {
+            case OutputType::FULLY_SPECIFIED:
+                // If the model output operands are fully specified, outputShapes must be either
+                // either empty, or have the same number of elements as the number of outputs.
+                ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+                ASSERT_TRUE(outputShapes.size() == 0 ||
+                            outputShapes.size() == test.operandDimensions.size());
+                break;
+            case OutputType::UNSPECIFIED:
+                // If the model output operands are not fully specified, outputShapes must have
+                // the same number of elements as the number of outputs.
+                ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+                ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
+                break;
+            case OutputType::INSUFFICIENT:
+                ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+                ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
+                ASSERT_FALSE(outputShapes[0].isSufficient);
+                return;
+        }
         // Go through all outputs, overwrite output dimensions with returned output shapes
-        if (testDynamicOutputShape) {
-            ASSERT_NE(outputShapes.size(), 0);
+        if (outputShapes.size() > 0) {
             for_each<uint32_t>(test.operandDimensions,
                                [&outputShapes](int idx, std::vector<uint32_t>& dim) {
                                    dim = outputShapes[idx].dimensions;
@@ -286,10 +358,10 @@
 template <typename T_IPreparedModel>
 void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
                            const std::vector<MixedTypedExample>& examples,
-                           bool hasRelaxedFloat32Model, Synchronously sync, MeasureTiming measure,
-                           bool testDynamicOutputShape) {
+                           bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure,
+                           OutputType outputType) {
     EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol,
-                          kDefaultRtol, sync, measure, testDynamicOutputShape);
+                          kDefaultRtol, executor, measure, outputType);
 }
 
 static void getPreparedModel(sp<PreparedModelCallback> callback,
@@ -338,15 +410,15 @@
         std::cout << "[          ]   Early termination of test because vendor service cannot "
                      "prepare model that it does not support."
                   << std::endl;
-        return;
+        GTEST_SKIP();
     }
     EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
     ASSERT_NE(nullptr, preparedModel.get());
 
     float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f;
     EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Synchronously::NO,
-                          MeasureTiming::NO, /*testDynamicOutputShape=*/false);
+                          /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC,
+                          MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
 }
 
 void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
@@ -386,14 +458,14 @@
         std::cout << "[          ]   Early termination of test because vendor service cannot "
                      "prepare model that it does not support."
                   << std::endl;
-        return;
+        GTEST_SKIP();
     }
     EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
     ASSERT_NE(nullptr, preparedModel.get());
 
     EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Synchronously::NO,
-                          MeasureTiming::NO, /*testDynamicOutputShape=*/false);
+                          model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC,
+                          MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
 }
 
 // TODO: Reduce code duplication.
@@ -435,23 +507,68 @@
         std::cout << "[          ]   Early termination of test because vendor service cannot "
                      "prepare model that it does not support."
                   << std::endl;
-        return;
+        GTEST_SKIP();
     }
     EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
     ASSERT_NE(nullptr, preparedModel.get());
 
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, Synchronously::NO,
-                          MeasureTiming::NO, testDynamicOutputShape);
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, Synchronously::YES,
-                          MeasureTiming::NO, testDynamicOutputShape);
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, Synchronously::NO,
-                          MeasureTiming::YES, testDynamicOutputShape);
-    EvaluatePreparedModel(preparedModel, is_ignored, examples,
-                          model.relaxComputationFloat32toFloat16, Synchronously::YES,
-                          MeasureTiming::YES, testDynamicOutputShape);
+    if (testDynamicOutputShape) {
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::ASYNC,
+                              MeasureTiming::NO, OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::SYNC,
+                              MeasureTiming::NO, OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::BURST,
+                              MeasureTiming::NO, OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::ASYNC,
+                              MeasureTiming::YES, OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::SYNC,
+                              MeasureTiming::YES, OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::BURST,
+                              MeasureTiming::YES, OutputType::UNSPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::ASYNC,
+                              MeasureTiming::NO, OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::SYNC,
+                              MeasureTiming::NO, OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::BURST,
+                              MeasureTiming::NO, OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::ASYNC,
+                              MeasureTiming::YES, OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::SYNC,
+                              MeasureTiming::YES, OutputType::INSUFFICIENT);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::BURST,
+                              MeasureTiming::YES, OutputType::INSUFFICIENT);
+    } else {
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::ASYNC,
+                              MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::SYNC,
+                              MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::BURST,
+                              MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::ASYNC,
+                              MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::SYNC,
+                              MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+        EvaluatePreparedModel(preparedModel, is_ignored, examples,
+                              model.relaxComputationFloat32toFloat16, Executor::BURST,
+                              MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+    }
 }
 
 }  // namespace generated_tests
diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal
index 6c3b483..de249b0 100644
--- a/neuralnetworks/1.2/IDevice.hal
+++ b/neuralnetworks/1.2/IDevice.hal
@@ -98,6 +98,25 @@
             generates (ErrorStatus status, vec<bool> supportedOperations);
 
     /**
+     * Gets whether the driver supports compilation caching.
+     *
+     * isCachingSupported indicates whether the driver supports compilation caching.
+     * Even if so, the driver may still choose not to cache certain compiled models.
+     *
+     * If the device reports the caching is not supported, the user may avoid calling
+     * IDevice::prepareModelFromCache and IPreparedModel::saveToCache.
+     *
+     * @return status Error status of the call, must be:
+     *     - NONE if successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if there is an unspecified error
+     * @return supported A boolean indicating whether the driver supports compilation
+     *                   caching. Even on returning true, the driver may still choose
+     *                   not to cache certain compiled models.
+     */
+    isCachingSupported() generates (ErrorStatus status, bool supported);
+
+    /**
      * Creates a prepared model for execution.
      *
      * prepareModel is used to make any necessary transformations or alternative
@@ -153,4 +172,84 @@
     prepareModel_1_2(Model model, ExecutionPreference preference,
                      IPreparedModelCallback callback)
           generates (ErrorStatus status);
+
+    /**
+     * Creates a prepared model from cache files for execution.
+     *
+     * prepareModelFromCache is used to retrieve a prepared model directly from
+     * cache files to avoid slow model compilation time. There are exactly two
+     * cache file descriptors provided to the driver: modelCache and dataCache.
+     *
+     * The dataCache is for caching constant data, possibly including preprocessed
+     * and transformed tensor buffers. Any modification to the dataCache should
+     * have no worse effect than generating bad output values at execution time.
+     *
+     * The modelCache is for caching security-sensitive data such as compiled
+     * executable machine code in the device's native binary format. A modification
+     * to the modelCache may affect the driver's execution behavior, and a malicious
+     * client could make use of this to execute beyond the granted permission. Thus,
+     * the driver must always check whether the modelCache is corrupted before preparing
+     * the model from cache.
+     *
+     * The two file descriptors may be closed by the client once the asynchronous
+     * preparation has finished. The driver has to copy all the data it needs.
+     *
+     * The model is prepared asynchronously with respect to the caller. The
+     * prepareModelFromCache function must verify the inputs to the
+     * prepareModelFromCache function are correct, and that the security-sensitive
+     * cache has not been modified since it was last written by the driver.
+     * If there is an error, or if compilation caching is not supported, or if the
+     * security-sensitive cache has been modified, prepareModelFromCache must
+     * immediately invoke the callback with the appropriate ErrorStatus value and
+     * nullptr for the IPreparedModel, then return with the same ErrorStatus. If
+     * the inputs to the prepareModelFromCache function are valid, the security-sensitive
+     * cache is not modified, and there is no error, prepareModelFromCache must launch an
+     * asynchronous task to prepare the model in the background, and immediately return
+     * from prepareModelFromCache with ErrorStatus::NONE. If the asynchronous task
+     * fails to launch, prepareModelFromCache must immediately invoke the callback
+     * with ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then
+     * return with ErrorStatus::GENERAL_FAILURE.
+     *
+     * When the asynchronous task has finished preparing the model, it must
+     * immediately invoke the callback function provided as an input to
+     * prepareModelFromCache. If the model was prepared successfully, the
+     * callback object must be invoked with an error status of ErrorStatus::NONE
+     * and the produced IPreparedModel object. If an error occurred preparing
+     * the model, the callback object must be invoked with the appropriate
+     * ErrorStatus value and nullptr for the IPreparedModel.
+     *
+     * The only information that may be unknown to the model at this stage is
+     * the shape of the tensors, which may only be known at execution time. As
+     * such, some driver services may return partially prepared models, where
+     * the prepared model may only be finished when it is paired with a set of
+     * inputs to the model. Note that the same prepared model object may be
+     * used with different shapes of inputs on different (possibly concurrent)
+     * executions.
+     *
+     * @param modelCache A handle holding exactly one cache file descriptor for the
+     *     security-sensitive cache.
+     * @param dataCache A handle holding exactly one cache file descriptor for the
+     *     constants' cache.
+     * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
+     *     identifying the prepared model. It is the same token provided when saving
+     *     the cache files with IPreparedModel::saveToCache. Tokens should be chosen
+     *     to have a low rate of collision for a particular application. The driver
+     *     cannot detect a collision; a collision will result in a failed execution
+     *     or in a successful execution that produces incorrect output values.
+     * @param callback A callback object used to return the error status of
+     *     preparing the model for execution and the prepared model if
+     *     successful, nullptr otherwise. The callback object's notify function
+     *     must be called exactly once, even if the model could not be prepared.
+     * @return status Error status of launching a task which prepares the model
+     *     in the background; must be:
+     *     - NONE if preparation task is successfully launched
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if caching is not supported or if there is an
+     *       unspecified error
+     *     - INVALID_ARGUMENT if one of the input arguments is invalid
+     */
+    prepareModelFromCache(handle modelCache, handle dataCache,
+                          uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
+                          IPreparedModelCallback callback)
+            generates (ErrorStatus status);
 };
diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal
index 5d2d80f..757d5f1 100644
--- a/neuralnetworks/1.2/IPreparedModel.hal
+++ b/neuralnetworks/1.2/IPreparedModel.hal
@@ -157,4 +157,62 @@
                             fmq_sync<FmqRequestDatum> requestChannel,
                             fmq_sync<FmqResultDatum> resultChannel)
                  generates (ErrorStatus status, IBurstContext context);
+
+    /*
+     * Saves the prepared model to cache files.
+     *
+     * saveToCache is used to save a prepared model to cache files for faster
+     * model compilation time when the same model preparation is requested in
+     * the future. There are exactly two cache file descriptors provided to the
+     * driver: modelCache and dataCache.
+     *
+     * The dataCache is for caching constant data, possibly including preprocessed
+     * and transformed tensor buffers. Any modification to the dataCache should
+     * have no worse effect than generating bad output values at execution time.
+     *
+     * The modelCache is for caching security-sensitive data such as compiled
+     * executable machine code in the device's native binary format. A modification
+     * to the modelCache may affect the driver's execution behavior, and a malicious
+     * client could make use of this to execute beyond the granted permission. Thus,
+     * the driver must always check whether the modelCache is corrupted before preparing
+     * the model from cache.
+     *
+     * The two file descriptors must point to two zero-length files with offset
+     * positioned at the beginning of the file. The file descriptors may be closed
+     * by the client once the method has returned.
+     *
+     * If the driver decides not to save the prepared model without looking at the
+     * input arguments to the saveToCache function, saveToCache must return with
+     * ErrorStatus::GENERAL_FAILURE. Otherwise, the saveToCache function must verify
+     * the input arguments to the saveToCache function are valid, and return with
+     * ErrorStatus::INVALID_ARGUMENT if not. If the inputs are valid but the driver
+     * could not save the prepared model, saveToCache must return with the appropriate
+     * ErrorStatus. Otherwise, it must write the cache files and return
+     * ErrorStatus::NONE. Unless saveToCache returns ErrorStatus::NONE, the contents
+     * of the cache files are undefined.
+     *
+     * @param modelCache A handle holding exactly one cache file descriptor for the
+     *                   security-sensitive cache.
+     * @param dataCache A handle holding exactly one cache file descriptor for the
+     *                  constants' cache.
+     * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
+     *              identifying the prepared model. The same token will be provided
+     *              when retrieving the prepared model from cache files with
+     *              IDevice::prepareModelFromCache. Tokens should be chosen to have
+     *              a low rate of collision for a particular application. The driver
+     *              cannot detect a collision; a collision will result in a failed
+     *              execution or in a successful execution that produces incorrect
+     *              output values.
+     * @return status Error status of saveToCache, must be:
+     *                - NONE if saveToCache is performed successfully
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if the driver could not save the
+     *                  prepared model or if there is an unspecified error
+     *                - INVALID_ARGUMENT if one of the input arguments is invalid,
+     *                  unless the driver decides not to save the prepared model
+     *                  without looking at the input arguments
+     */
+    saveToCache(handle modelCache, handle dataCache,
+                uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token)
+        generates (ErrorStatus status);
 };
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index bd8354f..4d5f0f4 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -25,6 +25,13 @@
 
 import android.hidl.safe_union@1.0::Monostate;
 
+enum Constant : uint32_t {
+    /**
+     * The byte size of the cache token.
+     */
+    BYTE_SIZE_OF_CACHE_TOKEN = 32,
+};
+
 enum OperandType : @1.0::OperandType {
     /**
      * An 8 bit boolean scalar value.
@@ -90,10 +97,10 @@
      */
     TENSOR_QUANT16_ASYMM = 12,
     /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
-     * OperandTypeRange::OPERAND_FUNDAMENTAL_MAX.
+     * OperandTypeRange::FUNDAMENTAL_MAX.
      */
     /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF
-     * OperandTypeRange::OPERAND_OEM_MAX.
+     * OperandTypeRange::OEM_MAX.
      */
 };
 
@@ -101,10 +108,10 @@
  * The range of operand values in the OperandType enum.
  */
 enum OperandTypeRange : uint32_t {
-    OPERAND_FUNDAMENTAL_MIN = 0,
-    OPERAND_FUNDAMENTAL_MAX = 12,
-    OPERAND_OEM_MIN     = 10000,
-    OPERAND_OEM_MAX     = 10001,
+    FUNDAMENTAL_MIN = 0,
+    FUNDAMENTAL_MAX = 12,
+    OEM_MIN     = 10000,
+    OEM_MAX     = 10001,
 };
 
 /**
@@ -171,10 +178,10 @@
     UNIDIRECTIONAL_SEQUENCE_LSTM = 92,
     UNIDIRECTIONAL_SEQUENCE_RNN = 93,
     /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
-     * OperationTypeRange::OPERATION_FUNDAMENTAL_MAX.
+     * OperationTypeRange::FUNDAMENTAL_MAX.
      */
     /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF
-     * OperationTypeRange::OPERATION_OEM_MAX.
+     * OperationTypeRange::OEM_MAX.
      */
 };
 
@@ -182,10 +189,10 @@
  * The range of values in the OperationType enum.
  */
 enum OperationTypeRange : uint32_t {
-    OPERATION_FUNDAMENTAL_MIN = 0,
-    OPERATION_FUNDAMENTAL_MAX = 93,
-    OPERATION_OEM_MIN = 10000,
-    OPERATION_OEM_MAX = 10000,
+    FUNDAMENTAL_MIN = 0,
+    FUNDAMENTAL_MAX = 93,
+    OEM_MIN = 10000,
+    OEM_MAX = 10000,
 };
 
 /**
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index bee2556..afa8e5f 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -128,10 +128,10 @@
 ///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
 
 static const uint32_t invalidOperandTypes[] = {
-    static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MIN) - 1,
-    static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MAX) + 1,
-    static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MIN) - 1,
-    static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MAX) + 1,
+        static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN) - 1,
+        static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX) + 1,
+        static_cast<uint32_t>(OperandTypeRange::OEM_MIN) - 1,
+        static_cast<uint32_t>(OperandTypeRange::OEM_MAX) + 1,
 };
 
 static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
@@ -387,10 +387,10 @@
 ///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
 
 static const uint32_t invalidOperationTypes[] = {
-    static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MIN) - 1,
-    static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MAX) + 1,
-    static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MIN) - 1,
-    static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MAX) + 1,
+        static_cast<uint32_t>(OperationTypeRange::FUNDAMENTAL_MIN) - 1,
+        static_cast<uint32_t>(OperationTypeRange::FUNDAMENTAL_MAX) + 1,
+        static_cast<uint32_t>(OperationTypeRange::OEM_MIN) - 1,
+        static_cast<uint32_t>(OperationTypeRange::OEM_MAX) + 1,
 };
 
 static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 00a7c3e..d411da4 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -19,6 +19,7 @@
 #include "VtsHalNeuralnetworks.h"
 
 #include "Callbacks.h"
+#include "ExecutionBurstController.h"
 #include "TestHarness.h"
 #include "Utils.h"
 
@@ -112,6 +113,7 @@
     };
     MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
 
+    // asynchronous
     {
         SCOPED_TRACE(message + " [execute_1_2]");
 
@@ -131,6 +133,7 @@
         ASSERT_TRUE(badTiming(timing));
     }
 
+    // synchronous
     {
         SCOPED_TRACE(message + " [executeSynchronously]");
 
@@ -144,6 +147,43 @@
                 });
         ASSERT_TRUE(executeStatus.isOk());
     }
+
+    // burst
+    {
+        SCOPED_TRACE(message + " [burst]");
+
+        // create burst
+        std::unique_ptr<::android::nn::ExecutionBurstController> burst =
+                ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
+        ASSERT_NE(nullptr, burst.get());
+
+        // create memory keys
+        std::vector<intptr_t> keys(request.pools.size());
+        for (size_t i = 0; i < keys.size(); ++i) {
+            keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+        }
+
+        // execute and verify
+        ErrorStatus error;
+        std::vector<OutputShape> outputShapes;
+        Timing timing;
+        std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys);
+        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+        EXPECT_EQ(outputShapes.size(), 0);
+        EXPECT_TRUE(badTiming(timing));
+
+        // additional burst testing
+        if (request.pools.size() > 0) {
+            // valid free
+            burst->freeMemory(keys.front());
+
+            // negative test: invalid free of unknown (blank) memory
+            burst->freeMemory(intptr_t{});
+
+            // negative test: double free of memory
+            burst->freeMemory(keys.front());
+        }
+    }
 }
 
 // Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 17718e0..8393cf5 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -1230,85 +1230,108 @@
 
 struct GsmSignalStrength {
     uint32_t signalStrength;              // Valid values are (0-61, 99) as defined in
-                                          // TS 27.007 8.69
-    uint32_t bitErrorRate;                // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+                                          // TS 27.007 8.69; INT_MAX means invalid/unreported.
+    uint32_t bitErrorRate;                // bit error rate (0-7, 99) as defined in TS 27.007 8.5;
+                                          // INT_MAX means invalid/unreported.
     int32_t timingAdvance;                // Timing Advance in bit periods. 1 bit period = 48/13 us.
-                                          // INT_MAX denotes invalid value
+                                          // INT_MAX means invalid/unreported.
 };
 
 struct WcdmaSignalStrength{
     int32_t signalStrength;               // Valid values are (0-31, 99) as defined in
-                                          // TS 27.007 8.5
-    int32_t bitErrorRate;                 // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+                                          // TS 27.007 8.5; INT_MAX means unreported.
+    int32_t bitErrorRate;                 // bit error rate (0-7, 99) as defined in TS 27.007 8.5;
+                                          // INT_MAX means invalid/unreported.
 };
 
 struct CdmaSignalStrength {
     uint32_t dbm;                         // This value is the actual RSSI
                                           // value multiplied by -1. Example: If the
                                           // actual RSSI is -75, then this response value will
-                                          // be 75.
+                                          // be 75. INT_MAX means invalid/unreported.
     uint32_t ecio;                        // This value is the actual
                                           // Ec/Io multiplied by -10. Example: If the
                                           // actual Ec/Io is -12.5 dB, then this response value
-                                          // will be 125.
+                                          // will be 125. INT_MAX means invalid/unreported.
 };
 
 struct EvdoSignalStrength {
     uint32_t dbm;                         // This value is the actual
                                           // RSSI value multiplied by -1.
                                           // Example: If the actual RSSI is -75,
-                                          // then this response value will be 75.
+                                          // then this response value will be 75; INT_MAX means
+                                          // invalid/unreported.
     uint32_t ecio;                        // This value is the actual
                                           // Ec/Io multiplied by -10. Example: If the
                                           // actual Ec/Io is -12.5 dB, then this response value
-                                          // will be 125.
+                                          // will be 125; INT_MAX means invalid/unreported.
     uint32_t signalNoiseRatio;            // Valid values are 0-8. 8 is the highest signal to
-                                          // noise ratio.
+                                          // noise ratio; INT_MAX means invalid/unreported.
 };
 
 struct LteSignalStrength {
     uint32_t signalStrength;              // Valid values are (0-31, 99) as defined in
-                                          // TS 27.007 8.5
+                                          // TS 27.007 8.5; INT_MAX means invalid/unreported.
     uint32_t rsrp;                        // The current Reference Signal Receive Power in dBm
                                           // multipled by -1.
-                                          // Range: 44 to 140 dBm
-                                          // INT_MAX: 0x7FFFFFFF denotes invalid value.
+                                          // Range: 44 to 140 dBm;
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.133 9.1.4
     uint32_t rsrq;                        // The current Reference Signal Receive Quality in dB
                                           // multiplied by -1.
-                                          // Range: 20 to 3 dB.
-                                          // INT_MAX: 0x7FFFFFFF denotes invalid value.
+                                          // Range: 20 to 3 dB;
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.133 9.1.7
     int32_t rssnr;                        // The current reference signal signal-to-noise ratio in
                                           // 0.1 dB units.
                                           // Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
-                                          // INT_MAX : 0x7FFFFFFF denotes invalid value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.101 8.1.1
     uint32_t cqi;                         // The current Channel Quality Indicator.
                                           // Range: 0 to 15.
-                                          // INT_MAX : 0x7FFFFFFF denotes invalid value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.101 9.2, 9.3, A.4
     uint32_t timingAdvance;               // timing advance in micro seconds for a one way trip
                                           // from cell to device.
                                           // Approximate distance is calculated using
                                           // 300m/us * timingAdvance.
                                           // Range: 0 to 1282 inclusive.
-                                          // INT_MAX : 0x7FFFFFFF denotes unknown value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP 36.213 section 4.2.3
 };
 
 struct TdScdmaSignalStrength {
     uint32_t rscp;                        // The Received Signal Code Power in dBm multiplied by -1.
                                           // Range : 25 to 120
-                                          // INT_MAX: 0x7FFFFFFF denotes invalid value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 25.123, section 9.1.1.1
 };
 
 struct SignalStrength {
+    /**
+     * If GSM measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     GsmSignalStrength gw;
+    /**
+     * If CDMA measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     CdmaSignalStrength cdma;
+    /**
+     * If EvDO measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     EvdoSignalStrength evdo;
+    /**
+     * If LTE measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     LteSignalStrength lte;
+    /**
+     * If TD-SCDMA measurements are provided, this structure must contain valid measurements;
+     * otherwise all fields should be set to INT_MAX to mark them as invalid.
+     */
     TdScdmaSignalStrength tdScdma;
 };
 
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 4715fac..2dceeb1 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -427,11 +427,13 @@
     /**
      * CPICH RSCP as defined in TS 25.215 5.1.1
      * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t rscp;
     /**
      * Ec/No value as defined in TS 25.215 5.1.5
      * Valid values are (0-49, 255) as defined in TS 27.007 8.69
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t ecno;
 
@@ -441,26 +443,53 @@
     /**
      * UTRA carrier RSSI as defined in TS 25.225 5.1.4
      * Valid values are (0-31, 99) as defined in TS 27.007 8.5
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t signalStrength;
     /**
      * Transport Channel BER as defined in TS 25.225 5.2.5
      * Valid values are (0-7, 99) as defined in TS 27.007 8.5
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t bitErrorRate;
     /**
      * P-CCPCH RSCP as defined in TS 25.225 5.1.1
      * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t rscp;
 };
 
 struct SignalStrength {
+    /**
+     * If GSM measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     GsmSignalStrength gsm;
+    /**
+     * If CDMA measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     CdmaSignalStrength cdma;
+    /**
+     * If EvDO measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     EvdoSignalStrength evdo;
+    /**
+     * If LTE measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     LteSignalStrength lte;
+    /**
+     * If TD-SCDMA measurements are provided, this structure must contain valid measurements;
+     * otherwise all fields should be set to INT_MAX to mark them as invalid.
+     */
     TdScdmaSignalStrength tdScdma;
+    /**
+     * If WCDMA measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     WcdmaSignalStrength wcdma;
 };