Merge "Enable Rust backend for NFC AIDL HAL" into main
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
index 818b18e..6b69845 100644
--- a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
@@ -14,8 +14,8 @@
 
 // To render: dot -Tpng stream-in-async-sm.gv -o stream-in-async-sm.png
 digraph stream_in_async_state_machine {
-    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
-    node [shape=point width=0.5] F;
+    node [shape=point style=filled fillcolor=black width=0.5] I;
+    node [shape=doublecircle width=0.5] F;
     node [shape=oval width=1];
     node [fillcolor=lightgreen] STANDBY;  // buffer is empty
     node [fillcolor=tomato] CLOSED;
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
index 805dc32..aa7af54 100644
--- a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
@@ -14,8 +14,8 @@
 
 // To render: dot -Tpng stream-in-sm.gv -o stream-in-sm.png
 digraph stream_in_state_machine {
-    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
-    node [shape=point width=0.5] F;
+    node [shape=point style=filled fillcolor=black width=0.5] I;
+    node [shape=doublecircle width=0.5] F;
     node [shape=oval width=1];
     node [fillcolor=lightgreen] STANDBY;  // buffer is empty
     node [fillcolor=tomato] CLOSED;
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index 501dc01..a3f0de9 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -14,8 +14,8 @@
 
 // To render: dot -Tpng stream-out-async-sm.gv -o stream-out-async-sm.png
 digraph stream_out_async_state_machine {
-    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
-    node [shape=point width=0.5] F;
+    node [shape=point style=filled fillcolor=black width=0.5] I;
+    node [shape=doublecircle width=0.5] F;
     node [shape=oval width=1];
     node [fillcolor=lightgreen] STANDBY;  // buffer is empty
     node [fillcolor=lightgreen] IDLE;     // buffer is empty
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
index 47e7fda..23fb5d9 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -14,8 +14,8 @@
 
 // To render: dot -Tpng stream-out-sm.gv -o stream-out-sm.png
 digraph stream_out_state_machine {
-    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
-    node [shape=point width=0.5] F;
+    node [shape=point style=filled fillcolor=black width=0.5] I;
+    node [shape=doublecircle width=0.5] F;
     node [shape=oval width=1];
     node [fillcolor=lightgreen] STANDBY;  // buffer is empty
     node [fillcolor=lightgreen] IDLE;     // buffer is empty
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index c88521e..ce369ba 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -25,12 +25,12 @@
 
     I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"];
     INIT -> F[label = "IFactory.destroyEffect"];
-    INIT -> IDLE[label = "open()" labelfontcolor = "lime"];
-    IDLE -> PROCESSING[label = "command(START"];
-    PROCESSING -> IDLE[label = "command(STOP)\ncommand(RESET)"];
-    IDLE -> INIT[label = "close()"];
+    INIT -> IDLE[label = "IEffect.open()" labelfontcolor = "lime"];
+    IDLE -> PROCESSING[label = "IEffect.command(START"];
+    PROCESSING -> IDLE[label = "IEffect.command(STOP)\nIEffect.command(RESET)"];
+    IDLE -> INIT[label = "IEffect.close()"];
 
-    INIT -> INIT[label = "getState\ngetDescriptor"];
-    IDLE -> IDLE[label = "getXXX\nsetParameter\ncommand(RESET)"];
-    PROCESSING -> PROCESSING[label = "getXXX\nsetParameter"];
+    INIT -> INIT[label = "IEffect.getState\nIEffect.getDescriptor"];
+    IDLE -> IDLE[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)"];
+    PROCESSING -> PROCESSING[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor"];
 }
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index 0d2121c..8107655 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -106,6 +106,9 @@
         std::lock_guard<std::mutex> lock(mWorkerLock);
         mWorkerState = error.empty() ? WorkerState::RUNNING : WorkerState::STOPPED;
         mError = error;
+#if defined(__ANDROID__)
+        mTid = pthread_gettid_np(pthread_self());
+#endif
     }
     mWorkerCv.notify_one();
     if (!error.empty()) return;
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index e9c1070..efdcc81 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <sys/types.h>
+
 #include <atomic>
 #include <condition_variable>
 #include <mutex>
@@ -52,6 +54,10 @@
         std::lock_guard<std::mutex> lock(mWorkerLock);
         return mError;
     }
+    pid_t getTid() {
+        std::lock_guard<std::mutex> lock(mWorkerLock);
+        return mTid;
+    }
     void stop();
     // Direct use of 'join' assumes that the StreamLogic is not intended
     // to run forever, and is guaranteed to exit by itself. This normally
@@ -78,6 +84,7 @@
     std::condition_variable mWorkerCv;
     WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::INITIAL;
     std::string mError GUARDED_BY(mWorkerLock);
+    pid_t mTid GUARDED_BY(mWorkerLock) = -1;
     // The atomic lock-free variable is used to prevent priority inversions
     // that can occur when a high priority worker tries to acquire the lock
     // which has been taken by a lower priority control thread which in its turn
@@ -143,6 +150,7 @@
     void resume() { mThread.resume(); }
     bool hasError() { return mThread.hasError(); }
     std::string getError() { return mThread.getError(); }
+    pid_t getTid() { return mThread.getTid(); }
     void stop() { mThread.stop(); }
     void join() { mThread.join(); }
     bool waitForAtLeastOneCycle() { return mThread.waitForAtLeastOneCycle(); }
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index f7a30b9..2b65740 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -87,6 +87,7 @@
 TEST_P(StreamWorkerInvalidTest, Uninitialized) {
     EXPECT_FALSE(worker.hasWorkerCycleCalled());
     EXPECT_FALSE(worker.hasError());
+    EXPECT_LE(worker.getTid(), 0);
 }
 
 TEST_P(StreamWorkerInvalidTest, UninitializedPauseIgnored) {
@@ -105,6 +106,9 @@
     EXPECT_FALSE(worker.start());
     EXPECT_FALSE(worker.hasWorkerCycleCalled());
     EXPECT_TRUE(worker.hasError());
+#if defined(__ANDROID__)
+    EXPECT_GT(worker.getTid(), 0);
+#endif
 }
 
 TEST_P(StreamWorkerInvalidTest, PauseIgnored) {
@@ -136,12 +140,16 @@
 TEST_P(StreamWorkerTest, Uninitialized) {
     EXPECT_FALSE(worker.hasWorkerCycleCalled());
     EXPECT_FALSE(worker.hasError());
+    EXPECT_LE(worker.getTid(), 0);
 }
 
 TEST_P(StreamWorkerTest, Start) {
     ASSERT_TRUE(worker.start());
     EXPECT_TRUE(worker.waitForAtLeastOneCycle());
     EXPECT_FALSE(worker.hasError());
+#if defined(__ANDROID__)
+    EXPECT_GT(worker.getTid(), 0);
+#endif
 }
 
 TEST_P(StreamWorkerTest, StartStop) {
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 19b2397..bb8d76f 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -76,13 +76,18 @@
         "ModulePrimary.cpp",
         "SoundDose.cpp",
         "Stream.cpp",
+        "StreamSwitcher.cpp",
         "Telephony.cpp",
         "alsa/Mixer.cpp",
         "alsa/ModuleAlsa.cpp",
         "alsa/StreamAlsa.cpp",
         "alsa/Utils.cpp",
+        "bluetooth/DevicePortProxy.cpp",
+        "bluetooth/ModuleBluetooth.cpp",
+        "bluetooth/StreamBluetooth.cpp",
+        "primary/PrimaryMixer.cpp",
+        "primary/StreamPrimary.cpp",
         "r_submix/ModuleRemoteSubmix.cpp",
-        "r_submix/RemoteSubmixUtils.cpp",
         "r_submix/SubmixRoute.cpp",
         "r_submix/StreamRemoteSubmix.cpp",
         "stub/ModuleStub.cpp",
@@ -104,7 +109,9 @@
         "audio_policy_engine_configuration_aidl_default",
     ],
     shared_libs: [
+        "android.hardware.bluetooth.audio-V3-ndk",
         "libaudio_aidl_conversion_common_ndk",
+        "libbluetooth_audio_session_aidl",
         "libmedia_helper",
         "libstagefright_foundation",
     ],
@@ -135,7 +142,9 @@
         "libaudioserviceexampleimpl",
     ],
     shared_libs: [
+        "android.hardware.bluetooth.audio-V3-ndk",
         "libaudio_aidl_conversion_common_ndk",
+        "libbluetooth_audio_session_aidl",
         "libmedia_helper",
         "libstagefright_foundation",
     ],
diff --git a/audio/aidl/default/Bluetooth.cpp b/audio/aidl/default/Bluetooth.cpp
index c32b538..072b89f 100644
--- a/audio/aidl/default/Bluetooth.cpp
+++ b/audio/aidl/default/Bluetooth.cpp
@@ -82,19 +82,18 @@
 
 ndk::ScopedAStatus BluetoothA2dp::isEnabled(bool* _aidl_return) {
     *_aidl_return = mEnabled;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus BluetoothA2dp::setEnabled(bool in_enabled) {
     mEnabled = in_enabled;
     LOG(DEBUG) << __func__ << ": " << mEnabled;
+    if (mHandler) return mHandler();
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus BluetoothA2dp::supportsOffloadReconfiguration(bool* _aidl_return) {
-    *_aidl_return = true;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    *_aidl_return = false;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -102,24 +101,22 @@
         const std::vector<::aidl::android::hardware::audio::core::VendorParameter>& in_parameters
                 __unused) {
     LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(in_parameters);
-    return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
 ndk::ScopedAStatus BluetoothLe::isEnabled(bool* _aidl_return) {
     *_aidl_return = mEnabled;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus BluetoothLe::setEnabled(bool in_enabled) {
     mEnabled = in_enabled;
-    LOG(DEBUG) << __func__ << ": " << mEnabled;
+    if (mHandler) return mHandler();
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus BluetoothLe::supportsOffloadReconfiguration(bool* _aidl_return) {
-    *_aidl_return = true;
-    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    *_aidl_return = false;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -127,7 +124,7 @@
         const std::vector<::aidl::android::hardware::audio::core::VendorParameter>& in_parameters
                 __unused) {
     LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(in_parameters);
-    return ndk::ScopedAStatus::ok();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp
index d1023da..308200a 100644
--- a/audio/aidl/default/Config.cpp
+++ b/audio/aidl/default/Config.cpp
@@ -27,12 +27,11 @@
 
 namespace aidl::android::hardware::audio::core {
 ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) {
+    static const auto& func = __func__;
     static const SurroundSoundConfig surroundSoundConfig = [this]() {
-        SurroundSoundConfig surroundCfg;
-        if (mAudioPolicyConverter.getStatus() == ::android::OK) {
-            surroundCfg = mAudioPolicyConverter.getSurroundSoundConfig();
-        } else {
-            LOG(WARNING) << __func__ << mAudioPolicyConverter.getError();
+        SurroundSoundConfig surroundCfg = mAudioPolicyConverter.getSurroundSoundConfig();
+        if (mAudioPolicyConverter.getStatus() != ::android::OK) {
+            LOG(WARNING) << func << ": " << mAudioPolicyConverter.getError();
         }
         return surroundCfg;
     }();
@@ -42,21 +41,22 @@
 }
 
 ndk::ScopedAStatus Config::getEngineConfig(AudioHalEngineConfig* _aidl_return) {
+    static const auto& func = __func__;
     static const AudioHalEngineConfig returnEngCfg = [this]() {
         AudioHalEngineConfig engConfig;
         if (mEngConfigConverter.getStatus() == ::android::OK) {
             engConfig = mEngConfigConverter.getAidlEngineConfig();
         } else {
-            LOG(INFO) << __func__ << mEngConfigConverter.getError();
+            LOG(INFO) << func << ": " << mEngConfigConverter.getError();
             if (mAudioPolicyConverter.getStatus() == ::android::OK) {
                 engConfig = mAudioPolicyConverter.getAidlEngineConfig();
             } else {
-                LOG(WARNING) << __func__ << mAudioPolicyConverter.getError();
+                LOG(WARNING) << func << ": " << mAudioPolicyConverter.getError();
             }
         }
         // Logging full contents of the config is an overkill, just provide statistics.
-        LOG(DEBUG) << "getEngineConfig: number of strategies parsed: "
-                   << engConfig.productStrategies.size()
+        LOG(DEBUG) << func
+                   << ": number of strategies parsed: " << engConfig.productStrategies.size()
                    << ", default strategy: " << engConfig.defaultProductStrategyId
                    << ", number of volume groups parsed: " << engConfig.volumeGroups.size();
         return engConfig;
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index a71c6ea..8e02e7d 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -81,8 +81,6 @@
         deviceExt.device.address = "bottom";
     } else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) {
         deviceExt.device.address = "back";
-    } else if (devType == AudioDeviceType::IN_SUBMIX || devType == AudioDeviceType::OUT_SUBMIX) {
-        deviceExt.device.address = "0";
     }
     deviceExt.device.type.connection = std::move(connection);
     deviceExt.flags = flags;
@@ -136,7 +134,7 @@
 // Device ports:
 //  * "Speaker", OUT_SPEAKER, default
 //    - no profiles specified
-//  * "Built-in Mic", IN_MICROPHONE, default
+//  * "Built-In Mic", IN_MICROPHONE, default
 //    - no profiles specified
 //  * "Telephony Tx", OUT_TELEPHONY_TX
 //    - no profiles specified
@@ -148,46 +146,35 @@
 // Mix ports:
 //  * "primary output", PRIMARY, 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//  * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
-//    - profile MP3; MONO, STEREO; 44100, 48000
-//  * "primary input", 2 max open, 2 max active streams
-//    - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
-//        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
-//        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+//  * "primary input", 1 max open, 1 max active stream
+//    - profile PCM 16-bit; MONO, STEREO;
+//        8000, 11025, 16000, 32000, 44100, 48000
 //  * "telephony_tx", 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "telephony_rx", 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "fm_tuner", 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
-//  "primary out", "compressed offload" -> "Speaker"
-//  "Built-in Mic" -> "primary input"
-//  "telephony_tx" -> "Telephony Tx"
+//  "primary out" -> "Speaker"
+//  "Built-In Mic" -> "primary input"
 //  "Telephony Rx" -> "telephony_rx"
+//  "telephony_tx" -> "Telephony Tx"
 //  "FM Tuner" -> "fm_tuner"
 //
 // Initial port configs:
-//  * "Speaker" device port: PCM 24-bit; STEREO; 48000
-//  * "Built-in Mic" device port: PCM 24-bit; MONO; 48000
-//  * "Telephony Tx" device port: PCM 24-bit; MONO; 48000
-//  * "Telephony Rx" device port: PCM 24-bit; MONO; 48000
-//  * "FM Tuner" device port: PCM 24-bit; STEREO; 48000
+//  * "Speaker" device port: PCM 16-bit; STEREO; 48000
+//  * "Built-In Mic" device port: PCM 16-bit; MONO; 48000
+//  * "Telephony Tx" device port: PCM 16-bit; MONO; 48000
+//  * "Telephony Rx" device port: PCM 16-bit; MONO; 48000
+//  * "FM Tuner" device port: PCM 16-bit; STEREO; 48000
 //
 std::unique_ptr<Configuration> getPrimaryConfiguration() {
     static const Configuration configuration = []() {
         const std::vector<AudioProfile> standardPcmAudioProfiles = {
                 createProfile(PcmType::INT_16_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {8000, 11025, 16000, 32000, 44100, 48000}),
-                createProfile(PcmType::INT_24_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
                               {8000, 11025, 16000, 32000, 44100, 48000})};
         Configuration c;
 
@@ -199,17 +186,17 @@
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
         c.ports.push_back(speakerOutDevice);
         c.initialConfigs.push_back(
-                createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_24_BIT,
+                createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_16_BIT,
                                  AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
                                  createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
 
         AudioPort micInDevice =
-                createPort(c.nextPortId++, "Built-in Mic", 0, true,
+                createPort(c.nextPortId++, "Built-In Mic", 0, true,
                            createDeviceExt(AudioDeviceType::IN_MICROPHONE,
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
         c.ports.push_back(micInDevice);
         c.initialConfigs.push_back(
-                createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_24_BIT,
+                createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_16_BIT,
                                  AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
                                  createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
 
@@ -219,7 +206,7 @@
         c.ports.push_back(telephonyTxOutDevice);
         c.initialConfigs.push_back(
                 createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
-                                 PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+                                 PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
                                  false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
 
         AudioPort telephonyRxInDevice =
@@ -228,14 +215,14 @@
         c.ports.push_back(telephonyRxInDevice);
         c.initialConfigs.push_back(
                 createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
-                                 PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+                                 PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
                                  true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
 
         AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
                                                createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
         c.ports.push_back(fmTunerInDevice);
         c.initialConfigs.push_back(
-                createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_24_BIT,
+                createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_16_BIT,
                                  AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
                                  createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
 
@@ -249,30 +236,12 @@
                                       standardPcmAudioProfiles.end());
         c.ports.push_back(primaryOutMix);
 
-        AudioPort compressedOffloadOutMix =
-                createPort(c.nextPortId++, "compressed offload",
-                           makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
-                                                    AudioOutputFlags::COMPRESS_OFFLOAD,
-                                                    AudioOutputFlags::NON_BLOCKING}),
-                           false, createPortMixExt(1, 1));
-        compressedOffloadOutMix.profiles.push_back(
-                createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {44100, 48000}));
-        c.ports.push_back(compressedOffloadOutMix);
-
         AudioPort primaryInMix =
-                createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
+                createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(1, 1));
         primaryInMix.profiles.push_back(
                 createProfile(PcmType::INT_16_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
-                               AudioChannelLayout::LAYOUT_FRONT_BACK},
-                              {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
-        primaryInMix.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
-                               AudioChannelLayout::LAYOUT_FRONT_BACK},
-                              {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {8000, 11025, 16000, 32000, 44100, 48000}));
         c.ports.push_back(primaryInMix);
 
         AudioPort telephonyTxOutMix =
@@ -296,10 +265,10 @@
                                      standardPcmAudioProfiles.end());
         c.ports.push_back(fmTunerInMix);
 
-        c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice));
+        c.routes.push_back(createRoute({primaryOutMix}, speakerOutDevice));
         c.routes.push_back(createRoute({micInDevice}, primaryInMix));
-        c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
         c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
+        c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
         c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
@@ -320,15 +289,21 @@
 //
 // Device ports:
 //  * "Remote Submix Out", OUT_SUBMIX
-//    - profile PCM 24-bit; STEREO; 48000
+//    - no profiles specified
 //  * "Remote Submix In", IN_SUBMIX
-//    - profile PCM 24-bit; STEREO; 48000
+//    - no profiles specified
 //
 // Mix ports:
-//  * "r_submix output", stream count unlimited
-//    - profile PCM 24-bit; STEREO; 48000
-//  * "r_submix input", stream count unlimited
-//    - profile PCM 24-bit; STEREO; 48000
+//  * "r_submix output", unlimited max open, unlimited max active stream
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "r_submix input", unlimited max open, unlimited max active stream
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
 //  "r_submix output" -> "Remote Submix Out"
@@ -337,6 +312,19 @@
 std::unique_ptr<Configuration> getRSubmixConfiguration() {
     static const Configuration configuration = []() {
         Configuration c;
+        const std::vector<AudioProfile> standardPcmAudioProfiles{
+                createProfile(PcmType::FLOAT_32_BIT,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {8000, 11025, 16000, 32000, 44100, 48000}),
+                createProfile(PcmType::INT_32_BIT,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {8000, 11025, 16000, 32000, 44100, 48000}),
+                createProfile(PcmType::INT_24_BIT,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {8000, 11025, 16000, 32000, 44100, 48000}),
+                createProfile(PcmType::INT_16_BIT,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {8000, 11025, 16000, 32000, 44100, 48000})};
 
         // Device ports
 
@@ -344,28 +332,26 @@
                 createPort(c.nextPortId++, "Remote Submix Out", 0, false,
                            createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
                                            AudioDeviceDescription::CONNECTION_VIRTUAL));
-        rsubmixOutDevice.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
         c.ports.push_back(rsubmixOutDevice);
+        c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;
 
-        AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
-                                               createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
-        rsubmixInDevice.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        AudioPort rsubmixInDevice =
+                createPort(c.nextPortId++, "Remote Submix In", 0, true,
+                           createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
+                                           AudioDeviceDescription::CONNECTION_VIRTUAL));
         c.ports.push_back(rsubmixInDevice);
+        c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;
 
         // Mix ports
 
         AudioPort rsubmixOutMix =
                 createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
-        rsubmixOutMix.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        rsubmixOutMix.profiles = standardPcmAudioProfiles;
         c.ports.push_back(rsubmixOutMix);
 
         AudioPort rsubmixInMix =
                 createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
-        rsubmixInMix.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        rsubmixInMix.profiles = standardPcmAudioProfiles;
         c.ports.push_back(rsubmixInMix);
 
         c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
@@ -479,14 +465,17 @@
 // Mix ports:
 //  * "test output", 1 max open, 1 max active stream
 //    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//  * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
+//  * "test fast output", 1 max open, 1 max active stream
+//    - profile PCM 24-bit; STEREO; 44100, 48000
+//  * "test compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active
+//  stream
 //    - profile MP3; MONO, STEREO; 44100, 48000
 //  * "test input", 2 max open, 2 max active streams
 //    - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
-//        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+//        8000, 11025, 16000, 22050, 32000, 44100, 48000
 //
 // Routes:
-//  "test output", "compressed offload" -> "Test Out"
+//  "test output", "test fast output", "test compressed offload" -> "Test Out"
 //  "Test In" -> "test input"
 //
 // Initial port configs:
@@ -525,8 +514,15 @@
                               {8000, 11025, 16000, 32000, 44100, 48000}));
         c.ports.push_back(testOutMix);
 
+        AudioPort testFastOutMix = createPort(c.nextPortId++, "test fast output",
+                                              makeBitPositionFlagMask({AudioOutputFlags::FAST}),
+                                              false, createPortMixExt(1, 1));
+        testFastOutMix.profiles.push_back(createProfile(
+                PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {44100, 48000}));
+        c.ports.push_back(testFastOutMix);
+
         AudioPort compressedOffloadOutMix =
-                createPort(c.nextPortId++, "compressed offload",
+                createPort(c.nextPortId++, "test compressed offload",
                            makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
                                                     AudioOutputFlags::COMPRESS_OFFLOAD,
                                                     AudioOutputFlags::NON_BLOCKING}),
@@ -543,15 +539,16 @@
                 createProfile(PcmType::INT_16_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
                                AudioChannelLayout::LAYOUT_FRONT_BACK},
-                              {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+                              {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
         testInMIx.profiles.push_back(
                 createProfile(PcmType::INT_24_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
                                AudioChannelLayout::LAYOUT_FRONT_BACK},
-                              {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+                              {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
         c.ports.push_back(testInMIx);
 
-        c.routes.push_back(createRoute({testOutMix, compressedOffloadOutMix}, testOutDevice));
+        c.routes.push_back(
+                createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice));
         c.routes.push_back(createRoute({testInDevice}, testInMIx));
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
@@ -561,4 +558,94 @@
     return std::make_unique<Configuration>(configuration);
 }
 
+// Bluetooth configuration:
+//
+// Device ports:
+//  * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP
+//    - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+//  * "BT A2DP Headphones", OUT_HEADPHONE, CONNECTION_BT_A2DP
+//    - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+//  * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP
+//    - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+//  * "BT Hearing Aid Out", OUT_HEARING_AID, CONNECTION_WIRELESS
+//    - no profiles specified
+//
+// Mix ports:
+//  * "a2dp output", 1 max open, 1 max active stream
+//    - no profiles specified
+//  * "hearing aid output", 1 max open, 1 max active stream
+//    - profile PCM 16-bit; STEREO; 16000, 24000
+//
+// Routes:
+//  "a2dp output" -> "BT A2DP Out"
+//  "a2dp output" -> "BT A2DP Headphones"
+//  "a2dp output" -> "BT A2DP Speaker"
+//  "hearing aid output" -> "BT Hearing Aid Out"
+//
+std::unique_ptr<Configuration> getBluetoothConfiguration() {
+    static const Configuration configuration = []() {
+        const std::vector<AudioProfile> standardPcmAudioProfiles = {
+                createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
+                              {44100, 48000, 88200, 96000})};
+        Configuration c;
+
+        // Device ports
+        AudioPort btOutDevice =
+                createPort(c.nextPortId++, "BT A2DP Out", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+                                           AudioDeviceDescription::CONNECTION_BT_A2DP));
+        btOutDevice.profiles.insert(btOutDevice.profiles.begin(), standardPcmAudioProfiles.begin(),
+                                    standardPcmAudioProfiles.end());
+        c.ports.push_back(btOutDevice);
+        c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles;
+
+        AudioPort btOutHeadphone =
+                createPort(c.nextPortId++, "BT A2DP Headphones", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_HEADPHONE, 0,
+                                           AudioDeviceDescription::CONNECTION_BT_A2DP));
+        btOutHeadphone.profiles.insert(btOutHeadphone.profiles.begin(),
+                                       standardPcmAudioProfiles.begin(),
+                                       standardPcmAudioProfiles.end());
+        c.ports.push_back(btOutHeadphone);
+        c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles;
+
+        AudioPort btOutSpeaker =
+                createPort(c.nextPortId++, "BT A2DP Speaker", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0,
+                                           AudioDeviceDescription::CONNECTION_BT_A2DP));
+        btOutSpeaker.profiles.insert(btOutSpeaker.profiles.begin(),
+                                     standardPcmAudioProfiles.begin(),
+                                     standardPcmAudioProfiles.end());
+        c.ports.push_back(btOutSpeaker);
+        c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles;
+
+        AudioPort btOutHearingAid =
+                createPort(c.nextPortId++, "BT Hearing Aid Out", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_HEARING_AID, 0,
+                                           AudioDeviceDescription::CONNECTION_WIRELESS));
+        c.ports.push_back(btOutHearingAid);
+        c.connectedProfiles[btOutHearingAid.id] = std::vector<AudioProfile>(
+                {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})});
+
+        // Mix ports
+        AudioPort btOutMix =
+                createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1));
+        c.ports.push_back(btOutMix);
+
+        AudioPort btHearingOutMix =
+                createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1));
+        btHearingOutMix.profiles.push_back(createProfile(
+                PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000}));
+        c.ports.push_back(btHearingOutMix);
+
+        c.routes.push_back(createRoute({btOutMix}, btOutDevice));
+        c.routes.push_back(createRoute({btOutMix}, btOutHeadphone));
+        c.routes.push_back(createRoute({btOutMix}, btOutSpeaker));
+        c.routes.push_back(createRoute({btHearingOutMix}, btOutHearingAid));
+
+        return c;
+    }();
+    return std::make_unique<Configuration>(configuration);
+}
+
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index 62f3c7e..96f13ba 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -49,18 +49,18 @@
             if (auto spEffect = it.first.lock()) {
                 LOG(ERROR) << __func__ << " erase remaining instance UUID "
                            << ::android::audio::utils::toString(it.second.first);
-                destroyEffectImpl(spEffect);
+                destroyEffectImpl_l(spEffect);
             }
         }
     }
 }
 
-ndk::ScopedAStatus Factory::getDescriptorWithUuid(const AudioUuid& uuid, Descriptor* desc) {
+ndk::ScopedAStatus Factory::getDescriptorWithUuid_l(const AudioUuid& uuid, Descriptor* desc) {
     RETURN_IF(!desc, EX_NULL_POINTER, "nullDescriptor");
 
     if (mEffectLibMap.count(uuid)) {
         auto& entry = mEffectLibMap[uuid];
-        getDlSyms(entry);
+        getDlSyms_l(entry);
         auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
         RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
                   "dlNullQueryEffectFunc");
@@ -75,6 +75,7 @@
                                          const std::optional<AudioUuid>& in_impl_uuid,
                                          const std::optional<AudioUuid>& in_proxy_uuid,
                                          std::vector<Descriptor>* _aidl_return) {
+    std::lock_guard lg(mMutex);
     // get the matching list
     std::vector<Descriptor::Identity> idList;
     std::copy_if(mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(idList),
@@ -88,7 +89,8 @@
     for (const auto& id : idList) {
         if (mEffectLibMap.count(id.uuid)) {
             Descriptor desc;
-            RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(id.uuid, &desc), "getDescriptorFailed");
+            RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid_l(id.uuid, &desc),
+                                     "getDescriptorFailed");
             // update proxy UUID with information from config xml
             desc.common.id.proxy = id.proxy;
             _aidl_return->emplace_back(std::move(desc));
@@ -99,6 +101,7 @@
 
 ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
                                             std::vector<Processing>* _aidl_return) {
+    std::lock_guard lg(mMutex);
     const auto& processings = mConfig.getProcessingMap();
     // Processing stream type
     for (const auto& procIter : processings) {
@@ -110,7 +113,7 @@
                     if (libs.proxyLibrary.has_value()) {
                         desc.common.id.proxy = libs.proxyLibrary.value().uuid;
                     }
-                    RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(lib.uuid, &desc),
+                    RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid_l(lib.uuid, &desc),
                                              "getDescriptorFailed");
                     process.ids.emplace_back(desc);
                 }
@@ -125,9 +128,10 @@
 ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
                                          std::shared_ptr<IEffect>* _aidl_return) {
     LOG(DEBUG) << __func__ << ": UUID " << ::android::audio::utils::toString(in_impl_uuid);
+    std::lock_guard lg(mMutex);
     if (mEffectLibMap.count(in_impl_uuid)) {
         auto& entry = mEffectLibMap[in_impl_uuid];
-        getDlSyms(entry);
+        getDlSyms_l(entry);
 
         auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
         RETURN_IF(!libInterface || !libInterface->createEffectFunc, EX_NULL_POINTER,
@@ -152,7 +156,7 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
+ndk::ScopedAStatus Factory::destroyEffectImpl_l(const std::shared_ptr<IEffect>& in_handle) {
     std::weak_ptr<IEffect> wpHandle(in_handle);
     // find the effect entry with key (std::weak_ptr<IEffect>)
     if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) {
@@ -177,7 +181,7 @@
 }
 
 // go over the map and cleanup all expired weak_ptrs.
-void Factory::cleanupEffectMap() {
+void Factory::cleanupEffectMap_l() {
     for (auto it = mEffectMap.begin(); it != mEffectMap.end();) {
         if (nullptr == it->first.lock()) {
             it = mEffectMap.erase(it);
@@ -189,13 +193,15 @@
 
 ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_handle) {
     LOG(DEBUG) << __func__ << ": instance " << in_handle.get();
-    ndk::ScopedAStatus status = destroyEffectImpl(in_handle);
+    std::lock_guard lg(mMutex);
+    ndk::ScopedAStatus status = destroyEffectImpl_l(in_handle);
     // always do the cleanup
-    cleanupEffectMap();
+    cleanupEffectMap_l();
     return status;
 }
 
-bool Factory::openEffectLibrary(const AudioUuid& impl, const std::string& path) {
+bool Factory::openEffectLibrary(const AudioUuid& impl,
+                                const std::string& path) NO_THREAD_SAFETY_ANALYSIS {
     std::function<void(void*)> dlClose = [](void* handle) -> void {
         if (handle && dlclose(handle)) {
             LOG(ERROR) << "dlclose failed " << dlerror();
@@ -219,9 +225,9 @@
     return true;
 }
 
-void Factory::createIdentityWithConfig(const EffectConfig::Library& configLib,
-                                       const AudioUuid& typeUuid,
-                                       const std::optional<AudioUuid> proxyUuid) {
+void Factory::createIdentityWithConfig(
+        const EffectConfig::Library& configLib, const AudioUuid& typeUuid,
+        const std::optional<AudioUuid> proxyUuid) NO_THREAD_SAFETY_ANALYSIS {
     static const auto& libMap = mConfig.getLibraryMap();
     const std::string& libName = configLib.name;
     if (auto path = libMap.find(libName); path != libMap.end()) {
@@ -263,7 +269,7 @@
     }
 }
 
-void Factory::getDlSyms(DlEntry& entry) {
+void Factory::getDlSyms_l(DlEntry& entry) {
     auto& dlHandle = std::get<kMapEntryHandleIndex>(entry);
     RETURN_VALUE_IF(!dlHandle, void(), "dlNullHandle");
     // Get the reference of the DL interfaces in library map tuple.
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index da1ad11..c81c731 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -76,7 +76,7 @@
 }
 
 ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
-    LOG(DEBUG) << getEffectName() << __func__ << " with: " << param.toString();
+    LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString();
 
     const auto tag = param.getTag();
     switch (tag) {
@@ -100,7 +100,6 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
-    LOG(DEBUG) << getEffectName() << __func__ << id.toString();
     auto tag = id.getTag();
     switch (tag) {
         case Parameter::Id::commonTag: {
@@ -117,7 +116,7 @@
             break;
         }
     }
-    LOG(DEBUG) << getEffectName() << __func__ << param->toString();
+    LOG(VERBOSE) << getEffectName() << __func__ << id.toString() << param->toString();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -254,7 +253,7 @@
     for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    LOG(DEBUG) << getEffectName() << __func__ << " done processing " << samples << " samples";
+    LOG(VERBOSE) << getEffectName() << __func__ << " done processing " << samples << " samples";
     return {STATUS_OK, samples, samples};
 }
 
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 574dc69..cd2ba53 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -149,8 +149,8 @@
         IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
         outputMQ->write(buffer, status.fmqProduced);
         statusMQ->writeBlocking(&status, 1);
-        LOG(DEBUG) << mName << __func__ << ": done processing, effect consumed "
-                   << status.fmqConsumed << " produced " << status.fmqProduced;
+        LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed "
+                     << status.fmqConsumed << " produced " << status.fmqProduced;
     }
 }
 
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 5478633..f81095e 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -26,6 +26,7 @@
 #include <error/expected_utils.h>
 
 #include "core-impl/Module.h"
+#include "core-impl/ModuleBluetooth.h"
 #include "core-impl/ModulePrimary.h"
 #include "core-impl/ModuleRemoteSubmix.h"
 #include "core-impl/ModuleStub.h"
@@ -117,6 +118,8 @@
             return ndk::SharedRefBase::make<ModuleStub>();
         case Type::USB:
             return ndk::SharedRefBase::make<ModuleUsb>();
+        case Type::BLUETOOTH:
+            return ndk::SharedRefBase::make<ModuleBluetooth>();
     }
 }
 
@@ -134,6 +137,9 @@
         case Module::Type::USB:
             os << "usb";
             break;
+        case Module::Type::BLUETOOTH:
+            os << "bluetooth";
+            break;
     }
     return os;
 }
@@ -301,6 +307,9 @@
         case Type::USB:
             config = std::move(internal::getUsbConfiguration());
             break;
+        case Type::BLUETOOTH:
+            config = std::move(internal::getBluetoothConfiguration());
+            break;
     }
     return config;
 }
@@ -675,7 +684,7 @@
                                                nullptr, nullptr, &context));
     context.fillDescriptor(&_aidl_return->desc);
     std::shared_ptr<StreamIn> stream;
-    RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context),
+    RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
                                              mConfig->microphones, &stream));
     StreamWrapper streamWrapper(stream);
     if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
@@ -721,7 +730,7 @@
                                                in_args.eventCallback, &context));
     context.fillDescriptor(&_aidl_return->desc);
     std::shared_ptr<StreamOut> stream;
-    RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context),
+    RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
                                               in_args.offloadInfo, &stream));
     StreamWrapper streamWrapper(stream);
     if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
@@ -1129,7 +1138,7 @@
     if (!mSoundDose) {
         mSoundDose = ndk::SharedRefBase::make<sounddose::SoundDose>();
     }
-    *_aidl_return = mSoundDose.getPtr();
+    *_aidl_return = mSoundDose.getInstance();
     LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
     return ndk::ScopedAStatus::ok();
 }
@@ -1362,4 +1371,13 @@
     return ndk::ScopedAStatus::ok();
 }
 
+Module::BtProfileHandles Module::getBtProfileManagerHandles() {
+    return std::make_tuple(std::weak_ptr<IBluetooth>(), std::weak_ptr<IBluetoothA2dp>(),
+                           std::weak_ptr<IBluetoothLe>());
+}
+
+ndk::ScopedAStatus Module::bluetoothParametersUpdated() {
+    return mStreams.bluetoothParametersUpdated();
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp
index cbb6730..9919c7f 100644
--- a/audio/aidl/default/ModulePrimary.cpp
+++ b/audio/aidl/default/ModulePrimary.cpp
@@ -21,7 +21,7 @@
 #include <android-base/logging.h>
 
 #include "core-impl/ModulePrimary.h"
-#include "core-impl/StreamStub.h"
+#include "core-impl/StreamPrimary.h"
 #include "core-impl/Telephony.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
@@ -37,24 +37,25 @@
     if (!mTelephony) {
         mTelephony = ndk::SharedRefBase::make<Telephony>();
     }
-    *_aidl_return = mTelephony.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
+    *_aidl_return = mTelephony.getInstance();
+    LOG(DEBUG) << __func__
+               << ": returning instance of ITelephony: " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata,
-                                                    StreamContext&& context,
+ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
+                                                    const SinkMetadata& sinkMetadata,
                                                     const std::vector<MicrophoneInfo>& microphones,
                                                     std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
-                                              microphones);
+    return createStreamInstance<StreamInPrimary>(result, std::move(context), sinkMetadata,
+                                                 microphones);
 }
 
 ndk::ScopedAStatus ModulePrimary::createOutputStream(
-        const SourceMetadata& sourceMetadata, StreamContext&& context,
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
-    return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
-                                               offloadInfo);
+    return createStreamInstance<StreamOutPrimary>(result, std::move(context), sourceMetadata,
+                                                  offloadInfo);
 }
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 215de94..af89f5f 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -27,12 +27,16 @@
 using aidl::android::hardware::audio::common::AudioOffloadMetadata;
 using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
 using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioDualMonoMode;
+using aidl::android::media::audio::common::AudioInputFlags;
+using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioLatencyMode;
 using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioOutputFlags;
 using aidl::android::media::audio::common::AudioPlaybackRate;
 using aidl::android::media::audio::common::MicrophoneDynamicInfo;
 using aidl::android::media::audio::common::MicrophoneInfo;
@@ -47,13 +51,19 @@
         desc->reply = mReplyMQ->dupeDesc();
     }
     if (mDataMQ) {
-        const size_t frameSize = getFrameSize();
-        desc->frameSizeBytes = frameSize;
-        desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
+        desc->frameSizeBytes = getFrameSize();
+        desc->bufferSizeFrames = getBufferSizeInFrames();
         desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
     }
 }
 
+size_t StreamContext::getBufferSizeInFrames() const {
+    if (mDataMQ) {
+        return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
+    }
+    return 0;
+}
+
 size_t StreamContext::getFrameSize() const {
     return getFrameSizeInBytes(mFormat, mChannelLayout);
 }
@@ -85,17 +95,18 @@
 }
 
 std::string StreamWorkerCommonLogic::init() {
-    if (mCommandMQ == nullptr) return "Command MQ is null";
-    if (mReplyMQ == nullptr) return "Reply MQ is null";
-    if (mDataMQ == nullptr) return "Data MQ is null";
-    if (sizeof(DataBufferElement) != mDataMQ->getQuantumSize()) {
-        return "Unexpected Data MQ quantum size: " + std::to_string(mDataMQ->getQuantumSize());
+    if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
+    if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
+    StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
+    if (dataMQ == nullptr) return "Data MQ is null";
+    if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
+        return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
     }
-    mDataBufferSize = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize();
+    mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
     mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
     if (mDataBuffer == nullptr) {
         return "Failed to allocate data buffer for element count " +
-               std::to_string(mDataMQ->getQuantumCount()) +
+               std::to_string(dataMQ->getQuantumCount()) +
                ", size in bytes: " + std::to_string(mDataBufferSize);
     }
     if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
@@ -108,9 +119,9 @@
                                             bool isConnected) const {
     reply->status = STATUS_OK;
     if (isConnected) {
-        reply->observable.frames = mFrameCount;
+        reply->observable.frames = mContext->getFrameCount();
         reply->observable.timeNs = ::android::elapsedRealtimeNano();
-        if (auto status = mDriver->getPosition(&reply->observable); status == ::android::OK) {
+        if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
             return;
         }
     }
@@ -135,7 +146,7 @@
     // TODO: Add a delay for transitions of async operations when/if they added.
 
     StreamDescriptor::Command command{};
-    if (!mCommandMQ->readBlocking(&command, 1)) {
+    if (!mContext->getCommandMQ()->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
         mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
@@ -153,7 +164,7 @@
     switch (command.getTag()) {
         case Tag::halReservedExit:
             if (const int32_t cookie = command.get<Tag::halReservedExit>();
-                cookie == mInternalCommandCookie) {
+                cookie == mContext->getInternalCommandCookie()) {
                 mDriver->shutdown();
                 setClosed();
                 // This is an internal command, no need to reply.
@@ -231,8 +242,8 @@
             break;
         case Tag::standby:
             if (mState == StreamDescriptor::State::IDLE) {
+                populateReply(&reply, mIsConnected);
                 if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
-                    populateReply(&reply, mIsConnected);
                     mState = StreamDescriptor::State::STANDBY;
                 } else {
                     LOG(ERROR) << __func__ << ": standby failed: " << status;
@@ -271,7 +282,7 @@
     }
     reply.state = mState;
     LOG(severity) << __func__ << ": writing reply " << reply.toString();
-    if (!mReplyMQ->writeBlocking(&reply, 1)) {
+    if (!mContext->getReplyMQ()->writeBlocking(&reply, 1)) {
         LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
         mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
@@ -280,14 +291,16 @@
 }
 
 bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
-    const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize});
+    StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
+    const size_t byteCount = std::min({clientSize, dataMQ->availableToWrite(), mDataBufferSize});
     const bool isConnected = mIsConnected;
+    const size_t frameSize = mContext->getFrameSize();
     size_t actualFrameCount = 0;
     bool fatal = false;
     int32_t latency = Module::kLatencyMs;
     if (isConnected) {
-        if (::android::status_t status = mDriver->transfer(
-                    mDataBuffer.get(), byteCount / mFrameSize, &actualFrameCount, &latency);
+        if (::android::status_t status = mDriver->transfer(mDataBuffer.get(), byteCount / frameSize,
+                                                           &actualFrameCount, &latency);
             status != ::android::OK) {
             fatal = true;
             LOG(ERROR) << __func__ << ": read failed: " << status;
@@ -295,17 +308,16 @@
     } else {
         usleep(3000);  // Simulate blocking transfer delay.
         for (size_t i = 0; i < byteCount; ++i) mDataBuffer[i] = 0;
-        actualFrameCount = byteCount / mFrameSize;
+        actualFrameCount = byteCount / frameSize;
     }
-    const size_t actualByteCount = actualFrameCount * mFrameSize;
-    if (bool success =
-                actualByteCount > 0 ? mDataMQ->write(&mDataBuffer[0], actualByteCount) : true;
+    const size_t actualByteCount = actualFrameCount * frameSize;
+    if (bool success = actualByteCount > 0 ? dataMQ->write(&mDataBuffer[0], actualByteCount) : true;
         success) {
         LOG(VERBOSE) << __func__ << ": writing of " << actualByteCount << " bytes into data MQ"
                      << " succeeded; connected? " << isConnected;
         // Frames are provided and counted regardless of connection status.
         reply->fmqByteCount += actualByteCount;
-        mFrameCount += actualFrameCount;
+        mContext->advanceFrameCount(actualFrameCount);
         populateReply(reply, isConnected);
     } else {
         LOG(WARNING) << __func__ << ": writing of " << actualByteCount
@@ -324,7 +336,8 @@
         if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
                     std::chrono::steady_clock::now() - mTransientStateStart);
             stateDurationMs >= mTransientStateDelayMs) {
-            if (mAsyncCallback == nullptr) {
+            std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
+            if (asyncCallback == nullptr) {
                 // In blocking mode, mState can only be DRAINING.
                 mState = StreamDescriptor::State::IDLE;
             } else {
@@ -332,13 +345,13 @@
                 // drain or transfer completion. In the stub, we switch unconditionally.
                 if (mState == StreamDescriptor::State::DRAINING) {
                     mState = StreamDescriptor::State::IDLE;
-                    ndk::ScopedAStatus status = mAsyncCallback->onDrainReady();
+                    ndk::ScopedAStatus status = asyncCallback->onDrainReady();
                     if (!status.isOk()) {
                         LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
                     }
                 } else {
                     mState = StreamDescriptor::State::ACTIVE;
-                    ndk::ScopedAStatus status = mAsyncCallback->onTransferReady();
+                    ndk::ScopedAStatus status = asyncCallback->onTransferReady();
                     if (!status.isOk()) {
                         LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
                     }
@@ -352,7 +365,7 @@
     }
 
     StreamDescriptor::Command command{};
-    if (!mCommandMQ->readBlocking(&command, 1)) {
+    if (!mContext->getCommandMQ()->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
         mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
@@ -371,7 +384,7 @@
     switch (command.getTag()) {
         case Tag::halReservedExit:
             if (const int32_t cookie = command.get<Tag::halReservedExit>();
-                cookie == mInternalCommandCookie) {
+                cookie == mContext->getInternalCommandCookie()) {
                 mDriver->shutdown();
                 setClosed();
                 // This is an internal command, no need to reply.
@@ -426,10 +439,11 @@
                     if (!write(fmqByteCount, &reply)) {
                         mState = StreamDescriptor::State::ERROR;
                     }
+                    std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
                     if (mState == StreamDescriptor::State::STANDBY ||
                         mState == StreamDescriptor::State::DRAIN_PAUSED ||
                         mState == StreamDescriptor::State::PAUSED) {
-                        if (mAsyncCallback == nullptr ||
+                        if (asyncCallback == nullptr ||
                             mState != StreamDescriptor::State::DRAIN_PAUSED) {
                             mState = StreamDescriptor::State::PAUSED;
                         } else {
@@ -438,7 +452,7 @@
                     } else if (mState == StreamDescriptor::State::IDLE ||
                                mState == StreamDescriptor::State::DRAINING ||
                                mState == StreamDescriptor::State::ACTIVE) {
-                        if (mAsyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
+                        if (asyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
                             mState = StreamDescriptor::State::ACTIVE;
                         } else {
                             switchToTransientState(StreamDescriptor::State::TRANSFERRING);
@@ -460,7 +474,8 @@
                     if (::android::status_t status = mDriver->drain(mode);
                         status == ::android::OK) {
                         populateReply(&reply, mIsConnected);
-                        if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
+                        if (mState == StreamDescriptor::State::ACTIVE &&
+                            mContext->getForceSynchronousDrain()) {
                             mState = StreamDescriptor::State::IDLE;
                         } else {
                             switchToTransientState(StreamDescriptor::State::DRAINING);
@@ -481,8 +496,8 @@
             break;
         case Tag::standby:
             if (mState == StreamDescriptor::State::IDLE) {
+                populateReply(&reply, mIsConnected);
                 if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
-                    populateReply(&reply, mIsConnected);
                     mState = StreamDescriptor::State::STANDBY;
                 } else {
                     LOG(ERROR) << __func__ << ": standby failed: " << status;
@@ -535,7 +550,7 @@
     }
     reply.state = mState;
     LOG(severity) << __func__ << ": writing reply " << reply.toString();
-    if (!mReplyMQ->writeBlocking(&reply, 1)) {
+    if (!mContext->getReplyMQ()->writeBlocking(&reply, 1)) {
         LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
         mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
@@ -544,38 +559,40 @@
 }
 
 bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
-    const size_t readByteCount = mDataMQ->availableToRead();
+    StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
+    const size_t readByteCount = dataMQ->availableToRead();
+    const size_t frameSize = mContext->getFrameSize();
     bool fatal = false;
     int32_t latency = Module::kLatencyMs;
-    if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
+    if (bool success = readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) {
         const bool isConnected = mIsConnected;
         LOG(VERBOSE) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
                      << " succeeded; connected? " << isConnected;
         // Amount of data that the HAL module is going to actually use.
         size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
-        if (byteCount >= mFrameSize && mForceTransientBurst) {
+        if (byteCount >= frameSize && mContext->getForceTransientBurst()) {
             // In order to prevent the state machine from going to ACTIVE state,
             // simulate partial write.
-            byteCount -= mFrameSize;
+            byteCount -= frameSize;
         }
         size_t actualFrameCount = 0;
         if (isConnected) {
             if (::android::status_t status = mDriver->transfer(
-                        mDataBuffer.get(), byteCount / mFrameSize, &actualFrameCount, &latency);
+                        mDataBuffer.get(), byteCount / frameSize, &actualFrameCount, &latency);
                 status != ::android::OK) {
                 fatal = true;
                 LOG(ERROR) << __func__ << ": write failed: " << status;
             }
         } else {
-            if (mAsyncCallback == nullptr) {
+            if (mContext->getAsyncCallback() == nullptr) {
                 usleep(3000);  // Simulate blocking transfer delay.
             }
-            actualFrameCount = byteCount / mFrameSize;
+            actualFrameCount = byteCount / frameSize;
         }
-        const size_t actualByteCount = actualFrameCount * mFrameSize;
+        const size_t actualByteCount = actualFrameCount * frameSize;
         // Frames are consumed and counted regardless of the connection status.
         reply->fmqByteCount += actualByteCount;
-        mFrameCount += actualFrameCount;
+        mContext->advanceFrameCount(actualFrameCount);
         populateReply(reply, isConnected);
     } else {
         LOG(WARNING) << __func__ << ": reading of " << readByteCount
@@ -597,18 +614,38 @@
 ndk::ScopedAStatus StreamCommonImpl::initInstance(
         const std::shared_ptr<StreamCommonInterface>& delegate) {
     mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
-    mCommonBinder = mCommon->asBinder();
-    AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
-    return mWorker->start() ? ndk::ScopedAStatus::ok()
-                            : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    if (!mWorker->start()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (auto flags = getContext().getFlags();
+        (flags.getTag() == AudioIoFlags::Tag::input &&
+         isBitPositionFlagSet(flags.template get<AudioIoFlags::Tag::input>(),
+                              AudioInputFlags::FAST)) ||
+        (flags.getTag() == AudioIoFlags::Tag::output &&
+         isBitPositionFlagSet(flags.template get<AudioIoFlags::Tag::output>(),
+                              AudioOutputFlags::FAST))) {
+        // FAST workers should be run with a SCHED_FIFO scheduler, however the host process
+        // might be lacking the capability to request it, thus a failure to set is not an error.
+        pid_t workerTid = mWorker->getTid();
+        if (workerTid > 0) {
+            struct sched_param param;
+            param.sched_priority = 3;  // Must match SchedulingPolicyService.PRIORITY_MAX (Java).
+            if (sched_setscheduler(workerTid, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
+                PLOG(WARNING) << __func__ << ": failed to set FIFO scheduler for a fast thread";
+            }
+        } else {
+            LOG(WARNING) << __func__ << ": invalid worker tid: " << workerTid;
+        }
+    }
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
         std::shared_ptr<IStreamCommon>* _aidl_return) {
-    if (mCommon == nullptr) {
+    if (!mCommon) {
         LOG(FATAL) << __func__ << ": the common interface was not created";
     }
-    *_aidl_return = mCommon;
+    *_aidl_return = mCommon.getInstance();
     LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
@@ -659,8 +696,7 @@
         LOG(DEBUG) << __func__ << ": joining the worker thread...";
         mWorker->stop();
         LOG(DEBUG) << __func__ << ": worker thread joined";
-        mContext.reset();
-        mWorker->setClosed();
+        onClose(mWorker->setClosed());
         return ndk::ScopedAStatus::ok();
     } else {
         LOG(ERROR) << __func__ << ": stream was already closed";
@@ -713,6 +749,11 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StreamCommonImpl::bluetoothParametersUpdated() {
+    LOG(DEBUG) << __func__;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 namespace {
 static std::map<AudioDevice, std::string> transformMicrophones(
         const std::vector<MicrophoneInfo>& microphones) {
@@ -723,11 +764,15 @@
 }
 }  // namespace
 
-StreamIn::StreamIn(const std::vector<MicrophoneInfo>& microphones)
-    : mMicrophones(transformMicrophones(microphones)) {
+StreamIn::StreamIn(StreamContext&& context, const std::vector<MicrophoneInfo>& microphones)
+    : mContextInstance(std::move(context)), mMicrophones(transformMicrophones(microphones)) {
     LOG(DEBUG) << __func__;
 }
 
+void StreamIn::defaultOnClose() {
+    mContextInstance.reset();
+}
+
 ndk::ScopedAStatus StreamIn::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return) {
     std::vector<MicrophoneDynamicInfo> result;
@@ -780,11 +825,41 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-StreamOut::StreamOut(const std::optional<AudioOffloadInfo>& offloadInfo)
-    : mOffloadInfo(offloadInfo) {
+StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
+    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+
+ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _aidl_return) {
+    *_aidl_return = mHwGains;
+    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInHwGainHelper::setHwGainImpl(const std::vector<float>& in_channelGains) {
+    LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+    if (in_channelGains.size() != mChannelCount) {
+        LOG(ERROR) << __func__
+                   << ": channel count does not match stream channel count: " << mChannelCount;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    for (float gain : in_channelGains) {
+        if (gain < StreamIn::HW_GAIN_MIN || gain > StreamIn::HW_GAIN_MAX) {
+            LOG(ERROR) << __func__ << ": gain value out of range: " << gain;
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+    }
+    mHwGains = in_channelGains;
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamOut::StreamOut(StreamContext&& context, const std::optional<AudioOffloadInfo>& offloadInfo)
+    : mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) {
     LOG(DEBUG) << __func__;
 }
 
+void StreamOut::defaultOnClose() {
+    mContextInstance.reset();
+}
+
 ndk::ScopedAStatus StreamOut::updateOffloadMetadata(
         const AudioOffloadMetadata& in_offloadMetadata) {
     LOG(DEBUG) << __func__;
@@ -881,4 +956,31 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context)
+    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+
+ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector<float>* _aidl_return) {
+    *_aidl_return = mHwVolumes;
+    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamOutHwVolumeHelper::setHwVolumeImpl(
+        const std::vector<float>& in_channelVolumes) {
+    LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
+    if (in_channelVolumes.size() != mChannelCount) {
+        LOG(ERROR) << __func__
+                   << ": channel count does not match stream channel count: " << mChannelCount;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    for (float volume : in_channelVolumes) {
+        if (volume < StreamOut::HW_VOLUME_MIN || volume > StreamOut::HW_VOLUME_MAX) {
+            LOG(ERROR) << __func__ << ": volume value out of range: " << volume;
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+    }
+    mHwVolumes = in_channelVolumes;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp
new file mode 100644
index 0000000..8ba15a8
--- /dev/null
+++ b/audio/aidl/default/StreamSwitcher.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits>
+
+#define LOG_TAG "AHAL_StreamSwitcher"
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <error/expected_utils.h>
+
+#include "core-impl/StreamStub.h"
+#include "core-impl/StreamSwitcher.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::media::audio::common::AudioDevice;
+
+namespace aidl::android::hardware::audio::core {
+
+StreamSwitcher::StreamSwitcher(StreamContext* context, const Metadata& metadata)
+    : mContext(context),
+      mMetadata(metadata),
+      mStream(new InnerStreamWrapper<StreamStub>(context, mMetadata)) {}
+
+ndk::ScopedAStatus StreamSwitcher::closeCurrentStream(bool validateStreamState) {
+    if (!mStream) return ndk::ScopedAStatus::ok();
+    RETURN_STATUS_IF_ERROR(mStream->prepareToClose());
+    RETURN_STATUS_IF_ERROR(mStream->close());
+    if (validateStreamState && !isValidClosingStreamState(mStream->getStatePriorToClosing())) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mStream.reset();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::close() {
+    if (mStream != nullptr) {
+        auto status = closeCurrentStream(false /*validateStreamState*/);
+        // The actual state is irrelevant since only StreamSwitcher cares about it.
+        onClose(StreamDescriptor::State::STANDBY);
+        return status;
+    }
+    LOG(ERROR) << __func__ << ": stream was already closed";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+}
+
+ndk::ScopedAStatus StreamSwitcher::prepareToClose() {
+    if (mStream != nullptr) {
+        return mStream->prepareToClose();
+    }
+    LOG(ERROR) << __func__ << ": stream was closed";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+}
+
+ndk::ScopedAStatus StreamSwitcher::updateHwAvSyncId(int32_t in_hwAvSyncId) {
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    RETURN_STATUS_IF_ERROR(mStream->updateHwAvSyncId(in_hwAvSyncId));
+    mHwAvSyncId = in_hwAvSyncId;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::getVendorParameters(const std::vector<std::string>& in_ids,
+                                                       std::vector<VendorParameter>* _aidl_return) {
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mIsStubStream) {
+        LOG(ERROR) << __func__ << ": the stream is not connected";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    return mStream->getVendorParameters(in_ids, _aidl_return);
+}
+
+ndk::ScopedAStatus StreamSwitcher::setVendorParameters(
+        const std::vector<VendorParameter>& in_parameters, bool in_async) {
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mIsStubStream) {
+        mMissedParameters.emplace_back(in_parameters, in_async);
+        return ndk::ScopedAStatus::ok();
+    }
+    return mStream->setVendorParameters(in_parameters, in_async);
+}
+
+ndk::ScopedAStatus StreamSwitcher::addEffect(const std::shared_ptr<IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": null effect";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!mIsStubStream) {
+        RETURN_STATUS_IF_ERROR(mStream->addEffect(in_effect));
+    }
+    mEffects.push_back(in_effect);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::removeEffect(const std::shared_ptr<IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": null effect";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    for (auto it = mEffects.begin(); it != mEffects.end(); ++it) {
+        if ((*it)->asBinder() == in_effect->asBinder()) {
+            mEffects.erase(it);
+            break;
+        }
+    }
+    return !mIsStubStream ? mStream->removeEffect(in_effect) : ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::getStreamCommonCommon(
+        std::shared_ptr<IStreamCommon>* _aidl_return) {
+    if (!mCommon) {
+        LOG(FATAL) << __func__ << ": the common interface was not created";
+    }
+    *_aidl_return = mCommon.getInstance();
+    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::updateMetadataCommon(const Metadata& metadata) {
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mMetadata = metadata;
+    return !mIsStubStream ? mStream->updateMetadataCommon(metadata) : ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::initInstance(
+        const std::shared_ptr<StreamCommonInterface>& delegate) {
+    mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
+    // The delegate is null because StreamSwitcher handles IStreamCommon methods by itself.
+    return mStream->initInstance(nullptr);
+}
+
+const StreamContext& StreamSwitcher::getContext() const {
+    return *mContext;
+}
+
+bool StreamSwitcher::isClosed() const {
+    return mStream == nullptr || mStream->isClosed();
+}
+
+const StreamCommonInterface::ConnectedDevices& StreamSwitcher::getConnectedDevices() const {
+    return mStream->getConnectedDevices();
+}
+
+ndk::ScopedAStatus StreamSwitcher::setConnectedDevices(const std::vector<AudioDevice>& devices) {
+    LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices);
+    if (mStream->getConnectedDevices() == devices) return ndk::ScopedAStatus::ok();
+    const DeviceSwitchBehavior behavior = switchCurrentStream(devices);
+    if (behavior == DeviceSwitchBehavior::UNSUPPORTED_DEVICES) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    } else if (behavior == DeviceSwitchBehavior::SWITCH_TO_STUB_STREAM && !devices.empty()) {
+        // This is an error in the extending class.
+        LOG(FATAL) << __func__
+                   << ": switching to stub stream with connected devices is not allowed";
+    }
+    if (behavior == USE_CURRENT_STREAM) {
+        mIsStubStream = false;
+    } else {
+        LOG(DEBUG) << __func__ << ": connected devices changed, switching stream";
+        // Two streams can't be opened for the same context, thus we always need to close
+        // the current one before creating a new one.
+        RETURN_STATUS_IF_ERROR(closeCurrentStream(true /*validateStreamState*/));
+        if (behavior == CREATE_NEW_STREAM) {
+            mStream = createNewStream(devices, mContext, mMetadata);
+            mIsStubStream = false;
+        } else {  // SWITCH_TO_STUB_STREAM
+            mStream.reset(new InnerStreamWrapper<StreamStub>(mContext, mMetadata));
+            mIsStubStream = true;
+        }
+        // The delegate is null because StreamSwitcher handles IStreamCommon methods by itself.
+        if (ndk::ScopedAStatus status = mStream->initInstance(nullptr); !status.isOk()) {
+            if (mIsStubStream) {
+                LOG(FATAL) << __func__
+                           << ": failed to initialize stub stream: " << status.getDescription();
+            }
+            // Need to close the current failed stream, and report an error.
+            // Since we can't operate without a stream implementation, put a stub in.
+            RETURN_STATUS_IF_ERROR(closeCurrentStream(false /*validateStreamState*/));
+            mStream.reset(new InnerStreamWrapper<StreamStub>(mContext, mMetadata));
+            (void)mStream->initInstance(nullptr);
+            (void)mStream->setConnectedDevices(devices);
+            return status;
+        }
+    }
+    RETURN_STATUS_IF_ERROR(mStream->setConnectedDevices(devices));
+    if (behavior == CREATE_NEW_STREAM) {
+        // These updates are less critical, only log warning on failure.
+        if (mHwAvSyncId.has_value()) {
+            if (auto status = mStream->updateHwAvSyncId(*mHwAvSyncId); !status.isOk()) {
+                LOG(WARNING) << __func__ << ": could not update HW AV Sync for a new stream: "
+                             << status.getDescription();
+            }
+        }
+        for (const auto& vndParam : mMissedParameters) {
+            if (auto status = mStream->setVendorParameters(vndParam.first, vndParam.second);
+                !status.isOk()) {
+                LOG(WARNING) << __func__ << ": error while setting parameters for a new stream: "
+                             << status.getDescription();
+            }
+        }
+        mMissedParameters.clear();
+        for (const auto& effect : mEffects) {
+            if (auto status = mStream->addEffect(effect); !status.isOk()) {
+                LOG(WARNING) << __func__ << ": error while adding effect for a new stream: "
+                             << status.getDescription();
+            }
+        }
+        if (mBluetoothParametersUpdated) {
+            if (auto status = mStream->bluetoothParametersUpdated(); !status.isOk()) {
+                LOG(WARNING) << __func__
+                             << ": error while updating BT parameters for a new stream: "
+                             << status.getDescription();
+            }
+        }
+        mBluetoothParametersUpdated = false;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() {
+    if (mStream == nullptr) {
+        LOG(ERROR) << __func__ << ": stream was closed";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mIsStubStream) {
+        mBluetoothParametersUpdated = true;
+        return ndk::ScopedAStatus::ok();
+    }
+    return mStream->bluetoothParametersUpdated();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp
index f0393e3..126c033 100644
--- a/audio/aidl/default/alsa/Mixer.cpp
+++ b/audio/aidl/default/alsa/Mixer.cpp
@@ -14,44 +14,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_AlsaMixer"
-#include <android-base/logging.h>
-
+#include <algorithm>
 #include <cmath>
 
+#define LOG_TAG "AHAL_AlsaMixer"
+#include <android-base/logging.h>
 #include <android/binder_status.h>
 
 #include "Mixer.h"
 
 namespace aidl::android::hardware::audio::core::alsa {
 
-//-----------------------------------------------------------------------------
-
-MixerControl::MixerControl(struct mixer_ctl* ctl)
-    : mCtl(ctl),
-      mNumValues(mixer_ctl_get_num_values(ctl)),
-      mMinValue(mixer_ctl_get_range_min(ctl)),
-      mMaxValue(mixer_ctl_get_range_max(ctl)) {}
-
-unsigned int MixerControl::getNumValues() const {
-    return mNumValues;
-}
-
-int MixerControl::getMaxValue() const {
-    return mMaxValue;
-}
-
-int MixerControl::getMinValue() const {
-    return mMinValue;
-}
-
-int MixerControl::setArray(const void* array, size_t count) {
-    const std::lock_guard guard(mLock);
-    return mixer_ctl_set_array(mCtl, array, count);
-}
-
-//-----------------------------------------------------------------------------
-
 // static
 const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
         Mixer::kPossibleControls = {
@@ -60,18 +33,20 @@
                 {Mixer::HW_VOLUME,
                  {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
                   {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
-                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
+                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}},
+                {Mixer::MIC_SWITCH, {{"Capture Switch", MIXER_CTL_TYPE_BOOL}}},
+                {Mixer::MIC_GAIN, {{"Capture Volume", MIXER_CTL_TYPE_INT}}}};
 
 // static
-std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerControls(
-        struct mixer* mixer) {
-    std::map<Mixer::Control, std::shared_ptr<MixerControl>> mixerControls;
+Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) {
+    if (mixer == nullptr) return {};
+    Controls mixerControls;
     std::string mixerCtlNames;
     for (const auto& [control, possibleCtls] : kPossibleControls) {
         for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
             struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
             if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
-                mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
+                mixerControls.emplace(control, ctl);
                 if (!mixerCtlNames.empty()) {
                     mixerCtlNames += ",";
                 }
@@ -84,71 +59,141 @@
     return mixerControls;
 }
 
-Mixer::Mixer(struct mixer* mixer)
-    : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
+std::ostream& operator<<(std::ostream& s, Mixer::Control c) {
+    switch (c) {
+        case Mixer::Control::MASTER_SWITCH:
+            s << "master mute";
+            break;
+        case Mixer::Control::MASTER_VOLUME:
+            s << "master volume";
+            break;
+        case Mixer::Control::HW_VOLUME:
+            s << "volume";
+            break;
+        case Mixer::Control::MIC_SWITCH:
+            s << "mic mute";
+            break;
+        case Mixer::Control::MIC_GAIN:
+            s << "mic gain";
+            break;
+    }
+    return s;
+}
+
+Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) {
+    if (!isValid()) {
+        PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
+    }
+}
 
 Mixer::~Mixer() {
-    mixer_close(mMixer);
+    if (isValid()) {
+        std::lock_guard l(mMixerAccess);
+        mixer_close(mMixer);
+    }
 }
 
-namespace {
-
-int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
-    return minValue + std::ceil((maxValue - minValue) * fValue);
-}
-
-}  // namespace
-
 ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
-    auto it = mMixerControls.find(Mixer::MASTER_SWITCH);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    std::vector<int> values(numValues, muted ? 0 : 1);
-    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
+    return setMixerControlMute(MASTER_SWITCH, muted);
 }
 
 ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
-    auto it = mMixerControls.find(Mixer::MASTER_VOLUME);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
-                                                            it->second->getMinValue()));
-    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
+    return setMixerControlVolume(MASTER_VOLUME, volume);
+}
+
+ndk::ScopedAStatus Mixer::setMicGain(float gain) {
+    return setMixerControlVolume(MIC_GAIN, gain);
+}
+
+ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
+    return setMixerControlMute(MIC_SWITCH, muted);
 }
 
 ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
+    if (!isValid()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     auto it = mMixerControls.find(Mixer::HW_VOLUME);
     if (it == mMixerControls.end()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
-    const int numValues = it->second->getNumValues();
-    if (numValues < 0) {
-        LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
-    }
-    const int maxValue = it->second->getMaxValue();
-    const int minValue = it->second->getMinValue();
-    std::vector<int> values;
-    size_t i = 0;
-    for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
-        values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
-    }
-    if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
+    std::vector<int> percents;
+    std::transform(
+            volumes.begin(), volumes.end(), std::back_inserter(percents),
+            [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlPercent(it->second, percents); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
+    if (!isValid()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    auto it = mMixerControls.find(ctl);
+    if (it == mMixerControls.end()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
+    if (!isValid()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    auto it = mMixerControls.find(ctl);
+    if (it == mMixerControls.end()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    volume = std::clamp(volume, 0.0f, 1.0f);
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
+    int ret = 0;
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
+            ret = error;
+        }
+    }
+    return ret;
+}
+
+int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
+    int ret = 0;
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
+            error != 0) {
+            ret = error;
+        }
+    }
+    return ret;
+}
+
+int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
+    int ret = 0;
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
+            ret = error;
+        }
+    }
+    return ret;
+}
+
 }  // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h
index de9e6f4..8fba1e0 100644
--- a/audio/aidl/default/alsa/Mixer.h
+++ b/audio/aidl/default/alsa/Mixer.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <iostream>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -31,34 +32,17 @@
 
 namespace aidl::android::hardware::audio::core::alsa {
 
-class MixerControl {
-  public:
-    explicit MixerControl(struct mixer_ctl* ctl);
-
-    unsigned int getNumValues() const;
-    int getMaxValue() const;
-    int getMinValue() const;
-    int setArray(const void* array, size_t count);
-
-  private:
-    std::mutex mLock;
-    // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
-    struct mixer_ctl* mCtl GUARDED_BY(mLock);
-    const unsigned int mNumValues;
-    const int mMinValue;
-    const int mMaxValue;
-};
-
 class Mixer {
   public:
-    explicit Mixer(struct mixer* mixer);
-
+    explicit Mixer(int card);
     ~Mixer();
 
     bool isValid() const { return mMixer != nullptr; }
 
     ndk::ScopedAStatus setMasterMute(bool muted);
     ndk::ScopedAStatus setMasterVolume(float volume);
+    ndk::ScopedAStatus setMicGain(float gain);
+    ndk::ScopedAStatus setMicMute(bool muted);
     ndk::ScopedAStatus setVolumes(const std::vector<float>& volumes);
 
   private:
@@ -66,17 +50,32 @@
         MASTER_SWITCH,
         MASTER_VOLUME,
         HW_VOLUME,
+        MIC_SWITCH,
+        MIC_GAIN,
     };
     using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
-    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
-    static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
-            struct mixer* mixer);
+    using Controls = std::map<Control, struct mixer_ctl*>;
 
+    friend std::ostream& operator<<(std::ostream&, Control);
+    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
+    static Controls initializeMixerControls(struct mixer* mixer);
+
+    ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
+    ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
+
+    int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
+    int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
+            REQUIRES(mMixerAccess);
+    int setMixerControlValue(struct mixer_ctl* ctl, int value) REQUIRES(mMixerAccess);
+
+    // Since ALSA functions do not use internal locking, enforce thread safety at our level.
+    std::mutex mMixerAccess;
     // The mixer object is owned by ALSA and will be released when the mixer is closed.
-    struct mixer* mMixer;
-    // `mMixerControls` will only be initialized in constructor. After that, it wil only be
-    // read but not be modified.
-    const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
+    struct mixer* const mMixer;
+    // `mMixerControls` will only be initialized in constructor. After that, it will only be
+    // read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is
+    // the same as of the mixer itself.
+    const Controls mMixerControls;
 };
 
 }  // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 17c7feb..0605d6f 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <cmath>
 #include <limits>
 
 #define LOG_TAG "AHAL_StreamAlsa"
@@ -27,45 +28,63 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
+StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries)
+    : StreamCommonImpl(context, metadata),
+      mBufferSizeFrames(getContext().getBufferSizeInFrames()),
       mFrameSizeBytes(getContext().getFrameSize()),
+      mSampleRate(getContext().getSampleRate()),
       mIsInput(isInput(metadata)),
-      mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {}
+      mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
+      mReadWriteRetries(readWriteRetries) {}
 
 ::android::status_t StreamAlsa::init() {
     return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
 }
 
+::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) {
+    if (!mIsInput) {
+        static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
+        const size_t delayUs = static_cast<size_t>(
+                std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate));
+        usleep(delayUs);
+    }
+    return ::android::OK;
+}
+
+::android::status_t StreamAlsa::flush() {
+    return ::android::OK;
+}
+
+::android::status_t StreamAlsa::pause() {
+    return ::android::OK;
+}
+
 ::android::status_t StreamAlsa::standby() {
     mAlsaDeviceProxies.clear();
     return ::android::OK;
 }
 
 ::android::status_t StreamAlsa::start() {
+    if (!mAlsaDeviceProxies.empty()) {
+        // This is a resume after a pause.
+        return ::android::OK;
+    }
     decltype(mAlsaDeviceProxies) alsaDeviceProxies;
     for (const auto& device : getDeviceProfiles()) {
-        auto profile = alsa::readAlsaDeviceInfo(device);
-        if (!profile.has_value()) {
-            LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device;
-            return ::android::UNKNOWN_ERROR;
+        alsa::DeviceProxy proxy;
+        if (device.isExternal) {
+            // Always ask alsa configure as required since the configuration should be supported
+            // by the connected device. That is guaranteed by `setAudioPortConfig` and
+            // `setAudioPatch`.
+            proxy = alsa::openProxyForExternalDevice(
+                    device, const_cast<struct pcm_config*>(&mConfig.value()),
+                    true /*require_exact_match*/);
+        } else {
+            proxy = alsa::openProxyForAttachedDevice(
+                    device, const_cast<struct pcm_config*>(&mConfig.value()), mBufferSizeFrames);
         }
-
-        auto proxy = alsa::makeDeviceProxy();
-        // Always ask for alsa configure as required since the configuration should be supported
-        // by the connected device. That is guaranteed by `setAudioPortConfig` and `setAudioPatch`.
-        if (int err = proxy_prepare(proxy.get(), &profile.value(),
-                                    const_cast<struct pcm_config*>(&mConfig.value()),
-                                    true /*require_exact_match*/);
-            err != 0) {
-            LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device
-                       << " error=" << err;
-            return ::android::UNKNOWN_ERROR;
-        }
-        if (int err = proxy_open(proxy.get()); err != 0) {
-            LOG(ERROR) << __func__ << ": failed to open device, address=" << device
-                       << " error=" << err;
-            return ::android::UNKNOWN_ERROR;
+        if (!proxy) {
+            return ::android::NO_INIT;
         }
         alsaDeviceProxies.push_back(std::move(proxy));
     }
@@ -75,19 +94,20 @@
 
 ::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                          int32_t* latencyMs) {
+    if (mAlsaDeviceProxies.empty()) {
+        LOG(FATAL) << __func__ << ": no opened devices";
+        return ::android::NO_INIT;
+    }
     const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
     unsigned maxLatency = 0;
     if (mIsInput) {
-        if (mAlsaDeviceProxies.empty()) {
-            LOG(FATAL) << __func__ << ": no input devices";
-            return ::android::NO_INIT;
-        }
         // For input case, only support single device.
-        proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+        proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer,
+                                mReadWriteRetries);
         maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
     } else {
         for (auto& proxy : mAlsaDeviceProxies) {
-            proxy_write(proxy.get(), buffer, bytesToTransfer);
+            proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries);
             maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
         }
     }
@@ -97,11 +117,14 @@
     return ::android::OK;
 }
 
-::android::status_t StreamAlsa::getPosition(StreamDescriptor::Position* position) {
+::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
     if (mAlsaDeviceProxies.empty()) {
-        LOG(FATAL) << __func__ << ": no input devices";
+        LOG(FATAL) << __func__ << ": no opened devices";
         return ::android::NO_INIT;
     }
+    // Since the proxy can only count transferred frames since its creation,
+    // we override its counter value with ours and let it to correct for buffered frames.
+    alsa::resetTransferredFrames(mAlsaDeviceProxies[0], position->frames);
     if (mIsInput) {
         if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames,
                                                  &position->timeNs);
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
index 162f852..9dcd024 100644
--- a/audio/aidl/default/alsa/Utils.cpp
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -217,7 +217,8 @@
     }
     return DeviceProfile{.card = alsaAddress[0],
                          .device = alsaAddress[1],
-                         .direction = isInput ? PCM_IN : PCM_OUT};
+                         .direction = isInput ? PCM_IN : PCM_OUT,
+                         .isExternal = !audioDevice.type.connection.empty()};
 }
 
 std::optional<DeviceProfile> getDeviceProfile(
@@ -261,12 +262,65 @@
 }
 
 DeviceProxy makeDeviceProxy() {
-    return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
+    DeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
         if (proxy != nullptr) {
             proxy_close(proxy);
             delete proxy;
         }
     });
+    memset(proxy.get(), 0, sizeof(alsa_device_proxy));
+    return proxy;
+}
+
+DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, size_t bufferFrameCount) {
+    if (deviceProfile.isExternal) {
+        LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
+    }
+    alsa_device_profile profile;
+    profile_init(&profile, deviceProfile.direction);
+    profile.card = deviceProfile.card;
+    profile.device = deviceProfile.device;
+    if (!profile_fill_builtin_device_info(&profile, pcmConfig, bufferFrameCount)) {
+        LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
+    }
+    auto proxy = makeDeviceProxy();
+    if (int err = proxy_prepare_from_default_config(proxy.get(), &profile); err != 0) {
+        LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    if (int err = proxy_open(proxy.get()); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    return proxy;
+}
+
+DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, bool requireExactMatch) {
+    if (!deviceProfile.isExternal) {
+        LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
+    }
+    auto profile = readAlsaDeviceInfo(deviceProfile);
+    if (!profile.has_value()) {
+        LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
+        return nullptr;
+    }
+    auto proxy = makeDeviceProxy();
+    if (int err = proxy_prepare(proxy.get(), &profile.value(), pcmConfig, requireExactMatch);
+        err != 0) {
+        LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    if (int err = proxy_open(proxy.get()); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
+                   << " error=" << err;
+        return nullptr;
+    }
+    return proxy;
 }
 
 std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
@@ -282,6 +336,12 @@
     return profile;
 }
 
+void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
+    if (proxy != nullptr) {
+        proxy->transferred = frames;
+    }
+}
+
 AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
     return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
 }
diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h
index c1b9b38..37414b3 100644
--- a/audio/aidl/default/alsa/Utils.h
+++ b/audio/aidl/default/alsa/Utils.h
@@ -40,6 +40,7 @@
     int card;
     int device;
     int direction; /* PCM_OUT or PCM_IN */
+    bool isExternal;
 };
 std::ostream& operator<<(std::ostream& os, const DeviceProfile& device);
 using DeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
@@ -60,7 +61,12 @@
 std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput);
 std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile);
 DeviceProxy makeDeviceProxy();
+DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, size_t bufferFrameCount);
+DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
+                                       struct pcm_config* pcmConfig, bool requireExactMatch);
 std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
+void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames);
 
 ::aidl::android::media::audio::common::AudioFormatDescription
 c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
index 2068735..757976f 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
@@ -3,7 +3,7 @@
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
-    capabilities BLOCK_SUSPEND
+    capabilities BLOCK_SUSPEND SYS_NICE
     # setting RLIMIT_RTPRIO allows binder RT priority inheritance
     rlimit rtprio 10 10
     ioprio rt 4
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index c9d6314..9db6061 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -22,6 +22,11 @@
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
     <version>1</version>
+    <fqname>IModule/bluetooth</fqname>
+  </hal>
+  <hal format="aidl">
+    <name>android.hardware.audio.core</name>
+    <version>1</version>
     <fqname>IConfig/default</fqname>
   </hal>
 </manifest>
diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
new file mode 100644
index 0000000..12e204a
--- /dev/null
+++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_BluetoothPortProxy"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <audio_utils/primitives.h>
+#include <inttypes.h>
+#include <log/log.h>
+
+#include "core-impl/DevicePortProxy.h"
+
+namespace android::bluetooth::audio::aidl {
+
+namespace {
+
+// The maximum time to wait in std::condition_variable::wait_for()
+constexpr unsigned int kMaxWaitingTimeMs = 4500;
+
+}  // namespace
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
+using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
+using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
+using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
+using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using ::aidl::android::hardware::bluetooth::audio::SessionType;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+using ::aidl::android::media::audio::common::AudioDeviceType;
+using ::android::base::StringPrintf;
+
+std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
+    switch (state) {
+        case BluetoothStreamState::DISABLED:
+            return os << "DISABLED";
+        case BluetoothStreamState::STANDBY:
+            return os << "STANDBY";
+        case BluetoothStreamState::STARTING:
+            return os << "STARTING";
+        case BluetoothStreamState::STARTED:
+            return os << "STARTED";
+        case BluetoothStreamState::SUSPENDING:
+            return os << "SUSPENDING";
+        case BluetoothStreamState::UNKNOWN:
+            return os << "UNKNOWN";
+        default:
+            return os << android::base::StringPrintf("%#hhx", state);
+    }
+}
+
+BluetoothAudioPortAidl::BluetoothAudioPortAidl()
+    : mCookie(::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined),
+      mState(BluetoothStreamState::DISABLED),
+      mSessionType(SessionType::UNKNOWN) {}
+
+BluetoothAudioPortAidl::~BluetoothAudioPortAidl() {
+    unregisterPort();
+}
+
+bool BluetoothAudioPortAidl::registerPort(const AudioDeviceDescription& description) {
+    if (inUse()) {
+        LOG(ERROR) << __func__ << debugMessage() << " already in use";
+        return false;
+    }
+
+    if (!initSessionType(description)) return false;
+
+    auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
+                                           const BluetoothAudioStatus& status) {
+        (void)start_resp;
+        port->controlResultHandler(cookie, status);
+    };
+    auto session_changed_cb = [port = this](uint16_t cookie) {
+        port->sessionChangedHandler(cookie);
+    };
+    // TODO: Add audio_config_changed_cb
+    PortStatusCallbacks cbacks = {
+            .control_result_cb_ = control_result_cb,
+            .session_changed_cb_ = session_changed_cb,
+    };
+    mCookie = BluetoothAudioSessionControl::RegisterControlResultCback(mSessionType, cbacks);
+    auto isOk = (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
+    if (isOk) {
+        std::lock_guard guard(mCvMutex);
+        mState = BluetoothStreamState::STANDBY;
+    }
+    LOG(DEBUG) << __func__ << debugMessage();
+    return isOk;
+}
+
+bool BluetoothAudioPortAidl::initSessionType(const AudioDeviceDescription& description) {
+    if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP &&
+        (description.type == AudioDeviceType::OUT_DEVICE ||
+         description.type == AudioDeviceType::OUT_HEADPHONE ||
+         description.type == AudioDeviceType::OUT_SPEAKER)) {
+        LOG(VERBOSE) << __func__
+                     << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) ("
+                     << description.toString() << ")";
+        mSessionType = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
+               description.type == AudioDeviceType::OUT_HEARING_AID) {
+        LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) ("
+                     << description.toString() << ")";
+        mSessionType = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+               description.type == AudioDeviceType::OUT_HEADSET) {
+        LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_HEADSET (MEDIA/VOICE) ("
+                     << description.toString() << ")";
+        mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+               description.type == AudioDeviceType::OUT_SPEAKER) {
+        LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_SPEAKER (MEDIA) ("
+                     << description.toString() << ")";
+        mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+               description.type == AudioDeviceType::IN_HEADSET) {
+        LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_IN_BLE_HEADSET (VOICE) ("
+                     << description.toString() << ")";
+        mSessionType = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH;
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+               description.type == AudioDeviceType::OUT_BROADCAST) {
+        LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_BROADCAST (MEDIA) ("
+                     << description.toString() << ")";
+        mSessionType = SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH;
+    } else {
+        LOG(ERROR) << __func__ << ": unknown device=" << description.toString();
+        return false;
+    }
+
+    if (!BluetoothAudioSessionControl::IsSessionReady(mSessionType)) {
+        LOG(ERROR) << __func__ << ": device=" << description.toString()
+                   << ", session_type=" << toString(mSessionType) << " is not ready";
+        return false;
+    }
+    return true;
+}
+
+void BluetoothAudioPortAidl::unregisterPort() {
+    if (!inUse()) {
+        LOG(WARNING) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return;
+    }
+    BluetoothAudioSessionControl::UnregisterControlResultCback(mSessionType, mCookie);
+    mCookie = ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined;
+    LOG(VERBOSE) << __func__ << debugMessage() << " port unregistered";
+}
+
+void BluetoothAudioPortAidl::controlResultHandler(uint16_t cookie,
+                                                  const BluetoothAudioStatus& status) {
+    std::lock_guard guard(mCvMutex);
+    if (!inUse()) {
+        LOG(ERROR) << "control_result_cb: BluetoothAudioPortAidl is not in use";
+        return;
+    }
+    if (mCookie != cookie) {
+        LOG(ERROR) << "control_result_cb: proxy of device port (cookie="
+                   << StringPrintf("%#hx", cookie) << ") is corrupted";
+        return;
+    }
+    BluetoothStreamState previous_state = mState;
+    LOG(INFO) << "control_result_cb:" << debugMessage() << ", previous_state=" << previous_state
+              << ", status=" << toString(status);
+
+    switch (previous_state) {
+        case BluetoothStreamState::STARTED:
+            /* Only Suspend signal can be send in STARTED state*/
+            if (status == BluetoothAudioStatus::RECONFIGURATION ||
+                status == BluetoothAudioStatus::SUCCESS) {
+                mState = BluetoothStreamState::STANDBY;
+            } else {
+                LOG(WARNING) << StringPrintf(
+                        "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, "
+                        "previous_state=%#hhx",
+                        toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+                        previous_state);
+            }
+            break;
+        case BluetoothStreamState::STARTING:
+            if (status == BluetoothAudioStatus::SUCCESS) {
+                mState = BluetoothStreamState::STARTED;
+            } else {
+                // Set to standby since the stack may be busy switching between outputs
+                LOG(WARNING) << StringPrintf(
+                        "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, "
+                        "previous_state=%#hhx",
+                        toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+                        previous_state);
+                mState = BluetoothStreamState::STANDBY;
+            }
+            break;
+        case BluetoothStreamState::SUSPENDING:
+            if (status == BluetoothAudioStatus::SUCCESS) {
+                mState = BluetoothStreamState::STANDBY;
+            } else {
+                // It will be failed if the headset is disconnecting, and set to disable
+                // to wait for re-init again
+                LOG(WARNING) << StringPrintf(
+                        "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, "
+                        "previous_state=%#hhx",
+                        toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+                        previous_state);
+                mState = BluetoothStreamState::DISABLED;
+            }
+            break;
+        default:
+            LOG(ERROR) << "control_result_cb: unexpected previous_state="
+                       << StringPrintf(
+                                  "control_result_cb: status=%s failure for session_type= %s, "
+                                  "cookie=%#hx, previous_state=%#hhx",
+                                  toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+                                  previous_state);
+            return;
+    }
+    mInternalCv.notify_all();
+}
+
+void BluetoothAudioPortAidl::sessionChangedHandler(uint16_t cookie) {
+    std::lock_guard guard(mCvMutex);
+    if (!inUse()) {
+        LOG(ERROR) << "session_changed_cb: BluetoothAudioPortAidl is not in use";
+        return;
+    }
+    if (mCookie != cookie) {
+        LOG(ERROR) << "session_changed_cb: proxy of device port (cookie="
+                   << StringPrintf("%#hx", cookie) << ") is corrupted";
+        return;
+    }
+    BluetoothStreamState previous_state = mState;
+    LOG(VERBOSE) << "session_changed_cb:" << debugMessage()
+                 << ", previous_state=" << previous_state;
+    mState = BluetoothStreamState::DISABLED;
+    mInternalCv.notify_all();
+}
+
+bool BluetoothAudioPortAidl::inUse() const {
+    return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
+}
+
+bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
+    if (!interval_us) {
+        LOG(ERROR) << __func__ << ": bad input arg";
+        return false;
+    }
+
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+
+    const AudioConfiguration& hal_audio_cfg =
+            BluetoothAudioSessionControl::GetAudioConfig(mSessionType);
+    if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) {
+        LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
+        return false;
+    }
+
+    *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
+    return true;
+}
+
+bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
+    if (!audio_cfg) {
+        LOG(ERROR) << __func__ << ": bad input arg";
+        return false;
+    }
+
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+
+    const AudioConfiguration& hal_audio_cfg =
+            BluetoothAudioSessionControl::GetAudioConfig(mSessionType);
+    if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) {
+        LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
+        return false;
+    }
+    *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
+                 << audio_cfg->toString() << "]";
+    if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
+        return false;
+    }
+    return true;
+}
+
+bool BluetoothAudioPortAidl::standby() {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    std::lock_guard guard(mCvMutex);
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request";
+    if (mState == BluetoothStreamState::DISABLED) {
+        mState = BluetoothStreamState::STANDBY;
+        LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done";
+        return true;
+    }
+    return false;
+}
+
+bool BluetoothAudioPortAidl::condWaitState(BluetoothStreamState state) {
+    const auto waitTime = std::chrono::milliseconds(kMaxWaitingTimeMs);
+    std::unique_lock lock(mCvMutex);
+    base::ScopedLockAssertion lock_assertion(mCvMutex);
+    switch (state) {
+        case BluetoothStreamState::STARTING: {
+            LOG(VERBOSE) << __func__ << debugMessage() << " waiting for STARTED";
+            mInternalCv.wait_for(lock, waitTime, [this] {
+                base::ScopedLockAssertion lock_assertion(mCvMutex);
+                return mState != BluetoothStreamState::STARTING;
+            });
+            return mState == BluetoothStreamState::STARTED;
+        }
+        case BluetoothStreamState::SUSPENDING: {
+            LOG(VERBOSE) << __func__ << debugMessage() << " waiting for SUSPENDED";
+            mInternalCv.wait_for(lock, waitTime, [this] {
+                base::ScopedLockAssertion lock_assertion(mCvMutex);
+                return mState != BluetoothStreamState::SUSPENDING;
+            });
+            return mState == BluetoothStreamState::STANDBY;
+        }
+        default:
+            LOG(WARNING) << __func__ << debugMessage() << " waiting for KNOWN";
+            return false;
+    }
+    return false;
+}
+
+bool BluetoothAudioPortAidl::start() {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState()
+                 << ", mono=" << (mIsStereoToMono ? "true" : "false") << " request";
+
+    {
+        std::unique_lock lock(mCvMutex);
+        base::ScopedLockAssertion lock_assertion(mCvMutex);
+        if (mState == BluetoothStreamState::STARTED) {
+            return true;  // nop, return
+        } else if (mState == BluetoothStreamState::SUSPENDING ||
+                   mState == BluetoothStreamState::STARTING) {
+            /* If port is in transient state, give some time to respond */
+            auto state_ = mState;
+            lock.unlock();
+            if (!condWaitState(state_)) {
+                LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+                return false;
+            }
+        }
+    }
+
+    bool retval = false;
+    {
+        std::unique_lock lock(mCvMutex);
+        base::ScopedLockAssertion lock_assertion(mCvMutex);
+        if (mState == BluetoothStreamState::STARTED) {
+            retval = true;
+        } else if (mState == BluetoothStreamState::STANDBY) {
+            mState = BluetoothStreamState::STARTING;
+            lock.unlock();
+            if (BluetoothAudioSessionControl::StartStream(mSessionType)) {
+                retval = condWaitState(BluetoothStreamState::STARTING);
+            } else {
+                LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
+                           << " Hal fails";
+            }
+        }
+    }
+
+    if (retval) {
+        LOG(INFO) << __func__ << debugMessage() << ", state=" << getState()
+                  << ", mono=" << (mIsStereoToMono ? "true" : "false") << " done";
+    } else {
+        LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+    }
+
+    return retval;  // false if any failure like timeout
+}
+
+bool BluetoothAudioPortAidl::suspend() {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request";
+
+    {
+        std::unique_lock lock(mCvMutex);
+        base::ScopedLockAssertion lock_assertion(mCvMutex);
+        if (mState == BluetoothStreamState::STANDBY) {
+            return true;  // nop, return
+        } else if (mState == BluetoothStreamState::SUSPENDING ||
+                   mState == BluetoothStreamState::STARTING) {
+            /* If port is in transient state, give some time to respond */
+            auto state_ = mState;
+            lock.unlock();
+            if (!condWaitState(state_)) {
+                LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+                return false;
+            }
+        }
+    }
+
+    bool retval = false;
+    {
+        std::unique_lock lock(mCvMutex);
+        base::ScopedLockAssertion lock_assertion(mCvMutex);
+        if (mState == BluetoothStreamState::STANDBY) {
+            retval = true;
+        } else if (mState == BluetoothStreamState::STARTED) {
+            mState = BluetoothStreamState::SUSPENDING;
+            lock.unlock();
+            if (BluetoothAudioSessionControl::SuspendStream(mSessionType)) {
+                retval = condWaitState(BluetoothStreamState::SUSPENDING);
+            } else {
+                LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
+                           << " Hal fails";
+            }
+        }
+    }
+
+    if (retval) {
+        LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() << " done";
+    } else {
+        LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+    }
+
+    return retval;  // false if any failure like timeout
+}
+
+void BluetoothAudioPortAidl::stop() {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return;
+    }
+    std::lock_guard guard(mCvMutex);
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request";
+    if (mState != BluetoothStreamState::DISABLED) {
+        BluetoothAudioSessionControl::StopStream(mSessionType);
+        mState = BluetoothStreamState::DISABLED;
+    }
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done";
+}
+
+size_t BluetoothAudioPortAidlOut::writeData(const void* buffer, size_t bytes) const {
+    if (!buffer) {
+        LOG(ERROR) << __func__ << ": bad input arg";
+        return 0;
+    }
+
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return 0;
+    }
+
+    if (!mIsStereoToMono) {
+        return BluetoothAudioSessionControl::OutWritePcmData(mSessionType, buffer, bytes);
+    }
+
+    // WAR to mix the stereo into Mono (16 bits per sample)
+    const size_t write_frames = bytes >> 2;
+    if (write_frames == 0) return 0;
+    auto src = static_cast<const int16_t*>(buffer);
+    std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]};
+    downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames);
+    // a frame is 16 bits, and the size of a mono frame is equal to half a stereo.
+    auto totalWrite = BluetoothAudioSessionControl::OutWritePcmData(mSessionType, dst.get(),
+                                                                    write_frames * 2);
+    return totalWrite * 2;
+}
+
+size_t BluetoothAudioPortAidlIn::readData(void* buffer, size_t bytes) const {
+    if (!buffer) {
+        LOG(ERROR) << __func__ << ": bad input arg";
+        return 0;
+    }
+
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return 0;
+    }
+
+    return BluetoothAudioSessionControl::InReadPcmData(mSessionType, buffer, bytes);
+}
+
+bool BluetoothAudioPortAidl::getPresentationPosition(
+        PresentationPosition& presentation_position) const {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    bool retval = BluetoothAudioSessionControl::GetPresentationPosition(mSessionType,
+                                                                        presentation_position);
+    LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState()
+                 << presentation_position.toString();
+
+    return retval;
+}
+
+bool BluetoothAudioPortAidl::updateSourceMetadata(const SourceMetadata& source_metadata) const {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", "
+               << source_metadata.tracks.size() << " track(s)";
+    if (source_metadata.tracks.size() == 0) return true;
+    return BluetoothAudioSessionControl::UpdateSourceMetadata(mSessionType, source_metadata);
+}
+
+bool BluetoothAudioPortAidl::updateSinkMetadata(const SinkMetadata& sink_metadata) const {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", "
+               << sink_metadata.tracks.size() << " track(s)";
+    if (sink_metadata.tracks.size() == 0) return true;
+    return BluetoothAudioSessionControl::UpdateSinkMetadata(mSessionType, sink_metadata);
+}
+
+BluetoothStreamState BluetoothAudioPortAidl::getState() const {
+    return mState;
+}
+
+bool BluetoothAudioPortAidl::setState(BluetoothStreamState state) {
+    if (!inUse()) {
+        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+        return false;
+    }
+    std::lock_guard guard(mCvMutex);
+    LOG(DEBUG) << __func__ << ": BluetoothAudioPortAidl old state = " << mState
+               << " new state = " << state;
+    mState = state;
+    return true;
+}
+
+bool BluetoothAudioPortAidl::isA2dp() const {
+    return mSessionType == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+           mSessionType == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+bool BluetoothAudioPortAidl::isLeAudio() const {
+    return mSessionType == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
+           mSessionType == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
+           mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+           mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+           mSessionType == SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH ||
+           mSessionType == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+std::string BluetoothAudioPortAidl::debugMessage() const {
+    return StringPrintf(": session_type=%s, cookie=%#hx", toString(mSessionType).c_str(), mCookie);
+}
+
+}  // namespace android::bluetooth::audio::aidl
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
new file mode 100644
index 0000000..bfe7ca0
--- /dev/null
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_ModuleBluetooth"
+
+#include <android-base/logging.h>
+
+#include "core-impl/ModuleBluetooth.h"
+#include "core-impl/StreamBluetooth.h"
+
+namespace aidl::android::hardware::audio::core {
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::MicrophoneInfo;
+
+ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
+        std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
+    if (!mBluetoothA2dp) {
+        auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
+        handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
+        mBluetoothA2dp = handle;
+    }
+    *_aidl_return = mBluetoothA2dp.getInstance();
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
+    if (!mBluetoothLe) {
+        auto handle = ndk::SharedRefBase::make<BluetoothLe>();
+        handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
+        mBluetoothLe = handle;
+    }
+    *_aidl_return = mBluetoothLe.getInstance();
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
+Module::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
+    return std::make_tuple(std::weak_ptr<IBluetooth>(), mBluetoothA2dp.getInstance(),
+                           mBluetoothLe.getInstance());
+}
+
+ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::setMicMute(bool in_mute __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createInputStream(
+        StreamContext&& context, const SinkMetadata& sinkMetadata,
+        const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+    return createStreamInstance<StreamInBluetooth>(result, std::move(context), sinkMetadata,
+                                                   microphones, getBtProfileManagerHandles());
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
+        const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+    return createStreamInstance<StreamOutBluetooth>(result, std::move(context), sourceMetadata,
+                                                    offloadInfo, getBtProfileManagerHandles());
+}
+
+ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::onMasterVolumeChanged(float) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
new file mode 100644
index 0000000..91a33c2
--- /dev/null
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_StreamBluetooth"
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <audio_utils/clock.h>
+
+#include "BluetoothAudioSessionControl.h"
+#include "core-impl/StreamBluetooth.h"
+
+namespace aidl::android::hardware::audio::core {
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+using ::aidl::android::hardware::audio::core::VendorParameter;
+using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
+using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using ::aidl::android::media::audio::common::AudioChannelLayout;
+using ::aidl::android::media::audio::common::AudioDevice;
+using ::aidl::android::media::audio::common::AudioDeviceAddress;
+using ::aidl::android::media::audio::common::AudioFormatDescription;
+using ::aidl::android::media::audio::common::AudioFormatType;
+using ::aidl::android::media::audio::common::AudioOffloadInfo;
+using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
+using ::aidl::android::media::audio::common::MicrophoneInfo;
+using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
+using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+using ::android::bluetooth::audio::aidl::BluetoothStreamState;
+
+constexpr int kBluetoothDefaultInputBufferMs = 20;
+constexpr int kBluetoothDefaultOutputBufferMs = 10;
+// constexpr int kBluetoothSpatializerOutputBufferMs = 10;
+
+size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) {
+    return (durationUs * sampleRate) / 1000000;
+}
+
+// pcm configuration params are not really used by the module
+StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
+                                 Module::BtProfileHandles&& btHandles)
+    : StreamCommonImpl(context, metadata),
+      mSampleRate(getContext().getSampleRate()),
+      mChannelLayout(getContext().getChannelLayout()),
+      mFormat(getContext().getFormat()),
+      mFrameSizeBytes(getContext().getFrameSize()),
+      mIsInput(isInput(metadata)),
+      mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
+      mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
+    mPreferredDataIntervalUs =
+            mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
+    mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
+    mIsInitialized = false;
+    mIsReadyToClose = false;
+}
+
+::android::status_t StreamBluetooth::init() {
+    return ::android::OK;  // defering this till we get AudioDeviceDescription
+}
+
+const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
+    std::lock_guard guard(mLock);
+    return StreamCommonImpl::getConnectedDevices();
+}
+
+ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
+        const std::vector<AudioDevice>& connectedDevices) {
+    if (mIsInput && connectedDevices.size() > 1) {
+        LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
+                   << ") for input stream";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    for (const auto& connectedDevice : connectedDevices) {
+        if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
+            LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+    }
+    std::lock_guard guard(mLock);
+    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+    mIsInitialized = false;  // updated connected device list, need initialization
+    return ndk::ScopedAStatus::ok();
+}
+
+::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::flush() {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::pause() {
+    return standby();
+}
+
+::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
+                                              size_t* actualFrameCount, int32_t* latencyMs) {
+    std::lock_guard guard(mLock);
+    if (!mIsInitialized || mIsReadyToClose) {
+        // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
+        *actualFrameCount = 0;
+        *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
+        return ::android::OK;
+    }
+    *actualFrameCount = 0;
+    *latencyMs = 0;
+    for (auto proxy : mBtDeviceProxies) {
+        if (!proxy->start()) {
+            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
+            return -EIO;
+        }
+        const size_t fc = std::min(frameCount, mPreferredFrameCount);
+        const size_t bytesToTransfer = fc * mFrameSizeBytes;
+        if (mIsInput) {
+            const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
+            *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
+        } else {
+            const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
+            *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
+        }
+        PresentationPosition presentation_position;
+        if (!proxy->getPresentationPosition(presentation_position)) {
+            LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
+            return ::android::UNKNOWN_ERROR;
+        }
+        *latencyMs =
+                std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
+                                               NANOS_PER_MILLISECOND));
+    }
+    return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::initialize() {
+    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
+        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
+        return ::android::UNKNOWN_ERROR;
+    }
+    if (StreamCommonImpl::getConnectedDevices().empty()) {
+        LOG(ERROR) << __func__ << ", has no connected devices";
+        return ::android::NO_INIT;
+    }
+    // unregister older proxies (if any)
+    for (auto proxy : mBtDeviceProxies) {
+        proxy->stop();
+        proxy->unregisterPort();
+    }
+    mBtDeviceProxies.clear();
+    for (auto it = StreamCommonImpl::getConnectedDevices().begin();
+         it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
+        std::shared_ptr<BluetoothAudioPortAidl> proxy =
+                mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
+                                   std::make_shared<BluetoothAudioPortAidlIn>())
+                         : std::shared_ptr<BluetoothAudioPortAidl>(
+                                   std::make_shared<BluetoothAudioPortAidlOut>());
+        if (proxy->registerPort(it->type)) {
+            LOG(ERROR) << __func__ << ": cannot init HAL";
+            return ::android::UNKNOWN_ERROR;
+        }
+        PcmConfiguration config;
+        if (!proxy->loadAudioConfig(&config)) {
+            LOG(ERROR) << __func__ << ": state=" << proxy->getState()
+                       << " failed to get audio config";
+            return ::android::UNKNOWN_ERROR;
+        }
+        // TODO: Ensure minimum duration for spatialized output?
+        // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
+        if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
+            proxy->forcePcmStereoToMono(true);
+            config.channelMode = ChannelMode::STEREO;
+            LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
+        }
+        if (!checkConfigParams(config)) {
+            LOG(ERROR) << __func__ << " checkConfigParams failed";
+            return ::android::UNKNOWN_ERROR;
+        }
+        mBtDeviceProxies.push_back(std::move(proxy));
+    }
+    mIsInitialized = true;
+    return ::android::OK;
+}
+
+bool StreamBluetooth::checkConfigParams(
+        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
+    if ((int)mSampleRate != config.sampleRateHz) {
+        LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
+                   << " hal val = " << config.sampleRateHz;
+        return false;
+    }
+    auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
+    if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
+        (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
+        LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
+                   << " hal val = " << toString(config.channelMode);
+        return false;
+    }
+    if (mFormat.type != AudioFormatType::PCM) {
+        LOG(ERROR) << __func__ << ": unexpected format type "
+                   << aidl::android::media::audio::common::toString(mFormat.type);
+        return false;
+    }
+    int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
+    if (bps != config.bitsPerSample) {
+        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
+                   << " hal val = " << config.bitsPerSample;
+        return false;
+    }
+    if (config.dataIntervalUs > 0) {
+        mPreferredDataIntervalUs =
+                std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
+        mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
+    }
+    return true;
+}
+
+ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
+    std::lock_guard guard(mLock);
+    mIsReadyToClose = true;
+    return ndk::ScopedAStatus::ok();
+}
+
+::android::status_t StreamBluetooth::standby() {
+    std::lock_guard guard(mLock);
+    if (!mIsInitialized) {
+        if (auto status = initialize(); status != ::android::OK) return status;
+    }
+    for (auto proxy : mBtDeviceProxies) {
+        if (!proxy->suspend()) {
+            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
+            return -EIO;
+        }
+    }
+    return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::start() {
+    std::lock_guard guard(mLock);
+    if (!mIsInitialized) return initialize();
+    return ::android::OK;
+}
+
+void StreamBluetooth::shutdown() {
+    std::lock_guard guard(mLock);
+    for (auto proxy : mBtDeviceProxies) {
+        proxy->stop();
+        proxy->unregisterPort();
+    }
+    mBtDeviceProxies.clear();
+}
+
+ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
+    std::lock_guard guard(mLock);
+    if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    bool isOk = true;
+    if (isInput(metadata)) {
+        isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
+    } else {
+        for (auto proxy : mBtDeviceProxies) {
+            if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
+        }
+    }
+    return isOk ? ndk::ScopedAStatus::ok()
+                : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
+    if (mIsInput) {
+        LOG(WARNING) << __func__ << ": not handled";
+        return ndk::ScopedAStatus::ok();
+    }
+    auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
+                         bool isEnabled) -> bool {
+        if (!isEnabled) {
+            if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED);
+            return false;
+        }
+        return proxy->standby();
+    };
+    bool hasA2dpParam, enableA2dp;
+    auto btA2dp = mBluetoothA2dp.lock();
+    hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk();
+    bool hasLeParam, enableLe;
+    auto btLe = mBluetoothLe.lock();
+    hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
+    std::unique_lock lock(mLock);
+    ::android::base::ScopedLockAssertion lock_assertion(mLock);
+    if (!mIsInitialized) {
+        LOG(WARNING) << __func__ << ": init not done";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    for (auto proxy : mBtDeviceProxies) {
+        if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
+            (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
+            LOG(DEBUG) << __func__ << ": applyParam failed";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
+                                     const std::vector<MicrophoneInfo>& microphones,
+                                     Module::BtProfileHandles&& btProfileHandles)
+    : StreamIn(std::move(context), microphones),
+      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
+
+ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
+        std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
+    LOG(DEBUG) << __func__ << ": not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
+                                       const SourceMetadata& sourceMetadata,
+                                       const std::optional<AudioOffloadInfo>& offloadInfo,
+                                       Module::BtProfileHandles&& btProfileHandles)
+    : StreamOut(std::move(context), offloadInfo),
+      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
index 59574f3..063b05d 100644
--- a/audio/aidl/default/config/audioPolicy/engine/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -209,11 +209,13 @@
   public enum UsageEnumType {
     method @NonNull public String getRawName();
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ALARM;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANT;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_EMERGENCY;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_GAME;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_MEDIA;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION;
@@ -222,7 +224,9 @@
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_SAFETY;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
     enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
index b58a6c8..40396bb 100644
--- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -359,6 +359,10 @@
             <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
             <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
             <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+            <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+            <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+            <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
         </xs:restriction>
     </xs:simpleType>
 
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
index 10e9045..44899bc 100644
--- a/audio/aidl/default/include/core-impl/Bluetooth.h
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -22,6 +22,15 @@
 
 namespace aidl::android::hardware::audio::core {
 
+class ParamChangeHandler {
+  public:
+    ParamChangeHandler() = default;
+    void registerHandler(std::function<ndk::ScopedAStatus()> handler) { mHandler = handler; }
+
+  protected:
+    std::function<ndk::ScopedAStatus()> mHandler = nullptr;
+};
+
 class Bluetooth : public BnBluetooth {
   public:
     Bluetooth();
@@ -34,7 +43,7 @@
     HfpConfig mHfpConfig;
 };
 
-class BluetoothA2dp : public BnBluetoothA2dp {
+class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
   public:
     BluetoothA2dp() = default;
 
@@ -49,7 +58,7 @@
     bool mEnabled = false;
 };
 
-class BluetoothLe : public BnBluetoothLe {
+class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler {
   public:
     BluetoothLe() = default;
 
diff --git a/audio/aidl/default/include/core-impl/ChildInterface.h b/audio/aidl/default/include/core-impl/ChildInterface.h
index 1b31691..2421b59 100644
--- a/audio/aidl/default/include/core-impl/ChildInterface.h
+++ b/audio/aidl/default/include/core-impl/ChildInterface.h
@@ -35,14 +35,20 @@
     }
     ChildInterface& operator=(std::shared_ptr<C>&& c) {
         this->first = std::move(c);
-        this->second = this->first->asBinder();
-        AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
         return *this;
     }
     explicit operator bool() const { return !!this->first; }
     C& operator*() const { return *(this->first); }
     C* operator->() const { return this->first; }
-    std::shared_ptr<C> getPtr() const { return this->first; }
+    // Use 'getInstance' when returning the interface instance.
+    std::shared_ptr<C> getInstance() {
+        if (this->second.get() == nullptr) {
+            this->second = this->first->asBinder();
+            AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL,
+                                           ANDROID_PRIORITY_AUDIO);
+        }
+        return this->first;
+    }
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 25bf7af..6277c38 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -47,5 +47,6 @@
 std::unique_ptr<Configuration> getRSubmixConfiguration();
 std::unique_ptr<Configuration> getStubConfiguration();
 std::unique_ptr<Configuration> getUsbConfiguration();
+std::unique_ptr<Configuration> getBluetoothConfiguration();
 
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h
new file mode 100644
index 0000000..13b8c91
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <condition_variable>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
+
+#include <aidl/android/hardware/audio/common/SinkMetadata.h>
+#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <aidl/android/media/audio/common/AudioDeviceDescription.h>
+
+#include "BluetoothAudioSessionControl.h"
+
+namespace android::bluetooth::audio::aidl {
+
+enum class BluetoothStreamState : uint8_t {
+    DISABLED = 0,  // This stream is closing or Bluetooth profiles (A2DP/LE) is disabled
+    STANDBY,
+    STARTING,
+    STARTED,
+    SUSPENDING,
+    UNKNOWN,
+};
+
+std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state);
+
+/**
+ * Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio
+ * Session Control. All methods are not thread safe, so users must acquire a
+ * lock. Note: currently, getState() of DevicePortProxy is only used for
+ * verbose logging, it is not locked, so the state may not be synchronized.
+ */
+class BluetoothAudioPort {
+  public:
+    BluetoothAudioPort() = default;
+    virtual ~BluetoothAudioPort() = default;
+
+    /**
+     * Fetch output control / data path of BluetoothAudioPort and setup
+     * callbacks into BluetoothAudioProvider. If registerPort() returns false, the audio
+     * HAL must delete this BluetoothAudioPort and return EINVAL to caller
+     */
+    virtual bool registerPort(
+            const ::aidl::android::media::audio::common::AudioDeviceDescription&) = 0;
+
+    /**
+     * Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
+     * Audio HAL must delete this BluetoothAudioPort after calling this.
+     */
+    virtual void unregisterPort() = 0;
+
+    /**
+     * When the Audio framework / HAL tries to query audio config about format,
+     * channel mask and sample rate, it uses this function to fetch from the
+     * Bluetooth stack
+     */
+    virtual bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0;
+
+    /**
+     * WAR to support Mono mode / 16 bits per sample
+     */
+    virtual void forcePcmStereoToMono(bool) = 0;
+
+    /**
+     * When the Audio framework / HAL wants to change the stream state, it invokes
+     * these 4 functions to control the Bluetooth stack (Audio Control Path).
+     * Note: standby(), start() and suspend() will return true when there are no errors.
+
+     * Called by Audio framework / HAL to change the state to stand by. When A2DP/LE profile is
+     * disabled, the port is first set to STANDBY by calling suspend and then mState is set to
+     * DISABLED. To reset the state back to STANDBY this method is called.
+     */
+    virtual bool standby() = 0;
+
+    /**
+     * Called by Audio framework / HAL to start the stream
+     */
+    virtual bool start() = 0;
+
+    /**
+     * Called by Audio framework / HAL to suspend the stream
+     */
+    virtual bool suspend() = 0;
+
+    /**
+     * Called by Audio framework / HAL to stop the stream
+     */
+    virtual void stop() = 0;
+
+    /**
+     * Called by the Audio framework / HAL to fetch information about audio frames
+     * presented to an external sink, or frames presented fror an internal sink
+     */
+    virtual bool getPresentationPosition(
+            ::aidl::android::hardware::bluetooth::audio::PresentationPosition&) const = 0;
+
+    /**
+     * Called by the Audio framework / HAL when the metadata of the stream's
+     * source has been changed.
+     */
+    virtual bool updateSourceMetadata(
+            const ::aidl::android::hardware::audio::common::SourceMetadata&) const {
+        return false;
+    }
+
+    /**
+     * Called by the Audio framework / HAL when the metadata of the stream's
+     * sink has been changed.
+     */
+    virtual bool updateSinkMetadata(
+            const ::aidl::android::hardware::audio::common::SinkMetadata&) const {
+        return false;
+    }
+
+    /**
+     * Return the current BluetoothStreamState
+     */
+    virtual BluetoothStreamState getState() const = 0;
+
+    /**
+     * Set the current BluetoothStreamState
+     */
+    virtual bool setState(BluetoothStreamState) = 0;
+
+    virtual bool isA2dp() const = 0;
+
+    virtual bool isLeAudio() const = 0;
+
+    virtual bool getPreferredDataIntervalUs(size_t*) const = 0;
+
+    virtual size_t writeData(const void*, size_t) const { return 0; }
+
+    virtual size_t readData(void*, size_t) const { return 0; }
+};
+
+class BluetoothAudioPortAidl : public BluetoothAudioPort {
+  public:
+    BluetoothAudioPortAidl();
+    virtual ~BluetoothAudioPortAidl();
+
+    bool registerPort(const ::aidl::android::media::audio::common::AudioDeviceDescription&
+                              description) override;
+
+    void unregisterPort() override;
+
+    bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg)
+            const override;
+
+    void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; }
+
+    bool standby() override;
+    bool start() override;
+    bool suspend() override;
+    void stop() override;
+
+    bool getPresentationPosition(::aidl::android::hardware::bluetooth::audio::PresentationPosition&
+                                         presentation_position) const override;
+
+    bool updateSourceMetadata(const ::aidl::android::hardware::audio::common::SourceMetadata&
+                                      sourceMetadata) const override;
+
+    bool updateSinkMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
+                                    sinkMetadata) const override;
+
+    /**
+     * Return the current BluetoothStreamState
+     * Note: This method is used for logging, does not lock, so value returned may not be latest
+     */
+    BluetoothStreamState getState() const override NO_THREAD_SAFETY_ANALYSIS;
+
+    bool setState(BluetoothStreamState state) override;
+
+    bool isA2dp() const override;
+
+    bool isLeAudio() const override;
+
+    bool getPreferredDataIntervalUs(size_t* interval_us) const override;
+
+  protected:
+    uint16_t mCookie;
+    BluetoothStreamState mState GUARDED_BY(mCvMutex);
+    ::aidl::android::hardware::bluetooth::audio::SessionType mSessionType;
+    // WR to support Mono: True if fetching Stereo and mixing into Mono
+    bool mIsStereoToMono = false;
+
+    bool inUse() const;
+
+    std::string debugMessage() const;
+
+  private:
+    // start()/suspend() report state change status via callback. Wait until kMaxWaitingTimeMs or a
+    // state change after a call to start()/suspend() and analyse the returned status. Below mutex,
+    // conditional variable serves this purpose.
+    mutable std::mutex mCvMutex;
+    std::condition_variable mInternalCv GUARDED_BY(mCvMutex);
+
+    // Check and initialize session type for |devices| If failed, this
+    // BluetoothAudioPortAidl is not initialized and must be deleted.
+    bool initSessionType(
+            const ::aidl::android::media::audio::common::AudioDeviceDescription& description);
+
+    bool condWaitState(BluetoothStreamState state);
+
+    void controlResultHandler(
+            uint16_t cookie,
+            const ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus& status);
+    void sessionChangedHandler(uint16_t cookie);
+};
+
+class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
+  public:
+    // The audio data path to the Bluetooth stack (Software encoding)
+    size_t writeData(const void* buffer, size_t bytes) const override;
+};
+
+class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
+  public:
+    // The audio data path from the Bluetooth stack (Software decoded)
+    size_t readData(void* buffer, size_t bytes) const override;
+};
+
+}  // namespace android::bluetooth::audio::aidl
\ No newline at end of file
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 294cc0e..fb3eef2 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -33,12 +33,17 @@
   public:
     // This value is used for all AudioPatches and reported by all streams.
     static constexpr int32_t kLatencyMs = 10;
-    enum Type : int { DEFAULT, R_SUBMIX, STUB, USB };
+    enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH };
+    enum BtInterface : int { BTCONF, BTA2DP, BTLE };
 
     static std::shared_ptr<Module> createInstance(Type type);
 
     explicit Module(Type type) : mType(type) {}
 
+    typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
+                       std::weak_ptr<IBluetoothLe>>
+            BtProfileHandles;
+
   protected:
     // The vendor extension done via inheritance can override interface methods and augment
     // a call to the base implementation.
@@ -159,13 +164,13 @@
     // The following virtual functions are intended for vendor extension via inheritance.
 
     virtual ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) = 0;
     virtual ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) = 0;
@@ -185,6 +190,7 @@
     virtual std::unique_ptr<internal::Configuration> initializeConfig();
 
     // Utility and helper functions accessible to subclasses.
+    ndk::ScopedAStatus bluetoothParametersUpdated();
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
             int32_t in_portConfigId, int64_t in_bufferSizeFrames,
@@ -196,6 +202,7 @@
     std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
     ndk::ScopedAStatus findPortIdForNewStream(
             int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
+    virtual BtProfileHandles getBtProfileManagerHandles();
     internal::Configuration& getConfig();
     const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
     bool getMasterMute() const { return mMasterMute; }
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
new file mode 100644
index 0000000..68b4e6b
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "core-impl/Bluetooth.h"
+#include "core-impl/Module.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class ModuleBluetooth final : public Module {
+  public:
+    ModuleBluetooth() : Module(Type::BLUETOOTH) {}
+
+  private:
+    BtProfileHandles getBtProfileManagerHandles() override;
+
+    ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
+    ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
+    ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+    ndk::ScopedAStatus setMicMute(bool in_mute) override;
+
+    ndk::ScopedAStatus createInputStream(
+            StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
+            std::shared_ptr<StreamIn>* result) override;
+    ndk::ScopedAStatus createOutputStream(
+            StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+            const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                    offloadInfo,
+            std::shared_ptr<StreamOut>* result) override;
+    ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
+    ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+
+    ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
+    ChildInterface<IBluetoothLe> mBluetoothLe;
+};
+
+}  // namespace aidl::android::hardware::audio::core
\ No newline at end of file
diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h
index bc808ab..6264237 100644
--- a/audio/aidl/default/include/core-impl/ModulePrimary.h
+++ b/audio/aidl/default/include/core-impl/ModulePrimary.h
@@ -28,13 +28,13 @@
     ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
 
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
index ccfcdd9..c4bf7b9 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -26,20 +26,18 @@
 
   private:
     // IModule interfaces
-    ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
-    ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
@@ -49,9 +47,6 @@
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
             override;
-    void onExternalDeviceConnectionChanged(
-            const ::aidl::android::media::audio::common::AudioPort& audioPort,
-            bool connected) override;
     ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
     ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
 };
diff --git a/audio/aidl/default/include/core-impl/ModuleStub.h b/audio/aidl/default/include/core-impl/ModuleStub.h
index 59c343f..4f77161 100644
--- a/audio/aidl/default/include/core-impl/ModuleStub.h
+++ b/audio/aidl/default/include/core-impl/ModuleStub.h
@@ -30,13 +30,13 @@
     ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
 
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h
index e6b3e66..a296b8c 100644
--- a/audio/aidl/default/include/core-impl/ModuleUsb.h
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -33,13 +33,13 @@
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
             std::shared_ptr<StreamIn>* result) override;
     ndk::ScopedAStatus createOutputStream(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index e64c578..a02655f 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -43,6 +43,7 @@
 #include <system/thread_defs.h>
 #include <utils/Errors.h>
 
+#include "core-impl/ChildInterface.h"
 #include "core-impl/utils.h"
 
 namespace aidl::android::hardware::audio::core {
@@ -65,7 +66,8 @@
             DataMQ;
 
     // Ensure that this value is not used by any of StreamDescriptor.State enums
-    static constexpr int32_t STATE_CLOSED = -1;
+    static constexpr StreamDescriptor::State STATE_CLOSED =
+            static_cast<StreamDescriptor::State>(-1);
 
     struct DebugParameters {
         // An extra delay for transient states, in ms.
@@ -112,7 +114,8 @@
           mDataMQ(std::move(other.mDataMQ)),
           mAsyncCallback(std::move(other.mAsyncCallback)),
           mOutEventCallback(std::move(other.mOutEventCallback)),
-          mDebugParameters(std::move(other.mDebugParameters)) {}
+          mDebugParameters(std::move(other.mDebugParameters)),
+          mFrameCount(other.mFrameCount) {}
     StreamContext& operator=(StreamContext&& other) {
         mCommandMQ = std::move(other.mCommandMQ);
         mInternalCommandCookie = other.mInternalCommandCookie;
@@ -127,11 +130,13 @@
         mAsyncCallback = std::move(other.mAsyncCallback);
         mOutEventCallback = std::move(other.mOutEventCallback);
         mDebugParameters = std::move(other.mDebugParameters);
+        mFrameCount = other.mFrameCount;
         return *this;
     }
 
     void fillDescriptor(StreamDescriptor* desc);
     std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
+    size_t getBufferSizeInFrames() const;
     ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
         return mChannelLayout;
     }
@@ -154,7 +159,12 @@
     int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
     int getSampleRate() const { return mSampleRate; }
     bool isValid() const;
+    // 'reset' is called on a Binder thread when closing the stream. Does not use
+    // locking because it only cleans MQ pointers which were also set on the Binder thread.
     void reset();
+    // 'advanceFrameCount' and 'getFrameCount' are only called on the worker thread.
+    long advanceFrameCount(size_t increase) { return mFrameCount += increase; }
+    long getFrameCount() const { return mFrameCount; }
 
   private:
     std::unique_ptr<CommandMQ> mCommandMQ;
@@ -170,6 +180,7 @@
     std::shared_ptr<IStreamCallback> mAsyncCallback;
     std::shared_ptr<IStreamOutEventCallback> mOutEventCallback;  // Only used by output streams
     DebugParameters mDebugParameters;
+    long mFrameCount = 0;
 };
 
 // This interface provides operations of the stream which are executed on the worker thread.
@@ -184,10 +195,10 @@
     virtual ::android::status_t start() = 0;
     virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                          int32_t* latencyMs) = 0;
-    // No need to implement 'getPosition' unless the driver can provide more precise
+    // No need to implement 'refinePosition' unless the driver can provide more precise
     // data than just total frame count. For example, the driver may correctly account
     // for any intermediate buffers.
-    virtual ::android::status_t getPosition(StreamDescriptor::Position* /*position*/) {
+    virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
         return ::android::OK;
     }
     virtual void shutdown() = 0;  // This function is only called once.
@@ -195,26 +206,23 @@
 
 class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
   public:
-    bool isClosed() const {
-        return static_cast<int32_t>(mState.load()) == StreamContext::STATE_CLOSED;
+    bool isClosed() const { return mState == StreamContext::STATE_CLOSED; }
+    StreamDescriptor::State setClosed() {
+        auto prevState = mState.exchange(StreamContext::STATE_CLOSED);
+        if (prevState != StreamContext::STATE_CLOSED) {
+            mStatePriorToClosing = prevState;
+        }
+        return mStatePriorToClosing;
     }
-    void setClosed() { mState = static_cast<StreamDescriptor::State>(StreamContext::STATE_CLOSED); }
     void setIsConnected(bool connected) { mIsConnected = connected; }
 
   protected:
     using DataBufferElement = int8_t;
 
-    StreamWorkerCommonLogic(const StreamContext& context, DriverInterface* driver)
-        : mDriver(driver),
-          mInternalCommandCookie(context.getInternalCommandCookie()),
-          mFrameSize(context.getFrameSize()),
-          mCommandMQ(context.getCommandMQ()),
-          mReplyMQ(context.getReplyMQ()),
-          mDataMQ(context.getDataMQ()),
-          mAsyncCallback(context.getAsyncCallback()),
-          mTransientStateDelayMs(context.getTransientStateDelayMs()),
-          mForceTransientBurst(context.getForceTransientBurst()),
-          mForceSynchronousDrain(context.getForceSynchronousDrain()) {}
+    StreamWorkerCommonLogic(StreamContext* context, DriverInterface* driver)
+        : mContext(context),
+          mDriver(driver),
+          mTransientStateDelayMs(context->getTransientStateDelayMs()) {}
     std::string init() override;
     void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
     void populateReplyWrongState(StreamDescriptor::Reply* reply,
@@ -224,39 +232,37 @@
         mTransientStateStart = std::chrono::steady_clock::now();
     }
 
+    // The context is only used for reading, except for updating the frame count,
+    // which happens on the worker thread only.
+    StreamContext* const mContext;
     DriverInterface* const mDriver;
+    // This is the state the stream was in before being closed. It is retrieved by the main
+    // thread after joining the worker thread.
+    StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY;
     // Atomic fields are used both by the main and worker threads.
     std::atomic<bool> mIsConnected = false;
     static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
     std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
-    // All fields are used on the worker thread only.
-    const int mInternalCommandCookie;
-    const size_t mFrameSize;
-    StreamContext::CommandMQ* const mCommandMQ;
-    StreamContext::ReplyMQ* const mReplyMQ;
-    StreamContext::DataMQ* const mDataMQ;
-    std::shared_ptr<IStreamCallback> mAsyncCallback;
+    // All fields below are used on the worker thread only.
     const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
     std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
-    const bool mForceTransientBurst;
-    const bool mForceSynchronousDrain;
     // We use an array and the "size" field instead of a vector to be able to detect
     // memory allocation issues.
     std::unique_ptr<DataBufferElement[]> mDataBuffer;
     size_t mDataBufferSize;
-    long mFrameCount = 0;
 };
 
 // This interface is used to decouple stream implementations from a concrete StreamWorker
 // implementation.
 struct StreamWorkerInterface {
-    using CreateInstance = std::function<StreamWorkerInterface*(const StreamContext& context,
-                                                                DriverInterface* driver)>;
+    using CreateInstance =
+            std::function<StreamWorkerInterface*(StreamContext* context, DriverInterface* driver)>;
     virtual ~StreamWorkerInterface() = default;
     virtual bool isClosed() const = 0;
     virtual void setIsConnected(bool isConnected) = 0;
-    virtual void setClosed() = 0;
+    virtual StreamDescriptor::State setClosed() = 0;
     virtual bool start() = 0;
+    virtual pid_t getTid() = 0;
     virtual void stop() = 0;
 };
 
@@ -266,21 +272,23 @@
     using WorkerImpl = ::android::hardware::audio::common::StreamWorker<WorkerLogic>;
 
   public:
-    StreamWorkerImpl(const StreamContext& context, DriverInterface* driver)
+    StreamWorkerImpl(StreamContext* context, DriverInterface* driver)
         : WorkerImpl(context, driver) {}
     bool isClosed() const override { return WorkerImpl::isClosed(); }
     void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); }
-    void setClosed() override { WorkerImpl::setClosed(); }
+    StreamDescriptor::State setClosed() override { return WorkerImpl::setClosed(); }
     bool start() override {
-        return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_AUDIO);
+        // This is an "audio service thread," must have elevated priority.
+        return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
     }
+    pid_t getTid() override { return WorkerImpl::getTid(); }
     void stop() override { return WorkerImpl::stop(); }
 };
 
 class StreamInWorkerLogic : public StreamWorkerCommonLogic {
   public:
     static const std::string kThreadName;
-    StreamInWorkerLogic(const StreamContext& context, DriverInterface* driver)
+    StreamInWorkerLogic(StreamContext* context, DriverInterface* driver)
         : StreamWorkerCommonLogic(context, driver) {}
 
   protected:
@@ -294,8 +302,9 @@
 class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
   public:
     static const std::string kThreadName;
-    StreamOutWorkerLogic(const StreamContext& context, DriverInterface* driver)
-        : StreamWorkerCommonLogic(context, driver), mEventCallback(context.getOutEventCallback()) {}
+    StreamOutWorkerLogic(StreamContext* context, DriverInterface* driver)
+        : StreamWorkerCommonLogic(context, driver),
+          mEventCallback(context->getOutEventCallback()) {}
 
   protected:
     Status cycle() override;
@@ -348,6 +357,7 @@
     virtual const ConnectedDevices& getConnectedDevices() const = 0;
     virtual ndk::ScopedAStatus setConnectedDevices(
             const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0;
+    virtual ndk::ScopedAStatus bluetoothParametersUpdated() = 0;
 };
 
 // This is equivalent to automatically generated 'IStreamCommonDelegator' but uses
@@ -409,16 +419,17 @@
 };
 
 // The implementation of DriverInterface must be provided by each concrete stream implementation.
+// Note that StreamCommonImpl does not own the context. This is to support swapping on the fly
+// implementations of the stream while keeping the same IStreamIn/Out instance. It's that instance
+// who must be owner of the context.
 class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface {
   public:
-    StreamCommonImpl(const Metadata& metadata, StreamContext&& context,
+    StreamCommonImpl(StreamContext* context, const Metadata& metadata,
                      const StreamWorkerInterface::CreateInstance& createWorker)
-        : mMetadata(metadata),
-          mContext(std::move(context)),
-          mWorker(createWorker(mContext, this)) {}
-    StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
+        : mContext(*context), mMetadata(metadata), mWorker(createWorker(context, this)) {}
+    StreamCommonImpl(StreamContext* context, const Metadata& metadata)
         : StreamCommonImpl(
-                  metadata, std::move(context),
+                  context, metadata,
                   isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {}
     ~StreamCommonImpl();
 
@@ -447,26 +458,27 @@
     ndk::ScopedAStatus setConnectedDevices(
             const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
             override;
+    ndk::ScopedAStatus bluetoothParametersUpdated() override;
 
   protected:
     static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() {
-        return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
+        return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* {
             return new StreamInWorker(ctx, driver);
         };
     }
     static StreamWorkerInterface::CreateInstance getDefaultOutWorkerCreator() {
-        return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
+        return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* {
             return new StreamOutWorker(ctx, driver);
         };
     }
 
+    virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0;
     void stopWorker();
 
+    const StreamContext& mContext;
     Metadata mMetadata;
-    StreamContext mContext;
     std::unique_ptr<StreamWorkerInterface> mWorker;
-    std::shared_ptr<StreamCommonDelegator> mCommon;
-    ndk::SpAIBinder mCommonBinder;
+    ChildInterface<StreamCommonDelegator> mCommon;
     ConnectedDevices mConnectedDevices;
 };
 
@@ -474,6 +486,8 @@
 // concrete input/output stream implementations.
 class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
   protected:
+    void defaultOnClose();
+
     ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
         return getStreamCommonCommon(_aidl_return);
     }
@@ -493,14 +507,28 @@
 
     friend class ndk::SharedRefBase;
 
-    explicit StreamIn(
-            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
+    StreamIn(StreamContext&& context,
+             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
 
+    StreamContext mContextInstance;
     const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
 };
 
+class StreamInHwGainHelper {
+  protected:
+    explicit StreamInHwGainHelper(const StreamContext* context);
+
+    ndk::ScopedAStatus getHwGainImpl(std::vector<float>* _aidl_return);
+    ndk::ScopedAStatus setHwGainImpl(const std::vector<float>& in_channelGains);
+
+    const size_t mChannelCount;
+    std::vector<float> mHwGains;
+};
+
 class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
   protected:
+    void defaultOnClose();
+
     ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
         return getStreamCommonCommon(_aidl_return);
     }
@@ -534,13 +562,26 @@
 
     friend class ndk::SharedRefBase;
 
-    explicit StreamOut(const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
-                               offloadInfo);
+    StreamOut(StreamContext&& context,
+              const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                      offloadInfo);
 
-    std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
+    StreamContext mContextInstance;
+    const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
     std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
 };
 
+class StreamOutHwVolumeHelper {
+  protected:
+    explicit StreamOutHwVolumeHelper(const StreamContext* context);
+
+    ndk::ScopedAStatus getHwVolumeImpl(std::vector<float>* _aidl_return);
+    ndk::ScopedAStatus setHwVolumeImpl(const std::vector<float>& in_channelVolumes);
+
+    const size_t mChannelCount;
+    std::vector<float> mHwVolumes;
+};
+
 // The recommended way to create a stream instance.
 // 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
 // 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'.
@@ -570,6 +611,11 @@
         if (s) return s->setConnectedDevices(devices);
         return ndk::ScopedAStatus::ok();
     }
+    ndk::ScopedAStatus bluetoothParametersUpdated() {
+        auto s = mStream.lock();
+        if (s) return s->bluetoothParametersUpdated();
+        return ndk::ScopedAStatus::ok();
+    }
 
   private:
     std::weak_ptr<StreamCommonInterface> mStream;
@@ -598,6 +644,14 @@
         }
         return ndk::ScopedAStatus::ok();
     }
+    ndk::ScopedAStatus bluetoothParametersUpdated() {
+        bool isOk = true;
+        for (auto& it : mStreams) {
+            if (!it.second.bluetoothParametersUpdated().isOk()) isOk = false;
+        }
+        return isOk ? ndk::ScopedAStatus::ok()
+                    : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
 
   private:
     // Maps port ids and port config ids to streams. Multimap because a port
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
index 5744d66..2c3b284 100644
--- a/audio/aidl/default/include/core-impl/StreamAlsa.h
+++ b/audio/aidl/default/include/core-impl/StreamAlsa.h
@@ -31,23 +31,29 @@
 // provide necessary overrides for all interface methods omitted here.
 class StreamAlsa : public StreamCommonImpl {
   public:
-    StreamAlsa(const Metadata& metadata, StreamContext&& context);
+    StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
+    ::android::status_t drain(StreamDescriptor::DrainMode) override;
+    ::android::status_t flush() override;
+    ::android::status_t pause() override;
     ::android::status_t standby() override;
     ::android::status_t start() override;
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                  int32_t* latencyMs) override;
-    ::android::status_t getPosition(StreamDescriptor::Position* position) override;
+    ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
     void shutdown() override;
 
   protected:
     // Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty.
     virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
 
+    const size_t mBufferSizeFrames;
     const size_t mFrameSizeBytes;
+    const int mSampleRate;
     const bool mIsInput;
     const std::optional<struct pcm_config> mConfig;
+    const int mReadWriteRetries;
     // All fields below are only used on the worker thread.
     std::vector<alsa::DeviceProxy> mAlsaDeviceProxies;
 };
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
new file mode 100644
index 0000000..c2f8c1d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <vector>
+
+#include <aidl/android/hardware/audio/core/IBluetooth.h>
+#include <aidl/android/hardware/audio/core/IBluetoothA2dp.h>
+#include <aidl/android/hardware/audio/core/IBluetoothLe.h>
+
+#include "core-impl/DevicePortProxy.h"
+#include "core-impl/Module.h"
+#include "core-impl/Stream.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamBluetooth : public StreamCommonImpl {
+  public:
+    StreamBluetooth(StreamContext* context, const Metadata& metadata,
+                    Module::BtProfileHandles&& btHandles);
+    // Methods of 'DriverInterface'.
+    ::android::status_t init() override;
+    ::android::status_t drain(StreamDescriptor::DrainMode) override;
+    ::android::status_t flush() override;
+    ::android::status_t pause() override;
+    ::android::status_t standby() override;
+    ::android::status_t start() override;
+    ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+                                 int32_t* latencyMs) override;
+    void shutdown() override;
+
+    // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
+    ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
+    ndk::ScopedAStatus prepareToClose() override;
+    const ConnectedDevices& getConnectedDevices() const override;
+    ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
+    ndk::ScopedAStatus bluetoothParametersUpdated() override;
+
+  private:
+    // Audio Pcm Config
+    const uint32_t mSampleRate;
+    const ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
+    const ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
+    const size_t mFrameSizeBytes;
+    const bool mIsInput;
+    const std::weak_ptr<IBluetoothA2dp> mBluetoothA2dp;
+    const std::weak_ptr<IBluetoothLe> mBluetoothLe;
+    size_t mPreferredDataIntervalUs;
+    size_t mPreferredFrameCount;
+
+    mutable std::mutex mLock;
+    bool mIsInitialized GUARDED_BY(mLock);
+    bool mIsReadyToClose GUARDED_BY(mLock);
+    std::vector<std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>>
+            mBtDeviceProxies GUARDED_BY(mLock);
+
+    ::android::status_t initialize() REQUIRES(mLock);
+    bool checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config);
+};
+
+class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
+  public:
+    friend class ndk::SharedRefBase;
+    StreamInBluetooth(
+            StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
+            Module::BtProfileHandles&& btHandles);
+
+  private:
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+    ndk::ScopedAStatus getActiveMicrophones(
+            std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
+            override;
+};
+
+class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
+  public:
+    friend class ndk::SharedRefBase;
+    StreamOutBluetooth(
+            StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+            const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                    offloadInfo,
+            Module::BtProfileHandles&& btHandles);
+
+  private:
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
new file mode 100644
index 0000000..b3ddd0b
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include "StreamAlsa.h"
+#include "StreamSwitcher.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamPrimary : public StreamAlsa {
+  public:
+    StreamPrimary(StreamContext* context, const Metadata& metadata);
+
+  protected:
+    std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
+
+    const bool mIsInput;
+};
+
+class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
+  public:
+    friend class ndk::SharedRefBase;
+    StreamInPrimary(
+            StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+            const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
+
+  private:
+    static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device);
+
+    DeviceSwitchBehavior switchCurrentStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
+    std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+            StreamContext* context, const Metadata& metadata) override;
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+
+    ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
+};
+
+class StreamOutPrimary final : public StreamOut,
+                               public StreamSwitcher,
+                               public StreamOutHwVolumeHelper {
+  public:
+    friend class ndk::SharedRefBase;
+    StreamOutPrimary(StreamContext&& context,
+                     const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+                     const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                             offloadInfo);
+
+  private:
+    static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device);
+
+    DeviceSwitchBehavior switchCurrentStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
+    std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+            StreamContext* context, const Metadata& metadata) override;
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+
+    ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 1bca910..94404a1 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -20,16 +20,16 @@
 #include <vector>
 
 #include "core-impl/Stream.h"
+#include "core-impl/StreamSwitcher.h"
 #include "r_submix/SubmixRoute.h"
 
 namespace aidl::android::hardware::audio::core {
 
-using aidl::android::hardware::audio::core::r_submix::AudioConfig;
-using aidl::android::hardware::audio::core::r_submix::SubmixRoute;
-
 class StreamRemoteSubmix : public StreamCommonImpl {
   public:
-    StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context);
+    StreamRemoteSubmix(
+            StreamContext* context, const Metadata& metadata,
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
 
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -39,7 +39,7 @@
     ::android::status_t start() override;
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                  int32_t* latencyMs) override;
-    ::android::status_t getPosition(StreamDescriptor::Position* position) override;
+    ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
     void shutdown() override;
 
     // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
@@ -51,16 +51,17 @@
     ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
     ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount);
 
-    const int mPortId;
+    const ::aidl::android::media::audio::common::AudioDeviceAddress mDeviceAddress;
     const bool mIsInput;
-    AudioConfig mStreamConfig;
-    std::shared_ptr<SubmixRoute> mCurrentRoute = nullptr;
+    r_submix::AudioConfig mStreamConfig;
+    std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
 
     // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
     // locks and none of the mutex locks should be taken together.
     static std::mutex sSubmixRoutesLock;
-    static std::map<int32_t, std::shared_ptr<SubmixRoute>> sSubmixRoutes
-            GUARDED_BY(sSubmixRoutesLock);
+    static std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
+                    std::shared_ptr<r_submix::SubmixRoute>>
+            sSubmixRoutes GUARDED_BY(sSubmixRoutesLock);
 
     // limit for number of read error log entries to avoid spamming the logs
     static constexpr int kMaxReadErrorLogs = 5;
@@ -72,28 +73,44 @@
     static constexpr int kReadAttemptSleepUs = 5000;
 };
 
-class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn {
+class StreamInRemoteSubmix final : public StreamIn, public StreamSwitcher {
   public:
     friend class ndk::SharedRefBase;
     StreamInRemoteSubmix(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
 
   private:
+    DeviceSwitchBehavior switchCurrentStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
+    std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+            StreamContext* context, const Metadata& metadata) override;
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
     ndk::ScopedAStatus getActiveMicrophones(
             std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
             override;
 };
 
-class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut {
+class StreamOutRemoteSubmix final : public StreamOut, public StreamSwitcher {
   public:
     friend class ndk::SharedRefBase;
     StreamOutRemoteSubmix(
-            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo);
+
+  private:
+    DeviceSwitchBehavior switchCurrentStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
+    std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+            StreamContext* context, const Metadata& metadata) override;
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index 6b1b2dd..3857e0e 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -22,7 +22,7 @@
 
 class StreamStub : public StreamCommonImpl {
   public:
-    StreamStub(const Metadata& metadata, StreamContext&& context);
+    StreamStub(StreamContext* context, const Metadata& metadata);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -35,6 +35,7 @@
     void shutdown() override;
 
   private:
+    const size_t mBufferSizeFrames;
     const size_t mFrameSizeBytes;
     const int mSampleRate;
     const bool mIsAsynchronous;
@@ -43,22 +44,28 @@
     bool mIsStandby = true;       // Used for validating the state machine logic.
 };
 
-class StreamInStub final : public StreamStub, public StreamIn {
+class StreamInStub final : public StreamIn, public StreamStub {
   public:
     friend class ndk::SharedRefBase;
     StreamInStub(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
+
+  private:
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
 };
 
-class StreamOutStub final : public StreamStub, public StreamOut {
+class StreamOutStub final : public StreamOut, public StreamStub {
   public:
     friend class ndk::SharedRefBase;
-    StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
-                  StreamContext&& context,
+    StreamOutStub(StreamContext&& context,
+                  const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
                   const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                           offloadInfo);
+
+  private:
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h
new file mode 100644
index 0000000..5764ad6
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Stream.h"
+
+namespace aidl::android::hardware::audio::core {
+
+// 'StreamSwitcher' is an implementation of 'StreamCommonInterface' which allows
+// dynamically switching the underlying stream implementation based on currently
+// connected devices. This is achieved by replacing inheritance from
+// 'StreamCommonImpl' with owning an instance of it. StreamSwitcher must be
+// extended in order to supply the logic for choosing the stream
+// implementation. When there are no connected devices, for instance, upon the
+// creation, the StreamSwitcher engages an instance of a stub stream in order to
+// keep serving requests coming via 'StreamDescriptor'.
+//
+// StreamSwitcher implements the 'IStreamCommon' interface directly, with
+// necessary delegation to the current stream implementation. While the stub
+// stream is engaged, any requests made via 'IStreamCommon' (parameters, effects
+// setting, etc) are postponed and only delivered on device connection change
+// to the "real" stream implementation provided by the extending class. This is why
+// the behavior of StreamSwitcher in the "stub" state is not identical to behavior
+// of 'StreamStub'. It can become a full substitute for 'StreamStub' once
+// device connection change event occurs and the extending class returns
+// 'LEAVE_CURRENT_STREAM' from 'switchCurrentStream' method.
+//
+// There is a natural limitation that the current stream implementation may only
+// be switched when the stream is in the 'STANDBY' state. Thus, when the event
+// to switch the stream occurs, the current stream is stopped and joined, and
+// its last state is validated. Since the change of the set of connected devices
+// normally occurs on patch updates, if the stream was not in standby, this is
+// reported to the caller of 'IModule.setAudioPatch' as the 'EX_ILLEGAL_STATE'
+// error.
+//
+// The simplest use case, when the implementor just needs to emulate the legacy HAL API
+// behavior of receiving the connected devices upon stream creation, the implementation
+// of the extending class can look as follows. We assume that 'StreamLegacy' implementation
+// is the one requiring to know connected devices on creation:
+//
+//   class StreamLegacy : public StreamCommonImpl {
+//     public:
+//       StreamLegacy(StreamContext* context, const Metadata& metadata,
+//                    const std::vector<AudioDevice>& devices);
+//   };
+//
+//   class StreamOutLegacy final : public StreamOut, public StreamSwitcher {
+//     public:
+//       StreamOutLegacy(StreamContext&& context, metatadata etc.)
+//     private:
+//       DeviceSwitchBehavior switchCurrentStream(const std::vector<AudioDevice>&) override {
+//           // This implementation effectively postpones stream creation until
+//           // receiving the first call to 'setConnectedDevices' with a non-empty list.
+//           return isStubStream() ? DeviceSwitchBehavior::CREATE_NEW_STREAM :
+//               DeviceSwitchBehavior::USE_CURRENT_STREAM;
+//       }
+//       std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+//               const std::vector<AudioDevice>& devices,
+//               StreamContext* context, const Metadata& metadata) override {
+//           return std::unique_ptr<StreamCommonInterfaceEx>(new InnerStreamWrapper<StreamLegacy>(
+//               context, metadata, devices));
+//       }
+//       void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+//   }
+//
+
+class StreamCommonInterfaceEx : virtual public StreamCommonInterface {
+  public:
+    virtual StreamDescriptor::State getStatePriorToClosing() const = 0;
+};
+
+template <typename T>
+class InnerStreamWrapper : public T, public StreamCommonInterfaceEx {
+  public:
+    template <typename... Args>
+    InnerStreamWrapper(Args&&... args) : T(std::forward<Args>(args)...) {}
+    StreamDescriptor::State getStatePriorToClosing() const override { return mStatePriorToClosing; }
+
+  private:
+    // Do not need to do anything on close notification from the inner stream
+    // because StreamSwitcher handles IStreamCommon::close by itself.
+    void onClose(StreamDescriptor::State statePriorToClosing) override {
+        mStatePriorToClosing = statePriorToClosing;
+    }
+
+    StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY;
+};
+
+class StreamSwitcher : virtual public StreamCommonInterface {
+  public:
+    StreamSwitcher(StreamContext* context, const Metadata& metadata);
+
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus prepareToClose() override;
+    ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override;
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override;
+    ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+    ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+
+    ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override;
+    ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
+
+    ndk::ScopedAStatus initInstance(
+            const std::shared_ptr<StreamCommonInterface>& delegate) override;
+    const StreamContext& getContext() const override;
+    bool isClosed() const override;
+    const ConnectedDevices& getConnectedDevices() const override;
+    ndk::ScopedAStatus setConnectedDevices(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
+    ndk::ScopedAStatus bluetoothParametersUpdated() override;
+
+  protected:
+    // Since switching a stream requires closing down the current stream, StreamSwitcher
+    // asks the extending class its intent on the connected devices change.
+    enum DeviceSwitchBehavior {
+        // Continue using the current stream implementation. If it's the stub implementation,
+        // StreamSwitcher starts treating the stub stream as a "real" implementation,
+        // without effectively closing it and starting again.
+        USE_CURRENT_STREAM,
+        // This is the normal case when the extending class provides a "real" implementation
+        // which is not a stub implementation.
+        CREATE_NEW_STREAM,
+        // This is the case when the extending class wants to revert back to the initial
+        // condition of using a stub stream provided by the StreamSwitcher. This behavior
+        // is only allowed when the list of connected devices is empty.
+        SWITCH_TO_STUB_STREAM,
+        // Use when the set of devices is not supported by the extending class. This returns
+        // 'EX_UNSUPPORTED_OPERATION' from 'setConnectedDevices'.
+        UNSUPPORTED_DEVICES,
+    };
+    // StreamSwitcher will call these methods from 'setConnectedDevices'. If the switch behavior
+    // is 'CREATE_NEW_STREAM', the 'createwNewStream' function will be called (with the same
+    // device vector) for obtaining a new stream implementation, assuming that closing
+    // the current stream was a success.
+    virtual DeviceSwitchBehavior switchCurrentStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0;
+    virtual std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+            StreamContext* context, const Metadata& metadata) = 0;
+    virtual void onClose(StreamDescriptor::State streamPriorToClosing) = 0;
+
+    bool isStubStream() const { return mIsStubStream; }
+    StreamCommonInterfaceEx* getCurrentStream() const { return mStream.get(); }
+
+  private:
+    using VndParam = std::pair<std::vector<VendorParameter>, bool /*isAsync*/>;
+
+    static constexpr bool isValidClosingStreamState(StreamDescriptor::State state) {
+        return state == StreamDescriptor::State::STANDBY || state == StreamDescriptor::State::ERROR;
+    }
+
+    ndk::ScopedAStatus closeCurrentStream(bool validateStreamState);
+
+    // StreamSwitcher does not own the context.
+    StreamContext* mContext;
+    Metadata mMetadata;
+    ChildInterface<StreamCommonDelegator> mCommon;
+    // The current stream.
+    std::unique_ptr<StreamCommonInterfaceEx> mStream;
+    // Indicates whether 'mCurrentStream' is a stub stream implementation
+    // maintained by StreamSwitcher until the extending class provides a "real"
+    // implementation. The invariant of this state is that there are no connected
+    // devices.
+    bool mIsStubStream = true;
+    // Storage for the data from commands received via 'IStreamCommon'.
+    std::optional<int32_t> mHwAvSyncId;
+    std::vector<VndParam> mMissedParameters;
+    std::vector<std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>> mEffects;
+    bool mBluetoothParametersUpdated = false;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 44f742a..608f27d 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -28,11 +28,8 @@
 
 class StreamUsb : public StreamAlsa {
   public:
-    StreamUsb(const Metadata& metadata, StreamContext&& context);
+    StreamUsb(StreamContext* context, const Metadata& metadata);
     // Methods of 'DriverInterface'.
-    ::android::status_t drain(StreamDescriptor::DrainMode) override;
-    ::android::status_t flush() override;
-    ::android::status_t pause() override;
     ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                  int32_t* latencyMs) override;
 
@@ -47,34 +44,33 @@
     std::atomic<bool> mConnectedDevicesUpdated = false;
 };
 
-class StreamInUsb final : public StreamUsb, public StreamIn {
+class StreamInUsb final : public StreamIn, public StreamUsb {
   public:
     friend class ndk::SharedRefBase;
     StreamInUsb(
-            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             StreamContext&& context,
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
 
   private:
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
     ndk::ScopedAStatus getActiveMicrophones(
             std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
             override;
 };
 
-class StreamOutUsb final : public StreamUsb, public StreamOut {
+class StreamOutUsb final : public StreamOut, public StreamUsb, public StreamOutHwVolumeHelper {
   public:
     friend class ndk::SharedRefBase;
-    StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
-                 StreamContext&& context,
+    StreamOutUsb(StreamContext&& context,
+                 const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
                  const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                          offloadInfo);
 
   private:
+    void onClose(StreamDescriptor::State) override { defaultOnClose(); }
     ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
     ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
-
-    const int mChannelCount;
-    std::vector<float> mHwVolumes;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h
index a68a6fd..383ea24 100644
--- a/audio/aidl/default/include/core-impl/XmlConverter.h
+++ b/audio/aidl/default/include/core-impl/XmlConverter.h
@@ -53,10 +53,16 @@
                                      const ::android::status_t& status) {
         std::string errorMessage;
         if (status != ::android::OK) {
-            if (!isReadableConfigFile) {
-                errorMessage = "Could not read requested config file:" + configFilePath;
+            if (configFilePath.empty()) {
+                errorMessage = "No audio configuration files found";
+            } else if (!isReadableConfigFile) {
+                errorMessage = std::string("Could not read requested XML config file: \"")
+                                       .append(configFilePath)
+                                       .append("\"");
             } else {
-                errorMessage = "Invalid config file: " + configFilePath;
+                errorMessage = std::string("Invalid XML config file: \"")
+                                       .append(configFilePath)
+                                       .append("\"");
             }
         }
         return errorMessage;
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 22cdb6b..698e7a5 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -124,11 +124,11 @@
 
     virtual RetCode setCommon(const Parameter::Common& common) {
         mCommon = common;
-        LOG(INFO) << __func__ << mCommon.toString();
+        LOG(VERBOSE) << __func__ << mCommon.toString();
         return RetCode::SUCCESS;
     }
     virtual Parameter::Common getCommon() {
-        LOG(DEBUG) << __func__ << mCommon.toString();
+        LOG(VERBOSE) << __func__ << mCommon.toString();
         return mCommon;
     }
 
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index b456817..421429a 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -45,8 +45,8 @@
         auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
         if (readSamples && writeSamples) {
             auto processSamples = std::min(readSamples, writeSamples);
-            LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
-                       << writeSamples << " process " << processSamples;
+            LOG(VERBOSE) << __func__ << " available to read " << readSamples
+                         << " available to write " << writeSamples << " process " << processSamples;
 
             auto buffer = mContext->getWorkBuffer();
             inputMQ->read(buffer, processSamples);
@@ -54,8 +54,8 @@
             IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
             outputMQ->write(buffer, status.fmqProduced);
             statusMQ->writeBlocking(&status, 1);
-            LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
-                       << " produced " << status.fmqProduced;
+            LOG(VERBOSE) << __func__ << " done processing, effect consumed " << status.fmqConsumed
+                         << " produced " << status.fmqProduced;
         } else {
             // TODO: maybe add some sleep here to avoid busy waiting
         }
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 1401db0..d0b8204 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include <android-base/thread_annotations.h>
 #include "EffectConfig.h"
 
 namespace aidl::android::hardware::audio::effect {
@@ -82,9 +83,11 @@
   private:
     const EffectConfig mConfig;
     ~Factory();
+
+    std::mutex mMutex;
     // Set of effect descriptors supported by the devices.
-    std::set<Descriptor> mDescSet;
-    std::set<Descriptor::Identity> mIdentitySet;
+    std::set<Descriptor> mDescSet GUARDED_BY(mMutex);
+    std::set<Descriptor::Identity> mIdentitySet GUARDED_BY(mMutex);
 
     static constexpr int kMapEntryHandleIndex = 0;
     static constexpr int kMapEntryInterfaceIndex = 1;
@@ -94,13 +97,15 @@
                        std::string /* library name */>
             DlEntry;
 
-    std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap;
+    std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap
+            GUARDED_BY(mMutex);
 
     typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
-    std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap;
+    std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap GUARDED_BY(mMutex);
 
-    ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
-    void cleanupEffectMap();
+    ndk::ScopedAStatus destroyEffectImpl_l(const std::shared_ptr<IEffect>& in_handle)
+            REQUIRES(mMutex);
+    void cleanupEffectMap_l() REQUIRES(mMutex);
     bool openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
                            const std::string& path);
     void createIdentityWithConfig(
@@ -108,12 +113,13 @@
             const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr,
             const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
 
-    ndk::ScopedAStatus getDescriptorWithUuid(
-            const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc);
+    ndk::ScopedAStatus getDescriptorWithUuid_l(
+            const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc)
+            REQUIRES(mMutex);
 
     void loadEffectLibs();
     /* Get effect_dl_interface_s from library handle */
-    void getDlSyms(DlEntry& entry);
+    void getDlSyms_l(DlEntry& entry) REQUIRES(mMutex);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 93fb366..a0c0fab 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -65,7 +65,8 @@
         return std::make_pair(module, moduleBinder);
     };
     auto modules = {createModule(Module::Type::DEFAULT), createModule(Module::Type::R_SUBMIX),
-                    createModule(Module::Type::USB), createModule(Module::Type::STUB)};
+                    createModule(Module::Type::USB), createModule(Module::Type::STUB),
+                    createModule(Module::Type::BLUETOOTH)};
     (void)modules;
 
     ABinderProcess_joinThreadPool();
diff --git a/audio/aidl/default/primary/PrimaryMixer.cpp b/audio/aidl/default/primary/PrimaryMixer.cpp
new file mode 100644
index 0000000..577d010
--- /dev/null
+++ b/audio/aidl/default/primary/PrimaryMixer.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_PrimaryMixer"
+
+#include "PrimaryMixer.h"
+
+namespace aidl::android::hardware::audio::core::primary {
+
+// static
+PrimaryMixer& PrimaryMixer::getInstance() {
+    static PrimaryMixer gInstance;
+    return gInstance;
+}
+
+}  // namespace aidl::android::hardware::audio::core::primary
diff --git a/audio/aidl/default/primary/PrimaryMixer.h b/audio/aidl/default/primary/PrimaryMixer.h
new file mode 100644
index 0000000..3806428
--- /dev/null
+++ b/audio/aidl/default/primary/PrimaryMixer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+
+#include "alsa/Mixer.h"
+
+namespace aidl::android::hardware::audio::core::primary {
+
+class PrimaryMixer : public alsa::Mixer {
+  public:
+    static constexpr int kAlsaCard = 0;
+    static constexpr int kAlsaDevice = 0;
+
+    static PrimaryMixer& getInstance();
+
+  private:
+    PrimaryMixer() : alsa::Mixer(kAlsaCard) {}
+};
+
+}  // namespace aidl::android::hardware::audio::core::primary
diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp
new file mode 100644
index 0000000..e01be8a
--- /dev/null
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits>
+
+#define LOG_TAG "AHAL_StreamPrimary"
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <error/expected_utils.h>
+
+#include "PrimaryMixer.h"
+#include "core-impl/StreamPrimary.h"
+#include "core-impl/StreamStub.h"
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::MicrophoneInfo;
+using android::base::GetBoolProperty;
+
+namespace aidl::android::hardware::audio::core {
+
+StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
+    : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {}
+
+std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
+    static const std::vector<alsa::DeviceProfile> kBuiltInSource{
+            alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
+                                .device = primary::PrimaryMixer::kAlsaDevice,
+                                .direction = PCM_IN,
+                                .isExternal = false}};
+    static const std::vector<alsa::DeviceProfile> kBuiltInSink{
+            alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
+                                .device = primary::PrimaryMixer::kAlsaDevice,
+                                .direction = PCM_OUT,
+                                .isExternal = false}};
+    return mIsInput ? kBuiltInSource : kBuiltInSink;
+}
+
+StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
+                                 const std::vector<MicrophoneInfo>& microphones)
+    : StreamIn(std::move(context), microphones),
+      StreamSwitcher(&mContextInstance, sinkMetadata),
+      StreamInHwGainHelper(&mContextInstance) {}
+
+bool StreamInPrimary::useStubStream(const AudioDevice& device) {
+    static const bool kSimulateInput =
+            GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
+    return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
+           device.type.type == AudioDeviceType::IN_FM_TUNER ||
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
+}
+
+StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+    LOG(DEBUG) << __func__;
+    if (devices.size() > 1) {
+        LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
+                   << devices.size();
+        return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
+    }
+    if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
+        return DeviceSwitchBehavior::USE_CURRENT_STREAM;
+    }
+    return DeviceSwitchBehavior::CREATE_NEW_STREAM;
+}
+
+std::unique_ptr<StreamCommonInterfaceEx> StreamInPrimary::createNewStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+        StreamContext* context, const Metadata& metadata) {
+    if (devices.empty()) {
+        LOG(FATAL) << __func__ << ": called with empty devices";  // see 'switchCurrentStream'
+    }
+    if (useStubStream(devices[0])) {
+        return std::unique_ptr<StreamCommonInterfaceEx>(
+                new InnerStreamWrapper<StreamStub>(context, metadata));
+    }
+    return std::unique_ptr<StreamCommonInterfaceEx>(
+            new InnerStreamWrapper<StreamPrimary>(context, metadata));
+}
+
+ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
+    if (isStubStream()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    return getHwGainImpl(_aidl_return);
+}
+
+ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& in_channelGains) {
+    if (isStubStream()) {
+        LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    auto currentGains = mHwGains;
+    RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains));
+    if (in_channelGains.size() < 1) {
+        LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size();
+    }
+    if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]);
+        !status.isOk()) {
+        mHwGains = currentGains;
+        return status;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata,
+                                   const std::optional<AudioOffloadInfo>& offloadInfo)
+    : StreamOut(std::move(context), offloadInfo),
+      StreamSwitcher(&mContextInstance, sourceMetadata),
+      StreamOutHwVolumeHelper(&mContextInstance) {}
+
+bool StreamOutPrimary::useStubStream(const AudioDevice& device) {
+    static const bool kSimulateOutput =
+            GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
+    return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
+}
+
+StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+    LOG(DEBUG) << __func__;
+    if (devices.size() > 1) {
+        LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
+                   << devices.size();
+        return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
+    }
+    if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
+        return DeviceSwitchBehavior::USE_CURRENT_STREAM;
+    }
+    return DeviceSwitchBehavior::CREATE_NEW_STREAM;
+}
+
+std::unique_ptr<StreamCommonInterfaceEx> StreamOutPrimary::createNewStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+        StreamContext* context, const Metadata& metadata) {
+    if (devices.empty()) {
+        LOG(FATAL) << __func__ << ": called with empty devices";  // see 'switchCurrentStream'
+    }
+    if (useStubStream(devices[0])) {
+        return std::unique_ptr<StreamCommonInterfaceEx>(
+                new InnerStreamWrapper<StreamStub>(context, metadata));
+    }
+    return std::unique_ptr<StreamCommonInterfaceEx>(
+            new InnerStreamWrapper<StreamPrimary>(context, metadata));
+}
+
+ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
+    if (isStubStream()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    return getHwVolumeImpl(_aidl_return);
+}
+
+ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& in_channelVolumes) {
+    if (isStubStream()) {
+        LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    auto currentVolumes = mHwVolumes;
+    RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
+    if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes);
+        !status.isOk()) {
+        mHwVolumes = currentVolumes;
+        return status;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
index 2b79f51..adea877 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -19,8 +19,8 @@
 #include <vector>
 
 #include <android-base/logging.h>
+#include <error/expected_utils.h>
 
-#include "RemoteSubmixUtils.h"
 #include "core-impl/ModuleRemoteSubmix.h"
 #include "core-impl/StreamRemoteSubmix.h"
 
@@ -33,18 +33,6 @@
 
 namespace aidl::android::hardware::audio::core {
 
-ndk::ScopedAStatus ModuleRemoteSubmix::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
-    *_aidl_return = nullptr;
-    LOG(DEBUG) << __func__ << ": returning null";
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus ModuleRemoteSubmix::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
-    *_aidl_return = nullptr;
-    LOG(DEBUG) << __func__ << ": returning null";
-    return ndk::ScopedAStatus::ok();
-}
-
 ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) {
     LOG(DEBUG) << __func__ << ": is not supported";
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -56,37 +44,40 @@
 }
 
 ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
-        const SinkMetadata& sinkMetadata, StreamContext&& context,
+        StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInRemoteSubmix>(result, sinkMetadata, std::move(context),
+    return createStreamInstance<StreamInRemoteSubmix>(result, std::move(context), sinkMetadata,
                                                       microphones);
 }
 
 ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
-        const SourceMetadata& sourceMetadata, StreamContext&& context,
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
-    return createStreamInstance<StreamOutRemoteSubmix>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutRemoteSubmix>(result, std::move(context), sourceMetadata,
                                                        offloadInfo);
 }
 
 ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) {
-    LOG(VERBOSE) << __func__ << ": Profiles already populated by Configuration";
-    for (auto profile : audioPort->profiles) {
-        for (auto channelMask : profile.channelMasks) {
-            if (!r_submix::isChannelMaskSupported(channelMask)) {
-                LOG(ERROR) << __func__ << ": the profile " << profile.name
-                           << " has unsupported channel mask : " << channelMask.toString();
-                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-            }
-        }
-        for (auto sampleRate : profile.sampleRates) {
-            if (!r_submix::isSampleRateSupported(sampleRate)) {
-                LOG(ERROR) << __func__ << ": the profile " << profile.name
-                           << " has unsupported sample rate : " << sampleRate;
-                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-            }
-        }
+    // Find the corresponding mix port and copy its profiles.
+    std::vector<AudioRoute> routes;
+    // At this moment, the port has the same ID as the template port, see connectExternalDevice.
+    RETURN_STATUS_IF_ERROR(getAudioRoutesForAudioPort(audioPort->id, &routes));
+    if (routes.empty()) {
+        LOG(ERROR) << __func__ << ": no routes found for the port " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    const auto& route = *routes.begin();
+    AudioPort mixPort;
+    if (route.sinkPortId == audioPort->id) {
+        if (route.sourcePortIds.empty()) {
+            LOG(ERROR) << __func__ << ": invalid route " << route.toString();
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        RETURN_STATUS_IF_ERROR(getAudioPort(*route.sourcePortIds.begin(), &mixPort));
+    } else {
+        RETURN_STATUS_IF_ERROR(getAudioPort(route.sinkPortId, &mixPort));
+    }
+    audioPort->profiles = mixPort.profiles;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -106,12 +97,6 @@
     return ndk::ScopedAStatus::ok();
 }
 
-void ModuleRemoteSubmix::onExternalDeviceConnectionChanged(
-        const ::aidl::android::media::audio::common::AudioPort& audioPort __unused,
-        bool connected __unused) {
-    LOG(DEBUG) << __func__ << ": do nothing and return";
-}
-
 ndk::ScopedAStatus ModuleRemoteSubmix::onMasterMuteChanged(bool __unused) {
     LOG(DEBUG) << __func__ << ": is not supported";
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
diff --git a/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp b/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp
deleted file mode 100644
index 2f5d17d..0000000
--- a/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-
-#include "RemoteSubmixUtils.h"
-
-namespace aidl::android::hardware::audio::core::r_submix {
-
-bool isChannelMaskSupported(const AudioChannelLayout& channelMask) {
-    const static std::vector<AudioChannelLayout> kSupportedChannelMask = {
-            AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
-                    AudioChannelLayout::LAYOUT_MONO),
-            AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
-                    AudioChannelLayout::LAYOUT_STEREO)};
-
-    if (std::find(kSupportedChannelMask.begin(), kSupportedChannelMask.end(), channelMask) !=
-        kSupportedChannelMask.end()) {
-        return true;
-    }
-    return false;
-}
-
-bool isSampleRateSupported(int sampleRate) {
-    const static std::vector<int> kSupportedSampleRates = {8000,  11025, 12000, 16000, 22050,
-                                                           24000, 32000, 44100, 48000};
-
-    if (std::find(kSupportedSampleRates.begin(), kSupportedSampleRates.end(), sampleRate) !=
-        kSupportedSampleRates.end()) {
-        return true;
-    }
-    return false;
-}
-
-}  // namespace aidl::android::hardware::audio::core::r_submix
diff --git a/audio/aidl/default/r_submix/RemoteSubmixUtils.h b/audio/aidl/default/r_submix/RemoteSubmixUtils.h
deleted file mode 100644
index 952a992..0000000
--- a/audio/aidl/default/r_submix/RemoteSubmixUtils.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <aidl/android/media/audio/common/AudioChannelLayout.h>
-#include <aidl/android/media/audio/common/AudioFormatDescription.h>
-
-using aidl::android::media::audio::common::AudioChannelLayout;
-
-namespace aidl::android::hardware::audio::core::r_submix {
-
-bool isChannelMaskSupported(const AudioChannelLayout& channelMask);
-
-bool isSampleRateSupported(int sampleRate);
-
-}  // namespace aidl::android::hardware::audio::core::r_submix
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 6d5185b..3134b86 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -23,30 +23,34 @@
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::r_submix::SubmixRoute;
+using aidl::android::media::audio::common::AudioDeviceAddress;
 using aidl::android::media::audio::common::AudioOffloadInfo;
 using aidl::android::media::audio::common::MicrophoneDynamicInfo;
 using aidl::android::media::audio::common::MicrophoneInfo;
 
 namespace aidl::android::hardware::audio::core {
 
-StreamRemoteSubmix::StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
-      mPortId(context.getPortId()),
+StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& metadata,
+                                       const AudioDeviceAddress& deviceAddress)
+    : StreamCommonImpl(context, metadata),
+      mDeviceAddress(deviceAddress),
       mIsInput(isInput(metadata)) {
-    mStreamConfig.frameSize = context.getFrameSize();
-    mStreamConfig.format = context.getFormat();
-    mStreamConfig.channelLayout = context.getChannelLayout();
-    mStreamConfig.sampleRate = context.getSampleRate();
+    mStreamConfig.frameSize = context->getFrameSize();
+    mStreamConfig.format = context->getFormat();
+    mStreamConfig.channelLayout = context->getChannelLayout();
+    mStreamConfig.sampleRate = context->getSampleRate();
 }
 
 std::mutex StreamRemoteSubmix::sSubmixRoutesLock;
-std::map<int32_t, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoutes;
+std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoutes;
 
 ::android::status_t StreamRemoteSubmix::init() {
     {
         std::lock_guard guard(sSubmixRoutesLock);
-        if (sSubmixRoutes.find(mPortId) != sSubmixRoutes.end()) {
-            mCurrentRoute = sSubmixRoutes[mPortId];
+        auto routeItr = sSubmixRoutes.find(mDeviceAddress);
+        if (routeItr != sSubmixRoutes.end()) {
+            mCurrentRoute = routeItr->second;
         }
     }
     // If route is not available for this port, add it.
@@ -59,7 +63,7 @@
         }
         {
             std::lock_guard guard(sSubmixRoutesLock);
-            sSubmixRoutes.emplace(mPortId, mCurrentRoute);
+            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
         }
     } else {
         if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
@@ -116,8 +120,9 @@
         std::shared_ptr<SubmixRoute> route = nullptr;
         {
             std::lock_guard guard(sSubmixRoutesLock);
-            if (sSubmixRoutes.find(mPortId) != sSubmixRoutes.end()) {
-                route = sSubmixRoutes[mPortId];
+            auto routeItr = sSubmixRoutes.find(mDeviceAddress);
+            if (routeItr != sSubmixRoutes.end()) {
+                route = routeItr->second;
             }
         }
         if (route != nullptr) {
@@ -146,7 +151,7 @@
         LOG(DEBUG) << __func__ << ": pipe destroyed";
 
         std::lock_guard guard(sSubmixRoutesLock);
-        sSubmixRoutes.erase(mPortId);
+        sSubmixRoutes.erase(mDeviceAddress);
     }
     mCurrentRoute.reset();
 }
@@ -179,7 +184,7 @@
                      : outWrite(buffer, frameCount, actualFrameCount));
 }
 
-::android::status_t StreamRemoteSubmix::getPosition(StreamDescriptor::Position* position) {
+::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) {
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
     if (source == nullptr) {
         return ::android::NO_INIT;
@@ -275,14 +280,18 @@
                                                size_t* actualFrameCount) {
     // about to read from audio source
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
-    if (source == nullptr) {
-        int readErrorCount = mCurrentRoute->notifyReadError();
-        if (readErrorCount < kMaxReadErrorLogs) {
-            LOG(ERROR)
-                    << __func__
-                    << ": no audio pipe yet we're trying to read! (not all errors will be logged)";
+    if (source == nullptr || source->availableToRead() == 0) {
+        if (source == nullptr) {
+            int readErrorCount = mCurrentRoute->notifyReadError();
+            if (readErrorCount < kMaxReadErrorLogs) {
+                LOG(ERROR) << __func__
+                           << ": no audio pipe yet we're trying to read! (not all errors will be "
+                              "logged)";
+            } else {
+                LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
+            }
         } else {
-            LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
+            LOG(INFO) << __func__ << ": no data to read yet, providing empty data";
         }
         const size_t delayUs = static_cast<size_t>(
                 std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
@@ -339,11 +348,9 @@
     // recording (including this call): it's converted to usec and compared to how long we've been
     // recording for, which gives us how long we must wait to sync the projected recording time, and
     // the observed recording time.
-    static constexpr float kScaleFactor = .8f;
-    const size_t projectedVsObservedOffsetUs =
-            kScaleFactor * (static_cast<size_t>(std::roundf((readCounterFrames * MICROS_PER_SECOND /
-                                                             mStreamConfig.sampleRate) -
-                                                            recordDurationUs.count())));
+    const int projectedVsObservedOffsetUs =
+            std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) -
+                        recordDurationUs.count());
 
     LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count()
                  << " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds";
@@ -353,10 +360,10 @@
     return ::android::OK;
 }
 
-StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata,
-                                           StreamContext&& context,
+StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context,
+                                           const SinkMetadata& sinkMetadata,
                                            const std::vector<MicrophoneInfo>& microphones)
-    : StreamRemoteSubmix(sinkMetadata, std::move(context)), StreamIn(microphones) {}
+    : StreamIn(std::move(context), microphones), StreamSwitcher(&mContextInstance, sinkMetadata) {}
 
 ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return) {
@@ -365,9 +372,66 @@
     return ndk::ScopedAStatus::ok();
 }
 
-StreamOutRemoteSubmix::StreamOutRemoteSubmix(const SourceMetadata& sourceMetadata,
-                                             StreamContext&& context,
+StreamSwitcher::DeviceSwitchBehavior StreamInRemoteSubmix::switchCurrentStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+    // This implementation effectively postpones stream creation until
+    // receiving the first call to 'setConnectedDevices' with a non-empty list.
+    if (isStubStream()) {
+        if (devices.size() == 1) {
+            auto deviceDesc = devices.front().type;
+            if (deviceDesc.type ==
+                ::aidl::android::media::audio::common::AudioDeviceType::IN_SUBMIX) {
+                return DeviceSwitchBehavior::CREATE_NEW_STREAM;
+            }
+            LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type)
+                       << " not supported";
+        } else {
+            LOG(ERROR) << __func__ << ": Only single device supported.";
+        }
+        return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
+    }
+    return DeviceSwitchBehavior::USE_CURRENT_STREAM;
+}
+
+std::unique_ptr<StreamCommonInterfaceEx> StreamInRemoteSubmix::createNewStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+        StreamContext* context, const Metadata& metadata) {
+    return std::unique_ptr<StreamCommonInterfaceEx>(
+            new InnerStreamWrapper<StreamRemoteSubmix>(context, metadata, devices.front().address));
+}
+
+StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context,
+                                             const SourceMetadata& sourceMetadata,
                                              const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamRemoteSubmix(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
+    : StreamOut(std::move(context), offloadInfo),
+      StreamSwitcher(&mContextInstance, sourceMetadata) {}
+
+StreamSwitcher::DeviceSwitchBehavior StreamOutRemoteSubmix::switchCurrentStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+    // This implementation effectively postpones stream creation until
+    // receiving the first call to 'setConnectedDevices' with a non-empty list.
+    if (isStubStream()) {
+        if (devices.size() == 1) {
+            auto deviceDesc = devices.front().type;
+            if (deviceDesc.type ==
+                ::aidl::android::media::audio::common::AudioDeviceType::OUT_SUBMIX) {
+                return DeviceSwitchBehavior::CREATE_NEW_STREAM;
+            }
+            LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type)
+                       << " not supported";
+        } else {
+            LOG(ERROR) << __func__ << ": Only single device supported.";
+        }
+        return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
+    }
+    return DeviceSwitchBehavior::USE_CURRENT_STREAM;
+}
+
+std::unique_ptr<StreamCommonInterfaceEx> StreamOutRemoteSubmix::createNewStream(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+        StreamContext* context, const Metadata& metadata) {
+    return std::unique_ptr<StreamCommonInterfaceEx>(
+            new InnerStreamWrapper<StreamRemoteSubmix>(context, metadata, devices.front().address));
+}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index 8f5b8cb..ddac64d 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -27,7 +27,7 @@
 namespace aidl::android::hardware::audio::core::r_submix {
 
 // Verify a submix input or output stream can be opened.
-bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig streamConfig) {
+bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamConfig) {
     // If the stream is already open, don't open it again.
     // ENABLE_LEGACY_INPUT_OPEN is default behaviour
     if (!isInput && isStreamOutOpen()) {
@@ -43,7 +43,7 @@
 
 // Compare this stream config with existing pipe config, returning false if they do *not*
 // match, true otherwise.
-bool SubmixRoute::isStreamConfigCompatible(const AudioConfig streamConfig) {
+bool SubmixRoute::isStreamConfigCompatible(const AudioConfig& streamConfig) {
     if (streamConfig.channelLayout != mPipeConfig.channelLayout) {
         LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = "
                    << streamConfig.channelLayout.toString()
@@ -126,7 +126,7 @@
 
 // If SubmixRoute doesn't exist for a port, create a pipe for the submix audio device of size
 // buffer_size_frames and store config of the submix audio device.
-::android::status_t SubmixRoute::createPipe(const AudioConfig streamConfig) {
+::android::status_t SubmixRoute::createPipe(const AudioConfig& streamConfig) {
     const int channelCount = getChannelCount(streamConfig.channelLayout);
     const audio_format_t audioFormat = VALUE_OR_RETURN_STATUS(
             aidl2legacy_AudioFormatDescription_audio_format_t(streamConfig.format));
@@ -201,9 +201,9 @@
 
     if (isInput) {
         mStreamInStandby = true;
-    } else {
+    } else if (!mStreamOutStandby) {
         mStreamOutStandby = true;
-        mStreamOutStandbyTransition = !mStreamOutStandbyTransition;
+        mStreamOutStandbyTransition = true;
     }
 }
 
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 5f7ea75..1a98df2 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -93,9 +93,9 @@
         return mSource;
     }
 
-    bool isStreamConfigValid(bool isInput, const AudioConfig streamConfig);
+    bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig);
     void closeStream(bool isInput);
-    ::android::status_t createPipe(const AudioConfig streamConfig);
+    ::android::status_t createPipe(const AudioConfig& streamConfig);
     void exitStandby(bool isInput);
     bool hasAtleastOneStreamOpen();
     int notifyReadError();
@@ -107,7 +107,7 @@
     long updateReadCounterFrames(size_t frameCount);
 
   private:
-    bool isStreamConfigCompatible(const AudioConfig streamConfig);
+    bool isStreamConfigCompatible(const AudioConfig& streamConfig);
 
     std::mutex mLock;
 
diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp
index a600752..9f6e0b4 100644
--- a/audio/aidl/default/stub/ModuleStub.cpp
+++ b/audio/aidl/default/stub/ModuleStub.cpp
@@ -37,8 +37,9 @@
     if (!mBluetooth) {
         mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
     }
-    *_aidl_return = mBluetooth.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+    *_aidl_return = mBluetooth.getInstance();
+    LOG(DEBUG) << __func__
+               << ": returning instance of IBluetooth: " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -46,8 +47,9 @@
     if (!mBluetoothA2dp) {
         mBluetoothA2dp = ndk::SharedRefBase::make<BluetoothA2dp>();
     }
-    *_aidl_return = mBluetoothA2dp.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
+    *_aidl_return = mBluetoothA2dp.getInstance();
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: "
+               << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -55,23 +57,24 @@
     if (!mBluetoothLe) {
         mBluetoothLe = ndk::SharedRefBase::make<BluetoothLe>();
     }
-    *_aidl_return = mBluetoothLe.getPtr();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+    *_aidl_return = mBluetoothLe.getInstance();
+    LOG(DEBUG) << __func__
+               << ": returning instance of IBluetoothLe: " << _aidl_return->get()->asBinder().get();
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus ModuleStub::createInputStream(const SinkMetadata& sinkMetadata,
-                                                 StreamContext&& context,
+ndk::ScopedAStatus ModuleStub::createInputStream(StreamContext&& context,
+                                                 const SinkMetadata& sinkMetadata,
                                                  const std::vector<MicrophoneInfo>& microphones,
                                                  std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
+    return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
                                               microphones);
 }
 
 ndk::ScopedAStatus ModuleStub::createOutputStream(
-        const SourceMetadata& sourceMetadata, StreamContext&& context,
+        StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
-    return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
                                                offloadInfo);
 }
 
diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
index 2dcf4d4..660a51e 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -31,8 +31,9 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
+StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
+    : StreamCommonImpl(context, metadata),
+      mBufferSizeFrames(getContext().getBufferSizeInFrames()),
       mFrameSizeBytes(getContext().getFrameSize()),
       mSampleRate(getContext().getSampleRate()),
       mIsAsynchronous(!!getContext().getAsyncCallback()),
@@ -40,7 +41,6 @@
 
 ::android::status_t StreamStub::init() {
     mIsInitialized = true;
-    usleep(500);
     return ::android::OK;
 }
 
@@ -48,7 +48,16 @@
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
-    usleep(500);
+    if (!mIsInput) {
+        if (!mIsAsynchronous) {
+            static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
+            const size_t delayUs = static_cast<size_t>(
+                    std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate));
+            usleep(delayUs);
+        } else {
+            usleep(500);
+        }
+    }
     return ::android::OK;
 }
 
@@ -56,7 +65,6 @@
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
-    usleep(500);
     return ::android::OK;
 }
 
@@ -64,7 +72,6 @@
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
-    usleep(500);
     return ::android::OK;
 }
 
@@ -118,12 +125,12 @@
     mIsInitialized = false;
 }
 
-StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
+StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata,
                            const std::vector<MicrophoneInfo>& microphones)
-    : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}
+    : StreamIn(std::move(context), microphones), StreamStub(&mContextInstance, sinkMetadata) {}
 
-StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context,
+StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata,
                              const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
+    : StreamOut(std::move(context), offloadInfo), StreamStub(&mContextInstance, sourceMetadata) {}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index a812e4d..f926e09 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -68,22 +68,22 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-ndk::ScopedAStatus ModuleUsb::createInputStream(const SinkMetadata& sinkMetadata,
-                                                StreamContext&& context,
+ndk::ScopedAStatus ModuleUsb::createInputStream(StreamContext&& context,
+                                                const SinkMetadata& sinkMetadata,
                                                 const std::vector<MicrophoneInfo>& microphones,
                                                 std::shared_ptr<StreamIn>* result) {
-    return createStreamInstance<StreamInUsb>(result, sinkMetadata, std::move(context), microphones);
+    return createStreamInstance<StreamInUsb>(result, std::move(context), sinkMetadata, microphones);
 }
 
-ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMetadata,
-                                                 StreamContext&& context,
+ndk::ScopedAStatus ModuleUsb::createOutputStream(StreamContext&& context,
+                                                 const SourceMetadata& sourceMetadata,
                                                  const std::optional<AudioOffloadInfo>& offloadInfo,
                                                  std::shared_ptr<StreamOut>* result) {
     if (offloadInfo.has_value()) {
         LOG(ERROR) << __func__ << ": offload is not supported";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    return createStreamInstance<StreamOutUsb>(result, sourceMetadata, std::move(context),
+    return createStreamInstance<StreamOutUsb>(result, std::move(context), sourceMetadata,
                                               offloadInfo);
 }
 
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index da0ad11..b60b4fd 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -18,14 +18,11 @@
 
 #define LOG_TAG "AHAL_StreamUsb"
 #include <android-base/logging.h>
-
-#include <Utils.h>
 #include <error/expected_utils.h>
 
 #include "UsbAlsaMixerControl.h"
 #include "core-impl/StreamUsb.h"
 
-using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
 using aidl::android::media::audio::common::AudioDevice;
@@ -35,8 +32,8 @@
 
 namespace aidl::android::hardware::audio::core {
 
-StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
-    : StreamAlsa(metadata, std::move(context)) {}
+StreamUsb::StreamUsb(StreamContext* context, const Metadata& metadata)
+    : StreamAlsa(context, metadata, 1 /*readWriteRetries*/) {}
 
 ndk::ScopedAStatus StreamUsb::setConnectedDevices(
         const std::vector<AudioDevice>& connectedDevices) {
@@ -55,28 +52,13 @@
         }
         connectedDeviceProfiles.push_back(*profile);
     }
-    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+    RETURN_STATUS_IF_ERROR(setConnectedDevices(connectedDevices));
     std::lock_guard guard(mLock);
     mConnectedDeviceProfiles = std::move(connectedDeviceProfiles);
     mConnectedDevicesUpdated.store(true, std::memory_order_release);
     return ndk::ScopedAStatus::ok();
 }
 
-::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) {
-    usleep(1000);
-    return ::android::OK;
-}
-
-::android::status_t StreamUsb::flush() {
-    usleep(1000);
-    return ::android::OK;
-}
-
-::android::status_t StreamUsb::pause() {
-    usleep(1000);
-    return ::android::OK;
-}
-
 ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                         int32_t* latencyMs) {
     if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
@@ -98,9 +80,9 @@
     return connectedDevices;
 }
 
-StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
+StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata,
                          const std::vector<MicrophoneInfo>& microphones)
-    : StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {}
+    : StreamIn(std::move(context), microphones), StreamUsb(&mContextInstance, sinkMetadata) {}
 
 ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -108,18 +90,19 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
+StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata,
                            const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamUsb(sourceMetadata, std::move(context)),
-      StreamOut(offloadInfo),
-      mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
+    : StreamOut(std::move(context), offloadInfo),
+      StreamUsb(&mContextInstance, sourceMetadata),
+      StreamOutHwVolumeHelper(&mContextInstance) {}
 
 ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
-    *_aidl_return = mHwVolumes;
-    return ndk::ScopedAStatus::ok();
+    return getHwVolumeImpl(_aidl_return);
 }
 
 ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
+    auto currentVolumes = mHwVolumes;
+    RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
     // Avoid using mConnectedDeviceProfiles because it requires a lock.
     for (const auto& device : getConnectedDevices()) {
         if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput);
@@ -129,11 +112,11 @@
                 !result.isOk()) {
                 LOG(ERROR) << __func__
                            << ": failed to set volume for device address=" << *deviceProfile;
+                mHwVolumes = currentVolumes;
                 return result;
             }
         }
     }
-    mHwVolumes = in_channelVolumes;
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
index 769d739..0a49446 100644
--- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
+++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
@@ -33,12 +33,10 @@
                                                    bool connected) {
     LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected;
     if (connected) {
-        struct mixer* mixer = mixer_open(card);
-        if (mixer == nullptr) {
-            PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
+        auto alsaMixer = std::make_shared<alsa::Mixer>(card);
+        if (!alsaMixer->isValid()) {
             return;
         }
-        auto alsaMixer = std::make_shared<alsa::Mixer>(mixer);
         alsaMixer->setMasterMute(masterMuted);
         alsaMixer->setMasterVolume(masterVolume);
         const std::lock_guard guard(mLock);
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 852255d..f7cf4ce 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -55,6 +55,7 @@
         "VtsHalAudioCoreConfigTargetTest.cpp",
         "VtsHalAudioCoreModuleTargetTest.cpp",
     ],
+    test_config: "VtsHalAudioCoreTargetTest.xml",
 }
 
 cc_test {
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 8c448a8..7213034 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -30,6 +30,7 @@
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::core::IModule;
 using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceDescription;
 using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioEncapsulationMode;
 using aidl::android::media::audio::common::AudioFormatDescription;
@@ -96,7 +97,10 @@
             } else {
                 mAttachedSinkDevicePorts.insert(port.id);
             }
-        } else if (port.profiles.empty()) {
+        } else if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_VIRTUAL
+                   // The "virtual" connection is used for remote submix which is a dynamic
+                   // device but it can be connected and used w/o external hardware.
+                   && port.profiles.empty()) {
             mExternalDevicePorts.insert(port.id);
         }
     }
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index a2e2ef7..03ebd61 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -1627,14 +1627,17 @@
     if (ports.empty()) {
         GTEST_SKIP() << "No external devices in the module.";
     }
-    AudioPort ignored;
     WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug);
     doNotSimulateConnections.flags().simulateDeviceConnections = false;
     ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
     for (const auto& port : ports) {
-        AudioPort portWithData = GenerateUniqueDeviceAddress(port);
-        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
-                << "static port " << portWithData.toString();
+        AudioPort portWithData = GenerateUniqueDeviceAddress(port), connectedPort;
+        ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort);
+        EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString();
+        if (status.isOk()) {
+            EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id))
+                    << "when disconnecting device port ID " << connectedPort.id;
+        }
     }
 }
 
@@ -3189,10 +3192,17 @@
     std::string mUnexpectedTransition;
 };
 
-enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS };
+enum {
+    NAMED_CMD_NAME,
+    NAMED_CMD_DELAY_MS,
+    NAMED_CMD_STREAM_TYPE,
+    NAMED_CMD_CMDS,
+    NAMED_CMD_VALIDATE_POS_INCREASE
+};
 enum class StreamTypeFilter { ANY, SYNC, ASYNC };
 using NamedCommandSequence =
-        std::tuple<std::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
+        std::tuple<std::string, int /*cmdDelayMs*/, StreamTypeFilter,
+                   std::shared_ptr<StateSequence>, bool /*validatePositionIncrease*/>;
 enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
 using StreamIoTestParameters =
         std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
@@ -3236,10 +3246,14 @@
             ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
             const auto& commandsAndStates =
                     std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+            const bool validatePositionIncrease =
+                    std::get<NAMED_CMD_VALIDATE_POS_INCREASE>(std::get<PARAM_CMD_SEQ>(GetParam()));
             if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
-                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates,
+                                                                    validatePositionIncrease));
             } else {
-                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates,
+                                                                    validatePositionIncrease));
             }
             if (isNonBlocking) {
                 // Also try running the same sequence with "aosp.forceTransientBurst" set.
@@ -3250,11 +3264,11 @@
                 if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
                             .isOk()) {
                     if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
-                        ASSERT_NO_FATAL_FAILURE(
-                                RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+                        ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(
+                                portConfig, commandsAndStates, validatePositionIncrease));
                     } else {
-                        ASSERT_NO_FATAL_FAILURE(
-                                RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+                        ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(
+                                portConfig, commandsAndStates, validatePositionIncrease));
                     }
                 }
             } else if (!IOTraits<Stream>::is_input) {
@@ -3267,11 +3281,11 @@
                 if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
                             .isOk()) {
                     if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
-                        ASSERT_NO_FATAL_FAILURE(
-                                RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+                        ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(
+                                portConfig, commandsAndStates, validatePositionIncrease));
                     } else {
-                        ASSERT_NO_FATAL_FAILURE(
-                                RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+                        ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(
+                                portConfig, commandsAndStates, validatePositionIncrease));
                     }
                 }
             }
@@ -3285,11 +3299,13 @@
 
     // Set up a patch first, then open a stream.
     void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
-                                     std::shared_ptr<StateSequence> commandsAndStates) {
+                                     std::shared_ptr<StateSequence> commandsAndStates,
+                                     bool validatePositionIncrease) {
         auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
                 IOTraits<Stream>::is_input, portConfig);
         ASSERT_FALSE(devicePorts.empty());
         auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+        SCOPED_TRACE(devicePortConfig.toString());
         WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
         ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
 
@@ -3307,14 +3323,17 @@
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
         if (ValidateObservablePosition(devicePortConfig)) {
-            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            if (validatePositionIncrease) {
+                EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            }
             EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
         }
     }
 
     // Open a stream, then set up a patch for it.
     void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
-                                     std::shared_ptr<StateSequence> commandsAndStates) {
+                                     std::shared_ptr<StateSequence> commandsAndStates,
+                                     bool validatePositionIncrease) {
         WithStream<Stream> stream(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         StreamLogicDefaultDriver driver(commandsAndStates,
@@ -3326,6 +3345,7 @@
                 IOTraits<Stream>::is_input, portConfig);
         ASSERT_FALSE(devicePorts.empty());
         auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+        SCOPED_TRACE(devicePortConfig.toString());
         WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
         ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
 
@@ -3336,7 +3356,9 @@
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
         if (ValidateObservablePosition(devicePortConfig)) {
-            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            if (validatePositionIncrease) {
+                EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            }
             EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
         }
     }
@@ -3668,22 +3690,28 @@
     using State = StreamDescriptor::State;
     auto d = std::make_unique<StateDag>();
     StateDag::Node last = d->makeFinalNode(State::ACTIVE);
-    StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last);
+    // Use a couple of bursts to ensure that the driver starts reporting the position.
+    StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
+    StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, active2);
     StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
     if (!isSync) {
         // Allow optional routing via the TRANSFERRING state on bursts.
-        active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+        active2.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+        active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active2));
         idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
     }
     d->makeNode(State::STANDBY, kStartCommand, idle);
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
 static const NamedCommandSequence kReadSeq =
-        std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true));
+        std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true),
+                        true /*validatePositionIncrease*/);
 static const NamedCommandSequence kWriteSyncSeq =
-        std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true));
+        std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true),
+                        true /*validatePositionIncrease*/);
 static const NamedCommandSequence kWriteAsyncSeq =
-        std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false));
+        std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false),
+                        true /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
     using State = StreamDescriptor::State;
@@ -3711,11 +3739,12 @@
     }
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
-static const NamedCommandSequence kWriteDrainAsyncSeq =
-        std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
-static const NamedCommandSequence kDrainInSeq = std::make_tuple(
-        std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
+static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple(
+        std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+        makeAsyncDrainCommands(false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kDrainInSeq =
+        std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ANY,
+                        makeAsyncDrainCommands(true), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
     using State = StreamDescriptor::State;
@@ -3735,10 +3764,12 @@
     d->makeNode(State::STANDBY, kStartCommand, idle);
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
-static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
-        std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
-static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
-        std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
+static const NamedCommandSequence kDrainOutSyncSeq =
+        std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true),
+                        false /*validatePositionIncrease*/);
+static const NamedCommandSequence kDrainOutAsyncSeq =
+        std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ASYNC,
+                        makeDrainOutCommands(false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
     using State = StreamDescriptor::State;
@@ -3759,12 +3790,12 @@
     d->makeNode(State::STANDBY, kStartCommand, idle);
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
-static const NamedCommandSequence kDrainPauseOutSyncSeq =
-        std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true));
-static const NamedCommandSequence kDrainPauseOutAsyncSeq =
-        std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false));
+static const NamedCommandSequence kDrainPauseOutSyncSeq = std::make_tuple(
+        std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
+        makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kDrainPauseOutAsyncSeq = std::make_tuple(
+        std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+        makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/);
 
 // This sequence also verifies that the capture / presentation position is not reset on standby.
 std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
@@ -3805,13 +3836,15 @@
     }
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
-static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
-        std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
-static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
-        std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
-static const NamedCommandSequence kStandbyOutAsyncSeq =
-        std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
+static const NamedCommandSequence kStandbyInSeq =
+        std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::ANY,
+                        makeStandbyCommands(true, false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kStandbyOutSyncSeq =
+        std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::SYNC,
+                        makeStandbyCommands(false, true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kStandbyOutAsyncSeq = std::make_tuple(
+        std::string("Standby"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+        makeStandbyCommands(false, false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
     using State = StreamDescriptor::State;
@@ -3846,13 +3879,15 @@
     }
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
-static const NamedCommandSequence kPauseInSeq = std::make_tuple(
-        std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false));
-static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple(
-        std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true));
-static const NamedCommandSequence kPauseOutAsyncSeq =
-        std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makePauseCommands(false, false));
+static const NamedCommandSequence kPauseInSeq =
+        std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
+                        makePauseCommands(true, false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kPauseOutSyncSeq =
+        std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
+                        makePauseCommands(false, true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
+        std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+        makePauseCommands(false, false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
     using State = StreamDescriptor::State;
@@ -3879,13 +3914,15 @@
     }
     return std::make_shared<StateSequenceFollower>(std::move(d));
 }
-static const NamedCommandSequence kFlushInSeq = std::make_tuple(
-        std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
-static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
-        std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
-static const NamedCommandSequence kFlushOutAsyncSeq =
-        std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
+static const NamedCommandSequence kFlushInSeq =
+        std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::ANY,
+                        makeFlushCommands(true, false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kFlushOutSyncSeq =
+        std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::SYNC,
+                        makeFlushCommands(false, true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kFlushOutAsyncSeq = std::make_tuple(
+        std::string("Flush"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+        makeFlushCommands(false, false), false /*validatePositionIncrease*/);
 
 std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
     using State = StreamDescriptor::State;
@@ -3906,10 +3943,12 @@
 }
 static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
         std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
+                        StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true),
+                        false /*validatePositionIncrease*/);
 static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
         std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
-                        StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false));
+                        StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false),
+                        false /*validatePositionIncrease*/);
 
 // Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
 std::string PrintStreamFilterToString(StreamTypeFilter filter) {
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
index dfc1039..9d3adc1 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
@@ -25,6 +25,11 @@
         <option name="teardown-command" value="setprop vts.native_server.on 0"/>
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioCoreTargetTest->/data/local/tmp/VtsHalAudioCoreTargetTest" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalAudioCoreTargetTest" />
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 8084a59..225640e 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -134,17 +134,18 @@
 /**
  * @brief Check at least support list of effect must be supported by aosp:
  * https://developer.android.com/reference/android/media/audiofx/AudioEffect
+ *
+ * For Android 13, they are: Equalizer, LoudnessEnhancer, Visualizer, and DynamicsProcessing.
+ * https://source.android.com/docs/compatibility/13/android-13-cdd#552_audio_effects
  */
-TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
+TEST_P(EffectFactoryTest, SupportMandatoryEffectTypes) {
     std::vector<Descriptor> descs;
-    std::set<AudioUuid> typeUuidSet(
-            {aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost(),
-             aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(),
-             aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb(),
-             aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb(),
-             aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(),
-             aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator(),
-             aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer()});
+    std::set<AudioUuid> typeUuidSet({
+            aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(),
+            aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(),
+            aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer(),
+            aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer(),
+    });
 
     EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
     EXPECT_TRUE(descs.size() >= typeUuidSet.size());
@@ -305,4 +306,4 @@
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/audio/core/all-versions/default/ParametersUtil.cpp b/audio/core/all-versions/default/ParametersUtil.cpp
index e21eff2..eb2d2c2 100644
--- a/audio/core/all-versions/default/ParametersUtil.cpp
+++ b/audio/core/all-versions/default/ParametersUtil.cpp
@@ -51,7 +51,7 @@
     Result retval = getParam(name, &halValue);
     *value = false;
     if (retval == Result::OK) {
-        if (halValue.empty()) {
+        if (halValue.length() == 0) {
             return Result::NOT_SUPPORTED;
         }
         *value = !(halValue == AudioParameter::valueOff);
@@ -97,15 +97,15 @@
             retval = getHalStatusToResult(status);
             break;
         }
-        result[i].key = halKey.string();
-        result[i].value = halValue.string();
+        result[i].key = halKey.c_str();
+        result[i].value = halValue.c_str();
     }
     cb(retval, result);
 }
 
 std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter& keys) {
     String8 paramsAndValues;
-    char* halValues = halGetParameters(keys.keysToString().string());
+    char* halValues = halGetParameters(keys.keysToString().c_str());
     if (halValues != NULL) {
         paramsAndValues.setTo(halValues);
         free(halValues);
@@ -163,7 +163,7 @@
 }
 
 Result ParametersUtil::setParams(const AudioParameter& param) {
-    int halStatus = halSetParameters(param.toString().string());
+    int halStatus = halSetParameters(param.toString().c_str());
     return util::analyzeStatus(halStatus);
 }
 
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index 8e85a8b..c11b675 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -114,7 +114,7 @@
     SampleRateSet halSampleRates;
     if (result == Result::OK) {
         halSampleRates =
-            samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator);
+                samplingRatesFromString(halListValue.c_str(), AudioParameter::valueListSeparator);
         sampleRates = hidl_vec<uint32_t>(halSampleRates.begin(), halSampleRates.end());
         // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
         // Note that this method must succeed (non empty list) if the format is supported.
@@ -140,7 +140,7 @@
     ChannelMaskSet halChannelMasks;
     if (result == Result::OK) {
         halChannelMasks =
-            channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator);
+                channelMasksFromString(halListValue.c_str(), AudioParameter::valueListSeparator);
         channelMasks.resize(halChannelMasks.size());
         size_t i = 0;
         for (auto channelMask : halChannelMasks) {
@@ -182,7 +182,7 @@
     hidl_vec<AudioFormat> formats;
     FormatVector halFormats;
     if (result == Result::OK) {
-        halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
+        halFormats = formatsFromString(halListValue.c_str(), AudioParameter::valueListSeparator);
         formats.resize(halFormats.size());
         for (size_t i = 0; i < halFormats.size(); ++i) {
             formats[i] = AudioFormat(halFormats[i]);
@@ -226,7 +226,7 @@
     // Ensure that the separator is one character, despite that it's defined as a C string.
     static_assert(sizeof(AUDIO_PARAMETER_VALUE_LIST_SEPARATOR) == 2);
     std::vector<std::string> halFormats =
-            splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+            splitString(halListValue.c_str(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
     hidl_vec<AudioFormat> formats;
     (void)HidlUtils::audioFormatsFromHal(halFormats, &formats);
     std::vector<AudioProfile> tempProfiles;
@@ -241,7 +241,7 @@
         result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
         if (result != Result::OK) break;
         std::vector<std::string> halSampleRates =
-                splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+                splitString(halListValue.c_str(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
         hidl_vec<uint32_t> sampleRates;
         sampleRates.resize(halSampleRates.size());
         for (size_t i = 0; i < sampleRates.size(); ++i) {
@@ -251,7 +251,7 @@
         result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
         if (result != Result::OK) break;
         std::vector<std::string> halChannelMasks =
-                splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+                splitString(halListValue.c_str(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
         hidl_vec<AudioChannelMask> channelMasks;
         (void)HidlUtils::audioChannelMasksFromHal(halChannelMasks, &channelMasks);
         // Create a profile.
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 84a2b71..01d77d7 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -209,11 +209,13 @@
   public enum UsageEnumType {
     method public String getRawName();
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ALARM;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANT;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_EMERGENCY;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION;
@@ -222,7 +224,9 @@
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_SAFETY;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index b58a6c8..40396bb 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -359,6 +359,10 @@
             <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
             <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
             <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+            <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+            <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+            <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
         </xs:restriction>
     </xs:simpleType>
 
diff --git a/authsecret/aidl/default/Android.bp b/authsecret/aidl/default/Android.bp
index 7ce83fd..7e6e48b 100644
--- a/authsecret/aidl/default/Android.bp
+++ b/authsecret/aidl/default/Android.bp
@@ -26,16 +26,60 @@
 cc_binary {
     name: "android.hardware.authsecret-service.example",
     relative_install_path: "hw",
-    init_rc: ["android.hardware.authsecret-service.example.rc"],
-    vintf_fragments: ["android.hardware.authsecret-service.example.xml"],
     vendor: true,
     srcs: [
         "service.cpp",
         "AuthSecret.cpp",
     ],
     shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    static_libs: [
         "android.hardware.authsecret-V1-ndk",
         "libbase",
-        "libbinder_ndk",
+    ],
+    stl: "c++_static",
+}
+
+prebuilt_etc {
+    name: "android.hardware.authsecret-service.example.rc",
+    src: "android.hardware.authsecret-service.example.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "android.hardware.authsecret-service.example.xml",
+    src: "android.hardware.authsecret-service.example.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex_key {
+    name: "com.android.hardware.authsecret.key",
+    public_key: "com.android.hardware.authsecret.avbpubkey",
+    private_key: "com.android.hardware.authsecret.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.authsecret.certificate",
+    certificate: "com.android.hardware.authsecret",
+}
+
+apex {
+    name: "com.android.hardware.authsecret",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.authsecret.key",
+    certificate: ":com.android.hardware.authsecret.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.authsecret-service.example",
+    ],
+    prebuilts: [
+        "android.hardware.authsecret-service.example.rc", // init_rc
+        "android.hardware.authsecret-service.example.xml", // vintf_fragments
     ],
 }
diff --git a/authsecret/aidl/default/android.hardware.authsecret-service.example.rc b/authsecret/aidl/default/android.hardware.authsecret-service.example.rc
index fef6e24..9f51837 100644
--- a/authsecret/aidl/default/android.hardware.authsecret-service.example.rc
+++ b/authsecret/aidl/default/android.hardware.authsecret-service.example.rc
@@ -1,4 +1,4 @@
-service vendor.authsecret_default /vendor/bin/hw/android.hardware.authsecret-service.example
+service vendor.authsecret_default /apex/com.android.hardware.authsecret/bin/hw/android.hardware.authsecret-service.example
     class hal
     user hsm
     group hsm
diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.avbpubkey b/authsecret/aidl/default/com.android.hardware.authsecret.avbpubkey
new file mode 100644
index 0000000..2fb5f0b
--- /dev/null
+++ b/authsecret/aidl/default/com.android.hardware.authsecret.avbpubkey
Binary files differ
diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.pem b/authsecret/aidl/default/com.android.hardware.authsecret.pem
new file mode 100644
index 0000000..644868c
--- /dev/null
+++ b/authsecret/aidl/default/com.android.hardware.authsecret.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCkkrpV5StewKq6
+HOog0IkbBRAtuChTsQjE1yQY6VXF/f/QWc2L0++pe0PTNzuKJZuqD05tgLYBxsFl
+QSLMKoUnGkQshVHxFLCls0CQo/umgygydxyVNW5cTdDDbl0VHrYcJJSWBobfy/hh
+dizJVET6HMQLY0shKM9CcdFDRqvM+WB6ceBxcFsxwm8r5qcB6CCeIDsPuBBo5Mpa
+NlVbaMBc/qrSRFLqLiVph6Goycg0Zk5+i1A4VBTJoHlOQwgX4uMdlNoAnaf1rLIm
+Qn2zNfcfeZ3BoiwKv8qMsvLNotaN+oIYLi4t21JcPsroByI+Ps5Gia17BhQvbbXx
+3eRShBn6/YcxcMQmCPoN5JbqeyzcE9f0grh3I8ubf1+ZAW0dL2r6QRM6uo6T4Jf7
+BFiMVB0RjTzfo8ngwgPLIm/aXU2O8IG8sILO1s1iOaQb23E2PveF1B7EOmFzW8x3
+xSQQLwn83zY+V+BTZs/Dfgv+M3omctsLS7lgGuvSx9KHV+EnbRMoIYa/2fx5KUxP
+kC3rGpR2BRHZibm3tBlHmdkzOsaHaoQy2fLtqK39Au+cL05O5VpOYObBN2wOlKUO
+iWLS79YoaWAKUZtZKwQNu1jpmK0OMgCeC13QSTz2AuPgL6XEuCUpcmblX3KMsu5w
+MK79Yke/V61cQ71e5qI0vr3IXjcjywIDAQABAoICAAYZ0GGNyNFO6CVVHBLSWDrR
+sbtYJ9qOZgpSBWsM/1qDI4AYTCfiV/Ca+rUyR3lEEqS3w4sIqfaf5Rx5US5rZxs/
+fIZ//L0orLG/1uVlxtbx5sQUKVGYtPokAli0VywIwuyBKKb1H/vc5lzKkjd2ccYp
+2dSoPilBB4npiT3quUS0e/CeFxltdlv+XrusZcWK0ua5wCbBho406RF2ESz90Z/A
+6xk3YjF/O3DRj9sfe9YBcuh7BqLH7ytYURbnIj4scYnvsjMypP7VA5eqgFlr5zjZ
++9CpT+OoH3yex6R65GRIBJmb4KdfiYqU41W9qfXPwzrXMMCuRYJKmWOZe7TZY9Mc
+V46jaDgLgKxe+mI4CLi2auKFE4KL8x68KSqa22y2dEjWwBPiT7If6v0ZL4CiAy9n
+SNHFaceMY3l485vaZEtXxusRB/UGDZnAXr9NqBVm4YVAfOaEnJNDSqvYefM5iyOG
+yQZ7dCXS9Ey4JvVlceA6mybj2JSx20QS2wN/tcyZjWsjM0f/sIHAJRS6KhEqCIfX
+4L8d5nXJ1wvnBFvcfboSERkPOTQsuipsvn9uj8Zs9QWNYYRSyleptL+ce8fBqed6
+9ryErCuB9lpVTjUsOiaIibtGdePleQb10club1B/4vsgPl5wvTPRNCTmpOCP3pSf
+Rei2x4z1VGFOBwd3MiTtAoIBAQDiQCsK87Zs8E5cwc0CqeMWstWHvJLTkj2B42OI
+Zrbr6ByRixuLpWgVWtJJLKbLXPN83wl8eksv3+Ba+yi17uafhXX7M1O5RlOzvTHt
+bbFPeysB3KEmNt96dRDRKYY3z0KHJxCRWKKZjZjp8Usf3TuKi9Xbque8o2n1LKKB
+KANRC4xtHmUesl6d4S4iAfIkq5/nA4ocuJ2qd/2t3nc6yhPPRrP9+4sUPYdqBEUz
+ds9isqt5erUybstCoHRgsEwWo/9ew8Dyj1TCIDTSqRt1/0QnEVm77bgBrA8P66HI
+KKFVoo/MLQSw5V+CDZwTJNlPQwrG9tyrSkcMFgLSRzi+7d/3AoIBAQC6Nm5Ztiad
+zm/1jM89uHmvedimKCKKG6+Eom5D96PduP76uRr65s6Usn0QCZ4Jvou0xnbtCP1K
+lzVI1+v6EiIQyWX0y1bd0UJDdyYo4Ck2nqOh0vgw+cBO70faV50J5QA2mS/wFdw0
+PvykQpPYGiIfv1MMHWA+rPDzMtf1uUQ18vzzN7RaZll88pletC7mc7qgBaucQVvB
+/qzOZSwhiaSSvXS1sFKfkqLqpJ3x9748D74MIwDD2i3fRxxfqPcgrG3B7xxIKVgd
+CYoFjeC9inZbnwvPmtaKzROJknsuJA21s/ckkSiWJJbjbyymVc1hWNhoMbtSPopa
+OOJ7u695Ls3NAoIBADtRE3fVmXhKMGFFNhiCrdTfoffqSpxJdPK+yPOT6lVDD2ph
+DCG6heVDYGpq2HfssLGGUBhgf6HXkhyISI4aSkB8Xwgy1rp2Y6915McYwSnTYt0k
+GOPJ8yFJ29TajCPJpOmGJmPU1xxm8TY0WrvJ5rhWHQVwcz0Tos3ym9A8y1HOM0zQ
+cTZxETlXNh8YX4GZtVx9oxIQnNV6i/mvn5a8MCFhqgLmlfoCf6Qd5n6toYWAzlAV
+CbhlL8kSBDDtR6WP7X3M2KM/TLtwcijgySBQgm+zrtEEa/+UOoa0AkBV1qZ67jRb
+gSVXnYidRNQIDykmrIapZgVKfgH/K1Ix9gCooNUCggEAeSMzwnS2xm4nc2w43YQG
+1VrEz8LIRWQhWH16kgilt3XDmkOVA6fmt+EtbqNzBg/JPr7lWupALKgVZ9/fiX0G
+YDlEdG1bg03Ad7cpQeohpYCqHnnqL6IpsrAC5E2ewXMSInKhNuRhrjNTk2AkYa8O
+h+ylD/qERAGpdeybhSUS9K2wVGDmmPCAQsJnd65r3EtpGvTVYP87vAX7UQGMJf0u
+7K8HH7Mm7Nwt08tnXKO4Q8ZR8f9LXh2vPdM66Bg5PC4v8LumgGM1CR7NhTN5ApTy
+zkO3IUUvUHh8v0BlleyqZow+uLEd4B7Jcgc+2q5yv2NW1OGVZLl+s5bR74B3dLQ3
++QKCAQBtxqTUKaRE/g+paQByORt0mFuXhO5UyfEBpg6l7+aUS4wTGMeKKDCFjTME
+lDjEK7eiAAOgN3AJYQ+r6831pm3hg6DG5lpxTKUuz2eMqMHk3LVlDFkH6BZF3Jxg
+XxWP1Abi88hK3nnbuGrt6rlUxvJRdWaJcF5nXybJzPMpvzPcDjAg5fCT11vZQsRl
+piAO6NjAECwUOaBHSHPvIXO9fWu4zY03rhg9px+dkutydSJ/6B3jq33q1CzHDQMd
+bklkBBrLu9inpuvETbhVK6IWP2zMHzdViR58M+xd5rg2E3GBQePyd6mjOB+7p7Gd
+hUHo4XX1/r2CDceZTmOjaZP/MQOJ
+-----END PRIVATE KEY-----
diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.pk8 b/authsecret/aidl/default/com.android.hardware.authsecret.pk8
new file mode 100644
index 0000000..1453366
--- /dev/null
+++ b/authsecret/aidl/default/com.android.hardware.authsecret.pk8
Binary files differ
diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.x509.pem b/authsecret/aidl/default/com.android.hardware.authsecret.x509.pem
new file mode 100644
index 0000000..71fe854
--- /dev/null
+++ b/authsecret/aidl/default/com.android.hardware.authsecret.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF4zCCA8sCFH8r8uUt7ZiBGNZm/OxNbzMI34N3MA0GCSqGSIb3DQEBCwUAMIGs
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEoMCYGA1UEAwwfY29t
+LmFuZHJvaWQuaGFyZHdhcmUuYXV0aHNlY3JldDAgFw0yMzA4MTgwNzA3MDFaGA80
+NzYxMDcxNDA3MDcwMVowgawxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQu
+Y29tMSgwJgYDVQQDDB9jb20uYW5kcm9pZC5oYXJkd2FyZS5hdXRoc2VjcmV0MIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1+ml99ip2TVpYdJXxqVnizLg
+/DAnOUy5rZE+mCpjua1zyHl7GFFnseq6GO5wftptWekcC9fVSPxg1YS+RVduRcNz
+rt3mCsJ60DexaHrElITc1GCC1vzyt9cg6UtmdYg+OXSPlfWZE2T7OLfGWrhU56El
+IFt1eQDu5RDBOHZ2/N30KmKXv3yhpdl5un/kaC6q6p1PPih0aYXT2PrHsyN17wBl
+smhhpWNg/OAzFhWKwFcSTLMCOAI+pjqWKqXmjQ1awBly+lLAtHEBxxEUDMD6Z4lv
+2OGftL9bdseb1Wbj2bgj22bkfwWj5Yu77ilz5H27aLxQouQsmSfBkVgLq6seQMzd
+ovg+MOFb9iyWgcWkGg7eKdSzjfzCKQ/d2GOxEqwGofEYUOxYM1+a0Fnb7vUtgT/v
+I4tJCgXxAMFtsYGySC+gBhNx7vqLfo/8gtcZjJL6PRtRJ2V7hF9x3xKFa2/6qOLn
+UD/R5z+uwzaEqom+AmmmKNdWtn58nBns7EGq/3KVPcb7CSi9Xf6CCJiV+AmRaBSx
+2CtLt1fBX46LM3bV+iw7ZFAYAAXE3j6FgpM/PlozQjl61TuomHQP1ILmu/988tiF
+FMbuRH6mI0u4VOkDBUg9lxmjr0uAVmysWmzkRrAKydzedsuG5WG6hy2ZcD+lCV05
+JzvE6pB65OaIEPB5cMECAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAozFo1vOIy/Js
+/EU5oRtSGSIoWCNIn7EYQ68jVHQk2ZhklVH2jW+6WVGmreOjPz5iWeDb0fC4KVtH
+MPXJ1Vd+GfvDysrnW5mDBzlI1O2xv/BWYeHt+RFWghhH/NFHaTQqDJpdOZXMZM4F
+dwFefxLchcXftE9jihHJXJ4k0cxC03Kpd0caZE7b67W1YQdJhU9mZx6CP1A3MdWU
+f48QIsmHgejkihtGNDRheBRzNdpHPhdOjYIWhOeAHh/xnm7PVZBMXmZeNW7MrAS0
++lN99r7Xj3eqtSdrMrrob845PWYsATA/a8ouUuTT7812fl8tZx69xb8wV5hNztDj
+srOxxJbjt1uwcSp67f2K91D97CQuMMPnOt1oFEXT+5QtLEiybXKfkshwO7VVDoIg
+owMLoKIiA2Xr+rZn7CEBeTrqQuRJfJEI+k/49zg2zWQIKGQAz8iaO0l95Hk5kPTE
+A5i9qxhn0UqC6a4Dkj8ybQOACzVA06IsbbYdprfzURQHjcUiSrEzjrwWxkkX/9El
+Z0CJAtkXx4pMxo5s6zt26ZPC3cxWB7aageWSC4xDbKuQP5VCNVg1nWymg6nF4Xk9
+d7n7yvSNH6fAZrpmZo7o7CBxCb4QN8j7TpyuaPd7nzyCyR6aGbh7fz8xksukvj6w
+ZSbAAy5uw4hyUwTTpyPyw+qQxI7O/PU=
+-----END CERTIFICATE-----
diff --git a/authsecret/aidl/default/file_contexts b/authsecret/aidl/default/file_contexts
new file mode 100644
index 0000000..8e79f26
--- /dev/null
+++ b/authsecret/aidl/default/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.authsecret-service\.example      u:object_r:hal_authsecret_default_exec:s0
\ No newline at end of file
diff --git a/authsecret/aidl/default/manifest.json b/authsecret/aidl/default/manifest.json
new file mode 100644
index 0000000..ad5a45b
--- /dev/null
+++ b/authsecret/aidl/default/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.authsecret",
+    "version": 1
+}
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index e82f6fa..3452ae9 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,5 +1,6 @@
 <manifest version="2.0" type="device">
     <hal format="aidl">
+        <version>2</version>
         <name>android.hardware.automotive.audiocontrol</name>
         <fqname>IAudioControl/default</fqname>
     </hal>
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 2e7298f..b3f4a0f 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -107,12 +107,18 @@
     // Gets the callback to be called when the request for this client has finished.
     std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
 
-    // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+    // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
     // callback.
     static void sendUpdatedValues(
             CallbackType callback,
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
                     updatedValues);
+    // Marshals the set property error events into largeParcelable and sends it through
+    // {@code onPropertySetError} callback.
+    static void sendPropertySetErrors(
+            CallbackType callback,
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
+                    vehiclePropErrors);
 
   protected:
     // Gets the callback to be called when the request for this client has timeout.
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 9c29816..b6dbbc1 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -247,10 +247,14 @@
             const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
 
     static void onPropertyChangeEvent(
-            std::weak_ptr<SubscriptionManager> subscriptionManager,
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
             const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                     updatedValues);
 
+    static void onPropertySetErrorEvent(
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+            const std::vector<SetValueErrorEvent>& errorEvents);
+
     static void checkHealth(IVehicleHardware* hardware,
                             std::weak_ptr<SubscriptionManager> subscriptionManager);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
index 7c8f1b4..4912093 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -103,6 +103,11 @@
     // property has not been subscribed before or is not a continuous property.
     std::optional<float> getSampleRate(const ClientIdType& clientId, int32_t propId,
                                        int32_t areaId);
+    // For a list of set property error events, returns a map that maps clients subscribing to the
+    // properties to a list of errors for each client.
+    std::unordered_map<CallbackType,
+                       std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
+    getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
 
     // Checks whether the sample rate is valid.
     static bool checkSampleRate(float sampleRate);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 81d231c..fb23a25 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -38,6 +38,8 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
 using ::android::base::Result;
@@ -300,7 +302,34 @@
     if (ScopedAStatus callbackStatus =
                 callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
         !callbackStatus.isOk()) {
-        ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
+        ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
+              "exception: %d, service specific error: %d",
+              callback->asBinder().get(), callbackStatus.getMessage(),
+              callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
+    }
+}
+
+void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
+                                               std::vector<VehiclePropError>&& vehiclePropErrors) {
+    if (vehiclePropErrors.empty()) {
+        return;
+    }
+
+    VehiclePropErrors vehiclePropErrorsLargeParcelable;
+    ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
+                                                         &vehiclePropErrorsLargeParcelable);
+    if (!status.isOk()) {
+        int statusCode = status.getServiceSpecificError();
+        ALOGE("subscribe: failed to marshal result into large parcelable, error: "
+              "%s, code: %d",
+              status.getMessage(), statusCode);
+        return;
+    }
+
+    if (ScopedAStatus callbackStatus =
+                callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
+        !callbackStatus.isOk()) {
+        ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
               "exception: %d, service specific error: %d",
               callback->asBinder().get(), callbackStatus.getMessage(),
               callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index b191aef..2e9a4b6 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -156,6 +156,11 @@
                     [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
                         onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
                     }));
+    mVehicleHardware->registerOnPropertySetErrorEvent(
+            std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
+                    [subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
+                        onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
+                    }));
 
     // Register heartbeat event.
     mRecurrentAction =
@@ -189,7 +194,7 @@
 }
 
 void DefaultVehicleHal::onPropertyChangeEvent(
-        std::weak_ptr<SubscriptionManager> subscriptionManager,
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
         const std::vector<VehiclePropValue>& updatedValues) {
     auto manager = subscriptionManager.lock();
     if (manager == nullptr) {
@@ -206,6 +211,20 @@
     }
 }
 
+void DefaultVehicleHal::onPropertySetErrorEvent(
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    auto manager = subscriptionManager.lock();
+    if (manager == nullptr) {
+        ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+    auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
+    for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) {
+        SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors));
+    }
+}
+
 template <class T>
 std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
         std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -669,15 +688,19 @@
         // Create a new SubscriptionClient if there isn't an existing one.
         mSubscriptionClients->maybeAddClient(callback);
 
-        // Since we have already check the sample rates, the following functions must succeed.
         if (!onChangeSubscriptions.empty()) {
-            return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
-                                                                   /*isContinuousProperty=*/false));
+            auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+                                                          /*isContinuousProperty=*/false);
+            if (!result.ok()) {
+                return toScopedAStatus(result);
+            }
         }
         if (!continuousSubscriptions.empty()) {
-            return toScopedAStatus(mSubscriptionManager->subscribe(callback,
-                                                                   continuousSubscriptions,
-                                                                   /*isContinuousProperty=*/true));
+            auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+                                                          /*isContinuousProperty=*/true);
+            if (!result.ok()) {
+                return toScopedAStatus(result);
+            }
         }
     }
     return ScopedAStatus::ok();
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index 2694401..566c303 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -36,6 +36,7 @@
 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::Error;
 using ::android::base::Result;
@@ -281,6 +282,32 @@
     return clients;
 }
 
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
+SubscriptionManager::getSubscribedClientsForErrorEvents(
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
+
+    for (const auto& errorEvent : errorEvents) {
+        PropIdAreaId propIdAreaId{
+                .propId = errorEvent.propId,
+                .areaId = errorEvent.areaId,
+        };
+        if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+            continue;
+        }
+
+        for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
+            clients[client].push_back({
+                    .propId = errorEvent.propId,
+                    .areaId = errorEvent.areaId,
+                    .errorCode = errorEvent.errorCode,
+            });
+        }
+    }
+    return clients;
+}
+
 bool SubscriptionManager::isEmpty() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index f48b906..76b57c7 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -62,6 +62,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
@@ -1656,6 +1657,63 @@
     ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
 }
 
+TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaIds = {0},
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaIds = {0},
+                    .sampleRate = 1,
+            },
+    };
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    std::vector<SetValueErrorEvent> errorEvents = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INTERNAL_ERROR,
+            },
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INVALID_ARG,
+            },
+    };
+    std::vector<VehiclePropError> expectedResults = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INTERNAL_ERROR,
+            },
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INVALID_ARG,
+            },
+    };
+    getHardware()->sendOnPropertySetErrorEvent(errorEvents);
+
+    ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u);
+    auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults();
+    ASSERT_TRUE(maybeVehiclePropErrors.has_value());
+    const auto& vehiclePropErrors = maybeVehiclePropErrors.value();
+    ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index 0e46357..75b8257 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -63,8 +63,9 @@
     return storeResults(results, &mOnPropertyEventResults);
 }
 
-ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
-    return ScopedAStatus::ok();
+ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return storeResults(results, &mOnPropertySetErrorResults);
 }
 
 std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
@@ -87,6 +88,16 @@
     return mOnPropertyEventResults.size();
 }
 
+std::optional<VehiclePropErrors> MockVehicleCallback::nextOnPropertySetErrorResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return pop(mOnPropertySetErrorResults);
+}
+
+size_t MockVehicleCallback::countOnPropertySetErrorResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mOnPropertySetErrorResults.size();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 0faaa1f..91dbb7e 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -62,6 +62,9 @@
     nextSetValueResults();
     std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
     nextOnPropertyEventResults();
+    size_t countOnPropertySetErrorResults();
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+    nextOnPropertySetErrorResults();
     size_t countOnPropertyEventResults();
 
   private:
@@ -73,6 +76,8 @@
     std::list<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
             mOnPropertyEventResults GUARDED_BY(mLock);
     int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
+    std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+            mOnPropertySetErrorResults GUARDED_BY(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index 4df4e1a..ba0d33d 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -131,8 +131,9 @@
 }
 
 void MockVehicleHardware::registerOnPropertySetErrorEvent(
-        std::unique_ptr<const PropertySetErrorCallback>) {
-    // TODO(b/200737967): mock this.
+        std::unique_ptr<const PropertySetErrorCallback> callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mPropertySetErrorCallback = std::move(callback);
 }
 
 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
@@ -254,6 +255,12 @@
         std::list<std::vector<SetValueRequest>>* storedRequests,
         std::list<std::vector<SetValueResult>>* storedResponses) const;
 
+void MockVehicleHardware::sendOnPropertySetErrorEvent(
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    (*mPropertySetErrorCallback)(errorEvents);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index 743841c..46b30b9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -85,6 +85,7 @@
                    aidl::android::hardware::automotive::vehicle::StatusCode status);
     void setSleepTime(int64_t timeInNano);
     void setDumpResult(DumpResult result);
+    void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
 
   private:
     mutable std::mutex mLock;
@@ -104,6 +105,7 @@
             mStatusByFunctions GUARDED_BY(mLock);
     int64_t mSleepTime GUARDED_BY(mLock) = 0;
     std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
+    std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
     std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
             std::shared_ptr<const GetValuesCallback>,
             const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
index 6010c60..c23d687 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
@@ -19,8 +19,6 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
     </target_preparer>
-    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup">
-    </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
@@ -31,6 +29,9 @@
         <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup">
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalBluetoothV1_0TargetTest->/data/local/tmp/VtsHalBluetoothV1_0TargetTest" />
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
index 782122f..013ab7f 100644
--- a/bluetooth/aidl/default/BluetoothHci.cpp
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -55,6 +55,19 @@
 
 void OnDeath(void* cookie);
 
+std::optional<std::string> GetSystemProperty(const std::string& property) {
+  std::array<char, PROPERTY_VALUE_MAX> value_array{0};
+  auto value_len = property_get(property.c_str(), value_array.data(), nullptr);
+  if (value_len <= 0) {
+    return std::nullopt;
+  }
+  return std::string(value_array.data(), value_len);
+}
+
+bool starts_with(const std::string& str, const std::string& prefix) {
+  return str.compare(0, prefix.length(), prefix) == 0;
+}
+
 class BluetoothDeathRecipient {
  public:
   BluetoothDeathRecipient(BluetoothHci* hci) : mHci(hci) {}
@@ -232,8 +245,19 @@
 
   mDeathRecipient->LinkToDeath(mCb);
 
-  // TODO: This should not be necessary when the device implements rfkill.
-  reset();
+  // TODO: HCI Reset on emulators since the bluetooth controller
+  // cannot be powered on/off during the HAL setup; and the stack
+  // might received spurious packets/events during boottime.
+  // Proper solution would be to use bt-virtio or vsock to better
+  // control the link to rootcanal and the controller lifetime.
+  const std::string kBoardProperty = "ro.product.board";
+  const std::string kCuttlefishBoard = "cutf";
+  auto board_name = GetSystemProperty(kBoardProperty);
+  if (board_name.has_value() && (
+        starts_with(board_name.value(), "cutf") ||
+        starts_with(board_name.value(), "goldfish"))) {
+    reset();
+  }
 
   mH4 = std::make_shared<H4Protocol>(
       mFd,
diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
index e5222a7..24eb4d0 100644
--- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
+++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
@@ -222,6 +222,8 @@
   int wait_for_completed_packets_event(uint16_t handle);
   void send_and_wait_for_cmd_complete(std::unique_ptr<CommandBuilder> cmd,
                                       std::vector<uint8_t>& cmd_complete);
+  void reassemble_sco_loopback_pkt(std::vector<uint8_t>& scoPackets,
+    size_t size);
 
   // A simple test implementation of BluetoothHciCallbacks.
   class BluetoothHciCallbacks
@@ -569,6 +571,11 @@
     ASSERT_TRUE(
         sco_queue.tryPopWithTimeout(sco_loopback, kWaitForScoDataTimeout));
 
+    if (sco_loopback.size() < size) {
+      // The packets may have been split for USB. Reassemble before checking.
+      reassemble_sco_loopback_pkt(sco_loopback, size);
+    }
+
     ASSERT_EQ(sco_packet, sco_loopback);
   }
   logger.setTotalBytes(num_packets * size * 2);
@@ -703,6 +710,22 @@
       wait_for_command_complete_event(view.GetOpCode(), cmd_complete));
 }
 
+// Handle the loopback packet.
+void BluetoothAidlTest::reassemble_sco_loopback_pkt(std::vector<uint8_t>& scoPackets,
+        size_t size) {
+    std::vector<uint8_t> sco_packet_whole;
+    sco_packet_whole.assign(scoPackets.begin(), scoPackets.end());
+    while (size + 3 > sco_packet_whole.size()) {
+      std::vector<uint8_t> sco_packets;
+      ASSERT_TRUE(
+      sco_queue.tryPopWithTimeout(sco_packets, kWaitForScoDataTimeout));
+      sco_packet_whole.insert(sco_packet_whole.end(), sco_packets.begin() + 3,
+          sco_packets.end());
+    }
+    scoPackets.assign(sco_packet_whole.begin(), sco_packet_whole.end());
+    scoPackets[2] = size;
+}
+
 // Empty test: Initialize()/Close() are called in SetUp()/TearDown().
 TEST_P(BluetoothAidlTest, InitializeAndClose) {}
 
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 618141f..1028fae 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -24,12 +24,13 @@
 aidl_interface {
     name: "android.hardware.bluetooth.audio",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/bluetooth/audio/*.aidl"],
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V1",
+        "android.hardware.audio.common-V2",
     ],
     backend: {
         cpp: {
@@ -64,7 +65,16 @@
                 "android.hardware.audio.common-V1",
             ],
         },
+        {
+            version: "3",
+            imports: [
+                "android.hardware.common-V2",
+                "android.hardware.common.fmq-V1",
+                "android.hardware.audio.common-V2",
+            ],
+        },
 
     ],
+    frozen: true,
 
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/.hash b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/.hash
new file mode 100644
index 0000000..36a90ad
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/.hash
@@ -0,0 +1 @@
+fead4df60244a5440283617064f184690414a685
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacCapabilities.aidl
new file mode 100644
index 0000000..e548cd3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacCapabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AacCapabilities {
+  android.hardware.bluetooth.audio.AacObjectType[] objectType;
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  boolean variableBitRateSupported;
+  byte[] bitsPerSample;
+  boolean adaptiveBitRateSupported;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacConfiguration.aidl
new file mode 100644
index 0000000..29ab8ce
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AacConfiguration {
+  android.hardware.bluetooth.audio.AacObjectType objectType;
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  boolean variableBitRateEnabled;
+  byte bitsPerSample;
+  boolean adaptiveBitRateSupported;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacObjectType.aidl
new file mode 100644
index 0000000..418dd7a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum AacObjectType {
+  MPEG2_LC,
+  MPEG4_LC,
+  MPEG4_LTP,
+  MPEG4_SCALABLE,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveCapabilities.aidl
new file mode 100644
index 0000000..4e5dfe6
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveCapabilities.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.AptxAdaptiveChannelMode[] channelMode;
+  byte[] bitsPerSample;
+  android.hardware.bluetooth.audio.AptxMode[] aptxMode;
+  android.hardware.bluetooth.audio.AptxSinkBuffering sinkBufferingMs;
+  android.hardware.bluetooth.audio.AptxAdaptiveTimeToPlay ttp;
+  android.hardware.bluetooth.audio.AptxAdaptiveInputMode inputMode;
+  int inputFadeDurationMs;
+  byte[] aptxAdaptiveConfigStream;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
new file mode 100644
index 0000000..675f9f2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AptxAdaptiveChannelMode {
+  JOINT_STEREO = 0,
+  MONO = 1,
+  DUAL_MONO = 2,
+  TWS_STEREO = 4,
+  UNKNOWN = 0xFF,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveConfiguration.aidl
new file mode 100644
index 0000000..aab0521
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveConfiguration.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.AptxAdaptiveChannelMode channelMode;
+  byte bitsPerSample;
+  android.hardware.bluetooth.audio.AptxMode aptxMode;
+  android.hardware.bluetooth.audio.AptxSinkBuffering sinkBufferingMs;
+  android.hardware.bluetooth.audio.AptxAdaptiveTimeToPlay ttp;
+  android.hardware.bluetooth.audio.AptxAdaptiveInputMode inputMode;
+  int inputFadeDurationMs;
+  byte[] aptxAdaptiveConfigStream;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
new file mode 100644
index 0000000..a18303e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AptxAdaptiveInputMode {
+  STEREO = 0x00,
+  DUAL_MONO = 0x01,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveLeCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveLeCapabilities.aidl
new file mode 100644
index 0000000..c9d3cde
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveLeCapabilities.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveLeCapabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveLeConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveLeConfiguration.aidl
new file mode 100644
index 0000000..76df4ed
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveLeConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveLeConfiguration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  int codecMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveTimeToPlay.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveTimeToPlay.aidl
new file mode 100644
index 0000000..3560666
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxAdaptiveTimeToPlay.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveTimeToPlay {
+  byte lowLowLatency;
+  byte highLowLatency;
+  byte lowHighQuality;
+  byte highHighQuality;
+  byte lowTws;
+  byte highTws;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxCapabilities.aidl
new file mode 100644
index 0000000..08a38e2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxConfiguration.aidl
new file mode 100644
index 0000000..91e88b3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxConfiguration.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxMode.aidl
new file mode 100644
index 0000000..dd8cf08
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AptxMode {
+  UNKNOWN = 0x00,
+  HIGH_QUALITY = 0x1000,
+  LOW_LATENCY = 0x2000,
+  ULTRA_LOW_LATENCY = 0x4000,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxSinkBuffering.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxSinkBuffering.aidl
new file mode 100644
index 0000000..527418e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AptxSinkBuffering.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxSinkBuffering {
+  byte minLowLatency;
+  byte maxLowLatency;
+  byte minHighQuality;
+  byte maxHighQuality;
+  byte minTws;
+  byte maxTws;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioCapabilities.aidl
new file mode 100644
index 0000000..8ae716f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union AudioCapabilities {
+  android.hardware.bluetooth.audio.PcmCapabilities pcmCapabilities;
+  android.hardware.bluetooth.audio.CodecCapabilities a2dpCapabilities;
+  android.hardware.bluetooth.audio.LeAudioCodecCapabilitiesSetting leAudioCapabilities;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioConfiguration.aidl
new file mode 100644
index 0000000..3abfb31
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union AudioConfiguration {
+  android.hardware.bluetooth.audio.PcmConfiguration pcmConfig;
+  android.hardware.bluetooth.audio.CodecConfiguration a2dpConfig;
+  android.hardware.bluetooth.audio.LeAudioConfiguration leAudioConfig;
+  android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration leAudioBroadcastConfig;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioLocation.aidl
new file mode 100644
index 0000000..941344c
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AudioLocation {
+  UNKNOWN = 1,
+  FRONT_LEFT = (1 << 1) /* 2 */,
+  FRONT_RIGHT = (1 << 2) /* 4 */,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
new file mode 100644
index 0000000..c20c057
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum BluetoothAudioStatus {
+  UNKNOWN = 0,
+  SUCCESS = 1,
+  UNSUPPORTED_CODEC_CONFIGURATION = 2,
+  FAILURE = 3,
+  RECONFIGURATION = 4,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/BroadcastCapability.aidl
new file mode 100644
index 0000000..58710ef
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable BroadcastCapability {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.AudioLocation supportedChannel;
+  int channelCountPerStream;
+  android.hardware.bluetooth.audio.BroadcastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union LeAudioCodecCapabilities {
+    @nullable android.hardware.bluetooth.audio.Lc3Capabilities[] lc3Capabilities;
+    @nullable android.hardware.bluetooth.audio.BroadcastCapability.VendorCapabilities[] vendorCapabillities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/ChannelMode.aidl
new file mode 100644
index 0000000..2bb5cd8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum ChannelMode {
+  UNKNOWN,
+  MONO,
+  STEREO,
+  DUALMONO,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecCapabilities.aidl
new file mode 100644
index 0000000..b00649a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable CodecCapabilities {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.CodecCapabilities.Capabilities capabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union Capabilities {
+    android.hardware.bluetooth.audio.SbcCapabilities sbcCapabilities;
+    android.hardware.bluetooth.audio.AacCapabilities aacCapabilities;
+    android.hardware.bluetooth.audio.LdacCapabilities ldacCapabilities;
+    android.hardware.bluetooth.audio.AptxCapabilities aptxCapabilities;
+    android.hardware.bluetooth.audio.AptxAdaptiveCapabilities aptxAdaptiveCapabilities;
+    android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+    android.hardware.bluetooth.audio.CodecCapabilities.VendorCapabilities vendorCapabilities;
+    @nullable android.hardware.bluetooth.audio.OpusCapabilities opusCapabilities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecConfiguration.aidl
new file mode 100644
index 0000000..7f5ea48
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable CodecConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  int encodedAudioBitrate;
+  int peerMtu;
+  boolean isScmstEnabled;
+  android.hardware.bluetooth.audio.CodecConfiguration.CodecSpecific config;
+  @VintfStability
+  parcelable VendorConfiguration {
+    int vendorId;
+    char codecId;
+    ParcelableHolder codecConfig;
+  }
+  @VintfStability
+  union CodecSpecific {
+    android.hardware.bluetooth.audio.SbcConfiguration sbcConfig;
+    android.hardware.bluetooth.audio.AacConfiguration aacConfig;
+    android.hardware.bluetooth.audio.LdacConfiguration ldacConfig;
+    android.hardware.bluetooth.audio.AptxConfiguration aptxConfig;
+    android.hardware.bluetooth.audio.AptxAdaptiveConfiguration aptxAdaptiveConfig;
+    android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+    android.hardware.bluetooth.audio.CodecConfiguration.VendorConfiguration vendorConfig;
+    @nullable android.hardware.bluetooth.audio.OpusConfiguration opusConfig;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecType.aidl
new file mode 100644
index 0000000..d4f205e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/CodecType.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum CodecType {
+  UNKNOWN,
+  SBC,
+  AAC,
+  APTX,
+  APTX_HD,
+  LDAC,
+  LC3,
+  VENDOR,
+  APTX_ADAPTIVE,
+  OPUS,
+  APTX_ADAPTIVE_LE,
+  APTX_ADAPTIVE_LEX,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
new file mode 100644
index 0000000..d364371
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioPort {
+  android.hardware.bluetooth.audio.PresentationPosition getPresentationPosition();
+  void startStream(boolean isLowLatency);
+  void stopStream();
+  void suspendStream();
+  void updateSourceMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+  void updateSinkMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+  void setLatencyMode(in android.hardware.bluetooth.audio.LatencyMode latencyMode);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
new file mode 100644
index 0000000..267af0f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioProvider {
+  void endSession();
+  android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> startSession(in android.hardware.bluetooth.audio.IBluetoothAudioPort hostIf, in android.hardware.bluetooth.audio.AudioConfiguration audioConfig, in android.hardware.bluetooth.audio.LatencyMode[] supportedLatencyModes);
+  void streamStarted(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
+  void streamSuspended(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
+  void updateAudioConfiguration(in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
+  void setLowLatencyModeAllowed(in boolean allowed);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
new file mode 100644
index 0000000..5e33deb
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioProviderFactory {
+  android.hardware.bluetooth.audio.AudioCapabilities[] getProviderCapabilities(in android.hardware.bluetooth.audio.SessionType sessionType);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider openProvider(in android.hardware.bluetooth.audio.SessionType sessionType);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LatencyMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LatencyMode.aidl
new file mode 100644
index 0000000..1140f9e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LatencyMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum LatencyMode {
+  UNKNOWN,
+  LOW_LATENCY,
+  FREE,
+  DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+  DYNAMIC_SPATIAL_AUDIO_HARDWARE,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/Lc3Capabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
new file mode 100644
index 0000000..cc4449a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable Lc3Capabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/Lc3Configuration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/Lc3Configuration.aidl
new file mode 100644
index 0000000..7e8dccf
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/Lc3Configuration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable Lc3Configuration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacCapabilities.aidl
new file mode 100644
index 0000000..aa4e4c8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LdacCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.LdacChannelMode[] channelMode;
+  android.hardware.bluetooth.audio.LdacQualityIndex[] qualityIndex;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacChannelMode.aidl
new file mode 100644
index 0000000..3d80c4b
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LdacChannelMode {
+  UNKNOWN,
+  STEREO,
+  DUAL,
+  MONO,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacConfiguration.aidl
new file mode 100644
index 0000000..8a37638
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LdacConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.LdacChannelMode channelMode;
+  android.hardware.bluetooth.audio.LdacQualityIndex qualityIndex;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
new file mode 100644
index 0000000..a332dc5
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LdacQualityIndex {
+  HIGH,
+  MID,
+  LOW,
+  ABR,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
new file mode 100644
index 0000000..2945710
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LeAudioBroadcastConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap[] streamMap;
+  @VintfStability
+  parcelable BroadcastStreamMap {
+    char streamHandle;
+    int audioChannelAllocation;
+    android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
+    char pcmStreamId;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
new file mode 100644
index 0000000..9818d54
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LeAudioCodecCapabilitiesSetting {
+  android.hardware.bluetooth.audio.UnicastCapability unicastEncodeCapability;
+  android.hardware.bluetooth.audio.UnicastCapability unicastDecodeCapability;
+  android.hardware.bluetooth.audio.BroadcastCapability broadcastCapability;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
new file mode 100644
index 0000000..031ee67
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union LeAudioCodecConfiguration {
+  android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+  android.hardware.bluetooth.audio.LeAudioCodecConfiguration.VendorConfiguration vendorConfig;
+  android.hardware.bluetooth.audio.AptxAdaptiveLeConfiguration aptxAdaptiveLeConfig;
+  @VintfStability
+  parcelable VendorConfiguration {
+    ParcelableHolder extension;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
new file mode 100644
index 0000000..2d9ebae
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LeAudioConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap[] streamMap;
+  int peerDelayUs;
+  android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
+  @nullable byte[] vendorSpecificMetadata;
+  @VintfStability
+  parcelable StreamMap {
+    char streamHandle;
+    int audioChannelAllocation;
+    boolean isStreamActive;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/OpusCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/OpusCapabilities.aidl
new file mode 100644
index 0000000..2c04b0f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/OpusCapabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable OpusCapabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/OpusConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/OpusConfiguration.aidl
new file mode 100644
index 0000000..811d32a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/OpusConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable OpusConfiguration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PcmCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PcmCapabilities.aidl
new file mode 100644
index 0000000..0c2f87d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PcmCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable PcmCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  byte[] bitsPerSample;
+  int[] dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PcmConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PcmConfiguration.aidl
new file mode 100644
index 0000000..93d7805
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PcmConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable PcmConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  byte bitsPerSample;
+  int dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PresentationPosition.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PresentationPosition.aidl
new file mode 100644
index 0000000..7e997e8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/PresentationPosition.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable PresentationPosition {
+  long remoteDeviceAudioDelayNanos;
+  long transmittedOctets;
+  android.hardware.bluetooth.audio.PresentationPosition.TimeSpec transmittedOctetsTimestamp;
+  @VintfStability
+  parcelable TimeSpec {
+    long tvSec;
+    long tvNSec;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
new file mode 100644
index 0000000..9cf65d5
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SbcAllocMethod {
+  ALLOC_MD_S,
+  ALLOC_MD_L,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcCapabilities.aidl
new file mode 100644
index 0000000..c8d7e7e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcCapabilities.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable SbcCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.SbcChannelMode[] channelMode;
+  byte[] blockLength;
+  byte[] numSubbands;
+  android.hardware.bluetooth.audio.SbcAllocMethod[] allocMethod;
+  byte[] bitsPerSample;
+  int minBitpool;
+  int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcChannelMode.aidl
new file mode 100644
index 0000000..7779aa0
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SbcChannelMode {
+  UNKNOWN,
+  JOINT_STEREO,
+  STEREO,
+  DUAL,
+  MONO,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcConfiguration.aidl
new file mode 100644
index 0000000..8eab9c3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SbcConfiguration.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable SbcConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.SbcChannelMode channelMode;
+  byte blockLength;
+  byte numSubbands;
+  android.hardware.bluetooth.audio.SbcAllocMethod allocMethod;
+  byte bitsPerSample;
+  int minBitpool;
+  int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SessionType.aidl
new file mode 100644
index 0000000..4b2c10f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/SessionType.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SessionType {
+  UNKNOWN,
+  A2DP_SOFTWARE_ENCODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  A2DP_SOFTWARE_DECODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/UnicastCapability.aidl
new file mode 100644
index 0000000..894a2f3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/3/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable UnicastCapability {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.AudioLocation supportedChannel;
+  int deviceCount;
+  int channelCountPerDevice;
+  android.hardware.bluetooth.audio.UnicastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union LeAudioCodecCapabilities {
+    android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+    android.hardware.bluetooth.audio.UnicastCapability.VendorCapabilities vendorCapabillities;
+    android.hardware.bluetooth.audio.AptxAdaptiveLeCapabilities aptxAdaptiveLeCapabilities;
+  }
+}
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index 3e6953f..fa85fa8 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -16,7 +16,7 @@
     tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     static_libs: [
-        "android.hardware.audio.common-V1-ndk",
+        "android.hardware.audio.common-V2-ndk",
         "android.hardware.bluetooth.audio-V3-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 2cba61e..a09e7fe 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -36,6 +36,7 @@
 cc_library_shared {
     name: "libbluetooth_audio_session_aidl",
     vendor: true,
+    host_supported: true,
     srcs: [
         "aidl_session/BluetoothAudioCodecs.cpp",
         "aidl_session/BluetoothAudioSession.cpp",
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 2b0caad..1777f77 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_manager.h>
+#include <hardware/audio.h>
 
 #include "BluetoothAudioSession.h"
 
@@ -502,6 +503,16 @@
 void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   low_latency_allowed_ = allowed;
+  // TODO(b/294498919): Remove this after there is API to update latency mode
+  // after audio session started. If low_latency_allowed_ is true, the session
+  // can support LOW_LATENCY and FREE LatencyMode.
+  if (low_latency_allowed_) {
+    if (std::find(latency_modes_.begin(), latency_modes_.end(),
+                  LatencyMode::LOW_LATENCY) == latency_modes_.end()) {
+      LOG(INFO) << __func__ << " - insert LOW_LATENCY LatencyMode";
+      latency_modes_.push_back(LatencyMode::LOW_LATENCY);
+    }
+  }
   if (observers_.empty()) {
     LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
                  << " has NO port state observer";
@@ -538,23 +549,9 @@
 
 void BluetoothAudioSession::UpdateSourceMetadata(
     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_ENCODING_DATAPATH ||
-      session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
-      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return;
-  }
-
   SourceMetadata hal_source_metadata;
   hal_source_metadata.tracks.resize(track_count);
   for (int i = 0; i < track_count; i++) {
@@ -571,33 +568,14 @@
                  << toString(hal_source_metadata.tracks[i].contentType)
                  << ", gain=" << hal_source_metadata.tracks[i].gain;
   }
-
-  auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_) << " failed";
-  }
+  UpdateSourceMetadata(hal_source_metadata);
 }
 
 void BluetoothAudioSession::UpdateSinkMetadata(
     const struct sink_metadata& sink_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 = sink_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_ENCODING_DATAPATH ||
-      session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
-      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return;
-  }
-
   SinkMetadata hal_sink_metadata;
   hal_sink_metadata.tracks.resize(track_count);
   for (int i = 0; i < track_count; i++) {
@@ -612,12 +590,57 @@
               << ", dest_device_address="
               << sink_metadata.tracks[i].dest_device_address;
   }
+  UpdateSinkMetadata(hal_sink_metadata);
+}
+
+bool BluetoothAudioSession::UpdateSourceMetadata(
+    const SourceMetadata& hal_source_metadata) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+
+  if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return false;
+  }
+
+  auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+bool BluetoothAudioSession::UpdateSinkMetadata(
+    const SinkMetadata& hal_sink_metadata) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+
+  if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return false;
+  }
 
   auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
   if (!hal_retval.isOk()) {
     LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
                  << toString(session_type_) << " failed";
+    return false;
   }
+  return true;
 }
 
 std::vector<LatencyMode> BluetoothAudioSession::GetSupportedLatencyModes() {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
index faf4ffb..25c676a 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -23,12 +23,15 @@
 #include <aidl/android/hardware/bluetooth/audio/LatencyMode.h>
 #include <aidl/android/hardware/bluetooth/audio/SessionType.h>
 #include <fmq/AidlMessageQueue.h>
-#include <hardware/audio.h>
 
 #include <mutex>
 #include <unordered_map>
 #include <vector>
 
+// To avoid inclusion of hardware/audio.h
+struct sink_metadata;
+struct source_metadata;
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -196,6 +199,9 @@
   bool GetPresentationPosition(PresentationPosition& presentation_position);
   void UpdateSourceMetadata(const struct source_metadata& source_metadata);
   void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
+  // New versions for AIDL-only clients.
+  bool UpdateSourceMetadata(const SourceMetadata& hal_source_metadata);
+  bool UpdateSinkMetadata(const SinkMetadata& hal_sink_metadata);
 
   std::vector<LatencyMode> GetSupportedLatencyModes();
   void SetLatencyMode(const LatencyMode& latency_mode);
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 881c6c1..6c60a3b 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -175,6 +175,26 @@
     }
   }
 
+  static bool UpdateSourceMetadata(const SessionType& session_type,
+                                   const SourceMetadata& source_metadata) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->UpdateSourceMetadata(source_metadata);
+    }
+    return false;
+  }
+
+  static bool UpdateSinkMetadata(const SessionType& session_type,
+                                 const SinkMetadata& sink_metadata) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->UpdateSinkMetadata(sink_metadata);
+    }
+    return false;
+  }
+
   static std::vector<LatencyMode> GetSupportedLatencyModes(
       const SessionType& session_type) {
     std::shared_ptr<BluetoothAudioSession> session_ptr =
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
index a4664f1..3d92ee7 100644
--- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -583,7 +583,7 @@
     *total_bytes_readed = presentation_position.transmittedOctets;
   if (data_position)
     *data_position = {
-        .tv_sec = static_cast<__kernel_old_time_t>(
+        .tv_sec = static_cast<long>(
             presentation_position.transmittedOctetsTimestamp.tvSec),
         .tv_nsec = static_cast<long>(
             presentation_position.transmittedOctetsTimestamp.tvNSec)};
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
index 622ee8f..1a08ebc 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
@@ -5,5 +5,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc
index 5df4825..a65160a 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc
@@ -2,5 +2,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
index 0721dc3..9fca8fd 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -6,5 +6,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc
index 132d943..19fd031 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc
@@ -2,5 +2,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
index d91fdce..8c2a894 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -7,5 +7,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
index b22971a..4b638bc 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -2,5 +2,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/Android.bp b/cas/aidl/default/Android.bp
old mode 100755
new mode 100644
index 3c16d57..6ce5681
--- a/cas/aidl/default/Android.bp
+++ b/cas/aidl/default/Android.bp
@@ -68,6 +68,7 @@
     defaults: ["cas_service_example_defaults"],
     init_rc: ["cas-default-lazy.rc"],
     cflags: ["-DLAZY_SERVICE"],
+    overrides: ["android.hardware.cas-service.example"],
 }
 
 cc_fuzz {
diff --git a/cas/aidl/default/CasImpl.cpp b/cas/aidl/default/CasImpl.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/CasImpl.h b/cas/aidl/default/CasImpl.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/DescramblerImpl.cpp b/cas/aidl/default/DescramblerImpl.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/DescramblerImpl.h b/cas/aidl/default/DescramblerImpl.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/FactoryLoader.h b/cas/aidl/default/FactoryLoader.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/MediaCasService.cpp b/cas/aidl/default/MediaCasService.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/MediaCasService.h b/cas/aidl/default/MediaCasService.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/SharedLibrary.cpp b/cas/aidl/default/SharedLibrary.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/SharedLibrary.h b/cas/aidl/default/SharedLibrary.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/TypeConvert.cpp b/cas/aidl/default/TypeConvert.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/TypeConvert.h b/cas/aidl/default/TypeConvert.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/android.hardware.cas-service.xml b/cas/aidl/default/android.hardware.cas-service.xml
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/cas-default-lazy.rc b/cas/aidl/default/cas-default-lazy.rc
old mode 100755
new mode 100644
index 60b59ca..7321cf0
--- a/cas/aidl/default/cas-default-lazy.rc
+++ b/cas/aidl/default/cas-default-lazy.rc
@@ -3,6 +3,7 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
     oneshot
diff --git a/cas/aidl/default/cas-default.rc b/cas/aidl/default/cas-default.rc
old mode 100755
new mode 100644
index e00b9c5..5a60368
--- a/cas/aidl/default/cas-default.rc
+++ b/cas/aidl/default/cas-default.rc
@@ -3,5 +3,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/fuzzer.cpp b/cas/aidl/default/fuzzer.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/service.cpp b/cas/aidl/default/service.cpp
old mode 100755
new mode 100644
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 40ceb32..148c63c 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -33,6 +33,7 @@
             apex_available: [
                 "//apex_available:platform",
                 "com.android.btservices",
+                "com.android.media.swcodec",
             ],
             min_sdk_version: "29",
         },
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index b9fb3f4..bb7637a 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -281,9 +281,15 @@
         <version>1.0</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.media.omx</name>
@@ -361,6 +367,7 @@
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index b374c8c..dad1558 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -319,11 +319,21 @@
         <version>1.0-1</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -399,6 +409,7 @@
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
index 40ae655..23f634d 100644
--- a/compatibility_matrices/compatibility_matrix.6.xml
+++ b/compatibility_matrices/compatibility_matrix.6.xml
@@ -368,11 +368,21 @@
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -454,6 +464,7 @@
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml
index e5ef954..14c330e 100644
--- a/compatibility_matrices/compatibility_matrix.7.xml
+++ b/compatibility_matrices/compatibility_matrix.7.xml
@@ -43,6 +43,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
+        <version>1-2</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
@@ -262,22 +263,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.visibility_control</name>
-        <version>1</version>
-        <interface>
-            <name>IGnssVisibilityControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.measurement_corrections</name>
-        <version>1</version>
-        <interface>
-            <name>IMeasurementCorrectionsInterface</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0 or the AIDL hal. -->
@@ -430,11 +415,21 @@
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -582,6 +577,7 @@
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 1c2cd50..69a3d4c 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -60,16 +60,9 @@
              <instance>default</instance>
          </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.authsecret</name>
-        <version>1.0</version>
-        <interface>
-            <name>IAuthSecret</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
+        <version>2</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
@@ -277,22 +270,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.visibility_control</name>
-        <version>1</version>
-        <interface>
-            <name>IGnssVisibilityControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.measurement_corrections</name>
-        <version>1</version>
-        <interface>
-            <name>IMeasurementCorrectionsInterface</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
          If the HIDL composer HAL exists, it must be at least version 2.0.
          See DeviceManifestTest.GrallocHal -->
@@ -433,10 +410,20 @@
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.media.c2</name>
         <version>1</version>
@@ -585,6 +572,7 @@
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 60bb2ab..9af095f 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -52,7 +52,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -70,6 +70,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
+        <version>2</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
@@ -269,22 +270,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.visibility_control</name>
-        <version>1</version>
-        <interface>
-            <name>IGnssVisibilityControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.measurement_corrections</name>
-        <version>1</version>
-        <interface>
-            <name>IMeasurementCorrectionsInterface</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
          If the HIDL composer HAL exists, it must be at least version 2.0.
          See DeviceManifestTest.GrallocHal -->
@@ -330,9 +315,6 @@
     <!-- Either the native or the HIDL mapper HAL must exist on the device -->
     <hal format="hidl" optional="true">
         <name>android.hardware.graphics.mapper</name>
-        <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
-        <version>2.1</version>
-        <version>3.0</version>
         <version>4.0</version>
         <interface>
             <name>IMapper</name>
@@ -394,7 +376,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
         <interface>
@@ -403,7 +385,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
         <interface>
@@ -425,10 +407,20 @@
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.media.c2</name>
         <version>1</version>
@@ -577,6 +569,7 @@
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
@@ -596,7 +589,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
         <interface>
@@ -604,7 +597,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.sharedsecret</name>
         <version>1</version>
         <interface>
@@ -741,7 +734,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.weaver</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IWeaver</name>
             <instance>default</instance>
@@ -763,7 +756,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.uwb</name>
         <version>1</version>
         <interface>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index b17c0e2..d92c0b9 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -23,9 +24,7 @@
 namespace android::vintf::details {
 
 // The predicate to VintfObject::checkMissingHalsInMatrices.
-bool ShouldCheckMissingHalsInFcm(const std::string& package) {
-    using std::placeholders::_1;
-
+bool ShouldCheckMissingHidlHalsInFcm(const std::string& packageAndVersion) {
     static std::vector<std::string> included_prefixes{
             // Other AOSP HALs (e.g. android.frameworks.*) are not added because only framework
             // matrix is checked.
@@ -50,28 +49,11 @@
             "android.hardware.media.bufferpool@1.0",
             "android.hardware.media.bufferpool@2.0",
             "android.hardware.radio.config@1.2",
-            // AIDL
-            "android.hardware.audio.common",
-            "android.hardware.audio.core.sounddose",
-            "android.hardware.biometrics.common",
-            "android.hardware.camera.metadata",
-            "android.hardware.camera.device",
-            "android.hardware.camera.common",
-            "android.hardware.common",
-            "android.hardware.common.fmq",
-            "android.hardware.graphics.common",
-            "android.hardware.input.common",
-            "android.hardware.keymaster",
-            "android.hardware.media.bufferpool2",
-            "android.hardware.radio",
-            "android.hardware.uwb.fira_android",
 
             // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
             // does not depend on this HAL, hence it is not declared in any manifests or matrices.
             "android.hardware.fastboot@1.0",
             "android.hardware.fastboot@1.1",
-            // Fastboot AIDL
-            "android.hardware.fastboot",
 
             // Deprecated HALs.
             // HIDL
@@ -105,7 +87,7 @@
     };
 
     auto package_has_prefix = [&](const std::string& prefix) {
-        return android::base::StartsWith(package, prefix);
+        return android::base::StartsWith(packageAndVersion, prefix);
     };
 
     // Only check packageAndVersions that are in the include list and not in the exclude list.
@@ -113,7 +95,69 @@
         return false;
     }
 
-    if (std::find(excluded_exact.begin(), excluded_exact.end(), package) != excluded_exact.end()) {
+    if (std::find(excluded_exact.begin(), excluded_exact.end(), packageAndVersion) !=
+        excluded_exact.end()) {
+        return false;
+    }
+
+    return !std::any_of(excluded_prefixes.begin(), excluded_prefixes.end(), package_has_prefix);
+}
+
+// The predicate to VintfObject::checkMissingHalsInMatrices.
+bool ShouldCheckMissingAidlHalsInFcm(const std::string& packageAndVersion) {
+    static std::vector<std::string> included_prefixes{
+            // Other AOSP HALs (e.g. android.frameworks.*) are not added because only framework
+            // matrix is checked.
+            "android.hardware.",
+    };
+
+    static std::vector<std::string> excluded_prefixes{
+            // Packages without top level interfaces (including types-only packages) are exempted.
+            "android.hardware.audio.common@",
+            "android.hardware.biometrics.common@",
+            "android.hardware.camera.metadata@",
+            "android.hardware.camera.device@",
+            "android.hardware.camera.common@",
+            "android.hardware.common@",
+            "android.hardware.common.fmq@",
+            "android.hardware.gnss.measurement_corrections@",
+            "android.hardware.gnss.visibility_control@",
+            "android.hardware.graphics.common@",
+            "android.hardware.input.common@",
+            "android.hardware.keymaster@",
+            "android.hardware.media.bufferpool2@",
+            "android.hardware.radio@",
+            "android.hardware.uwb.fira_android@",
+
+            // Test packages are exempted.
+            "android.hardware.tests.",
+
+            // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
+            // does not depend on this HAL, hence it is not declared in any manifests or matrices.
+            "android.hardware.fastboot@",
+    };
+
+    static std::vector<std::string> excluded_exact{
+            // Packages without top level interfaces (including types-only packages) are exempted.
+
+            // AIDL
+            "android.hardware.audio.core.sounddose@1",
+
+            // Deprecated HALs.
+            "android.hardware.bluetooth.audio@1",
+    };
+
+    auto package_has_prefix = [&](const std::string& prefix) {
+        return android::base::StartsWith(packageAndVersion, prefix);
+    };
+
+    // Only check packageAndVersions that are in the include list and not in the exclude list.
+    if (!std::any_of(included_prefixes.begin(), included_prefixes.end(), package_has_prefix)) {
+        return false;
+    }
+
+    if (std::find(excluded_exact.begin(), excluded_exact.end(), packageAndVersion) !=
+        excluded_exact.end()) {
         return false;
     }
 
diff --git a/compatibility_matrices/exclude/include/vintf/fcm_exclude.h b/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
index f74c217..e7ef4a0 100644
--- a/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
+++ b/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
@@ -24,7 +24,8 @@
 // Determine whether VINTF checks |package| is missing from FCMs.
 // |package| can be a HIDL package and version like
 // "android.hardware.foo@1.0", or an AIDL package name like
-// "android.hardware.foo".
-bool ShouldCheckMissingHalsInFcm(const std::string& package);
+// "android.hardware.foo@1".
+bool ShouldCheckMissingHidlHalsInFcm(const std::string& packageAndVersion);
+bool ShouldCheckMissingAidlHalsInFcm(const std::string& packageAndVersion);
 
 }  // namespace android::vintf::details
diff --git a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
index c89243b..032f7e2 100644
--- a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
+++ b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
@@ -221,6 +221,47 @@
 }
 
 /**
+ * Ensure that passwords containing a NUL byte aren't truncated
+ */
+TEST_P(GatekeeperAidlTest, PasswordIsBinaryData) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    std::vector<uint8_t> rightPassword = {'A', 'B', 'C', '\0', 'D', 'E', 'F'};
+    std::vector<uint8_t> wrongPassword = {'A', 'B', 'C', '\0', '\0', '\0', '\0'};
+
+    ALOGI("Testing Enroll+Verify of password with embedded NUL (expected success)");
+    enrollNewPassword(rightPassword, enrollRsp, true);
+    verifyPassword(rightPassword, enrollRsp.data, 1, verifyRsp, true);
+
+    ALOGI("Testing Verify of wrong password (expected failure)");
+    verifyPassword(wrongPassword, enrollRsp.data, 1, verifyRsp, false);
+
+    ALOGI("PasswordIsBinaryData test done");
+}
+
+/**
+ * Ensure that long passwords aren't truncated
+ */
+TEST_P(GatekeeperAidlTest, LongPassword) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    std::vector<uint8_t> password;
+
+    password.resize(64);  // maximum length used by Android
+    memset(password.data(), 'A', password.size());
+
+    ALOGI("Testing Enroll+Verify of long password (expected success)");
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+    ALOGI("Testing Verify of wrong password (expected failure)");
+    password[password.size() - 1] ^= 1;
+    verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
+
+    ALOGI("LongPassword test done");
+}
+
+/**
  * Ensure we can securely update password (keep the same
  * secure user_id) if we prove we know old password
  */
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
index ba6fe97..18b219c 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
@@ -40,14 +40,12 @@
     /**
      * The stage in which dimming operations should be performed when compositing
      * the client target.
+     *
      * Note that with a COLORIMETRIC RenderIntent, DimmingSpace must be LINEAR. That is, dimming
-     * is defined to occur in linear space.
-     * However, some composer implementations may, with other vendor-defined RenderIntents,
-     * configure their hardware such as image quality adjustments is intended to occur after
-     * composition. In this scenario, if the dimming operation were applied in linear space,
-     * then the resulting dimming operation may comepl those image quality adjustments to
-     * incorrectly alter the gamma curve. To avoid this issue, those implementations must opt to
-     * dim in gamma space.
+     * is defined to occur in linear space. However, some composer implementations may, with
+     * other vendor-defined RenderIntents, apply certain image quality adjustments that are
+     * sensitive to gamma shift when dimming in linear space. To avoid this issue, those
+     * implementations must opt to dim in gamma space.
      */
     DimmingStage dimmingStage;
 }
diff --git a/health/utils/libhealthloop/include/health/HealthLoop.h b/health/utils/libhealthloop/include/health/HealthLoop.h
index 54b2740..fc3066e 100644
--- a/health/utils/libhealthloop/include/health/HealthLoop.h
+++ b/health/utils/libhealthloop/include/health/HealthLoop.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <vector>
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 5ea2948..b01cdbe 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -40,6 +40,11 @@
         },
         ndk: {
             enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media.swcodec",
+            ],
+            min_sdk_version: "29",
         },
     },
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
index 54896d4..5899a40 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -34,5 +34,10 @@
 package android.hardware.media.bufferpool2;
 @VintfStability
 interface IClientManager {
-  long registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+  android.hardware.media.bufferpool2.IClientManager.Registration registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+  @VintfStability
+  parcelable Registration {
+    long connectionId;
+    boolean isNew = true;
+  }
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
index 300fcba..844e920 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
@@ -35,12 +35,13 @@
 @VintfStability
 interface IConnection {
   android.hardware.media.bufferpool2.IConnection.FetchResult[] fetch(in android.hardware.media.bufferpool2.IConnection.FetchInfo[] fetchInfos);
+  void sync();
   parcelable FetchInfo {
     long transactionId;
     int bufferId;
   }
   union FetchResult {
     android.hardware.media.bufferpool2.Buffer buffer;
-    android.hardware.media.bufferpool2.ResultStatus failure;
+    int failure;
   }
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
index 7370998..4bc3889 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
@@ -34,7 +34,6 @@
 package android.hardware.media.bufferpool2;
 @VintfStability
 parcelable ResultStatus {
-  int resultStatus;
   const int OK = 0;
   const int NO_MEMORY = 1;
   const int ALREADY_EXISTS = 2;
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
index bf36e25..a3054cb 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -28,6 +28,16 @@
 @VintfStability
 interface IClientManager {
     /**
+     * Result of registerSender.
+     */
+    @VintfStability
+    parcelable Registration {
+        /** registered connection id    */
+        long connectionId;
+        /** true when the connection is new */
+        boolean isNew = true;
+    }
+    /**
      * Sets up a buffer receiving communication node for the specified
      * buffer pool. A manager must create a IConnection to the buffer
      * pool if it does not already have a connection.
@@ -39,8 +49,7 @@
      *     sent to that connection during transfers.
      * @throws ServiceSpecificException with one of the following values:
      *     ResultStatus::NO_MEMORY        - Memory allocation failure occurred.
-     *     ResultStatus::ALREADY_EXISTS   - A sender was registered already.
      *     ResultStatus::CRITICAL_ERROR   - Other errors.
      */
-    long registerSender(in IAccessor bufferPool);
+    Registration registerSender(in IAccessor bufferPool);
 }
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
index d869f47..68367c7 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
@@ -49,7 +49,7 @@
          * ResultStatus::NOT_FOUND        - A buffer was not found due to invalidation.
          * ResultStatus::CRITICAL_ERROR   - Other errors.
          */
-        ResultStatus failure;
+        int failure;
     }
 
     /**
@@ -70,4 +70,12 @@
      *     ResultStatus::CRITICAL_ERROR   - Other errors.
      */
     FetchResult[] fetch(in FetchInfo[] fetchInfos);
+
+    /**
+     * Enforce processing of unprocessed bufferpool messages.
+     *
+     * BufferPool implementation optimizes message processing by piggy-backing approach.
+     * This method can ensure pending bufferpool messages being processed timely.
+     */
+    void sync();
 }
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
index 162f9a7..003d147 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
@@ -23,6 +23,4 @@
     const int ALREADY_EXISTS = 2;
     const int NOT_FOUND = 3;
     const int CRITICAL_ERROR = 4;
-
-    int resultStatus;
 }
diff --git a/media/bufferpool/aidl/default/Accessor.cpp b/media/bufferpool/aidl/default/Accessor.cpp
new file mode 100644
index 0000000..3d206ac
--- /dev/null
+++ b/media/bufferpool/aidl/default/Accessor.cpp
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolAcc"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <thread>
+
+#include "Accessor.h"
+#include "Connection.h"
+#include "DataHelper.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+namespace {
+    static constexpr nsecs_t kEvictGranularityNs = 1000000000; // 1 sec
+    static constexpr nsecs_t kEvictDurationNs = 5000000000; // 5 secs
+}
+
+#ifdef __ANDROID_VNDK__
+static constexpr uint32_t kSeqIdVndkBit = 1U << 31;
+#else
+static constexpr uint32_t kSeqIdVndkBit = 0;
+#endif
+
+static constexpr uint32_t kSeqIdMax = 0x7fffffff;
+uint32_t Accessor::sSeqId = time(nullptr) & kSeqIdMax;
+
+namespace {
+// anonymous namespace
+static std::shared_ptr<ConnectionDeathRecipient> sConnectionDeathRecipient =
+    std::make_shared<ConnectionDeathRecipient>();
+
+void serviceDied(void *cookie) {
+    if (sConnectionDeathRecipient) {
+        sConnectionDeathRecipient->onDead(cookie);
+    }
+}
+}
+
+std::shared_ptr<ConnectionDeathRecipient> Accessor::getConnectionDeathRecipient() {
+    return sConnectionDeathRecipient;
+}
+
+ConnectionDeathRecipient::ConnectionDeathRecipient() {
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(serviceDied));
+}
+
+void ConnectionDeathRecipient::add(
+        int64_t connectionId,
+        const std::shared_ptr<Accessor> &accessor) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mAccessors.find(connectionId) == mAccessors.end()) {
+        mAccessors.insert(std::make_pair(connectionId, accessor));
+    }
+}
+
+void ConnectionDeathRecipient::remove(int64_t connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mAccessors.erase(connectionId);
+    auto it = mConnectionToCookie.find(connectionId);
+    if (it != mConnectionToCookie.end()) {
+        void * cookie = it->second;
+        mConnectionToCookie.erase(it);
+        auto cit = mCookieToConnections.find(cookie);
+        if (cit != mCookieToConnections.end()) {
+            cit->second.erase(connectionId);
+            if (cit->second.size() == 0) {
+                mCookieToConnections.erase(cit);
+            }
+        }
+    }
+}
+
+void ConnectionDeathRecipient::addCookieToConnection(
+        void *cookie,
+        int64_t connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mAccessors.find(connectionId) == mAccessors.end()) {
+        return;
+    }
+    mConnectionToCookie.insert(std::make_pair(connectionId, cookie));
+    auto it = mCookieToConnections.find(cookie);
+    if (it != mCookieToConnections.end()) {
+        it->second.insert(connectionId);
+    } else {
+        mCookieToConnections.insert(std::make_pair(
+                cookie, std::set<int64_t>{connectionId}));
+    }
+}
+
+void ConnectionDeathRecipient::onDead(void *cookie) {
+    std::map<int64_t, const std::weak_ptr<Accessor>> connectionsToClose;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        auto it = mCookieToConnections.find(cookie);
+        if (it != mCookieToConnections.end()) {
+            for (auto conIt = it->second.begin(); conIt != it->second.end(); ++conIt) {
+                auto accessorIt = mAccessors.find(*conIt);
+                if (accessorIt != mAccessors.end()) {
+                    connectionsToClose.insert(std::make_pair(*conIt, accessorIt->second));
+                    mAccessors.erase(accessorIt);
+                }
+                mConnectionToCookie.erase(*conIt);
+            }
+            mCookieToConnections.erase(it);
+        }
+    }
+
+    if (connectionsToClose.size() > 0) {
+        std::shared_ptr<Accessor> accessor;
+        for (auto it = connectionsToClose.begin(); it != connectionsToClose.end(); ++it) {
+            accessor = it->second.lock();
+
+            if (accessor) {
+                accessor->close(it->first);
+                ALOGD("connection %lld closed on death", (long long)it->first);
+            }
+        }
+    }
+}
+
+AIBinder_DeathRecipient *ConnectionDeathRecipient::getRecipient() {
+    return mDeathRecipient.get();
+}
+
+::ndk::ScopedAStatus Accessor::connect(const std::shared_ptr<::aidl::android::hardware::media::bufferpool2::IObserver>& in_observer, ::aidl::android::hardware::media::bufferpool2::IAccessor::ConnectionInfo* _aidl_return) {
+    std::shared_ptr<Connection> connection;
+    ConnectionId connectionId;
+    uint32_t msgId;
+    StatusDescriptor statusDesc;
+    InvalidationDescriptor invDesc;
+    BufferPoolStatus status = connect(
+            in_observer, false, &connection, &connectionId, &msgId, &statusDesc, &invDesc);
+    if (status == ResultStatus::OK) {
+        _aidl_return->connection = connection;
+        _aidl_return->connectionId = connectionId;
+        _aidl_return->msgId = msgId;
+        _aidl_return->toFmqDesc = std::move(statusDesc);
+        _aidl_return->fromFmqDesc = std::move(invDesc);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
+}
+
+Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
+    : mAllocator(allocator), mScheduleEvictTs(0) {}
+
+Accessor::~Accessor() {
+}
+
+bool Accessor::isValid() {
+    return mBufferPool.isValid();
+}
+
+BufferPoolStatus Accessor::flush() {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.flush(ref<Accessor>());
+    return ResultStatus::OK;
+}
+
+BufferPoolStatus Accessor::allocate(
+        ConnectionId connectionId,
+        const std::vector<uint8_t> &params,
+        BufferId *bufferId, const native_handle_t** handle) {
+    std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    BufferPoolStatus status = ResultStatus::OK;
+    if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
+        lock.unlock();
+        std::shared_ptr<BufferPoolAllocation> alloc;
+        size_t allocSize;
+        status = mAllocator->allocate(params, &alloc, &allocSize);
+        lock.lock();
+        if (status == ResultStatus::OK) {
+            status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
+        }
+        ALOGV("create a buffer %d : %u %p",
+              status == ResultStatus::OK, *bufferId, *handle);
+    }
+    if (status == ResultStatus::OK) {
+        // TODO: handle ownBuffer failure
+        mBufferPool.handleOwnBuffer(connectionId, *bufferId);
+    }
+    mBufferPool.cleanUp();
+    scheduleEvictIfNeeded();
+    return status;
+}
+
+BufferPoolStatus Accessor::fetch(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, const native_handle_t** handle) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    auto found = mBufferPool.mTransactions.find(transactionId);
+    if (found != mBufferPool.mTransactions.end() &&
+            contains(&mBufferPool.mPendingTransactions,
+                     connectionId, transactionId)) {
+        if (found->second->mSenderValidated &&
+                found->second->mStatus == BufferStatus::TRANSFER_FROM &&
+                found->second->mBufferId == bufferId) {
+            found->second->mStatus = BufferStatus::TRANSFER_FETCH;
+            auto bufferIt = mBufferPool.mBuffers.find(bufferId);
+            if (bufferIt != mBufferPool.mBuffers.end()) {
+                mBufferPool.mStats.onBufferFetched();
+                *handle = bufferIt->second->handle();
+                return ResultStatus::OK;
+            }
+        }
+    }
+    mBufferPool.cleanUp();
+    scheduleEvictIfNeeded();
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus Accessor::connect(
+        const std::shared_ptr<IObserver> &observer, bool local,
+        std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
+        uint32_t *pMsgId,
+        StatusDescriptor* statusDescPtr,
+        InvalidationDescriptor* invDescPtr) {
+    std::shared_ptr<Connection> newConnection = ::ndk::SharedRefBase::make<Connection>();
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        if (newConnection) {
+            int32_t pid = getpid();
+            ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
+            status = mBufferPool.mObserver.open(id, statusDescPtr);
+            if (status == ResultStatus::OK) {
+                newConnection->initialize(ref<Accessor>(), id);
+                *connection = newConnection;
+                *pConnectionId = id;
+                *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+                mBufferPool.mConnectionIds.insert(id);
+                mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
+                mBufferPool.mInvalidation.onConnect(id, observer);
+                if (sSeqId == kSeqIdMax) {
+                   sSeqId = 0;
+                } else {
+                    ++sSeqId;
+                }
+            }
+
+        }
+        mBufferPool.processStatusMessages();
+        mBufferPool.cleanUp();
+        scheduleEvictIfNeeded();
+    }
+    if (!local && status == ResultStatus::OK) {
+        std::shared_ptr<Accessor> accessor(ref<Accessor>());
+        sConnectionDeathRecipient->add(*pConnectionId, accessor);
+    }
+    return status;
+}
+
+BufferPoolStatus Accessor::close(ConnectionId connectionId) {
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        ALOGV("connection close %lld: %u", (long long)connectionId, mBufferPool.mInvalidation.mId);
+        mBufferPool.processStatusMessages();
+        mBufferPool.handleClose(connectionId);
+        mBufferPool.mObserver.close(connectionId);
+        mBufferPool.mInvalidation.onClose(connectionId);
+        // Since close# will be called after all works are finished, it is OK to
+        // evict unused buffers.
+        mBufferPool.cleanUp(true);
+        scheduleEvictIfNeeded();
+    }
+    sConnectionDeathRecipient->remove(connectionId);
+    return ResultStatus::OK;
+}
+
+void Accessor::cleanUp(bool clearCache) {
+    // transaction timeout, buffer caching TTL handling
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.cleanUp(clearCache);
+}
+
+void Accessor::handleInvalidateAck() {
+    std::map<ConnectionId, const std::shared_ptr<IObserver>> observers;
+    uint32_t invalidationId;
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        mBufferPool.processStatusMessages();
+        mBufferPool.mInvalidation.onHandleAck(&observers, &invalidationId);
+    }
+    // Do not hold lock for send invalidations
+    size_t deadClients = 0;
+    for (auto it = observers.begin(); it != observers.end(); ++it) {
+        const std::shared_ptr<IObserver> observer = it->second;
+        if (observer) {
+            ::ndk::ScopedAStatus status = observer->onMessage(it->first, invalidationId);
+            if (!status.isOk()) {
+                ++deadClients;
+            }
+        }
+    }
+    if (deadClients > 0) {
+        ALOGD("During invalidation found %zu dead clients", deadClients);
+    }
+}
+
+void Accessor::invalidatorThread(
+            std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
+            std::mutex &mutex,
+            std::condition_variable &cv,
+            bool &ready) {
+    constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
+    constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
+    constexpr useconds_t MAX_SLEEP_US = 10000;
+    uint32_t numSpin = 0;
+    useconds_t sleepUs = 1;
+
+    while(true) {
+        std::map<uint32_t, const std::weak_ptr<Accessor>> copied;
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            while (!ready) {
+                numSpin = 0;
+                sleepUs = 1;
+                cv.wait(lock);
+            }
+            copied.insert(accessors.begin(), accessors.end());
+        }
+        std::list<ConnectionId> erased;
+        for (auto it = copied.begin(); it != copied.end(); ++it) {
+            const std::shared_ptr<Accessor> acc = it->second.lock();
+            if (!acc) {
+                erased.push_back(it->first);
+            } else {
+                acc->handleInvalidateAck();
+            }
+        }
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            for (auto it = erased.begin(); it != erased.end(); ++it) {
+                accessors.erase(*it);
+            }
+            if (accessors.size() == 0) {
+                ready = false;
+            } else {
+                // N.B. Since there is not a efficient way to wait over FMQ,
+                // polling over the FMQ is the current way to prevent draining
+                // CPU.
+                lock.unlock();
+                ++numSpin;
+                if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
+                    sleepUs < MAX_SLEEP_US) {
+                    sleepUs *= 10;
+                }
+                if (numSpin % NUM_SPIN_TO_LOG == 0) {
+                    ALOGW("invalidator thread spinning");
+                }
+                ::usleep(sleepUs);
+            }
+        }
+    }
+}
+
+Accessor::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
+    std::thread invalidator(
+            invalidatorThread,
+            std::ref(mAccessors),
+            std::ref(mMutex),
+            std::ref(mCv),
+            std::ref(mReady));
+    invalidator.detach();
+}
+
+void Accessor::AccessorInvalidator::addAccessor(
+        uint32_t accessorId, const std::weak_ptr<Accessor> &accessor) {
+    bool notify = false;
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (mAccessors.find(accessorId) == mAccessors.end()) {
+        if (!mReady) {
+            mReady = true;
+            notify = true;
+        }
+        mAccessors.emplace(accessorId, accessor);
+        ALOGV("buffer invalidation added bp:%u %d", accessorId, notify);
+    }
+    lock.unlock();
+    if (notify) {
+        mCv.notify_one();
+    }
+}
+
+void Accessor::AccessorInvalidator::delAccessor(uint32_t accessorId) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mAccessors.erase(accessorId);
+    ALOGV("buffer invalidation deleted bp:%u", accessorId);
+    if (mAccessors.size() == 0) {
+        mReady = false;
+    }
+}
+
+std::unique_ptr<Accessor::AccessorInvalidator> Accessor::sInvalidator;
+
+void Accessor::createInvalidator() {
+    if (!sInvalidator) {
+        sInvalidator = std::make_unique<Accessor::AccessorInvalidator>();
+    }
+}
+
+void Accessor::evictorThread(
+        std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv) {
+    std::list<const std::weak_ptr<Accessor>> evictList;
+    while (true) {
+        int expired = 0;
+        int evicted = 0;
+        {
+            nsecs_t now = systemTime();
+            std::unique_lock<std::mutex> lock(mutex);
+            while (accessors.size() == 0) {
+                cv.wait(lock);
+            }
+            auto it = accessors.begin();
+            while (it != accessors.end()) {
+                if (now > (it->second + kEvictDurationNs)) {
+                    ++expired;
+                    evictList.push_back(it->first);
+                    it = accessors.erase(it);
+                } else {
+                    ++it;
+                }
+            }
+        }
+        // evict idle accessors;
+        for (auto it = evictList.begin(); it != evictList.end(); ++it) {
+            const std::shared_ptr<Accessor> accessor = it->lock();
+            if (accessor) {
+                accessor->cleanUp(true);
+                ++evicted;
+            }
+        }
+        if (expired > 0) {
+            ALOGD("evictor expired: %d, evicted: %d", expired, evicted);
+        }
+        evictList.clear();
+        ::usleep(kEvictGranularityNs / 1000);
+    }
+}
+
+Accessor::AccessorEvictor::AccessorEvictor() {
+    std::thread evictor(
+            evictorThread,
+            std::ref(mAccessors),
+            std::ref(mMutex),
+            std::ref(mCv));
+    evictor.detach();
+}
+
+void Accessor::AccessorEvictor::addAccessor(
+        const std::weak_ptr<Accessor> &accessor, nsecs_t ts) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    bool notify = mAccessors.empty();
+    auto it = mAccessors.find(accessor);
+    if (it == mAccessors.end()) {
+        mAccessors.emplace(accessor, ts);
+    } else {
+        it->second = ts;
+    }
+    if (notify) {
+        mCv.notify_one();
+    }
+}
+
+std::unique_ptr<Accessor::AccessorEvictor> Accessor::sEvictor;
+
+void Accessor::createEvictor() {
+    if (!sEvictor) {
+        sEvictor = std::make_unique<Accessor::AccessorEvictor>();
+    }
+}
+
+void Accessor::scheduleEvictIfNeeded() {
+    nsecs_t now = systemTime();
+
+    if (now > (mScheduleEvictTs + kEvictGranularityNs)) {
+        mScheduleEvictTs = now;
+        sEvictor->addAccessor(ref<Accessor>(), now);
+    }
+}
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implemntation {
diff --git a/media/bufferpool/aidl/default/Accessor.h b/media/bufferpool/aidl/default/Accessor.h
new file mode 100644
index 0000000..85e2fa7
--- /dev/null
+++ b/media/bufferpool/aidl/default/Accessor.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/media/bufferpool2/BnAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/IObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+#include <memory>
+#include <map>
+#include <set>
+#include <condition_variable>
+
+#include "BufferPool.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+struct Connection;
+using ::aidl::android::hardware::media::bufferpool2::IObserver;
+using ::aidl::android::hardware::media::bufferpool2::IAccessor;
+
+/**
+ * Receives death notifications from remote connections.
+ * On death notifications, the connections are closed and used resources
+ * are released.
+ */
+struct ConnectionDeathRecipient {
+    ConnectionDeathRecipient();
+    /**
+     * Registers a newly connected connection from remote processes.
+     */
+    void add(int64_t connectionId, const std::shared_ptr<Accessor> &accessor);
+
+    /**
+     * Removes a connection.
+     */
+    void remove(int64_t connectionId);
+
+    void addCookieToConnection(void *cookie, int64_t connectionId);
+
+    void onDead(void *cookie);
+
+    AIBinder_DeathRecipient *getRecipient();
+
+private:
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    std::mutex mLock;
+    std::map<void *, std::set<int64_t>>  mCookieToConnections;
+    std::map<int64_t, void *> mConnectionToCookie;
+    std::map<int64_t, const std::weak_ptr<Accessor>> mAccessors;
+};
+
+/**
+ * A buffer pool accessor which enables a buffer pool to communicate with buffer
+ * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
+ */
+struct Accessor : public BnAccessor {
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IAccessor.
+    ::ndk::ScopedAStatus connect(const std::shared_ptr<IObserver>& in_observer,
+                                 IAccessor::ConnectionInfo* _aidl_return) override;
+
+    /**
+     * Creates a buffer pool accessor which uses the specified allocator.
+     *
+     * @param allocator buffer allocator.
+     */
+    explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
+
+    /** Destructs a buffer pool accessor. */
+    ~Accessor();
+
+    /** Returns whether the accessor is valid. */
+    bool isValid();
+
+    /** Invalidates all buffers which are owned by bufferpool */
+    BufferPoolStatus flush();
+
+    /** Allocates a buffer from a buffer pool.
+     *
+     * @param connectionId  the connection id of the client.
+     * @param params        the allocation parameters.
+     * @param bufferId      the id of the allocated buffer.
+     * @param handle        the native handle of the allocated buffer.
+     *
+     * @return OK when a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus allocate(
+            ConnectionId connectionId,
+            const std::vector<uint8_t>& params,
+            BufferId *bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Fetches a buffer for the specified transaction.
+     *
+     * @param connectionId  the id of receiving connection(client).
+     * @param transactionId the id of the transfer transaction.
+     * @param bufferId      the id of the buffer to be fetched.
+     * @param handle        the native handle of the fetched buffer.
+     *
+     * @return OK when a buffer is successfully fetched.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus fetch(
+            ConnectionId connectionId,
+            TransactionId transactionId,
+            BufferId bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Makes a connection to the buffer pool. The buffer pool client uses the
+     * created connection in order to communicate with the buffer pool. An
+     * FMQ for buffer status message is also created for the client.
+     *
+     * @param observer      client observer for buffer invalidation
+     * @param local         true when a connection request comes from local process,
+     *                      false otherwise.
+     * @param connection    created connection
+     * @param pConnectionId the id of the created connection
+     * @param pMsgId        the id of the recent buffer pool message
+     * @param statusDescPtr FMQ descriptor for shared buffer status message
+     *                      queue between a buffer pool and the client.
+     * @param invDescPtr    FMQ descriptor for buffer invalidation message
+     *                      queue from a buffer pool to the client.
+     *
+     * @return OK when a connection is successfully made.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus connect(
+            const std::shared_ptr<IObserver>& observer,
+            bool local,
+            std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
+            uint32_t *pMsgId,
+            StatusDescriptor* statusDescPtr,
+            InvalidationDescriptor* invDescPtr);
+
+    /**
+     * Closes the specified connection to the client.
+     *
+     * @param connectionId  the id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus close(ConnectionId connectionId);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache
+     * cleaning.
+     *
+     * @param clearCache    if clearCache is true, it frees all buffers waiting
+     *                      to be recycled.
+     */
+    void cleanUp(bool clearCache);
+
+    /**
+     * ACK on buffer invalidation messages
+     */
+    void handleInvalidateAck();
+
+    /**
+     * Gets a death_recipient for remote connection death.
+     */
+    static std::shared_ptr<ConnectionDeathRecipient> getConnectionDeathRecipient();
+
+    static void createInvalidator();
+
+    static void createEvictor();
+
+private:
+    // ConnectionId = pid : (timestamp_created + seqId)
+    // in order to guarantee uniqueness for each connection
+    static uint32_t sSeqId;
+
+    const std::shared_ptr<BufferPoolAllocator> mAllocator;
+    nsecs_t mScheduleEvictTs;
+    BufferPool mBufferPool;
+
+    struct  AccessorInvalidator {
+        std::map<uint32_t, const std::weak_ptr<Accessor>> mAccessors;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+        bool mReady;
+
+        AccessorInvalidator();
+        void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor> &accessor);
+        void delAccessor(uint32_t accessorId);
+    };
+
+    static std::unique_ptr<AccessorInvalidator> sInvalidator;
+
+    static void invalidatorThread(
+        std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv,
+        bool &ready);
+
+    struct AccessorEvictor {
+        std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> mAccessors;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+
+        AccessorEvictor();
+        void addAccessor(const std::weak_ptr<Accessor> &accessor, nsecs_t ts);
+    };
+
+    static std::unique_ptr<AccessorEvictor> sEvictor;
+
+    static void evictorThread(
+        std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv);
+
+    void scheduleEvictIfNeeded();
+
+    friend struct BufferPool;
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Android.bp b/media/bufferpool/aidl/default/Android.bp
new file mode 100644
index 0000000..11a6163
--- /dev/null
+++ b/media/bufferpool/aidl/default/Android.bp
@@ -0,0 +1,50 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+    name: "libstagefright_aidl_bufferpool2",
+    vendor_available: true,
+    min_sdk_version: "29",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    srcs: [
+        "Accessor.cpp",
+        "BufferPool.cpp",
+        "BufferPoolClient.cpp",
+        "BufferStatus.cpp",
+        "ClientManager.cpp",
+        "Connection.cpp",
+        "Observer.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+    export_shared_lib_headers: [
+        "libfmq",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    double_loadable: true,
+    cflags: [
+        "-DBUFFERPOOL_CLONE_HANDLES",
+    ],
+}
diff --git a/media/bufferpool/aidl/default/BufferPool.cpp b/media/bufferpool/aidl/default/BufferPool.cpp
new file mode 100644
index 0000000..ed4574f
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPool.cpp
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPool"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <thread>
+#include "Accessor.h"
+#include "BufferPool.h"
+#include "Connection.h"
+#include "DataHelper.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+namespace {
+    static constexpr int64_t kCleanUpDurationMs = 500; // 0.5 sec
+    static constexpr int64_t kLogDurationMs = 5000; // 5 secs
+
+    static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
+    static constexpr size_t kMinBufferCountForEviction = 25;
+    static constexpr size_t kMaxUnusedBufferCount = 64;
+    static constexpr size_t kUnusedBufferCountTarget = kMaxUnusedBufferCount - 16;
+}
+
+BufferPool::BufferPool()
+    : mTimestampMs(::android::elapsedRealtime()),
+      mLastCleanUpMs(mTimestampMs),
+      mLastLogMs(mTimestampMs),
+      mSeq(0),
+      mStartSeq(0) {
+    mValid = mInvalidationChannel.isValid();
+}
+
+
+// Statistics helper
+template<typename T, typename S>
+int percentage(T base, S total) {
+    return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
+}
+
+std::atomic<std::uint32_t> BufferPool::Invalidation::sInvSeqId(0);
+
+BufferPool::~BufferPool() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    ALOGD("Destruction - bufferpool2 %p "
+          "cached: %zu/%zuM, %zu/%d%% in use; "
+          "allocs: %zu, %d%% recycled; "
+          "transfers: %zu, %d%% unfetched",
+          this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
+          mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
+          mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
+          mStats.mTotalTransfers,
+          percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
+}
+
+void BufferPool::Invalidation::onConnect(
+        ConnectionId conId, const std::shared_ptr<IObserver>& observer) {
+    mAcks[conId] = mInvalidationId; // starts from current invalidationId
+    mObservers.insert(std::make_pair(conId, observer));
+}
+
+void BufferPool::Invalidation::onClose(ConnectionId conId) {
+    mAcks.erase(conId);
+    mObservers.erase(conId);
+}
+
+void BufferPool::Invalidation::onAck(
+        ConnectionId conId,
+        uint32_t msgId) {
+    auto it = mAcks.find(conId);
+    if (it == mAcks.end()) {
+        ALOGW("ACK from inconsistent connection! %lld", (long long)conId);
+        return;
+    }
+    if (isMessageLater(msgId, it->second)) {
+        mAcks[conId] = msgId;
+    }
+}
+
+void BufferPool::Invalidation::onBufferInvalidated(
+        BufferId bufferId,
+        BufferInvalidationChannel &channel) {
+    for (auto it = mPendings.begin(); it != mPendings.end();) {
+        if (it->isInvalidated(bufferId)) {
+            uint32_t msgId = 0;
+            if (it->mNeedsAck) {
+                msgId = ++mInvalidationId;
+                if (msgId == 0) {
+                    // wrap happens
+                    msgId = ++mInvalidationId;
+                }
+            }
+            channel.postInvalidation(msgId, it->mFrom, it->mTo);
+            it = mPendings.erase(it);
+            continue;
+        }
+        ++it;
+    }
+}
+
+void BufferPool::Invalidation::onInvalidationRequest(
+        bool needsAck,
+        uint32_t from,
+        uint32_t to,
+        size_t left,
+        BufferInvalidationChannel &channel,
+        const std::shared_ptr<Accessor> &impl) {
+        uint32_t msgId = 0;
+    if (needsAck) {
+        msgId = ++mInvalidationId;
+        if (msgId == 0) {
+            // wrap happens
+            msgId = ++mInvalidationId;
+        }
+    }
+    ALOGV("bufferpool2 invalidation requested and queued");
+    if (left == 0) {
+        channel.postInvalidation(msgId, from, to);
+    } else {
+        ALOGV("bufferpoo2 invalidation requested and pending");
+        Pending pending(needsAck, from, to, left, impl);
+        mPendings.push_back(pending);
+    }
+    Accessor::sInvalidator->addAccessor(mId, impl);
+}
+
+void BufferPool::Invalidation::onHandleAck(
+        std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
+        uint32_t *invalidationId) {
+    if (mInvalidationId != 0) {
+        *invalidationId = mInvalidationId;
+        std::set<int> deads;
+        for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
+            if (it->second != mInvalidationId) {
+                const std::shared_ptr<IObserver> observer = mObservers[it->first];
+                if (observer) {
+                    observers->emplace(it->first, observer);
+                    ALOGV("connection %lld will call observer (%u: %u)",
+                          (long long)it->first, it->second, mInvalidationId);
+                    // N.B: onMessage will be called later. ignore possibility of
+                    // onMessage# oneway call being lost.
+                    it->second = mInvalidationId;
+                } else {
+                    ALOGV("bufferpool2 observer died %lld", (long long)it->first);
+                    deads.insert(it->first);
+                }
+            }
+        }
+        if (deads.size() > 0) {
+            for (auto it = deads.begin(); it != deads.end(); ++it) {
+                onClose(*it);
+            }
+        }
+    }
+    if (mPendings.size() == 0) {
+        // All invalidation Ids are synced and no more pending invalidations.
+        Accessor::sInvalidator->delAccessor(mId);
+    }
+}
+
+bool BufferPool::handleOwnBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+
+    bool added = insert(&mUsingBuffers, connectionId, bufferId);
+    if (added) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount++;
+    }
+    insert(&mUsingConnections, bufferId, connectionId);
+    return added;
+}
+
+bool BufferPool::handleReleaseBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+    bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
+    if (deleted) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount--;
+        if (iter->second->mOwnerCount == 0 &&
+                iter->second->mTransactionCount == 0) {
+            if (!iter->second->mInvalidated) {
+                mStats.onBufferUnused(iter->second->mAllocSize);
+                mFreeBuffers.insert(bufferId);
+            } else {
+                mStats.onBufferUnused(iter->second->mAllocSize);
+                mStats.onBufferEvicted(iter->second->mAllocSize);
+                mBuffers.erase(iter);
+                mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+            }
+        }
+    }
+    erase(&mUsingConnections, bufferId, connectionId);
+    ALOGV("release buffer %u : %d", bufferId, deleted);
+    return deleted;
+}
+
+bool BufferPool::handleTransferTo(const BufferStatusMessage &message) {
+    auto completed = mCompletedTransactions.find(
+            message.transactionId);
+    if (completed != mCompletedTransactions.end()) {
+        // already completed
+        mCompletedTransactions.erase(completed);
+        return true;
+    }
+    // the buffer should exist and be owned.
+    auto bufferIter = mBuffers.find(message.bufferId);
+    if (bufferIter == mBuffers.end() ||
+            !contains(&mUsingBuffers, message.connectionId, FromAidl(message.bufferId))) {
+        return false;
+    }
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        // transfer_from was received earlier.
+        found->second->mSender = message.connectionId;
+        found->second->mSenderValidated = true;
+        return true;
+    }
+    if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+        // N.B: it could be fake or receive connection already closed.
+        ALOGD("bufferpool2 %p receiver connection %lld is no longer valid",
+              this, (long long)message.targetConnectionId);
+        return false;
+    }
+    mStats.onBufferSent();
+    mTransactions.insert(std::make_pair(
+            message.transactionId,
+            std::make_unique<TransactionStatus>(message, mTimestampMs)));
+    insert(&mPendingTransactions, message.targetConnectionId,
+           FromAidl(message.transactionId));
+    bufferIter->second->mTransactionCount++;
+    return true;
+}
+
+bool BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found == mTransactions.end()) {
+        // TODO: is it feasible to check ownership here?
+        mStats.onBufferSent();
+        mTransactions.insert(std::make_pair(
+                message.transactionId,
+                std::make_unique<TransactionStatus>(message, mTimestampMs)));
+        insert(&mPendingTransactions, message.connectionId,
+               FromAidl(message.transactionId));
+        auto bufferIter = mBuffers.find(message.bufferId);
+        bufferIter->second->mTransactionCount++;
+    } else {
+        if (message.connectionId == found->second->mReceiver) {
+            found->second->mStatus = BufferStatus::TRANSFER_FROM;
+        }
+    }
+    return true;
+}
+
+bool BufferPool::handleTransferResult(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        bool deleted = erase(&mPendingTransactions, message.connectionId,
+                             FromAidl(message.transactionId));
+        if (deleted) {
+            if (!found->second->mSenderValidated) {
+                mCompletedTransactions.insert(message.transactionId);
+            }
+            auto bufferIter = mBuffers.find(message.bufferId);
+            if (message.status == BufferStatus::TRANSFER_OK) {
+                handleOwnBuffer(message.connectionId, message.bufferId);
+            }
+            bufferIter->second->mTransactionCount--;
+            if (bufferIter->second->mOwnerCount == 0
+                && bufferIter->second->mTransactionCount == 0) {
+                if (!bufferIter->second->mInvalidated) {
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mFreeBuffers.insert(message.bufferId);
+                } else {
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                    mBuffers.erase(bufferIter);
+                    mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
+                }
+            }
+            mTransactions.erase(found);
+        }
+        ALOGV("transfer finished %llu %u - %d", (unsigned long long)message.transactionId,
+              message.bufferId, deleted);
+        return deleted;
+    }
+    ALOGV("transfer not found %llu %u", (unsigned long long)message.transactionId,
+          message.bufferId);
+    return false;
+}
+
+void BufferPool::processStatusMessages() {
+    std::vector<BufferStatusMessage> messages;
+    mObserver.getBufferStatusChanges(messages);
+    mTimestampMs = ::android::elapsedRealtime();
+    for (BufferStatusMessage& message: messages) {
+        bool ret = false;
+        switch (message.status) {
+            case BufferStatus::NOT_USED:
+                ret = handleReleaseBuffer(
+                        message.connectionId, message.bufferId);
+                break;
+            case BufferStatus::USED:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_TO:
+                ret = handleTransferTo(message);
+                break;
+            case BufferStatus::TRANSFER_FROM:
+                ret = handleTransferFrom(message);
+                break;
+            case BufferStatus::TRANSFER_TIMEOUT:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_LOST:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_FETCH:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_OK:
+            case BufferStatus::TRANSFER_ERROR:
+                ret = handleTransferResult(message);
+                break;
+            case BufferStatus::INVALIDATION_ACK:
+                mInvalidation.onAck(message.connectionId, message.bufferId);
+                ret = true;
+                break;
+        }
+        if (ret == false) {
+            ALOGW("buffer status message processing failure - message : %d connection : %lld",
+                  message.status, (long long)message.connectionId);
+        }
+    }
+    messages.clear();
+}
+
+bool BufferPool::handleClose(ConnectionId connectionId) {
+    // Cleaning buffers
+    auto buffers = mUsingBuffers.find(connectionId);
+    if (buffers != mUsingBuffers.end()) {
+        for (const BufferId& bufferId : buffers->second) {
+            bool deleted = erase(&mUsingConnections, bufferId, connectionId);
+            if (deleted) {
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mOwnerCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                        bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    if (!bufferIter->second->mInvalidated) {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mFreeBuffers.insert(bufferId);
+                    } else {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                        mBuffers.erase(bufferIter);
+                        mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+                    }
+                }
+            }
+        }
+        mUsingBuffers.erase(buffers);
+    }
+
+    // Cleaning transactions
+    auto pending = mPendingTransactions.find(connectionId);
+    if (pending != mPendingTransactions.end()) {
+        for (const TransactionId& transactionId : pending->second) {
+            auto iter = mTransactions.find(transactionId);
+            if (iter != mTransactions.end()) {
+                if (!iter->second->mSenderValidated) {
+                    mCompletedTransactions.insert(transactionId);
+                }
+                BufferId bufferId = iter->second->mBufferId;
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mTransactionCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                    bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    if (!bufferIter->second->mInvalidated) {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mFreeBuffers.insert(bufferId);
+                    } else {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                        mBuffers.erase(bufferIter);
+                        mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+                    }
+                }
+                mTransactions.erase(iter);
+            }
+        }
+    }
+    mConnectionIds.erase(connectionId);
+    return true;
+}
+
+bool BufferPool::getFreeBuffer(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        const std::vector<uint8_t> &params, BufferId *pId,
+        const native_handle_t** handle) {
+    auto bufferIt = mFreeBuffers.begin();
+    for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
+        BufferId bufferId = *bufferIt;
+        if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
+            break;
+        }
+    }
+    if (bufferIt != mFreeBuffers.end()) {
+        BufferId id = *bufferIt;
+        mFreeBuffers.erase(bufferIt);
+        mStats.onBufferRecycled(mBuffers[id]->mAllocSize);
+        *handle = mBuffers[id]->handle();
+        *pId = id;
+        ALOGV("recycle a buffer %u %p", id, *handle);
+        return true;
+    }
+    return false;
+}
+
+BufferPoolStatus BufferPool::addNewBuffer(
+        const std::shared_ptr<BufferPoolAllocation> &alloc,
+        const size_t allocSize,
+        const std::vector<uint8_t> &params,
+        BufferId *pId,
+        const native_handle_t** handle) {
+
+    BufferId bufferId = mSeq++;
+    if (mSeq == Connection::SYNC_BUFFERID) {
+        mSeq = 0;
+    }
+    std::unique_ptr<InternalBuffer> buffer =
+            std::make_unique<InternalBuffer>(
+                    bufferId, alloc, allocSize, params);
+    if (buffer) {
+        auto res = mBuffers.insert(std::make_pair(
+                bufferId, std::move(buffer)));
+        if (res.second) {
+            mStats.onBufferAllocated(allocSize);
+            *handle = alloc->handle();
+            *pId = bufferId;
+            return ResultStatus::OK;
+        }
+    }
+    return ResultStatus::NO_MEMORY;
+}
+
+void BufferPool::cleanUp(bool clearCache) {
+    if (clearCache || mTimestampMs > mLastCleanUpMs + kCleanUpDurationMs ||
+            mStats.buffersNotInUse() > kMaxUnusedBufferCount) {
+        mLastCleanUpMs = mTimestampMs;
+        if (mTimestampMs > mLastLogMs + kLogDurationMs ||
+                mStats.buffersNotInUse() > kMaxUnusedBufferCount) {
+            mLastLogMs = mTimestampMs;
+            ALOGD("bufferpool2 %p : %zu(%zu size) total buffers - "
+                  "%zu(%zu size) used buffers - %zu/%zu (recycle/alloc) - "
+                  "%zu/%zu (fetch/transfer)",
+                  this, mStats.mBuffersCached, mStats.mSizeCached,
+                  mStats.mBuffersInUse, mStats.mSizeInUse,
+                  mStats.mTotalRecycles, mStats.mTotalAllocations,
+                  mStats.mTotalFetches, mStats.mTotalTransfers);
+        }
+        for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+            if (!clearCache && mStats.buffersNotInUse() <= kUnusedBufferCountTarget &&
+                    (mStats.mSizeCached < kMinAllocBytesForEviction ||
+                     mBuffers.size() < kMinBufferCountForEviction)) {
+                break;
+            }
+            auto it = mBuffers.find(*freeIt);
+            if (it != mBuffers.end() &&
+                    it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+                mStats.onBufferEvicted(it->second->mAllocSize);
+                mBuffers.erase(it);
+                freeIt = mFreeBuffers.erase(freeIt);
+            } else {
+                ++freeIt;
+                ALOGW("bufferpool2 inconsistent!");
+            }
+        }
+    }
+}
+
+void BufferPool::invalidate(
+        bool needsAck, BufferId from, BufferId to,
+        const std::shared_ptr<Accessor> &impl) {
+    for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+        if (isBufferInRange(from, to, *freeIt)) {
+            auto it = mBuffers.find(*freeIt);
+            if (it != mBuffers.end() &&
+                it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+                mStats.onBufferEvicted(it->second->mAllocSize);
+                mBuffers.erase(it);
+                freeIt = mFreeBuffers.erase(freeIt);
+                continue;
+            } else {
+                ALOGW("bufferpool2 inconsistent!");
+            }
+        }
+        ++freeIt;
+    }
+
+    size_t left = 0;
+    for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+        if (isBufferInRange(from, to, it->first)) {
+            it->second->invalidate();
+            ++left;
+        }
+    }
+    mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
+}
+
+void BufferPool::flush(const std::shared_ptr<Accessor> &impl) {
+    BufferId from = mStartSeq;
+    BufferId to = mSeq;
+    mStartSeq = mSeq;
+    // TODO: needsAck params
+    ALOGV("buffer invalidation request bp:%u %u %u", mInvalidation.mId, from, to);
+    if (from != to) {
+        invalidate(true, from, to, impl);
+    }
+}
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPool.h b/media/bufferpool/aidl/default/BufferPool.h
new file mode 100644
index 0000000..1529a53
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPool.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <vector>
+#include <mutex>
+#include <condition_variable>
+#include <utils/Timers.h>
+
+#include "BufferStatus.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using BufferStatus = aidl::android::hardware::media::bufferpool2::BufferStatus;
+using BufferStatusMessage = aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+
+struct Accessor;
+struct InternalBuffer;
+struct TransactionStatus;
+
+/**
+ * Buffer pool implementation.
+ *
+ * Handles buffer status messages. Handles buffer allocation/recycling.
+ * Handles buffer transfer between buffer pool clients.
+ */
+struct BufferPool {
+private:
+    std::mutex mMutex;
+    int64_t mTimestampMs;
+    int64_t mLastCleanUpMs;
+    int64_t mLastLogMs;
+    BufferId mSeq;
+    BufferId mStartSeq;
+    bool mValid;
+    BufferStatusObserver mObserver;
+    BufferInvalidationChannel mInvalidationChannel;
+
+    std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
+    std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
+
+    std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
+    // Transactions completed before TRANSFER_TO message arrival.
+    // Fetch does not occur for the transactions.
+    // Only transaction id is kept for the transactions in short duration.
+    std::set<TransactionId> mCompletedTransactions;
+    // Currently active(pending) transations' status & information.
+    std::map<TransactionId, std::unique_ptr<TransactionStatus>>
+            mTransactions;
+
+    std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
+    std::set<BufferId> mFreeBuffers;
+    std::set<ConnectionId> mConnectionIds;
+
+    struct Invalidation {
+        static std::atomic<std::uint32_t> sInvSeqId;
+
+        struct Pending {
+            bool mNeedsAck;
+            uint32_t mFrom;
+            uint32_t mTo;
+            size_t mLeft;
+            const std::weak_ptr<Accessor> mImpl;
+            Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
+                    const std::shared_ptr<Accessor> &impl)
+                    : mNeedsAck(needsAck),
+                      mFrom(from),
+                      mTo(to),
+                      mLeft(left),
+                      mImpl(impl)
+            {}
+
+            bool isInvalidated(uint32_t bufferId) {
+                return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
+            }
+        };
+
+        std::list<Pending> mPendings;
+        std::map<ConnectionId, uint32_t> mAcks;
+        std::map<ConnectionId, const std::shared_ptr<IObserver>> mObservers;
+        uint32_t mInvalidationId;
+        uint32_t mId;
+
+        Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
+
+        void onConnect(ConnectionId conId, const std::shared_ptr<IObserver> &observer);
+
+        void onClose(ConnectionId conId);
+
+        void onAck(ConnectionId conId, uint32_t msgId);
+
+        void onBufferInvalidated(
+                BufferId bufferId,
+                BufferInvalidationChannel &channel);
+
+        void onInvalidationRequest(
+                bool needsAck, uint32_t from, uint32_t to, size_t left,
+                BufferInvalidationChannel &channel,
+                const std::shared_ptr<Accessor> &impl);
+
+        void onHandleAck(
+                std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
+                uint32_t *invalidationId);
+    } mInvalidation;
+    /// Buffer pool statistics which tracks allocation and transfer statistics.
+    struct Stats {
+        /// Total size of allocations which are used or available to use.
+        /// (bytes or pixels)
+        size_t mSizeCached;
+        /// # of cached buffers which are used or available to use.
+        size_t mBuffersCached;
+        /// Total size of allocations which are currently used. (bytes or pixels)
+        size_t mSizeInUse;
+        /// # of currently used buffers
+        size_t mBuffersInUse;
+
+        /// # of allocations called on bufferpool. (# of fetched from BlockPool)
+        size_t mTotalAllocations;
+        /// # of allocations that were served from the cache.
+        /// (# of allocator alloc prevented)
+        size_t mTotalRecycles;
+        /// # of buffer transfers initiated.
+        size_t mTotalTransfers;
+        /// # of transfers that had to be fetched.
+        size_t mTotalFetches;
+
+        Stats()
+            : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
+              mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
+
+        /// # of currently unused buffers
+        size_t buffersNotInUse() const {
+            ALOG_ASSERT(mBuffersCached >= mBuffersInUse);
+            return mBuffersCached - mBuffersInUse;
+        }
+
+        /// A new buffer is allocated on an allocation request.
+        void onBufferAllocated(size_t allocSize) {
+            mSizeCached += allocSize;
+            mBuffersCached++;
+
+            mSizeInUse += allocSize;
+            mBuffersInUse++;
+
+            mTotalAllocations++;
+        }
+
+        /// A buffer is evicted and destroyed.
+        void onBufferEvicted(size_t allocSize) {
+            mSizeCached -= allocSize;
+            mBuffersCached--;
+        }
+
+        /// A buffer is recycled on an allocation request.
+        void onBufferRecycled(size_t allocSize) {
+            mSizeInUse += allocSize;
+            mBuffersInUse++;
+
+            mTotalAllocations++;
+            mTotalRecycles++;
+        }
+
+        /// A buffer is available to be recycled.
+        void onBufferUnused(size_t allocSize) {
+            mSizeInUse -= allocSize;
+            mBuffersInUse--;
+        }
+
+        /// A buffer transfer is initiated.
+        void onBufferSent() {
+            mTotalTransfers++;
+        }
+
+        /// A buffer fetch is invoked by a buffer transfer.
+        void onBufferFetched() {
+            mTotalFetches++;
+        }
+    } mStats;
+
+    bool isValid() {
+        return mValid;
+    }
+
+    void invalidate(bool needsAck, BufferId from, BufferId to,
+                    const std::shared_ptr<Accessor> &impl);
+
+    static void createInvalidator();
+
+public:
+    /** Creates a buffer pool. */
+    BufferPool();
+
+    /** Destroys a buffer pool. */
+    ~BufferPool();
+
+    /**
+     * Processes all pending buffer status messages, and returns the result.
+     * Each status message is handled by methods with 'handle' prefix.
+     */
+    void processStatusMessages();
+
+    /**
+     * Handles a buffer being owned by a connection.
+     *
+     * @param connectionId  the id of the buffer owning connection.
+     * @param bufferId      the id of the buffer.
+     *
+     * @return {@code true} when the buffer is owned,
+     *         {@code false} otherwise.
+     */
+    bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
+
+    /**
+     * Handles a buffer being released by a connection.
+     *
+     * @param connectionId  the id of the buffer owning connection.
+     * @param bufferId      the id of the buffer.
+     *
+     * @return {@code true} when the buffer ownership is released,
+     *         {@code false} otherwise.
+     */
+    bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
+
+    /**
+     * Handles a transfer transaction start message from the sender.
+     *
+     * @param message   a buffer status message for the transaction.
+     *
+     * @result {@code true} when transfer_to message is acknowledged,
+     *         {@code false} otherwise.
+     */
+    bool handleTransferTo(const BufferStatusMessage &message);
+
+    /**
+     * Handles a transfer transaction being acked by the receiver.
+     *
+     * @param message   a buffer status message for the transaction.
+     *
+     * @result {@code true} when transfer_from message is acknowledged,
+     *         {@code false} otherwise.
+     */
+    bool handleTransferFrom(const BufferStatusMessage &message);
+
+    /**
+     * Handles a transfer transaction result message from the receiver.
+     *
+     * @param message   a buffer status message for the transaction.
+     *
+     * @result {@code true} when the existing transaction is finished,
+     *         {@code false} otherwise.
+     */
+    bool handleTransferResult(const BufferStatusMessage &message);
+
+    /**
+     * Handles a connection being closed, and returns the result. All the
+     * buffers and transactions owned by the connection will be cleaned up.
+     * The related FMQ will be cleaned up too.
+     *
+     * @param connectionId  the id of the connection.
+     *
+     * @result {@code true} when the connection existed,
+     *         {@code false} otherwise.
+     */
+    bool handleClose(ConnectionId connectionId);
+
+    /**
+     * Recycles a existing free buffer if it is possible.
+     *
+     * @param allocator the buffer allocator
+     * @param params    the allocation parameters.
+     * @param pId       the id of the recycled buffer.
+     * @param handle    the native handle of the recycled buffer.
+     *
+     * @return {@code true} when a buffer is recycled, {@code false}
+     *         otherwise.
+     */
+    bool getFreeBuffer(
+            const std::shared_ptr<BufferPoolAllocator> &allocator,
+            const std::vector<uint8_t> &params,
+            BufferId *pId, const native_handle_t **handle);
+
+    /**
+     * Adds a newly allocated buffer to bufferpool.
+     *
+     * @param alloc     the newly allocated buffer.
+     * @param allocSize the size of the newly allocated buffer.
+     * @param params    the allocation parameters.
+     * @param pId       the buffer id for the newly allocated buffer.
+     * @param handle    the native handle for the newly allocated buffer.
+     *
+     * @return OK when an allocation is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus addNewBuffer(
+            const std::shared_ptr<BufferPoolAllocation> &alloc,
+            const size_t allocSize,
+            const std::vector<uint8_t> &params,
+            BufferId *pId,
+            const native_handle_t **handle);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache
+     * cleaning.
+     *
+     * @param clearCache    if clearCache is true, it frees all buffers
+     *                      waiting to be recycled.
+     */
+    void cleanUp(bool clearCache = false);
+
+    /**
+     * Processes pending buffer status messages and invalidate all current
+     * free buffers. Active buffers are invalidated after being inactive.
+     */
+    void flush(const std::shared_ptr<Accessor> &impl);
+
+    friend struct Accessor;
+};
+
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
new file mode 100644
index 0000000..e9777d8
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolCli"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <utils/Log.h>
+#include "BufferPoolClient.h"
+#include "Accessor.h"
+#include "Connection.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::IConnection;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using FetchInfo = aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo;
+using FetchResult = aidl::android::hardware::media::bufferpool2::IConnection::FetchResult;
+
+static constexpr int64_t kReceiveTimeoutMs = 2000; // 2s
+static constexpr int kPostMaxRetry = 3;
+static constexpr int kCacheTtlMs = 1000;
+static constexpr size_t kMaxCachedBufferCount = 64;
+static constexpr size_t kCachedBufferCountTarget = kMaxCachedBufferCount - 16;
+
+class BufferPoolClient::Impl
+        : public std::enable_shared_from_this<BufferPoolClient::Impl> {
+public:
+    explicit Impl(const std::shared_ptr<Accessor> &accessor,
+                  const std::shared_ptr<IObserver> &observer);
+
+    explicit Impl(const std::shared_ptr<IAccessor> &accessor,
+                  const std::shared_ptr<IObserver> &observer);
+
+    bool isValid() {
+        return mValid;
+    }
+
+    bool isLocal() {
+        return mValid && mLocal;
+    }
+
+    ConnectionId getConnectionId() {
+        return mConnectionId;
+    }
+
+    std::shared_ptr<IAccessor> &getAccessor() {
+        return mAccessor;
+    }
+
+    bool isActive(int64_t *lastTransactionMs, bool clearCache);
+
+    void receiveInvalidation(uint32_t msgID);
+
+    BufferPoolStatus flush();
+
+    BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus receive(
+            TransactionId transactionId, BufferId bufferId,
+            int64_t timestampMs,
+            native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
+
+    void postBufferRelease(BufferId bufferId);
+
+    bool postSend(
+            BufferId bufferId, ConnectionId receiver,
+            TransactionId *transactionId, int64_t *timestampMs);
+private:
+
+    bool postReceive(
+            BufferId bufferId, TransactionId transactionId,
+            int64_t timestampMs);
+
+    bool postReceiveResult(
+            BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync);
+
+    void trySyncFromRemote();
+
+    bool syncReleased(uint32_t msgId = 0);
+
+    void evictCaches(bool clearCache = false);
+
+    void invalidateBuffer(BufferId id);
+
+    void invalidateRange(BufferId from, BufferId to);
+
+    BufferPoolStatus allocateBufferHandle(
+            const std::vector<uint8_t>& params, BufferId *bufferId,
+            native_handle_t **handle);
+
+    BufferPoolStatus fetchBufferHandle(
+            TransactionId transactionId, BufferId bufferId,
+            native_handle_t **handle);
+
+    struct BlockPoolDataDtor;
+    struct ClientBuffer;
+
+    bool mLocal;
+    bool mValid;
+    std::shared_ptr<IAccessor> mAccessor;
+    std::shared_ptr<Connection> mLocalConnection;
+    std::shared_ptr<IConnection> mRemoteConnection;
+    uint32_t mSeqId;
+    ConnectionId mConnectionId;
+    int64_t mLastEvictCacheMs;
+    std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
+
+    // CachedBuffers
+    struct BufferCache {
+        std::mutex mLock;
+        bool mCreating;
+        std::condition_variable mCreateCv;
+        std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
+        int mActive;
+        int64_t mLastChangeMs;
+
+        BufferCache() : mCreating(false), mActive(0),
+                mLastChangeMs(::android::elapsedRealtime()) {}
+
+        void incActive_l() {
+            ++mActive;
+            mLastChangeMs = ::android::elapsedRealtime();
+        }
+
+        void decActive_l() {
+            --mActive;
+            mLastChangeMs = ::android::elapsedRealtime();
+        }
+
+        int cachedBufferCount() const {
+            return mBuffers.size() - mActive;
+        }
+    } mCache;
+
+    // FMQ - release notifier
+    struct ReleaseCache {
+        std::mutex mLock;
+        std::list<BufferId> mReleasingIds;
+        std::list<BufferId> mReleasedIds;
+        uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
+        bool mInvalidateAck;
+        std::unique_ptr<BufferStatusChannel> mStatusChannel;
+
+        ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
+    } mReleasing;
+
+    // This lock is held during synchronization from remote side.
+    // In order to minimize remote calls and locking duration, this lock is held
+    // by best effort approach using try_lock().
+    std::mutex mRemoteSyncLock;
+};
+
+struct BufferPoolClient::Impl::BlockPoolDataDtor {
+    BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
+            : mImpl(impl) {}
+
+    void operator()(BufferPoolData *buffer) {
+        BufferId id = buffer->mId;
+        delete buffer;
+
+        auto impl = mImpl.lock();
+        if (impl && impl->isValid()) {
+            impl->postBufferRelease(id);
+        }
+    }
+    const std::weak_ptr<BufferPoolClient::Impl> mImpl;
+};
+
+struct BufferPoolClient::Impl::ClientBuffer {
+private:
+    int64_t mExpireMs;
+    bool mHasCache;
+    ConnectionId mConnectionId;
+    BufferId mId;
+    native_handle_t *mHandle;
+    std::weak_ptr<BufferPoolData> mCache;
+
+    void updateExpire() {
+        mExpireMs = ::android::elapsedRealtime() + kCacheTtlMs;
+    }
+
+public:
+    ClientBuffer(
+            ConnectionId connectionId, BufferId id, native_handle_t *handle)
+            : mHasCache(false), mConnectionId(connectionId),
+              mId(id), mHandle(handle) {
+        mExpireMs = ::android::elapsedRealtime() + kCacheTtlMs;
+    }
+
+    ~ClientBuffer() {
+        if (mHandle) {
+            native_handle_close(mHandle);
+            native_handle_delete(mHandle);
+        }
+    }
+
+    BufferId id() const {
+        return mId;
+    }
+
+    bool expire() const {
+        int64_t now = ::android::elapsedRealtime();
+        return now >= mExpireMs;
+    }
+
+    bool hasCache() const {
+        return mHasCache;
+    }
+
+    std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
+        if (mHasCache) {
+            std::shared_ptr<BufferPoolData> cache = mCache.lock();
+            if (cache) {
+                *pHandle = mHandle;
+            }
+            return cache;
+        }
+        return nullptr;
+    }
+
+    std::shared_ptr<BufferPoolData> createCache(
+            const std::shared_ptr<BufferPoolClient::Impl> &impl,
+            native_handle_t **pHandle) {
+        if (!mHasCache) {
+            // Allocates a raw ptr in order to avoid sending #postBufferRelease
+            // from deleter, in case of native_handle_clone failure.
+            BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
+            if (ptr) {
+                std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
+                if (cache) {
+                    mCache = cache;
+                    mHasCache = true;
+                    *pHandle = mHandle;
+                    return cache;
+                }
+            }
+            if (ptr) {
+                delete ptr;
+            }
+        }
+        return nullptr;
+    }
+
+    bool onCacheRelease() {
+        if (mHasCache) {
+            // TODO: verify mCache is not valid;
+            updateExpire();
+            mHasCache = false;
+            return true;
+        }
+        return false;
+    }
+};
+
+BufferPoolClient::Impl::Impl(const std::shared_ptr<Accessor> &accessor,
+                             const std::shared_ptr<IObserver> &observer)
+    : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
+      mLastEvictCacheMs(::android::elapsedRealtime()) {
+    StatusDescriptor statusDesc;
+    InvalidationDescriptor invDesc;
+    BufferPoolStatus status = accessor->connect(
+            observer, true,
+            &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
+            &statusDesc, &invDesc);
+    if (status == ResultStatus::OK) {
+        mReleasing.mStatusChannel =
+                std::make_unique<BufferStatusChannel>(statusDesc);
+        mInvalidationListener =
+                std::make_unique<BufferInvalidationListener>(invDesc);
+        mValid = mReleasing.mStatusChannel &&
+                mReleasing.mStatusChannel->isValid() &&
+                mInvalidationListener &&
+                mInvalidationListener->isValid();
+    }
+}
+
+BufferPoolClient::Impl::Impl(const std::shared_ptr<IAccessor> &accessor,
+                             const std::shared_ptr<IObserver> &observer)
+    : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
+      mLastEvictCacheMs(::android::elapsedRealtime()) {
+    IAccessor::ConnectionInfo conInfo;
+    bool valid = false;
+    if(accessor->connect(observer, &conInfo).isOk()) {
+        auto channel = std::make_unique<BufferStatusChannel>(conInfo.toFmqDesc);
+        auto observer = std::make_unique<BufferInvalidationListener>(conInfo.fromFmqDesc);
+
+        if (channel && channel->isValid()
+            && observer && observer->isValid()) {
+            mRemoteConnection = conInfo.connection;
+            mConnectionId = conInfo.connectionId;
+            mReleasing.mInvalidateId = conInfo.msgId;
+            mReleasing.mStatusChannel = std::move(channel);
+            mInvalidationListener = std::move(observer);
+            valid = true;
+        }
+    }
+    mValid = valid;
+}
+
+bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionMs, bool clearCache) {
+    bool active = false;
+    {
+        std::lock_guard<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches(clearCache);
+        *lastTransactionMs = mCache.mLastChangeMs;
+        active = mCache.mActive > 0;
+    }
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(clearCache);
+        return true;
+    }
+    return active;
+}
+
+void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
+    std::lock_guard<std::mutex> lock(mCache.mLock);
+    syncReleased(messageId);
+    // TODO: evict cache required?
+}
+
+BufferPoolStatus BufferPoolClient::Impl::flush() {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches();
+        return mLocalConnection->flush();
+    }
+}
+
+BufferPoolStatus BufferPoolClient::Impl::allocate(
+        const std::vector<uint8_t> &params,
+        native_handle_t **pHandle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    BufferId bufferId;
+    native_handle_t *handle = nullptr;
+    buffer->reset();
+    BufferPoolStatus status = allocateBufferHandle(params, &bufferId, &handle);
+    if (status == ResultStatus::OK) {
+        if (handle) {
+            std::unique_lock<std::mutex> lock(mCache.mLock);
+            syncReleased();
+            evictCaches();
+            auto cacheIt = mCache.mBuffers.find(bufferId);
+            if (cacheIt != mCache.mBuffers.end()) {
+                // TODO: verify it is recycled. (not having active ref)
+                mCache.mBuffers.erase(cacheIt);
+            }
+            auto clientBuffer = std::make_unique<ClientBuffer>(
+                    mConnectionId, bufferId, handle);
+            if (clientBuffer) {
+                auto result = mCache.mBuffers.insert(std::make_pair(
+                        bufferId, std::move(clientBuffer)));
+                if (result.second) {
+                    *buffer = result.first->second->createCache(
+                            shared_from_this(), pHandle);
+                    if (*buffer) {
+                        mCache.incActive_l();
+                    }
+                }
+            }
+        }
+        if (!*buffer) {
+            ALOGV("client cache creation failure %d: %lld",
+                  handle != nullptr, (long long)mConnectionId);
+            status = ResultStatus::NO_MEMORY;
+            postBufferRelease(bufferId);
+        }
+    }
+    return status;
+}
+
+BufferPoolStatus BufferPoolClient::Impl::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampMs,
+        native_handle_t **pHandle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (!mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    if (timestampMs != 0) {
+        timestampMs += kReceiveTimeoutMs;
+    }
+    if (!postReceive(bufferId, transactionId, timestampMs)) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    buffer->reset();
+    while(1) {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches();
+        auto cacheIt = mCache.mBuffers.find(bufferId);
+        if (cacheIt != mCache.mBuffers.end()) {
+            if (cacheIt->second->hasCache()) {
+                *buffer = cacheIt->second->fetchCache(pHandle);
+                if (!*buffer) {
+                    // check transfer time_out
+                    lock.unlock();
+                    std::this_thread::yield();
+                    continue;
+                }
+                ALOGV("client receive from reference %lld", (long long)mConnectionId);
+                break;
+            } else {
+                *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
+                if (*buffer) {
+                    mCache.incActive_l();
+                }
+                ALOGV("client receive from cache %lld", (long long)mConnectionId);
+                break;
+            }
+        } else {
+            if (!mCache.mCreating) {
+                mCache.mCreating = true;
+                lock.unlock();
+                native_handle_t* handle = nullptr;
+                status = fetchBufferHandle(transactionId, bufferId, &handle);
+                lock.lock();
+                if (status == ResultStatus::OK) {
+                    if (handle) {
+                        auto clientBuffer = std::make_unique<ClientBuffer>(
+                                mConnectionId, bufferId, handle);
+                        if (clientBuffer) {
+                            auto result = mCache.mBuffers.insert(
+                                    std::make_pair(bufferId, std::move(
+                                            clientBuffer)));
+                            if (result.second) {
+                                *buffer = result.first->second->createCache(
+                                        shared_from_this(), pHandle);
+                                if (*buffer) {
+                                    mCache.incActive_l();
+                                }
+                            }
+                        }
+                    }
+                    if (!*buffer) {
+                        status = ResultStatus::NO_MEMORY;
+                    }
+                }
+                mCache.mCreating = false;
+                lock.unlock();
+                mCache.mCreateCv.notify_all();
+                break;
+            }
+            mCache.mCreateCv.wait(lock);
+        }
+    }
+    bool needsSync = false;
+    bool posted = postReceiveResult(bufferId, transactionId,
+                                      *buffer ? true : false, &needsSync);
+    ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
+          *buffer ? "ok" : "fail", posted);
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(false);
+    }
+    if (needsSync && mRemoteConnection) {
+        trySyncFromRemote();
+    }
+    if (*buffer) {
+        if (!posted) {
+            buffer->reset();
+            return ResultStatus::CRITICAL_ERROR;
+        }
+        return ResultStatus::OK;
+    }
+    return status;
+}
+
+
+void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    mReleasing.mReleasingIds.push_back(bufferId);
+    mReleasing.mStatusChannel->postBufferRelease(
+            mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+}
+
+// TODO: revise ad-hoc posting data structure
+bool BufferPoolClient::Impl::postSend(
+        BufferId bufferId, ConnectionId receiver,
+        TransactionId *transactionId, int64_t *timestampMs) {
+    {
+        // TODO: don't need to call syncReleased every time
+        std::lock_guard<std::mutex> lock(mCache.mLock);
+        syncReleased();
+    }
+    bool ret = false;
+    bool needsSync = false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        *timestampMs = ::android::elapsedRealtime();
+        *transactionId = (mConnectionId << 32) | mSeqId++;
+        // TODO: retry, add timeout, target?
+        ret =  mReleasing.mStatusChannel->postBufferStatusMessage(
+                *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
+                receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+        needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+    }
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(false);
+    }
+    if (needsSync && mRemoteConnection) {
+        trySyncFromRemote();
+    }
+    return ret;
+}
+
+bool BufferPoolClient::Impl::postReceive(
+        BufferId bufferId, TransactionId transactionId, int64_t timestampMs) {
+    for (int i = 0; i < kPostMaxRetry; ++i) {
+        std::unique_lock<std::mutex> lock(mReleasing.mLock);
+        int64_t now = ::android::elapsedRealtime();
+        if (timestampMs == 0 || now < timestampMs) {
+            bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_FROM,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            if (result) {
+                return true;
+            }
+            lock.unlock();
+            std::this_thread::yield();
+        } else {
+            mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            return false;
+        }
+    }
+    return false;
+}
+
+bool BufferPoolClient::Impl::postReceiveResult(
+        BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    // TODO: retry, add timeout
+    bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
+            transactionId, bufferId,
+            result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
+            mConnectionId, -1, mReleasing.mReleasingIds,
+            mReleasing.mReleasedIds);
+    *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+    return ret;
+}
+
+void BufferPoolClient::Impl::trySyncFromRemote() {
+    if (mRemoteSyncLock.try_lock()) {
+        bool needsSync = false;
+        {
+            std::lock_guard<std::mutex> lock(mReleasing.mLock);
+            needsSync = mReleasing.mStatusChannel->needsSync();
+        }
+        if (needsSync) {
+            if (!mRemoteConnection->sync().isOk()) {
+                ALOGD("sync from client %lld failed: bufferpool process died.",
+                      (long long)mConnectionId);
+            }
+        }
+        mRemoteSyncLock.unlock();
+    }
+}
+
+// should have mCache.mLock
+bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
+    bool cleared = false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        if (mReleasing.mReleasingIds.size() > 0) {
+            mReleasing.mStatusChannel->postBufferRelease(
+                    mConnectionId, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+        }
+        if (mReleasing.mReleasedIds.size() > 0) {
+            for (BufferId& id: mReleasing.mReleasedIds) {
+                ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+                auto found = mCache.mBuffers.find(id);
+                if (found != mCache.mBuffers.end()) {
+                    if (found->second->onCacheRelease()) {
+                        mCache.decActive_l();
+                    } else {
+                        // should not happen!
+                        ALOGW("client %lld cache release status inconsistent!",
+                            (long long)mConnectionId);
+                    }
+                } else {
+                    // should not happen!
+                    ALOGW("client %lld cache status inconsistent!", (long long)mConnectionId);
+                }
+            }
+            mReleasing.mReleasedIds.clear();
+            cleared = true;
+        }
+    }
+    std::vector<BufferInvalidationMessage> invalidations;
+    mInvalidationListener->getInvalidations(invalidations);
+    uint32_t lastMsgId = 0;
+    if (invalidations.size() > 0) {
+        for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
+            if (it->messageId != 0) {
+                lastMsgId = it->messageId;
+            }
+            if (it->fromBufferId == it->toBufferId) {
+                // TODO: handle fromBufferId = UINT32_MAX
+                invalidateBuffer(it->fromBufferId);
+            } else {
+                invalidateRange(it->fromBufferId, it->toBufferId);
+            }
+        }
+    }
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        if (lastMsgId != 0) {
+            if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
+                mReleasing.mInvalidateId = lastMsgId;
+                mReleasing.mInvalidateAck = false;
+            }
+        } else if (messageId != 0) {
+            // messages are drained.
+            if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
+                mReleasing.mInvalidateId = messageId;
+                mReleasing.mInvalidateAck = true;
+            }
+        }
+        if (!mReleasing.mInvalidateAck) {
+            // post ACK
+            mReleasing.mStatusChannel->postBufferInvalidateAck(
+                    mConnectionId,
+                    mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
+            ALOGV("client %lld invalidateion ack (%d) %u",
+                (long long)mConnectionId,
+                mReleasing.mInvalidateAck, mReleasing.mInvalidateId);
+        }
+    }
+    return cleared;
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::evictCaches(bool clearCache) {
+    int64_t now = ::android::elapsedRealtime();
+    if (now >= mLastEvictCacheMs + kCacheTtlMs ||
+            clearCache || mCache.cachedBufferCount() > kMaxCachedBufferCount) {
+        size_t evicted = 0;
+        for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+            if (!it->second->hasCache() && (it->second->expire() ||
+                        clearCache || mCache.cachedBufferCount() > kCachedBufferCountTarget)) {
+                it = mCache.mBuffers.erase(it);
+                ++evicted;
+            } else {
+                ++it;
+            }
+        }
+        ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
+              (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
+        mLastEvictCacheMs = now;
+    }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
+    for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
+        if (id == it->second->id()) {
+            if (!it->second->hasCache()) {
+                mCache.mBuffers.erase(it);
+                ALOGV("cache invalidated %lld : buffer %u",
+                      (long long)mConnectionId, id);
+            } else {
+                ALOGW("Inconsistent invalidation %lld : activer buffer!! %u",
+                      (long long)mConnectionId, (unsigned int)id);
+            }
+            break;
+        }
+    }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
+    size_t invalidated = 0;
+    for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+        if (!it->second->hasCache()) {
+            BufferId bid = it->second->id();
+            if (from < to) {
+                if (from <= bid && bid < to) {
+                    ++invalidated;
+                    it = mCache.mBuffers.erase(it);
+                    continue;
+                }
+            } else {
+                if (from <= bid || bid < to) {
+                    ++invalidated;
+                    it = mCache.mBuffers.erase(it);
+                    continue;
+                }
+            }
+        }
+        ++it;
+    }
+    ALOGV("cache invalidated %lld : # of invalidated %zu",
+          (long long)mConnectionId, invalidated);
+}
+
+BufferPoolStatus BufferPoolClient::Impl::allocateBufferHandle(
+        const std::vector<uint8_t>& params, BufferId *bufferId,
+        native_handle_t** handle) {
+    if (mLocalConnection) {
+        const native_handle_t* allocHandle = nullptr;
+        BufferPoolStatus status = mLocalConnection->allocate(
+                params, bufferId, &allocHandle);
+        if (status == ResultStatus::OK) {
+            *handle = native_handle_clone(allocHandle);
+        }
+        ALOGV("client allocate result %lld %d : %u clone %p",
+              (long long)mConnectionId, status == ResultStatus::OK,
+              *handle ? *bufferId : 0 , *handle);
+        return status;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::Impl::fetchBufferHandle(
+        TransactionId transactionId, BufferId bufferId,
+        native_handle_t **handle) {
+    std::shared_ptr<IConnection> connection;
+    if (mLocal) {
+        connection = mLocalConnection;
+    } else {
+        connection = mRemoteConnection;
+    }
+    std::vector<FetchInfo> infos;
+    std::vector<FetchResult> results;
+    infos.emplace_back(FetchInfo{ToAidl(transactionId), ToAidl(bufferId)});
+    ndk::ScopedAStatus status = connection->fetch(infos, &results);
+    if (!status.isOk()) {
+        BufferPoolStatus svcSpecific = status.getServiceSpecificError();
+        return svcSpecific ? svcSpecific : ResultStatus::CRITICAL_ERROR;
+    }
+    if (results[0].getTag() == FetchResult::buffer) {
+        *handle = ::android::dupFromAidl(results[0].get<FetchResult::buffer>().buffer);
+        return ResultStatus::OK;
+    }
+    return results[0].get<FetchResult::failure>();
+}
+
+
+BufferPoolClient::BufferPoolClient(const std::shared_ptr<Accessor> &accessor,
+                                   const std::shared_ptr<IObserver> &observer) {
+    mImpl = std::make_shared<Impl>(accessor, observer);
+}
+
+BufferPoolClient::BufferPoolClient(const std::shared_ptr<IAccessor> &accessor,
+                                   const std::shared_ptr<IObserver> &observer) {
+    mImpl = std::make_shared<Impl>(accessor, observer);
+}
+
+BufferPoolClient::~BufferPoolClient() {
+    // TODO: how to handle orphaned buffers?
+}
+
+bool BufferPoolClient::isValid() {
+    return mImpl && mImpl->isValid();
+}
+
+bool BufferPoolClient::isLocal() {
+    return mImpl && mImpl->isLocal();
+}
+
+bool BufferPoolClient::isActive(int64_t *lastTransactionMs, bool clearCache) {
+    if (!isValid()) {
+        *lastTransactionMs = 0;
+        return false;
+    }
+    return mImpl->isActive(lastTransactionMs, clearCache);
+}
+
+ConnectionId BufferPoolClient::getConnectionId() {
+    if (isValid()) {
+        return mImpl->getConnectionId();
+    }
+    return -1;
+}
+
+BufferPoolStatus BufferPoolClient::getAccessor(std::shared_ptr<IAccessor> *accessor) {
+    if (isValid()) {
+        *accessor = mImpl->getAccessor();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
+    ALOGV("bufferpool2 client recv inv %u", msgId);
+    if (isValid()) {
+        mImpl->receiveInvalidation(msgId);
+    }
+}
+
+BufferPoolStatus BufferPoolClient::flush() {
+    if (isValid()) {
+        return mImpl->flush();
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::allocate(
+        const std::vector<uint8_t> &params,
+        native_handle_t **handle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->allocate(params, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampMs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->receive(transactionId, bufferId, timestampMs, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::postSend(
+        ConnectionId receiverId,
+        const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId,
+        int64_t *timestampMs) {
+    if (isValid()) {
+        bool result = mImpl->postSend(
+                buffer->mId, receiverId, transactionId, timestampMs);
+        return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.h b/media/bufferpool/aidl/default/BufferPoolClient.h
new file mode 100644
index 0000000..80fd43e
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPoolClient.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <aidl/android/hardware/media/bufferpool2/IAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/IObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::IAccessor;
+using aidl::android::hardware::media::bufferpool2::IObserver;
+
+struct Accessor;
+
+/**
+ * A buffer pool client for a buffer pool. For a specific buffer pool, at most
+ * one buffer pool client exists per process. This class will not be exposed
+ * outside. A buffer pool client will be used via ClientManager.
+ */
+class BufferPoolClient {
+public:
+    /**
+     * Creates a buffer pool client from a local buffer pool
+     * (via ClientManager#create).
+     */
+    explicit BufferPoolClient(const std::shared_ptr<Accessor> &accessor,
+                              const std::shared_ptr<IObserver> &observer);
+
+    /**
+     * Creates a buffer pool client from a remote buffer pool
+     * (via ClientManager#registerSender).
+     * Note: A buffer pool client created with remote buffer pool cannot
+     * allocate a buffer.
+     */
+    explicit BufferPoolClient(const std::shared_ptr<IAccessor> &accessor,
+                              const std::shared_ptr<IObserver> &observer);
+
+    /** Destructs a buffer pool client. */
+    ~BufferPoolClient();
+
+private:
+    bool isValid();
+
+    bool isLocal();
+
+    bool isActive(int64_t *lastTransactionMs, bool clearCache);
+
+    ConnectionId getConnectionId();
+
+    BufferPoolStatus getAccessor(std::shared_ptr<IAccessor> *accessor);
+
+    void receiveInvalidation(uint32_t msgId);
+
+    BufferPoolStatus flush();
+
+    BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus receive(TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampMs,
+                         native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus postSend(ConnectionId receiver,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampMs);
+
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+
+    friend struct ClientManager;
+    friend struct Observer;
+};
+
+}  // namespace aidl::android::hardware::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferStatus.cpp b/media/bufferpool/aidl/default/BufferStatus.cpp
new file mode 100644
index 0000000..19caa1e
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferStatus.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolStatus"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <time.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatus.h>
+#include "BufferStatus.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::BufferStatus;
+
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
+    return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+}
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
+    if (from < to) {
+        return from <= bufferId && bufferId < to;
+    } else { // wrap happens
+        return from <= bufferId || bufferId < to;
+    }
+}
+
+static constexpr int kNumElementsInQueue = 1024*16;
+static constexpr int kMinElementsToSyncInQueue = 128;
+
+BufferPoolStatus BufferStatusObserver::open(
+        ConnectionId id, StatusDescriptor* fmqDescPtr) {
+    if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
+        ALOGE("connection id collision %lld", (unsigned long long)id);
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    auto queue = std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
+    if (!queue || queue->isValid() == false) {
+        return ResultStatus::NO_MEMORY;
+    }
+    *fmqDescPtr = queue->dupeDesc();
+    auto result = mBufferStatusQueues.insert(
+            std::make_pair(id, std::move(queue)));
+    if (!result.second) {
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+}
+
+BufferPoolStatus BufferStatusObserver::close(ConnectionId id) {
+    if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    mBufferStatusQueues.erase(id);
+    return ResultStatus::OK;
+}
+
+void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
+    for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
+        BufferStatusMessage message;
+        size_t avail = it->second->availableToRead();
+        while (avail > 0) {
+            if (!it->second->read(&message, 1)) {
+                // Since available # of reads are already confirmed,
+                // this should not happen.
+                // TODO: error handling (spurious client?)
+                ALOGW("FMQ message cannot be read from %lld", (long long)it->first);
+                return;
+            }
+            message.connectionId = it->first;
+            messages.push_back(message);
+            --avail;
+        }
+    }
+}
+
+BufferStatusChannel::BufferStatusChannel(
+        const StatusDescriptor &fmqDesc) {
+    auto queue = std::make_unique<BufferStatusQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferStatusQueue = std::move(queue);
+}
+
+bool BufferStatusChannel::isValid() {
+    return mValid;
+}
+
+bool BufferStatusChannel::needsSync() {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        return avail + kMinElementsToSyncInQueue < kNumElementsInQueue;
+    }
+    return false;
+}
+
+void BufferStatusChannel::postBufferRelease(
+        ConnectionId connectionId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid && pending.size() > 0) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        avail = std::min(avail, pending.size());
+        BufferStatusMessage message;
+        for (size_t i = 0 ; i < avail; ++i) {
+            BufferId id = pending.front();
+            message.status = BufferStatus::NOT_USED;
+            message.bufferId = id;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since available # of writes are already confirmed,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return;
+            }
+            pending.pop_front();
+            posted.push_back(id);
+        }
+    }
+}
+
+void BufferStatusChannel::postBufferInvalidateAck(
+        ConnectionId connectionId,
+        uint32_t invalidateId,
+        bool *invalidated) {
+    if (mValid && !*invalidated) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        if (avail > 0) {
+            BufferStatusMessage message;
+            message.status = BufferStatus::INVALIDATION_ACK;
+            message.bufferId = invalidateId;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since available # of writes are already confirmed,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return;
+            }
+            *invalidated = true;
+        }
+    }
+}
+
+bool BufferStatusChannel::postBufferStatusMessage(
+        TransactionId transactionId, BufferId bufferId,
+        BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        size_t numPending = pending.size();
+        if (avail >= numPending + 1) {
+            BufferStatusMessage release, message;
+            for (size_t i = 0; i < numPending; ++i) {
+                BufferId id = pending.front();
+                release.status = BufferStatus::NOT_USED;
+                release.bufferId = id;
+                release.connectionId = connectionId;
+                if (!mBufferStatusQueue->write(&release, 1)) {
+                    // Since available # of writes are already confirmed,
+                    // this should not happen.
+                    // TODO: error handling?
+                    ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                    return false;
+                }
+                pending.pop_front();
+                posted.push_back(id);
+            }
+            message.transactionId = transactionId;
+            message.bufferId = bufferId;
+            message.status = status;
+            message.connectionId = connectionId;
+            message.targetConnectionId = targetId;
+            // TODO : timesatamp
+            message.timestampUs = 0;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since available # of writes are already confirmed,
+                // this should not happen.
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return false;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+BufferInvalidationListener::BufferInvalidationListener(
+        const InvalidationDescriptor &fmqDesc) {
+    std::unique_ptr<BufferInvalidationQueue> queue =
+            std::make_unique<BufferInvalidationQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferInvalidationQueue = std::move(queue);
+    // drain previous messages
+    size_t avail = std::min(
+            mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+    std::vector<BufferInvalidationMessage> temp(avail);
+    if (avail > 0) {
+        mBufferInvalidationQueue->read(temp.data(), avail);
+    }
+}
+
+void BufferInvalidationListener::getInvalidations(
+        std::vector<BufferInvalidationMessage> &messages) {
+    // Try twice in case of overflow.
+    // TODO: handling overflow though it may not happen.
+    for (int i = 0; i < 2; ++i) {
+        size_t avail = std::min(
+                mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+        if (avail > 0) {
+            std::vector<BufferInvalidationMessage> temp(avail);
+            if (mBufferInvalidationQueue->read(temp.data(), avail)) {
+                messages.reserve(messages.size() + avail);
+                for (auto it = temp.begin(); it != temp.end(); ++it) {
+                    messages.push_back(*it);
+                }
+                break;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+bool BufferInvalidationListener::isValid() {
+    return mValid;
+}
+
+BufferInvalidationChannel::BufferInvalidationChannel()
+    : mValid(true),
+      mBufferInvalidationQueue(
+              std::make_unique<BufferInvalidationQueue>(kNumElementsInQueue, true)) {
+    if (!mBufferInvalidationQueue || mBufferInvalidationQueue->isValid() == false) {
+        mValid = false;
+    }
+}
+
+bool BufferInvalidationChannel::isValid() {
+    return mValid;
+}
+
+void BufferInvalidationChannel::getDesc(InvalidationDescriptor *fmqDescPtr) {
+    if (mValid) {
+        *fmqDescPtr = mBufferInvalidationQueue->dupeDesc();
+    }
+    // TODO: writing invalid descriptor?
+}
+
+void BufferInvalidationChannel::postInvalidation(
+        uint32_t msgId, BufferId fromId, BufferId toId) {
+    BufferInvalidationMessage message;
+
+    message.messageId = msgId;
+    message.fromBufferId = fromId;
+    message.toBufferId = toId;
+    // TODO: handle failure (it does not happen normally.)
+    mBufferInvalidationQueue->write(&message);
+}
+
+}  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/BufferStatus.h b/media/bufferpool/aidl/default/BufferStatus.h
new file mode 100644
index 0000000..3dd92f4
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferStatus.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <bufferpool2/BufferPoolTypes.h>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <list>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId);
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId);
+
+/**
+ * A collection of buffer status message FMQ for a buffer pool. buffer
+ * ownership/status change messages are sent via the FMQs from the clients.
+ */
+class BufferStatusObserver {
+private:
+    std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
+            mBufferStatusQueues;
+
+public:
+    /** Creates a buffer status message FMQ for the specified
+     * connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     * @param fmqDescPtr    ptr of created FMQ's descriptor.
+     *
+     * @return OK if FMQ is created successfully.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus open(ConnectionId id, StatusDescriptor* _Nonnull fmqDescPtr);
+
+    /** Closes a buffer status message FMQ for the specified
+     * connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     *
+     * @return OK if the specified connection is closed successfully.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus close(ConnectionId id);
+
+    /** Retrieves all pending FMQ buffer status messages from clients.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
+};
+
+/**
+ * A buffer status message FMQ for a buffer pool client. Buffer ownership/status
+ * change messages are sent via the fmq to the buffer pool.
+ */
+class BufferStatusChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
+
+public:
+    /**
+     * Connects to a buffer status message FMQ from a descriptor of
+     * the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferStatusChannel(const StatusDescriptor &fmqDesc);
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+
+    /** Returns whether the FMQ needs to be synced from the buffer pool */
+    bool needsSync();
+
+    /**
+     * Posts a buffer release message to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     */
+    void postBufferRelease(
+            ConnectionId connectionId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer status message regarding the specified buffer
+     * transfer transaction.
+     *
+     * @param transactionId Id of the specified transaction.
+     * @param bufferId      buffer Id of the specified transaction.
+     * @param status        new status of the buffer.
+     * @param connectionId  connection Id of the client.
+     * @param targetId      connection Id of the receiver(only when the sender
+     *                      posts a status message).
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     *
+     * @return {@code true} when the specified message is posted,
+     *         {@code false} otherwise.
+     */
+    bool postBufferStatusMessage(
+            TransactionId transactionId,
+            BufferId bufferId,
+            BufferStatus status,
+            ConnectionId connectionId,
+            ConnectionId targetId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer invaliadation message to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param invalidateId  invalidation ack to the buffer pool.
+     *                      if invalidation id is zero, the ack will not be
+     *                      posted.
+     * @param invalidated   sets {@code true} only when the invalidation ack is
+     *                      posted.
+     */
+    void postBufferInvalidateAck(
+            ConnectionId connectionId,
+            uint32_t invalidateId,
+            bool* _Nonnull invalidated);
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool client. Buffer invalidation
+ * messages are received via the fmq from the buffer pool. Buffer invalidation
+ * messages are handled as soon as possible.
+ */
+class BufferInvalidationListener {
+private:
+    bool mValid;
+    std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+    /**
+     * Connects to a buffer invalidation FMQ from a descriptor of the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferInvalidationListener(const InvalidationDescriptor &fmqDesc);
+
+    /** Retrieves all pending buffer invalidation messages from the buffer pool.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getInvalidations(std::vector<BufferInvalidationMessage> &messages);
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool. A buffer pool will send buffer
+ * invalidation messages to the clients via the FMQ. The FMQ is shared among
+ * buffer pool clients.
+ */
+class BufferInvalidationChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+    /**
+     * Creates a buffer invalidation FMQ for a buffer pool.
+     */
+    BufferInvalidationChannel();
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+
+    /**
+     * Retrieves the descriptor of a buffer invalidation FMQ. the descriptor may
+     * be passed to the client for buffer invalidation handling.
+     *
+     * @param fmqDescPtr    ptr of created FMQ's descriptor.
+     */
+    void getDesc(InvalidationDescriptor* _Nonnull fmqDescPtr);
+
+    /** Posts a buffer invalidation for invalidated buffers.
+     *
+     * @param msgId     Invalidation message id which is used when clients send
+     *                  acks back via BufferStatusMessage
+     * @param fromId    The start bufferid of the invalidated buffers(inclusive)
+     * @param toId      The end bufferId of the invalidated buffers(inclusive)
+     */
+    void postInvalidation(uint32_t msgId, BufferId fromId, BufferId toId);
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/ClientManager.cpp b/media/bufferpool/aidl/default/ClientManager.cpp
new file mode 100644
index 0000000..de1db50
--- /dev/null
+++ b/media/bufferpool/aidl/default/ClientManager.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolMgr"
+//#define LOG_NDEBUG 0
+
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <sys/types.h>
+#include <utils/SystemClock.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include <chrono>
+
+#include "BufferPoolClient.h"
+#include "Observer.h"
+#include "Accessor.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using namespace std::chrono_literals;
+
+using Registration = aidl::android::hardware::media::bufferpool2::IClientManager::Registration;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+
+static constexpr int64_t kRegisterTimeoutMs = 500; // 0.5 sec
+static constexpr int64_t kCleanUpDurationMs = 1000; // TODO: 1 sec tune
+static constexpr int64_t kClientTimeoutMs = 5000; // TODO: 5 secs tune
+
+class ClientManager::Impl {
+public:
+    Impl();
+
+    // BnRegisterSender
+    BufferPoolStatus registerSender(const std::shared_ptr<IAccessor> &accessor,
+                                Registration *pRegistration);
+
+    // BpRegisterSender
+    BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
+                                ConnectionId senderId,
+                                ConnectionId *receiverId,
+                                bool *isNew);
+
+    BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+                        ConnectionId *pConnectionId);
+
+    BufferPoolStatus close(ConnectionId connectionId);
+
+    BufferPoolStatus flush(ConnectionId connectionId);
+
+    BufferPoolStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampMs,
+                         native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus postSend(ConnectionId receiverId,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampMs);
+
+    BufferPoolStatus getAccessor(ConnectionId connectionId,
+                             std::shared_ptr<IAccessor> *accessor);
+
+    void cleanUp(bool clearCache = false);
+
+private:
+    // In order to prevent deadlock between multiple locks,
+    // always lock ClientCache.lock before locking ActiveClients.lock.
+    struct ClientCache {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed while holding the lock.
+        std::mutex mMutex;
+        std::list<std::pair<const std::weak_ptr<IAccessor>, const std::weak_ptr<BufferPoolClient>>>
+                mClients;
+        std::condition_variable mConnectCv;
+        bool mConnecting;
+        int64_t mLastCleanUpMs;
+
+        ClientCache() : mConnecting(false), mLastCleanUpMs(::android::elapsedRealtime()) {}
+    } mCache;
+
+    // Active clients which can be retrieved via ConnectionId
+    struct ActiveClients {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed holding the lock.
+        std::mutex mMutex;
+        std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
+                mClients;
+    } mActive;
+
+    std::shared_ptr<Observer> mObserver;
+};
+
+ClientManager::Impl::Impl()
+    : mObserver(::ndk::SharedRefBase::make<Observer>()) {}
+
+BufferPoolStatus ClientManager::Impl::registerSender(
+        const std::shared_ptr<IAccessor> &accessor, Registration *pRegistration) {
+    cleanUp();
+    int64_t timeoutMs = ::android::elapsedRealtime() + kRegisterTimeoutMs;
+    do {
+        std::unique_lock<std::mutex> lock(mCache.mMutex);
+        for (auto it = mCache.mClients.begin(); it != mCache.mClients.end(); ++it) {
+            std::shared_ptr<IAccessor> sAccessor = it->first.lock();
+            if (sAccessor && sAccessor.get() == accessor.get()) {
+                const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+                if (client) {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    pRegistration->connectionId = client->getConnectionId();
+                    if (mActive.mClients.find(pRegistration->connectionId)
+                            != mActive.mClients.end()) {
+                        ALOGV("register existing connection %lld",
+                              (long long)pRegistration->connectionId);
+                        pRegistration->isNew = false;
+                        return ResultStatus::OK;
+                    }
+                }
+                mCache.mClients.erase(it);
+                break;
+            }
+        }
+        if (!mCache.mConnecting) {
+            mCache.mConnecting = true;
+            lock.unlock();
+            BufferPoolStatus result = ResultStatus::OK;
+            const std::shared_ptr<BufferPoolClient> client =
+                    std::make_shared<BufferPoolClient>(accessor, mObserver);
+            lock.lock();
+            if (!client) {
+                result = ResultStatus::NO_MEMORY;
+            } else if (!client->isValid()) {
+                result = ResultStatus::CRITICAL_ERROR;
+            }
+            if (result == ResultStatus::OK) {
+                // TODO: handle insert fail. (malloc fail)
+                const std::weak_ptr<BufferPoolClient> wclient = client;
+                mCache.mClients.push_back(std::make_pair(accessor, wclient));
+                ConnectionId conId = client->getConnectionId();
+                mObserver->addClient(conId, wclient);
+                {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    mActive.mClients.insert(std::make_pair(conId, client));
+                }
+                pRegistration->connectionId = conId;
+                pRegistration->isNew = true;
+                ALOGV("register new connection %lld", (long long)conId);
+            }
+            mCache.mConnecting = false;
+            lock.unlock();
+            mCache.mConnectCv.notify_all();
+            return result;
+        }
+        mCache.mConnectCv.wait_for(lock, kRegisterTimeoutMs*1ms);
+    } while (::android::elapsedRealtime() < timeoutMs);
+    // TODO: return timeout error
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::Impl::registerSender(
+        const std::shared_ptr<IClientManager> &receiver,
+        ConnectionId senderId,
+        ConnectionId *receiverId,
+        bool *isNew) {
+    std::shared_ptr<IAccessor> accessor;
+    bool local = false;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(senderId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        it->second->getAccessor(&accessor);
+        local = it->second->isLocal();
+    }
+    if (accessor) {
+        Registration registration;
+        ::ndk::ScopedAStatus status = receiver->registerSender(accessor, &registration);
+        if (!status.isOk()) {
+            return ResultStatus::CRITICAL_ERROR;
+        } else if (local) {
+            std::shared_ptr<ConnectionDeathRecipient> recipient =
+                    Accessor::getConnectionDeathRecipient();
+            if (recipient)  {
+                ALOGV("client death recipient registered %lld", (long long)*receiverId);
+                recipient->addCookieToConnection(receiver->asBinder().get(), *receiverId);
+                AIBinder_linkToDeath(receiver->asBinder().get(), recipient->getRecipient(),
+                                     receiver->asBinder().get());
+            }
+        }
+        *receiverId = registration.connectionId;
+        *isNew = registration.isNew;
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::Impl::create(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        ConnectionId *pConnectionId) {
+    std::shared_ptr<Accessor> accessor = ::ndk::SharedRefBase::make<Accessor>(allocator);
+    if (!accessor || !accessor->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    // TODO: observer is local. use direct call instead of hidl call.
+    std::shared_ptr<BufferPoolClient> client =
+            std::make_shared<BufferPoolClient>(accessor, mObserver);
+    if (!client || !client->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    // Since a new bufferpool is created, evict memories which are used by
+    // existing bufferpools and clients.
+    cleanUp(true);
+    {
+        // TODO: handle insert fail. (malloc fail)
+        std::lock_guard<std::mutex> lock(mCache.mMutex);
+        const std::weak_ptr<BufferPoolClient> wclient = client;
+        mCache.mClients.push_back(std::make_pair(accessor, wclient));
+        ConnectionId conId = client->getConnectionId();
+        mObserver->addClient(conId, wclient);
+        {
+            std::lock_guard<std::mutex> lock(mActive.mMutex);
+            mActive.mClients.insert(std::make_pair(conId, client));
+        }
+        *pConnectionId = conId;
+        ALOGV("create new connection %lld", (long long)*pConnectionId);
+    }
+    return ResultStatus::OK;
+}
+
+BufferPoolStatus ClientManager::Impl::close(ConnectionId connectionId) {
+    std::unique_lock<std::mutex> lock1(mCache.mMutex);
+    std::unique_lock<std::mutex> lock2(mActive.mMutex);
+    auto it = mActive.mClients.find(connectionId);
+    if (it != mActive.mClients.end()) {
+        std::shared_ptr<IAccessor> accessor;
+        it->second->getAccessor(&accessor);
+        std::shared_ptr<BufferPoolClient> closing = it->second;
+        mActive.mClients.erase(connectionId);
+        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+            // clean up dead client caches
+            std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
+            if (!cAccessor || (accessor && cAccessor.get() ==  accessor.get())) {
+                cit = mCache.mClients.erase(cit);
+            } else {
+                cit++;
+            }
+        }
+        lock2.unlock();
+        lock1.unlock();
+        closing->flush();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::NOT_FOUND;
+}
+
+BufferPoolStatus ClientManager::Impl::flush(ConnectionId connectionId) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->flush();
+}
+
+BufferPoolStatus ClientManager::Impl::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+    native_handle_t *origHandle;
+    BufferPoolStatus res = client->allocate(params, &origHandle, buffer);
+    if (res != ResultStatus::OK) {
+        return res;
+    }
+    *handle = native_handle_clone(origHandle);
+    if (handle == NULL) {
+        buffer->reset();
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+#else
+    return client->allocate(params, handle, buffer);
+#endif
+}
+
+BufferPoolStatus ClientManager::Impl::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampMs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+    native_handle_t *origHandle;
+    BufferPoolStatus res = client->receive(
+            transactionId, bufferId, timestampMs, &origHandle, buffer);
+    if (res != ResultStatus::OK) {
+        return res;
+    }
+    *handle = native_handle_clone(origHandle);
+    if (handle == NULL) {
+        buffer->reset();
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+#else
+    return client->receive(transactionId, bufferId, timestampMs, handle, buffer);
+#endif
+}
+
+BufferPoolStatus ClientManager::Impl::postSend(
+        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId, int64_t *timestampMs) {
+    ConnectionId connectionId = buffer->mConnectionId;
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->postSend(receiverId, buffer, transactionId, timestampMs);
+}
+
+BufferPoolStatus ClientManager::Impl::getAccessor(
+        ConnectionId connectionId, std::shared_ptr<IAccessor> *accessor) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->getAccessor(accessor);
+}
+
+void ClientManager::Impl::cleanUp(bool clearCache) {
+    int64_t now = ::android::elapsedRealtime();
+    int64_t lastTransactionMs;
+    std::lock_guard<std::mutex> lock1(mCache.mMutex);
+    if (clearCache || mCache.mLastCleanUpMs + kCleanUpDurationMs < now) {
+        std::lock_guard<std::mutex> lock2(mActive.mMutex);
+        int cleaned = 0;
+        for (auto it = mActive.mClients.begin(); it != mActive.mClients.end();) {
+            if (!it->second->isActive(&lastTransactionMs, clearCache)) {
+                if (lastTransactionMs + kClientTimeoutMs < now) {
+                  std::shared_ptr<IAccessor> accessor;
+                    it->second->getAccessor(&accessor);
+                    it = mActive.mClients.erase(it);
+                    ++cleaned;
+                    continue;
+                }
+            }
+            ++it;
+        }
+        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+            // clean up dead client caches
+          std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
+            if (!cAccessor) {
+                cit = mCache.mClients.erase(cit);
+            } else {
+                ++cit;
+            }
+        }
+        ALOGV("# of cleaned connections: %d", cleaned);
+        mCache.mLastCleanUpMs = now;
+    }
+}
+
+::ndk::ScopedAStatus ClientManager::registerSender(
+        const std::shared_ptr<IAccessor>& in_bufferPool, Registration* _aidl_return) {
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    if (mImpl) {
+        status = mImpl->registerSender(in_bufferPool, _aidl_return);
+    }
+    if (status != ResultStatus::OK) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+// Methods for local use.
+std::shared_ptr<ClientManager> ClientManager::sInstance;
+std::mutex ClientManager::sInstanceLock;
+
+std::shared_ptr<ClientManager> ClientManager::getInstance() {
+    std::lock_guard<std::mutex> lock(sInstanceLock);
+    if (!sInstance) {
+        sInstance = ::ndk::SharedRefBase::make<ClientManager>();
+        // TODO: configure thread count for threadpool properly
+        // after b/261652496 is resolved.
+    }
+    Accessor::createInvalidator();
+    Accessor::createEvictor();
+    return sInstance;
+}
+
+ClientManager::ClientManager() : mImpl(new Impl()) {}
+
+ClientManager::~ClientManager() {
+}
+
+BufferPoolStatus ClientManager::create(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        ConnectionId *pConnectionId) {
+    if (mImpl) {
+        return mImpl->create(allocator, pConnectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::registerSender(
+        const std::shared_ptr<IClientManager> &receiver,
+        ConnectionId senderId,
+        ConnectionId *receiverId,
+        bool *isNew) {
+    if (mImpl) {
+        return mImpl->registerSender(receiver, senderId, receiverId, isNew);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::close(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->close(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::flush(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->flush(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->allocate(connectionId, params, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampMs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->receive(connectionId, transactionId, bufferId,
+                              timestampMs, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::postSend(
+        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId, int64_t* timestampMs) {
+    if (mImpl && buffer) {
+        return mImpl->postSend(receiverId, buffer, transactionId, timestampMs);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void ClientManager::cleanUp() {
+    if (mImpl) {
+        mImpl->cleanUp(true);
+    }
+}
+
+}  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Connection.cpp b/media/bufferpool/aidl/default/Connection.cpp
new file mode 100644
index 0000000..53d350d
--- /dev/null
+++ b/media/bufferpool/aidl/default/Connection.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolCon"
+//#define LOG_NDEBUG 0
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+#include "Connection.h"
+#include "Accessor.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using Buffer = aidl::android::hardware::media::bufferpool2::Buffer;
+using FetchInfo = aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo;
+using FetchResult = aidl::android::hardware::media::bufferpool2::IConnection::FetchResult;
+
+::ndk::ScopedAStatus Connection::fetch(const std::vector<FetchInfo>& in_fetchInfos,
+                           std::vector<FetchResult>* _aidl_return) {
+    int success = 0;
+    int failure = 0;
+    if (mInitialized && mAccessor) {
+        for (auto it = in_fetchInfos.begin(); it != in_fetchInfos.end(); ++it) {
+            if (fetch(it->transactionId, it->bufferId, _aidl_return)) {
+                success++;
+            } else {
+                failure++;
+            }
+        }
+        if (failure > 0) {
+            ALOGD("total fetch %d, failure %d", success + failure, failure);
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(ResultStatus::CRITICAL_ERROR);
+}
+
+::ndk::ScopedAStatus Connection::sync() {
+    if (mInitialized && mAccessor) {
+        mAccessor->cleanUp(false);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+
+bool Connection::fetch(TransactionId transactionId, BufferId bufferId,
+                       std::vector<FetchResult> *result) {
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    const native_handle_t *handle = nullptr;
+    status = mAccessor->fetch(
+            mConnectionId, transactionId, bufferId, &handle);
+    if (status == ResultStatus::OK) {
+        result->emplace_back(FetchResult::make<FetchResult::buffer>());
+        result->back().get<FetchResult::buffer>().id = bufferId;
+        result->back().get<FetchResult::buffer>().buffer = ::android::dupToAidl(handle);
+        return true;
+    }
+    result->emplace_back(FetchResult::make<FetchResult::failure>(status));
+    return false;
+}
+
+Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
+
+Connection::~Connection() {
+    if (mInitialized && mAccessor) {
+        mAccessor->close(mConnectionId);
+    }
+}
+
+void Connection::initialize(
+        const std::shared_ptr<Accessor>& accessor, ConnectionId connectionId) {
+    if (!mInitialized) {
+        mAccessor = accessor;
+        mConnectionId = connectionId;
+        mInitialized = true;
+    }
+}
+
+BufferPoolStatus Connection::flush() {
+    if (mInitialized && mAccessor) {
+        return mAccessor->flush();
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus Connection::allocate(
+        const std::vector<uint8_t> &params, BufferId *bufferId,
+        const native_handle_t **handle) {
+    if (mInitialized && mAccessor) {
+        return mAccessor->allocate(mConnectionId, params, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void Connection::cleanUp(bool clearCache) {
+    if (mInitialized && mAccessor) {
+        mAccessor->cleanUp(clearCache);
+    }
+}
+
+}  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Connection.h b/media/bufferpool/aidl/default/Connection.h
new file mode 100644
index 0000000..d8298af
--- /dev/null
+++ b/media/bufferpool/aidl/default/Connection.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <aidl/android/hardware/media/bufferpool2/BnConnection.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+struct Accessor;
+
+struct Connection : public BnConnection {
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IConnection.
+    ::ndk::ScopedAStatus fetch(const std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo>& in_fetchInfos, std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchResult>* _aidl_return) override;
+
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IConnection.
+    ::ndk::ScopedAStatus sync() override;
+
+    /**
+     * Invalidates all buffers which are active and/or are ready to be recycled.
+     */
+    BufferPoolStatus flush();
+
+    /**
+     * Allocates a buffer using the specified parameters. Recycles a buffer if
+     * it is possible. The returned buffer can be transferred to other remote
+     * clients(Connection).
+     *
+     * @param params    allocation parameters.
+     * @param bufferId  Id of the allocated buffer.
+     * @param handle    native handle of the allocated buffer.
+     *
+     * @return OK if a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                          BufferId *bufferId, const native_handle_t **handle);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache cleaning
+     * from bufferpool.
+     *
+     * @param clearCache    if clearCache is true, bufferpool frees all buffers
+     *                      waiting to be recycled.
+     */
+    void cleanUp(bool clearCache);
+
+    /** Destructs a connection. */
+    ~Connection();
+
+    /** Creates a connection. */
+    Connection();
+
+    /**
+     * Initializes with the specified buffer pool and the connection id.
+     * The connection id should be unique in the whole system.
+     *
+     * @param accessor      the specified buffer pool.
+     * @param connectionId  Id.
+     */
+    void initialize(const std::shared_ptr<Accessor> &accessor, ConnectionId connectionId);
+
+    enum : uint32_t {
+        SYNC_BUFFERID = UINT32_MAX,
+    };
+
+private:
+    bool mInitialized;
+    std::shared_ptr<Accessor> mAccessor;
+    ConnectionId mConnectionId;
+
+    bool fetch(
+        uint64_t transactionId,
+        uint32_t bufferId,
+        std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchResult>
+                *result);
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/DataHelper.h b/media/bufferpool/aidl/default/DataHelper.h
new file mode 100644
index 0000000..a90b3c7
--- /dev/null
+++ b/media/bufferpool/aidl/default/DataHelper.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+#include <map>
+#include <set>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter == mapOfSet->end()) {
+        std::set<U> valueSet{value};
+        mapOfSet->insert(std::make_pair(key, valueSet));
+        return true;
+    } else if (iter->second.find(value)  == iter->second.end()) {
+        iter->second.insert(value);
+        return true;
+    }
+    return false;
+}
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    bool ret = false;
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        if (iter->second.erase(value) > 0) {
+            ret = true;
+        }
+        if (iter->second.size() == 0) {
+            mapOfSet->erase(iter);
+        }
+    }
+    return ret;
+}
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        auto setIter = iter->second.find(value);
+        return setIter != iter->second.end();
+    }
+    return false;
+}
+
+// Buffer data structure for internal BufferPool use.(storage/fetching)
+struct InternalBuffer {
+    BufferId mId;
+    size_t mOwnerCount;
+    size_t mTransactionCount;
+    const std::shared_ptr<BufferPoolAllocation> mAllocation;
+    const size_t mAllocSize;
+    const std::vector<uint8_t> mConfig;
+    bool mInvalidated;
+
+    InternalBuffer(
+            BufferId id,
+            const std::shared_ptr<BufferPoolAllocation> &alloc,
+            const size_t allocSize,
+            const std::vector<uint8_t> &allocConfig)
+            : mId(id), mOwnerCount(0), mTransactionCount(0),
+            mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
+            mInvalidated(false) {}
+
+    const native_handle_t *handle() {
+        return mAllocation->handle();
+    }
+
+    void invalidate() {
+        mInvalidated = true;
+    }
+};
+
+// Buffer transacion status/message data structure for internal BufferPool use.
+struct TransactionStatus {
+    TransactionId mId;
+    BufferId mBufferId;
+    ConnectionId mSender;
+    ConnectionId mReceiver;
+    BufferStatus mStatus;
+    int64_t mTimestampMs;
+    bool mSenderValidated;
+
+    TransactionStatus(const BufferStatusMessage &message, int64_t timestampMs) {
+        mId = message.transactionId;
+        mBufferId = message.bufferId;
+        mStatus = message.status;
+        mTimestampMs = timestampMs;
+        if (mStatus == BufferStatus::TRANSFER_TO) {
+            mSender = message.connectionId;
+            mReceiver = message.targetConnectionId;
+            mSenderValidated = true;
+        } else {
+            mSender = -1LL;
+            mReceiver = message.connectionId;
+            mSenderValidated = false;
+        }
+    }
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Observer.cpp b/media/bufferpool/aidl/default/Observer.cpp
new file mode 100644
index 0000000..a22e825
--- /dev/null
+++ b/media/bufferpool/aidl/default/Observer.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Observer.h"
+#include "BufferPoolClient.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+Observer::Observer() {
+}
+
+Observer::~Observer() {
+}
+
+::ndk::ScopedAStatus Observer::onMessage(int64_t in_connectionId, int32_t in_msgId) {
+    std::unique_lock<std::mutex> lock(mLock);
+    auto it = mClients.find(in_connectionId);
+    if (it != mClients.end()) {
+        const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+        if (!client) {
+            mClients.erase(it);
+        } else {
+            lock.unlock();
+            client->receiveInvalidation(in_msgId);
+        }
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+void Observer::addClient(ConnectionId connectionId,
+                         const std::weak_ptr<BufferPoolClient> &wclient) {
+    std::lock_guard<std::mutex> lock(mLock);
+    for (auto it = mClients.begin(); it != mClients.end();) {
+        if (!it->second.lock() || it->first == connectionId) {
+            it = mClients.erase(it);
+        } else {
+            ++it;
+        }
+    }
+    mClients.insert(std::make_pair(connectionId, wclient));
+
+}
+
+void Observer::delClient(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mClients.erase(connectionId);
+}
+
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Observer.h b/media/bufferpool/aidl/default/Observer.h
new file mode 100644
index 0000000..febb21b
--- /dev/null
+++ b/media/bufferpool/aidl/default/Observer.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <aidl/android/hardware/media/bufferpool2/BnObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+class BufferPoolClient;
+
+struct Observer : public BnObserver {
+    ::ndk::ScopedAStatus onMessage(int64_t in_connectionId, int32_t in_msgId) override;
+
+    ~Observer();
+
+    void addClient(ConnectionId connectionId,
+                   const std::weak_ptr<BufferPoolClient> &wclient);
+
+    void delClient(ConnectionId connectionId);
+
+private:
+    Observer();
+
+    friend class ::ndk::SharedRefBase;
+
+    std::mutex mLock;
+    std::map<ConnectionId, const std::weak_ptr<BufferPoolClient>> mClients;
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h b/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h
new file mode 100644
index 0000000..b833362
--- /dev/null
+++ b/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cutils/native_handle.h>
+#include <fmq/AidlMessageQueue.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferInvalidationMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+
+namespace aidl::android::hardware::media::bufferpool2 {
+
+struct BufferPoolData {
+    // For local use, to specify a bufferpool (client connection) for buffers.
+    // Retrieved from returned info of IAccessor#connect(android.hardware.media.bufferpool@2.0).
+    int64_t mConnectionId;
+    // BufferId
+    uint32_t mId;
+
+    BufferPoolData() : mConnectionId(0), mId(0) {}
+
+    BufferPoolData(
+            int64_t connectionId, uint32_t id)
+            : mConnectionId(connectionId), mId(id) {}
+
+    ~BufferPoolData() {}
+};
+
+namespace implementation {
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
+
+using aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+using aidl::android::hardware::media::bufferpool2::BufferInvalidationMessage;
+
+typedef uint32_t BufferId;
+typedef uint64_t TransactionId;
+typedef int64_t ConnectionId;
+typedef int32_t BufferPoolStatus;
+
+// AIDL hal description language does not support unsigned.
+int32_t static inline ToAidl(BufferId id) {return static_cast<int32_t>(id);}
+int64_t static inline ToAidl(TransactionId id) {return static_cast<int64_t>(id);}
+
+BufferId static inline FromAidl(int32_t id) {return static_cast<BufferId>(id);}
+TransactionId static inline FromAidl(int64_t id) {return static_cast<TransactionId>(id);}
+
+enum : ConnectionId {
+    INVALID_CONNECTIONID = 0,
+};
+
+typedef ::android::AidlMessageQueue<BufferStatusMessage, SynchronizedReadWrite> BufferStatusQueue;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<BufferStatusMessage, SynchronizedReadWrite>
+        StatusDescriptor;
+
+typedef ::android::AidlMessageQueue<BufferInvalidationMessage, UnsynchronizedWrite>
+        BufferInvalidationQueue;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<BufferInvalidationMessage, UnsynchronizedWrite>
+        InvalidationDescriptor;
+
+/**
+ * Allocation wrapper class for buffer pool.
+ */
+struct BufferPoolAllocation {
+    const native_handle_t *mHandle;
+
+    const native_handle_t *handle() {
+        return mHandle;
+    }
+
+    BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
+
+    ~BufferPoolAllocation() {};
+};
+
+/**
+ * Allocator wrapper class for buffer pool.
+ */
+class BufferPoolAllocator {
+public:
+
+    /**
+     * Allocate an allocation(buffer) for buffer pool.
+     *
+     * @param params    allocation parameters
+     * @param alloc     created allocation
+     * @param allocSize size of created allocation
+     *
+     * @return OK when an allocation is created successfully.
+     */
+    virtual BufferPoolStatus allocate(
+            const std::vector<uint8_t> &params,
+            std::shared_ptr<BufferPoolAllocation> *alloc,
+            size_t *allocSize) = 0;
+
+    /**
+     * Returns whether allocation parameters of an old allocation are
+     * compatible with new allocation parameters.
+     */
+    virtual bool compatible(const std::vector<uint8_t> &newParams,
+                            const std::vector<uint8_t> &oldParams) = 0;
+
+protected:
+    BufferPoolAllocator() = default;
+
+    virtual ~BufferPoolAllocator() = default;
+};
+
+}  // namespace implementation
+}  // namespace aidl::android::hareware::media::bufferpool2
+
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
new file mode 100644
index 0000000..bff75ba
--- /dev/null
+++ b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/media/bufferpool2/IAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/BnClientManager.h>
+#include <memory>
+#include "BufferPoolTypes.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::BnClientManager;
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::IAccessor;
+
+struct ClientManager : public BnClientManager {
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IClientManager follow.
+    ::ndk::ScopedAStatus registerSender(
+        const std::shared_ptr<IAccessor>& in_bufferPool,
+        ::aidl::android::hardware::media::bufferpool2::IClientManager::Registration* _aidl_return)
+        override;
+
+    /** Gets an instance. */
+    static std::shared_ptr<ClientManager> getInstance();
+
+    /**
+     * Creates a local connection with a newly created buffer pool.
+     *
+     * @param allocator     for new buffer allocation.
+     * @param pConnectionId Id of the created connection. This is
+     *                      system-wide unique.
+     *
+     * @return OK when a buffer pool and a local connection is successfully
+     *         created.
+     *         ResultStatus::NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+                        ConnectionId *pConnectionId);
+
+    /**
+     * Register a created connection as sender for remote process.
+     *
+     * @param receiver      The remote receiving process.
+     * @param senderId      A local connection which will send buffers to.
+     * @param receiverId    Id of the created receiving connection on the receiver
+     *                      process.
+     * @param isNew         @true when the receiving connection is newly created.
+     *
+     * @return OK when the receiving connection is successfully created on the
+     *         receiver process.
+     *         NOT_FOUND when the sender connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
+                                ConnectionId senderId,
+                                ConnectionId *receiverId,
+                                bool *isNew);
+
+    /**
+     * Closes the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus close(ConnectionId connectionId);
+
+    /**
+     * Evicts cached allocations. If it's local connection, release the
+     * previous allocations and do not recycle current active allocations.
+     *
+     * @param connectionId The id of the connection.
+     *
+     * @return OK when the connection is resetted.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus flush(ConnectionId connectionId);
+
+    /**
+     * Allocates a buffer from the specified connection. The output parameter
+     * handle is cloned from the internal handle. So it is safe to use directly,
+     * and it should be deleted and destroyed after use.
+     *
+     * @param connectionId  The id of the connection.
+     * @param params        The allocation parameters.
+     * @param handle        The native handle to the allocated buffer. handle
+     *                      should be cloned before use.
+     * @param buffer        The allocated buffer.
+     *
+     * @return OK when a buffer was allocated successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    /**
+     * Receives a buffer for the transaction. The output parameter handle is
+     * cloned from the internal handle. So it is safe to use directly, and it
+     * should be deleted and destoyed after use.
+     *
+     * @param connectionId  The id of the receiving connection.
+     * @param transactionId The id for the transaction.
+     * @param bufferId      The id for the buffer.
+     * @param timestampMs   The timestamp of the buffer is being sent.
+     * @param handle        The native handle to the allocated buffer. handle
+     *                      should be cloned before use.
+     * @param buffer        The received buffer.
+     *
+     * @return OK when a buffer was received successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampMs,
+                          native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    /**
+     * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
+     * to other remote clients(connection) after this call has been succeeded.
+     *
+     * @param receiverId    The id of the receiving connection.
+     * @param buffer        to transfer
+     * @param transactionId Id of the transfer transaction.
+     * @param timestampMs   The timestamp of the buffer transaction is being
+     *                      posted.
+     *
+     * @return OK when a buffer transaction was posted successfully.
+     *         NOT_FOUND when the sending connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus postSend(ConnectionId receiverId,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampMs);
+
+    /**
+     *  Time out inactive lingering connections and close.
+     */
+    void cleanUp();
+
+    /** Destructs the manager of buffer pool clients.  */
+    ~ClientManager();
+private:
+    static std::shared_ptr<ClientManager> sInstance;
+    static std::mutex sInstanceLock;
+
+    class Impl;
+    const std::unique_ptr<Impl> mImpl;
+
+    friend class ::ndk::SharedRefBase;
+
+    ClientManager();
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/tests/Android.bp b/media/bufferpool/aidl/default/tests/Android.bp
new file mode 100644
index 0000000..549af57
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/Android.bp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsVndkAidlBufferpool2V1_0TargetSingleTest",
+    test_suites: ["device-tests"],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "single.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libstagefright_aidl_bufferpool2"
+    ],
+    compile_multilib: "both",
+}
+
+cc_test {
+    name: "VtsVndkAidlBufferpool2V1_0TargetMultiTest",
+    test_suites: ["device-tests"],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "multi.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libstagefright_aidl_bufferpool2"
+    ],
+    compile_multilib: "both",
+}
+
+cc_test {
+    name: "VtsVndkAidlBufferpool2V1_0TargetCondTest",
+    test_suites: ["device-tests"],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "cond.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libstagefright_aidl_bufferpool2"
+    ],
+    compile_multilib: "both",
+}
diff --git a/media/bufferpool/aidl/default/tests/allocator.cpp b/media/bufferpool/aidl/default/tests/allocator.cpp
new file mode 100644
index 0000000..16b33a6
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/allocator.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/ashmem.h>
+#include <sys/mman.h>
+#include "allocator.h"
+
+union Params {
+  struct {
+    uint32_t capacity;
+  } data;
+  uint8_t array[0];
+  Params() : data{0} {}
+  Params(uint32_t size)
+      : data{size} {}
+};
+
+
+namespace {
+
+struct HandleAshmem : public native_handle_t {
+  HandleAshmem(int ashmemFd, size_t size)
+    : native_handle_t(cHeader),
+    mFds{ ashmemFd },
+    mInts{ int (size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } {}
+
+  int ashmemFd() const { return mFds.mAshmem; }
+  size_t size() const {
+    return size_t(unsigned(mInts.mSizeLo))
+        | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+  }
+
+  static bool isValid(const native_handle_t * const o);
+
+protected:
+  struct {
+    int mAshmem;
+  } mFds;
+  struct {
+    int mSizeLo;
+    int mSizeHi;
+    int mMagic;
+  } mInts;
+
+private:
+  enum {
+    kMagic = 'ahm\x00',
+    numFds = sizeof(mFds) / sizeof(int),
+    numInts = sizeof(mInts) / sizeof(int),
+    version = sizeof(native_handle_t)
+  };
+  const static native_handle_t cHeader;
+};
+
+const native_handle_t HandleAshmem::cHeader = {
+  HandleAshmem::version,
+  HandleAshmem::numFds,
+  HandleAshmem::numInts,
+  {}
+};
+
+bool HandleAshmem::isValid(const native_handle_t * const o) {
+  if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+    return false;
+  }
+  const HandleAshmem *other = static_cast<const HandleAshmem*>(o);
+  return other->mInts.mMagic == kMagic;
+}
+
+class AllocationAshmem {
+private:
+  AllocationAshmem(int ashmemFd, size_t capacity, bool res)
+    : mHandle(ashmemFd, capacity),
+      mInit(res) {}
+
+public:
+  static AllocationAshmem *Alloc(size_t size) {
+    constexpr static const char *kAllocationTag = "bufferpool_test";
+    int ashmemFd = ashmem_create_region(kAllocationTag, size);
+    return new AllocationAshmem(ashmemFd, size, ashmemFd >= 0);
+  }
+
+  ~AllocationAshmem() {
+    if (mInit) {
+      native_handle_close(&mHandle);
+    }
+  }
+
+  const HandleAshmem *handle() {
+    return &mHandle;
+  }
+
+private:
+  HandleAshmem mHandle;
+  bool mInit;
+  // TODO: mapping and map fd
+};
+
+struct AllocationDtor {
+  AllocationDtor(const std::shared_ptr<AllocationAshmem> &alloc)
+      : mAlloc(alloc) {}
+
+  void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+  const std::shared_ptr<AllocationAshmem> mAlloc;
+};
+
+}
+
+void IpcMutex::init() {
+  pthread_mutexattr_t mattr;
+  pthread_mutexattr_init(&mattr);
+  pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
+  pthread_mutex_init(&lock, &mattr);
+  pthread_mutexattr_destroy(&mattr);
+
+  pthread_condattr_t cattr;
+  pthread_condattr_init(&cattr);
+  pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
+  pthread_cond_init(&cond, &cattr);
+  pthread_condattr_destroy(&cattr);
+}
+
+IpcMutex *IpcMutex::Import(void *pMutex) {
+  return reinterpret_cast<IpcMutex *>(pMutex);
+}
+
+
+BufferPoolStatus TestBufferPoolAllocator::allocate(
+    const std::vector<uint8_t> &params,
+    std::shared_ptr<BufferPoolAllocation> *alloc,
+    size_t *allocSize) {
+  Params ashmemParams;
+  memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size()));
+
+  std::shared_ptr<AllocationAshmem> ashmemAlloc =
+      std::shared_ptr<AllocationAshmem>(
+          AllocationAshmem::Alloc(ashmemParams.data.capacity));
+  if (ashmemAlloc) {
+    BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle());
+    if (ptr) {
+      *alloc = std::shared_ptr<BufferPoolAllocation>(ptr, AllocationDtor(ashmemAlloc));
+      if (*alloc) {
+          *allocSize = ashmemParams.data.capacity;
+          return ResultStatus::OK;
+      }
+      delete ptr;
+      return ResultStatus::NO_MEMORY;
+    }
+  }
+  return ResultStatus::CRITICAL_ERROR;
+}
+
+bool TestBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
+                                        const std::vector<uint8_t> &oldParams) {
+  size_t newSize = newParams.size();
+  size_t oldSize = oldParams.size();
+  if (newSize == oldSize) {
+    for (size_t i = 0; i < newSize; ++i) {
+      if (newParams[i] != oldParams[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::Fill(const native_handle_t *handle, const unsigned char val) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  unsigned char *ptr = (unsigned char *)mmap(
+      NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+
+  if (ptr != MAP_FAILED) {
+    for (size_t i = 0; i < o->size(); ++i) {
+      ptr[i] = val;
+    }
+    munmap(ptr, o->size());
+    return true;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  unsigned char *ptr = (unsigned char *)mmap(
+      NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0);
+
+  if (ptr != MAP_FAILED) {
+    bool res = true;
+    for (size_t i = 0; i < o->size(); ++i) {
+      if (ptr[i] != val) {
+        res = false;
+        break;
+      }
+    }
+    munmap(ptr, o->size());
+    return res;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::MapMemoryForMutex(const native_handle_t *handle, void **mem) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  *mem = mmap(
+      NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+  if (*mem == MAP_FAILED || *mem == nullptr) {
+    return false;
+  }
+  return true;
+}
+
+bool TestBufferPoolAllocator::UnmapMemoryForMutex(void *mem) {
+  munmap(mem, sizeof(IpcMutex));
+  return true;
+}
+
+void getTestAllocatorParams(std::vector<uint8_t> *params) {
+  constexpr static int kAllocationSize = 1024 * 10;
+  Params ashmemParams(kAllocationSize);
+
+  params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
+
+void getIpcMutexParams(std::vector<uint8_t> *params) {
+  Params ashmemParams(sizeof(IpcMutex));
+
+  params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
diff --git a/media/bufferpool/aidl/default/tests/allocator.h b/media/bufferpool/aidl/default/tests/allocator.h
new file mode 100644
index 0000000..7e7203f
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/allocator.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <pthread.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+using aidl::android::hardware::media::bufferpool2::implementation::
+    BufferPoolStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::
+    BufferPoolAllocation;
+using aidl::android::hardware::media::bufferpool2::implementation::
+    BufferPoolAllocator;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+
+struct IpcMutex {
+  pthread_mutex_t lock;
+  pthread_cond_t cond;
+  int counter = 0;
+  bool signalled = false;
+
+  void init();
+
+  static IpcMutex *Import(void *mem);
+};
+
+// buffer allocator for the tests
+class TestBufferPoolAllocator : public BufferPoolAllocator {
+ public:
+  TestBufferPoolAllocator() {}
+
+  ~TestBufferPoolAllocator() override {}
+
+  BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                        std::shared_ptr<BufferPoolAllocation> *alloc,
+                        size_t *allocSize) override;
+
+  bool compatible(const std::vector<uint8_t> &newParams,
+                  const std::vector<uint8_t> &oldParams) override;
+
+  static bool Fill(const native_handle_t *handle, const unsigned char val);
+
+  static bool Verify(const native_handle_t *handle, const unsigned char val);
+
+  static bool MapMemoryForMutex(const native_handle_t *handle, void **mem);
+
+  static bool UnmapMemoryForMutex(void *mem);
+};
+
+// retrieve buffer allocator parameters
+void getTestAllocatorParams(std::vector<uint8_t> *params);
+
+void getIpcMutexParams(std::vector<uint8_t> *params);
diff --git a/media/bufferpool/aidl/default/tests/cond.cpp b/media/bufferpool/aidl/default/tests/cond.cpp
new file mode 100644
index 0000000..6d469ce
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/cond.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <android-base/logging.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+const std::string testInstance  = std::string() + ClientManager::descriptor + "/condtest";
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+    INIT_OK = 0,
+    INIT_ERROR,
+    SEND,
+    RECEIVE_OK,
+    RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+    struct  {
+        int32_t command;
+        BufferId bufferId;
+        ConnectionId connectionId;
+        TransactionId transactionId;
+        int64_t  timestampUs;
+    } data;
+    char array[0];
+};
+
+constexpr int kSignalInt = 200;
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    BufferPoolStatus status;
+    mReceiverPid = -1;
+    mConnectionValid = false;
+
+    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+    mReceiverPid = fork();
+    ASSERT_TRUE(mReceiverPid >= 0);
+
+    if (mReceiverPid == 0) {
+      doReceiver();
+      // In order to ignore gtest behaviour, wait for being killed from
+      // tearDown
+      pause();
+    }
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    mConnectionValid = true;
+  }
+
+  virtual void TearDown() override {
+    if (mReceiverPid > 0) {
+      kill(mReceiverPid, SIGKILL);
+      int wstatus;
+      wait(&wstatus);
+    }
+
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  std::shared_ptr<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  pid_t mReceiverPid;
+  int mCommandPipeFds[2];
+  int mResultPipeFds[2];
+
+  bool sendMessage(int *pipes, const PipeMessage &message) {
+    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  bool receiveMessage(int *pipes, PipeMessage *message) {
+    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  void doReceiver() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    PipeMessage message;
+    mManager = ClientManager::getInstance();
+    if (!mManager) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    auto binder = mManager->asBinder();
+    AIBinder_forceDowngradeToSystemStability(binder.get());
+    binder_status_t status =
+        AServiceManager_addService(binder.get(), testInstance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+    if (status != android::OK) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    message.data.command = PipeCommand::INIT_OK;
+    sendMessage(mResultPipeFds, message);
+
+    int val = 0;
+    receiveMessage(mCommandPipeFds, &message);
+    {
+      native_handle_t *rhandle = nullptr;
+      std::shared_ptr<BufferPoolData> rbuffer;
+      void *mem = nullptr;
+      IpcMutex *mutex = nullptr;
+      BufferPoolStatus status = mManager->receive(
+          message.data.connectionId, message.data.transactionId,
+          message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+      mManager->close(message.data.connectionId);
+      if (status != ResultStatus::OK) {
+          message.data.command = PipeCommand::RECEIVE_ERROR;
+          sendMessage(mResultPipeFds, message);
+          return;
+      }
+      if (!TestBufferPoolAllocator::MapMemoryForMutex(rhandle, &mem)) {
+          message.data.command = PipeCommand::RECEIVE_ERROR;
+          sendMessage(mResultPipeFds, message);
+          return;
+      }
+      mutex = IpcMutex::Import(mem);
+      pthread_mutex_lock(&(mutex->lock));
+      while (mutex->signalled != true) {
+          pthread_cond_wait(&(mutex->cond), &(mutex->lock));
+      }
+      val = mutex->counter;
+      pthread_mutex_unlock(&(mutex->lock));
+
+      (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+      if (rhandle) {
+        native_handle_close(rhandle);
+        native_handle_delete(rhandle);
+      }
+    }
+    if (val == kSignalInt) {
+      message.data.command = PipeCommand::RECEIVE_OK;
+    } else {
+      message.data.command = PipeCommand::RECEIVE_ERROR;
+    }
+    sendMessage(mResultPipeFds, message);
+  }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+  BufferPoolStatus status;
+  PipeMessage message;
+
+  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+  ABinderProcess_setThreadPoolMaxThreadCount(1);
+  ABinderProcess_startThreadPool();
+
+
+  std::shared_ptr<IClientManager> receiver =
+      IClientManager::fromBinder(
+          ndk::SpAIBinder(AServiceManager_waitForService(testInstance.c_str())));
+  ASSERT_NE(receiver, nullptr);
+  ConnectionId receiverId;
+
+  bool isNew = true;
+  status = mManager->registerSender(receiver, mConnectionId, &receiverId, &isNew);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  {
+    native_handle_t *shandle = nullptr;
+    std::shared_ptr<BufferPoolData> sbuffer;
+    TransactionId transactionId;
+    int64_t postUs;
+    std::vector<uint8_t> vecParams;
+    void *mem = nullptr;
+    IpcMutex *mutex = nullptr;
+
+    getIpcMutexParams(&vecParams);
+    status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    ASSERT_TRUE(TestBufferPoolAllocator::MapMemoryForMutex(shandle, &mem));
+
+    mutex = new(mem) IpcMutex();
+    mutex->init();
+
+    status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    message.data.command = PipeCommand::SEND;
+    message.data.bufferId = sbuffer->mId;
+    message.data.connectionId = receiverId;
+    message.data.transactionId = transactionId;
+    message.data.timestampUs = postUs;
+    sendMessage(mCommandPipeFds, message);
+    for (int i=0; i < 200000000; ++i) {
+      // no-op in order to ensure
+      // pthread_cond_wait is called before pthread_cond_signal
+    }
+    pthread_mutex_lock(&(mutex->lock));
+    mutex->counter = kSignalInt;
+    mutex->signalled = true;
+    pthread_cond_signal(&(mutex->cond));
+    pthread_mutex_unlock(&(mutex->lock));
+    (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+    if (shandle) {
+      native_handle_close(shandle);
+      native_handle_delete(shandle);
+    }
+  }
+  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+  EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/bufferpool/aidl/default/tests/multi.cpp b/media/bufferpool/aidl/default/tests/multi.cpp
new file mode 100644
index 0000000..8806eb0
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/multi.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <android-base/logging.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+const std::string testInstance  = std::string() + ClientManager::descriptor + "/multitest";
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+    INIT_OK = 0,
+    INIT_ERROR,
+    SEND,
+    RECEIVE_OK,
+    RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+    struct  {
+        int32_t command;
+        BufferId bufferId;
+        ConnectionId connectionId;
+        TransactionId transactionId;
+        int64_t  timestampUs;
+    } data;
+    char array[0];
+};
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    BufferPoolStatus status;
+    mReceiverPid = -1;
+    mConnectionValid = false;
+
+    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+    mReceiverPid = fork();
+    ASSERT_TRUE(mReceiverPid >= 0);
+
+    if (mReceiverPid == 0) {
+      doReceiver();
+      // In order to ignore gtest behaviour, wait for being killed from
+      // tearDown
+      pause();
+    }
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    mConnectionValid = true;
+  }
+
+  virtual void TearDown() override {
+    if (mReceiverPid > 0) {
+      kill(mReceiverPid, SIGKILL);
+      int wstatus;
+      wait(&wstatus);
+    }
+
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  std::shared_ptr<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  pid_t mReceiverPid;
+  int mCommandPipeFds[2];
+  int mResultPipeFds[2];
+
+  bool sendMessage(int *pipes, const PipeMessage &message) {
+    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  bool receiveMessage(int *pipes, PipeMessage *message) {
+    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  void doReceiver() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    PipeMessage message;
+    mManager = ClientManager::getInstance();
+    if (!mManager) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    auto binder = mManager->asBinder();
+    AIBinder_forceDowngradeToSystemStability(binder.get());
+    binder_status_t status =
+        AServiceManager_addService(binder.get(), testInstance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+    if (status != android::OK) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    message.data.command = PipeCommand::INIT_OK;
+    sendMessage(mResultPipeFds, message);
+
+    receiveMessage(mCommandPipeFds, &message);
+    {
+      native_handle_t *rhandle = nullptr;
+      std::shared_ptr<BufferPoolData> rbuffer;
+      BufferPoolStatus status = mManager->receive(
+          message.data.connectionId, message.data.transactionId,
+          message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+      mManager->close(message.data.connectionId);
+      if (status != ResultStatus::OK) {
+        message.data.command = PipeCommand::RECEIVE_ERROR;
+        sendMessage(mResultPipeFds, message);
+        return;
+      }
+      if (!TestBufferPoolAllocator::Verify(rhandle, 0x77)) {
+        message.data.command = PipeCommand::RECEIVE_ERROR;
+        sendMessage(mResultPipeFds, message);
+        return;
+      }
+      if (rhandle) {
+        native_handle_close(rhandle);
+        native_handle_delete(rhandle);
+      }
+    }
+    message.data.command = PipeCommand::RECEIVE_OK;
+    sendMessage(mResultPipeFds, message);
+  }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+  BufferPoolStatus status;
+  PipeMessage message;
+
+  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+  ABinderProcess_setThreadPoolMaxThreadCount(1);
+  ABinderProcess_startThreadPool();
+
+  std::shared_ptr<IClientManager> receiver = IClientManager::fromBinder(ndk::SpAIBinder(
+      AServiceManager_waitForService(testInstance.c_str())));
+  ASSERT_NE(receiver, nullptr);
+  ConnectionId receiverId;
+
+  bool isNew = true;
+  status = mManager->registerSender(receiver, mConnectionId, &receiverId, &isNew);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  {
+    native_handle_t *shandle = nullptr;
+    std::shared_ptr<BufferPoolData> sbuffer;
+    TransactionId transactionId;
+    int64_t postUs;
+    std::vector<uint8_t> vecParams;
+
+    getTestAllocatorParams(&vecParams);
+    status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    ASSERT_TRUE(TestBufferPoolAllocator::Fill(shandle, 0x77));
+    if (shandle) {
+        native_handle_close(shandle);
+        native_handle_delete(shandle);
+    }
+
+    status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    message.data.command = PipeCommand::SEND;
+    message.data.bufferId = sbuffer->mId;
+    message.data.connectionId = receiverId;
+    message.data.transactionId = transactionId;
+    message.data.timestampUs = postUs;
+    sendMessage(mCommandPipeFds, message);
+  }
+  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+  EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/bufferpool/aidl/default/tests/single.cpp b/media/bufferpool/aidl/default/tests/single.cpp
new file mode 100644
index 0000000..66aa5e9
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/single.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <bufferpool2/ClientManager.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferPoolStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+// Number of iteration for buffer allocation test.
+constexpr static int kNumAllocationTest = 3;
+
+// Number of iteration for buffer recycling test.
+constexpr static int kNumRecycleTest = 3;
+
+// media.bufferpool test setup
+class BufferpoolSingleTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    BufferPoolStatus status;
+    mConnectionValid = false;
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    mConnectionValid = true;
+
+    bool isNew = true;
+    status = mManager->registerSender(mManager, mConnectionId, &mReceiverId, &isNew);
+    ASSERT_TRUE(status == ResultStatus::OK && isNew == false &&
+                mReceiverId == mConnectionId);
+  }
+
+  virtual void TearDown() override {
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  std::shared_ptr<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  ConnectionId mReceiverId;
+
+};
+
+// Buffer allocation test.
+// Check whether each buffer allocation is done successfully with
+// unique buffer id.
+TEST_F(BufferpoolSingleTest, AllocateBuffer) {
+  BufferPoolStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+
+  std::shared_ptr<BufferPoolData> buffer[kNumAllocationTest];
+  native_handle_t *allocHandle = nullptr;
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer[i]);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    if (allocHandle) {
+      native_handle_close(allocHandle);
+      native_handle_delete(allocHandle);
+    }
+  }
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    for (int j = i + 1; j < kNumAllocationTest; ++j) {
+      ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
+    }
+  }
+  EXPECT_TRUE(kNumAllocationTest > 1);
+}
+
+// Buffer recycle test.
+// Check whether de-allocated buffers are recycled.
+TEST_F(BufferpoolSingleTest, RecycleBuffer) {
+  BufferPoolStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+
+  BufferId bid[kNumRecycleTest];
+  for (int i = 0; i < kNumRecycleTest; ++i) {
+    std::shared_ptr<BufferPoolData> buffer;
+    native_handle_t *allocHandle = nullptr;
+    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    bid[i] = buffer->mId;
+    if (allocHandle) {
+      native_handle_close(allocHandle);
+      native_handle_delete(allocHandle);
+    }
+  }
+  for (int i = 1; i < kNumRecycleTest; ++i) {
+    ASSERT_TRUE(bid[i - 1] == bid[i]);
+  }
+  EXPECT_TRUE(kNumRecycleTest > 1);
+}
+
+// Buffer transfer test.
+// Check whether buffer is transferred to another client successfully.
+TEST_F(BufferpoolSingleTest, TransferBuffer) {
+  BufferPoolStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+  std::shared_ptr<BufferPoolData> sbuffer, rbuffer;
+  native_handle_t *allocHandle = nullptr;
+  native_handle_t *recvHandle = nullptr;
+
+  TransactionId transactionId;
+  int64_t postMs;
+
+  status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &sbuffer);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  ASSERT_TRUE(TestBufferPoolAllocator::Fill(allocHandle, 0x77));
+  status = mManager->postSend(mReceiverId, sbuffer, &transactionId, &postMs);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postMs,
+                             &recvHandle, &rbuffer);
+  EXPECT_TRUE(status == ResultStatus::OK);
+  ASSERT_TRUE(TestBufferPoolAllocator::Verify(recvHandle, 0x77));
+
+  if (allocHandle) {
+    native_handle_close(allocHandle);
+    native_handle_delete(allocHandle);
+  }
+  if (recvHandle) {
+    native_handle_close(recvHandle);
+    native_handle_delete(recvHandle);
+  }
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/power/stats/aidl/Android.bp b/power/stats/aidl/Android.bp
index b1b2515..43bcfc8 100644
--- a/power/stats/aidl/Android.bp
+++ b/power/stats/aidl/Android.bp
@@ -37,5 +37,17 @@
         },
     },
     host_supported: true,
-    versions: ["1"],
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+        {
+            version: "2",
+            imports: [],
+        },
+
+    ],
+    frozen: true,
+
 }
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/.hash b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/.hash
new file mode 100644
index 0000000..b715ccb
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/.hash
@@ -0,0 +1 @@
+c3e113101b731c666717eb579492efa287a8f529
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/Channel.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/Channel.aidl
new file mode 100644
index 0000000..d1048a4
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/Channel.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable Channel {
+  int id;
+  @utf8InCpp String name;
+  @utf8InCpp String subsystem;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumer.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumer.aidl
new file mode 100644
index 0000000..13f528d
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumer.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable EnergyConsumer {
+  int id;
+  int ordinal;
+  android.hardware.power.stats.EnergyConsumerType type = android.hardware.power.stats.EnergyConsumerType.OTHER;
+  @utf8InCpp String name;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerAttribution.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerAttribution.aidl
new file mode 100644
index 0000000..ee12068
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerAttribution.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable EnergyConsumerAttribution {
+  int uid;
+  long energyUWs;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerResult.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerResult.aidl
new file mode 100644
index 0000000..7d8aa98
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerResult.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable EnergyConsumerResult {
+  int id;
+  long timestampMs;
+  long energyUWs;
+  android.hardware.power.stats.EnergyConsumerAttribution[] attribution;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerType.aidl
new file mode 100644
index 0000000..02b612b
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+enum EnergyConsumerType {
+  OTHER,
+  BLUETOOTH,
+  CPU_CLUSTER,
+  DISPLAY,
+  GNSS,
+  MOBILE_RADIO,
+  WIFI,
+  CAMERA,
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyMeasurement.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyMeasurement.aidl
new file mode 100644
index 0000000..ffe3aa4
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/EnergyMeasurement.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable EnergyMeasurement {
+  int id;
+  long timestampMs;
+  long durationMs;
+  long energyUWs;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/IPowerStats.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/IPowerStats.aidl
new file mode 100644
index 0000000..7917515
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/IPowerStats.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+interface IPowerStats {
+  android.hardware.power.stats.PowerEntity[] getPowerEntityInfo();
+  android.hardware.power.stats.StateResidencyResult[] getStateResidency(in int[] powerEntityIds);
+  android.hardware.power.stats.EnergyConsumer[] getEnergyConsumerInfo();
+  android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(in int[] energyConsumerIds);
+  android.hardware.power.stats.Channel[] getEnergyMeterInfo();
+  android.hardware.power.stats.EnergyMeasurement[] readEnergyMeter(in int[] channelIds);
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/PowerEntity.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/PowerEntity.aidl
new file mode 100644
index 0000000..f42e715
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/PowerEntity.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable PowerEntity {
+  int id;
+  @utf8InCpp String name;
+  android.hardware.power.stats.State[] states;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/State.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/State.aidl
new file mode 100644
index 0000000..cf29dd7
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/State.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable State {
+  int id;
+  @utf8InCpp String name;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/StateResidency.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/StateResidency.aidl
new file mode 100644
index 0000000..0af35b3
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/StateResidency.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable StateResidency {
+  int id;
+  long totalTimeInStateMs;
+  long totalStateEntryCount;
+  long lastEntryTimestampMs;
+}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/StateResidencyResult.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/StateResidencyResult.aidl
new file mode 100644
index 0000000..14358b7
--- /dev/null
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/2/android/hardware/power/stats/StateResidencyResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power.stats;
+@VintfStability
+parcelable StateResidencyResult {
+  int id;
+  android.hardware.power.stats.StateResidency[] stateResidencyData;
+}
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 0499079..4c46719 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -89,6 +89,29 @@
     return imei;
 }
 
+// Use `ro.product.<property>_for_attestation` property for attestation if it is present else
+// fallback to use `ro.product.vendor.<property>` if it is present else fallback to
+// `ro.product.<property>`. Similar logic can be seen in Java method `getVendorDeviceIdProperty`
+// in frameworks/base/core/java/android/os/Build.java.
+template <Tag tag>
+void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
+                        TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
+    ::android::String8 prop_name =
+            ::android::String8::format("ro.product.%s_for_attestation", prop);
+    std::string prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+    if (!prop_value.empty()) {
+        add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+    } else {
+        prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
+        prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+        if (!prop_value.empty()) {
+            add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+        } else {
+            prop_name = ::android::String8::format("ro.product.%s", prop);
+            add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+        }
+    }
+}
 }  // namespace
 
 class AttestKeyTest : public KeyMintAidlTestBase {
@@ -133,7 +156,7 @@
         vector<uint8_t> attested_key_blob;
         vector<KeyCharacteristics> attested_key_characteristics;
         vector<Certificate> attested_key_cert_chain;
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -144,9 +167,11 @@
                               &attested_key_cert_chain));
         KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
+
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -163,7 +188,7 @@
          */
         attested_key_characteristics.resize(0);
         attested_key_cert_chain.resize(0);
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaEncryptionKey(2048, 65537)
                                       .Digest(Digest::NONE)
@@ -176,9 +201,11 @@
                               &attested_key_cert_chain));
         KeyBlobDeleter attested_deleter2(keymint_, attested_key_blob);
 
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
+
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo2", "bar2", sw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo2", "bar2", sw_enforced,
                                               hw_enforced, SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -196,7 +223,7 @@
         attested_key_characteristics.resize(0);
         attested_key_cert_chain.resize(0);
         uint64_t timestamp = 1619621648000;
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -208,6 +235,8 @@
                               &attested_key_cert_chain));
         KeyBlobDeleter attested_deleter3(keymint_, attested_key_blob);
 
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
+
         // The returned key characteristics will include CREATION_DATETIME (checked below)
         // in SecurityLevel::KEYSTORE; this will be stripped out in the CheckCharacteristics()
         // call below, to match what getKeyCharacteristics() returns (which doesn't include
@@ -223,7 +252,7 @@
         EXPECT_TRUE(sw_enforced.Contains(TAG_CREATION_DATETIME, timestamp))
                 << "expected CREATION_TIMESTAMP in sw_enforced:" << sw_enforced
                 << " not in hw_enforced:" << hw_enforced;
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -313,7 +342,7 @@
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attest_key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attest_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                           sw_enforced, hw_enforced, SecLevel(),
                                           attest_key_cert_chain[0].encodedCertificate));
 
@@ -331,7 +360,7 @@
     uint64_t serial_int2 = 255;
     vector<uint8_t> serial_blob2(build_serial_blob(serial_int2));
 
-    EXPECT_EQ(ErrorCode::OK,
+    ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                                   .RsaSigningKey(2048, 65537)
                                   .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -344,9 +373,11 @@
                           &attested_key_cert_chain));
     KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
+    ASSERT_GT(attested_key_cert_chain.size(), 0);
+
     AuthorizationSet hw_enforced2 = HwEnforcedAuthorizations(attested_key_characteristics);
     AuthorizationSet sw_enforced2 = SwEnforcedAuthorizations(attested_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced2, hw_enforced2,
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced2, hw_enforced2,
                                           SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
 
@@ -414,7 +445,7 @@
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
@@ -489,7 +520,7 @@
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
@@ -605,7 +636,7 @@
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
@@ -655,7 +686,7 @@
         vector<uint8_t> attested_key_blob;
         vector<KeyCharacteristics> attested_key_characteristics;
         vector<Certificate> attested_key_cert_chain;
-        EXPECT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
+        ASSERT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -664,7 +695,7 @@
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
 
-        EXPECT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
+        ASSERT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
                   GenerateKey(AuthorizationSetBuilder()
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -702,7 +733,7 @@
         vector<uint8_t> attested_key_blob;
         vector<KeyCharacteristics> attested_key_characteristics;
         vector<Certificate> attested_key_cert_chain;
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -717,7 +748,7 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -733,7 +764,7 @@
         /*
          * Use attestation key to sign EC key
          */
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -748,7 +779,7 @@
 
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -786,7 +817,7 @@
     vector<uint8_t> attested_key_blob;
     vector<KeyCharacteristics> attested_key_characteristics;
     vector<Certificate> attested_key_cert_chain;
-    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
               GenerateKey(AuthorizationSetBuilder()
                                   .EcdsaSigningKey(EcCurve::P_256)
                                   .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -798,11 +829,6 @@
 }
 
 TEST_P(AttestKeyTest, EcdsaAttestationID) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
     // Create attestation key.
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
@@ -822,39 +848,12 @@
 
     // Collection of valid attestation ID tags.
     auto attestation_id_tags = AuthorizationSetBuilder();
-    // Use ro.product.brand_for_attestation property for attestation if it is present else fallback
-    // to ro.product.brand
-    std::string prop_value =
-            ::android::base::GetProperty("ro.product.brand_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND,
-                          "ro.product.brand_for_attestation");
-    } else {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
-    }
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
-    // Use ro.product.name_for_attestation property for attestation if it is present else fallback
-    // to ro.product.name
-    prop_value = ::android::base::GetProperty("ro.product.name_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT,
-                          "ro.product.name_for_attestation");
-    } else {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    }
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "model");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
-                      "ro.product.manufacturer");
-    // Use ro.product.model_for_attestation property for attestation if it is present else fallback
-    // to ro.product.model
-    prop_value =
-            ::android::base::GetProperty("ro.product.model_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL,
-                          "ro.product.model_for_attestation");
-    } else {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
-    }
 
     string imei = get_imei(0);
     if (!imei.empty()) {
@@ -881,6 +880,7 @@
         }
 
         ASSERT_EQ(result, ErrorCode::OK);
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
         KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
@@ -891,7 +891,7 @@
         // attestation extension should contain them, so make sure the extra tag is added.
         hw_enforced.push_back(tag);
 
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
                                               hw_enforced, SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
     }
@@ -928,7 +928,9 @@
                     .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
 
     if (isSecondImeiIdAttestationRequired()) {
-        attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, "invalid-second-imei");
+        // Note: the invalid value here is < 16 bytes long to avoid triggering any implementation
+        // checks on valid IMEI lengths.
+        attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, "invalid-imei2");
     }
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
@@ -955,12 +957,6 @@
 }
 
 TEST_P(AttestKeyTest, SecondIMEIAttestationIDSuccess) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
-
     // Skip the test if there is no second IMEI exists.
     string second_imei = get_imei(1);
     if (second_imei.empty()) {
@@ -1011,6 +1007,7 @@
     }
 
     ASSERT_EQ(result, ErrorCode::OK);
+    ASSERT_GT(attested_key_cert_chain.size(), 0);
     KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
@@ -1023,18 +1020,12 @@
     KeyParameter imei_tag = Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, imei_blob);
     hw_enforced.push_back(imei_tag);
 
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
                                           hw_enforced, SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
 }
 
 TEST_P(AttestKeyTest, MultipleIMEIAttestationIDSuccess) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
-
     // Skip the test if there is no first IMEI exists.
     string imei = get_imei(0);
     if (imei.empty()) {
@@ -1088,6 +1079,7 @@
     }
 
     ASSERT_EQ(result, ErrorCode::OK);
+    ASSERT_GT(attested_key_cert_chain.size(), 0);
     KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
@@ -1103,7 +1095,7 @@
     KeyParameter sec_imei_tag = Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, sec_imei_blob);
     hw_enforced.push_back(sec_imei_tag);
 
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
                                           hw_enforced, SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
 }
diff --git a/security/keymint/aidl/vts/functional/AuthTest.cpp b/security/keymint/aidl/vts/functional/AuthTest.cpp
index 290e8fc..ecaee11 100644
--- a/security/keymint/aidl/vts/functional/AuthTest.cpp
+++ b/security/keymint/aidl/vts/functional/AuthTest.cpp
@@ -453,8 +453,18 @@
     vector<uint8_t> keyblob;
     vector<KeyCharacteristics> key_characteristics;
     vector<Certificate> cert_chain;
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
+    auto result = GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain);
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
+            result = GenerateKeyWithSelfSignedAttestKey(AuthorizationSetBuilder()
+                                                                .EcdsaKey(EcCurve::P_256)
+                                                                .AttestKey()
+                                                                .SetDefaultValidity(),
+                                                        builder, &keyblob, &key_characteristics,
+                                                        &cert_chain);
+        }
+    }
+    ASSERT_EQ(ErrorCode::OK, result);
 
     // Verify first user to get a HAT that should work.
     const uint64_t challenge = 42;
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 1e61a18..022dd3f 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -2565,22 +2565,24 @@
  * NewKeyGenerationTest.EcdsaDefaultSize
  *
  * Verifies that failing to specify a curve for EC key generation returns
- * UNSUPPORTED_KEY_SIZE.
+ * UNSUPPORTED_KEY_SIZE or UNSUPPORTED_EC_CURVE.
  */
 TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
-    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .Authorization(TAG_ALGORITHM, Algorithm::EC)
-                                  .SigningKey()
-                                  .Digest(Digest::NONE)
-                                  .SetDefaultValidity()));
+    auto result = GenerateKey(AuthorizationSetBuilder()
+                                      .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                      .SigningKey()
+                                      .Digest(Digest::NONE)
+                                      .SetDefaultValidity());
+    ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+                result == ErrorCode::UNSUPPORTED_EC_CURVE)
+            << "unexpected result " << result;
 }
 
 /*
  * NewKeyGenerationTest.EcdsaInvalidCurve
  *
  * Verifies that specifying an invalid curve for EC key generation returns
- * UNSUPPORTED_KEY_SIZE.
+ * UNSUPPORTED_KEY_SIZE or UNSUPPORTED_EC_CURVE.
  */
 TEST_P(NewKeyGenerationTest, EcdsaInvalidCurve) {
     for (auto curve : InvalidCurves()) {
@@ -2593,7 +2595,8 @@
                                           .SetDefaultValidity(),
                                   &key_blob, &key_characteristics);
         ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
-                    result == ErrorCode::UNSUPPORTED_EC_CURVE);
+                    result == ErrorCode::UNSUPPORTED_EC_CURVE)
+                << "unexpected result " << result;
     }
 
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
@@ -8755,6 +8758,7 @@
 
 using VsrRequirementTest = KeyMintAidlTestBase;
 
+// @VsrTest = VSR-3.10-008
 TEST_P(VsrRequirementTest, Vsr13Test) {
     int vsr_api_level = get_vsr_api_level();
     if (vsr_api_level < __ANDROID_API_T__) {
@@ -8763,6 +8767,7 @@
     EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
 }
 
+// @VsrTest = VSR-3.10-013.001
 TEST_P(VsrRequirementTest, Vsr14Test) {
     int vsr_api_level = get_vsr_api_level();
     if (vsr_api_level < __ANDROID_API_U__) {
diff --git a/security/rkp/README.md b/security/rkp/README.md
index f8e1d5e..15ea817 100644
--- a/security/rkp/README.md
+++ b/security/rkp/README.md
@@ -42,7 +42,9 @@
 sign certificate requests. Instead, UDS\_pub is just the first public key in a
 chain of public keys that end the KeyMint public key. All keys in the chain are
 transitively derived from the UDS and joined in a certificate chain following
-the specification of the [Android Profile for DICE](#android-profile-for-dice).
+the specification of the [Android Profile for DICE](android-profile-for-dice).
+
+[android-profile-for-dice]: https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md
 
 ### Phases
 
@@ -52,8 +54,8 @@
 * Degenerate DICE (Phase 1): A TEE root of trust key pair is used to sign
   certificate requests; a single self-signed certificate signifies this phase.
 * DICE (Phase 2): A hardware root of trust key pair is only accessible to ROM
-  code; the boot process follows the [Android Profile for
-  DICE](#android-profile-for-dice).
+  or ROM extension code; the boot process follows the [Android Profile for
+  DICE](android-profile-for-dice).
 * SoC vendor certified DICE (Phase 3): This is identical to Phase 2, except the
   SoC vendor also does the UDS\_pub extraction or certification in their
   facilities, along with the OEM doing it in the factory. This tightens up the
@@ -163,67 +165,6 @@
 *   **KeyMint** is the secure area component that manages cryptographic keys and
     performs attestations (or perhaps some other secure area component).
 
-### Android Profile for DICE
-
-The Android Profile for DICE is based on the [Open Profile for
-DICE](https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md),
-with additional constraints for details that the Open Profile for DICE leaves
-intentionally underspecified. This section describes the differences from the
-Open Profile for DICE.
-
-#### Algorithms
-
-The choice of algorithm must remain consistent with a given certificate e.g. if
-SHA-256 is used for the code hash then the authority hash, config hash, etc.
-must also use SHA-256.
-
-* UDS and CDI key pairs:
-  * Ed25519 / P-256 / P-384
-* Hash algorithms (digests can be encoded with their natural size and do not
-  need to be the 64-bytes specified by the Open Profile for DICE):
-  * SHA-256 / SHA-384 / SHA-512
-* HKDF with a supported message digest for all key derivation
-
-#### Mode
-
-A certificate must only set the mode to `normal` when all of the following
-conditions are met when loading and verifying the software component that is
-being described by the certificate:
-
-* verified boot with anti-rollback protection is enabled
-* only the verified boot authorities for production images are enabled
-* debug ports, fuses, or other debug facilities are disabled
-* device booted software from the normal primary source e.g. internal flash
-
-The mode should never be `not configured`.
-
-Every certificate in the DICE chain will need to be have the `normal` mode in
-order to be provisioned with production certificates by RKP.
-
-#### Configuration descriptor
-
-The configuration descriptor is a CBOR map with the following optional fields.
-If no fields are relevant, an empty map should be encoded. The key value range
-\[-70000, -70999\] is reserved for the Android Profile for DICE.
-Implementation-specific fields may be added using key values outside of the
-reserved range.
-
-```
-| Name              | Key    | Value type | Meaning                           |
-| ----------------- | ------ | ---------- | ----------------------------------|
-| Component name    | -70002 | tstr       | Name of firmware component / boot |
-:                   :        :            : stage                             :
-| Component version | -70003 | int / tstr | Version of firmware component /   |
-:                   :        :            : boot stage                        :
-| Resettable        | -70004 | null       | If present, key changes on factory|
-:                   :        :            : reset                             :
-| Security version  | -70005 | uint       | Machine-comparable, monotonically |
-:                   :        :            : increasing version of the firmware:
-:                   :        :            : component / boot stage where a    :
-:                   :        :            : greater value indicates a newer   :
-:                   :        :            : version                           :
-```
-
 ### HAL
 
 The remote provisioning HAL provides a simple interface that can be implemented
diff --git a/sensors/aidl/default/Sensor.cpp b/sensors/aidl/default/Sensor.cpp
index 3bdd8b6..ca3eb14 100644
--- a/sensors/aidl/default/Sensor.cpp
+++ b/sensors/aidl/default/Sensor.cpp
@@ -268,7 +268,7 @@
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
 };
 
 void MagnetometerSensor::readEventPayload(EventPayload& payload) {
@@ -343,7 +343,7 @@
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
 };
 
 void GyroSensor::readEventPayload(EventPayload& payload) {
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index e6e0888..a15e7fe 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -124,7 +124,8 @@
 
   private:
     static constexpr uint64_t kBufferUsage =
-            static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
+            static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN |
+                                  BufferUsage::CPU_WRITE_RARELY);
     AllocatorWrapperT<AllocatorT> mAllocator;
     sp<MapperT> mMapper;
 
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index ff9c247..21951b6 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -45,6 +45,7 @@
   CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
   CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
   CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
+  CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
   RADAR_SUPPORT = 0xB0,
   SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
   SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
new file mode 100644
index 0000000..efafa32
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="byte") @VintfStability
+enum UwbVendorDataPacketFormat {
+  RADAR_DATA_MESSAGE = 0xF,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 34bc4ec..1506406 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -39,5 +39,4 @@
   ANDROID_RANGE_DIAGNOSTICS = 0x2,
   RADAR_SET_APP_CONFIG = 0x11,
   RADAR_GET_APP_CONFIG = 0x12,
-  RADAR_DATA_NTF = 0x13,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index ceef1be..2141b5a 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -149,6 +149,11 @@
      */
     CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
 
+    /**
+     * Byte array of channels supported by the device, ordered by priority from highest to lowest.
+     */
+    CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
+
     /*********************************************
      * RADAR specific
      ********************************************/
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
new file mode 100644
index 0000000..7a1b033
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor DPF (Data Packet Format) should be defined here.
+ */
+@VintfStability
+@Backing(type="byte")
+enum UwbVendorDataPacketFormat {
+    // Used to send radar data messages from UWBS to the host.
+    RADAR_DATA_MESSAGE = 0xF,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 203b940..95c10a8 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -46,6 +46,4 @@
     RADAR_SET_APP_CONFIG = 0x11,
     // Used to get application configurations for radar session.
     RADAR_GET_APP_CONFIG = 0x12,
-    // Used to report radar data for certain radar data types.
-    RADAR_DATA_NTF = 0x13,
 }
diff --git a/uwb/aidl/default/Android.bp b/uwb/aidl/default/Android.bp
index 9621f2c..c6d1a52 100644
--- a/uwb/aidl/default/Android.bp
+++ b/uwb/aidl/default/Android.bp
@@ -11,8 +11,8 @@
     name: "android.hardware.uwb-service",
     crate_name: "uwb_default_hal",
     relative_install_path: "hw",
-    vintf_fragments: ["uwb-service.xml"],
     vendor: true,
+    prefer_rlib: true,
     rustlibs: [
         "android.hardware.uwb-V1-rust",
         "liblogger",
@@ -30,3 +30,47 @@
         "src/service.rs",
     ],
 }
+
+prebuilt_etc {
+    name: "uwb-service.rc",
+    src: "uwb-service.rc",
+    vendor: true,
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "uwb-service.xml",
+    src: "uwb-service.xml",
+    sub_dir: "vintf",
+    vendor: true,
+    installable: false,
+}
+
+apex_key {
+    name: "com.android.hardware.uwb.key",
+    public_key: "com.android.hardware.uwb.avbpubkey",
+    private_key: "com.android.hardware.uwb.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.uwb.certificate",
+    certificate: "com.android.hardware.uwb",
+}
+
+apex {
+    name: "com.android.hardware.uwb",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.uwb.key",
+    certificate: ":com.android.hardware.uwb.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.uwb-service",
+    ],
+    prebuilts: [
+        "uwb-service.rc", // init_rc
+        "uwb-service.xml", // vintf_fragments
+    ],
+}
diff --git a/uwb/aidl/default/com.android.hardware.uwb.avbpubkey b/uwb/aidl/default/com.android.hardware.uwb.avbpubkey
new file mode 100644
index 0000000..7a7fce8
--- /dev/null
+++ b/uwb/aidl/default/com.android.hardware.uwb.avbpubkey
Binary files differ
diff --git a/uwb/aidl/default/com.android.hardware.uwb.pem b/uwb/aidl/default/com.android.hardware.uwb.pem
new file mode 100644
index 0000000..cd38ef8
--- /dev/null
+++ b/uwb/aidl/default/com.android.hardware.uwb.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQChE5EVDbSAKAru
+myK22LP72i2ivpJGi8DqRjgA5r6Zz3OKwtvrtSBaTtACv3j6ZALLndA2sgxbt64B
+ik1vU1tpnrGnaqcdlgDio6QIfpavWEcZ9rOHuGXvLlv3Tzc2gyr1UKsaGtce+os8
+jbfyEl4keN59oI2D8Nj1VVKYRKS+mrp4+hnvt3itGbvIKLCgGBYlcSxIiWKDfJXy
+jQEpb5pZy3wCdn2CCrTb64oclkmYbGcfoYuSBV6+PBrGa2b0b5aWm40YFbgZ5h+j
+Hlkb7sX7Vz499DK1lbm8rRt+EkHZ/9IFS1DBSj6MK3LKyGspj7BzJ25UQI23B3pM
+iaNsjBR1gGwqJxWpjuuZm9qdNPMSUUSxs/EB0GX96jnC5HFjh3sLOWKqqP6SRCZW
+xYRzjAno1L1jjPXdDqM9n2aJHu35+YVG/sFn20eIBSxH9u1hSnOw8ccc0Zo774cc
+oTJHKlL9GUO5SEGLkz3XTMEe6e55yujChymMe5jz8jkkCaXqsNDB0AMUtQ6g0Kzu
+FNUdTS2DAr/Xo7qxJ6VoDwOx/OQeDQSjSuojt/JMHEp6QMir+/axVWuxIaegjElH
+Kmx7Ie6ZGZscaTxKFEYEkWaIeJKTml0NxEitrJAibc58itj93zBMP2EDve46ghWJ
+SlmeeVmn0CuYeE8EHwZSB4I7EaHP1QIDAQABAoICADQESZnu7xdj1wPu/Wrm2FjA
+wHQJ7trxTr9ZJcTEv1CUec+Z1cNsnqILSYlZpAvYOD7hG9hN70e/LWY573+//4lA
+Qka6XnVjd625AsPrfWXqsCtmS9vMZL60zeYzorTr7veBsX+go0/RwR0w9vIplFVa
+4x7Wtlyhbq7retzJbhpPhWCEA9Qx/7qG0Ol2mnNY0+4Lei2CkFm95f6KIpHrBIFz
+AP0anrVcF8PdcKCCuAmNGFBSruvc6Beu+UaScJEHaC4C1bGtceKLOjRHHKe0mCLu
+rZ78OVQCohSYIoS4CKQJxR0IkW+aNlC1x0BNMK4fRPArD6oNnrY4p/oHiMsJAaHc
+tLWeUqvlSAdK0C5ejUzdjTiZW7rzI2gluy+BBKY1nByQsVWK7saG6hEON63idfl+
+GwPPb253n49UIk3UlUy1PxVb/othlw0dlD7p4wAlOJoRlOuJnqAifwWckS2rpNHO
+9wR1tak8hLi2LMDJqu/GlHoSqkb+JdAV5yujLQ8k1So/y/4bvNY2pRpXPydxkOew
+FY/BOoslS6RD5/XHfSJsK/Oq53Y+d04qdV7jwgrp4lqFEqMwJgzVEoC5cMvJVeK9
+/wjUdWw9hg0DSk8LVmNbIWZjZs4C39uQljmt8s+exSmzm5MSQU3K11vGRGKOsPlA
+5ZzRRaV81lBYKhATE8aRAoIBAQDfPgJ3l/38RPyoNrJuhOPH4UJj0rDX0+5ezqla
+iAXDxec55lM8qbPDW3jl/MWE3LePVokKN8DBxwZxi9Po4UEQ4hG4+zIyPcT1AQlH
++kHGG0TBtJox8J+DkG5oW79wXCn6tyl8ZLwWNa6T/3vIi3BNadnoe3AFqgcHVwHz
+e/tl0z6Tz56r/eNN6dl01+D31rirqiYRbe3982ZiX3JfS3t+AIQoxcU4suU+DC37
+G5h0zbzjgXP+ZrpPfh6O7JwH7Ac83nJAYBsVcHU4P/ZstkIWjuzleEQcDcsj3sHu
+NO2/wbReo/8Yvk0q2vUQm9IkWlU83H2KLPzIa1VuzTfPql0bAoIBAQC4tlP393ly
+krhmRLs6msAjXp5oZzoyHnrYvn+5LlKoPul98EqAW9GczLSlgjYO3w2DqnimBhU/
+YorWvkhcSJsrjiEn7CZ3UXuXoLciRiyHk/3xSDP4CLZ8tvUcEGs34LITXMPlrIk1
+WfYseSukE1TB6GDEj4MsxFILKhwnxGWeD9x9+ejOPj7+Jk3oTiZPVc67LR0MDgDz
+hRZW/8VOsequ+B/TF9LiwUHI3Ps3Geh3kKMR6DQaxXW08HDk1NGsZmKXq+O+JWFT
+3ZwCNnXqUCpm9YsD6QXTHILtBHVS5cxE65BFs08WEAqcgDhr3Yczz8L/UN/qR+FH
+RSOcymVFHQXPAoIBAQDK8Lsbbw+UGj64yGhysdnD5dINnwXmXiHPC/3Gb+sVqr3l
+060Nc5QYXvpL0PraKi+wXVFc+YwAXGZOKHfut38H0wubZreeFqsKsvN1/Fl4t2dM
+1FpsVbscxdqogedJRG9hHMrY61ZUtl5K6jDkAWaI6VYP0s7mR0f2czEx4B6M1XmI
+s3AiGD5foNtvLaS0iPz+CUJsC8wTVQZZHT2CxcKwq9V4nzkHrxFY04elQ9PXMwSo
+qRECTu7FvvgWo5/AT9/QhMPGI9fbKI1XIkZpU1JG4Y0XmboI6r0lkaYoXvNWo8fN
+VTZcjvrln4CypYRmSbw9BJAXYYg2xeQ3QtWesdfLAoIBAQCM9ifyjpvSQgITmdRA
+jySeWXEOP+j7oqMhkY+rZJyT5R8Pizdv6aJ3xQj/XfWfN736gzf7i5zfeHZ4F1Ll
+iktQ2/CVpPReDoMBXhckQuVsuhYL8owmd4+8cWtw9V69j+6WNC8Tsa4sVvE1U2to
+lZATQyHGH7d9jH0IJCTEfG8IRxZ/1R5DduFf1x+Rb0JxPQy9b1pBftZfAWvhDOQo
+gEKXMKgo0n+PqOhpP6s/i7gKtwibe9d3rsV7RhsBpyA0LxaCpRzyWViDRhXu4lzu
+aitR04U5gLV/PLz14Hcgwlo3JoY9iu+J6MgQUxG7z52EfsNTUQbwpdZYK31YBGVw
+bwulAoIBAQClsNAtbbwmExh3P0rjkgQOVy7FMQXgOyldR/LYTRI6Zbt47Jb4eO6M
+vfKK4C67/RoD1PEWgdboY8axPNj3dR1RdAuyTOOJfhJYVCW2eRS2fjSjYmUnLoFB
+N2ABYE8yKmmcPIlcJzXs3Jzeb+URxtDrvuEWPBHm8Ia1u29t42W7pg4AZHitilTl
+Su1Xi+Ic2n0NVzqZzLVUb6dKr2NFAjynthOCFXbbwD6awFeTxFIXVGT9TPTaiIlA
+Ssnh+yii4NHRoZjivUCsrfEfn+NiCzOgrfXTtUiRDvhZHdpqAIqQ6lpju7naCCwG
+vApJsLERxjCi0eqDwVx/e6xbeOVUZc/m
+-----END PRIVATE KEY-----
diff --git a/uwb/aidl/default/com.android.hardware.uwb.pk8 b/uwb/aidl/default/com.android.hardware.uwb.pk8
new file mode 100644
index 0000000..8855197
--- /dev/null
+++ b/uwb/aidl/default/com.android.hardware.uwb.pk8
Binary files differ
diff --git a/uwb/aidl/default/com.android.hardware.uwb.x509.pem b/uwb/aidl/default/com.android.hardware.uwb.x509.pem
new file mode 100644
index 0000000..762ad88
--- /dev/null
+++ b/uwb/aidl/default/com.android.hardware.uwb.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF1TCCA70CFEagTJLwbnblSQu8MjFHXcEDFQ1MMA0GCSqGSIb3DQEBCwUAMIGl
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEhMB8GA1UEAwwYY29t
+LmFuZHJvaWQuaGFyZHdhcmUudXdiMCAXDTIzMDgyMTA0MTE0M1oYDzQ3NjEwNzE3
+MDQxMTQzWjCBpTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAU
+BgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsM
+B0FuZHJvaWQxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20xITAf
+BgNVBAMMGGNvbS5hbmRyb2lkLmhhcmR3YXJlLnV3YjCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBAJpvvE7i50v4hE5VmlFTiOsQ+zOYWF+MjzEMXcqLQDzs
+26XBYJV7O3TwgrQNp1XV8KCPTAF8APEyGb237rlZO/3KvS9zYa3zFfEMPg5pnFmR
+QLWSfqrXm7ttKIQHNVAjqrLnlt8pjvKS/t/UXLAWgHiXnd2ZX62tQjyDouszLEwP
+59zJbkgX9o6fwEssdRTpuyoRoyPylfK3Thk22RBSTt+pS6pwqeUj4vttrPr7k7YU
+S5CeB7XVBRPRzXFrpasgzQqp2deOpqxC44H90+pl7QmBHFrnGk+90lcOPYgqF2Ah
+DfCBxAHzn8ioSsAJ0U34yqoNbWIUX3ZHgq1ru1uctdLwGMrKmqsw4uvfXLV+sjoi
+qUFW+9uEOHAVnmZEO2T7LAlUIoAGgdd58EJ+hdXP2yvNpGVPestrwWttAaMJoEJN
+qEWt67+iEjdEpVn0lUFo+up42mYEXGUAOpoc6t5WJinrQTY4JK/OIGJPUiOjbUTI
+T/hQTddr0HNGsKP2zRv0d49VtVht6wR0HlO1srCFZAGxRIdBtjjenu1l7ALMWlHw
+4YXLSpQoeYfavV8C3j5bzz6KaDj6HcKvRbyHRX8+JL9kFDgpOD1yI/jaaPepRAe6
+qek5jEJMEFj0tFifB8e0CZbURreXa1tErWybfuDkaNBDtAHL333/IQGI0vV7zr0x
+AgMBAAEwDQYJKoZIhvcNAQELBQADggIBAFqnBngYd7rXHwIXHYKZuRMf+NLQxNFN
+f0m6ioFYgNnMwoMQidBHdRsJ2qTb9zfyt5O1/5Wel8Ix9aUCRbJejyX2lYXNIJNC
+ykahkoP+3CEA8QtPkmtWzNraDJRh2eYn6V5DJOWyvkz02DsHA4mxatYkF7dUfqLx
+f/y1y3cbnTyAraotTRb3W/F/zEYbcCzwlFZDT/IASVM89WRDE76+rp7/wDNJ0aEJ
+l6cQaUWDPbrvDWZaptRWfnebPtg81v03qKauwrBADddxu+/Nqs0iczBdsP1tdXr/
+Hxs47D7+fZnytVQglldBG4yky9YceL22yft/bCNDe5d7nF1/iUpJNbRIcrZxD86Z
+wwPpo0VMJ+r6VuD6UGQTS6Zyi94QD3GYYkGrPPwyrLKpp1EU6dV32bWCNp5eQojY
+FyTse/lfAJ9/Xu3klHYuR9xOaJiH+2MmtJTwKdjvK5h+EIiVbyrDJJHBd9sWav3a
+Emo+wKaIxQzXEUjWxUwy7eAAwq5WzawLMMQ97P0zIgasNIlUHW2cvBzVsQlM1tN7
+2t+7UPs5RifK5hadK6Ge1oqkG0xC1t65E7yGwrPMzKuz9aPgg7j1YAaETcKuFOHG
+rZr/0kALZc6VKNSZ8eM2P5ObrelLOe4ED9Ha1ZhmnCDXN9BP2gwqmCekwfNJ3cPA
+GObJiF81f9ZM
+-----END CERTIFICATE-----
diff --git a/uwb/aidl/default/file_contexts b/uwb/aidl/default/file_contexts
new file mode 100644
index 0000000..6ec53ed
--- /dev/null
+++ b/uwb/aidl/default/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.uwb-service          u:object_r:hal_uwb_default_exec:s0
\ No newline at end of file
diff --git a/uwb/aidl/default/manifest.json b/uwb/aidl/default/manifest.json
new file mode 100644
index 0000000..3f2f911
--- /dev/null
+++ b/uwb/aidl/default/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.uwb",
+    "version": 1
+}
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index cf32694..9587efb 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -6,8 +6,8 @@
 use async_trait::async_trait;
 use binder::{Result, Strong};
 
-use tokio::fs::{self, File};
-use tokio::io::AsyncReadExt;
+use tokio::fs::{File, OpenOptions};
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
 use tokio::sync::Mutex;
 
 use std::os::fd::AsRawFd;
@@ -22,6 +22,7 @@
         callbacks: Strong<dyn IUwbClientCallback>,
         #[allow(dead_code)]
         tasks: tokio::task::JoinSet<()>,
+        serial: File,
     },
 }
 
@@ -64,7 +65,11 @@
     async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
         log::debug!("open: {:?}", &self.path);
 
-        let mut serial = File::open(&self.path)
+        let serial = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(false)
+            .open(&self.path)
             .await
             .and_then(makeraw)
             .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
@@ -75,13 +80,17 @@
             let client_callbacks = callbacks.clone();
 
             let mut tasks = tokio::task::JoinSet::new();
+            let mut reader = serial
+                .try_clone()
+                .await
+                .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
 
             tasks.spawn(async move {
                 loop {
                     const UWB_HEADER_SIZE: usize = 4;
 
                     let mut buffer = vec![0; UWB_HEADER_SIZE];
-                    serial
+                    reader
                         .read_exact(&mut buffer[0..UWB_HEADER_SIZE])
                         .await
                         .unwrap();
@@ -89,7 +98,7 @@
                     let length = buffer[3] as usize + UWB_HEADER_SIZE;
 
                     buffer.resize(length, 0);
-                    serial
+                    reader
                         .read_exact(&mut buffer[UWB_HEADER_SIZE..length])
                         .await
                         .unwrap();
@@ -103,6 +112,7 @@
             *state = State::Opened {
                 callbacks: callbacks.clone(),
                 tasks,
+                serial,
             };
 
             Ok(())
@@ -149,10 +159,11 @@
     async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
         log::debug!("sendUciMessage");
 
-        if let State::Opened { .. } = &mut *self.state.lock().await {
-            fs::write(&self.path, data)
+        if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
+            serial
+                .write(data)
                 .await
-                .map(|_| data.len() as i32)
+                .map(|written| written as i32)
                 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
         } else {
             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
diff --git a/uwb/aidl/default/uwb-service.rc b/uwb/aidl/default/uwb-service.rc
new file mode 100644
index 0000000..d6a8eda
--- /dev/null
+++ b/uwb/aidl/default/uwb-service.rc
@@ -0,0 +1,3 @@
+service vendor.uwb_hal /apex/com.android.hardware.uwb/bin/hw/android.hardware.uwb-service ${ro.vendor.uwb.dev}
+    class hal
+    user uwb
diff --git a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
index 049ec73..00943fd 100644
--- a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
+++ b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
@@ -18,7 +18,6 @@
 #include <android-base/logging.h>
 #include <android/hardware/vr/1.0/IVr.h>
 #include <gtest/gtest.h>
-#include <hardware/vr.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp
deleted file mode 100644
index cc1d284..0000000
--- a/weaver/1.0/vts/functional/Android.bp
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_test {
-    name: "VtsHalWeaverV1_0TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalWeaverV1_0TargetTest.cpp"],
-    static_libs: ["android.hardware.weaver@1.0"],
-    test_suites: ["general-tests", "vts"],
-}
diff --git a/weaver/1.0/vts/functional/OWNERS b/weaver/1.0/vts/functional/OWNERS
deleted file mode 100644
index ec8c304..0000000
--- a/weaver/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 186411
-chengyouho@google.com
-frankwoo@google.com
diff --git a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp b/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
deleted file mode 100644
index 66465a9..0000000
--- a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/weaver/1.0/IWeaver.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-
-#include <limits>
-
-using ::android::hardware::weaver::V1_0::IWeaver;
-using ::android::hardware::weaver::V1_0::WeaverConfig;
-using ::android::hardware::weaver::V1_0::WeaverReadStatus;
-using ::android::hardware::weaver::V1_0::WeaverReadResponse;
-using ::android::hardware::weaver::V1_0::WeaverStatus;
-using ::android::hardware::Return;
-using ::android::sp;
-
-const std::vector<uint8_t> KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-const std::vector<uint8_t> WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-const std::vector<uint8_t> VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
-const std::vector<uint8_t> OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255};
-
-struct WeaverHidlTest : public ::testing::TestWithParam<std::string> {
-    virtual void SetUp() override {
-        weaver = IWeaver::getService(GetParam());
-        ASSERT_NE(weaver, nullptr);
-    }
-
-    virtual void TearDown() override {}
-
-    sp<IWeaver> weaver;
-};
-
-/*
- * Checks config values are suitably large
- */
-TEST_P(WeaverHidlTest, GetConfig) {
-    WeaverStatus status;
-    WeaverConfig config;
-
-    bool callbackCalled = false;
-    auto ret = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        callbackCalled = true;
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    EXPECT_GE(config.slots, 16u);
-    EXPECT_GE(config.keySize, 16u);
-    EXPECT_GE(config.valueSize, 16u);
-}
-
-/*
- * Gets the config twice and checks they are the same
- */
-TEST_P(WeaverHidlTest, GettingConfigMultipleTimesGivesSameResult) {
-    WeaverConfig config1;
-    WeaverConfig config2;
-
-    WeaverStatus status;
-    bool callbackCalled = false;
-    auto ret = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        callbackCalled = true;
-        status = s;
-        config1 = c;
-    });
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    callbackCalled = false;
-    ret = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        callbackCalled = true;
-        status = s;
-        config2 = c;
-    });
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    EXPECT_EQ(config1, config2);
-}
-
-/*
- * Gets the number of slots from the config and writes a key and value to the last one
- */
-TEST_P(WeaverHidlTest, WriteToLastSlot) {
-    WeaverStatus status;
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(configRet.isOk());
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    const uint32_t lastSlot = config.slots - 1;
-    const auto writeRet = weaver->write(lastSlot, KEY, VALUE);
-    ASSERT_TRUE(writeRet.isOk());
-    ASSERT_EQ(writeRet, WeaverStatus::OK);
-}
-
-/*
- * Writes a key and value to a slot
- * Reads the slot with the same key and receives the value that was previously written
- */
-TEST_P(WeaverHidlTest, WriteFollowedByReadGivesTheSameValue) {
-    constexpr uint32_t slotId = 0;
-    const auto ret = weaver->write(slotId, KEY, VALUE);
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(ret, WeaverStatus::OK);
-
-    bool callbackCalled = false;
-    WeaverReadStatus status;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet = weaver->read(slotId, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) {
-        callbackCalled = true;
-        status = s;
-        readValue = r.value;
-        timeout = r.timeout;
-    });
-    ASSERT_TRUE(readRet.isOk());
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_EQ(status, WeaverReadStatus::OK);
-    EXPECT_EQ(readValue, VALUE);
-    EXPECT_EQ(timeout, 0u);
-}
-
-/*
- * Writes a key and value to a slot
- * Overwrites the slot with a new key and value
- * Reads the slot with the new key and receives the new value
- */
-TEST_P(WeaverHidlTest, OverwritingSlotUpdatesTheValue) {
-    constexpr uint32_t slotId = 0;
-    const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE);
-    ASSERT_TRUE(initialWriteRet.isOk());
-    ASSERT_EQ(initialWriteRet, WeaverStatus::OK);
-
-    const auto overwriteRet = weaver->write(slotId, KEY, OTHER_VALUE);
-    ASSERT_TRUE(overwriteRet.isOk());
-    ASSERT_EQ(overwriteRet, WeaverStatus::OK);
-
-    bool callbackCalled = false;
-    WeaverReadStatus status;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet = weaver->read(slotId, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) {
-        callbackCalled = true;
-        status = s;
-        readValue = r.value;
-        timeout = r.timeout;
-    });
-    ASSERT_TRUE(readRet.isOk());
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_EQ(status, WeaverReadStatus::OK);
-    EXPECT_EQ(readValue, OTHER_VALUE);
-    EXPECT_EQ(timeout, 0u);
-}
-
-/*
- * Writes a key and value to a slot
- * Reads the slot with a different key so does not receive the value
- */
-TEST_P(WeaverHidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
-    constexpr uint32_t slotId = 0;
-    const auto ret = weaver->write(slotId, KEY, VALUE);
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(ret, WeaverStatus::OK);
-
-    bool callbackCalled = false;
-    WeaverReadStatus status;
-    std::vector<uint8_t> readValue;
-    const auto readRet =
-        weaver->read(slotId, WRONG_KEY, [&](WeaverReadStatus s, WeaverReadResponse r) {
-            callbackCalled = true;
-            status = s;
-            readValue = r.value;
-        });
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_TRUE(readRet.isOk());
-    ASSERT_EQ(status, WeaverReadStatus::INCORRECT_KEY);
-    EXPECT_TRUE(readValue.empty());
-}
-
-/*
- * Writing to an invalid slot fails
- */
-TEST_P(WeaverHidlTest, WritingToInvalidSlotFails) {
-    WeaverStatus status;
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(configRet.isOk());
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    if (config.slots == std::numeric_limits<uint32_t>::max()) {
-        // If there are no invalid slots then pass
-        return;
-    }
-
-    const auto writeRet = weaver->write(config.slots, KEY, VALUE);
-    ASSERT_TRUE(writeRet.isOk());
-    ASSERT_EQ(writeRet, WeaverStatus::FAILED);
-}
-
-/*
- * Reading from an invalid slot fails rather than incorrect key
- */
-TEST_P(WeaverHidlTest, ReadingFromInvalidSlotFails) {
-    WeaverStatus status;
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(configRet.isOk());
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    if (config.slots == std::numeric_limits<uint32_t>::max()) {
-        // If there are no invalid slots then pass
-        return;
-    }
-
-    bool callbackCalled = false;
-    WeaverReadStatus readStatus;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet =
-        weaver->read(config.slots, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) {
-            callbackCalled = true;
-            readStatus = s;
-            readValue = r.value;
-            timeout = r.timeout;
-        });
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_TRUE(readRet.isOk());
-    ASSERT_EQ(readStatus, WeaverReadStatus::FAILED);
-    EXPECT_TRUE(readValue.empty());
-    EXPECT_EQ(timeout, 0u);
-}
-
-/*
- * Writing a key that is too large fails
- */
-TEST_P(WeaverHidlTest, WriteWithTooLargeKeyFails) {
-    WeaverStatus status;
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(configRet.isOk());
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    std::vector<uint8_t> bigKey(config.keySize + 1);
-
-    constexpr uint32_t slotId = 0;
-    const auto writeRet = weaver->write(slotId, bigKey, VALUE);
-    ASSERT_TRUE(writeRet.isOk());
-    ASSERT_EQ(writeRet, WeaverStatus::FAILED);
-}
-
-/*
- * Writing a value that is too large fails
- */
-TEST_P(WeaverHidlTest, WriteWithTooLargeValueFails) {
-    WeaverStatus status;
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(configRet.isOk());
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    std::vector<uint8_t> bigValue(config.valueSize + 1);
-
-    constexpr uint32_t slotId = 0;
-    const auto writeRet = weaver->write(slotId, KEY, bigValue);
-    ASSERT_TRUE(writeRet.isOk());
-    ASSERT_EQ(writeRet, WeaverStatus::FAILED);
-}
-
-/*
- * Reading with a key that is loo large fails
- */
-TEST_P(WeaverHidlTest, ReadWithTooLargeKeyFails) {
-    WeaverStatus status;
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) {
-        status = s;
-        config = c;
-    });
-    ASSERT_TRUE(configRet.isOk());
-    ASSERT_EQ(status, WeaverStatus::OK);
-
-    std::vector<uint8_t> bigKey(config.keySize + 1);
-
-    constexpr uint32_t slotId = 0;
-    bool callbackCalled = false;
-    WeaverReadStatus readStatus;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet =
-        weaver->read(slotId, bigKey, [&](WeaverReadStatus s, WeaverReadResponse r) {
-            callbackCalled = true;
-            readStatus = s;
-            readValue = r.value;
-            timeout = r.timeout;
-        });
-    ASSERT_TRUE(callbackCalled);
-    ASSERT_TRUE(readRet.isOk());
-    ASSERT_EQ(readStatus, WeaverReadStatus::FAILED);
-    EXPECT_TRUE(readValue.empty());
-    EXPECT_EQ(timeout, 0u);
-}
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverHidlTest);
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, WeaverHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IWeaver::descriptor)),
-        android::hardware::PrintInstanceNameToString);
diff --git a/weaver/OWNERS b/weaver/OWNERS
new file mode 100644
index 0000000..7e579f6
--- /dev/null
+++ b/weaver/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 1081729
+ebiggers@google.com
+paulcrowley@google.com
+swillden@google.com
+wfrichar@google.com
+chengyouho@google.com
diff --git a/weaver/aidl/Android.bp b/weaver/aidl/Android.bp
index caa92aa..38d017f 100644
--- a/weaver/aidl/Android.bp
+++ b/weaver/aidl/Android.bp
@@ -17,5 +17,16 @@
             platform_apis: true,
         },
     },
-    versions: ["1"],
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+        {
+            version: "2",
+            imports: [],
+        },
+
+    ],
+    frozen: true,
 }
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/2/.hash b/weaver/aidl/aidl_api/android.hardware.weaver/2/.hash
new file mode 100644
index 0000000..0d204c9
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/2/.hash
@@ -0,0 +1 @@
+0d60d74c2704ad281e219244514516db8482ef3d
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/IWeaver.aidl
new file mode 100644
index 0000000..61627d9
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/IWeaver.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.weaver;
+@VintfStability
+interface IWeaver {
+  android.hardware.weaver.WeaverConfig getConfig();
+  android.hardware.weaver.WeaverReadResponse read(in int slotId, in byte[] key);
+  void write(in int slotId, in byte[] key, in byte[] value);
+  const int STATUS_FAILED = 1;
+  const int STATUS_INCORRECT_KEY = 2;
+  const int STATUS_THROTTLE = 3;
+}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverConfig.aidl
new file mode 100644
index 0000000..7491f32
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverConfig.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.weaver;
+@VintfStability
+parcelable WeaverConfig {
+  int slots;
+  int keySize;
+  int valueSize;
+}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverReadResponse.aidl
new file mode 100644
index 0000000..96e528f
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverReadResponse.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.weaver;
+@VintfStability
+parcelable WeaverReadResponse {
+  long timeout;
+  byte[] value;
+  android.hardware.weaver.WeaverReadStatus status = android.hardware.weaver.WeaverReadStatus.FAILED;
+}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverReadStatus.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverReadStatus.aidl
new file mode 100644
index 0000000..e0be80e
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/2/android/hardware/weaver/WeaverReadStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.weaver;
+@Backing(type="int") @VintfStability
+enum WeaverReadStatus {
+  OK,
+  FAILED,
+  INCORRECT_KEY,
+  THROTTLE,
+}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
index 47ee4c8..96e528f 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,4 +36,5 @@
 parcelable WeaverReadResponse {
   long timeout;
   byte[] value;
+  android.hardware.weaver.WeaverReadStatus status = android.hardware.weaver.WeaverReadStatus.FAILED;
 }
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl
new file mode 100644
index 0000000..fce9758
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.weaver;
+@Backing(type="int") @VintfStability
+enum WeaverReadStatus {
+  OK = 0,
+  FAILED = 1,
+  INCORRECT_KEY = 2,
+  THROTTLE = 3,
+}
diff --git a/weaver/aidl/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
index f51034a..ae816ef 100644
--- a/weaver/aidl/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
@@ -20,8 +20,8 @@
 import android.hardware.weaver.WeaverReadResponse;
 
 /**
- * Weaver provides secure storage of secret values that may only be read if the
- * corresponding key has been presented.
+ * Weaver provides secure persistent storage of secret values that may only be
+ * read if the corresponding key has been presented.
  *
  * The storage must be secure as the device's user authentication and encryption
  * relies on the security of these values. The cardinality of the domains of the
@@ -76,7 +76,8 @@
     WeaverReadResponse read(in int slotId, in byte[] key);
 
     /**
-     * Overwrites the identified slot with the provided key and value.
+     * Overwrites the identified slot with the provided key and value, rendering
+     * the previous contents of the slot permanently unrecoverable.
      *
      * The new values are written regardless of the current state of the slot in
      * order to remain idempotent.
diff --git a/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
index ec006e8..17ea718 100644
--- a/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,15 +16,22 @@
 
 package android.hardware.weaver;
 
+import android.hardware.weaver.WeaverReadStatus;
+
 @VintfStability
 parcelable WeaverReadResponse {
     /**
-     * The time to wait, in milliseconds, before making the next request.
+     * The time to wait, in milliseconds, before making the next request,
+     * must be greater than or equal to zero and less than INT_MAX.
      */
     long timeout;
     /**
      * The value read from the slot or empty if the value was not read.
      */
     byte[] value;
+    /**
+     * Status from WeaverReadStatus
+     */
+    WeaverReadStatus status = WeaverReadStatus.FAILED;
 }
 
diff --git a/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl b/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl
new file mode 100644
index 0000000..36e731f
--- /dev/null
+++ b/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.weaver;
+
+@VintfStability
+@Backing(type="int")
+enum WeaverReadStatus {
+    OK,
+    FAILED,
+    INCORRECT_KEY,
+    THROTTLE,
+}
diff --git a/weaver/aidl/default/Android.bp b/weaver/aidl/default/Android.bp
index 70d9171..494cb1b 100644
--- a/weaver/aidl/default/Android.bp
+++ b/weaver/aidl/default/Android.bp
@@ -34,7 +34,7 @@
         "Weaver.cpp",
     ],
     shared_libs: [
-        "android.hardware.weaver-V1-ndk",
+        "android.hardware.weaver-V2-ndk",
         "libbase",
         "libbinder_ndk",
     ],
diff --git a/weaver/aidl/default/Weaver.cpp b/weaver/aidl/default/Weaver.cpp
index 6b77924..c9ffe85 100644
--- a/weaver/aidl/default/Weaver.cpp
+++ b/weaver/aidl/default/Weaver.cpp
@@ -37,18 +37,19 @@
 }
 
 ::ndk::ScopedAStatus Weaver::read(int32_t in_slotId, const std::vector<uint8_t>& in_key, WeaverReadResponse* out_response) {
+    using ::aidl::android::hardware::weaver::WeaverReadStatus;
 
     if (in_slotId > 15 || in_key.size() > 16) {
-        *out_response = {0, {}};
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_FAILED));
+        *out_response = {0, {}, WeaverReadStatus::FAILED};
+        return ndk::ScopedAStatus::ok();
     }
 
     if (slot_array[in_slotId].key != in_key) {
-        *out_response = {0, {}};
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_INCORRECT_KEY));
+        *out_response = {0, {}, WeaverReadStatus::INCORRECT_KEY};
+        return ndk::ScopedAStatus::ok();
     }
 
-    *out_response = {0, slot_array[in_slotId].value};
+    *out_response = {0, slot_array[in_slotId].value, WeaverReadStatus::OK};
 
     return ::ndk::ScopedAStatus::ok();
 }
diff --git a/weaver/aidl/default/android.hardware.weaver-service.example.xml b/weaver/aidl/default/android.hardware.weaver-service.example.xml
index ed291cd..bfe4396 100644
--- a/weaver/aidl/default/android.hardware.weaver-service.example.xml
+++ b/weaver/aidl/default/android.hardware.weaver-service.example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.weaver</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IWeaver</name>
             <instance>default</instance>
diff --git a/weaver/aidl/vts/OWNERS b/weaver/aidl/vts/OWNERS
deleted file mode 100644
index 40d95e4..0000000
--- a/weaver/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chengyouho@google.com
-frankwoo@google.com
diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
deleted file mode 100644
index 878c762..0000000
--- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
-
-#include <aidl/android/hardware/weaver/IWeaver.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-
-#include <limits>
-
-using ::aidl::android::hardware::weaver::IWeaver;
-using ::aidl::android::hardware::weaver::WeaverConfig;
-using ::aidl::android::hardware::weaver::WeaverReadResponse;
-
-using ::ndk::SpAIBinder;
-
-const std::vector<uint8_t> KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-const std::vector<uint8_t> WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-const std::vector<uint8_t> VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
-const std::vector<uint8_t> OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255};
-
-struct WeaverAidlTest : public ::testing::TestWithParam<std::string> {
-    virtual void SetUp() override {
-        weaver = IWeaver::fromBinder(
-            SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
-        ASSERT_NE(weaver, nullptr);
-    }
-
-    virtual void TearDown() override {}
-
-    std::shared_ptr<IWeaver> weaver;
-};
-
-/*
- * Checks config values are suitably large
- */
-TEST_P(WeaverAidlTest, GetConfig) {
-    WeaverConfig config;
-
-    auto ret = weaver->getConfig(&config);
-
-    ASSERT_TRUE(ret.isOk());
-
-    EXPECT_GE(config.slots, 16u);
-    EXPECT_GE(config.keySize, 16u);
-    EXPECT_GE(config.valueSize, 16u);
-}
-
-/*
- * Gets the config twice and checks they are the same
- */
-TEST_P(WeaverAidlTest, GettingConfigMultipleTimesGivesSameResult) {
-    WeaverConfig config1;
-    WeaverConfig config2;
-
-    auto ret = weaver->getConfig(&config1);
-    ASSERT_TRUE(ret.isOk());
-
-    ret = weaver->getConfig(&config2);
-    ASSERT_TRUE(ret.isOk());
-
-    EXPECT_EQ(config1, config2);
-}
-
-/*
- * Gets the number of slots from the config and writes a key and value to the last one
- */
-TEST_P(WeaverAidlTest, WriteToLastSlot) {
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig(&config);
-
-    ASSERT_TRUE(configRet.isOk());
-
-    const uint32_t lastSlot = config.slots - 1;
-    const auto writeRet = weaver->write(lastSlot, KEY, VALUE);
-    ASSERT_TRUE(writeRet.isOk());
-}
-
-/*
- * Writes a key and value to a slot
- * Reads the slot with the same key and receives the value that was previously written
- */
-TEST_P(WeaverAidlTest, WriteFollowedByReadGivesTheSameValue) {
-    constexpr uint32_t slotId = 0;
-    const auto ret = weaver->write(slotId, KEY, VALUE);
-    ASSERT_TRUE(ret.isOk());
-
-    WeaverReadResponse response;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet = weaver->read(slotId, KEY, &response);
-
-    readValue = response.value;
-    timeout = response.timeout;
-
-    ASSERT_TRUE(readRet.isOk());
-    EXPECT_EQ(readValue, VALUE);
-    EXPECT_EQ(timeout, 0u);
-}
-
-/*
- * Writes a key and value to a slot
- * Overwrites the slot with a new key and value
- * Reads the slot with the new key and receives the new value
- */
-TEST_P(WeaverAidlTest, OverwritingSlotUpdatesTheValue) {
-    constexpr uint32_t slotId = 0;
-    const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE);
-    ASSERT_TRUE(initialWriteRet.isOk());
-
-    const auto overwriteRet = weaver->write(slotId, KEY, OTHER_VALUE);
-    ASSERT_TRUE(overwriteRet.isOk());
-
-    WeaverReadResponse response;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet = weaver->read(slotId, KEY, &response);
-
-    readValue = response.value;
-    timeout = response.timeout;
-
-    ASSERT_TRUE(readRet.isOk());
-    EXPECT_EQ(readValue, OTHER_VALUE);
-    EXPECT_EQ(timeout, 0u);
-}
-
-/*
- * Writes a key and value to a slot
- * Reads the slot with a different key so does not receive the value
- */
-TEST_P(WeaverAidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
-    constexpr uint32_t slotId = 0;
-    const auto ret = weaver->write(slotId, KEY, VALUE);
-    ASSERT_TRUE(ret.isOk());
-
-    WeaverReadResponse response;
-    std::vector<uint8_t> readValue;
-    const auto readRet =
-        weaver->read(slotId, WRONG_KEY, &response);
-
-    readValue = response.value;
-
-    ASSERT_FALSE(readRet.isOk());
-    ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::STATUS_INCORRECT_KEY, readRet.getServiceSpecificError());
-    EXPECT_TRUE(readValue.empty());
-}
-
-/*
- * Writing to an invalid slot fails
- */
-TEST_P(WeaverAidlTest, WritingToInvalidSlotFails) {
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig(&config);
-    ASSERT_TRUE(configRet.isOk());
-
-    if (config.slots == std::numeric_limits<uint32_t>::max()) {
-        // If there are no invalid slots then pass
-        return;
-    }
-
-    const auto writeRet = weaver->write(config.slots, KEY, VALUE);
-    ASSERT_FALSE(writeRet.isOk());
-}
-
-/*
- * Reading from an invalid slot fails rather than incorrect key
- */
-TEST_P(WeaverAidlTest, ReadingFromInvalidSlotFails) {
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig(&config);
-    ASSERT_TRUE(configRet.isOk());
-
-    if (config.slots == std::numeric_limits<uint32_t>::max()) {
-        // If there are no invalid slots then pass
-        return;
-    }
-
-    WeaverReadResponse response;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet =
-        weaver->read(config.slots, KEY, &response);
-
-    readValue = response.value;
-    timeout = response.timeout;
-
-    ASSERT_FALSE(readRet.isOk());
-    ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::STATUS_FAILED, readRet.getServiceSpecificError());
-    EXPECT_TRUE(readValue.empty());
-    EXPECT_EQ(timeout, 0u);
-}
-
-/*
- * Writing a key that is too large fails
- */
-TEST_P(WeaverAidlTest, WriteWithTooLargeKeyFails) {
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig(&config);
-    ASSERT_TRUE(configRet.isOk());
-
-    std::vector<uint8_t> bigKey(config.keySize + 1);
-
-    constexpr uint32_t slotId = 0;
-    const auto writeRet = weaver->write(slotId, bigKey, VALUE);
-    ASSERT_FALSE(writeRet.isOk());
-}
-
-/*
- * Writing a value that is too large fails
- */
-TEST_P(WeaverAidlTest, WriteWithTooLargeValueFails) {
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig(&config);
-    ASSERT_TRUE(configRet.isOk());
-
-    std::vector<uint8_t> bigValue(config.valueSize + 1);
-
-    constexpr uint32_t slotId = 0;
-    const auto writeRet = weaver->write(slotId, KEY, bigValue);
-    ASSERT_FALSE(writeRet.isOk());
-}
-
-/*
- * Reading with a key that is loo large fails
- */
-TEST_P(WeaverAidlTest, ReadWithTooLargeKeyFails) {
-    WeaverConfig config;
-    const auto configRet = weaver->getConfig(&config);
-    ASSERT_TRUE(configRet.isOk());
-
-    std::vector<uint8_t> bigKey(config.keySize + 1);
-
-    constexpr uint32_t slotId = 0;
-    WeaverReadResponse response;
-    std::vector<uint8_t> readValue;
-    uint32_t timeout;
-    const auto readRet =
-        weaver->read(slotId, bigKey, &response);
-
-    readValue = response.value;
-    timeout = response.timeout;
-
-    ASSERT_FALSE(readRet.isOk());
-    ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::STATUS_FAILED, readRet.getServiceSpecificError());
-    EXPECT_TRUE(readValue.empty());
-    EXPECT_EQ(timeout, 0u);
-}
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverAidlTest);
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, WeaverAidlTest,
-        testing::ValuesIn(android::getAidlHalInstanceNames(IWeaver::descriptor)),
-        android::PrintInstanceNameToString);
-
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    ABinderProcess_setThreadPoolMaxThreadCount(1);
-    ABinderProcess_startThreadPool();
-    return RUN_ALL_TESTS();
-}
diff --git a/weaver/aidl/vts/Android.bp b/weaver/vts/Android.bp
similarity index 92%
rename from weaver/aidl/vts/Android.bp
rename to weaver/vts/Android.bp
index cf1661c..ee03b28 100644
--- a/weaver/aidl/vts/Android.bp
+++ b/weaver/vts/Android.bp
@@ -34,7 +34,10 @@
         "libbinder_ndk",
         "libbase",
     ],
-    static_libs: ["android.hardware.weaver-V1-ndk"],
+    static_libs: [
+        "android.hardware.weaver-V2-ndk",
+        "android.hardware.weaver@1.0",
+    ],
     test_suites: [
         "general-tests",
         "vts",
diff --git a/weaver/vts/VtsHalWeaverTargetTest.cpp b/weaver/vts/VtsHalWeaverTargetTest.cpp
new file mode 100644
index 0000000..754d467
--- /dev/null
+++ b/weaver/vts/VtsHalWeaverTargetTest.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/weaver/IWeaver.h>
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/hardware/weaver/1.0/IWeaver.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <limits>
+
+using ::aidl::android::hardware::weaver::IWeaver;
+using ::aidl::android::hardware::weaver::WeaverConfig;
+using ::aidl::android::hardware::weaver::WeaverReadResponse;
+using ::aidl::android::hardware::weaver::WeaverReadStatus;
+
+using HidlIWeaver = ::android::hardware::weaver::V1_0::IWeaver;
+using HidlWeaverConfig = ::android::hardware::weaver::V1_0::WeaverConfig;
+using HidlWeaverReadStatus = ::android::hardware::weaver::V1_0::WeaverReadStatus;
+using HidlWeaverReadResponse = ::android::hardware::weaver::V1_0::WeaverReadResponse;
+using HidlWeaverStatus = ::android::hardware::weaver::V1_0::WeaverStatus;
+
+const std::string kSlotMapFile = "/metadata/password_slots/slot_map";
+const std::vector<uint8_t> KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+const std::vector<uint8_t> WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+const std::vector<uint8_t> VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+const std::vector<uint8_t> OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255};
+
+class WeaverAdapter {
+  public:
+    virtual ~WeaverAdapter() {}
+    virtual bool isReady() = 0;
+    virtual ::ndk::ScopedAStatus getConfig(WeaverConfig* _aidl_return) = 0;
+    virtual ::ndk::ScopedAStatus read(int32_t in_slotId, const std::vector<uint8_t>& in_key,
+                                      WeaverReadResponse* _aidl_return) = 0;
+    virtual ::ndk::ScopedAStatus write(int32_t in_slotId, const std::vector<uint8_t>& in_key,
+                                       const std::vector<uint8_t>& in_value) = 0;
+};
+
+class WeaverAidlAdapter : public WeaverAdapter {
+  public:
+    WeaverAidlAdapter(const std::string& param)
+        : aidl_weaver_(IWeaver::fromBinder(
+                  ::ndk::SpAIBinder(AServiceManager_waitForService(param.c_str())))) {}
+    ~WeaverAidlAdapter() {}
+
+    bool isReady() { return aidl_weaver_ != nullptr; }
+
+    ::ndk::ScopedAStatus getConfig(WeaverConfig* _aidl_return) {
+        return aidl_weaver_->getConfig(_aidl_return);
+    }
+
+    ::ndk::ScopedAStatus read(int32_t in_slotId, const std::vector<uint8_t>& in_key,
+                              WeaverReadResponse* _aidl_return) {
+        return aidl_weaver_->read(in_slotId, in_key, _aidl_return);
+    }
+
+    ::ndk::ScopedAStatus write(int32_t in_slotId, const std::vector<uint8_t>& in_key,
+                               const std::vector<uint8_t>& in_value) {
+        return aidl_weaver_->write(in_slotId, in_key, in_value);
+    }
+
+  private:
+    std::shared_ptr<IWeaver> aidl_weaver_;
+};
+
+class WeaverHidlAdapter : public WeaverAdapter {
+  public:
+    WeaverHidlAdapter(const std::string& param) : hidl_weaver_(HidlIWeaver::getService(param)) {}
+    ~WeaverHidlAdapter() {}
+
+    bool isReady() { return hidl_weaver_ != nullptr; }
+
+    ::ndk::ScopedAStatus getConfig(WeaverConfig* _aidl_return) {
+        bool callbackCalled = false;
+        HidlWeaverStatus status;
+        HidlWeaverConfig config;
+        auto ret = hidl_weaver_->getConfig([&](HidlWeaverStatus s, HidlWeaverConfig c) {
+            callbackCalled = true;
+            status = s;
+            config = c;
+        });
+        if (!ret.isOk() || !callbackCalled || status != HidlWeaverStatus::OK) {
+            return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
+        }
+        _aidl_return->slots = config.slots;
+        _aidl_return->keySize = config.keySize;
+        _aidl_return->valueSize = config.valueSize;
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    ::ndk::ScopedAStatus read(int32_t in_slotId, const std::vector<uint8_t>& in_key,
+                              WeaverReadResponse* _aidl_return) {
+        bool callbackCalled = false;
+        HidlWeaverReadStatus status;
+        std::vector<uint8_t> value;
+        uint32_t timeout;
+        auto ret = hidl_weaver_->read(in_slotId, in_key,
+                                      [&](HidlWeaverReadStatus s, HidlWeaverReadResponse r) {
+                                          callbackCalled = true;
+                                          status = s;
+                                          value = r.value;
+                                          timeout = r.timeout;
+                                      });
+        if (!ret.isOk() || !callbackCalled) {
+            return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
+        }
+        switch (status) {
+            case HidlWeaverReadStatus::OK:
+                _aidl_return->status = WeaverReadStatus::OK;
+                break;
+            case HidlWeaverReadStatus::FAILED:
+                _aidl_return->status = WeaverReadStatus::FAILED;
+                break;
+            case HidlWeaverReadStatus::INCORRECT_KEY:
+                _aidl_return->status = WeaverReadStatus::INCORRECT_KEY;
+                break;
+            case HidlWeaverReadStatus::THROTTLE:
+                _aidl_return->status = WeaverReadStatus::THROTTLE;
+                break;
+            default:
+                ADD_FAILURE() << "Unknown HIDL read status: " << static_cast<uint32_t>(status);
+                _aidl_return->status = WeaverReadStatus::FAILED;
+                break;
+        }
+        _aidl_return->value = value;
+        _aidl_return->timeout = timeout;
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    ::ndk::ScopedAStatus write(int32_t in_slotId, const std::vector<uint8_t>& in_key,
+                               const std::vector<uint8_t>& in_value) {
+        auto status = hidl_weaver_->write(in_slotId, in_key, in_value);
+        switch (status) {
+            case HidlWeaverStatus::OK:
+                return ::ndk::ScopedAStatus::ok();
+            case HidlWeaverStatus::FAILED:
+                return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
+            default:
+                ADD_FAILURE() << "Unknown HIDL write status: " << status.description();
+                return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
+        }
+    }
+
+  private:
+    android::sp<HidlIWeaver> hidl_weaver_;
+};
+
+class WeaverTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
+    void SetUp() override;
+    void TearDown() override {}
+    void FindFreeSlots();
+
+    std::unique_ptr<WeaverAdapter> weaver_;
+    WeaverConfig config_;
+    uint32_t first_free_slot_;
+    uint32_t last_free_slot_;
+};
+
+void WeaverTest::SetUp() {
+    std::string api, instance_name;
+    std::tie(api, instance_name) = GetParam();
+    if (api == "hidl") {
+        weaver_.reset(new WeaverHidlAdapter(instance_name));
+    } else if (api == "aidl") {
+        weaver_.reset(new WeaverAidlAdapter(instance_name));
+    } else {
+        FAIL() << "Bad test parameterization";
+    }
+    ASSERT_TRUE(weaver_->isReady());
+
+    auto ret = weaver_->getConfig(&config_);
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_GT(config_.slots, 0);
+    GTEST_LOG_(INFO) << "WeaverConfig: slots=" << config_.slots << ", keySize=" << config_.keySize
+                     << ", valueSize=" << config_.valueSize;
+
+    FindFreeSlots();
+    GTEST_LOG_(INFO) << "First free slot is " << first_free_slot_ << ", last free slot is "
+                     << last_free_slot_;
+}
+
+void WeaverTest::FindFreeSlots() {
+    // Determine which Weaver slots are in use by the system. These slots can't be used by the test.
+    std::set<uint32_t> used_slots;
+    if (access(kSlotMapFile.c_str(), F_OK) == 0) {
+        std::string contents;
+        ASSERT_TRUE(android::base::ReadFileToString(kSlotMapFile, &contents))
+                << "Failed to read " << kSlotMapFile;
+        for (const auto& line : android::base::Split(contents, "\n")) {
+            auto trimmed_line = android::base::Trim(line);
+            if (trimmed_line[0] == '#' || trimmed_line[0] == '\0') continue;
+            auto slot_and_user = android::base::Split(trimmed_line, "=");
+            uint32_t slot;
+            ASSERT_TRUE(slot_and_user.size() == 2 &&
+                        android::base::ParseUint(slot_and_user[0], &slot))
+                    << "Error parsing " << kSlotMapFile << " at \"" << line << "\"";
+            GTEST_LOG_(INFO) << "Slot " << slot << " is in use by " << slot_and_user[1];
+            ASSERT_LT(slot, config_.slots);
+            used_slots.insert(slot);
+        }
+    }
+    // Starting in Android 14, the system will always use at least one Weaver slot if Weaver is
+    // supported at all.  Make sure we saw at least one.
+    // TODO: uncomment after Android 14 is merged into AOSP
+    // ASSERT_FALSE(used_slots.empty())
+    //<< "Could not determine which Weaver slots are in use by the system";
+
+    // Find the first free slot.
+    int found = 0;
+    for (uint32_t i = 0; i < config_.slots; i++) {
+        if (used_slots.find(i) == used_slots.end()) {
+            first_free_slot_ = i;
+            found++;
+            break;
+        }
+    }
+    // Find the last free slot.
+    for (uint32_t i = config_.slots; i > 0; i--) {
+        if (used_slots.find(i - 1) == used_slots.end()) {
+            last_free_slot_ = i - 1;
+            found++;
+            break;
+        }
+    }
+    ASSERT_EQ(found, 2) << "All Weaver slots are already in use by the system";
+}
+
+/*
+ * Checks config values are suitably large
+ */
+TEST_P(WeaverTest, GetConfig) {
+    EXPECT_GE(config_.slots, 16u);
+    EXPECT_GE(config_.keySize, 16u);
+    EXPECT_GE(config_.valueSize, 16u);
+}
+
+/*
+ * Gets the config twice and checks they are the same
+ */
+TEST_P(WeaverTest, GettingConfigMultipleTimesGivesSameResult) {
+    WeaverConfig config2;
+
+    auto ret = weaver_->getConfig(&config2);
+    ASSERT_TRUE(ret.isOk());
+
+    EXPECT_EQ(config_, config2);
+}
+
+/*
+ * Writes a key and value to the last free slot
+ */
+TEST_P(WeaverTest, WriteToLastSlot) {
+    const auto writeRet = weaver_->write(last_free_slot_, KEY, VALUE);
+    ASSERT_TRUE(writeRet.isOk());
+}
+
+/*
+ * Writes a key and value to a slot
+ * Reads the slot with the same key and receives the value that was previously written
+ */
+TEST_P(WeaverTest, WriteFollowedByReadGivesTheSameValue) {
+    const uint32_t slotId = first_free_slot_;
+    const auto ret = weaver_->write(slotId, KEY, VALUE);
+    ASSERT_TRUE(ret.isOk());
+
+    WeaverReadResponse response;
+    const auto readRet = weaver_->read(slotId, KEY, &response);
+    ASSERT_TRUE(readRet.isOk());
+    EXPECT_EQ(response.value, VALUE);
+    EXPECT_EQ(response.timeout, 0u);
+    EXPECT_EQ(response.status, WeaverReadStatus::OK);
+}
+
+/*
+ * Writes a key and value to a slot
+ * Overwrites the slot with a new key and value
+ * Reads the slot with the new key and receives the new value
+ */
+TEST_P(WeaverTest, OverwritingSlotUpdatesTheValue) {
+    const uint32_t slotId = first_free_slot_;
+    const auto initialWriteRet = weaver_->write(slotId, WRONG_KEY, VALUE);
+    ASSERT_TRUE(initialWriteRet.isOk());
+
+    const auto overwriteRet = weaver_->write(slotId, KEY, OTHER_VALUE);
+    ASSERT_TRUE(overwriteRet.isOk());
+
+    WeaverReadResponse response;
+    const auto readRet = weaver_->read(slotId, KEY, &response);
+    ASSERT_TRUE(readRet.isOk());
+    EXPECT_EQ(response.value, OTHER_VALUE);
+    EXPECT_EQ(response.timeout, 0u);
+    EXPECT_EQ(response.status, WeaverReadStatus::OK);
+}
+
+/*
+ * Writes a key and value to a slot
+ * Reads the slot with a different key so does not receive the value
+ */
+TEST_P(WeaverTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) {
+    const uint32_t slotId = first_free_slot_;
+    const auto writeRet = weaver_->write(slotId, KEY, VALUE);
+    ASSERT_TRUE(writeRet.isOk());
+
+    WeaverReadResponse response;
+    const auto readRet = weaver_->read(slotId, WRONG_KEY, &response);
+    ASSERT_TRUE(readRet.isOk());
+    EXPECT_TRUE(response.value.empty());
+    EXPECT_EQ(response.status, WeaverReadStatus::INCORRECT_KEY);
+}
+
+/*
+ * Writing to an invalid slot fails
+ */
+TEST_P(WeaverTest, WritingToInvalidSlotFails) {
+    if (config_.slots == std::numeric_limits<uint32_t>::max()) {
+        // If there are no invalid slots then pass
+        return;
+    }
+
+    const auto writeRet = weaver_->write(config_.slots, KEY, VALUE);
+    ASSERT_FALSE(writeRet.isOk());
+}
+
+/*
+ * Reading from an invalid slot fails rather than incorrect key
+ */
+TEST_P(WeaverTest, ReadingFromInvalidSlotFails) {
+    if (config_.slots == std::numeric_limits<uint32_t>::max()) {
+        // If there are no invalid slots then pass
+        return;
+    }
+
+    WeaverReadResponse response;
+    const auto readRet = weaver_->read(config_.slots, KEY, &response);
+    ASSERT_TRUE(readRet.isOk());
+    EXPECT_TRUE(response.value.empty());
+    EXPECT_EQ(response.timeout, 0u);
+    EXPECT_EQ(response.status, WeaverReadStatus::FAILED);
+}
+
+/*
+ * Writing a key that is too large fails
+ */
+TEST_P(WeaverTest, WriteWithTooLargeKeyFails) {
+    std::vector<uint8_t> bigKey(config_.keySize + 1);
+
+    const auto writeRet = weaver_->write(first_free_slot_, bigKey, VALUE);
+    ASSERT_FALSE(writeRet.isOk());
+}
+
+/*
+ * Writing a value that is too large fails
+ */
+TEST_P(WeaverTest, WriteWithTooLargeValueFails) {
+    std::vector<uint8_t> bigValue(config_.valueSize + 1);
+
+    const auto writeRet = weaver_->write(first_free_slot_, KEY, bigValue);
+    ASSERT_FALSE(writeRet.isOk());
+}
+
+/*
+ * Reading with a key that is too large fails
+ */
+TEST_P(WeaverTest, ReadWithTooLargeKeyFails) {
+    std::vector<uint8_t> bigKey(config_.keySize + 1);
+
+    WeaverReadResponse response;
+    const auto readRet = weaver_->read(first_free_slot_, bigKey, &response);
+    ASSERT_TRUE(readRet.isOk());
+    EXPECT_TRUE(response.value.empty());
+    EXPECT_EQ(response.timeout, 0u);
+    EXPECT_EQ(response.status, WeaverReadStatus::FAILED);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverTest);
+
+// Instantiate the test for each HIDL Weaver service.
+INSTANTIATE_TEST_SUITE_P(
+        PerHidlInstance, WeaverTest,
+        testing::Combine(testing::Values("hidl"),
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 HidlIWeaver::descriptor))),
+        [](const testing::TestParamInfo<std::tuple<std::string, std::string>>& info) {
+            return android::hardware::PrintInstanceNameToString(
+                    testing::TestParamInfo<std::string>{std::get<1>(info.param), info.index});
+        });
+
+// Instantiate the test for each AIDL Weaver service.
+INSTANTIATE_TEST_SUITE_P(
+        PerAidlInstance, WeaverTest,
+        testing::Combine(testing::Values("aidl"),
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IWeaver::descriptor))),
+        [](const testing::TestParamInfo<std::tuple<std::string, std::string>>& info) {
+            // This name_generator makes the instance name be included in the test case names, e.g.
+            // "PerAidlInstance/WeaverTest#GetConfig/0_android_hardware_weaver_IWeaver_default"
+            // instead of "PerAidlInstance/WeaverTest#GetConfig/0".
+            return android::PrintInstanceNameToString(
+                    testing::TestParamInfo<std::string>{std::get<1>(info.param), info.index});
+        });
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
index ded9122..e84a5cf 100644
--- a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
+++ b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
@@ -28,7 +28,7 @@
 using namespace std::chrono_literals;
 
 static constexpr std::chrono::milliseconds kPollTimeout = 300ms;
-static constexpr bool kSuperVerbose = true;
+static constexpr bool kSuperVerbose = false;
 
 InterceptorRelay::InterceptorRelay(uint32_t nlFamily, uint32_t clientNlPid,
                                    const std::string& clientName)