Merge changes Ic93dd0c7,Ibabbb998,I3a26f901,I9708086f into main

* changes:
  Add last video render time to bug reports
  Support video render metrics for OMX
  Fix delay used when polling for rendered buffers
  Add perfetto trigger for video freeze
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 24a11e3..0d20f52 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -111,6 +111,7 @@
 
 cc_library_shared {
     name: "libcamera2ndk_vendor",
+    cpp_std: "gnu++17",
     vendor: true,
     srcs: [
         "ndk_vendor/impl/ACameraDevice.cpp",
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
index 4b489e2..96bf4f5 100644
--- a/media/aconfig/Android.bp
+++ b/media/aconfig/Android.bp
@@ -12,5 +12,11 @@
 
 cc_aconfig_library {
     name: "aconfig_mediacodec_flags_c_lib",
+    min_sdk_version: "30",
+    vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+    ],
     aconfig_declarations: "aconfig_mediacodec_flags",
 }
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index 90ddf27..c82ad4d 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -13,3 +13,10 @@
   description: "Feature flags for media codec importance"
   bug: "297929011"
 }
+
+flag {
+  name: "aidl_hal"
+  namespace: "codec_fwk"
+  description: "Feature flags for enabling AIDL HAL handling"
+  bug: "251850069"
+}
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 5558259..947352f 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -565,7 +565,8 @@
                 AudioDeviceType::IN_DEVICE, AudioDeviceType::OUT_DEVICE);
         append_AudioDeviceDescription(pairs,
                 AUDIO_DEVICE_IN_PROXY, AUDIO_DEVICE_OUT_PROXY,
-                AudioDeviceType::IN_AFE_PROXY, AudioDeviceType::OUT_AFE_PROXY);
+                AudioDeviceType::IN_AFE_PROXY, AudioDeviceType::OUT_AFE_PROXY,
+                GET_DEVICE_DESC_CONNECTION(VIRTUAL));
         append_AudioDeviceDescription(pairs,
                 AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_OUT_USB_HEADSET,
                 AudioDeviceType::IN_HEADSET, AudioDeviceType::OUT_HEADSET,
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 73cae93..7a9af18 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -6,7 +6,10 @@
 // use libcodec2-aidl-client-defaults instead
 cc_library {
     name: "libcodec2_aidl_client",
-    min_sdk_version: "31",
+
+    defaults: [
+        "libcodec2_hal_selection",
+    ],
 
     srcs: [
         "BufferTypes.cpp",
@@ -36,7 +39,6 @@
     ],
 
     static_libs: [
-        "libPlatformProperties",
         "libaidlcommonsupport",
     ],
 
@@ -55,12 +57,15 @@
 // use libcodec2-aidl-defaults instead
 cc_library {
     name: "libcodec2_aidl",
-    min_sdk_version: "31",
+    min_sdk_version: "30",
     vendor_available: true,
     apex_available: [
         "//apex_available:platform",
         "com.android.media.swcodec",
-        "test_com.android.media.swcodec",
+    ],
+
+    defaults: [
+        "libcodec2_hal_selection",
     ],
 
     srcs: [
@@ -98,7 +103,6 @@
     ],
 
     static_libs: [
-        "libPlatformProperties",
         "libaidlcommonsupport",
     ],
 
@@ -134,7 +138,7 @@
 // public dependency for Codec 2.0 HAL service implementations
 cc_defaults {
     name: "libcodec2-aidl-defaults",
-    min_sdk_version: "31",
+    min_sdk_version: "30",
     defaults: ["libcodec2-impl-defaults"],
 
     shared_libs: [
@@ -147,7 +151,6 @@
 // public dependency for Codec 2.0 HAL client
 cc_defaults {
     name: "libcodec2-aidl-client-defaults",
-    min_sdk_version: "31",
     defaults: ["libcodec2-impl-defaults"],
 
     shared_libs: [
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
index b1af579..bc4948b 100644
--- a/media/codec2/hal/aidl/BufferTypes.cpp
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -201,7 +201,7 @@
 
 template<>
 void SetHandle(BaseBlock *block, const C2Handle *handle) {
-    block->set<BaseBlock::nativeBlock>(makeToAidl(handle));
+    block->set<BaseBlock::nativeBlock>(dupToAidl(handle));
 }
 
 template<>
diff --git a/media/codec2/hal/aidl/ParamTypes.cpp b/media/codec2/hal/aidl/ParamTypes.cpp
index 41e6f50..5ad0810 100644
--- a/media/codec2/hal/aidl/ParamTypes.cpp
+++ b/media/codec2/hal/aidl/ParamTypes.cpp
@@ -19,8 +19,11 @@
 #include <android-base/logging.h>
 
 #include <android/binder_manager.h>
-#include <android/sysprop/MediaProperties.sysprop.h>
+// NOTE: due to dependency from mainline modules cannot use libsysprop
+// #include <android/sysprop/MediaProperties.sysprop.h>
+#include <android-base/properties.h>
 #include <codec2/aidl/ParamTypes.h>
+#include <codec2/common/HalSelection.h>
 #include <codec2/common/ParamTypes.h>
 
 #include "ParamTypes-specialization.h"
@@ -160,28 +163,7 @@
 namespace utils {
 
 bool IsSelected() {
-    // TODO: read from aconfig flags
-    const bool enabled = false;
-
-    if (!enabled) {
-        // Cannot select AIDL if not enabled
-        return false;
-    }
-    using ::android::sysprop::MediaProperties::codec2_hal_selection;
-    using ::android::sysprop::MediaProperties::codec2_hal_selection_values;
-    constexpr codec2_hal_selection_values AIDL = codec2_hal_selection_values::AIDL;
-    constexpr codec2_hal_selection_values HIDL = codec2_hal_selection_values::HIDL;
-    codec2_hal_selection_values selection = codec2_hal_selection().value_or(HIDL);
-    switch (selection) {
-    case AIDL:
-        return true;
-    case HIDL:
-        return false;
-    default:
-        LOG(FATAL) << "Unexpected codec2 HAL selection value: " << (int)selection;
-    }
-
-    return false;
+    return ::android::IsCodec2AidlHalSelected();
 }
 
 const char* asString(Status status, const char* def) {
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 1e9aa7f..597852a 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -46,6 +46,7 @@
 #include <aidl/android/hardware/media/c2/StructDescriptor.h>
 
 #include <aidlcommonsupport/NativeHandle.h>
+#include <android/api-level.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_ibinder.h>
 #include <android/binder_manager.h>
@@ -1440,12 +1441,16 @@
     std::vector<std::string> names;
 
     if (c2_aidl::utils::IsSelected()) {
-        // Get AIDL service names
-        AServiceManager_forEachDeclaredInstance(
-                AidlBase::descriptor, &names, [](const char *name, void *context) {
-                    std::vector<std::string> *names = (std::vector<std::string> *)context;
-                    names->emplace_back(name);
-                });
+        if (__builtin_available(android __ANDROID_API_S__, *)) {
+            // Get AIDL service names
+            AServiceManager_forEachDeclaredInstance(
+                    AidlBase::descriptor, &names, [](const char *name, void *context) {
+                        std::vector<std::string> *names = (std::vector<std::string> *)context;
+                        names->emplace_back(name);
+                    });
+        } else {
+            LOG(FATAL) << "C2 AIDL cannot be selected on Android version older than 35";
+        }
     } else {
         // Get HIDL service names
         using ::android::hardware::media::c2::V1_0::IComponentStore;
@@ -1547,21 +1552,25 @@
     LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
 
     if (c2_aidl::utils::IsSelected()) {
-        std::string instanceName =
-            ::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
-        if (AServiceManager_isDeclared(instanceName.c_str())) {
-            std::shared_ptr<AidlBase> baseStore = AidlBase::fromBinder(
-                    ::ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
-            CHECK(baseStore) << "Codec2 AIDL service \"" << name << "\""
-                                " inaccessible for unknown reasons.";
-            LOG(VERBOSE) << "Client to Codec2 AIDL service \"" << name << "\" created";
-            std::shared_ptr<c2_aidl::IConfigurable> configurable;
-            ::ndk::ScopedAStatus transStatus = baseStore->getConfigurable(&configurable);
-            CHECK(transStatus.isOk()) << "Codec2 AIDL service \"" << name << "\""
-                                        "does not have IConfigurable.";
-            return std::make_shared<Codec2Client>(baseStore, configurable, index);
+        if (__builtin_available(android __ANDROID_API_S__, *)) {
+            std::string instanceName =
+                ::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
+            if (AServiceManager_isDeclared(instanceName.c_str())) {
+                std::shared_ptr<AidlBase> baseStore = AidlBase::fromBinder(
+                        ::ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
+                CHECK(baseStore) << "Codec2 AIDL service \"" << name << "\""
+                                    " inaccessible for unknown reasons.";
+                LOG(VERBOSE) << "Client to Codec2 AIDL service \"" << name << "\" created";
+                std::shared_ptr<c2_aidl::IConfigurable> configurable;
+                ::ndk::ScopedAStatus transStatus = baseStore->getConfigurable(&configurable);
+                CHECK(transStatus.isOk()) << "Codec2 AIDL service \"" << name << "\""
+                                            "does not have IConfigurable.";
+                return std::make_shared<Codec2Client>(baseStore, configurable, index);
+            } else {
+                LOG(ERROR) << "Codec2 AIDL service \"" << name << "\" is not declared";
+            }
         } else {
-            LOG(ERROR) << "Codec2 AIDL service \"" << name << "\" is not declared";
+            LOG(FATAL) << "C2 AIDL cannot be selected on Android version older than 35";
         }
     } else {
         std::string instanceName = "android.hardware.media.c2/" + name;
@@ -2361,6 +2370,11 @@
     mOutputBufferQueue->expireOldWaiters();
 }
 
+void Codec2Client::Component::onBufferReleasedFromOutputSurface(
+        uint32_t generation) {
+    (void) generation;
+}
+
 c2_status_t Codec2Client::Component::connectToInputSurface(
         const std::shared_ptr<InputSurface>& inputSurface,
         std::shared_ptr<InputSurfaceConnection>* connection) {
diff --git a/media/codec2/hal/client/include/codec2/hidl/client.h b/media/codec2/hal/client/include/codec2/hidl/client.h
index 0c7dd77..a8dd0bf 100644
--- a/media/codec2/hal/client/include/codec2/hidl/client.h
+++ b/media/codec2/hal/client/include/codec2/hidl/client.h
@@ -474,6 +474,10 @@
     void stopUsingOutputSurface(
             C2BlockPool::local_id_t blockPoolId);
 
+    // Notify a buffer is released from output surface.
+    void onBufferReleasedFromOutputSurface(
+            uint32_t generation);
+
     // Connect to a given InputSurface.
     c2_status_t connectToInputSurface(
             const std::shared_ptr<InputSurface>& inputSurface,
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index f86e048..7f4f86b 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -141,11 +141,14 @@
                             "status = " << INVALID_OPERATION << ".";
             return INVALID_OPERATION;
         }
-        result = igbp->attachBuffer(bqSlot, graphicBuffer);
-        if (result == OK) {
-            syncVar->notifyDequeuedLocked();
-        }
+        syncVar->notifyDequeuedLocked();
         syncVar->unlock();
+        result = igbp->attachBuffer(bqSlot, graphicBuffer);
+        if (result != OK) {
+            syncVar->lock();
+            syncVar->notifyQueuedLocked();
+            syncVar->unlock();
+        }
     } else {
         result = igbp->attachBuffer(bqSlot, graphicBuffer);
     }
@@ -435,13 +438,13 @@
 
         auto syncVar = syncMem ? syncMem->mem() : nullptr;
         if(syncVar) {
-            syncVar->lock();
             status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                          input, output);
             if (status == OK) {
+                syncVar->lock();
                 syncVar->notifyQueuedLocked();
+                syncVar->unlock();
             }
-            syncVar->unlock();
         } else {
             status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                          input, output);
@@ -490,13 +493,13 @@
     auto syncVar = syncMem ? syncMem->mem() : nullptr;
     status_t status = OK;
     if (syncVar) {
-        syncVar->lock();
         status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                                   input, output);
         if (status == OK) {
+            syncVar->lock();
             syncVar->notifyQueuedLocked();
+            syncVar->unlock();
         }
-        syncVar->unlock();
     } else {
         status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                                   input, output);
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index f0193d7..2aedd8b 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -28,3 +28,40 @@
         "libstagefright_foundation",
     ],
 }
+
+cc_library_static {
+    name: "libcodec2_hal_selection_static",
+    double_loadable: true,
+    vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
+
+    srcs: [
+        "HalSelection.cpp",
+    ],
+
+    export_include_dirs: ["include/"],
+
+    shared_libs: [
+        "libbase",
+        "server_configurable_flags",
+    ],
+
+    static_libs: ["aconfig_mediacodec_flags_c_lib"],
+}
+
+cc_defaults {
+    name: "libcodec2_hal_selection",
+    static_libs: [
+        "aconfig_mediacodec_flags_c_lib",
+        "libcodec2_hal_selection_static",
+    ],
+    shared_libs: [
+        "libbase",
+        "server_configurable_flags",
+    ],
+}
diff --git a/media/codec2/hal/common/HalSelection.cpp b/media/codec2/hal/common/HalSelection.cpp
new file mode 100644
index 0000000..761a409
--- /dev/null
+++ b/media/codec2/hal/common/HalSelection.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "Codec2-HalSelection"
+#include <android-base/logging.h>
+
+// NOTE: due to dependency from mainline modules cannot use libsysprop
+// #include <android/sysprop/MediaProperties.sysprop.h>
+#include <android-base/properties.h>
+#include <com_android_media_codec_flags.h>
+
+#include <codec2/common/HalSelection.h>
+
+namespace android {
+
+bool IsCodec2AidlHalSelected() {
+    if (!com::android::media::codec::flags::provider_->aidl_hal()) {
+        // Cannot select AIDL if not enabled
+        return false;
+    }
+#if 0
+    // NOTE: due to dependency from mainline modules cannot use libsysprop
+    using ::android::sysprop::MediaProperties::codec2_hal_selection;
+    using ::android::sysprop::MediaProperties::codec2_hal_selection_values;
+    constexpr codec2_hal_selection_values AIDL = codec2_hal_selection_values::AIDL;
+    constexpr codec2_hal_selection_values HIDL = codec2_hal_selection_values::HIDL;
+    codec2_hal_selection_values selection = codec2_hal_selection().value_or(HIDL);
+    switch (selection) {
+    case AIDL:
+        return true;
+    case HIDL:
+        return false;
+    default:
+        LOG(FATAL) << "Unexpected codec2 HAL selection value: " << (int)selection;
+    }
+#else
+    std::string selection = ::android::base::GetProperty("media.c2.hal.selection", "hidl");
+    if (selection == "aidl") {
+        return true;
+    } else if (selection == "hidl") {
+        return false;
+    } else {
+        LOG(FATAL) << "Unexpected codec2 HAL selection value: " << selection;
+    }
+#endif
+
+    return false;
+}
+
+}  // namespace android
diff --git a/media/codec2/hal/common/include/codec2/common/BufferTypes.h b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
index afd2db0..af71122 100644
--- a/media/codec2/hal/common/include/codec2/common/BufferTypes.h
+++ b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
@@ -183,7 +183,8 @@
                 baseBlocks, baseBlockIndices);
     }
     switch (blockPoolData->getType()) {
-    case _C2BlockPoolData::TYPE_BUFFERPOOL: {
+    case _C2BlockPoolData::TYPE_BUFFERPOOL:
+    case _C2BlockPoolData::TYPE_BUFFERPOOL2: {
             // BufferPoolData
             std::shared_ptr<typename BufferPoolTypes::BufferPoolData> bpData;
             if (!GetBufferPoolData<BufferPoolTypes>(blockPoolData, &bpData) || !bpData) {
@@ -194,28 +195,30 @@
                     index, bpData,
                     bufferPoolSender, baseBlocks, baseBlockIndices);
         }
-    case _C2BlockPoolData::TYPE_BUFFERQUEUE:
-        uint32_t gen;
-        uint64_t bqId;
-        int32_t bqSlot;
-        // Update handle if migration happened.
-        if (_C2BlockFactory::GetBufferQueueData(
-                blockPoolData, &gen, &bqId, &bqSlot)) {
-            android::MigrateNativeCodec2GrallocHandle(
-                    const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
+    case _C2BlockPoolData::TYPE_BUFFERQUEUE: {
+            uint32_t gen;
+            uint64_t bqId;
+            int32_t bqSlot;
+            // Update handle if migration happened.
+            if (_C2BlockFactory::GetBufferQueueData(
+                    blockPoolData, &gen, &bqId, &bqSlot)) {
+                android::MigrateNativeCodec2GrallocHandle(
+                        const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
+            }
+            return _addBaseBlock(
+                    index, handle,
+                    baseBlocks, baseBlockIndices);
         }
-        return _addBaseBlock(
-                index, handle,
-                baseBlocks, baseBlockIndices);
-    case _C2BlockPoolData::TYPE_AHWBUFFER:
-        AHardwareBuffer *pBuf;
-        if (!_C2BlockFactory::GetAHardwareBuffer(blockPoolData, &pBuf)) {
-            LOG(ERROR) << "AHardwareBuffer unavailable in a block.";
-            return false;
+    case _C2BlockPoolData::TYPE_AHWBUFFER: {
+            AHardwareBuffer *pBuf;
+            if (!_C2BlockFactory::GetAHardwareBuffer(blockPoolData, &pBuf)) {
+                LOG(ERROR) << "AHardwareBuffer unavailable in a block.";
+                return false;
+            }
+            return _addBaseBlock(
+                    index, pBuf,
+                    baseBlocks, baseBlockIndices);
         }
-        return _addBaseBlock(
-                index, pBuf,
-                baseBlocks, baseBlockIndices);
     default:
         LOG(ERROR) << "Unknown C2BlockPoolData type.";
         return false;
diff --git a/media/codec2/hal/common/include/codec2/common/HalSelection.h b/media/codec2/hal/common/include/codec2/common/HalSelection.h
new file mode 100644
index 0000000..7c77515
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/HalSelection.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HAL_SELECTION_H
+#define CODEC2_HAL_SELECTION_H
+
+namespace android {
+
+// Returns true iff AIDL c2 HAL is selected for the system
+bool IsCodec2AidlHalSelected();
+
+}  // namespace android
+
+#endif  // CODEC2_HAL_SELECTION_H
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 222c3d2..ce9fc39 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define LOG_TAG "codec2_hidl_hal_audio_dec_test"
 
 #include <android-base/logging.h>
+#include <android/binder_process.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <stdio.h>
@@ -27,6 +28,7 @@
 #include <C2BufferPriv.h>
 #include <C2Config.h>
 #include <C2Debug.h>
+#include <codec2/aidl/ParamTypes.h>
 #include <codec2/hidl/client.h>
 
 #include "media_c2_hidl_test_common.h"
@@ -88,7 +90,8 @@
 
         std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
+        mLinearPool = std::make_shared<C2PooledBlockPool>(
+                mLinearAllocator, mBlockPoolId++, getBufferPoolVer());
         ASSERT_NE(mLinearPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
@@ -864,5 +867,6 @@
     }
 
     ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index 327717b..f8c2903 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define LOG_TAG "codec2_hidl_hal_audio_enc_test"
 
 #include <android-base/logging.h>
+#include <android/binder_process.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <stdio.h>
@@ -69,7 +70,8 @@
 
         std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
+        mLinearPool = std::make_shared<C2PooledBlockPool>(
+                mLinearAllocator, mBlockPoolId++, getBufferPoolVer());
         ASSERT_NE(mLinearPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
@@ -775,6 +777,7 @@
                 std::make_tuple(std::get<0>(params), std::get<1>(params), true, 2));
     }
 
+    ABinderProcess_startThreadPool();
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/Android.bp b/media/codec2/hal/hidl/1.0/vts/functional/common/Android.bp
index be4bafa..0f07077 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/Android.bp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/Android.bp
@@ -11,6 +11,7 @@
     name: "VtsHalMediaC2V1_0CommonUtil",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "libcodec2-aidl-client-defaults",
         "libcodec2-hidl-client-defaults",
     ],
 
@@ -29,6 +30,7 @@
     name: "VtsHalMediaC2V1_0Defaults",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "libcodec2-aidl-client-defaults",
         "libcodec2-hidl-client-defaults",
     ],
 
@@ -38,6 +40,7 @@
     ],
 
     shared_libs: [
+        "libbinder_ndk",
         "libcodec2_client",
     ],
     test_suites: [
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index 1f1681d..f36bc41 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define LOG_TAG "media_c2_hidl_test_common"
 #include <stdio.h>
 
 #include "media_c2_hidl_test_common.h"
 
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <codec2/aidl/ParamTypes.h>
 
 std::string sResourceDir = "";
 
@@ -44,6 +45,14 @@
     std::cerr << "\t -h,  --help:   Print usage \n";
 }
 
+C2PooledBlockPool::BufferPoolVer getBufferPoolVer() {
+    if (::aidl::android::hardware::media::c2::utils::IsSelected()) {
+        return C2PooledBlockPool::VER_AIDL2;
+    } else {
+        return C2PooledBlockPool::VER_HIDL;
+    }
+}
+
 void parseArgs(int argc, char** argv) {
     int arg;
     int option_index;
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index ecab0cb..48e80a4 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -17,8 +17,10 @@
 #ifndef MEDIA_C2_HIDL_TEST_COMMON_H
 #define MEDIA_C2_HIDL_TEST_COMMON_H
 
+#include <C2BufferPriv.h>
 #include <C2Component.h>
 #include <C2Config.h>
+#include <C2PlatformSupport.h>
 
 #include <codec2/hidl/client.h>
 #include <getopt.h>
@@ -126,6 +128,8 @@
     std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> callBack;
 };
 
+C2PooledBlockPool::BufferPoolVer getBufferPoolVer();
+
 void parseArgs(int argc, char** argv);
 
 // Return all test parameters, a list of tuple of <instance, component>.
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index d561adc..2cf0d6e 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "codec2_hidl_hal_video_dec_test"
 
 #include <android-base/logging.h>
+#include <android/binder_process.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <stdio.h>
@@ -119,7 +120,8 @@
 
         std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
+        mLinearPool = std::make_shared<C2PooledBlockPool>(
+                mLinearAllocator, mBlockPoolId++, getBufferPoolVer());
         ASSERT_NE(mLinearPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
@@ -1132,5 +1134,6 @@
     }
 
     ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index db68b96..fbb4f18 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "codec2_hidl_hal_video_enc_test"
 
 #include <android-base/logging.h>
+#include <android/binder_process.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <stdio.h>
@@ -930,5 +931,6 @@
     }
 
     ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 0c8457d..cab522e 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -862,6 +862,8 @@
         sp<Surface> surface;
         if (msg->findObject("native-window", &obj)) {
             surface = static_cast<Surface *>(obj.get());
+            int32_t generation;
+            (void)msg->findInt32("native-window-generation", &generation);
             // setup tunneled playback
             if (surface != nullptr) {
                 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
@@ -896,7 +898,7 @@
                     }
                 }
             }
-            setSurface(surface);
+            setSurface(surface, (uint32_t)generation);
         }
 
         Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
@@ -2033,7 +2035,7 @@
     }
 }
 
-status_t CCodec::setSurface(const sp<Surface> &surface) {
+status_t CCodec::setSurface(const sp<Surface> &surface, uint32_t generation) {
     bool pushBlankBuffer = false;
     {
         Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
@@ -2062,7 +2064,7 @@
         }
         pushBlankBuffer = config->mPushBlankBuffersOnStop;
     }
-    return mChannel->setSurface(surface, pushBlankBuffer);
+    return mChannel->setSurface(surface, generation, pushBlankBuffer);
 }
 
 void CCodec::signalFlush() {
@@ -2326,9 +2328,12 @@
 void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
     if (!workItems.empty()) {
         Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
+        bool shouldPost = queue->empty();
         queue->splice(queue->end(), workItems);
+        if (shouldPost) {
+            (new AMessage(kWhatWorkDone, this))->post();
+        }
     }
-    (new AMessage(kWhatWorkDone, this))->post();
 }
 
 void CCodec::onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index bddf3cb..f89e889 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1121,6 +1121,10 @@
     processRenderedFrames(delta);
 }
 
+void CCodecBufferChannel::onBufferReleasedFromOutputSurface(uint32_t generation) {
+    mComponent->onBufferReleasedFromOutputSurface(generation);
+}
+
 status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
     ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
     bool released = false;
@@ -2265,12 +2269,8 @@
     }
 }
 
-status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface, bool pushBlankBuffer) {
-    static std::atomic_uint32_t surfaceGeneration{0};
-    uint32_t generation = (getpid() << 10) |
-            ((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1)
-                & ((1 << 10) - 1));
-
+status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface,
+                                         uint32_t generation, bool pushBlankBuffer) {
     sp<IGraphicBufferProducer> producer;
     int maxDequeueCount;
     sp<Surface> oldSurface;
@@ -2284,7 +2284,6 @@
         newSurface->setDequeueTimeout(kDequeueTimeoutNs);
         newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
         producer = newSurface->getIGraphicBufferProducer();
-        producer->setGenerationNumber(generation);
     } else {
         ALOGE("[%s] setting output surface to null", mName);
         return INVALID_OPERATION;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 1b5c031..f23cb83 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -62,8 +62,8 @@
     void setCrypto(const sp<ICrypto> &crypto) override;
     void setDescrambler(const sp<IDescrambler> &descrambler) override;
 
-    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
-    virtual status_t queueSecureInputBuffer(
+    status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    status_t queueSecureInputBuffer(
             const sp<MediaCodecBuffer> &buffer,
             bool secure,
             const uint8_t *key,
@@ -73,10 +73,10 @@
             const CryptoPlugin::SubSample *subSamples,
             size_t numSubSamples,
             AString *errorDetailMsg) override;
-    virtual status_t attachBuffer(
+    status_t attachBuffer(
             const std::shared_ptr<C2Buffer> &c2Buffer,
             const sp<MediaCodecBuffer> &buffer) override;
-    virtual status_t attachEncryptedBuffer(
+    status_t attachEncryptedBuffer(
             const sp<hardware::HidlMemory> &memory,
             bool secure,
             const uint8_t *key,
@@ -88,12 +88,13 @@
             size_t numSubSamples,
             const sp<MediaCodecBuffer> &buffer,
             AString* errorDetailMsg) override;
-    virtual status_t renderOutputBuffer(
+    status_t renderOutputBuffer(
             const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
-    virtual void pollForRenderedBuffers() override;
-    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
-    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
-    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    void pollForRenderedBuffers() override;
+    void onBufferReleasedFromOutputSurface(uint32_t generation) override;
+    status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
 
     // Methods below are interface for CCodec to use.
 
@@ -105,7 +106,7 @@
     /**
      * Set output graphic surface for rendering.
      */
-    status_t setSurface(const sp<Surface> &surface, bool pushBlankBuffer);
+    status_t setSurface(const sp<Surface> &surface, uint32_t generation, bool pushBlankBuffer);
 
     /**
      * Set GraphicBufferSource object from which the component extracts input
diff --git a/media/codec2/sfplugin/include/media/stagefright/CCodec.h b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
index 13713bc..ffae08d 100644
--- a/media/codec2/sfplugin/include/media/stagefright/CCodec.h
+++ b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
@@ -56,7 +56,7 @@
     virtual void initiateStart() override;
     virtual void initiateShutdown(bool keepComponentAllocated = false) override;
 
-    virtual status_t setSurface(const sp<Surface> &surface) override;
+    virtual status_t setSurface(const sp<Surface> &surface, uint32_t generation) override;
 
     virtual void signalFlush() override;
     virtual void signalResume() override;
diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
index 7492cab..ff72b1f 100644
--- a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
@@ -47,35 +47,12 @@
 }
 
 static bool isP010Allowed() {
-    // The first SDK the device shipped with.
-    static const int32_t kProductFirstApiLevel =
-        base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
+    // The Vendor API level which is min(ro.product.first_api_level, ro.board.[first_]api_level).
+    // This is the api level to which VSR requirement the device conform.
+    static const int32_t kVendorApiLevel =
+        base::GetIntProperty<int32_t>("ro.vendor.api_level", 0);
 
-    // GRF devices (introduced in Android 11) list the first and possibly the current api levels
-    // to signal which VSR requirements they conform to even if the first device SDK was higher.
-    static const int32_t kBoardFirstApiLevel =
-        base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
-
-    // Some devices that launched prior to Android S may not support P010 correctly, even
-    // though they may advertise it as supported.
-    if (kProductFirstApiLevel != 0 && kProductFirstApiLevel < __ANDROID_API_S__) {
-        return false;
-    }
-
-    if (kBoardFirstApiLevel != 0 && kBoardFirstApiLevel < __ANDROID_API_S__) {
-        return false;
-    }
-
-    static const int32_t kBoardApiLevel =
-        base::GetIntProperty<int32_t>("ro.board.api_level", 0);
-
-    // For non-GRF devices, use the first SDK version by the product.
-    static const int32_t kFirstApiLevel =
-        kBoardApiLevel != 0 ? kBoardApiLevel :
-        kBoardFirstApiLevel != 0 ? kBoardFirstApiLevel :
-        kProductFirstApiLevel;
-
-    return kFirstApiLevel >= __ANDROID_API_T__;
+    return kVendorApiLevel >= __ANDROID_API_T__;
 }
 
 bool isHalPixelFormatSupported(AHardwareBuffer_Format format) {
diff --git a/media/codec2/tests/Android.bp b/media/codec2/tests/Android.bp
index 2217235..02c356c 100644
--- a/media/codec2/tests/Android.bp
+++ b/media/codec2/tests/Android.bp
@@ -27,6 +27,7 @@
     static_libs: [
     ],
 
+    cpp_std: "gnu++17",
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index bbe228c..af2683b 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -52,6 +52,9 @@
         "com.android.media.swcodec",
     ],
 
+    defaults: [
+        "libcodec2_hal_selection",
+    ],
 
     srcs: [
         "C2AllocatorBlob.cpp",
@@ -129,6 +132,10 @@
 cc_defaults {
     name: "libcodec2-static-defaults",
 
+    defaults: [
+        "libcodec2_hal_selection",
+    ],
+
     static_libs: [
         "liblog",
         "libion",
@@ -171,6 +178,11 @@
 // public dependency for implementing Codec 2 components
 cc_defaults {
     name: "libcodec2-impl-defaults",
+    cpp_std: "gnu++17",
+
+    defaults: [
+        "libcodec2_hal_selection",
+    ],
 
     shared_libs: [
         "libbase", // for C2_LOG
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 61aafa7..76c378d 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -28,6 +28,7 @@
 #include <C2Config.h>
 #include <C2PlatformStorePluginLoader.h>
 #include <C2PlatformSupport.h>
+#include <codec2/common/HalSelection.h>
 #include <cutils/properties.h>
 #include <util/C2InterfaceHelper.h>
 
@@ -447,6 +448,12 @@
 
 namespace {
 
+static C2PooledBlockPool::BufferPoolVer GetBufferPoolVer() {
+    static C2PooledBlockPool::BufferPoolVer sVer =
+        IsCodec2AidlHalSelected() ? C2PooledBlockPool::VER_AIDL2 : C2PooledBlockPool::VER_HIDL;
+    return sVer;
+}
+
 class _C2BlockPoolCache {
 public:
     _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
@@ -477,7 +484,7 @@
                         C2PlatformAllocatorStore::ION, &allocator);
                 if (res == C2_OK) {
                     std::shared_ptr<C2BlockPool> ptr(
-                            new C2PooledBlockPool(allocator, poolId), deleter);
+                            new C2PooledBlockPool(allocator, poolId, GetBufferPoolVer()), deleter);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
                     mComponents[poolId].insert(
@@ -490,7 +497,7 @@
                         C2PlatformAllocatorStore::BLOB, &allocator);
                 if (res == C2_OK) {
                     std::shared_ptr<C2BlockPool> ptr(
-                            new C2PooledBlockPool(allocator, poolId), deleter);
+                            new C2PooledBlockPool(allocator, poolId, GetBufferPoolVer()), deleter);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
                     mComponents[poolId].insert(
@@ -504,7 +511,7 @@
                         C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
                 if (res == C2_OK) {
                     std::shared_ptr<C2BlockPool> ptr(
-                        new C2PooledBlockPool(allocator, poolId), deleter);
+                            new C2PooledBlockPool(allocator, poolId, GetBufferPoolVer()), deleter);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
                     mComponents[poolId].insert(
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 073a030..91bc700 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -68,10 +68,9 @@
     }
 
     // We double the size of input buffer for ping pong use of record buffer.
-    // Assumes audio_is_linear_pcm(format)
-    const auto sampleSize = audio_channel_count_from_in_mask(channelMask) *
-                                      audio_bytes_per_sample(format);
-    if (sampleSize == 0 || ((*frameCount = (size * 2) / sampleSize) == 0)) {
+    const auto frameSize = audio_bytes_per_frame(
+            audio_channel_count_from_in_mask(channelMask), format);
+    if (frameSize == 0 || ((*frameCount = (size * 2) / frameSize) == 0)) {
         ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
                 __func__, sampleRate, format, channelMask);
         return BAD_VALUE;
@@ -353,12 +352,7 @@
     }
 
     mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
-
-    if (audio_is_linear_pcm(mFormat)) {
-        mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat);
-    } else {
-        mFrameSize = sizeof(uint8_t);
-    }
+    mFrameSize = audio_bytes_per_frame(mChannelCount, mFormat);
 
     // mFrameCount is initialized in createRecord_l
     mReqFrameCount = frameCount;
@@ -1231,8 +1225,12 @@
         }
 
         size_t bytesRead = audioBuffer.frameCount * mFrameSize;
-        memcpy_by_audio_format(buffer, mFormat, audioBuffer.raw, mServerConfig.format,
-                               audioBuffer.mSize / mServerSampleSize);
+        if (audio_is_linear_pcm(mFormat)) {
+            memcpy_by_audio_format(buffer, mFormat, audioBuffer.raw, mServerConfig.format,
+                                audioBuffer.mSize / mServerSampleSize);
+        } else {
+            memcpy(buffer, audioBuffer.raw, audioBuffer.mSize);
+        }
         buffer = ((char *) buffer) + bytesRead;
         userSize -= bytesRead;
         read += bytesRead;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index f3539a1..f050a20 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -594,18 +594,13 @@
     channelCount = audio_channel_count_from_out_mask(channelMask);
     mChannelCount = channelCount;
 
-    if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (audio_has_proportional_frames(format)) {
-            mFrameSize = channelCount * audio_bytes_per_sample(format);
-        } else {
-            mFrameSize = sizeof(uint8_t);
-        }
-    } else {
-        ALOG_ASSERT(audio_has_proportional_frames(format));
-        mFrameSize = channelCount * audio_bytes_per_sample(format);
+    if (!(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
         // createTrack will return an error if PCM format is not supported by server,
         // so no need to check for specific PCM formats here
+        ALOGW_IF(!audio_has_proportional_frames(format), "%s(): no direct flag for format 0x%x",
+            __func__, format);
     }
+    mFrameSize = audio_bytes_per_frame(channelCount, format);
 
     // sampling rate must be specified for direct outputs
     if (sampleRate == 0 && (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
index 501831d..2ab8053 100644
--- a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -79,8 +79,8 @@
 
     bool equals(const sp<DeviceDescriptorBase>& other) const;
 
-    status_t writeToParcelable(media::AudioPortFw* parcelable) const;
-    status_t readFromParcelable(const media::AudioPortFw& parcelable);
+    virtual status_t writeToParcelable(media::AudioPortFw* parcelable) const;
+    virtual status_t readFromParcelable(const media::AudioPortFw& parcelable);
 
 protected:
     AudioDeviceTypeAddr mDeviceTypeAddr;
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index 1689365..fb1cc34 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -319,6 +319,7 @@
         "ConversionHelperAidl.cpp",
         "DeviceHalAidl.cpp",
         "DevicesFactoryHalAidl.cpp",
+        "Hal2AidlMapper.cpp",
         "StreamHalAidl.cpp",
     ],
 }
diff --git a/media/libaudiohal/impl/Cleanups.h b/media/libaudiohal/impl/Cleanups.h
new file mode 100644
index 0000000..a313da1
--- /dev/null
+++ b/media/libaudiohal/impl/Cleanups.h
@@ -0,0 +1,107 @@
+/*
+ * 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 <forward_list>
+#include <mutex>
+#include <utility>
+
+namespace android {
+
+// This class implements the "monitor" idiom for providing locked access to a class instance.
+// This is how it is intended to be used. Let's assume there is a "Main" class which owns
+// an instance of a "Resource" class, which is protected by a mutex. We add an instance of
+// "LockedAccessor<Resource>" as a member of "Main":
+//
+// class Resource;
+//
+// class Main {
+//     Main() : mAccessor(mResource, mLock) {}
+//   private:
+//     std::mutex mLock;
+//     Resource mResource GUARDED_BY(mLock);  // owns the resource
+//     LockedAccessor<Resource> mAccessor;
+// };
+//
+// The accessor is initialized in the constructor when no locking is needed. The accessor
+// defers locking until the resource is accessed.
+//
+// Although "mAccessor" can be used by the methods of "Main" for scoped access to the resource,
+// its main role is for granting access to the resource to other classes. This is achieved by
+// making a copy of "mAccessor" and giving it away to another class. This obviously does not
+// transfer ownership of the resource. The intent is to allow another class to use the resource
+// with proper locking in a "lazy" fashion:
+//
+// class Another {
+//   public:
+//     Another(const LockedAccessor<Resource>& accessor) : mAccessor(accessor) {}
+//     void doItLater() {  // Use explicit 'lock' / 'unlock'
+//         auto resource = mAccessor.lock();
+//         resource.use();
+//         mAccessor.unlock();
+//     }
+//     void doItLaterScoped() {  // Rely on the scoped accessor do perform unlocking.
+//         LockedAccessor<Resource> scopedAccessor(mAccessor);
+//         auto resource = scopedAccessor.lock();
+//         resource.use();
+//     }
+//   private:
+//     LockedAccessor<Resource> mAccessor;
+// };
+//
+template<class C>
+class LockedAccessor {
+  public:
+    LockedAccessor(C& instance, std::mutex& mutex)
+            : mInstance(instance), mMutex(mutex), mLock(mMutex, std::defer_lock) {}
+    LockedAccessor(const LockedAccessor& other)
+            : mInstance(other.mInstance), mMutex(other.mMutex), mLock(mMutex, std::defer_lock) {}
+    ~LockedAccessor() { if (mLock.owns_lock()) mLock.unlock(); }
+    C& lock() { mLock.lock(); return mInstance; }
+    void unlock() { mLock.unlock(); }
+  private:
+    C& mInstance;
+    std::mutex& mMutex;
+    std::unique_lock<std::mutex> mLock;
+};
+
+// This class implements scoped cleanups. A "cleanup" is a call to a method of class "C" which
+// takes an integer parameter. Cleanups are executed in the reverse order to how they were added.
+// For executing cleanups, the instance of "C" is retrieved via the provided "LockedAccessor".
+template<class C>
+class Cleanups {
+  public:
+    typedef void (C::*Cleaner)(int32_t);  // A member function of "C" performing a cleanup action.
+    explicit Cleanups(const LockedAccessor<C>& accessor) : mAccessor(accessor) {}
+    ~Cleanups() {
+        if (!mCleanups.empty()) {
+            C& c = mAccessor.lock();
+            for (auto& cleanup : mCleanups) (c.*cleanup.first)(cleanup.second);
+            mAccessor.unlock();
+        }
+    }
+    void add(Cleaner cleaner, int32_t id) {
+        mCleanups.emplace_front(cleaner, id);
+    }
+    void disarmAll() { mCleanups.clear(); }
+  private:
+    using Cleanup = std::pair<Cleaner, int32_t>;
+    LockedAccessor<C> mAccessor;
+    std::forward_list<Cleanup> mCleanups;
+};
+
+}  // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index e2233c7..8a843ed 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -18,7 +18,6 @@
 // #define LOG_NDEBUG 0
 
 #include <algorithm>
-#include <forward_list>
 
 #include <aidl/android/hardware/audio/core/BnStreamCallback.h>
 #include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
@@ -28,6 +27,7 @@
 #include <media/AidlConversionNdkCpp.h>
 #include <media/AidlConversionUtil.h>
 #include <mediautils/TimeCheck.h>
+#include <system/audio.h>
 #include <Utils.h>
 #include <utils/Log.h>
 
@@ -37,14 +37,9 @@
 
 using aidl::android::aidl_utils::statusTFromBinderStatus;
 using aidl::android::media::audio::common::Boolean;
-using aidl::android::media::audio::common::AudioChannelLayout;
 using aidl::android::media::audio::common::AudioConfig;
 using aidl::android::media::audio::common::AudioDevice;
-using aidl::android::media::audio::common::AudioDeviceAddress;
 using aidl::android::media::audio::common::AudioDeviceType;
-using aidl::android::media::audio::common::AudioFormatDescription;
-using aidl::android::media::audio::common::AudioFormatType;
-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::AudioMMapPolicy;
@@ -54,11 +49,7 @@
 using aidl::android::media::audio::common::AudioOutputFlags;
 using aidl::android::media::audio::common::AudioPort;
 using aidl::android::media::audio::common::AudioPortConfig;
-using aidl::android::media::audio::common::AudioPortDeviceExt;
 using aidl::android::media::audio::common::AudioPortExt;
-using aidl::android::media::audio::common::AudioPortMixExt;
-using aidl::android::media::audio::common::AudioPortMixExtUseCase;
-using aidl::android::media::audio::common::AudioProfile;
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::Float;
 using aidl::android::media::audio::common::Int;
@@ -67,9 +58,8 @@
 using aidl::android::media::audio::IHalAdapterVendorExtension;
 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
-using aidl::android::hardware::audio::common::isDefaultAudioFormat;
-using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
 using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 using aidl::android::hardware::audio::core::AudioPatch;
 using aidl::android::hardware::audio::core::AudioRoute;
 using aidl::android::hardware::audio::core::IBluetooth;
@@ -78,37 +68,12 @@
 using aidl::android::hardware::audio::core::IModule;
 using aidl::android::hardware::audio::core::ITelephony;
 using aidl::android::hardware::audio::core::ModuleDebug;
-using aidl::android::hardware::audio::core::StreamDescriptor;
 using aidl::android::hardware::audio::core::VendorParameter;
 
 namespace android {
 
 namespace {
 
-bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
-    return portConfig.sampleRate.value().value == config.base.sampleRate &&
-            portConfig.channelMask.value() == config.base.channelMask &&
-            portConfig.format.value() == config.base.format;
-}
-
-void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
-    config->base.sampleRate = portConfig.sampleRate.value().value;
-    config->base.channelMask = portConfig.channelMask.value();
-    config->base.format = portConfig.format.value();
-}
-
-void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
-    if (config.base.sampleRate != 0) {
-        portConfig->sampleRate = Int{ .value = config.base.sampleRate };
-    }
-    if (config.base.channelMask != AudioChannelLayout{}) {
-        portConfig->channelMask = config.base.channelMask;
-    }
-    if (config.base.format != AudioFormatDescription{}) {
-        portConfig->format = config.base.format;
-    }
-}
-
 // Note: these converters are for types defined in different AIDL files. Although these
 // AIDL files are copies of each other, however formally these are different types
 // thus we don't use a conversion via a parcelable.
@@ -142,28 +107,29 @@
           mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
           mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
           mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
-          mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
+          mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)),
+          mSoundDose(retrieveSubInterface<ISoundDose>(module, &IModule::getSoundDose)),
+          mMapper(instance, module), mMapperAccessor(mMapper, mLock) {
 }
 
 status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
-    return ::aidl::android::convertContainer(mPorts, ports,
-            [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
+    std::lock_guard l(mLock);
+    return mMapper.getAudioPorts(ports, ndk2cpp_AudioPort);
 }
 
 status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
-    *routes = VALUE_OR_RETURN_STATUS(
-            ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
-                    mRoutes, ndk2cpp_AudioRoute));
-    return OK;
+    std::lock_guard l(mLock);
+    return mMapper.getAudioRoutes(routes, ndk2cpp_AudioRoute);
 }
 
 status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
+    if (mTelephony == nullptr) return INVALID_OPERATION;
     if (modes == nullptr) {
         return BAD_VALUE;
     }
-    if (mModule == nullptr) return NO_INIT;
-    if (mTelephony == nullptr) return INVALID_OPERATION;
     std::vector<AudioMode> aidlModes;
     RETURN_STATUS_IF_ERROR(
             statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
@@ -179,51 +145,17 @@
 }
 
 status_t DeviceHalAidl::initCheck() {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
     if (mModule == nullptr) return NO_INIT;
-    std::vector<AudioPort> ports;
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
-    ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
-            __func__, mInstance.c_str());
-    std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
-            [](const auto& p) { return std::make_pair(p.id, p); });
-    mDefaultInputPortId = mDefaultOutputPortId = -1;
-    const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
-    for (const auto& pair : mPorts) {
-        const auto& p = pair.second;
-        if (p.ext.getTag() == AudioPortExt::Tag::device &&
-                (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
-            if (p.flags.getTag() == AudioIoFlags::Tag::input) {
-                mDefaultInputPortId = p.id;
-            } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
-                mDefaultOutputPortId = p.id;
-            }
-        }
-    }
-    ALOGI("%s: module %s default port ids: input %d, output %d",
-            __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
-    RETURN_STATUS_IF_ERROR(updateRoutes());
-    std::vector<AudioPortConfig> portConfigs;
-    RETURN_STATUS_IF_ERROR(
-            statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs)));  // OK if empty
-    std::transform(portConfigs.begin(), portConfigs.end(),
-            std::inserter(mPortConfigs, mPortConfigs.end()),
-            [](const auto& p) { return std::make_pair(p.id, p); });
-    std::transform(mPortConfigs.begin(), mPortConfigs.end(),
-            std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
-            [](const auto& pcPair) { return pcPair.first; });
-    std::vector<AudioPatch> patches;
-    RETURN_STATUS_IF_ERROR(
-            statusTFromBinderStatus(mModule->getAudioPatches(&patches)));  // OK if empty
-    std::transform(patches.begin(), patches.end(),
-            std::inserter(mPatches, mPatches.end()),
-            [](const auto& p) { return std::make_pair(p.id, p); });
-    return OK;
+    std::lock_guard l(mLock);
+    return mMapper.initialize();
 }
 
 status_t DeviceHalAidl::setVoiceVolume(float volume) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (mTelephony == nullptr) return INVALID_OPERATION;
     ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
     RETURN_STATUS_IF_ERROR(
@@ -235,20 +167,26 @@
 }
 
 status_t DeviceHalAidl::setMasterVolume(float volume) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     return statusTFromBinderStatus(mModule->setMasterVolume(volume));
 }
 
 status_t DeviceHalAidl::getMasterVolume(float *volume) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
+    if (volume == nullptr) {
+        return BAD_VALUE;
+    }
     return statusTFromBinderStatus(mModule->getMasterVolume(volume));
 }
 
 status_t DeviceHalAidl::setMode(audio_mode_t mode) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
     if (mTelephony != nullptr) {
         RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
@@ -257,31 +195,43 @@
 }
 
 status_t DeviceHalAidl::setMicMute(bool state) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     return statusTFromBinderStatus(mModule->setMicMute(state));
 }
 
 status_t DeviceHalAidl::getMicMute(bool *state) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
+    if (state == nullptr) {
+        return BAD_VALUE;
+    }
     return statusTFromBinderStatus(mModule->getMicMute(state));
 }
 
 status_t DeviceHalAidl::setMasterMute(bool state) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     return statusTFromBinderStatus(mModule->setMasterMute(state));
 }
 
 status_t DeviceHalAidl::getMasterMute(bool *state) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
+    if (state == nullptr) {
+        return BAD_VALUE;
+    }
     return statusTFromBinderStatus(mModule->getMasterMute(state));
 }
 
 status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
-    if (!mModule) return NO_INIT;
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+    TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
     AudioParameter parameters(kvPairs);
     ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
 
@@ -307,8 +257,9 @@
 }
 
 status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (values == nullptr) {
         return BAD_VALUE;
     }
@@ -320,44 +271,13 @@
     return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
 }
 
-namespace {
-
-class Cleanup {
-  public:
-    typedef void (DeviceHalAidl::*Cleaner)(int32_t);
-
-    Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
-            mDevice(device), mCleaner(cleaner), mId(id) {}
-    ~Cleanup() { clean(); }
-    void clean() {
-        if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
-        disarm();
-    }
-    void disarm() { mDevice = nullptr; }
-
-  private:
-    DeviceHalAidl* mDevice;
-    const Cleaner mCleaner;
-    const int32_t mId;
-};
-
-}  // namespace
-
-// Since the order of container elements destruction is unspecified,
-// ensure that cleanups are performed from the most recent one and upwards.
-// This is the same as if there were individual Cleanup instances on the stack,
-// however the bonus is that we can disarm all of them with just one statement.
-class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
-  public:
-    ~Cleanups() { for (auto& c : *this) c.clean(); }
-    void disarmAll() { for (auto& c : *this) c.disarm(); }
-};
-
 status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
-    if (size == nullptr) return BAD_VALUE;
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
+    if (config == nullptr || size == nullptr) {
+        return BAD_VALUE;
+    }
     AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
     AudioDevice aidlDevice;
@@ -365,61 +285,20 @@
     AudioSource aidlSource = AudioSource::DEFAULT;
     AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
     AudioPortConfig mixPortConfig;
-    Cleanups cleanups;
-    audio_config writableConfig = *config;
+    Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
     AudioPatch aidlPatch;
-    RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
-                    &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
+                        0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
+                        &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+    }
     *size = aidlConfig.frameCount *
             getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
     // Do not disarm cleanups to release temporary port configs.
     return OK;
 }
 
-status_t DeviceHalAidl::prepareToOpenStream(
-        int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
-        AudioSource aidlSource, struct audio_config* config,
-        Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
-        AudioPatch* aidlPatch) {
-    ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
-            this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
-            aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
-            aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
-    resetUnusedPatchesAndPortConfigs();
-    const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
-    // Find / create AudioPortConfigs for the device port and the mix port,
-    // then find / create a patch between them, and open a stream on the mix port.
-    AudioPortConfig devicePortConfig;
-    bool created = false;
-    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
-                                                  &devicePortConfig, &created));
-    if (created) {
-        cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
-    }
-    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
-                    std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
-    if (created) {
-        cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
-    }
-    setConfigFromPortConfig(aidlConfig, *mixPortConfig);
-    if (isInput) {
-        RETURN_STATUS_IF_ERROR(findOrCreatePatch(
-                        {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
-    } else {
-        RETURN_STATUS_IF_ERROR(findOrCreatePatch(
-                        {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
-    }
-    if (created) {
-        cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
-    }
-    if (aidlConfig->frameCount <= 0) {
-        aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
-    }
-    *config = VALUE_OR_RETURN_STATUS(
-            ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
-    return OK;
-}
-
 namespace {
 
 class StreamCallbackBase {
@@ -543,26 +422,32 @@
         const char* address,
         sp<StreamOutHalInterface>* outStream) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
-    if (!outStream || !config) {
+    TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
+    if (outStream == nullptr || config == nullptr) {
         return BAD_VALUE;
     }
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    constexpr bool isInput = false;
     int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
     AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
-            ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
+            ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
     AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
     int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
     AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
     AudioPortConfig mixPortConfig;
-    Cleanups cleanups;
     AudioPatch aidlPatch;
-    RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
-                    AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
-                    config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+    Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
+                        AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
+                        &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+    }
+    *config = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
     ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
     args.portConfigId = mixPortConfig.id;
     const bool isOffload = isBitPositionFlagSet(
@@ -588,11 +473,11 @@
     }
     *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
             std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
-    mStreams.insert(std::pair(*outStream, aidlPatch.id));
     void* cbCookie = (*outStream).get();
     {
         std::lock_guard l(mLock);
         mCallbacks.emplace(cbCookie, Callbacks{});
+        mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
     }
     if (streamCb) streamCb->setCookie(cbCookie);
     eventCb->setCookie(cbCookie);
@@ -607,15 +492,16 @@
         audio_devices_t outputDevice, const char* outputDeviceAddress,
         sp<StreamInHalInterface>* inStream) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
-    if (!inStream || !config) {
+    TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
+    if (inStream == nullptr || config == nullptr) {
         return BAD_VALUE;
     }
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    constexpr bool isInput = true;
     int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
     AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
-            ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
+            ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
     AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
     int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
@@ -624,10 +510,16 @@
     AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
     AudioPortConfig mixPortConfig;
-    Cleanups cleanups;
     AudioPatch aidlPatch;
-    RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
-                    config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+    Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
+                        aidlHandle, aidlDevice, aidlFlags, aidlSource,
+                        &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
+    }
+    *config = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
     ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
     args.portConfigId = mixPortConfig.id;
     RecordTrackMetadata aidlTrackMetadata{
@@ -649,12 +541,18 @@
     }
     *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
             std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
-    mStreams.insert(std::pair(*inStream, aidlPatch.id));
+    {
+        std::lock_guard l(mLock);
+        mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
+    }
     cleanups.disarmAll();
     return OK;
 }
 
 status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
+    if (supportsPatches == nullptr) {
+        return BAD_VALUE;
+    }
     *supportsPatches = true;
     return OK;
 }
@@ -666,7 +564,7 @@
                                          audio_patch_handle_t* patch) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
         sources == nullptr || sinks == nullptr || patch == nullptr) {
         return BAD_VALUE;
@@ -683,7 +581,7 @@
     // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
     // that both the framework and the HAL use the same value for "no ID":
     static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
-    int32_t halPatchId = static_cast<int32_t>(*patch);
+    int32_t aidlPatchId = static_cast<int32_t>(*patch);
 
     // Upon conversion, mix port configs contain audio configuration, while
     // device port configs contain device address. This data is used to find
@@ -705,68 +603,13 @@
                         ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
                                 sinks[i], isInput, 0)));
     }
-    Cleanups cleanups;
-    auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
-    AudioPatch aidlPatch;
-    if (existingPatchIt != mPatches.end()) {
-        aidlPatch = existingPatchIt->second;
-        aidlPatch.sourcePortConfigIds.clear();
-        aidlPatch.sinkPortConfigIds.clear();
+    Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
+                        aidlSources, aidlSinks, &aidlPatchId, &cleanups));
     }
-    // The IDs will be found by 'fillPortConfigs', however the original 'aidlSources' and
-    // 'aidlSinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
-    // the source arguments, where only the audio configuration and device specifications
-    // are relevant.
-    ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
-            __func__, ::android::internal::ToString(aidlSources).c_str(),
-            ::android::internal::ToString(aidlSinks).c_str());
-    auto fillPortConfigs = [&](
-            const std::vector<AudioPortConfig>& configs,
-            const std::set<int32_t>& destinationPortIds,
-            std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
-        for (const auto& s : configs) {
-            AudioPortConfig portConfig;
-            bool created = false;
-            RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
-                            s, destinationPortIds, &portConfig, &created));
-            if (created) {
-                cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
-            }
-            ids->push_back(portConfig.id);
-            if (portIds != nullptr) {
-                portIds->insert(portConfig.portId);
-            }
-        }
-        return OK;
-    };
-    // When looking up port configs, the destinationPortId is only used for mix ports.
-    // Thus, we process device port configs first, and look up the destination port ID from them.
-    bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
-            [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
-    const std::vector<AudioPortConfig>& devicePortConfigs =
-            sourceIsDevice ? aidlSources : aidlSinks;
-    std::vector<int32_t>* devicePortConfigIds =
-            sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
-    const std::vector<AudioPortConfig>& mixPortConfigs =
-            sourceIsDevice ? aidlSinks : aidlSources;
-    std::vector<int32_t>* mixPortConfigIds =
-            sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
-    std::set<int32_t> devicePortIds;
-    RETURN_STATUS_IF_ERROR(fillPortConfigs(
-                    devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
-    RETURN_STATUS_IF_ERROR(fillPortConfigs(
-                    mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
-    if (existingPatchIt != mPatches.end()) {
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-                        mModule->setAudioPatch(aidlPatch, &aidlPatch)));
-        existingPatchIt->second = aidlPatch;
-    } else {
-        bool created = false;
-        RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
-        // Since no cleanup of the patch is needed, 'created' is ignored.
-        halPatchId = aidlPatch.id;
-        *patch = static_cast<audio_patch_handle_t>(halPatchId);
-    }
+    *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
     cleanups.disarmAll();
     return OK;
 }
@@ -774,26 +617,17 @@
 status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
     if (patch == AUDIO_PATCH_HANDLE_NONE) {
         return BAD_VALUE;
     }
-    int32_t halPatchId = static_cast<int32_t>(patch);
-    auto patchIt = mPatches.find(halPatchId);
-    if (patchIt == mPatches.end()) {
-        ALOGE("%s: patch with id %d not found", __func__, halPatchId);
-        return BAD_VALUE;
-    }
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
-    mPatches.erase(patchIt);
+    std::lock_guard l(mLock);
+    RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch)));
     return OK;
 }
 
 status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
-    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
     if (port == nullptr) {
         return BAD_VALUE;
     }
@@ -806,7 +640,7 @@
 status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (port == nullptr) {
         return BAD_VALUE;
     }
@@ -822,14 +656,11 @@
     const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
     // It seems that we don't have to call HAL since all valid ports have been added either
     // during initialization, or while handling connection of an external device.
-    auto portsIt = findPort(matchDevice);
-    if (portsIt == mPorts.end()) {
-        ALOGE("%s: device port for device %s is not found in the module %s",
-                __func__, matchDevice.toString().c_str(), mInstance.c_str());
-        return BAD_VALUE;
-    }
     const int32_t fwkId = aidlPort.id;
-    aidlPort = portsIt->second;
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
+    }
     aidlPort.id = fwkId;
     *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
                     aidlPort, isInput));
@@ -839,34 +670,30 @@
 status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
                                         struct audio_port_v7 *mixPort) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
-    if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
-        return BAD_VALUE;
-    }
-    if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
+    TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
+    if (devicePort == nullptr || mixPort == nullptr ||
+            devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
         return BAD_VALUE;
     }
     const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
             ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
-    auto it = findPortConfig(std::nullopt /*config*/, std::nullopt/*flags*/, aidlHandle);
-    if (it == mPortConfigs.end()) {
-        ALOGE("%s, cannot find mix port config for handle=%u", __func__, aidlHandle);
-        return BAD_VALUE;
-    }
     AudioPort port;
-    if (status_t status = getAudioPort(it->second.portId, &port); status != NO_ERROR) {
-        return status;
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
     }
     const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
             mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
     *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
             port, isInput));
-    return NO_ERROR;
+    return OK;
 }
 
 status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (config == nullptr) {
         return BAD_VALUE;
     }
@@ -876,13 +703,16 @@
             ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
                     *config, isInput, 0 /*portId*/));
     AudioPortConfig portConfig;
-    bool created = false;
-    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
-                    requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
-    return OK;
+    std::lock_guard l(mLock);
+    return mMapper.findOrCreatePortConfig(
+            requestedPortConfig, std::set<int32_t>(), &portConfig);
 }
 
 MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+    TIME_CHECK();
+    if (!mModule) return {};
+    std::lock_guard l(mLock);
     if (mMicrophones.status == Microphones::Status::UNKNOWN) {
         TIME_CHECK();
         std::vector<MicrophoneInfo> aidlInfo;
@@ -905,11 +735,12 @@
 
 status_t DeviceHalAidl::getMicrophones(
         std::vector<audio_microphone_characteristic_t>* microphones) {
-    if (!microphones) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+    TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
+    if (microphones == nullptr) {
         return BAD_VALUE;
     }
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
     auto staticInfo = getMicrophoneInfo();
     if (!staticInfo) return INVALID_OPERATION;
     std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
@@ -926,9 +757,10 @@
 
 status_t DeviceHalAidl::addDeviceEffect(
         const struct audio_port_config *device, sp<EffectHalInterface> effect) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
-    if (!effect) {
+    if (mModule == nullptr) return NO_INIT;
+    if (device == nullptr || effect == nullptr) {
         return BAD_VALUE;
     }
     bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
@@ -942,12 +774,11 @@
         return BAD_VALUE;
     }
     AudioPortConfig devicePortConfig;
-    bool created;
-    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
-                    requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
-    Cleanups cleanups;
-    if (created) {
-        cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
+    Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.findOrCreatePortConfig(
+                    requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
     }
     auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
@@ -957,9 +788,10 @@
 }
 status_t DeviceHalAidl::removeDeviceEffect(
         const struct audio_port_config *device, sp<EffectHalInterface> effect) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
-    if (!effect) {
+    if (mModule == nullptr) return NO_INIT;
+    if (device == nullptr || effect == nullptr) {
         return BAD_VALUE;
     }
     bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
@@ -972,22 +804,24 @@
                 __func__, requestedPortConfig.toString().c_str());
         return BAD_VALUE;
     }
-    auto existingPortConfigIt = findPortConfig(
-            requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
-    if (existingPortConfigIt == mPortConfigs.end()) {
-        ALOGE("%s: could not find a configured device port for the config %s",
-                __func__, requestedPortConfig.toString().c_str());
-        return BAD_VALUE;
+    AudioPortConfig devicePortConfig;
+    {
+        std::lock_guard l(mLock);
+        RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
+                        requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
+                        &devicePortConfig));
     }
     auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
     return statusTFromBinderStatus(mModule->removeDeviceEffect(
-                    existingPortConfigIt->first, aidlEffect->getIEffect()));
+                    devicePortConfig.id, aidlEffect->getIEffect()));
 }
 
 status_t DeviceHalAidl::getMmapPolicyInfos(
         media::audio::common::AudioMMapPolicyType policyType,
         std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
     AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
             cpp2ndk_AudioMMapPolicyType(policyType));
 
@@ -1005,7 +839,9 @@
 }
 
 int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
     int32_t mixerBurstCount = 0;
     if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
         return mixerBurstCount;
@@ -1014,7 +850,9 @@
 }
 
 int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
+    if (mModule == nullptr) return NO_INIT;
     int32_t hardwareBurstMinUsec = 0;
     if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
         return hardwareBurstMinUsec;
@@ -1023,8 +861,9 @@
 }
 
 error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     int32_t aidlHwAvSync;
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
     return VALUE_OR_RETURN_STATUS(
@@ -1033,13 +872,14 @@
 
 status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     return mModule->dump(fd, Args(args).args(), args.size());
 }
 
 status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (supports == nullptr) {
         return BAD_VALUE;
     }
@@ -1048,21 +888,16 @@
 
 status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
                                               ::ndk::SpAIBinder* soundDoseBinder)  {
-    TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (soundDoseBinder == nullptr) {
+        return BAD_VALUE;
+    }
     if (mSoundDose == nullptr) {
-        ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
-        if (!status.isOk()) {
-            ALOGE("%s failed to return the sound dose interface for module %s: %s",
-                  __func__,
-                  module.c_str(),
-                  status.getDescription().c_str());
-            return BAD_VALUE;
-        }
+        ALOGE("%s failed to retrieve the sound dose interface for module %s",
+                __func__, module.c_str());
+        return BAD_VALUE;
     }
     *soundDoseBinder = mSoundDose->asBinder();
     ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
-
     return OK;
 }
 
@@ -1070,28 +905,32 @@
     // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
     // Call `setConnectedState` instead.
     // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
-    if (const status_t status = setConnectedState(port, false /*connected*/); status == NO_ERROR) {
-        mDeviceDisconnectionNotified.insert(port->id);
-    }
+    RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
+    std::lock_guard l(mLock);
+    mDeviceDisconnectionNotified.insert(port->id);
     // Return that there was no error as otherwise the disconnection procedure will not be
-    // considered complete for upper layers, and 'setConnectedState' will not be called again.
-    return NO_ERROR;
+    // considered complete for upper layers, and 'setConnectedState' will not be called again
+    return OK;
 }
 
 status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
+    if (mModule == nullptr) return NO_INIT;
     if (port == nullptr) {
         return BAD_VALUE;
     }
-    if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
-        // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
-        // and then call `setConnectedState`. However, there is no API for
-        // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
-        // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
-        // previous call is successful. Also remove the cache here to avoid a large cache after
-        // a long run.
-        return NO_ERROR;
+    if (!connected) {
+        std::lock_guard l(mLock);
+        if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
+            // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
+            // and then call `setConnectedState`. However, there is no API for
+            // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
+            // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
+            // previous call is successful. Also remove the cache here to avoid a large cache after
+            // a long run.
+            return OK;
+        }
     }
     bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
             ::aidl::android::AudioPortDirection::INPUT;
@@ -1102,64 +941,17 @@
                 __func__, mInstance.c_str(), aidlPort.toString().c_str());
         return BAD_VALUE;
     }
-    if (connected) {
-        AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
-        // Reset the device address to find the "template" port.
-        matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
-        auto portsIt = findPort(matchDevice);
-        if (portsIt == mPorts.end()) {
-            // Since 'setConnectedState' is called for all modules, it is normal when the device
-            // port not found in every one of them.
-            return BAD_VALUE;
-        } else {
-            ALOGD("%s: device port for device %s found in the module %s",
-                    __func__, matchDevice.toString().c_str(), mInstance.c_str());
-        }
-        resetUnusedPatchesAndPortConfigs();
-        // Use the ID of the "template" port, use all the information from the provided port.
-        aidlPort.id = portsIt->first;
-        AudioPort connectedPort;
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
-                                aidlPort, &connectedPort)));
-        const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
-        LOG_ALWAYS_FATAL_IF(!inserted,
-                "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
-                __func__, mInstance.c_str(), connectedPort.toString().c_str(),
-                it->second.toString().c_str());
-        mConnectedPorts[connectedPort.id] = false;
-    } else {  // !connected
-        AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
-        auto portsIt = findPort(matchDevice);
-        if (portsIt == mPorts.end()) {
-            // Since 'setConnectedState' is called for all modules, it is normal when the device
-            // port not found in every one of them.
-            return BAD_VALUE;
-        } else {
-            ALOGD("%s: device port for device %s found in the module %s",
-                    __func__, matchDevice.toString().c_str(), mInstance.c_str());
-        }
-        resetUnusedPatchesAndPortConfigs();
-        // Streams are closed by AudioFlinger independently from device disconnections.
-        // It is possible that the stream has not been closed yet.
-        const int32_t portId = portsIt->second.id;
-        if (!isPortHeldByAStream(portId)) {
-            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-                            mModule->disconnectExternalDevice(portId)));
-            mPorts.erase(portsIt);
-            mConnectedPorts.erase(portId);
-        } else {
-            ALOGD("%s: since device port ID %d is used by a stream, "
-                    "external device disconnection postponed", __func__, portId);
-            mConnectedPorts[portId] = true;
-        }
-    }
-    return updateRoutes();
+    std::lock_guard l(mLock);
+    return mMapper.setDevicePortConnectedState(aidlPort, connected);
 }
 
 status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
     TIME_CHECK();
-    if (!mModule) return NO_INIT;
-    resetUnusedPatchesAndPortConfigs();
+    if (mModule == nullptr) return NO_INIT;
+    {
+        std::lock_guard l(mLock);
+        mMapper.resetUnusedPatchesAndPortConfigs();
+    }
     ModuleDebug debug{ .simulateDeviceConnections = enabled };
     status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
     // This is important to log as it affects HAL behavior.
@@ -1171,54 +963,8 @@
     return status;
 }
 
-bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
-    if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
-    return p.ext.get<AudioPortExt::Tag::device>().device == device;
-}
-
-bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
-    if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
-    if (device.type.type == AudioDeviceType::IN_DEFAULT) {
-        return p.portId == mDefaultInputPortId;
-    } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
-        return p.portId == mDefaultOutputPortId;
-    }
-    return p.ext.get<AudioPortExt::Tag::device>().device == device;
-}
-
-status_t DeviceHalAidl::createOrUpdatePortConfig(
-        const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
-    TIME_CHECK();
-    AudioPortConfig appliedPortConfig;
-    bool applied = false;
-    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
-                            requestedPortConfig, &appliedPortConfig, &applied)));
-    if (!applied) {
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
-                                appliedPortConfig, &appliedPortConfig, &applied)));
-        if (!applied) {
-            ALOGE("%s: module %s did not apply suggested config %s",
-                    __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
-            return NO_INIT;
-        }
-    }
-
-    int32_t id = appliedPortConfig.id;
-    if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
-        LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
-                requestedPortConfig.id, id);
-    }
-
-    auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
-            std::move(appliedPortConfig));
-    *result = it;
-    *created = inserted;
-    return OK;
-}
-
 status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
         AudioParameter &keys, AudioParameter *result) {
-    TIME_CHECK();
     if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
         keys.remove(key);
         if (mBluetoothA2dp != nullptr) {
@@ -1235,7 +981,6 @@
 }
 
 status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
-    TIME_CHECK();
     std::optional<bool> a2dpEnabled;
     std::optional<std::vector<VendorParameter>> reconfigureOffload;
     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
@@ -1277,7 +1022,6 @@
 }
 
 status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
-    TIME_CHECK();
     IBluetooth::HfpConfig hfpConfig;
     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
                     parameters, String8(AudioParameter::keyBtHfpEnable),
@@ -1316,7 +1060,6 @@
 }
 
 status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
-    TIME_CHECK();
     std::optional<bool> leEnabled;
     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
                     parameters, String8(AudioParameter::keyBtLeSuspended),
@@ -1339,7 +1082,6 @@
 }
 
 status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
-    TIME_CHECK();
     IBluetooth::ScoConfig scoConfig;
     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
                     parameters, String8(AudioParameter::keyBtSco),
@@ -1397,7 +1139,6 @@
 }
 
 status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
-    TIME_CHECK();
     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
                     parameters, String8(AudioParameter::keyScreenState),
                     [&](const String8& onOrOff) -> status_t {
@@ -1435,7 +1176,6 @@
 }
 
 status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
-    TIME_CHECK();
     using TtyMode = ITelephony::TelecomConfig::TtyMode;
     ITelephony::TelecomConfig telConfig;
     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
@@ -1480,420 +1220,6 @@
     return OK;
 }
 
-status_t DeviceHalAidl::findOrCreatePatch(
-        const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
-    std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
-            requestedPatch.sourcePortConfigIds.end());
-    std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
-            requestedPatch.sinkPortConfigIds.end());
-    return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
-}
-
-status_t DeviceHalAidl::findOrCreatePatch(
-        const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
-        AudioPatch* patch, bool* created) {
-    auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
-    if (patchIt == mPatches.end()) {
-        TIME_CHECK();
-        AudioPatch requestedPatch, appliedPatch;
-        requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
-                sourcePortConfigIds.begin(), sourcePortConfigIds.end());
-        requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
-                sinkPortConfigIds.begin(), sinkPortConfigIds.end());
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
-                                requestedPatch, &appliedPatch)));
-        patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
-        *created = true;
-    } else {
-        *created = false;
-    }
-    *patch = patchIt->second;
-    return OK;
-}
-
-status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
-        AudioPortConfig* portConfig, bool* created) {
-    auto portConfigIt = findPortConfig(device);
-    if (portConfigIt == mPortConfigs.end()) {
-        auto portsIt = findPort(device);
-        if (portsIt == mPorts.end()) {
-            ALOGE("%s: device port for device %s is not found in the module %s",
-                    __func__, device.toString().c_str(), mInstance.c_str());
-            return BAD_VALUE;
-        }
-        AudioPortConfig requestedPortConfig;
-        requestedPortConfig.portId = portsIt->first;
-        if (config != nullptr) {
-            setPortConfigFromConfig(&requestedPortConfig, *config);
-        }
-        RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
-                created));
-    } else {
-        *created = false;
-    }
-    *portConfig = portConfigIt->second;
-    return OK;
-}
-
-status_t DeviceHalAidl::findOrCreatePortConfig(
-        const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
-        AudioSource source, const std::set<int32_t>& destinationPortIds,
-        AudioPortConfig* portConfig, bool* created) {
-    // These flags get removed one by one in this order when retrying port finding.
-    static const std::vector<AudioInputFlags> kOptionalInputFlags{
-        AudioInputFlags::FAST, AudioInputFlags::RAW };
-    auto portConfigIt = findPortConfig(config, flags, ioHandle);
-    if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
-        auto optionalInputFlagsIt = kOptionalInputFlags.begin();
-        AudioIoFlags matchFlags = flags.value();
-        auto portsIt = findPort(config, matchFlags, destinationPortIds);
-        while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
-                && optionalInputFlagsIt != kOptionalInputFlags.end()) {
-            if (!isBitPositionFlagSet(
-                            matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
-                ++optionalInputFlagsIt;
-                continue;
-            }
-            matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
-                    ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
-            portsIt = findPort(config, matchFlags, destinationPortIds);
-            ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
-                    "retried with flags %s", __func__, config.toString().c_str(),
-                    flags.value().toString().c_str(), mInstance.c_str(),
-                    matchFlags.toString().c_str());
-        }
-        if (portsIt == mPorts.end()) {
-            ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
-                    __func__, config.toString().c_str(), matchFlags.toString().c_str(),
-                    mInstance.c_str());
-            return BAD_VALUE;
-        }
-        AudioPortConfig requestedPortConfig;
-        requestedPortConfig.portId = portsIt->first;
-        setPortConfigFromConfig(&requestedPortConfig, config);
-        requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
-        if (matchFlags.getTag() == AudioIoFlags::Tag::input
-                && source != AudioSource::SYS_RESERVED_INVALID) {
-            requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
-                    AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
-        }
-        RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
-                created));
-    } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
-        ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
-                "and was not created as flags are not specified",
-                __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
-        return BAD_VALUE;
-    } else {
-        AudioPortConfig requestedPortConfig = portConfigIt->second;
-        if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
-            AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
-            if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
-                    source != AudioSource::SYS_RESERVED_INVALID) {
-                mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
-            }
-        }
-
-        if (requestedPortConfig != portConfigIt->second) {
-            RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
-                    created));
-        } else {
-            *created = false;
-        }
-    }
-    *portConfig = portConfigIt->second;
-    return OK;
-}
-
-status_t DeviceHalAidl::findOrCreatePortConfig(
-        const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
-        AudioPortConfig* portConfig, bool* created) {
-    using Tag = AudioPortExt::Tag;
-    if (requestedPortConfig.ext.getTag() == Tag::mix) {
-        if (const auto& p = requestedPortConfig;
-                !p.sampleRate.has_value() || !p.channelMask.has_value() ||
-                !p.format.has_value()) {
-            ALOGW("%s: provided mix port config is not fully specified: %s",
-                    __func__, p.toString().c_str());
-            return BAD_VALUE;
-        }
-        AudioConfig config;
-        setConfigFromPortConfig(&config, requestedPortConfig);
-        AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
-                AudioPortMixExtUseCase::Tag::source ?
-                requestedPortConfig.ext.get<Tag::mix>().usecase.
-                get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
-        return findOrCreatePortConfig(config, requestedPortConfig.flags,
-                requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
-                portConfig, created);
-    } else if (requestedPortConfig.ext.getTag() == Tag::device) {
-        return findOrCreatePortConfig(
-                requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
-                portConfig, created);
-    }
-    ALOGW("%s: unsupported audio port config: %s",
-            __func__, requestedPortConfig.toString().c_str());
-    return BAD_VALUE;
-}
-
-DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
-        const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
-    return std::find_if(mPatches.begin(), mPatches.end(),
-            [&](const auto& pair) {
-                const auto& p = pair.second;
-                std::set<int32_t> patchSrcs(
-                        p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
-                std::set<int32_t> patchSinks(
-                        p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
-                return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
-}
-
-DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
-    if (device.type.type == AudioDeviceType::IN_DEFAULT) {
-        return mPorts.find(mDefaultInputPortId);
-    } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
-        return mPorts.find(mDefaultOutputPortId);
-    }
-    if (device.address.getTag() != AudioDeviceAddress::id ||
-            !device.address.get<AudioDeviceAddress::id>().empty()) {
-        return std::find_if(mPorts.begin(), mPorts.end(),
-                [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
-    }
-    // For connection w/o an address, two ports can be found: the template port,
-    // and a connected port (if exists). Make sure we return the connected port.
-    DeviceHalAidl::Ports::iterator portIt = mPorts.end();
-    for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
-        if (audioDeviceMatches(device, it->second)) {
-            if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
-                return it;
-            } else {
-                // Will return 'it' if there is no connected port.
-                portIt = it;
-            }
-        }
-    }
-    return portIt;
-}
-
-DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
-            const AudioConfig& config, const AudioIoFlags& flags,
-            const std::set<int32_t>& destinationPortIds) {
-    auto belongsToProfile = [&config](const AudioProfile& prof) {
-        return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
-                (config.base.channelMask.getTag() == AudioChannelLayout::none ||
-                        std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
-                                config.base.channelMask) != prof.channelMasks.end()) &&
-                (config.base.sampleRate == 0 ||
-                        std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
-                                config.base.sampleRate) != prof.sampleRates.end());
-    };
-    static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
-    int optionalFlags = 0;
-    auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
-        // Ports should be able to match if the optional flags are not requested.
-        return portFlags == flags ||
-               (portFlags.getTag() == AudioIoFlags::Tag::output &&
-                        AudioIoFlags::make<AudioIoFlags::Tag::output>(
-                                portFlags.get<AudioIoFlags::Tag::output>() &
-                                        ~optionalFlags) == flags);
-    };
-    auto matcher = [&](const auto& pair) {
-        const auto& p = pair.second;
-        return p.ext.getTag() == AudioPortExt::Tag::mix &&
-                flagMatches(p.flags) &&
-                (destinationPortIds.empty() ||
-                        std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
-                                [&](const int32_t destId) { return mRoutingMatrix.count(
-                                            std::make_pair(p.id, destId)) != 0; })) &&
-                (p.profiles.empty() ||
-                        std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
-                        p.profiles.end()); };
-    auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
-    if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
-        auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
-        while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
-            if (isBitPositionFlagSet(
-                        flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
-                // If the flag is set by the request, it must be matched.
-                ++optionalOutputFlagsIt;
-                continue;
-            }
-            optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
-            result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
-            ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
-                  "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
-                    flags.toString().c_str(), mInstance.c_str(), optionalFlags);
-        }
-    }
-    return result;
-}
-
-DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
-    return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
-            [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
-}
-
-DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
-            const std::optional<AudioConfig>& config,
-            const std::optional<AudioIoFlags>& flags,
-            int32_t ioHandle) {
-    using Tag = AudioPortExt::Tag;
-    return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
-            [&](const auto& pair) {
-                const auto& p = pair.second;
-                LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
-                        (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
-                                !p.format.has_value() || !p.flags.has_value()),
-                        "%s: stored mix port config is not fully specified: %s",
-                        __func__, p.toString().c_str());
-                return p.ext.getTag() == Tag::mix &&
-                        (!config.has_value() ||
-                                isConfigEqualToPortConfig(config.value(), p)) &&
-                        (!flags.has_value() || p.flags.value() == flags.value()) &&
-                        p.ext.template get<Tag::mix>().handle == ioHandle; });
-}
-
-bool DeviceHalAidl::isPortHeldByAStream(int32_t portId) {
-    // It is assumed that mStreams has already been cleaned up.
-    for (const auto& streamPair : mStreams) {
-        int32_t patchId = streamPair.second;
-        auto patchIt = mPatches.find(patchId);
-        if (patchIt == mPatches.end()) continue;
-        for (int32_t id : patchIt->second.sourcePortConfigIds) {
-            auto portConfigIt = mPortConfigs.find(id);
-            if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
-                return true;
-            }
-        }
-        for (int32_t id : patchIt->second.sinkPortConfigIds) {
-            auto portConfigIt = mPortConfigs.find(id);
-            if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-void DeviceHalAidl::resetPatch(int32_t patchId) {
-    if (auto it = mPatches.find(patchId); it != mPatches.end()) {
-        mPatches.erase(it);
-        TIME_CHECK();
-        if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
-            ALOGE("%s: error while resetting patch %d: %s",
-                    __func__, patchId, status.getDescription().c_str());
-        }
-        return;
-    }
-    ALOGE("%s: patch id %d not found", __func__, patchId);
-}
-
-void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
-    if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
-        mPortConfigs.erase(it);
-        TIME_CHECK();
-        if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
-                !status.isOk()) {
-            ALOGE("%s: error while resetting port config %d: %s",
-                    __func__, portConfigId, status.getDescription().c_str());
-        }
-        return;
-    }
-    ALOGE("%s: port config id %d not found", __func__, portConfigId);
-}
-
-void DeviceHalAidl::resetUnusedPatches() {
-    // Since patches can be created independently of streams via 'createAudioPatch',
-    // here we only clean up patches for released streams.
-    for (auto it = mStreams.begin(); it != mStreams.end(); ) {
-        if (auto streamSp = it->first.promote(); streamSp) {
-            ++it;
-        } else {
-            resetPatch(it->second);
-            it = mStreams.erase(it);
-        }
-    }
-}
-
-void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
-    resetUnusedPatches();
-    resetUnusedPortConfigs();
-}
-
-void DeviceHalAidl::resetUnusedPortConfigs() {
-    // The assumption is that port configs are used to create patches
-    // (or to open streams, but that involves creation of patches, too). Thus,
-    // orphaned port configs can and should be reset.
-    std::map<int32_t, int32_t /*portID*/> portConfigIds;
-    std::transform(mPortConfigs.begin(), mPortConfigs.end(),
-            std::inserter(portConfigIds, portConfigIds.end()),
-            [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
-    for (const auto& p : mPatches) {
-        for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
-        for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
-    }
-    for (int32_t id : mInitialPortConfigIds) {
-        portConfigIds.erase(id);
-    }
-    std::set<int32_t> retryDeviceDisconnection;
-    for (const auto& portConfigAndIdPair : portConfigIds) {
-        resetPortConfig(portConfigAndIdPair.first);
-        if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
-                it != mConnectedPorts.end() && it->second) {
-            retryDeviceDisconnection.insert(portConfigAndIdPair.second);
-        }
-    }
-    for (int32_t portId : retryDeviceDisconnection) {
-        if (!isPortHeldByAStream(portId)) {
-            TIME_CHECK();
-            if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
-                mPorts.erase(portId);
-                mConnectedPorts.erase(portId);
-                ALOGD("%s: executed postponed external device disconnection for port ID %d",
-                        __func__, portId);
-            }
-        }
-    }
-    if (!retryDeviceDisconnection.empty()) {
-        updateRoutes();
-    }
-}
-
-status_t DeviceHalAidl::updateRoutes() {
-    TIME_CHECK();
-    RETURN_STATUS_IF_ERROR(
-            statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
-    ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
-            __func__, mInstance.c_str());
-    mRoutingMatrix.clear();
-    for (const auto& r : mRoutes) {
-        for (auto portId : r.sourcePortIds) {
-            mRoutingMatrix.emplace(r.sinkPortId, portId);
-            mRoutingMatrix.emplace(portId, r.sinkPortId);
-        }
-    }
-    return OK;
-}
-
-status_t DeviceHalAidl::getAudioPort(int32_t portId, AudioPort* port) {
-    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
-    TIME_CHECK();
-    if (!mModule) {
-        return NO_INIT;
-    }
-    const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
-    if (status == OK) {
-        auto portIt = mPorts.find(portId);
-        if (portIt != mPorts.end()) {
-            portIt->second = *port;
-        } else {
-            ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
-                  __func__, portId);
-        }
-    }
-    return status;
-}
-
 void DeviceHalAidl::clearCallbacks(void* cookie) {
     std::lock_guard l(mLock);
     mCallbacks.erase(cookie);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index e1fe4d1..9493e47 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -17,7 +17,9 @@
 #pragma once
 
 #include <map>
-#include <set>
+#include <memory>
+#include <mutex>
+#include <string>
 #include <vector>
 
 #include <aidl/android/media/audio/IHalAdapterVendorExtension.h>
@@ -26,9 +28,10 @@
 #include <android-base/thread_annotations.h>
 #include <media/audiohal/DeviceHalInterface.h>
 #include <media/audiohal/EffectHalInterface.h>
-#include <media/audiohal/StreamHalInterface.h>
 
+#include "Cleanups.h"
 #include "ConversionHelperAidl.h"
+#include "Hal2AidlMapper.h"
 
 namespace android {
 
@@ -194,19 +197,6 @@
         Status status = Status::UNKNOWN;
         MicrophoneInfoProvider::Info info;
     };
-    // IDs of ports for connected external devices, and whether they are held by streams.
-    using ConnectedPorts = std::map<int32_t /*port ID*/, bool>;
-    using Patches = std::map<int32_t /*patch ID*/,
-            ::aidl::android::hardware::audio::core::AudioPatch>;
-    using PortConfigs = std::map<int32_t /*port config ID*/,
-            ::aidl::android::media::audio::common::AudioPortConfig>;
-    using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
-    using Routes = std::vector<::aidl::android::hardware::audio::core::AudioRoute>;
-    // Answers the question "whether portID 'first' is reachable from portID 'second'?"
-    // It's not a map because both portIDs are known. The matrix is symmetric.
-    using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>;
-    using Streams = std::map<wp<StreamHalInterface>, int32_t /*patch ID*/>;
-    class Cleanups;
 
     // Must not be constructed directly by clients.
     DeviceHalAidl(
@@ -216,13 +206,6 @@
 
     ~DeviceHalAidl() override = default;
 
-    bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
-            const ::aidl::android::media::audio::common::AudioPort& p);
-    bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
-            const ::aidl::android::media::audio::common::AudioPortConfig& p);
-    status_t createOrUpdatePortConfig(
-            const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
-            PortConfigs::iterator* result, bool *created);
     status_t filterAndRetrieveBtA2dpParameters(AudioParameter &keys, AudioParameter *result);
     status_t filterAndUpdateBtA2dpParameters(AudioParameter &parameters);
     status_t filterAndUpdateBtHfpParameters(AudioParameter &parameters);
@@ -230,60 +213,6 @@
     status_t filterAndUpdateBtScoParameters(AudioParameter &parameters);
     status_t filterAndUpdateScreenParameters(AudioParameter &parameters);
     status_t filterAndUpdateTelephonyParameters(AudioParameter &parameters);
-    status_t findOrCreatePatch(
-        const std::set<int32_t>& sourcePortConfigIds,
-        const std::set<int32_t>& sinkPortConfigIds,
-        ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
-    status_t findOrCreatePatch(
-        const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch,
-        ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
-    status_t findOrCreatePortConfig(
-            const ::aidl::android::media::audio::common::AudioDevice& device,
-            const ::aidl::android::media::audio::common::AudioConfig* config,
-            ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
-            bool* created);
-    status_t findOrCreatePortConfig(
-            const ::aidl::android::media::audio::common::AudioConfig& config,
-            const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
-            int32_t ioHandle,
-            ::aidl::android::media::audio::common::AudioSource aidlSource,
-            const std::set<int32_t>& destinationPortIds,
-            ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
-    status_t findOrCreatePortConfig(
-        const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
-        const std::set<int32_t>& destinationPortIds,
-        ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
-    Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds,
-            const std::set<int32_t>& sinkPortConfigIds);
-    Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device);
-    Ports::iterator findPort(
-            const ::aidl::android::media::audio::common::AudioConfig& config,
-            const ::aidl::android::media::audio::common::AudioIoFlags& flags,
-            const std::set<int32_t>& destinationPortIds);
-    PortConfigs::iterator findPortConfig(
-            const ::aidl::android::media::audio::common::AudioDevice& device);
-    PortConfigs::iterator findPortConfig(
-            const std::optional<::aidl::android::media::audio::common::AudioConfig>& config,
-            const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
-            int32_t ioHandle);
-    bool isPortHeldByAStream(int32_t portId);
-    status_t prepareToOpenStream(
-        int32_t aidlHandle,
-        const ::aidl::android::media::audio::common::AudioDevice& aidlDevice,
-        const ::aidl::android::media::audio::common::AudioIoFlags& aidlFlags,
-        ::aidl::android::media::audio::common::AudioSource aidlSource,
-        struct audio_config* config,
-        Cleanups* cleanups,
-        ::aidl::android::media::audio::common::AudioConfig* aidlConfig,
-        ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
-        ::aidl::android::hardware::audio::core::AudioPatch* aidlPatch);
-    void resetPatch(int32_t patchId);
-    void resetPortConfig(int32_t portConfigId);
-    void resetUnusedPatches();
-    void resetUnusedPatchesAndPortConfigs();
-    void resetUnusedPortConfigs();
-    status_t updateRoutes();
-    status_t getAudioPort(int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
 
     // CallbackBroker implementation
     void clearCallbacks(void* cookie) override;
@@ -310,22 +239,14 @@
     const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetooth> mBluetooth;
     const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothA2dp> mBluetoothA2dp;
     const std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothLe> mBluetoothLe;
-    std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose>
-        mSoundDose = nullptr;
-    Ports mPorts;
-    int32_t mDefaultInputPortId = -1;
-    int32_t mDefaultOutputPortId = -1;
-    PortConfigs mPortConfigs;
-    std::set<int32_t> mInitialPortConfigIds;
-    Patches mPatches;
-    Routes mRoutes;
-    RoutingMatrix mRoutingMatrix;
-    Streams mStreams;
-    Microphones mMicrophones;
+    const std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose> mSoundDose;
+
     std::mutex mLock;
     std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
-    std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
-    ConnectedPorts mConnectedPorts;
+    std::set<audio_port_handle_t> mDeviceDisconnectionNotified GUARDED_BY(mLock);
+    Hal2AidlMapper mMapper GUARDED_BY(mLock);
+    LockedAccessor<Hal2AidlMapper> mMapperAccessor;
+    Microphones mMicrophones GUARDED_BY(mLock);
 };
 
 } // namespace android
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index 1099b6d..aee42a9 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -162,7 +162,11 @@
 
 Descriptor::Common EffectProxy::buildDescriptorCommon(
         const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs) {
-    Descriptor::Common common;
+    // initial flag values before we know which sub-effect to active (with setOffloadParam)
+    // align to HIDL EffectProxy flags
+    Descriptor::Common common = {.flags = {.type = Flags::Type::INSERT,
+                                           .insert = Flags::Insert::LAST,
+                                           .volume = Flags::Volume::CTRL}};
 
     for (const auto& desc : subEffectDescs) {
         if (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) {
@@ -174,14 +178,12 @@
         common.flags.deviceIndication |= desc.common.flags.deviceIndication;
         common.flags.audioModeIndication |= desc.common.flags.audioModeIndication;
         common.flags.audioSourceIndication |= desc.common.flags.audioSourceIndication;
+        // Set to NONE if any sub-effect not supporting any Volume command
+        if (desc.common.flags.volume == Flags::Volume::NONE) {
+            common.flags.volume = Flags::Volume::NONE;
+        }
     }
 
-    // initial flag values before we know which sub-effect to active (with setOffloadParam)
-    // same as HIDL EffectProxy flags
-    common.flags.type = Flags::Type::INSERT;
-    common.flags.insert = Flags::Insert::LAST;
-    common.flags.volume = Flags::Volume::CTRL;
-
     // copy type UUID from any of sub-effects, all sub-effects should have same type
     common.id.type = subEffectDescs[0].common.id.type;
     // replace implementation UUID with proxy UUID.
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
new file mode 100644
index 0000000..f187057
--- /dev/null
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -0,0 +1,927 @@
+/*
+ * 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 "Hal2AidlMapper"
+// #define LOG_NDEBUG 0
+
+#include <algorithm>
+
+#include <media/audiohal/StreamHalInterface.h>
+#include <error/expected_utils.h>
+#include <system/audio.h>  // For AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS
+#include <Utils.h>
+#include <utils/Log.h>
+
+#include "Hal2AidlMapper.h"
+
+using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfig;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioInputFlags;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioPortMixExt;
+using aidl::android::media::audio::common::AudioPortMixExtUseCase;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::Int;
+using aidl::android::hardware::audio::common::isBitPositionFlagSet;
+using aidl::android::hardware::audio::common::isDefaultAudioFormat;
+using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IModule;
+
+namespace android {
+
+namespace {
+
+bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
+    return portConfig.sampleRate.value().value == config.base.sampleRate &&
+            portConfig.channelMask.value() == config.base.channelMask &&
+            portConfig.format.value() == config.base.format;
+}
+
+void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
+    config->base.sampleRate = portConfig.sampleRate.value().value;
+    config->base.channelMask = portConfig.channelMask.value();
+    config->base.format = portConfig.format.value();
+}
+
+void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
+    if (config.base.sampleRate != 0) {
+        portConfig->sampleRate = Int{ .value = config.base.sampleRate };
+    }
+    if (config.base.channelMask != AudioChannelLayout{}) {
+        portConfig->channelMask = config.base.channelMask;
+    }
+    if (config.base.format != AudioFormatDescription{}) {
+        portConfig->format = config.base.format;
+    }
+}
+
+}  // namespace
+
+Hal2AidlMapper::Hal2AidlMapper(const std::string& instance, const std::shared_ptr<IModule>& module)
+        : mInstance(instance), mModule(module) {
+}
+
+void Hal2AidlMapper::addStream(
+        const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId) {
+    mStreams.insert(std::pair(stream, std::pair(portConfigId, patchId)));
+}
+
+bool Hal2AidlMapper::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
+    if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
+    return p.ext.get<AudioPortExt::Tag::device>().device == device;
+}
+
+bool Hal2AidlMapper::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
+    if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
+    if (device.type.type == AudioDeviceType::IN_DEFAULT) {
+        return p.portId == mDefaultInputPortId;
+    } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
+        return p.portId == mDefaultOutputPortId;
+    }
+    return p.ext.get<AudioPortExt::Tag::device>().device == device;
+}
+
+status_t Hal2AidlMapper::createOrUpdatePatch(
+        const std::vector<AudioPortConfig>& sources,
+        const std::vector<AudioPortConfig>& sinks,
+        int32_t* patchId, Cleanups* cleanups) {
+    auto existingPatchIt = *patchId != 0 ? mPatches.find(*patchId): mPatches.end();
+    AudioPatch patch;
+    if (existingPatchIt != mPatches.end()) {
+        patch = existingPatchIt->second;
+        patch.sourcePortConfigIds.clear();
+        patch.sinkPortConfigIds.clear();
+    }
+    // The IDs will be found by 'fillPortConfigs', however the original 'sources' and
+    // 'sinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
+    // the source arguments, where only the audio configuration and device specifications
+    // are relevant.
+    ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
+            __func__, ::android::internal::ToString(sources).c_str(),
+            ::android::internal::ToString(sinks).c_str());
+    auto fillPortConfigs = [&](
+            const std::vector<AudioPortConfig>& configs,
+            const std::set<int32_t>& destinationPortIds,
+            std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
+        for (const auto& s : configs) {
+            AudioPortConfig portConfig;
+            RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+                            s, destinationPortIds, &portConfig, cleanups));
+            ids->push_back(portConfig.id);
+            if (portIds != nullptr) {
+                portIds->insert(portConfig.portId);
+            }
+        }
+        return OK;
+    };
+    // When looking up port configs, the destinationPortId is only used for mix ports.
+    // Thus, we process device port configs first, and look up the destination port ID from them.
+    bool sourceIsDevice = std::any_of(sources.begin(), sources.end(),
+            [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
+    const std::vector<AudioPortConfig>& devicePortConfigs =
+            sourceIsDevice ? sources : sinks;
+    std::vector<int32_t>* devicePortConfigIds =
+            sourceIsDevice ? &patch.sourcePortConfigIds : &patch.sinkPortConfigIds;
+    const std::vector<AudioPortConfig>& mixPortConfigs =
+            sourceIsDevice ? sinks : sources;
+    std::vector<int32_t>* mixPortConfigIds =
+            sourceIsDevice ? &patch.sinkPortConfigIds : &patch.sourcePortConfigIds;
+    std::set<int32_t> devicePortIds;
+    RETURN_STATUS_IF_ERROR(fillPortConfigs(
+                    devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
+    RETURN_STATUS_IF_ERROR(fillPortConfigs(
+                    mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
+    if (existingPatchIt != mPatches.end()) {
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+                        mModule->setAudioPatch(patch, &patch)));
+        existingPatchIt->second = patch;
+    } else {
+        bool created = false;
+        RETURN_STATUS_IF_ERROR(findOrCreatePatch(patch, &patch, &created));
+        // No cleanup of the patch is needed, it is managed by the framework.
+        *patchId = patch.id;
+        if (!created) {
+            // The framework might have "created" a patch which already existed due to
+            // stream creation. Need to release the ownership from the stream.
+            for (auto& s : mStreams) {
+                if (s.second.second == patch.id) s.second.second = -1;
+            }
+        }
+    }
+    return OK;
+}
+
+status_t Hal2AidlMapper::createOrUpdatePortConfig(
+        const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
+    AudioPortConfig appliedPortConfig;
+    bool applied = false;
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
+                            requestedPortConfig, &appliedPortConfig, &applied)));
+    if (!applied) {
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
+                                appliedPortConfig, &appliedPortConfig, &applied)));
+        if (!applied) {
+            ALOGE("%s: module %s did not apply suggested config %s",
+                    __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
+            return NO_INIT;
+        }
+    }
+
+    int32_t id = appliedPortConfig.id;
+    if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
+        LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
+                requestedPortConfig.id, id);
+    }
+
+    auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
+            std::move(appliedPortConfig));
+    *result = it;
+    *created = inserted;
+    return OK;
+}
+
+void Hal2AidlMapper::eraseConnectedPort(int32_t portId) {
+    mPorts.erase(portId);
+    mConnectedPorts.erase(portId);
+    if (mDisconnectedPortReplacement.first == portId) {
+        const auto& port = mDisconnectedPortReplacement.second;
+        mPorts.insert(std::make_pair(port.id, port));
+        ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
+        mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
+    }
+}
+
+status_t Hal2AidlMapper::findOrCreatePatch(
+        const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
+    std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
+            requestedPatch.sourcePortConfigIds.end());
+    std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
+            requestedPatch.sinkPortConfigIds.end());
+    return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
+}
+
+status_t Hal2AidlMapper::findOrCreatePatch(
+        const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
+        AudioPatch* patch, bool* created) {
+    auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
+    if (patchIt == mPatches.end()) {
+        AudioPatch requestedPatch, appliedPatch;
+        requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
+                sourcePortConfigIds.begin(), sourcePortConfigIds.end());
+        requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
+                sinkPortConfigIds.begin(), sinkPortConfigIds.end());
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
+                                requestedPatch, &appliedPatch)));
+        patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
+        *created = true;
+    } else {
+        *created = false;
+    }
+    *patch = patchIt->second;
+    return OK;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+        const AudioDevice& device, const AudioConfig* config, AudioPortConfig* portConfig,
+        bool* created) {
+    auto portConfigIt = findPortConfig(device);
+    if (portConfigIt == mPortConfigs.end()) {
+        auto portsIt = findPort(device);
+        if (portsIt == mPorts.end()) {
+            ALOGE("%s: device port for device %s is not found in the module %s",
+                    __func__, device.toString().c_str(), mInstance.c_str());
+            return BAD_VALUE;
+        }
+        AudioPortConfig requestedPortConfig;
+        requestedPortConfig.portId = portsIt->first;
+        if (config != nullptr) {
+            setPortConfigFromConfig(&requestedPortConfig, *config);
+        }
+        RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+                created));
+    } else {
+        *created = false;
+    }
+    *portConfig = portConfigIt->second;
+    return OK;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+        const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
+        AudioSource source, const std::set<int32_t>& destinationPortIds,
+        AudioPortConfig* portConfig, bool* created) {
+    // These flags get removed one by one in this order when retrying port finding.
+    static const std::vector<AudioInputFlags> kOptionalInputFlags{
+        AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
+    auto portConfigIt = findPortConfig(config, flags, ioHandle);
+    if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
+        auto optionalInputFlagsIt = kOptionalInputFlags.begin();
+        AudioIoFlags matchFlags = flags.value();
+        auto portsIt = findPort(config, matchFlags, destinationPortIds);
+        while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
+                && optionalInputFlagsIt != kOptionalInputFlags.end()) {
+            if (!isBitPositionFlagSet(
+                            matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
+                ++optionalInputFlagsIt;
+                continue;
+            }
+            matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
+                    ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
+            portsIt = findPort(config, matchFlags, destinationPortIds);
+            ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
+                    "retried with flags %s", __func__, config.toString().c_str(),
+                    flags.value().toString().c_str(), mInstance.c_str(),
+                    matchFlags.toString().c_str());
+        }
+        if (portsIt == mPorts.end()) {
+            ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
+                    __func__, config.toString().c_str(), matchFlags.toString().c_str(),
+                    mInstance.c_str());
+            return BAD_VALUE;
+        }
+        AudioPortConfig requestedPortConfig;
+        requestedPortConfig.portId = portsIt->first;
+        setPortConfigFromConfig(&requestedPortConfig, config);
+        requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
+        if (matchFlags.getTag() == AudioIoFlags::Tag::input
+                && source != AudioSource::SYS_RESERVED_INVALID) {
+            requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
+                    AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
+        }
+        RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+                created));
+    } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
+        ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
+                "and was not created as flags are not specified",
+                __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
+        return BAD_VALUE;
+    } else {
+        AudioPortConfig requestedPortConfig = portConfigIt->second;
+        if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
+            AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
+            if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
+                    source != AudioSource::SYS_RESERVED_INVALID) {
+                mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
+            }
+        }
+
+        if (requestedPortConfig != portConfigIt->second) {
+            RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+                    created));
+        } else {
+            *created = false;
+        }
+    }
+    *portConfig = portConfigIt->second;
+    return OK;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+        const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
+        AudioPortConfig* portConfig, bool* created) {
+    using Tag = AudioPortExt::Tag;
+    if (requestedPortConfig.ext.getTag() == Tag::mix) {
+        if (const auto& p = requestedPortConfig;
+                !p.sampleRate.has_value() || !p.channelMask.has_value() ||
+                !p.format.has_value()) {
+            ALOGW("%s: provided mix port config is not fully specified: %s",
+                    __func__, p.toString().c_str());
+            return BAD_VALUE;
+        }
+        AudioConfig config;
+        setConfigFromPortConfig(&config, requestedPortConfig);
+        AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
+                AudioPortMixExtUseCase::Tag::source ?
+                requestedPortConfig.ext.get<Tag::mix>().usecase.
+                get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
+        return findOrCreatePortConfig(config, requestedPortConfig.flags,
+                requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
+                portConfig, created);
+    } else if (requestedPortConfig.ext.getTag() == Tag::device) {
+        return findOrCreatePortConfig(
+                requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
+                portConfig, created);
+    }
+    ALOGW("%s: unsupported audio port config: %s",
+            __func__, requestedPortConfig.toString().c_str());
+    return BAD_VALUE;
+}
+
+status_t Hal2AidlMapper::findOrCreatePortConfig(
+        const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
+        AudioPortConfig* portConfig, Cleanups* cleanups) {
+    bool created = false;
+    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+                    requestedPortConfig, destinationPortIds, portConfig, &created));
+    if (created && cleanups != nullptr) {
+        cleanups->add(&Hal2AidlMapper::resetPortConfig, portConfig->id);
+    }
+    return OK;
+}
+
+status_t Hal2AidlMapper::findPortConfig(const AudioDevice& device, AudioPortConfig* portConfig) {
+    if (auto it = findPortConfig(device); it != mPortConfigs.end()) {
+        *portConfig = it->second;
+        return OK;
+    }
+    ALOGE("%s: could not find a configured device port for device %s",
+            __func__, device.toString().c_str());
+    return BAD_VALUE;
+}
+
+Hal2AidlMapper::Patches::iterator Hal2AidlMapper::findPatch(
+        const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
+    return std::find_if(mPatches.begin(), mPatches.end(),
+            [&](const auto& pair) {
+                const auto& p = pair.second;
+                std::set<int32_t> patchSrcs(
+                        p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
+                std::set<int32_t> patchSinks(
+                        p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
+                return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
+}
+
+Hal2AidlMapper::Ports::iterator Hal2AidlMapper::findPort(const AudioDevice& device) {
+    if (device.type.type == AudioDeviceType::IN_DEFAULT) {
+        return mPorts.find(mDefaultInputPortId);
+    } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
+        return mPorts.find(mDefaultOutputPortId);
+    }
+    if (device.address.getTag() != AudioDeviceAddress::id ||
+            !device.address.get<AudioDeviceAddress::id>().empty()) {
+        return std::find_if(mPorts.begin(), mPorts.end(),
+                [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+    }
+    // For connection w/o an address, two ports can be found: the template port,
+    // and a connected port (if exists). Make sure we return the connected port.
+    Hal2AidlMapper::Ports::iterator portIt = mPorts.end();
+    for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
+        if (audioDeviceMatches(device, it->second)) {
+            if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
+                return it;
+            } else {
+                // Will return 'it' if there is no connected port.
+                portIt = it;
+            }
+        }
+    }
+    return portIt;
+}
+
+Hal2AidlMapper::Ports::iterator Hal2AidlMapper::findPort(
+            const AudioConfig& config, const AudioIoFlags& flags,
+            const std::set<int32_t>& destinationPortIds) {
+    auto belongsToProfile = [&config](const AudioProfile& prof) {
+        return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
+                (config.base.channelMask.getTag() == AudioChannelLayout::none ||
+                        std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
+                                config.base.channelMask) != prof.channelMasks.end()) &&
+                (config.base.sampleRate == 0 ||
+                        std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
+                                config.base.sampleRate) != prof.sampleRates.end());
+    };
+    static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
+    int optionalFlags = 0;
+    auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
+        // Ports should be able to match if the optional flags are not requested.
+        return portFlags == flags ||
+               (portFlags.getTag() == AudioIoFlags::Tag::output &&
+                        AudioIoFlags::make<AudioIoFlags::Tag::output>(
+                                portFlags.get<AudioIoFlags::Tag::output>() &
+                                        ~optionalFlags) == flags);
+    };
+    auto matcher = [&](const auto& pair) {
+        const auto& p = pair.second;
+        return p.ext.getTag() == AudioPortExt::Tag::mix &&
+                flagMatches(p.flags) &&
+                (destinationPortIds.empty() ||
+                        std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
+                                [&](const int32_t destId) { return mRoutingMatrix.count(
+                                            std::make_pair(p.id, destId)) != 0; })) &&
+                (p.profiles.empty() ||
+                        std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
+                        p.profiles.end()); };
+    auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
+    if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
+        auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
+        while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
+            if (isBitPositionFlagSet(
+                        flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
+                // If the flag is set by the request, it must be matched.
+                ++optionalOutputFlagsIt;
+                continue;
+            }
+            optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
+            result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
+            ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
+                  "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
+                    flags.toString().c_str(), mInstance.c_str(), optionalFlags);
+        }
+    }
+    return result;
+}
+
+Hal2AidlMapper::PortConfigs::iterator Hal2AidlMapper::findPortConfig(const AudioDevice& device) {
+    return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+            [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+}
+
+Hal2AidlMapper::PortConfigs::iterator Hal2AidlMapper::findPortConfig(
+            const std::optional<AudioConfig>& config,
+            const std::optional<AudioIoFlags>& flags,
+            int32_t ioHandle) {
+    using Tag = AudioPortExt::Tag;
+    return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+            [&](const auto& pair) {
+                const auto& p = pair.second;
+                LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
+                        (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
+                                !p.format.has_value() || !p.flags.has_value()),
+                        "%s: stored mix port config is not fully specified: %s",
+                        __func__, p.toString().c_str());
+                return p.ext.getTag() == Tag::mix &&
+                        (!config.has_value() ||
+                                isConfigEqualToPortConfig(config.value(), p)) &&
+                        (!flags.has_value() || p.flags.value() == flags.value()) &&
+                        p.ext.template get<Tag::mix>().handle == ioHandle; });
+}
+
+status_t Hal2AidlMapper::getAudioMixPort(int32_t ioHandle, AudioPort* port) {
+    auto it = findPortConfig(std::nullopt /*config*/, std::nullopt /*flags*/, ioHandle);
+    if (it == mPortConfigs.end()) {
+        ALOGE("%s, cannot find mix port config for handle %u", __func__, ioHandle);
+        return BAD_VALUE;
+    }
+    return updateAudioPort(it->second.portId, port);
+}
+
+status_t Hal2AidlMapper::getAudioPortCached(
+        const ::aidl::android::media::audio::common::AudioDevice& device,
+        ::aidl::android::media::audio::common::AudioPort* port) {
+
+    if (auto portsIt = findPort(device); portsIt != mPorts.end()) {
+        *port = portsIt->second;
+        return OK;
+    }
+    ALOGE("%s: device port for device %s is not found in the module %s",
+            __func__, device.toString().c_str(), mInstance.c_str());
+    return BAD_VALUE;
+}
+
+status_t Hal2AidlMapper::initialize() {
+    std::vector<AudioPort> ports;
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
+    ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
+            __func__, mInstance.c_str());
+    mDefaultInputPortId = mDefaultOutputPortId = -1;
+    const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+    for (auto it = ports.begin(); it != ports.end(); ) {
+        const auto& port = *it;
+        if (port.ext.getTag() != AudioPortExt::Tag::device) {
+            ++it;
+            continue;
+        }
+        const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>();
+        if ((deviceExt.flags & defaultDeviceFlag) != 0) {
+            if (port.flags.getTag() == AudioIoFlags::Tag::input) {
+                mDefaultInputPortId = port.id;
+            } else if (port.flags.getTag() == AudioIoFlags::Tag::output) {
+                mDefaultOutputPortId = port.id;
+            }
+        }
+        // For compatibility with HIDL, hide "template" remote submix ports from ports list.
+        if (const auto& devDesc = deviceExt.device;
+                (devDesc.type.type == AudioDeviceType::IN_SUBMIX ||
+                        devDesc.type.type == AudioDeviceType::OUT_SUBMIX) &&
+                devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) {
+            if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) {
+                mRemoteSubmixIn = port;
+            } else {
+                mRemoteSubmixOut = port;
+            }
+            it = ports.erase(it);
+        } else {
+            ++it;
+        }
+    }
+    if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) {
+        ALOGE("%s: The configuration only has input or output remote submix device, must have both",
+                __func__);
+        mRemoteSubmixIn.reset();
+        mRemoteSubmixOut.reset();
+    }
+    if (mRemoteSubmixIn.has_value()) {
+        AudioPort connectedRSubmixIn = *mRemoteSubmixIn;
+        connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address =
+                AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
+        ALOGD("%s: connecting remote submix input", __func__);
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+                                connectedRSubmixIn, &connectedRSubmixIn)));
+        // The template port for the remote submix input couldn't be "default" because it is not
+        // attached. The connected port can now be made default because we never disconnect it.
+        if (mDefaultInputPortId == -1) {
+            mDefaultInputPortId = connectedRSubmixIn.id;
+        }
+        ports.push_back(std::move(connectedRSubmixIn));
+
+        // Remote submix output must not be connected until the framework actually starts
+        // using it, however for legacy compatibility we need to provide an "augmented template"
+        // port with an address and profiles. It is obtained by connecting the output and then
+        // immediately disconnecting it. This is a cheap operation as we don't open any streams.
+        AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut;
+        tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address =
+                AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
+        ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__);
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+                                tempConnectedRSubmixOut, &tempConnectedRSubmixOut)));
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
+                                tempConnectedRSubmixOut.id)));
+        tempConnectedRSubmixOut.id = mRemoteSubmixOut->id;
+        ports.push_back(std::move(tempConnectedRSubmixOut));
+    }
+
+    ALOGI("%s: module %s default port ids: input %d, output %d",
+            __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
+    std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
+            [](const auto& p) { return std::make_pair(p.id, p); });
+    RETURN_STATUS_IF_ERROR(updateRoutes());
+    std::vector<AudioPortConfig> portConfigs;
+    RETURN_STATUS_IF_ERROR(
+            statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs)));  // OK if empty
+    std::transform(portConfigs.begin(), portConfigs.end(),
+            std::inserter(mPortConfigs, mPortConfigs.end()),
+            [](const auto& p) { return std::make_pair(p.id, p); });
+    std::transform(mPortConfigs.begin(), mPortConfigs.end(),
+            std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
+            [](const auto& pcPair) { return pcPair.first; });
+    std::vector<AudioPatch> patches;
+    RETURN_STATUS_IF_ERROR(
+            statusTFromBinderStatus(mModule->getAudioPatches(&patches)));  // OK if empty
+    std::transform(patches.begin(), patches.end(),
+            std::inserter(mPatches, mPatches.end()),
+            [](const auto& p) { return std::make_pair(p.id, p); });
+    return OK;
+}
+
+bool Hal2AidlMapper::isPortBeingHeld(int32_t portId) {
+    // It is assumed that mStreams has already been cleaned up.
+    for (const auto& s : mStreams) {
+        if (portConfigBelongsToPort(s.second.first, portId)) return true;
+    }
+    for (const auto& [_, patch] : mPatches) {
+        for (int32_t id : patch.sourcePortConfigIds) {
+            if (portConfigBelongsToPort(id, portId)) return true;
+        }
+        for (int32_t id : patch.sinkPortConfigIds) {
+            if (portConfigBelongsToPort(id, portId)) return true;
+        }
+    }
+    return false;
+}
+
+status_t Hal2AidlMapper::prepareToOpenStream(
+        int32_t ioHandle, const AudioDevice& device, const AudioIoFlags& flags,
+        AudioSource source, Cleanups* cleanups, AudioConfig* config,
+        AudioPortConfig* mixPortConfig, AudioPatch* patch) {
+    ALOGD("%p %s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
+            this, __func__, ioHandle, device.toString().c_str(),
+            flags.toString().c_str(), toString(source).c_str(),
+            config->toString().c_str(), mixPortConfig->toString().c_str());
+    resetUnusedPatchesAndPortConfigs();
+    const bool isInput = flags.getTag() == AudioIoFlags::Tag::input;
+    // Find / create AudioPortConfigs for the device port and the mix port,
+    // then find / create a patch between them, and open a stream on the mix port.
+    AudioPortConfig devicePortConfig;
+    bool created = false;
+    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(device, config,
+                                                  &devicePortConfig, &created));
+    if (created) {
+        cleanups->add(&Hal2AidlMapper::resetPortConfig, devicePortConfig.id);
+    }
+    RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*config, flags, ioHandle, source,
+                    std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
+    if (created) {
+        cleanups->add(&Hal2AidlMapper::resetPortConfig, mixPortConfig->id);
+    }
+    setConfigFromPortConfig(config, *mixPortConfig);
+    if (isInput) {
+        RETURN_STATUS_IF_ERROR(findOrCreatePatch(
+                        {devicePortConfig.id}, {mixPortConfig->id}, patch, &created));
+    } else {
+        RETURN_STATUS_IF_ERROR(findOrCreatePatch(
+                        {mixPortConfig->id}, {devicePortConfig.id}, patch, &created));
+    }
+    if (created) {
+        cleanups->add(&Hal2AidlMapper::resetPatch, patch->id);
+    }
+    if (config->frameCount <= 0) {
+        config->frameCount = patch->minimumStreamBufferSizeFrames;
+    }
+    return OK;
+}
+
+status_t Hal2AidlMapper::releaseAudioPatch(int32_t patchId) {
+    return releaseAudioPatches({patchId});
+}
+
+status_t Hal2AidlMapper::releaseAudioPatches(const std::set<int32_t>& patchIds) {
+    status_t result = OK;
+    for (const auto patchId : patchIds) {
+        if (auto it = mPatches.find(patchId); it != mPatches.end()) {
+            mPatches.erase(it);
+            if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
+                ALOGE("%s: error while resetting patch %d: %s",
+                        __func__, patchId, status.getDescription().c_str());
+                result = statusTFromBinderStatus(status);
+            }
+        } else {
+            ALOGE("%s: patch id %d not found", __func__, patchId);
+            result = BAD_VALUE;
+        }
+    }
+    resetUnusedPortConfigs();
+    return result;
+}
+
+void Hal2AidlMapper::resetPortConfig(int32_t portConfigId) {
+    if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
+        mPortConfigs.erase(it);
+        if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
+                !status.isOk()) {
+            ALOGE("%s: error while resetting port config %d: %s",
+                    __func__, portConfigId, status.getDescription().c_str());
+        }
+        return;
+    }
+    ALOGE("%s: port config id %d not found", __func__, portConfigId);
+}
+
+void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() {
+    // Since patches can be created independently of streams via 'createOrUpdatePatch',
+    // here we only clean up patches for released streams.
+    std::set<int32_t> patchesToRelease;
+    for (auto it = mStreams.begin(); it != mStreams.end(); ) {
+        if (auto streamSp = it->first.promote(); streamSp) {
+            ++it;
+        } else {
+            if (const int32_t patchId = it->second.second; patchId != -1) {
+                patchesToRelease.insert(patchId);
+            }
+            it = mStreams.erase(it);
+        }
+    }
+    // 'releaseAudioPatches' also resets unused port configs.
+    releaseAudioPatches(patchesToRelease);
+}
+
+void Hal2AidlMapper::resetUnusedPortConfigs() {
+    // The assumption is that port configs are used to create patches
+    // (or to open streams, but that involves creation of patches, too). Thus,
+    // orphaned port configs can and should be reset.
+    std::map<int32_t, int32_t /*portID*/> portConfigIds;
+    std::transform(mPortConfigs.begin(), mPortConfigs.end(),
+            std::inserter(portConfigIds, portConfigIds.end()),
+            [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
+    for (const auto& p : mPatches) {
+        for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
+        for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
+    }
+    for (int32_t id : mInitialPortConfigIds) {
+        portConfigIds.erase(id);
+    }
+    for (const auto& s : mStreams) {
+        portConfigIds.erase(s.second.first);
+    }
+    std::set<int32_t> retryDeviceDisconnection;
+    for (const auto& portConfigAndIdPair : portConfigIds) {
+        resetPortConfig(portConfigAndIdPair.first);
+        if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
+                it != mConnectedPorts.end() && it->second) {
+            retryDeviceDisconnection.insert(portConfigAndIdPair.second);
+        }
+    }
+    for (int32_t portId : retryDeviceDisconnection) {
+        if (!isPortBeingHeld(portId)) {
+            if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
+                eraseConnectedPort(portId);
+                ALOGD("%s: executed postponed external device disconnection for port ID %d",
+                        __func__, portId);
+            }
+        }
+    }
+    if (!retryDeviceDisconnection.empty()) {
+        updateRoutes();
+    }
+}
+
+status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) {
+    if (connected) {
+        AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
+        std::optional<AudioPort> templatePort;
+        auto erasePortAfterConnectionIt = mPorts.end();
+        // Connection of remote submix out with address "0" is a special case. Since there is
+        // already an "augmented template" port with this address in mPorts, we need to replace
+        // it with a connected port.
+        // Connection of remote submix outs with any other address is done as usual except that
+        // the template port is in `mRemoteSubmixOut`.
+        if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) {
+            if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
+                            AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
+                erasePortAfterConnectionIt = findPort(matchDevice);
+            }
+            templatePort = mRemoteSubmixOut;
+        } else if (mRemoteSubmixIn.has_value() &&
+                matchDevice.type.type == AudioDeviceType::IN_SUBMIX) {
+            templatePort = mRemoteSubmixIn;
+        } else {
+            // Reset the device address to find the "template" port.
+            matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
+        }
+        if (!templatePort.has_value()) {
+            auto portsIt = findPort(matchDevice);
+            if (portsIt == mPorts.end()) {
+                // Since 'setConnectedState' is called for all modules, it is normal when the device
+                // port not found in every one of them.
+                return BAD_VALUE;
+            } else {
+                ALOGD("%s: device port for device %s found in the module %s",
+                        __func__, matchDevice.toString().c_str(), mInstance.c_str());
+            }
+            templatePort = portsIt->second;
+        }
+        resetUnusedPatchesAndPortConfigs();
+
+        // Use the ID of the "template" port, use all the information from the provided port.
+        AudioPort connectedPort = devicePort;
+        connectedPort.id = templatePort->id;
+        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+                                connectedPort, &connectedPort)));
+        const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
+        LOG_ALWAYS_FATAL_IF(!inserted,
+                "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
+                __func__, mInstance.c_str(), connectedPort.toString().c_str(),
+                it->second.toString().c_str());
+        mConnectedPorts[connectedPort.id] = false;
+        if (erasePortAfterConnectionIt != mPorts.end()) {
+            mPorts.erase(erasePortAfterConnectionIt);
+        }
+    } else {  // !connected
+        AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
+        auto portsIt = findPort(matchDevice);
+        if (portsIt == mPorts.end()) {
+            // Since 'setConnectedState' is called for all modules, it is normal when the device
+            // port not found in every one of them.
+            return BAD_VALUE;
+        } else {
+            ALOGD("%s: device port for device %s found in the module %s",
+                    __func__, matchDevice.toString().c_str(), mInstance.c_str());
+        }
+        resetUnusedPatchesAndPortConfigs();
+
+        // Disconnection of remote submix out with address "0" is a special case. We need to replace
+        // the connected port entry with the "augmented template".
+        const int32_t portId = portsIt->second.id;
+        if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX &&
+                matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
+                        AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
+            mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut);
+            auto& port = mDisconnectedPortReplacement.second;
+            port.ext.get<AudioPortExt::Tag::device>().device = matchDevice;
+            port.profiles = portsIt->second.profiles;
+        }
+        // Streams are closed by AudioFlinger independently from device disconnections.
+        // It is possible that the stream has not been closed yet.
+        if (!isPortBeingHeld(portId)) {
+            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+                            mModule->disconnectExternalDevice(portId)));
+            eraseConnectedPort(portId);
+        } else {
+            ALOGD("%s: since device port ID %d is used by a stream, "
+                    "external device disconnection postponed", __func__, portId);
+            mConnectedPorts[portId] = true;
+        }
+    }
+    return updateRoutes();
+}
+
+status_t Hal2AidlMapper::updateAudioPort(int32_t portId, AudioPort* port) {
+    const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
+    if (status == OK) {
+        auto portIt = mPorts.find(portId);
+        if (portIt != mPorts.end()) {
+            portIt->second = *port;
+        } else {
+            ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
+                  __func__, portId);
+        }
+    }
+    return status;
+}
+
+status_t Hal2AidlMapper::updateRoutes() {
+    RETURN_STATUS_IF_ERROR(
+            statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
+    ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
+            __func__, mInstance.c_str());
+    if (mRemoteSubmixIn.has_value()) {
+        // Remove mentions of the template remote submix input from routes.
+        int32_t rSubmixInId = mRemoteSubmixIn->id;
+        // Remove mentions of the template remote submix out only if it is not in mPorts
+        // (that means there is a connected port in mPorts).
+        int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ?
+                mRemoteSubmixOut->id : -1;
+        for (auto it = mRoutes.begin(); it != mRoutes.end();) {
+            auto& route = *it;
+            if (route.sinkPortId == rSubmixOutId) {
+                it = mRoutes.erase(it);
+                continue;
+            }
+            if (auto routeIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
+                            rSubmixInId); routeIt != route.sourcePortIds.end()) {
+                route.sourcePortIds.erase(routeIt);
+                if (route.sourcePortIds.empty()) {
+                    it = mRoutes.erase(it);
+                    continue;
+                }
+            }
+            ++it;
+        }
+    }
+    mRoutingMatrix.clear();
+    for (const auto& r : mRoutes) {
+        for (auto portId : r.sourcePortIds) {
+            mRoutingMatrix.emplace(r.sinkPortId, portId);
+            mRoutingMatrix.emplace(portId, r.sinkPortId);
+        }
+    }
+    return OK;
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
new file mode 100644
index 0000000..70a2bd7
--- /dev/null
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <media/AidlConversionUtil.h>
+
+#include "Cleanups.h"
+
+namespace android {
+
+class Hal2AidlMapper;
+class StreamHalInterface;
+
+// The mapper class is needed because the framework was not yet updated to operate on AIDL-based
+// structures directly. Mapper does the job of translating the "legacy" way of identifying ports
+// and port configs (by device addresses and I/O handles) into AIDL IDs. Once the framework will
+// be updated to provide these IDs directly to libaudiohal, the need for the mapper will cease.
+class Hal2AidlMapper {
+  public:
+    using Cleanups = Cleanups<Hal2AidlMapper>;
+
+    Hal2AidlMapper(
+            const std::string& instance,
+            const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module);
+
+    void addStream(const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId);
+    status_t createOrUpdatePatch(
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources,
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks,
+            int32_t* patchId, Cleanups* cleanups);
+    status_t findOrCreatePortConfig(
+            const ::aidl::android::media::audio::common::AudioDevice& device,
+            const ::aidl::android::media::audio::common::AudioConfig* config,
+            ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+            bool* created);
+    status_t findOrCreatePortConfig(
+            const ::aidl::android::media::audio::common::AudioConfig& config,
+            const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
+            int32_t ioHandle,
+            ::aidl::android::media::audio::common::AudioSource source,
+            const std::set<int32_t>& destinationPortIds,
+            ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+    status_t findOrCreatePortConfig(
+        const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+        const std::set<int32_t>& destinationPortIds,
+        ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+    status_t findOrCreatePortConfig(
+        const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+        const std::set<int32_t>& destinationPortIds,
+        ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+        Cleanups* cleanups = nullptr);
+    status_t findPortConfig(
+            const ::aidl::android::media::audio::common::AudioDevice& device,
+            ::aidl::android::media::audio::common::AudioPortConfig* portConfig);
+    status_t getAudioMixPort(
+            int32_t ioHandle, ::aidl::android::media::audio::common::AudioPort* port);
+    status_t getAudioPortCached(
+            const ::aidl::android::media::audio::common::AudioDevice& device,
+            ::aidl::android::media::audio::common::AudioPort* port);
+    template<typename OutputContainer, typename Func>
+    status_t getAudioPorts(OutputContainer* ports, Func converter) {
+        return ::aidl::android::convertContainer(mPorts, ports,
+                [&converter](const auto& pair) { return converter(pair.second); });
+    }
+    template<typename OutputContainer, typename Func>
+    status_t getAudioRoutes(OutputContainer* routes, Func converter) {
+        return ::aidl::android::convertContainer(mRoutes, routes, converter);
+    }
+    status_t initialize();
+    status_t prepareToOpenStream(
+        int32_t ioHandle,
+        const ::aidl::android::media::audio::common::AudioDevice& device,
+        const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+        ::aidl::android::media::audio::common::AudioSource source,
+        Cleanups* cleanups,
+        ::aidl::android::media::audio::common::AudioConfig* config,
+        ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
+        ::aidl::android::hardware::audio::core::AudioPatch* patch);
+    status_t releaseAudioPatch(int32_t patchId);
+    void resetUnusedPatchesAndPortConfigs();
+    status_t setDevicePortConnectedState(
+            const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected);
+
+  private:
+    // IDs of ports for connected external devices, and whether they are held by streams.
+    using ConnectedPorts = std::map<int32_t /*port ID*/, bool>;
+    using Patches = std::map<int32_t /*patch ID*/,
+            ::aidl::android::hardware::audio::core::AudioPatch>;
+    using PortConfigs = std::map<int32_t /*port config ID*/,
+            ::aidl::android::media::audio::common::AudioPortConfig>;
+    using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
+    using Routes = std::vector<::aidl::android::hardware::audio::core::AudioRoute>;
+    // Answers the question "whether portID 'first' is reachable from portID 'second'?"
+    // It's not a map because both portIDs are known. The matrix is symmetric.
+    using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>;
+    // There is always a port config ID set. The patch ID is set after stream
+    // creation, and can be set to '-1' later if the framework happens to create
+    // a patch between the same endpoints. In that case, the ownership of the patch
+    // is on the framework.
+    using Streams = std::map<wp<StreamHalInterface>,
+            std::pair<int32_t /*port config ID*/, int32_t /*patch ID*/>>;
+
+    const std::string mInstance;
+    const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule;
+
+    bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
+            const ::aidl::android::media::audio::common::AudioPort& p);
+    bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
+            const ::aidl::android::media::audio::common::AudioPortConfig& p);
+    status_t createOrUpdatePortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+            PortConfigs::iterator* result, bool *created);
+    void eraseConnectedPort(int32_t portId);
+    status_t findOrCreatePatch(
+        const std::set<int32_t>& sourcePortConfigIds,
+        const std::set<int32_t>& sinkPortConfigIds,
+        ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+    status_t findOrCreatePatch(
+        const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch,
+        ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+    Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds,
+            const std::set<int32_t>& sinkPortConfigIds);
+    Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device);
+    Ports::iterator findPort(
+            const ::aidl::android::media::audio::common::AudioConfig& config,
+            const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+            const std::set<int32_t>& destinationPortIds);
+    PortConfigs::iterator findPortConfig(
+            const ::aidl::android::media::audio::common::AudioDevice& device);
+    PortConfigs::iterator findPortConfig(
+            const std::optional<::aidl::android::media::audio::common::AudioConfig>& config,
+            const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
+            int32_t ioHandle);
+    bool isPortBeingHeld(int32_t portId);
+    bool portConfigBelongsToPort(int32_t portConfigId, int32_t portId) {
+        auto it = mPortConfigs.find(portConfigId);
+        return it != mPortConfigs.end() && it->second.portId == portId;
+    }
+    status_t releaseAudioPatches(const std::set<int32_t>& patchIds);
+    void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); }
+    void resetPortConfig(int32_t portConfigId);
+    void resetUnusedPortConfigs();
+    status_t updateAudioPort(
+            int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
+    status_t updateRoutes();
+
+    Ports mPorts;
+    // Remote submix "template" ports (no address specified, no profiles).
+    // They are excluded from `mPorts` as their presence confuses the framework code.
+    std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn;
+    std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut;
+    int32_t mDefaultInputPortId = -1;
+    int32_t mDefaultOutputPortId = -1;
+    PortConfigs mPortConfigs;
+    std::set<int32_t> mInitialPortConfigIds;
+    Patches mPatches;
+    Routes mRoutes;
+    RoutingMatrix mRoutingMatrix;
+    Streams mStreams;
+    ConnectedPorts mConnectedPorts;
+    std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
+            mDisconnectedPortReplacement;
+};
+
+}  // namespace android
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index e74fc16..378d919 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -83,6 +83,7 @@
           mContext(std::move(context)),
           mStream(stream),
           mVendorExt(vext) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     {
         std::lock_guard l(mLock);
         mLastReply.latencyMs = nominalLatency;
@@ -97,6 +98,7 @@
 }
 
 StreamHalAidl::~StreamHalAidl() {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     if (mStream != nullptr) {
         ndk::ScopedAStatus status = mStream->close();
         ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index df64676..1a37622 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -17,7 +17,7 @@
 #ifndef LVM_FLOAT
 typedef float LVM_FLOAT;
 #endif
-#define LOG_TAG "Bundle"
+#define LOG_TAG "EffectBundle"
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array)[0])
 //#define LOG_NDEBUG 0
 
@@ -1191,11 +1191,13 @@
 //  0            if the configuration is supported
 //----------------------------------------------------------------------------
 int VirtualizerIsDeviceSupported(audio_devices_t deviceType) {
+    ALOGV("%s: deviceType:%#x", __func__, deviceType);
     switch (deviceType) {
         case AUDIO_DEVICE_OUT_WIRED_HEADSET:
         case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
         case AUDIO_DEVICE_OUT_USB_HEADSET:
+        case AUDIO_DEVICE_OUT_BLE_HEADSET:
             // case AUDIO_DEVICE_OUT_USB_DEVICE:  // For USB testing of the virtualizer only.
             return 0;
         default:
@@ -3372,10 +3374,10 @@
             if (pContext->EffectType == LVM_BASS_BOOST) {
                 if ((device == AUDIO_DEVICE_OUT_SPEAKER) ||
                     (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
-                    (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
-                    ALOGV("\tEFFECT_CMD_SET_DEVICE device is invalid for LVM_BASS_BOOST %d",
-                          *(int32_t*)pCmdData);
-                    ALOGV("\tEFFECT_CMD_SET_DEVICE temporary disable LVM_BAS_BOOST");
+                     device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER ||
+                     device == AUDIO_DEVICE_OUT_BLE_SPEAKER) {
+                    ALOGV("%s: EFFECT_CMD_SET_DEVICE device %#x is invalid for LVM_BASS_BOOST",
+                            __func__, device);
 
                     // If a device doesn't support bassboost the effect must be temporarily disabled
                     // the effect must still report its original state as this can only be changed
diff --git a/media/liberror/include/error/expected_utils.h b/media/liberror/include/error/expected_utils.h
index ddc8517..8c1654a 100644
--- a/media/liberror/include/error/expected_utils.h
+++ b/media/liberror/include/error/expected_utils.h
@@ -20,6 +20,10 @@
 #include <android-base/expected.h>
 #include <log/log_main.h>
 
+#pragma push_macro("LOG_TAG")
+#undef LOG_TAG
+#define LOG_TAG "MediaLibError"
+
 /**
  * Useful macros for working with status codes and base::expected.
  *
@@ -50,18 +54,26 @@
  *   human-readable version of the status.
  */
 
-#define VALUE_OR_RETURN(exp)                                                         \
-    ({                                                                               \
-        auto _tmp = (exp);                                                           \
-        if (!_tmp.ok()) return ::android::base::unexpected(std::move(_tmp.error())); \
-        std::move(_tmp.value());                                                     \
+#define VALUE_OR_RETURN(exp)                                                          \
+    ({                                                                                \
+        auto _tmp = (exp);                                                            \
+        if (!_tmp.ok()) {                                                             \
+            ALOGE("Function: %s Line: %d Failed result (%s)", __FUNCTION__, __LINE__, \
+                  errorToString(_tmp.error()).c_str());                               \
+            return ::android::base::unexpected(std::move(_tmp.error()));              \
+        }                                                                             \
+        std::move(_tmp.value());                                                      \
     })
 
-#define VALUE_OR_RETURN_STATUS(exp)                     \
-    ({                                                  \
-        auto _tmp = (exp);                              \
-        if (!_tmp.ok()) return std::move(_tmp.error()); \
-        std::move(_tmp.value());                        \
+#define VALUE_OR_RETURN_STATUS(exp)                                                   \
+    ({                                                                                \
+        auto _tmp = (exp);                                                            \
+        if (!_tmp.ok()) {                                                             \
+            ALOGE("Function: %s Line: %d Failed result (%s)", __FUNCTION__, __LINE__, \
+                  errorToString(_tmp.error()).c_str());                               \
+            return std::move(_tmp.error());                                           \
+        }                                                                             \
+        std::move(_tmp.value());                                                      \
     })
 
 #define VALUE_OR_FATAL(exp)                                                                       \
@@ -72,15 +84,29 @@
         std::move(_tmp.value());                                                                  \
     })
 
-#define RETURN_IF_ERROR(exp) \
-    if (auto _tmp = (exp); !errorIsOk(_tmp)) return ::android::base::unexpected(std::move(_tmp));
+#define RETURN_IF_ERROR(exp)                                                \
+    ({                                                                      \
+        auto _tmp = (exp);                                                  \
+        if (!errorIsOk(_tmp)) {                                             \
+            ALOGE("Function: %s Line: %d Failed ", __FUNCTION__, __LINE__); \
+            return ::android::base::unexpected(std::move(_tmp));            \
+        }                                                                   \
+    })
 
-#define RETURN_STATUS_IF_ERROR(exp) \
-    if (auto _tmp = (exp); !errorIsOk(_tmp)) return _tmp;
+#define RETURN_STATUS_IF_ERROR(exp)                                         \
+    ({                                                                      \
+        auto _tmp = (exp);                                                  \
+        if (!errorIsOk(_tmp)) {                                             \
+            ALOGE("Function: %s Line: %d Failed ", __FUNCTION__, __LINE__); \
+            return _tmp;                                                    \
+        }                                                                   \
+    })
 
 #define FATAL_IF_ERROR(exp)                                                                \
     {                                                                                      \
         auto _tmp = (exp);                                                                 \
         LOG_ALWAYS_FATAL_IF(!errorIsOk(_tmp), "Function: %s Line: %d Failed result: (%s)", \
-                            __FUNCTION__, __LINE__, errorToString(_tmp).c_str());         \
+                            __FUNCTION__, __LINE__, errorToString(_tmp).c_str());          \
     }
+
+#pragma pop_macro("LOG_TAG")
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index a6f0b60..1bcb4b9 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -61,8 +61,9 @@
 }
 
 //static
-MediaResource MediaResource::VideoBatteryResource() {
-    return MediaResource(Type::kBattery, SubType::kVideoCodec, 1);
+MediaResource MediaResource::VideoBatteryResource(bool isHardware) {
+    SubType subType = isHardware ? SubType::kHwVideoCodec : SubType::kSwVideoCodec;
+    return MediaResource(Type::kBattery, subType, 1);
 }
 
 //static
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 3b69d4f..c88fee2 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -41,7 +41,7 @@
             int64_t instanceCount = 1);
     static MediaResource GraphicMemoryResource(int64_t value);
     static MediaResource CpuBoostResource();
-    static MediaResource VideoBatteryResource();
+    static MediaResource VideoBatteryResource(bool isHardware = true);
     static MediaResource DrmSessionResource(const std::vector<uint8_t> &id, int64_t value);
 };
 
@@ -61,10 +61,13 @@
 inline static const char *asString(MediaResource::SubType i, const char *def = "??") {
     switch (i) {
         case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
-        case MediaResource::SubType::kAudioCodec:         return "audio-codec";
-        case MediaResource::SubType::kVideoCodec:         return "video-codec";
-        case MediaResource::SubType::kImageCodec:         return "image-codec";
-        default:                                 return def;
+        case MediaResource::SubType::kHwAudioCodec:       return "hw-audio-codec";
+        case MediaResource::SubType::kSwAudioCodec:       return "sw-audio-codec";
+        case MediaResource::SubType::kHwVideoCodec:       return "hw-video-codec";
+        case MediaResource::SubType::kSwVideoCodec:       return "sw-video-codec";
+        case MediaResource::SubType::kHwImageCodec:       return "hw-image-codec";
+        case MediaResource::SubType::kSwImageCodec:       return "sw-image-codec";
+        default:                                          return def;
     }
 }
 
diff --git a/media/libmediametrics/MediaMetrics.cpp b/media/libmediametrics/MediaMetrics.cpp
index 2240223..26fe306 100644
--- a/media/libmediametrics/MediaMetrics.cpp
+++ b/media/libmediametrics/MediaMetrics.cpp
@@ -87,7 +87,7 @@
 }
 
 void mediametrics_setString(mediametrics_handle_t handle, attr_t attr,
-                                 const std::string &string) {
+                            const std::string &string) {
     mediametrics_setCString(handle, attr, string.c_str());
 }
 
diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
index 1cb4410..3abc35e 100644
--- a/media/libnbaio/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -55,8 +55,7 @@
     ret.mSampleRate = sampleRate;
     ret.mChannelCount = channelCount;
     ret.mFormat = format;
-    ret.mFrameSize = audio_is_linear_pcm(format) ?
-            channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t);
+    ret.mFrameSize = audio_bytes_per_frame(channelCount, format);
     return ret;
 }
 
diff --git a/media/libshmem/ShmemCompat.cpp b/media/libshmem/ShmemCompat.cpp
index 246cb24..4200c2e 100644
--- a/media/libshmem/ShmemCompat.cpp
+++ b/media/libshmem/ShmemCompat.cpp
@@ -84,11 +84,11 @@
             return false;
         }
 
-        const int fd = fcntl(heap->getHeapID(), F_DUPFD_CLOEXEC, 0);
-        if (fd < 0) {
+        base::unique_fd fd(fcntl(heap->getHeapID(), F_DUPFD_CLOEXEC, 0));
+        if (!fd.ok()) {
             return false;
         }
-        result->fd.reset(base::unique_fd(fd));
+        result->fd.reset(std::move(fd));
         result->size = size;
         result->offset = heap->getOffset() + offset;
         result->writeable = (heap->getFlags() & IMemoryHeap::READ_ONLY) == 0;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 1a32e61..db7db08 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -659,7 +659,7 @@
     msg->post();
 }
 
-status_t ACodec::setSurface(const sp<Surface> &surface) {
+status_t ACodec::setSurface(const sp<Surface> &surface, uint32_t /*generation*/) {
     sp<AMessage> msg = new AMessage(kWhatSetSurface, this);
     msg->setObject("surface", surface);
 
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index a26fcbe..0af9d12 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -270,10 +270,10 @@
         "SurfaceUtils.cpp",
         "ThrottledSource.cpp",
         "Utils.cpp",
-        "VideoRenderQualityTracker.cpp",
         "VideoFrameSchedulerBase.cpp",
         "VideoFrameScheduler.cpp",
-    ],
+        "VideoRenderQualityTracker.cpp",
+      ],
 
     shared_libs: [
         "libstagefright_framecapture_utils",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c048be5..829ee6b 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -245,7 +245,7 @@
         "android.media.mediacodec.judder-score-histogram-buckets";
 // Freeze event
 static const char *kCodecFreezeEventCount = "android.media.mediacodec.freeze-event-count";
-static const char *kFreezeEventKeyName = "freeze";
+static const char *kFreezeEventKeyName = "videofreeze";
 static const char *kFreezeEventInitialTimeUs = "android.media.mediacodec.freeze.initial-time-us";
 static const char *kFreezeEventDurationMs = "android.media.mediacodec.freeze.duration-ms";
 static const char *kFreezeEventCount = "android.media.mediacodec.freeze.count";
@@ -257,7 +257,7 @@
         "android.media.mediacodec.freeze.details-distance-ms";
 // Judder event
 static const char *kCodecJudderEventCount = "android.media.mediacodec.judder-event-count";
-static const char *kJudderEventKeyName = "judder";
+static const char *kJudderEventKeyName = "videojudder";
 static const char *kJudderEventInitialTimeUs = "android.media.mediacodec.judder.initial-time-us";
 static const char *kJudderEventDurationMs = "android.media.mediacodec.judder.duration-ms";
 static const char *kJudderEventCount = "android.media.mediacodec.judder.count";
@@ -824,6 +824,37 @@
     const sp<AMessage> mNotify;
 };
 
+class OnBufferReleasedListener : public ::android::BnProducerListener{
+private:
+    uint32_t mGeneration;
+    std::weak_ptr<BufferChannelBase> mBufferChannel;
+
+    void notifyBufferReleased() {
+        auto p = mBufferChannel.lock();
+        if (p) {
+            p->onBufferReleasedFromOutputSurface(mGeneration);
+        }
+    }
+
+public:
+    explicit OnBufferReleasedListener(
+            uint32_t generation,
+            const std::shared_ptr<BufferChannelBase> &bufferChannel)
+            : mGeneration(generation), mBufferChannel(bufferChannel) {}
+
+    virtual ~OnBufferReleasedListener() = default;
+
+    void onBufferReleased() override {
+        notifyBufferReleased();
+    }
+
+    void onBufferDetached([[maybe_unused]] int slot) override {
+        notifyBufferReleased();
+    }
+
+    bool needsReleaseNotify() override { return true; }
+};
+
 class BufferCallback : public CodecBase::BufferCallback {
 public:
     explicit BufferCallback(const sp<AMessage> &notify);
@@ -1019,12 +1050,19 @@
     notify->post();
 }
 
-static MediaResourceSubType toMediaResourceSubType(MediaCodec::Domain domain) {
+static MediaResourceSubType toMediaResourceSubType(bool isHardware, MediaCodec::Domain domain) {
     switch (domain) {
-        case MediaCodec::DOMAIN_VIDEO: return MediaResourceSubType::kVideoCodec;
-        case MediaCodec::DOMAIN_AUDIO: return MediaResourceSubType::kAudioCodec;
-        case MediaCodec::DOMAIN_IMAGE: return MediaResourceSubType::kImageCodec;
-        default:                       return MediaResourceSubType::kUnspecifiedSubType;
+    case MediaCodec::DOMAIN_VIDEO:
+        return isHardware? MediaResourceSubType::kHwVideoCodec :
+                           MediaResourceSubType::kSwVideoCodec;
+    case MediaCodec::DOMAIN_AUDIO:
+        return isHardware? MediaResourceSubType::kHwAudioCodec :
+                           MediaResourceSubType::kSwAudioCodec;
+    case MediaCodec::DOMAIN_IMAGE:
+        return isHardware? MediaResourceSubType::kHwImageCodec :
+                           MediaResourceSubType::kSwImageCodec;
+    default:
+        return MediaResourceSubType::kUnspecifiedSubType;
     }
 }
 
@@ -1794,7 +1832,7 @@
 
     if (mBatteryChecker != nullptr) {
         mBatteryChecker->onCodecActivity([this] () {
-            mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
+            mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource(mIsHardware));
         });
     }
 
@@ -1866,7 +1904,7 @@
 
     if (mBatteryChecker != nullptr) {
         mBatteryChecker->onCodecActivity([this] () {
-            mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
+            mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource(mIsHardware));
         });
     }
 
@@ -2121,13 +2159,16 @@
         mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
     }
 
-    std::vector<MediaResourceParcel> resources;
-    resources.push_back(MediaResource::CodecResource(secureCodec, toMediaResourceSubType(mDomain)));
-
     // If the ComponentName is not set yet, use the name passed by the user.
     if (mComponentName.empty()) {
+        mIsHardware = !MediaCodecList::isSoftwareCodec(name);
         mResourceManagerProxy->setCodecName(name.c_str());
     }
+
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(MediaResource::CodecResource(secureCodec,
+                                                     toMediaResourceSubType(mIsHardware, mDomain)));
+
     for (int i = 0; i <= kMaxRetry; ++i) {
         if (i > 0) {
             // Don't try to reclaim resource for the first time.
@@ -2371,7 +2412,7 @@
     status_t err;
     std::vector<MediaResourceParcel> resources;
     resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
-            toMediaResourceSubType(mDomain)));
+            toMediaResourceSubType(mIsHardware, mDomain)));
     if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
         // Don't know the buffer size at this point, but it's fine to use 1 because
         // the reclaimResource call doesn't consider the requester's buffer size for now.
@@ -2976,7 +3017,7 @@
     status_t err;
     std::vector<MediaResourceParcel> resources;
     resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
-            toMediaResourceSubType(mDomain)));
+            toMediaResourceSubType(mIsHardware, mDomain)));
     if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
         // Don't know the buffer size at this point, but it's fine to use 1 because
         // the reclaimResource call doesn't consider the requester's buffer size for now.
@@ -2994,12 +3035,6 @@
                 ALOGE("retrying start: failed to reset codec");
                 break;
             }
-            sp<AMessage> response;
-            err = PostAndAwaitResponse(mConfigureMsg, &response);
-            if (err != OK) {
-                ALOGE("retrying start: failed to configure codec");
-                break;
-            }
             if (callback != nullptr) {
                 err = setCallback(callback);
                 if (err != OK) {
@@ -3008,6 +3043,12 @@
                 }
                 ALOGD("succeed to set callback for reclaim");
             }
+            sp<AMessage> response;
+            err = PostAndAwaitResponse(mConfigureMsg, &response);
+            if (err != OK) {
+                ALOGE("retrying start: failed to configure codec");
+                break;
+            }
         }
 
         // Keep callback message after the first iteration if necessary.
@@ -3732,9 +3773,8 @@
 
 
 inline void MediaCodec::initClientConfigParcel(ClientConfigParcel& clientConfig) {
-    clientConfig.codecType = toMediaResourceSubType(mDomain);
+    clientConfig.codecType = toMediaResourceSubType(mIsHardware, mDomain);
     clientConfig.isEncoder = mFlags & kFlagIsEncoder;
-    clientConfig.isHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
     clientConfig.width = mWidth;
     clientConfig.height = mHeight;
     clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
@@ -3963,6 +4003,7 @@
                     CHECK(msg->findString("componentName", &mComponentName));
 
                     if (mComponentName.c_str()) {
+                        mIsHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
                         mediametrics_setCString(mMetricsHandle, kCodecCodec,
                                                 mComponentName.c_str());
                         // Update the codec name.
@@ -3990,7 +4031,7 @@
                                           MediaCodecList::isSoftwareCodec(mComponentName) ? 0 : 1);
 
                     mResourceManagerProxy->addResource(MediaResource::CodecResource(
-                            mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
+                            mFlags & kFlagIsSecure, toMediaResourceSubType(mIsHardware, mDomain)));
 
                     postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
                     break;
@@ -4674,6 +4715,8 @@
                     PostReplyWithError(replyID, err);
                     break;
                 }
+                uint32_t generation = mSurfaceGeneration;
+                format->setInt32("native-window-generation", generation);
             } else {
                 // we are not using surface so this variable is not used, but initialize sensibly anyway
                 mAllowFrameDroppingBySurface = false;
@@ -4802,7 +4845,8 @@
                         mErrorLog.log(LOG_TAG, "Unsetting surface is not supported");
                         err = BAD_VALUE;
                     } else {
-                        err = connectToSurface(surface);
+                        uint32_t generation;
+                        err = connectToSurface(surface, &generation);
                         if (err == ALREADY_EXISTS) {
                             // reconnecting to same surface
                             err = OK;
@@ -4817,12 +4861,13 @@
                                     mSoftRenderer = new SoftwareRenderer(surface);
                                     // TODO: check if this was successful
                                 } else {
-                                    err = mCodec->setSurface(surface);
+                                    err = mCodec->setSurface(surface, generation);
                                 }
                             }
                             if (err == OK) {
                                 (void)disconnectFromSurface();
                                 mSurface = surface;
+                                mSurfaceGeneration = generation;
                             }
                             mReliabilityContextMetrics.setOutputSurfaceCount++;
                         }
@@ -5060,15 +5105,17 @@
                     mReleaseSurface.reset(new ReleaseSurface(usage));
                 }
                 if (mSurface != mReleaseSurface->getSurface()) {
-                    status_t err = connectToSurface(mReleaseSurface->getSurface());
+                    uint32_t generation;
+                    status_t err = connectToSurface(mReleaseSurface->getSurface(), &generation);
                     ALOGW_IF(err != OK, "error connecting to release surface: err = %d", err);
                     if (err == OK && !(mFlags & kFlagUsesSoftwareRenderer)) {
-                        err = mCodec->setSurface(mReleaseSurface->getSurface());
+                        err = mCodec->setSurface(mReleaseSurface->getSurface(), generation);
                         ALOGW_IF(err != OK, "error setting release surface: err = %d", err);
                     }
                     if (err == OK) {
                         (void)disconnectFromSurface();
                         mSurface = mReleaseSurface->getSurface();
+                        mSurfaceGeneration = generation;
                     } else {
                         // We were not able to switch the surface, so force
                         // synchronous release.
@@ -5509,7 +5556,7 @@
             if (mBatteryChecker != nullptr) {
                 mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
                     mResourceManagerProxy->removeResource(
-                            MediaResource::VideoBatteryResource());
+                            MediaResource::VideoBatteryResource(mIsHardware));
                 });
             }
             break;
@@ -6338,7 +6385,7 @@
     return index;
 }
 
-status_t MediaCodec::connectToSurface(const sp<Surface> &surface) {
+status_t MediaCodec::connectToSurface(const sp<Surface> &surface, uint32_t *generation) {
     status_t err = OK;
     if (surface != NULL) {
         uint64_t oldId, newId;
@@ -6360,21 +6407,26 @@
             // number. Rely on the fact that max supported process id by Linux is 2^22.
             // PID is never 0 so we don't have to worry that we use the default generation of 0.
             // TODO: come up with a unique scheme if other producers also set the generation number.
-            static uint32_t mSurfaceGeneration = 0;
-            uint32_t generation = (getpid() << 10) | (++mSurfaceGeneration & ((1 << 10) - 1));
-            surface->setGenerationNumber(generation);
-            ALOGI("[%s] setting surface generation to %u", mComponentName.c_str(), generation);
+            static uint32_t sSurfaceGeneration = 0;
+            *generation = (getpid() << 10) | (++sSurfaceGeneration & ((1 << 10) - 1));
+            surface->setGenerationNumber(*generation);
+            ALOGI("[%s] setting surface generation to %u", mComponentName.c_str(), *generation);
 
             // HACK: clear any free buffers. Remove when connect will automatically do this.
             // This is needed as the consumer may be holding onto stale frames that it can reattach
             // to this surface after disconnect/connect, and those free frames would inherit the new
             // generation number. Disconnecting after setting a unique generation prevents this.
             nativeWindowDisconnect(surface.get(), "connectToSurface(reconnect)");
-            err = nativeWindowConnect(surface.get(), "connectToSurface(reconnect)");
+            sp<IProducerListener> listener =
+                    new OnBufferReleasedListener(*generation, mBufferChannel);
+            err = surfaceConnectWithListener(
+                    surface, listener, "connectToSurface(reconnect-with-listener)");
         }
 
         if (err != OK) {
-            ALOGE("nativeWindowConnect returned an error: %s (%d)", strerror(-err), err);
+            *generation = 0;
+            ALOGE("nativeWindowConnect/surfaceConnectWithListener returned an error: %s (%d)",
+                    strerror(-err), err);
         } else {
             if (!mAllowFrameDroppingBySurface) {
                 disableLegacyBufferDropPostQ(surface);
@@ -6400,6 +6452,7 @@
         }
         // assume disconnected even on error
         mSurface.clear();
+        mSurfaceGeneration = 0;
         mIsSurfaceToDisplay = false;
     }
     return err;
@@ -6411,9 +6464,11 @@
         (void)disconnectFromSurface();
     }
     if (surface != NULL) {
-        err = connectToSurface(surface);
+        uint32_t generation;
+        err = connectToSurface(surface, &generation);
         if (err == OK) {
             mSurface = surface;
+            mSurfaceGeneration = generation;
         }
     }
     return err;
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 291b892..f16e635 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -225,6 +225,13 @@
         return err;
     };
 
+    // We need to set sidebandStream to nullptr before pushing blank buffers
+    err = native_window_set_sideband_stream(nativeWindow, nullptr);
+    if (err != NO_ERROR) {
+        ALOGE("error setting sidebandStream to nullptr: %s (%d)", strerror(-err), -err);
+        return err;
+    }
+
     // We need to reconnect to the ANativeWindow as a CPU client to ensure that
     // no frames get dropped by SurfaceFlinger assuming that these are video
     // frames.
@@ -321,6 +328,16 @@
     return err;
 }
 
+status_t surfaceConnectWithListener(
+        const sp<Surface> &surface, sp<IProducerListener> listener, const char *reason) {
+    ALOGD("connecting to surface %p, reason %s", surface.get(), reason);
+
+    status_t err = surface->connect(NATIVE_WINDOW_API_MEDIA, listener);
+    ALOGE_IF(err != OK, "Failed to connect from surface %p, err %d", surface.get(), err);
+
+    return err;
+}
+
 status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason) {
     ALOGD("disconnecting from surface %p, reason %s", surface, reason);
 
diff --git a/media/libstagefright/httplive/fuzzer/Android.bp b/media/libstagefright/httplive/fuzzer/Android.bp
index dd49714..cb2f4ee 100644
--- a/media/libstagefright/httplive/fuzzer/Android.bp
+++ b/media/libstagefright/httplive/fuzzer/Android.bp
@@ -48,6 +48,7 @@
         "libstagefright_httplive_headers",
     ],
     shared_libs: [
+        "libbase",
         "libcrypto",
         "libstagefright_foundation",
         "libhidlbase",
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index a464504..946d533 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -72,8 +72,8 @@
     void setCrypto(const sp<ICrypto> &crypto) override;
     void setDescrambler(const sp<IDescrambler> &descrambler) override;
 
-    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
-    virtual status_t queueSecureInputBuffer(
+    status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    status_t queueSecureInputBuffer(
             const sp<MediaCodecBuffer> &buffer,
             bool secure,
             const uint8_t *key,
@@ -83,10 +83,10 @@
             const CryptoPlugin::SubSample *subSamples,
             size_t numSubSamples,
             AString *errorDetailMsg) override;
-    virtual status_t attachBuffer(
+    status_t attachBuffer(
             const std::shared_ptr<C2Buffer> &c2Buffer,
             const sp<MediaCodecBuffer> &buffer) override;
-    virtual status_t attachEncryptedBuffer(
+    status_t attachEncryptedBuffer(
             const sp<hardware::HidlMemory> &memory,
             bool secure,
             const uint8_t *key,
@@ -98,12 +98,12 @@
             size_t numSubSamples,
             const sp<MediaCodecBuffer> &buffer,
             AString* errorDetailMsg) override;
-    virtual status_t renderOutputBuffer(
+    status_t renderOutputBuffer(
             const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
-    virtual void pollForRenderedBuffers() override;
-    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
-    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
-    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    void pollForRenderedBuffers() override;
+    status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
 
     // Methods below are interface for ACodec to use.
 
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index ec4a04c..2a5c168 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -83,7 +83,7 @@
             const char* mime, bool isEncoder,
             MediaCodecInfo::CapabilitiesWriter* caps);
 
-    virtual status_t setSurface(const sp<Surface> &surface);
+    virtual status_t setSurface(const sp<Surface> &surface, uint32_t /*generation*/);
 
     virtual void signalFlush();
     virtual void signalResume();
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 6f06bc6..0927653 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -239,7 +239,9 @@
     // require an explicit message handler
     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
 
-    virtual status_t setSurface(const sp<Surface>& /*surface*/) { return INVALID_OPERATION; }
+    virtual status_t setSurface(const sp<Surface>& /*surface*/, uint32_t /*generation*/) {
+        return INVALID_OPERATION;
+    }
 
     virtual void signalFlush() = 0;
     virtual void signalResume() = 0;
@@ -424,6 +426,15 @@
     virtual void pollForRenderedBuffers() = 0;
 
     /**
+     * Notify a buffer is released from output surface.
+     *
+     * @param     generation    MediaCodec's surface specifier
+     */
+    virtual void onBufferReleasedFromOutputSurface(uint32_t /*generation*/) {
+        // default: no-op
+    };
+
+    /**
      * Discard a buffer to the underlying CodecBase object.
      *
      * TODO: remove once this operation can be handled by just clearing the
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index ceba7d7..f99a78b 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -449,6 +449,7 @@
     int64_t mPresentationTimeUs = 0;
     status_t mStickyError;
     sp<Surface> mSurface;
+    uint32_t mSurfaceGeneration = 0;
     SoftwareRenderer *mSoftRenderer;
 
     Mutex mMetricsLock;
@@ -617,7 +618,7 @@
     status_t queueCSDInputBuffer(size_t bufferIndex);
 
     status_t handleSetSurface(const sp<Surface> &surface);
-    status_t connectToSurface(const sp<Surface> &surface);
+    status_t connectToSurface(const sp<Surface> &surface, uint32_t *generation);
     status_t disconnectFromSurface();
 
     bool hasCryptoOrDescrambler() {
@@ -723,6 +724,7 @@
 
     // An unique ID for the codec - Used by the metrics.
     uint64_t mCodecId = 0;
+    bool     mIsHardware = false;
 
     std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
     std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
diff --git a/media/libstagefright/include/media/stagefright/MediaHistogram.h b/media/libstagefright/include/media/stagefright/MediaHistogram.h
index 50fa258..46ee288 100644
--- a/media/libstagefright/include/media/stagefright/MediaHistogram.h
+++ b/media/libstagefright/include/media/stagefright/MediaHistogram.h
@@ -29,11 +29,11 @@
 public:
     MediaHistogram();
     void clear();
-    bool setup(int bucketCount, T width, T floor = 0);
+    bool setup(size_t bucketCount, T width, T floor = 0);
     bool setup(const std::vector<T> &bucketLimits);
     void insert(T sample);
-    size_t size();
-    int64_t operator[](int);
+    size_t size() const;
+    int64_t operator[](int) const;
     T getMin() const { return mMin; }
     T getMax() const { return mMax; }
     T getCount() const { return mCount; }
@@ -45,7 +45,7 @@
 private:
     MediaHistogram(const MediaHistogram &); // disallow
 
-    bool allocate(int bucketCount, bool withBucketLimits);
+    void allocate(size_t bucketCount, bool withBucketLimits);
 
     T mFloor, mCeiling, mWidth;
     T mMin, mMax, mSum;
@@ -73,13 +73,12 @@
 }
 
 template<typename T>
-bool MediaHistogram<T>::setup(int bucketCount, T width, T floor) {
+bool MediaHistogram<T>::setup(size_t bucketCount, T width, T floor) {
     if (bucketCount <= 0 || width <= 0) {
         return false;
     }
-    if (!allocate(bucketCount, false)) {
-        return false;
-    }
+    allocate(bucketCount, false);
+
     mWidth = width;
     mFloor = floor;
     mCeiling = floor + bucketCount * width;
@@ -92,14 +91,14 @@
     if (bucketLimits.size() <= 1) {
         return false;
     }
-    int bucketCount = bucketLimits.size() - 1;
-    if (!allocate(bucketCount, true)) {
-        return false;
-    }
+    // The floor is the first bucket limit value, so offset by 1
+    size_t bucketCount = bucketLimits.size() - 1;
+    allocate(bucketCount, true);
 
     mWidth = -1;
     mFloor = bucketLimits[0];
-    for (int i = 0; i < bucketCount; ++i) {
+    for (size_t i = 0; i < bucketCount; ++i) {
+        // The floor is the first bucket, so offset by 1
         mBucketLimits[i] = bucketLimits[i + 1];
     }
     mCeiling = bucketLimits[bucketCount];
@@ -108,7 +107,7 @@
 }
 
 template<typename T>
-bool MediaHistogram<T>::allocate(int bucketCount, bool withBucketLimits) {
+void MediaHistogram<T>::allocate(size_t bucketCount, bool withBucketLimits) {
     assert(bucketCount > 0);
     if (bucketCount != mBuckets.size()) {
         mBuckets = std::vector<T>(bucketCount, 0);
@@ -116,7 +115,6 @@
     if (withBucketLimits && mBucketLimits.size() != bucketCount) {
         mBucketLimits = std::vector<T>(bucketCount, 0);
     }
-    return true;
 }
 
 template<typename T>
@@ -128,8 +126,8 @@
 
     mCount++;
     mSum += sample;
-    if (mMin > sample) mMin = sample;
-    if (mMax < sample) mMax = sample;
+    mMin = std::min(mMin, sample);
+    mMax = std::max(mMax, sample);
 
     if (sample < mFloor) {
         mBelow++;
@@ -138,7 +136,7 @@
     } else if (mWidth == -1) {
         // A binary search might be more efficient for large number of buckets, but it is expected
         // that there will never be a large amount of buckets, so keep the code simple.
-        for (int slot = 0; slot < mBucketLimits.size(); ++slot) {
+        for (size_t slot = 0; slot < mBucketLimits.size(); ++slot) {
             if (sample < mBucketLimits[slot]) {
                 mBuckets[slot]++;
                 break;
@@ -153,12 +151,12 @@
 }
 
 template<typename T>
-size_t MediaHistogram<T>::size() {
+size_t MediaHistogram<T>::size() const {
     return mBuckets.size() + 1;
 }
 
 template<typename T>
-int64_t MediaHistogram<T>::operator[](int i) {
+int64_t MediaHistogram<T>::operator[](int i) const {
     assert(i >= 0);
     assert(i <= mBuckets.size());
     if (i == mBuckets.size()) {
@@ -179,7 +177,7 @@
     } else {
         ss << mFloor << "," << mWidth << "," << mBelow << "{";
     }
-    for (int i = 0; i < mBuckets.size(); i++) {
+    for (size_t i = 0; i < mBuckets.size(); i++) {
         if (i != 0) {
             ss << ",";
         }
@@ -194,12 +192,12 @@
     std::stringstream ss("");
     if (mWidth == -1) {
         ss << mFloor;
-        for (int i = 0; i < mBucketLimits.size(); ++i) {
+        for (size_t i = 0; i < mBucketLimits.size(); ++i) {
             ss << ',' << mBucketLimits[i];
         }
     } else {
         ss << mFloor;
-        for (int i = 1; i <= mBuckets.size(); ++i) {
+        for (size_t i = 1; i <= mBuckets.size(); ++i) {
             ss << ',' << (mFloor + i * mWidth);
         }
     }
diff --git a/media/libstagefright/include/media/stagefright/SurfaceUtils.h b/media/libstagefright/include/media/stagefright/SurfaceUtils.h
index 35b3fa2..eccb413 100644
--- a/media/libstagefright/include/media/stagefright/SurfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceUtils.h
@@ -27,6 +27,7 @@
 namespace android {
 
 struct HDRStaticInfo;
+class IProducerListener;
 
 /**
  * Configures |nativeWindow| for given |width|x|height|, pixel |format|, |rotation| and |usage|.
@@ -43,6 +44,8 @@
 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */);
 status_t nativeWindowConnect(ANativeWindow *surface, const char *reason);
 status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason);
+status_t surfaceConnectWithListener(const sp<Surface> &surface,
+        sp<IProducerListener> listener, const char *reason);
 
 /**
  * Disable buffer dropping behavior of BufferQueue if target sdk of application
diff --git a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
index 3b70636..78140dd 100644
--- a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
+++ b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
@@ -298,7 +298,7 @@
     Configuration::GetServerConfigurableFlagFn getServerConfigurableFlagFn{
         [](const std::string &, const std::string &flag, const std::string &) -> std::string {
             if (flag == "render_metrics_enabled") {
-                return "false";
+                return "true";
             } else if (flag == "render_metrics_are_skipped_frames_dropped") {
                 return "false";
             } else if (flag == "render_metrics_max_expected_content_frame_duration_us") {
@@ -349,7 +349,7 @@
     // default - if we are accidentally configuring to the default then we're not necessarily
     // testing the parsing.
     Configuration d;
-    EXPECT_EQ(c.enabled, false);
+    EXPECT_EQ(c.enabled, true);
     EXPECT_NE(c.enabled, d.enabled);
     EXPECT_EQ(c.areSkippedFramesDropped, false);
     EXPECT_NE(c.areSkippedFramesDropped, d.areSkippedFramesDropped);
@@ -407,6 +407,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, countsReleasedFrames) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c);
     h.drop(10);
     h.render({16.66, 16.66, 16.66});
@@ -418,6 +419,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, countsSkippedFrames) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c);
     h.drop(10); // dropped frames are not counted
     h.skip(10); // frames skipped before rendering a frame are not counted
@@ -432,6 +434,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSkippedFramesAreDropped_countsDroppedFrames) {
     Configuration c;
+    c.enabled = true;
     c.areSkippedFramesDropped = true;
     Helper h(16.66, c);
     h.skip(10); // skipped frames at the beginning of playback are not counted
@@ -448,6 +451,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenNotSkippedFramesAreDropped_countsDroppedFrames) {
     Configuration c;
+    c.enabled = true;
     c.areSkippedFramesDropped = false;
     Helper h(16.66, c);
     h.skip(10); // skipped frames at the beginning of playback are not counted
@@ -464,6 +468,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, countsRenderedFrames) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c);
     h.drop(10); // dropped frames are not counted
     h.render({16.66, 16.66, 16.66});
@@ -475,6 +480,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, detectsFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -484,6 +490,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, handlesSeeking) {
     Configuration c;
+    c.enabled = true;
     c.maxExpectedContentFrameDurationUs = 30;
     VideoRenderQualityTracker v(c);
     v.onFrameReleased(0, 0);
@@ -522,6 +529,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, withSkipping_handlesSeeking) {
     Configuration c;
+    c.enabled = true;
     c.maxExpectedContentFrameDurationUs = 30;
     VideoRenderQualityTracker v(c);
     v.onFrameReleased(0, 0);
@@ -558,6 +566,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenLowTolerance_doesntDetectFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 0;
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -567,6 +576,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenFrameRateDestabilizes_detectsFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -577,6 +587,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, detects32Pulldown) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(41.66, c);
     h.render({49.9, 33.2, 50.0, 33.4, 50.1, 33.2});
@@ -586,6 +597,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBad32Pulldown_doesntDetect32Pulldown) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(41.66, c);
     h.render({50.0, 33.33, 33.33, 50.00, 33.33, 50.00});
@@ -595,6 +607,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenFrameRateChanges_detectsMostRecentFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.6, 16.7, 16.6, 16.7});
@@ -608,6 +621,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenFrameRateIsUnstable_doesntDetectFrameRate) {
     Configuration c;
+    c.enabled = true;
     c.frameRateDetectionToleranceUs = 2 * 1000; // 2 ms
     Helper h(16.66, c);
     h.render({16.66, 30.0, 16.66, 30.0, 16.66});
@@ -617,6 +631,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeRate) {
     Configuration c;
+    c.enabled = true;
     Helper h(20, c);
     h.render(3);
     EXPECT_EQ(h.getMetrics().freezeRate, 0);
@@ -629,6 +644,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeDurationHistogram) {
     Configuration c;
+    c.enabled = true;
     // +17 because freeze durations include the render time of the previous frame
     c.freezeDurationMsHistogramBuckets = {2 * 17 + 17, 3 * 17 + 17, 6 * 17 + 17};
     Helper h(17, c);
@@ -662,6 +678,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeDistanceHistogram) {
     Configuration c;
+    c.enabled = true;
     c.freezeDistanceMsHistogramBuckets = {1 * 17, 5 * 17, 6 * 17};
     Helper h(17, c);
     h.render(1);
@@ -693,6 +710,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when60hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c); // ~24Hz
     h.render({16.66, 16.66, 16.66, 16.66, 16.66, 16.66, 16.66});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -701,6 +719,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSmallVariance60hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c); // ~24Hz
     h.render({14, 18, 14, 18, 14, 18, 14, 18});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -709,6 +728,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBadSmallVariance60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(16.66, c); // ~24Hz
     h.render({14, 18, 14, /* no 18 between 14s */ 14, 18, 14, 18});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 1);
@@ -716,6 +736,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when30Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({33.33, 33.33, 33.33, 33.33, 33.33, 33.33});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -724,6 +745,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSmallVariance30Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({29.0, 35.0, 29.0, 35.0, 29.0, 35.0});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -732,6 +754,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBadSmallVariance30Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({29.0, 35.0, 29.0, /* no 35 between 29s */ 29.0, 35.0, 29.0, 35.0});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 1);
@@ -739,6 +762,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBad30HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({33.33, 33.33, 50.0, /* frame stayed 1 vsync too long */ 16.66, 33.33, 33.33});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 2); // note: 2 counts of judder
@@ -746,6 +770,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when24HzTo60Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(41.66, c);
     h.render({50.0, 33.33, 50.0, 33.33, 50.0, 33.33});
     EXPECT_LE(h.getMetrics().judderScoreHistogram.getMax(), 0);
@@ -754,6 +779,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when25HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(40, c);
     h.render({33.33, 33.33, 50.0});
     h.render({33.33, 33.33, 50.0});
@@ -766,6 +792,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when50HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(20, c);
     h.render({16.66, 16.66, 16.66, 33.33});
     h.render({16.66, 16.66, 16.66, 33.33});
@@ -778,6 +805,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, when30HzTo50Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(33.33, c);
     h.render({40.0, 40.0, 40.0, 60.0});
     h.render({40.0, 40.0, 40.0, 60.0});
@@ -789,6 +817,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenSmallVariancePulldown24HzTo60Hz_hasNoJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(41.66, c);
     h.render({52.0, 31.33, 52.0, 31.33, 52.0, 31.33});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 0);
@@ -796,6 +825,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, whenBad24HzTo60Hz_hasJudder) {
     Configuration c;
+    c.enabled = true;
     Helper h(41.66, c);
     h.render({50.0, 33.33, 50.0, 33.33, /* no 50 between 33s */ 33.33, 50.0, 33.33});
     EXPECT_EQ(h.getMetrics().judderScoreHistogram.getCount(), 1);
@@ -803,6 +833,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesJudderScoreHistogram) {
     Configuration c;
+    c.enabled = true;
     c.judderErrorToleranceUs = 2000;
     c.judderScoreHistogramBuckets = {1, 5, 8};
     Helper h(16, c);
@@ -817,6 +848,7 @@
 TEST_F(VideoRenderQualityTrackerTest, ranksJudderScoresInOrder) {
     // Each rendering is ranked from best to worst from a user experience
     Configuration c;
+    c.enabled = true;
     c.judderErrorToleranceUs = 2000;
     c.judderScoreHistogramBuckets = {0, 1000};
     int64_t previousScore = 0;
@@ -896,6 +928,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesFreezeEvents) {
     Configuration c;
+    c.enabled = true;
     c.freezeEventMax = 5;
     c.freezeEventDetailsMax = 4;
     c.freezeEventDistanceToleranceMs = 1000;
@@ -988,6 +1021,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesJudderEvents) {
     Configuration c;
+    c.enabled = true;
     c.judderEventMax = 4;
     c.judderEventDetailsMax = 3;
     c.judderEventDistanceToleranceMs = 100;
@@ -1038,6 +1072,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesOverallFreezeScore) {
     Configuration c;
+    c.enabled = true;
     // # drops * 20ms + 20ms because current frame is frozen + 1 for bucket threshold
     c.freezeDurationMsHistogramBuckets = {1 * 20 + 21, 5 * 20 + 21, 10 * 20 + 21};
     c.freezeDurationMsHistogramToScore = {10, 100, 1000};
@@ -1062,6 +1097,7 @@
 
 TEST_F(VideoRenderQualityTrackerTest, capturesOverallJudderScore) {
     Configuration c;
+    c.enabled = true;
     c.judderScoreHistogramBuckets = {0, 6, 10};
     c.judderScoreHistogramToScore = {10, 100, 1000};
     Helper h(20, c);
diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
index 71ddbe5..ed01e36 100644
--- a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
+++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
@@ -89,7 +89,8 @@
     MOCK_METHOD(void, initiateStart, (), (override));
     MOCK_METHOD(void, initiateShutdown, (bool keepComponentAllocated), (override));
     MOCK_METHOD(void, onMessageReceived, (const sp<AMessage> &msg), (override));
-    MOCK_METHOD(status_t, setSurface, (const sp<Surface> &surface), (override));
+    MOCK_METHOD(
+            status_t, setSurface, (const sp<Surface> &surface, uint32_t generation), (override));
     MOCK_METHOD(void, signalFlush, (), (override));
     MOCK_METHOD(void, signalResume, (), (override));
     MOCK_METHOD(void, signalRequestIDRFrame, (), (override));
diff --git a/media/mediaserver/manifest_media_c2_software.xml b/media/mediaserver/manifest_media_c2_software.xml
index a5b4896..d7fb1a0 100644
--- a/media/mediaserver/manifest_media_c2_software.xml
+++ b/media/mediaserver/manifest_media_c2_software.xml
@@ -8,4 +8,9 @@
             <instance>software</instance>
         </interface>
     </hal>
+    <hal format="aidl">
+        <name>android.hardware.media.c2</name>
+        <version>1</version>
+        <fqname>IComponentStore/software</fqname>
+    </hal>
 </manifest>
diff --git a/media/module/TEST_MAPPING b/media/module/TEST_MAPPING
new file mode 100644
index 0000000..c59df72
--- /dev/null
+++ b/media/module/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "postsubmit": [
+    {
+      "name": "hal_implementation_test"
+    }
+  ]
+}
+
diff --git a/media/module/codecserviceregistrant/Android.bp b/media/module/codecserviceregistrant/Android.bp
index 9ee81a4..becb98a 100644
--- a/media/module/codecserviceregistrant/Android.bp
+++ b/media/module/codecserviceregistrant/Android.bp
@@ -64,6 +64,7 @@
     ],
 
     defaults: [
+        "libcodec2-aidl-defaults",
         "libcodec2-hidl-defaults",
         "libcodec2-runtime-libs",
     ],
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 1de9efe..65d537b 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -20,15 +20,25 @@
 #include <android/api-level.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 
 #include <C2Component.h>
 #include <C2PlatformSupport.h>
+
 #include <codec2/hidl/1.0/ComponentStore.h>
 #include <codec2/hidl/1.1/ComponentStore.h>
 #include <codec2/hidl/1.2/ComponentStore.h>
 #include <codec2/hidl/1.2/Configurable.h>
 #include <codec2/hidl/1.2/types.h>
 #include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <codec2/aidl/ComponentStore.h>
+#include <codec2/aidl/ParamTypes.h>
+
 #include <media/CodecServiceRegistrant.h>
 
 namespace /* unnamed */ {
@@ -36,59 +46,142 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::hidl_string;
 using ::android::hardware::Return;
-using ::android::hardware::Void;
 using ::android::sp;
-using namespace ::android::hardware::media::c2::V1_2;
-using namespace ::android::hardware::media::c2::V1_2::utils;
+using ::ndk::ScopedAStatus;
+namespace c2_hidl = ::android::hardware::media::c2::V1_2;
+namespace c2_aidl = ::aidl::android::hardware::media::c2;
 
 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
 
 // Converter from IComponentStore to C2ComponentStore.
 class H2C2ComponentStore : public C2ComponentStore {
 protected:
-    using IComponentStore =
+    using HidlComponentStore =
         ::android::hardware::media::c2::V1_0::IComponentStore;
-    using IConfigurable =
+    using HidlConfigurable =
         ::android::hardware::media::c2::V1_0::IConfigurable;
-    sp<IComponentStore> mStore;
-    sp<IConfigurable> mConfigurable;
+    sp<HidlComponentStore> mHidlStore;
+    sp<HidlConfigurable> mHidlConfigurable;
+
+    using AidlComponentStore =
+        ::aidl::android::hardware::media::c2::IComponentStore;
+    using AidlConfigurable =
+        ::aidl::android::hardware::media::c2::IConfigurable;
+    std::shared_ptr<AidlComponentStore> mAidlStore;
+    std::shared_ptr<AidlConfigurable> mAidlConfigurable;
 public:
-    explicit H2C2ComponentStore(sp<IComponentStore> const& store)
-          : mStore{store},
-            mConfigurable{[store]() -> sp<IConfigurable>{
+    explicit H2C2ComponentStore(nullptr_t) {
+    }
+
+    explicit H2C2ComponentStore(sp<HidlComponentStore> const& store)
+          : mHidlStore{store},
+            mHidlConfigurable{[store]() -> sp<HidlConfigurable>{
                 if (!store) {
                     return nullptr;
                 }
-                Return<sp<IConfigurable>> transResult =
+                Return<sp<HidlConfigurable>> transResult =
                     store->getConfigurable();
                 return transResult.isOk() ?
-                        static_cast<sp<IConfigurable>>(transResult) :
+                        static_cast<sp<HidlConfigurable>>(transResult) :
                         nullptr;
             }()} {
-        if (!mConfigurable) {
+        if (!mHidlConfigurable) {
+            LOG(ERROR) << "Preferred store is corrupted.";
+        }
+    }
+
+    explicit H2C2ComponentStore(std::shared_ptr<AidlComponentStore> const& store)
+          : mAidlStore{store},
+            mAidlConfigurable{[store]() -> std::shared_ptr<AidlConfigurable>{
+                if (!store) {
+                    return nullptr;
+                }
+                std::shared_ptr<AidlConfigurable> configurable;
+                ScopedAStatus status = store->getConfigurable(&configurable);
+                if (!status.isOk()) {
+                    return nullptr;
+                }
+                return configurable;
+            }()} {
+        if (!mAidlConfigurable) {
             LOG(ERROR) << "Preferred store is corrupted.";
         }
     }
 
     virtual ~H2C2ComponentStore() override = default;
 
-    virtual c2_status_t config_sm(
+    c2_status_t config_sm(
             std::vector<C2Param*> const &params,
             std::vector<std::unique_ptr<C2SettingResult>>* const failures
             ) override {
-        Params hidlParams;
-        if (!createParamsBlob(&hidlParams, params)) {
+        if (mAidlStore) {
+            return config_sm_aidl(params, failures);
+        } else if (mHidlStore) {
+            return config_sm_hidl(params, failures);
+        } else {
+            return C2_OMITTED;
+        }
+    }
+
+    c2_status_t config_sm_aidl(
+            std::vector<C2Param*> const &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) {
+        c2_aidl::Params aidlParams;
+        if (!c2_aidl::utils::CreateParamsBlob(&aidlParams, params)) {
+            LOG(ERROR) << "config -- bad input.";
+            return C2_TRANSACTION_FAILED;
+        }
+        c2_status_t status = C2_OK;
+        c2_aidl::IConfigurable::ConfigResult configResult;
+        ScopedAStatus transResult = mAidlConfigurable->config(
+                aidlParams, true, &configResult);
+        if (!transResult.isOk()) {
+            if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                status = c2_status_t(transResult.getServiceSpecificError());
+                if (status != C2_BAD_INDEX) {
+                    LOG(DEBUG) << "config -- call failed: "
+                               << status << ".";
+                }
+            } else {
+                LOG(ERROR) << "config -- transaction failed.";
+                return C2_TRANSACTION_FAILED;
+            }
+        }
+        size_t i = failures->size();
+        failures->resize(i + configResult.failures.size());
+        for (const c2_aidl::SettingResult& sf : configResult.failures) {
+            if (!c2_aidl::utils::FromAidl(&(*failures)[i++], sf)) {
+                LOG(ERROR) << "config -- "
+                           << "invalid SettingResult returned.";
+                status = C2_CORRUPTED;
+            }
+        }
+        if (!c2_aidl::utils::UpdateParamsFromBlob(params, configResult.params)) {
+            LOG(ERROR) << "config -- "
+                       << "failed to parse returned params.";
+            status = C2_CORRUPTED;
+        }
+        return status;
+    };
+
+    c2_status_t config_sm_hidl(
+            std::vector<C2Param*> const &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) {
+        c2_hidl::Params hidlParams;
+        if (!c2_hidl::utils::createParamsBlob(&hidlParams, params)) {
             LOG(ERROR) << "config -- bad input.";
             return C2_TRANSACTION_FAILED;
         }
         c2_status_t status{};
-        Return<void> transResult = mConfigurable->config(
+        Return<void> transResult = mHidlConfigurable->config(
                 hidlParams,
                 true,
                 [&status, &params, failures](
-                        Status s,
-                        const hidl_vec<SettingResult> f,
-                        const Params& o) {
+                        c2_hidl::Status s,
+                        const hidl_vec<c2_hidl::SettingResult> f,
+                        const c2_hidl::Params& o) {
                     status = static_cast<c2_status_t>(s);
                     if (status != C2_OK && status != C2_BAD_INDEX) {
                         LOG(DEBUG) << "config -- call failed: "
@@ -96,14 +189,14 @@
                     }
                     size_t i = failures->size();
                     failures->resize(i + f.size());
-                    for (const SettingResult& sf : f) {
-                        if (!objcpy(&(*failures)[i++], sf)) {
+                    for (const c2_hidl::SettingResult& sf : f) {
+                        if (!c2_hidl::utils::objcpy(&(*failures)[i++], sf)) {
                             LOG(ERROR) << "config -- "
                                        << "invalid SettingResult returned.";
                             return;
                         }
                     }
-                    if (!updateParamsFromBlob(params, o)) {
+                    if (!c2_hidl::utils::updateParamsFromBlob(params, o)) {
                         LOG(ERROR) << "config -- "
                                    << "failed to parse returned params.";
                         status = C2_CORRUPTED;
@@ -116,33 +209,142 @@
         return status;
     };
 
-    virtual c2_status_t copyBuffer(
+    c2_status_t copyBuffer(
             std::shared_ptr<C2GraphicBuffer>,
             std::shared_ptr<C2GraphicBuffer>) override {
         LOG(ERROR) << "copyBuffer -- not supported.";
         return C2_OMITTED;
     }
 
-    virtual c2_status_t createComponent(
+    c2_status_t createComponent(
             C2String, std::shared_ptr<C2Component> *const component) override {
         component->reset();
         LOG(ERROR) << "createComponent -- not supported.";
         return C2_OMITTED;
     }
 
-    virtual c2_status_t createInterface(
-            C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
+    c2_status_t createInterface(
+            C2String, std::shared_ptr<C2ComponentInterface> *const interface) override {
         interface->reset();
         LOG(ERROR) << "createInterface -- not supported.";
         return C2_OMITTED;
     }
 
-    virtual c2_status_t query_sm(
+    c2_status_t query_sm(
             const std::vector<C2Param *> &stackParams,
             const std::vector<C2Param::Index> &heapParamIndices,
-            std::vector<std::unique_ptr<C2Param>> *const heapParams) const
-            override {
-        hidl_vec<ParamIndex> indices(
+            std::vector<std::unique_ptr<C2Param>> *const heapParams) const override {
+        if (mAidlStore) {
+            return query_sm_aidl(stackParams, heapParamIndices, heapParams);
+        } else if (mHidlStore) {
+            return query_sm_hidl(stackParams, heapParamIndices, heapParams);
+        } else {
+            return C2_OMITTED;
+        }
+    }
+
+    static c2_status_t UpdateQueryResult(
+            const std::vector<C2Param *> &paramPointers,
+            size_t numStackIndices,
+            const std::vector<C2Param *> &stackParams,
+            std::vector<std::unique_ptr<C2Param>> *const heapParams) {
+        c2_status_t status = C2_OK;
+        size_t i = 0;
+        for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
+            C2Param* paramPointer = *it;
+            if (numStackIndices > 0) {
+                --numStackIndices;
+                if (!paramPointer) {
+                    LOG(WARNING) << "query -- null stack param.";
+                    ++it;
+                    continue;
+                }
+                for (; i < stackParams.size() && !stackParams[i]; ) {
+                    ++i;
+                }
+                if (i >= stackParams.size()) {
+                    LOG(ERROR) << "query -- unexpected error.";
+                    status = C2_CORRUPTED;
+                    break;
+                }
+                if (stackParams[i]->index() != paramPointer->index()) {
+                    LOG(WARNING) << "query -- param skipped: "
+                                    "index = "
+                                 << stackParams[i]->index() << ".";
+                    stackParams[i++]->invalidate();
+                    continue;
+                }
+                if (!stackParams[i++]->updateFrom(*paramPointer)) {
+                    LOG(WARNING) << "query -- param update failed: "
+                                    "index = "
+                                 << paramPointer->index() << ".";
+                }
+            } else {
+                if (!paramPointer) {
+                    LOG(WARNING) << "query -- null heap param.";
+                    ++it;
+                    continue;
+                }
+                if (!heapParams) {
+                    LOG(WARNING) << "query -- "
+                                    "unexpected extra stack param.";
+                } else {
+                    heapParams->emplace_back(
+                            C2Param::Copy(*paramPointer));
+                }
+            }
+            ++it;
+        }
+        return status;
+    }
+
+    c2_status_t query_sm_aidl(
+            const std::vector<C2Param *> &stackParams,
+            const std::vector<C2Param::Index> &heapParamIndices,
+            std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
+        std::vector<int32_t> indices;
+        size_t numIndices = 0;
+        for (C2Param* const& stackParam : stackParams) {
+            if (!stackParam) {
+                LOG(WARNING) << "query -- null stack param encountered.";
+                continue;
+            }
+            indices[numIndices++] = stackParam->index();
+        }
+        size_t numStackIndices = numIndices;
+        for (const C2Param::Index& index : heapParamIndices) {
+            indices[numIndices++] = static_cast<uint32_t>(index);
+        }
+        indices.resize(numIndices);
+        if (heapParams) {
+            heapParams->reserve(heapParams->size() + numIndices);
+        }
+        c2_status_t status = C2_OK;
+        c2_aidl::Params aidlParams;
+        ScopedAStatus transResult = mAidlConfigurable->query(indices, true, &aidlParams);
+        if (!transResult.isOk()) {
+            if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                status = c2_status_t(transResult.getServiceSpecificError());
+                LOG(DEBUG) << "query -- call failed: " << status << ".";
+                return status;
+            } else {
+                LOG(ERROR) << "query -- transaction failed.";
+                return C2_TRANSACTION_FAILED;
+            }
+        }
+        std::vector<C2Param*> paramPointers;
+        if (!c2_aidl::utils::ParseParamsBlob(&paramPointers, aidlParams)) {
+            LOG(ERROR) << "query -- error while parsing params.";
+            return C2_CORRUPTED;
+        }
+        return UpdateQueryResult(paramPointers, numStackIndices, stackParams, heapParams);
+    }
+
+    c2_status_t query_sm_hidl(
+            const std::vector<C2Param *> &stackParams,
+            const std::vector<C2Param::Index> &heapParamIndices,
+            std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
+        hidl_vec<c2_hidl::ParamIndex> indices(
                 stackParams.size() + heapParamIndices.size());
         size_t numIndices = 0;
         for (C2Param* const& stackParam : stackParams) {
@@ -150,23 +352,23 @@
                 LOG(WARNING) << "query -- null stack param encountered.";
                 continue;
             }
-            indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
+            indices[numIndices++] = static_cast<c2_hidl::ParamIndex>(stackParam->index());
         }
         size_t numStackIndices = numIndices;
         for (const C2Param::Index& index : heapParamIndices) {
             indices[numIndices++] =
-                    static_cast<ParamIndex>(static_cast<uint32_t>(index));
+                    static_cast<c2_hidl::ParamIndex>(static_cast<uint32_t>(index));
         }
         indices.resize(numIndices);
         if (heapParams) {
             heapParams->reserve(heapParams->size() + numIndices);
         }
         c2_status_t status;
-        Return<void> transResult = mConfigurable->query(
+        Return<void> transResult = mHidlConfigurable->query(
                 indices,
                 true,
                 [&status, &numStackIndices, &stackParams, heapParams](
-                        Status s, const Params& p) {
+                        c2_hidl::Status s, const c2_hidl::Params& p) {
                     status = static_cast<c2_status_t>(s);
                     if (status != C2_OK && status != C2_BAD_INDEX) {
                         LOG(DEBUG) << "query -- call failed: "
@@ -174,58 +376,13 @@
                         return;
                     }
                     std::vector<C2Param*> paramPointers;
-                    if (!parseParamsBlob(&paramPointers, p)) {
+                    if (!c2_hidl::utils::parseParamsBlob(&paramPointers, p)) {
                         LOG(ERROR) << "query -- error while parsing params.";
                         status = C2_CORRUPTED;
                         return;
                     }
-                    size_t i = 0;
-                    for (auto it = paramPointers.begin();
-                            it != paramPointers.end(); ) {
-                        C2Param* paramPointer = *it;
-                        if (numStackIndices > 0) {
-                            --numStackIndices;
-                            if (!paramPointer) {
-                                LOG(WARNING) << "query -- null stack param.";
-                                ++it;
-                                continue;
-                            }
-                            for (; i < stackParams.size() && !stackParams[i]; ) {
-                                ++i;
-                            }
-                            if (i >= stackParams.size()) {
-                                LOG(ERROR) << "query -- unexpected error.";
-                                status = C2_CORRUPTED;
-                                return;
-                            }
-                            if (stackParams[i]->index() != paramPointer->index()) {
-                                LOG(WARNING) << "query -- param skipped: "
-                                                "index = "
-                                             << stackParams[i]->index() << ".";
-                                stackParams[i++]->invalidate();
-                                continue;
-                            }
-                            if (!stackParams[i++]->updateFrom(*paramPointer)) {
-                                LOG(WARNING) << "query -- param update failed: "
-                                                "index = "
-                                             << paramPointer->index() << ".";
-                            }
-                        } else {
-                            if (!paramPointer) {
-                                LOG(WARNING) << "query -- null heap param.";
-                                ++it;
-                                continue;
-                            }
-                            if (!heapParams) {
-                                LOG(WARNING) << "query -- "
-                                                "unexpected extra stack param.";
-                            } else {
-                                heapParams->emplace_back(
-                                        C2Param::Copy(*paramPointer));
-                            }
-                        }
-                        ++it;
-                    }
+                    status = UpdateQueryResult(
+                            paramPointers, numStackIndices, stackParams, heapParams);
                 });
         if (!transResult.isOk()) {
             LOG(ERROR) << "query -- transaction failed.";
@@ -234,15 +391,58 @@
         return status;
     }
 
-    virtual c2_status_t querySupportedParams_nb(
+    c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override {
+        if (mAidlStore) {
+            return querySupportedParams_nb_aidl(params);
+        } else if (mHidlStore) {
+            return querySupportedParams_nb_hidl(params);
+        } else {
+            return C2_OMITTED;
+        }
+    }
+
+    c2_status_t querySupportedParams_nb_aidl(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+        c2_status_t status = C2_OK;
+        std::vector<c2_aidl::ParamDescriptor> aidlParams;
+        ScopedAStatus transResult = mAidlConfigurable->querySupportedParams(
+                std::numeric_limits<uint32_t>::min(),
+                std::numeric_limits<uint32_t>::max(),
+                &aidlParams);
+        if (!transResult.isOk()) {
+            if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                status = c2_status_t(transResult.getServiceSpecificError());
+                LOG(DEBUG) << "querySupportedParams -- call failed: "
+                           << status << ".";
+                return status;
+            } else {
+                LOG(ERROR) << "querySupportedParams -- transaction failed.";
+                return C2_TRANSACTION_FAILED;
+            }
+        }
+
+        size_t i = params->size();
+        params->resize(i + aidlParams.size());
+        for (const c2_aidl::ParamDescriptor& sp : aidlParams) {
+            if (!c2_aidl::utils::FromAidl(&(*params)[i++], sp)) {
+                LOG(ERROR) << "querySupportedParams -- "
+                           << "invalid returned ParamDescriptor.";
+                break;
+            }
+        }
+        return status;
+    }
+
+    c2_status_t querySupportedParams_nb_hidl(
             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
         c2_status_t status;
-        Return<void> transResult = mConfigurable->querySupportedParams(
+        Return<void> transResult = mHidlConfigurable->querySupportedParams(
                 std::numeric_limits<uint32_t>::min(),
                 std::numeric_limits<uint32_t>::max(),
                 [&status, params](
-                        Status s,
-                        const hidl_vec<ParamDescriptor>& p) {
+                        c2_hidl::Status s,
+                        const hidl_vec<c2_hidl::ParamDescriptor>& p) {
                     status = static_cast<c2_status_t>(s);
                     if (status != C2_OK) {
                         LOG(DEBUG) << "querySupportedParams -- call failed: "
@@ -251,8 +451,8 @@
                     }
                     size_t i = params->size();
                     params->resize(i + p.size());
-                    for (const ParamDescriptor& sp : p) {
-                        if (!objcpy(&(*params)[i++], sp)) {
+                    for (const c2_hidl::ParamDescriptor& sp : p) {
+                        if (!c2_hidl::utils::objcpy(&(*params)[i++], sp)) {
                             LOG(ERROR) << "querySupportedParams -- "
                                        << "invalid returned ParamDescriptor.";
                             return;
@@ -266,23 +466,75 @@
         return status;
     }
 
-    virtual c2_status_t querySupportedValues_sm(
+    c2_status_t querySupportedValues_sm(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const override {
+        if (mAidlStore) {
+            return querySupportedValues_sm_aidl(fields);
+        } else if (mHidlStore) {
+            return querySupportedValues_sm_hidl(fields);
+        } else {
+            return C2_OMITTED;
+        }
+    }
+
+    c2_status_t querySupportedValues_sm_aidl(
             std::vector<C2FieldSupportedValuesQuery> &fields) const {
-        hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
+        std::vector<c2_aidl::FieldSupportedValuesQuery> aidlFields(fields.size());
         for (size_t i = 0; i < fields.size(); ++i) {
-            if (!objcpy(&inFields[i], fields[i])) {
+            if (!c2_aidl::utils::ToAidl(&aidlFields[i], fields[i])) {
+                LOG(ERROR) << "querySupportedValues -- bad input";
+                return C2_TRANSACTION_FAILED;
+            }
+        }
+
+        c2_status_t status = C2_OK;
+        std::vector<c2_aidl::FieldSupportedValuesQueryResult> queryResults;
+        ScopedAStatus transResult = mAidlConfigurable->querySupportedValues(
+                aidlFields, true, &queryResults);
+        if (!transResult.isOk()) {
+            if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                status = c2_status_t(transResult.getServiceSpecificError());
+                LOG(DEBUG) << "querySupportedValues -- call failed: "
+                           << status << ".";
+                return status;
+            } else {
+                LOG(ERROR) << "querySupportedValues -- transaction failed.";
+                return C2_TRANSACTION_FAILED;
+            }
+        }
+        if (queryResults.size() != fields.size()) {
+            LOG(ERROR) << "querySupportedValues -- "
+                          "input and output lists "
+                          "have different sizes.";
+            return C2_CORRUPTED;
+        }
+        for (size_t i = 0; i < fields.size(); ++i) {
+            if (!c2_aidl::utils::FromAidl(&fields[i], aidlFields[i], queryResults[i])) {
+                LOG(ERROR) << "querySupportedValues -- "
+                              "invalid returned value.";
+                return C2_CORRUPTED;
+            }
+        }
+        return status;
+    }
+
+    c2_status_t querySupportedValues_sm_hidl(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const {
+        hidl_vec<c2_hidl::FieldSupportedValuesQuery> inFields(fields.size());
+        for (size_t i = 0; i < fields.size(); ++i) {
+            if (!c2_hidl::utils::objcpy(&inFields[i], fields[i])) {
                 LOG(ERROR) << "querySupportedValues -- bad input";
                 return C2_TRANSACTION_FAILED;
             }
         }
 
         c2_status_t status;
-        Return<void> transResult = mConfigurable->querySupportedValues(
+        Return<void> transResult = mHidlConfigurable->querySupportedValues(
                 inFields,
                 true,
                 [&status, &inFields, &fields](
-                        Status s,
-                        const hidl_vec<FieldSupportedValuesQueryResult>& r) {
+                        c2_hidl::Status s,
+                        const hidl_vec<c2_hidl::FieldSupportedValuesQueryResult>& r) {
                     status = static_cast<c2_status_t>(s);
                     if (status != C2_OK) {
                         LOG(DEBUG) << "querySupportedValues -- call failed: "
@@ -297,7 +549,7 @@
                         return;
                     }
                     for (size_t i = 0; i < fields.size(); ++i) {
-                        if (!objcpy(&fields[i], inFields[i], r[i])) {
+                        if (!c2_hidl::utils::objcpy(&fields[i], inFields[i], r[i])) {
                             LOG(ERROR) << "querySupportedValues -- "
                                           "invalid returned value.";
                             status = C2_CORRUPTED;
@@ -312,31 +564,83 @@
         return status;
     }
 
-    virtual C2String getName() const {
-        C2String outName;
-        Return<void> transResult = mConfigurable->getName(
-                [&outName](const hidl_string& name) {
-                    outName = name.c_str();
-                });
-        if (!transResult.isOk()) {
-            LOG(ERROR) << "getName -- transaction failed.";
+    C2String getName() const override {
+        C2String outName = "(unknown)";
+        if (mAidlStore) {
+            ScopedAStatus transResult = mAidlConfigurable->getName(&outName);
+            if (!transResult.isOk()) {
+                LOG(ERROR) << "getName -- transaction failed.";
+            }
+        } else if (mHidlStore) {
+            Return<void> transResult = mHidlConfigurable->getName(
+                    [&outName](const hidl_string& name) {
+                        outName = name.c_str();
+                    });
+            if (!transResult.isOk()) {
+                LOG(ERROR) << "getName -- transaction failed.";
+            }
         }
         return outName;
     }
 
-    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const
-            override {
+    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override {
         struct SimpleParamReflector : public C2ParamReflector {
-            virtual std::unique_ptr<C2StructDescriptor> describe(
+            std::unique_ptr<C2StructDescriptor> describe(
+                    C2Param::CoreIndex coreIndex) const override {
+                if (mAidlBase) {
+                    return describe_aidl(coreIndex);
+                } else if (mHidlBase) {
+                    return describe_hidl(coreIndex);
+                } else {
+                    return nullptr;
+                }
+            }
+
+            std::unique_ptr<C2StructDescriptor> describe_aidl(
                     C2Param::CoreIndex coreIndex) const {
-                hidl_vec<ParamIndex> indices(1);
-                indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
+                std::vector<int32_t> indices(1);
+                indices[0] = coreIndex.coreIndex();
                 std::unique_ptr<C2StructDescriptor> descriptor;
-                Return<void> transResult = mBase->getStructDescriptors(
+                std::vector<c2_aidl::StructDescriptor> aidlDescs;
+                ScopedAStatus transResult = mAidlBase->getStructDescriptors(
+                        indices, &aidlDescs);
+                if (!transResult.isOk()) {
+                    c2_status_t status = C2_TRANSACTION_FAILED;
+                    if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                        status = c2_status_t(transResult.getServiceSpecificError());
+                        LOG(DEBUG) << "SimpleParamReflector -- "
+                                      "getStructDescriptors() failed: "
+                                   << status << ".";
+                        return nullptr;
+                    }
+                }
+                if (aidlDescs.size() != 1) {
+                    LOG(DEBUG) << "SimpleParamReflector -- "
+                                  "getStructDescriptors() "
+                                  "returned vector of size "
+                               << aidlDescs.size() << ". "
+                                  "It should be 1.";
+                    return nullptr;
+                }
+                if (!c2_aidl::utils::FromAidl(&descriptor, aidlDescs[0])) {
+                    LOG(DEBUG) << "SimpleParamReflector -- "
+                                  "getStructDescriptors() returned "
+                                  "corrupted data.";
+                    return nullptr;
+                }
+                return descriptor;
+            }
+
+            std::unique_ptr<C2StructDescriptor> describe_hidl(
+                    C2Param::CoreIndex coreIndex) const {
+                hidl_vec<c2_hidl::ParamIndex> indices(1);
+                indices[0] = static_cast<c2_hidl::ParamIndex>(coreIndex.coreIndex());
+                std::unique_ptr<C2StructDescriptor> descriptor;
+                Return<void> transResult = mHidlBase->getStructDescriptors(
                         indices,
                         [&descriptor](
-                                Status s,
-                                const hidl_vec<StructDescriptor>& sd) {
+                                c2_hidl::Status s,
+                                const hidl_vec<c2_hidl::StructDescriptor>& sd) {
                             c2_status_t status = static_cast<c2_status_t>(s);
                             if (status != C2_OK) {
                                 LOG(DEBUG) << "SimpleParamReflector -- "
@@ -354,7 +658,7 @@
                                 descriptor.reset();
                                 return;
                             }
-                            if (!objcpy(&descriptor, sd[0])) {
+                            if (!c2_hidl::utils::objcpy(&descriptor, sd[0])) {
                                 LOG(DEBUG) << "SimpleParamReflector -- "
                                               "getStructDescriptors() returned "
                                               "corrupted data.";
@@ -365,13 +669,23 @@
                 return descriptor;
             }
 
-            explicit SimpleParamReflector(sp<IComponentStore> base)
-                : mBase(base) { }
+            explicit SimpleParamReflector(const sp<HidlComponentStore> &base)
+                : mHidlBase(base) { }
 
-            sp<IComponentStore> mBase;
+            explicit SimpleParamReflector(const std::shared_ptr<AidlComponentStore> &base)
+                : mAidlBase(base) { }
+
+            std::shared_ptr<AidlComponentStore> mAidlBase;
+            sp<HidlComponentStore> mHidlBase;
         };
 
-        return std::make_shared<SimpleParamReflector>(mStore);
+        if (mAidlStore) {
+            return std::make_shared<SimpleParamReflector>(mAidlStore);
+        } else if (mHidlStore) {
+            return std::make_shared<SimpleParamReflector>(mHidlStore);
+        } else {
+            return nullptr;
+        }
     }
 
     virtual std::vector<std::shared_ptr<const C2Component::Traits>>
@@ -406,6 +720,12 @@
 } // unnamed namespace
 
 extern "C" void RegisterCodecServices() {
+    const bool aidlSelected = c2_aidl::utils::IsSelected();
+    constexpr int kThreadCount = 64;
+    ABinderProcess_setThreadPoolMaxThreadCount(kThreadCount);
+    ABinderProcess_startThreadPool();
+    ::android::hardware::configureRpcThreadpool(kThreadCount, false);
+
     LOG(INFO) << "Creating software Codec2 service...";
     std::shared_ptr<C2ComponentStore> store =
         android::GetCodec2PlatformComponentStore();
@@ -417,28 +737,27 @@
     using namespace ::android::hardware::media::c2;
 
     int platformVersion = android_get_device_api_level();
+    // STOPSHIP: Remove code name checking once platform version bumps up to 35.
+    std::string codeName =
+        android::base::GetProperty("ro.build.version.codename", "");
+    if (codeName == "VanillaIceCream") {
+        platformVersion = __ANDROID_API_V__;
+    }
 
-    if (platformVersion >= __ANDROID_API_S__) {
-        android::sp<V1_2::IComponentStore> storeV1_2 =
-            new V1_2::utils::ComponentStore(store);
-        if (storeV1_2->registerAsService("software") != android::OK) {
-            LOG(ERROR) << "Cannot register software Codec2 v1.2 service.";
-            return;
-        }
+    android::sp<V1_0::IComponentStore> hidlStore;
+    std::shared_ptr<c2_aidl::IComponentStore> aidlStore;
+    const char *hidlVer = "(unknown)";
+    if (aidlSelected) {
+        aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(store);
+    } else if (platformVersion >= __ANDROID_API_S__) {
+        hidlStore = ::android::sp<V1_2::utils::ComponentStore>::make(store);
+        hidlVer = "1.2";
     } else if (platformVersion == __ANDROID_API_R__) {
-        android::sp<V1_1::IComponentStore> storeV1_1 =
-            new V1_1::utils::ComponentStore(store);
-        if (storeV1_1->registerAsService("software") != android::OK) {
-            LOG(ERROR) << "Cannot register software Codec2 v1.1 service.";
-            return;
-        }
+        hidlStore = ::android::sp<V1_1::utils::ComponentStore>::make(store);
+        hidlVer = "1.1";
     } else if (platformVersion == __ANDROID_API_Q__) {
-        android::sp<V1_0::IComponentStore> storeV1_0 =
-            new V1_0::utils::ComponentStore(store);
-        if (storeV1_0->registerAsService("software") != android::OK) {
-            LOG(ERROR) << "Cannot register software Codec2 v1.0 service.";
-            return;
-        }
+        hidlStore = ::android::sp<V1_0::utils::ComponentStore>::make(store);
+        hidlVer = "1.0";
     } else {  // platformVersion < __ANDROID_API_Q__
         LOG(ERROR) << "The platform version " << platformVersion <<
                       " is not supported.";
@@ -448,19 +767,70 @@
         using IComponentStore =
             ::android::hardware::media::c2::V1_0::IComponentStore;
         std::string const preferredStoreName = "default";
-        sp<IComponentStore> preferredStore =
-            IComponentStore::getService(preferredStoreName.c_str());
-        if (preferredStore) {
-            ::android::SetPreferredCodec2ComponentStore(
-                    std::make_shared<H2C2ComponentStore>(preferredStore));
-            LOG(INFO) <<
-                    "Preferred Codec2 store is set to \"" <<
-                    preferredStoreName << "\".";
+        if (aidlSelected) {
+            std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
+            if (__builtin_available(android __ANDROID_API_S__, *)) {
+                std::string instanceName = ::android::base::StringPrintf(
+                        "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
+                if (AServiceManager_isDeclared(instanceName.c_str())) {
+                    preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
+                            AServiceManager_waitForService(instanceName.c_str())));
+                }
+            }
+            if (preferredStore) {
+                ::android::SetPreferredCodec2ComponentStore(
+                        std::make_shared<H2C2ComponentStore>(preferredStore));
+                LOG(INFO) <<
+                        "Preferred Codec2 AIDL store is set to \"" <<
+                        preferredStoreName << "\".";
+            } else {
+                LOG(INFO) <<
+                        "Preferred Codec2 AIDL store is defaulted to \"software\".";
+            }
         } else {
-            LOG(INFO) <<
-                    "Preferred Codec2 store is defaulted to \"software\".";
+            sp<IComponentStore> preferredStore =
+                IComponentStore::getService(preferredStoreName.c_str());
+            if (preferredStore) {
+                ::android::SetPreferredCodec2ComponentStore(
+                        std::make_shared<H2C2ComponentStore>(preferredStore));
+                LOG(INFO) <<
+                        "Preferred Codec2 HIDL store is set to \"" <<
+                        preferredStoreName << "\".";
+            } else {
+                LOG(INFO) <<
+                        "Preferred Codec2 HIDL store is defaulted to \"software\".";
+            }
         }
     }
+
+    if (platformVersion >= __ANDROID_API_V__) {
+        if (!aidlStore) {
+            aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(
+                    std::make_shared<H2C2ComponentStore>(nullptr));
+        }
+        const std::string serviceName =
+            std::string(c2_aidl::IComponentStore::descriptor) + "/software";
+        binder_exception_t ex = AServiceManager_addService(
+                aidlStore->asBinder().get(), serviceName.c_str());
+        if (ex != EX_NONE) {
+            LOG(ERROR) << "Cannot register software Codec2 AIDL service.";
+            return;
+        }
+    }
+
+    if (!hidlStore) {
+        hidlStore = ::android::sp<V1_0::utils::ComponentStore>::make(
+                std::make_shared<H2C2ComponentStore>(nullptr));
+        hidlVer = "1.0";
+    }
+    if (hidlStore->registerAsService("software") != android::OK) {
+        LOG(ERROR) << "Cannot register software Codec2 v" << hidlVer << " service.";
+        return;
+    }
+
     LOG(INFO) << "Software Codec2 service created and registered.";
+
+    ABinderProcess_joinThreadPool();
+    ::android::hardware::joinRpcThreadpool();
 }
 
diff --git a/media/module/codecserviceregistrant/fuzzer/Android.bp b/media/module/codecserviceregistrant/fuzzer/Android.bp
index 1cb8c2b..f4e8751 100644
--- a/media/module/codecserviceregistrant/fuzzer/Android.bp
+++ b/media/module/codecserviceregistrant/fuzzer/Android.bp
@@ -34,6 +34,7 @@
         "libmedia_headers",
     ],
     defaults: [
+        "libcodec2-aidl-defaults",
         "libcodec2-hidl-defaults",
     ],
     fuzz_config: {
diff --git a/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp b/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
index fba4230..4868e0c 100644
--- a/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
+++ b/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
@@ -86,8 +86,8 @@
   }
 
   string const preferredStoreName = string(kServiceName);
-  sp<IComponentStore> preferredStore =
-      IComponentStore::getService(preferredStoreName.c_str());
+  sp<V1_0::IComponentStore> preferredStore =
+      V1_0::IComponentStore::getService(preferredStoreName.c_str());
   mH2C2 = new H2C2ComponentStore(preferredStore);
 }
 
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 91ca7b1..0a8d2ab 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -69,9 +69,9 @@
 
     fuzz_config: {
         cc: [
-            "android-media-fuzzing-reports@google.com",
+            "android-media-playback+bugs@google.com",
         ],
-        componentid: 155276,
+        componentid: 817235,
         hotlists: [
             "4593311",
         ],
diff --git a/media/module/mpeg2ts/ATSParser.cpp b/media/module/mpeg2ts/ATSParser.cpp
index 6aeea3b..86187bd 100644
--- a/media/module/mpeg2ts/ATSParser.cpp
+++ b/media/module/mpeg2ts/ATSParser.cpp
@@ -23,8 +23,8 @@
 #include "ESQueue.h"
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
+#include <cutils/ashmem.h>
 #include <cutils/native_handle.h>
 #include <hidlmemory/mapping.h>
 #include <media/cas/DescramblerAPI.h>
@@ -46,12 +46,12 @@
 #include <inttypes.h>
 
 namespace android {
+using hardware::hidl_handle;
 using hardware::hidl_string;
 using hardware::hidl_vec;
 using hardware::hidl_memory;
 using namespace hardware::cas::V1_0;
 using namespace hardware::cas::native::V1_0;
-typedef hidl::allocator::V1_0::IAllocator TAllocator;
 typedef hidl::memory::V1_0::IMemory TMemory;
 
 // I want the expression "y" evaluated even if verbose logging is off.
@@ -210,7 +210,6 @@
     bool mSampleEncrypted;
     sp<AMessage> mSampleAesKeyItem;
     sp<TMemory> mHidlMemory;
-    sp<TAllocator> mHidlAllocator;
     hardware::cas::native::V1_0::SharedBuffer mDescramblerSrcBuffer;
     sp<ABuffer> mDescrambledBuffer;
     List<SubSampleInfo> mSubSamples;
@@ -1006,34 +1005,29 @@
     sp<ABuffer> newBuffer, newScrambledBuffer;
     sp<TMemory> newMem;
     if (mScrambled) {
-        if (mHidlAllocator == nullptr) {
-            mHidlAllocator = TAllocator::getService("ashmem");
-            if (mHidlAllocator == nullptr) {
-                ALOGE("[stream %d] can't get hidl allocator", mElementaryPID);
-                return false;
+        int fd = ashmem_create_region("mediaATS", neededSize);
+        if (fd < 0) {
+             ALOGE("[stream %d] create_ashmem_region failed for size %zu. FD returned: %d",
+                    mElementaryPID, neededSize, fd);
+            return false;
+        }
+
+        native_handle_t* handle = native_handle_create(1 /*numFds*/, 0/*numInts*/);
+        if (handle == nullptr) {
+            ALOGE("[stream %d] failed to create a native_handle_t", mElementaryPID);
+            if (close(fd)) {
+                ALOGE("[stream %d] failed to close ashmem fd. errno: %s", mElementaryPID,
+                      strerror(errno));
             }
-        }
 
-        hidl_memory hidlMemToken;
-        bool success;
-        auto transStatus = mHidlAllocator->allocate(
-                neededSize,
-                [&success, &hidlMemToken](
-                        bool s,
-                        hidl_memory const& m) {
-                    success = s;
-                    hidlMemToken = m;
-                });
-
-        if (!transStatus.isOk()) {
-            ALOGE("[stream %d] hidl allocator failed at the transport: %s",
-                    mElementaryPID, transStatus.description().c_str());
             return false;
         }
-        if (!success) {
-            ALOGE("[stream %d] hidl allocator failed", mElementaryPID);
-            return false;
-        }
+
+        handle->data[0] = fd;
+        hidl_handle memHandle;
+        memHandle.setTo(handle, true /*shouldOwn*/);
+        hidl_memory hidlMemToken("ashmem", memHandle, neededSize);
+
         newMem = mapMemory(hidlMemToken);
         if (newMem == nullptr || newMem->getPointer() == nullptr) {
             ALOGE("[stream %d] hidl failed to map memory", mElementaryPID);
diff --git a/media/module/mpeg2ts/Android.bp b/media/module/mpeg2ts/Android.bp
index bf762c6..c710ffb 100644
--- a/media/module/mpeg2ts/Android.bp
+++ b/media/module/mpeg2ts/Android.bp
@@ -44,7 +44,6 @@
         "libhidlmemory",
         "android.hardware.cas.native@1.0",
         "android.hidl.memory@1.0",
-        "android.hidl.allocator@1.0",
     ],
 
     header_libs: [
diff --git a/media/module/mpeg2ts/test/Android.bp b/media/module/mpeg2ts/test/Android.bp
index 34a8d3e..cccefac 100644
--- a/media/module/mpeg2ts/test/Android.bp
+++ b/media/module/mpeg2ts/test/Android.bp
@@ -37,9 +37,8 @@
     shared_libs: [
         "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
-        "android.hidl.token@1.0-utils",
-        "android.hidl.allocator@1.0",
         "libcrypto",
+        "libcutils",
         "libhidlbase",
         "libhidlmemory",
         "liblog",
diff --git a/media/module/service.mediatranscoding/tests/Android.bp b/media/module/service.mediatranscoding/tests/Android.bp
index 97fbd4c..9fb6d0d 100644
--- a/media/module/service.mediatranscoding/tests/Android.bp
+++ b/media/module/service.mediatranscoding/tests/Android.bp
@@ -14,6 +14,7 @@
 cc_defaults {
     name: "mediatranscodingservice_test_defaults",
 
+    cpp_std: "gnu++17",
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index 0689083..0d6a4c5 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -13,6 +13,7 @@
 
     host_supported: true,
 
+    cpp_std: "gnu++17",
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 29c6845..180c150 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -27,6 +27,7 @@
 //#define BUFLOG_NDEBUG 0
 #include <afutils/BufLog.h>
 #include <afutils/DumpTryLock.h>
+#include <afutils/NBAIO_Tee.h>
 #include <afutils/Permission.h>
 #include <afutils/PropertyUtils.h>
 #include <afutils/TypedLogger.h>
@@ -1889,7 +1890,7 @@
         return 0;
     }
     if ((sampleRate == 0) ||
-            !audio_is_valid_format(format) || !audio_has_proportional_frames(format) ||
+            !audio_is_valid_format(format) ||
             !audio_is_input_channel(channelMask)) {
         return 0;
     }
@@ -1912,6 +1913,10 @@
 
     std::vector<audio_format_t> formats = {format};
     if (format != AUDIO_FORMAT_PCM_16_BIT) {
+        // For compressed format, buffer size may be queried using PCM. Allow this for compatibility
+        // in cases the primary hw dev does not support the format.
+        // TODO: replace with a table of formats and nominal buffer sizes (based on nominal bitrate
+        // and codec frame size).
         formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
     }
 
@@ -2090,7 +2095,8 @@
     }
 }
 
-void AudioFlinger::ioConfigChanged(audio_io_config_event_t event,
+// Hold either AudioFlinger::mutex or ThreadBase::mutex
+void AudioFlinger::ioConfigChanged_l(audio_io_config_event_t event,
                                    const sp<AudioIoDescriptor>& ioDesc,
                                    pid_t pid) {
     media::AudioIoConfigEvent eventAidl = VALUE_OR_FATAL(
@@ -2262,8 +2268,8 @@
     }
     adjAttributionSource = afutils::checkAttributionSourcePackage(
             adjAttributionSource);
-    // we don't yet support anything other than linear PCM
-    if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) {
+    // further format checks are performed by createRecordTrack_l()
+    if (!audio_is_valid_format(input.config.format)) {
         ALOGE("createRecord() invalid format %#x", input.config.format);
         lStatus = BAD_VALUE;
         goto Exit;
@@ -2944,7 +2950,7 @@
             latencyMs = playbackThread->latency();
 
             // notify client processes of the new output creation
-            playbackThread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
+            playbackThread->ioConfigChanged_l(AUDIO_OUTPUT_OPENED);
 
             // the first primary output opened designates the primary hw device if no HW module
             // named "primary" was already loaded.
@@ -2958,7 +2964,7 @@
                 mHardwareStatus = AUDIO_HW_IDLE;
             }
         } else {
-            thread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
+            thread->ioConfigChanged_l(AUDIO_OUTPUT_OPENED);
         }
         response->output = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
         response->config = VALUE_OR_RETURN_STATUS(
@@ -2991,7 +2997,7 @@
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(id, thread);
     // notify client processes of the new output creation
-    thread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
+    thread->ioConfigChanged_l(AUDIO_OUTPUT_OPENED);
     return id;
 }
 
@@ -3051,7 +3057,7 @@
             mMmapThreads.removeItem(output);
             ALOGD("closing mmapThread %p", mmapThread.get());
         }
-        ioConfigChanged(AUDIO_OUTPUT_CLOSED, sp<AudioIoDescriptor>::make(output));
+        ioConfigChanged_l(AUDIO_OUTPUT_CLOSED, sp<AudioIoDescriptor>::make(output));
         mPatchPanel->notifyStreamClosed(output);
     }
     // The thread entity (active unit of execution) is no longer running here,
@@ -3154,7 +3160,7 @@
 
     if (thread != 0) {
         // notify client processes of the new input creation
-        thread->ioConfigChanged(AUDIO_INPUT_OPENED);
+        thread->ioConfigChanged_l(AUDIO_INPUT_OPENED);
         return NO_ERROR;
     }
     return NO_INIT;
@@ -3313,7 +3319,7 @@
             dumpToThreadLog_l(mmapThread);
             mMmapThreads.removeItem(input);
         }
-        ioConfigChanged(AUDIO_INPUT_CLOSED, sp<AudioIoDescriptor>::make(input));
+        ioConfigChanged_l(AUDIO_INPUT_CLOSED, sp<AudioIoDescriptor>::make(input));
     }
     // FIXME: calling thread->exit() without mutex() held should not be needed anymore now that
     // we have a different lock for notification client
@@ -3693,7 +3699,8 @@
         return {};
     }
 
-    return thread->outDeviceTypes();
+    audio_utils::lock_guard l(thread->mutex());
+    return thread->outDeviceTypes_l();
 }
 
 IAfPlaybackThread* AudioFlinger::fastPlaybackThread_l() const
@@ -4487,8 +4494,9 @@
     }
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        sp<IAfEffectChain> ec =
-                mPlaybackThreads.valueAt(i)->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
+        const auto thread = mPlaybackThreads.valueAt(i);
+        audio_utils::lock_guard l(thread->mutex());
+        const sp<IAfEffectChain> ec = thread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
         if (ec != 0 && ec->isNonOffloadableEnabled()) {
             return true;
         }
@@ -4748,16 +4756,6 @@
     mediautils::TimeCheck::kDefaultSecondChanceDuration,
     true /* crashOnTimeout */);
 
-    // Make sure we connect to Audio Policy Service before calling into AudioFlinger:
-    //  - AudioFlinger can call into Audio Policy Service with its global mutex held
-    //  - If this is the first time Audio Policy Service is queried from inside audioserver process
-    //  this will trigger Audio Policy Manager initialization.
-    //  - Audio Policy Manager initialization calls into AudioFlinger which will try to lock
-    //  its global mutex and a deadlock will occur.
-    if (IPCThreadState::self()->getCallingPid() != getpid()) {
-        AudioSystem::get_audio_policy_service();
-    }
-
     return delegate();
 }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e7f9255..b1751da 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -342,7 +342,8 @@
 
     // ----- begin IAfThreadCallback interface
 
-    bool isNonOffloadableGlobalEffectEnabled_l() const final REQUIRES(mutex());
+    bool isNonOffloadableGlobalEffectEnabled_l() const final
+            REQUIRES(mutex()) EXCLUDES_ThreadBase_Mutex;
     bool btNrecIsOff() const final { return mBtNrecIsOff.load(); }
     float masterVolume_l() const final REQUIRES(mutex());
     bool masterMute_l() const final REQUIRES(mutex());
@@ -387,7 +388,8 @@
             const audioflinger::SyncEventCallback& callBack,
             const wp<IAfTrackBase>& cookie) final EXCLUDES_AudioFlinger_Mutex;
 
-    void ioConfigChanged(audio_io_config_event_t event,
+    // Hold either AudioFlinger::mutex or ThreadBase::mutex
+    void ioConfigChanged_l(audio_io_config_event_t event,
             const sp<AudioIoDescriptor>& ioDesc,
             pid_t pid = 0) final EXCLUDES_AudioFlinger_ClientMutex;
     void onNonOffloadableGlobalEffectEnable() final EXCLUDES_AudioFlinger_Mutex;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 0f3e130..95fed5b 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2570,6 +2570,7 @@
             uint32_t rightZero = 0;
             volumeControlEffect->setVolume(&leftZero, &rightZero, true /*controller*/);
         }
+        mVolumeControlEffect = volumeControlEffect;
     }
     mLeftVolume = newLeft;
     mRightVolume = newRight;
@@ -3084,7 +3085,10 @@
     return t->sampleRate();
 }
 
-audio_channel_mask_t EffectChain::EffectCallback::inChannelMask(int id) const {
+audio_channel_mask_t EffectChain::EffectCallback::inChannelMask(int id) const
+NO_THREAD_SAFETY_ANALYSIS
+// calling function 'hasAudioSession_l' requires holding mutex 'ThreadBase_Mutex' exclusively
+{
     const sp<IAfThreadBase> t = thread().promote();
     if (t == nullptr) {
         return AUDIO_CHANNEL_NONE;
@@ -3120,7 +3124,10 @@
     return audio_channel_count_from_out_mask(inChannelMask(id));
 }
 
-audio_channel_mask_t EffectChain::EffectCallback::outChannelMask() const {
+audio_channel_mask_t EffectChain::EffectCallback::outChannelMask() const
+NO_THREAD_SAFETY_ANALYSIS
+// calling function 'hasAudioSession_l' requires holding mutex 'ThreadBase_Mutex' exclusively
+{
     const sp<IAfThreadBase> t = thread().promote();
     if (t == nullptr) {
         return AUDIO_CHANNEL_NONE;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index aeb0fea..8869b69 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -488,8 +488,10 @@
     bool isBitPerfectCompatible() const final;
 
     // isCompatibleWithThread_l() must be called with thread->mutex() held
-    bool isCompatibleWithThread_l(const sp<IAfThreadBase>& thread) const final;
+    bool isCompatibleWithThread_l(const sp<IAfThreadBase>& thread) const final
+            REQUIRES(audio_utils::ThreadBase_Mutex);
 
+    // Requires either IAfThreadBase::mutex() or EffectChain::mutex() held
     bool containsHapticGeneratingEffect_l() final;
 
     void setHapticIntensity_l(int id, os::HapticScale intensity) final;
@@ -648,7 +650,7 @@
 
              const sp<EffectCallback> mEffectCallback;
 
-             wp<EffectModule> mVolumeControlEffect;
+             wp<IAfEffectModule> mVolumeControlEffect;
 };
 
 class DeviceEffectProxy : public IAfDeviceEffectProxy, public EffectBase {
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index fc2f805..5a7429d 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -70,7 +70,7 @@
     virtual audio_utils::mutex& mutex() const
             RETURN_CAPABILITY(audio_utils::AudioFlinger_Mutex) = 0;
     virtual bool isNonOffloadableGlobalEffectEnabled_l() const
-            REQUIRES(mutex()) = 0;  // Tracks
+            REQUIRES(mutex()) EXCLUDES_ThreadBase_Mutex = 0;  // Tracks
     virtual audio_unique_id_t nextUniqueId(audio_unique_id_use_t use) = 0;
     virtual bool btNrecIsOff() const = 0;
     virtual float masterVolume_l() const
@@ -110,7 +110,8 @@
             const wp<IAfTrackBase>& cookie)
             EXCLUDES_AudioFlinger_Mutex = 0;
 
-    virtual void ioConfigChanged(audio_io_config_event_t event,
+    // Hold either AudioFlinger::mutex or ThreadBase::mutex
+    virtual void ioConfigChanged_l(audio_io_config_event_t event,
             const sp<AudioIoDescriptor>& ioDesc,
             pid_t pid = 0) EXCLUDES_AudioFlinger_ClientMutex = 0;
     virtual void onNonOffloadableGlobalEffectEnable() EXCLUDES_AudioFlinger_Mutex = 0;
@@ -140,7 +141,7 @@
     static bool isValidPcmSinkFormat(audio_format_t format);
 
     virtual status_t readyToRun() = 0;
-    virtual void clearPowerManager() = 0;
+    virtual void clearPowerManager() EXCLUDES_ThreadBase_Mutex = 0;
     virtual status_t initCheck() const = 0;
     virtual type_t type() const = 0;
     virtual bool isDuplicating() const = 0;
@@ -156,21 +157,23 @@
     virtual size_t frameCount() const = 0;
     virtual audio_channel_mask_t hapticChannelMask() const = 0;
     virtual uint32_t hapticChannelCount() const = 0;
-    virtual uint32_t latency_l() const = 0;
-    virtual void setVolumeForOutput_l(float left, float right) const = 0;
+    virtual uint32_t latency_l() const = 0;  // NO_THREAD_SAFETY_ANALYSIS
+    virtual void setVolumeForOutput_l(float left, float right) const REQUIRES(mutex()) = 0;
 
     // Return's the HAL's frame count i.e. fast mixer buffer size.
     virtual size_t frameCountHAL() const = 0;
     virtual size_t frameSize() const = 0;
     // Should be "virtual status_t requestExitAndWait()" and override same
     // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
-    virtual void exit() = 0;
-    virtual bool checkForNewParameter_l(const String8& keyValuePair, status_t& status) = 0;
-    virtual status_t setParameters(const String8& keyValuePairs) = 0;
-    virtual String8 getParameters(const String8& keys) = 0;
-    virtual void ioConfigChanged(
+    virtual void exit() EXCLUDES_ThreadBase_Mutex = 0;
+    virtual bool checkForNewParameter_l(const String8& keyValuePair, status_t& status)
+             REQUIRES(mutex()) = 0;
+    virtual status_t setParameters(const String8& keyValuePairs) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual String8 getParameters(const String8& keys) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void ioConfigChanged_l(
             audio_io_config_event_t event, pid_t pid = 0,
-            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) = 0;
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE)
+            /* holds either AF::mutex or TB::mutex */ = 0;
 
     // sendConfigEvent_l() must be called with ThreadBase::mLock held
     // Can temporarily release the lock if waiting for a reply from
@@ -178,38 +181,53 @@
     // status_t sendConfigEvent_l(sp<ConfigEvent>& event);
     virtual void sendIoConfigEvent(
             audio_io_config_event_t event, pid_t pid = 0,
-            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) = 0;
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) EXCLUDES_ThreadBase_Mutex = 0;
     virtual void sendIoConfigEvent_l(
             audio_io_config_event_t event, pid_t pid = 0,
-            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) = 0;
-    virtual void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) = 0;
-    virtual void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp) = 0;
-    virtual status_t sendSetParameterConfigEvent_l(const String8& keyValuePair) = 0;
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) REQUIRES(mutex()) = 0;
+    virtual void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp)
+            REQUIRES(mutex()) = 0;
+    virtual status_t sendSetParameterConfigEvent_l(const String8& keyValuePair)
+            REQUIRES(mutex()) = 0;
     virtual status_t sendCreateAudioPatchConfigEvent(
-            const struct audio_patch* patch, audio_patch_handle_t* handle) = 0;
-    virtual status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle) = 0;
+            const struct audio_patch* patch, audio_patch_handle_t* handle)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle)
+            EXCLUDES_ThreadBase_Mutex = 0;
     virtual status_t sendUpdateOutDeviceConfigEvent(
-            const DeviceDescriptorBaseVector& outDevices) = 0;
-    virtual void sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs) = 0;
-    virtual void sendCheckOutputStageEffectsEvent() = 0;
-    virtual void sendCheckOutputStageEffectsEvent_l() = 0;
-    virtual void sendHalLatencyModesChangedEvent_l() = 0;
+            const DeviceDescriptorBaseVector& outDevices) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs)
+            REQUIRES(mutex()) = 0;
+    virtual void sendCheckOutputStageEffectsEvent() EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void sendCheckOutputStageEffectsEvent_l()
+            REQUIRES(mutex()) = 0;
+    virtual void sendHalLatencyModesChangedEvent_l()
+            REQUIRES(mutex()) = 0;
 
-    virtual void processConfigEvents_l() = 0;
-    virtual void setCheckOutputStageEffects() = 0;
-    virtual void cacheParameters_l() = 0;
+    virtual void processConfigEvents_l()
+            REQUIRES(mutex()) = 0;
+    virtual void setCheckOutputStageEffects() = 0;  // no mutex needed
+    virtual void cacheParameters_l()
+            REQUIRES(mutex()) = 0;
     virtual status_t createAudioPatch_l(
-            const struct audio_patch* patch, audio_patch_handle_t* handle) = 0;
-    virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
-    virtual void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) = 0;
-    virtual void toAudioPortConfig(struct audio_port_config* config) = 0;
-    virtual void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) = 0;
+            const struct audio_patch* patch, audio_patch_handle_t* handle)
+            REQUIRES(mutex()) = 0;
+    virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle)
+            REQUIRES(mutex()) = 0;
+    virtual void updateOutDevices(const DeviceDescriptorBaseVector& outDevices)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void toAudioPortConfig(struct audio_port_config* config)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs)
+            REQUIRES(mutex()) = 0;
 
     // see note at declaration of mStandby, mOutDevice and mInDevice
     virtual bool inStandby() const = 0;
-    virtual const DeviceTypeSet outDeviceTypes() const = 0;
-    virtual audio_devices_t inDeviceType() const = 0;
-    virtual DeviceTypeSet getDeviceTypes() const = 0;
+    virtual const DeviceTypeSet outDeviceTypes_l() const REQUIRES(mutex()) = 0;
+    virtual audio_devices_t inDeviceType_l() const REQUIRES(mutex()) = 0;
+    virtual DeviceTypeSet getDeviceTypes_l() const REQUIRES(mutex()) = 0;
     virtual const AudioDeviceTypeAddrVector& outDeviceTypeAddrs() const = 0;
     virtual const AudioDeviceTypeAddr& inDeviceTypeAddr() const = 0;
     virtual bool isOutput() const = 0;
@@ -226,7 +244,7 @@
             bool pinned,
             bool probe,
             bool notifyFramesProcessed)
-            REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
+            REQUIRES(audio_utils::AudioFlinger_Mutex) EXCLUDES_ThreadBase_Mutex = 0;
 
     // return values for hasAudioSession (bit field)
     enum effect_state {
@@ -243,28 +261,39 @@
     };
 
     // get effect chain corresponding to session Id.
-    virtual sp<IAfEffectChain> getEffectChain(audio_session_t sessionId) const = 0;
+    virtual sp<IAfEffectChain> getEffectChain(audio_session_t sessionId) const
+            EXCLUDES_ThreadBase_Mutex = 0;
     // same as getEffectChain() but must be called with ThreadBase mutex locked
-    virtual sp<IAfEffectChain> getEffectChain_l(audio_session_t sessionId) const = 0;
-    virtual std::vector<int> getEffectIds_l(audio_session_t sessionId) const = 0;
+    virtual sp<IAfEffectChain> getEffectChain_l(audio_session_t sessionId) const
+            REQUIRES(mutex()) = 0;
+    virtual std::vector<int> getEffectIds_l(audio_session_t sessionId) const
+            REQUIRES(mutex()) = 0;
     // add an effect chain to the chain list (mEffectChains)
-    virtual status_t addEffectChain_l(const sp<IAfEffectChain>& chain) = 0;
+    virtual status_t addEffectChain_l(const sp<IAfEffectChain>& chain)
+            REQUIRES(mutex()) = 0;
     // remove an effect chain from the chain list (mEffectChains)
-    virtual size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) = 0;
+    virtual size_t removeEffectChain_l(const sp<IAfEffectChain>& chain)
+            REQUIRES(mutex()) = 0;
     // lock all effect chains Mutexes. Must be called before releasing the
     // ThreadBase mutex before processing the mixer and effects. This guarantees the
     // integrity of the chains during the process.
     // Also sets the parameter 'effectChains' to current value of mEffectChains.
-    virtual void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains) = 0;
+    virtual void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains)
+            REQUIRES(mutex()) = 0;
     // unlock effect chains after process
-    virtual void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains) = 0;
+    virtual void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains)
+            EXCLUDES_ThreadBase_Mutex = 0;
     // get a copy of mEffectChains vector
-    virtual Vector<sp<IAfEffectChain>> getEffectChains_l() const = 0;
+    virtual Vector<sp<IAfEffectChain>> getEffectChains_l() const
+            REQUIRES(mutex()) = 0;
     // set audio mode to all effect chains
-    virtual void setMode(audio_mode_t mode) = 0;
+    virtual void setMode(audio_mode_t mode)
+            EXCLUDES_ThreadBase_Mutex = 0;
     // get effect module with corresponding ID on specified audio session
-    virtual sp<IAfEffectModule> getEffect(audio_session_t sessionId, int effectId) const = 0;
-    virtual sp<IAfEffectModule> getEffect_l(audio_session_t sessionId, int effectId) const = 0;
+    virtual sp<IAfEffectModule> getEffect(audio_session_t sessionId, int effectId) const
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual sp<IAfEffectModule> getEffect_l(audio_session_t sessionId, int effectId) const
+            REQUIRES(mutex()) = 0;
     // add and effect module. Also creates the effect chain is none exists for
     // the effects audio session. Only called in a context of moving an effect
     // from one thread to another
@@ -272,29 +301,36 @@
             REQUIRES(audio_utils::AudioFlinger_Mutex, mutex()) = 0;
     // remove and effect module. Also removes the effect chain is this was the last
     // effect
-    virtual void removeEffect_l(const sp<IAfEffectModule>& effect, bool release = false) = 0;
+    virtual void removeEffect_l(const sp<IAfEffectModule>& effect, bool release = false)
+            REQUIRES(mutex()) = 0;
     // disconnect an effect handle from module and destroy module if last handle
-    virtual void disconnectEffectHandle(IAfEffectHandle* handle, bool unpinIfLast) = 0;
+    virtual void disconnectEffectHandle(IAfEffectHandle* handle, bool unpinIfLast)
+            EXCLUDES_ThreadBase_Mutex = 0;
     // detach all tracks connected to an auxiliary effect
-    virtual void detachAuxEffect_l(int effectId) = 0;
+    virtual void detachAuxEffect_l(int effectId) REQUIRES(mutex()) = 0;
     // returns a combination of:
     // - EFFECT_SESSION if effects on this audio session exist in one chain
     // - TRACK_SESSION if tracks on this audio session exist
     // - FAST_SESSION if fast tracks on this audio session exist
     // - SPATIALIZED_SESSION if spatialized tracks on this audio session exist
-    virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const = 0;
-    virtual uint32_t hasAudioSession(audio_session_t sessionId) const = 0;
+    virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const REQUIRES(mutex()) = 0;
+    virtual uint32_t hasAudioSession(audio_session_t sessionId) const
+            EXCLUDES_ThreadBase_Mutex = 0;
 
     // the value returned by default implementation is not important as the
     // strategy is only meaningful for PlaybackThread which implements this method
-    virtual product_strategy_t getStrategyForSession_l(audio_session_t sessionId) const = 0;
+    virtual product_strategy_t getStrategyForSession_l(audio_session_t sessionId) const
+            REQUIRES(mutex()) = 0;
 
     // check if some effects must be suspended/restored when an effect is enabled
     // or disabled
     virtual void checkSuspendOnEffectEnabled(
-            bool enabled, audio_session_t sessionId, bool threadLocked) = 0;
+            bool enabled, audio_session_t sessionId, bool threadLocked)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
-    virtual status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) = 0;
+    virtual status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    // internally static, perhaps make static member.
     virtual bool isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const = 0;
 
     // Return a reference to a per-thread heap which can be used to allocate IMemory
@@ -307,33 +343,35 @@
 
     virtual sp<IMemory> pipeMemory() const = 0;
 
-    virtual void systemReady() = 0;
+    virtual void systemReady() EXCLUDES_ThreadBase_Mutex = 0;
 
     // checkEffectCompatibility_l() must be called with ThreadBase::mLock held
     virtual status_t checkEffectCompatibility_l(
-            const effect_descriptor_t* desc, audio_session_t sessionId) = 0;
+            const effect_descriptor_t* desc, audio_session_t sessionId) REQUIRES(mutex()) = 0;
 
-    virtual void broadcast_l() = 0;
+    virtual void broadcast_l() REQUIRES(mutex()) = 0;
 
-    virtual bool isTimestampCorrectionEnabled() const = 0;
+    virtual bool isTimestampCorrectionEnabled_l() const REQUIRES(mutex()) = 0;
 
     virtual bool isMsdDevice() const = 0;
 
-    virtual void dump(int fd, const Vector<String16>& args) = 0;
+    virtual void dump(int fd, const Vector<String16>& args) EXCLUDES_ThreadBase_Mutex = 0;
 
     // deliver stats to mediametrics.
-    virtual void sendStatistics(bool force) = 0;
+    virtual void sendStatistics(bool force) EXCLUDES_ThreadBase_Mutex = 0;
 
     virtual audio_utils::mutex& mutex() const
             RETURN_CAPABILITY(audio_utils::ThreadBase_Mutex) = 0;
 
-    virtual void onEffectEnable(const sp<IAfEffectModule>& effect) = 0;
-    virtual void onEffectDisable() = 0;
+    virtual void onEffectEnable(const sp<IAfEffectModule>& effect) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void onEffectDisable() EXCLUDES_ThreadBase_Mutex = 0;
 
     // invalidateTracksForAudioSession_l must be called with holding mLock.
-    virtual void invalidateTracksForAudioSession_l(audio_session_t sessionId) const = 0;
+    virtual void invalidateTracksForAudioSession_l(audio_session_t sessionId) const
+            REQUIRES(mutex()) = 0;
     // Invalidate all the tracks with the given audio session.
-    virtual void invalidateTracksForAudioSession(audio_session_t sessionId) const = 0;
+    virtual void invalidateTracksForAudioSession(audio_session_t sessionId) const
+            EXCLUDES_ThreadBase_Mutex = 0;
 
     virtual bool isStreamInitialized() const = 0;
     virtual void startMelComputation_l(const sp<audio_utils::MelProcessor>& processor)
@@ -341,10 +379,12 @@
     virtual void stopMelComputation_l()
             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
 
-    virtual product_strategy_t getStrategyForStream(audio_stream_type_t stream) const = 0;
+    virtual product_strategy_t getStrategyForStream(audio_stream_type_t stream) const
+            EXCLUDES_AUDIO_ALL = 0;
 
     virtual void setEffectSuspended_l(
-            const effect_uuid_t* type, bool suspend, audio_session_t sessionId) = 0;
+            const effect_uuid_t* type, bool suspend, audio_session_t sessionId)
+            REQUIRES(mutex()) = 0;
 
     // Dynamic cast to derived interface
     virtual sp<IAfDirectOutputThread> asIAfDirectOutputThread() { return nullptr; }
@@ -392,7 +432,7 @@
     // return estimated latency in milliseconds, as reported by HAL
     virtual uint32_t latency() const = 0;  // should be in IAfThreadBase?
 
-    virtual uint32_t& fastTrackAvailMask_l() = 0;
+    virtual uint32_t& fastTrackAvailMask_l() REQUIRES(mutex()) = 0;
 
     virtual sp<IAfTrack> createTrack_l(
             const sp<Client>& client,
@@ -418,63 +458,70 @@
             bool isBitPerfect)
             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
 
-    virtual status_t addTrack_l(const sp<IAfTrack>& track) = 0;
-    virtual bool destroyTrack_l(const sp<IAfTrack>& track) = 0;
-    virtual bool isTrackActive(const sp<IAfTrack>& track) const = 0;
-    virtual void addOutputTrack_l(const sp<IAfTrack>& track) = 0;
+    virtual status_t addTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex()) = 0;
+    virtual bool destroyTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex()) = 0;
+    virtual bool isTrackActive(const sp<IAfTrack>& track) const REQUIRES(mutex()) = 0;
+    virtual void addOutputTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex()) = 0;
 
-    virtual AudioStreamOut* getOutput_l() const = 0;
-    virtual AudioStreamOut* getOutput() const = 0;
-    virtual AudioStreamOut* clearOutput() = 0;
+    virtual AudioStreamOut* getOutput_l() const REQUIRES(mutex()) = 0;
+    virtual AudioStreamOut* getOutput() const EXCLUDES_ThreadBase_Mutex = 0;
+    virtual AudioStreamOut* clearOutput() EXCLUDES_ThreadBase_Mutex = 0;
 
     // a very large number of suspend() will eventually wraparound, but unlikely
     virtual void suspend() = 0;
     virtual void restore() = 0;
     virtual bool isSuspended() const = 0;
-    virtual status_t getRenderPosition(uint32_t* halFrames, uint32_t* dspFrames) const = 0;
+    virtual status_t getRenderPosition(uint32_t* halFrames, uint32_t* dspFrames) const
+            EXCLUDES_ThreadBase_Mutex = 0;
     // Consider also removing and passing an explicit mMainBuffer initialization
     // parameter to AF::IAfTrack::Track().
     virtual float* sinkBuffer() const = 0;
 
-    virtual status_t attachAuxEffect(const sp<IAfTrack>& track, int EffectId) = 0;
-    virtual status_t attachAuxEffect_l(const sp<IAfTrack>& track, int EffectId) = 0;
+    virtual status_t attachAuxEffect(const sp<IAfTrack>& track, int EffectId)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t attachAuxEffect_l(const sp<IAfTrack>& track, int EffectId)
+            REQUIRES(mutex()) = 0;
 
     // called with AudioFlinger lock held
-    virtual bool invalidateTracks_l(audio_stream_type_t streamType) = 0;
-    virtual bool invalidateTracks_l(std::set<audio_port_handle_t>& portIds) = 0;
-    virtual void invalidateTracks(audio_stream_type_t streamType) = 0;
+    virtual bool invalidateTracks_l(audio_stream_type_t streamType) REQUIRES(mutex()) = 0;
+    virtual bool invalidateTracks_l(std::set<audio_port_handle_t>& portIds) REQUIRES(mutex()) = 0;
+    virtual void invalidateTracks(audio_stream_type_t streamType)
+            EXCLUDES_ThreadBase_Mutex = 0;
     // Invalidate tracks by a set of port ids. The port id will be removed from
     // the given set if the corresponding track is found and invalidated.
-    virtual void invalidateTracks(std::set<audio_port_handle_t>& portIds) = 0;
+    virtual void invalidateTracks(std::set<audio_port_handle_t>& portIds)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
-    virtual status_t getTimestamp_l(AudioTimestamp& timestamp) = 0;
-    virtual void addPatchTrack(const sp<IAfPatchTrack>& track) = 0;
-    virtual void deletePatchTrack(const sp<IAfPatchTrack>& track) = 0;
+    virtual status_t getTimestamp_l(AudioTimestamp& timestamp) REQUIRES(mutex()) = 0;
+    virtual void addPatchTrack(const sp<IAfPatchTrack>& track) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void deletePatchTrack(const sp<IAfPatchTrack>& track) EXCLUDES_ThreadBase_Mutex = 0;
 
     // Return the asynchronous signal wait time.
-    virtual int64_t computeWaitTimeNs_l() const = 0;
+    virtual int64_t computeWaitTimeNs_l() const REQUIRES(mutex()) = 0;
     // returns true if the track is allowed to be added to the thread.
     virtual bool isTrackAllowed_l(
             audio_channel_mask_t channelMask, audio_format_t format, audio_session_t sessionId,
-            uid_t uid) const = 0;
+            uid_t uid) const REQUIRES(mutex()) = 0;
 
     virtual bool supportsHapticPlayback() const = 0;
 
-    virtual void setDownStreamPatch(const struct audio_patch* patch) = 0;
+    virtual void setDownStreamPatch(const struct audio_patch* patch)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
-    virtual IAfTrack* getTrackById_l(audio_port_handle_t trackId) = 0;
+    virtual IAfTrack* getTrackById_l(audio_port_handle_t trackId) REQUIRES(mutex()) = 0;
 
     virtual bool hasMixer() const = 0;
 
     virtual status_t setRequestedLatencyMode(audio_latency_mode_t mode) = 0;
 
-    virtual status_t getSupportedLatencyModes(std::vector<audio_latency_mode_t>* modes) = 0;
+    virtual status_t getSupportedLatencyModes(std::vector<audio_latency_mode_t>* modes)
+           EXCLUDES_ThreadBase_Mutex = 0;
 
     virtual status_t setBluetoothVariableLatencyEnabled(bool enabled) = 0;
 
-    virtual void setStandby() = 0;
-    virtual void setStandby_l() = 0;
-    virtual bool waitForHalStart() = 0;
+    virtual void setStandby() EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void setStandby_l() REQUIRES(mutex()) = 0;
+    virtual bool waitForHalStart() EXCLUDES_ThreadBase_Mutex = 0;
 
     virtual bool hasFastMixer() const = 0;
     virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const = 0;
@@ -494,9 +541,9 @@
             const sp<IAfThreadCallback>& afThreadCallback, IAfPlaybackThread* mainThread,
             audio_io_handle_t id, bool systemReady);
 
-    virtual void addOutputTrack(IAfPlaybackThread* thread) = 0;
+    virtual void addOutputTrack(IAfPlaybackThread* thread) EXCLUDES_ThreadBase_Mutex = 0;
     virtual uint32_t waitTimeMs() const = 0;
-    virtual void removeOutputTrack(IAfPlaybackThread* thread) = 0;
+    virtual void removeOutputTrack(IAfPlaybackThread* thread) EXCLUDES_ThreadBase_Mutex = 0;
 };
 
 class IAfRecordThread : public virtual IAfThreadBase {
@@ -521,42 +568,49 @@
             status_t* status /*non-NULL*/,
             audio_port_handle_t portId,
             int32_t maxSharedAudioHistoryMs)
-            REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
-    virtual void destroyTrack_l(const sp<IAfRecordTrack>& track) = 0;
-    virtual void removeTrack_l(const sp<IAfRecordTrack>& track) = 0;
+            REQUIRES(audio_utils::AudioFlinger_Mutex) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void destroyTrack_l(const sp<IAfRecordTrack>& track) REQUIRES(mutex()) = 0;
+    virtual void removeTrack_l(const sp<IAfRecordTrack>& track) REQUIRES(mutex()) = 0;
 
     virtual status_t start(
             IAfRecordTrack* recordTrack, AudioSystem::sync_event_t event,
-            audio_session_t triggerSession) = 0;
+            audio_session_t triggerSession) EXCLUDES_ThreadBase_Mutex = 0;
 
     // ask the thread to stop the specified track, and
     // return true if the caller should then do it's part of the stopping process
-    virtual bool stop(IAfRecordTrack* recordTrack) = 0;
+    virtual bool stop(IAfRecordTrack* recordTrack) EXCLUDES_ThreadBase_Mutex = 0;
 
+    // NO_THREAD_SAFETY_ANALYSIS: consider atomics
     virtual AudioStreamIn* getInput() const = 0;
     virtual AudioStreamIn* clearInput() = 0;
 
     virtual status_t getActiveMicrophones(
-            std::vector<media::MicrophoneInfoFw>* activeMicrophones) const = 0;
-    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) = 0;
-    virtual status_t setPreferredMicrophoneFieldDimension(float zoom) = 0;
+            std::vector<media::MicrophoneInfoFw>* activeMicrophones)
+            const EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
-    virtual void addPatchTrack(const sp<IAfPatchRecord>& record) = 0;
-    virtual void deletePatchTrack(const sp<IAfPatchRecord>& record) = 0;
+    virtual void addPatchTrack(const sp<IAfPatchRecord>& record)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void deletePatchTrack(const sp<IAfPatchRecord>& record)
+            EXCLUDES_ThreadBase_Mutex = 0;
     virtual bool fastTrackAvailable() const = 0;
     virtual void setFastTrackAvailable(bool available) = 0;
 
-    virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced) = 0;
+    virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced)
+            EXCLUDES_ThreadBase_Mutex = 0;
     virtual bool hasFastCapture() const = 0;
 
-    virtual void checkBtNrec() = 0;
-    virtual uint32_t getInputFramesLost() const = 0;
+    virtual void checkBtNrec() EXCLUDES_ThreadBase_Mutex = 0;
+    virtual uint32_t getInputFramesLost() const EXCLUDES_ThreadBase_Mutex = 0;
 
     virtual status_t shareAudioHistory(
             const std::string& sharedAudioPackageName,
             audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
-            int64_t sharedAudioStartMs = -1) = 0;
-    virtual void resetAudioHistory_l() = 0;
+            int64_t sharedAudioStartMs = -1) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void resetAudioHistory_l() REQUIRES(mutex()) = 0;
 };
 
 class IAfMmapThread : public virtual IAfThreadBase {
@@ -575,26 +629,32 @@
             audio_session_t sessionId,
             const sp<MmapStreamCallback>& callback,
             audio_port_handle_t deviceId,
-            audio_port_handle_t portId) = 0;
-    virtual void disconnect() = 0;
+            audio_port_handle_t portId) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual void disconnect() EXCLUDES_ThreadBase_Mutex = 0;
 
     // MmapStreamInterface handling (see adapter)
     virtual status_t createMmapBuffer(
-            int32_t minSizeFrames, struct audio_mmap_buffer_info* info) = 0;
-    virtual status_t getMmapPosition(struct audio_mmap_position* position) const = 0;
+            int32_t minSizeFrames, struct audio_mmap_buffer_info* info)
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t getMmapPosition(struct audio_mmap_position* position) const
+            EXCLUDES_ThreadBase_Mutex = 0;
     virtual status_t start(
             const AudioClient& client, const audio_attributes_t* attr,
-            audio_port_handle_t* handle) = 0;
-    virtual status_t stop(audio_port_handle_t handle) = 0;
-    virtual status_t standby() = 0;
-    virtual status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const = 0;
-    virtual status_t reportData(const void* buffer, size_t frameCount) = 0;
+            audio_port_handle_t* handle) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t stop(audio_port_handle_t handle) EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t standby() EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const
+            EXCLUDES_ThreadBase_Mutex = 0;
+    virtual status_t reportData(const void* buffer, size_t frameCount)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
     // TODO(b/291317898)  move to IAfThreadBase?
-    virtual void invalidateTracks(std::set<audio_port_handle_t>& portIds) = 0;
+    virtual void invalidateTracks(std::set<audio_port_handle_t>& portIds)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
     // Sets the UID records silence - TODO(b/291317898)  move to IAfMmapCaptureThread
-    virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced) = 0;
+    virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced)
+            EXCLUDES_ThreadBase_Mutex = 0;
 
     virtual sp<IAfMmapPlaybackThread> asIAfMmapPlaybackThread() { return nullptr; }
     virtual sp<IAfMmapCaptureThread> asIAfMmapCaptureThread() { return nullptr; }
@@ -606,7 +666,7 @@
             const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
             AudioHwDevice* hwDev, AudioStreamOut* output, bool systemReady);
 
-    virtual AudioStreamOut* clearOutput() = 0;
+    virtual AudioStreamOut* clearOutput() EXCLUDES_ThreadBase_Mutex = 0;
 };
 
 class IAfMmapCaptureThread : public virtual IAfMmapThread {
@@ -615,7 +675,7 @@
             const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
             AudioHwDevice* hwDev, AudioStreamIn* input, bool systemReady);
 
-    virtual AudioStreamIn* clearInput() = 0;
+    virtual AudioStreamIn* clearInput() EXCLUDES_ThreadBase_Mutex = 0;
 };
 
 }  // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0b73fba..9a1fe1f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -875,7 +875,7 @@
         } break;
         case CFG_EVENT_IO: {
             IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
-            ioConfigChanged(data->mEvent, data->mPid, data->mPortId);
+            ioConfigChanged_l(data->mEvent, data->mPid, data->mPortId);
         } break;
         case CFG_EVENT_SET_PARAMETER: {
             SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
@@ -886,22 +886,22 @@
             }
         } break;
         case CFG_EVENT_CREATE_AUDIO_PATCH: {
-            const DeviceTypeSet oldDevices = getDeviceTypes();
+            const DeviceTypeSet oldDevices = getDeviceTypes_l();
             CreateAudioPatchConfigEventData *data =
                                             (CreateAudioPatchConfigEventData *)event->mData.get();
             event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
-            const DeviceTypeSet newDevices = getDeviceTypes();
+            const DeviceTypeSet newDevices = getDeviceTypes_l();
             configChanged = oldDevices != newDevices;
             mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
                     dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
                     dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
         } break;
         case CFG_EVENT_RELEASE_AUDIO_PATCH: {
-            const DeviceTypeSet oldDevices = getDeviceTypes();
+            const DeviceTypeSet oldDevices = getDeviceTypes_l();
             ReleaseAudioPatchConfigEventData *data =
                                             (ReleaseAudioPatchConfigEventData *)event->mData.get();
             event->mStatus = releaseAudioPatch_l(data->mHandle);
-            const DeviceTypeSet newDevices = getDeviceTypes();
+            const DeviceTypeSet newDevices = getDeviceTypes_l();
             configChanged = oldDevices != newDevices;
             mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
                     dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
@@ -1089,9 +1089,9 @@
     }
     // Note: output device may be used by capture threads for effects such as AEC.
     dprintf(fd, "  Output devices: %s (%s)\n",
-            dumpDeviceTypes(outDeviceTypes()).c_str(), toString(outDeviceTypes()).c_str());
+            dumpDeviceTypes(outDeviceTypes_l()).c_str(), toString(outDeviceTypes_l()).c_str());
     dprintf(fd, "  Input device: %#x (%s)\n",
-            inDeviceType(), toString(inDeviceType()).c_str());
+            inDeviceType_l(), toString(inDeviceType_l()).c_str());
     dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, toString(mAudioSource).c_str());
 
     // Dump timestamp statistics for the Thread types that support it.
@@ -1102,7 +1102,8 @@
             || mType == OFFLOAD
             || mType == SPATIALIZER) {
         dprintf(fd, "  Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
-        dprintf(fd, "  Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
+        dprintf(fd, "  Timestamp corrected: %s\n",
+                isTimestampCorrectionEnabled_l() ? "yes" : "no");
     }
 
     if (mLastIoBeginNs > 0) { // MMAP may not set this
@@ -1979,7 +1980,7 @@
 }
 
 template <typename T>
-void ThreadBase::ActiveTracks<T>::updatePowerState(
+void ThreadBase::ActiveTracks<T>::updatePowerState_l(
         const sp<ThreadBase>& thread, bool force) {
     // Updates ActiveTracks client uids to the thread wakelock.
     if (mActiveTracksGeneration != mLastActiveTracksGeneration || force) {
@@ -2045,6 +2046,7 @@
 // Call only from threadLoop() or when it is idle.
 // Do not call from high performance code as this may do binder rpc to the MediaMetrics service.
 void ThreadBase::sendStatistics(bool force)
+NO_THREAD_SAFETY_ANALYSIS
 {
     // Do not log if we have no stats.
     // We choose the timestamp verifier because it is the most likely item to be present.
@@ -2076,8 +2078,8 @@
     item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
     item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
     item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
-    item->setCString(MM_PREFIX "outDevice", toString(outDeviceTypes()).c_str());
-    item->setCString(MM_PREFIX "inDevice", toString(inDeviceType()).c_str());
+    item->setCString(MM_PREFIX "outDevice", toString(outDeviceTypes_l()).c_str());
+    item->setCString(MM_PREFIX "inDevice", toString(inDeviceType_l()).c_str());
 
     // thread statistics
     if (mIoJitterMs.getN() > 0) {
@@ -2358,10 +2360,7 @@
     dprintf(fd, "  Total writes: %d\n", mNumWrites);
     dprintf(fd, "  Delayed writes: %d\n", mNumDelayedWrites);
     dprintf(fd, "  Blocked in write: %s\n", mInWrite ? "yes" : "no");
-    dprintf(fd, "  Suspend count: %d\n", mSuspended);
-    dprintf(fd, "  Sink buffer : %p\n", mSinkBuffer);
-    dprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
-    dprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
+    dprintf(fd, "  Suspend count: %d\n", (int32_t)mSuspended);
     dprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);
     dprintf(fd, "  Standby delay ns=%lld\n", (long long)mStandbyDelayNs);
     AudioStreamOut *output = mOutput;
@@ -2434,6 +2433,7 @@
     }
 
     if (isBitPerfect) {
+        audio_utils::lock_guard _l(mutex());
         sp<IAfEffectChain> chain = getEffectChain_l(sessionId);
         if (chain.get() != nullptr) {
             // Bit-perfect is required according to the configuration and preferred mixer
@@ -2791,6 +2791,8 @@
     return latency_l();
 }
 uint32_t PlaybackThread::latency_l() const
+NO_THREAD_SAFETY_ANALYSIS
+// Fix later.
 {
     uint32_t latency;
     if (initCheck() == NO_ERROR && mOutput->stream->getLatency(&latency) == OK) {
@@ -2858,7 +2860,6 @@
 
 // addTrack_l() must be called with ThreadBase::mutex() held
 status_t PlaybackThread::addTrack_l(const sp<IAfTrack>& track)
-NO_THREAD_SAFETY_ANALYSIS  // release and re-acquire mutex()
 {
     status_t status = ALREADY_EXISTS;
 
@@ -3026,7 +3027,7 @@
     return mOutput->stream->selectPresentation(presentationId, programId);
 }
 
-void PlaybackThread::ioConfigChanged(audio_io_config_event_t event, pid_t pid,
+void PlaybackThread::ioConfigChanged_l(audio_io_config_event_t event, pid_t pid,
                                                    audio_port_handle_t portId) {
     ALOGV("PlaybackThread::ioConfigChanged, thread %p, event %d", this, event);
     sp<AudioIoDescriptor> desc;
@@ -3048,7 +3049,7 @@
         desc = sp<AudioIoDescriptor>::make(mId);
         break;
     }
-    mAfThreadCallback->ioConfigChanged(event, desc, pid);
+    mAfThreadCallback->ioConfigChanged_l(event, desc, pid);
 }
 
 void PlaybackThread::onWriteReady()
@@ -3234,8 +3235,8 @@
     if (hasMixer()) {
         mNormalFrameCount = (mNormalFrameCount + 15) & ~15;
     }
-    ALOGI("HAL output buffer size %zu frames, normal sink buffer size %zu frames", mFrameCount,
-            mNormalFrameCount);
+    ALOGI("HAL output buffer size %zu frames, normal sink buffer size %zu frames",
+            (size_t)mFrameCount, mNormalFrameCount);
 
     // Check if we want to throttle the processing to no more than 2x normal rate
     mThreadThrottle = property_get_bool("af.thread.throttle", true /* default_value */);
@@ -3472,7 +3473,7 @@
             ALOGD("ro.audio.silent is ignored since no output device is set");
             return;
         }
-        if (isSingleDeviceType(outDeviceTypes(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
+        if (isSingleDeviceType(outDeviceTypes_l(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
             ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
             return;
         }
@@ -3642,7 +3643,7 @@
 
     // make sure standby delay is not too short when connected to an A2DP sink to avoid
     // truncating audio when going to standby.
-    if (!Intersection(outDeviceTypes(),  getAudioDeviceOutAllA2dpSet()).empty()) {
+    if (!Intersection(outDeviceTypes_l(),  getAudioDeviceOutAllA2dpSet()).empty()) {
         if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
             mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
         }
@@ -3990,7 +3991,7 @@
         // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
         //
         // Note: we access outDeviceTypes() outside of mutex().
-        if (isMsdDevice() && outDeviceTypes().count(AUDIO_DEVICE_OUT_BUS) != 0) {
+        if (isMsdDevice() && outDeviceTypes_l().count(AUDIO_DEVICE_OUT_BUS) != 0) {
             // Here, we try for the AF lock, but do not block on it as the latency
             // is more informational.
             if (mAfThreadCallback->mutex().try_lock()) {
@@ -4135,7 +4136,7 @@
             // mMixerStatusIgnoringFastTracks is also updated internally
             mMixerStatus = prepareTracks_l(&tracksToRemove);
 
-            mActiveTracks.updatePowerState(this);
+            mActiveTracks.updatePowerState_l(this);
 
             metadataUpdate = updateMetadata_l();
 
@@ -4508,9 +4509,10 @@
                                 // notify of throttle end on debug log
                                 // but prevent spamming for bluetooth
                                 ALOGD_IF(!isSingleDeviceType(
-                                                 outDeviceTypes(), audio_is_a2dp_out_device) &&
+                                                 outDeviceTypes_l(), audio_is_a2dp_out_device) &&
                                          !isSingleDeviceType(
-                                                 outDeviceTypes(), audio_is_hearing_aid_out_device),
+                                                 outDeviceTypes_l(),
+                                                 audio_is_hearing_aid_out_device),
                                         "mixer(%p) throttle end: throttle time(%u)", this, diff);
                                 mThreadThrottleEndMs = mThreadThrottleTimeMs;
                             }
@@ -4606,7 +4608,7 @@
                 timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
                 mSampleRate);
 
-        if (isTimestampCorrectionEnabled()) {
+        if (isTimestampCorrectionEnabled_l()) {
             ALOGVV("TS_BEFORE: %d %lld %lld", id(),
                     (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
                     (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
@@ -4685,7 +4687,7 @@
             // and we use systemTime().
             mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] = mFramesWritten;
             mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = mLastIoBeginNs == -1
-                    ? systemTime() : mLastIoBeginNs;
+                    ? systemTime() : (int64_t)mLastIoBeginNs;
         }
 
         for (const sp<IAfTrack>& t : mActiveTracks) {
@@ -5326,7 +5328,8 @@
 // shared by MIXER and DIRECT, overridden by DUPLICATING
 void PlaybackThread::threadLoop_standby()
 {
-    ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended);
+    ALOGV("%s: audio hardware entering standby, mixer %p, suspend count %d",
+            __func__, this, (int32_t)mSuspended);
     mOutput->standby();
     if (mUseAsyncWrite != 0) {
         // discard any pending drain or write ack by incrementing sequence
@@ -6367,7 +6370,7 @@
 void MixerThread::dumpInternals_l(int fd, const Vector<String16>& args)
 {
     PlaybackThread::dumpInternals_l(fd, args);
-    dprintf(fd, "  Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
+    dprintf(fd, "  Thread throttle time (msecs): %u\n", (uint32_t)mThreadThrottleTimeMs);
     dprintf(fd, "  AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str());
     dprintf(fd, "  Master mono: %s\n", mMasterMono ? "on" : "off");
     dprintf(fd, "  Master balance: %f (%s)\n", mMasterBalance.load(),
@@ -7218,6 +7221,7 @@
 {
     if (mFlushPending || mHwPaused) {
         // If a flush is pending or track was paused, just discard buffered data
+        audio_utils::lock_guard l(mutex());
         flushHw_l();
     } else {
         mMixerStatus = MIXER_DRAIN_ALL;
@@ -7704,8 +7708,13 @@
             mOutputTracks[i]->destroy();
             mOutputTracks.removeAt(i);
             updateWaitTime_l();
-            if (thread->getOutput() == mOutput) {
-                mOutput = NULL;
+            // NO_THREAD_SAFETY_ANALYSIS
+            // Lambda workaround: as thread != this
+            // we can safely call the remote thread getOutput.
+            const bool equalOutput =
+                    [&](){ return thread->getOutput() == mOutput; }();
+            if (equalOutput) {
+                mOutput = nullptr;
             }
             return;
         }
@@ -7970,10 +7979,11 @@
         break;
     case FastCapture_Static:
         initFastCapture = !mIsMsdDevice // Disable fast capture for MSD BUS devices.
+                && audio_is_linear_pcm(mFormat)
                 && (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
-        ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d "
-                "mIsMsdDevice = %d", this, (long long)mFrameCount, mSampleRate,
-                kMinNormalCaptureBufferSizeMs, initFastCapture, mIsMsdDevice);
+        ALOGV("%p kUseFastCapture = Static, format = 0x%x, (%lld * 1000) / %u vs %u, "
+                "initFastCapture = %d, mIsMsdDevice = %d", this, mFormat, (long long)mFrameCount,
+                mSampleRate, kMinNormalCaptureBufferSizeMs, initFastCapture, mIsMsdDevice);
         break;
     // case FastCapture_Dynamic:
     }
@@ -8117,6 +8127,9 @@
     // used to request a deferred sleep, to be executed later while mutex is unlocked
     uint32_t sleepUs = 0;
 
+    // timestamp correction enable is determined under lock, used in processing step.
+    bool timestampCorrectionEnabled = false;
+
     int64_t lastLoopCountRead = -2;  // never matches "previous" loop, when loopCount = 0.
 
     // loop while there is work to do
@@ -8261,7 +8274,7 @@
 
             }
 
-            mActiveTracks.updatePowerState(this);
+            mActiveTracks.updatePowerState_l(this);
 
             updateMetadata_l();
 
@@ -8281,6 +8294,7 @@
             }
             sleepUs = 0;
 
+            timestampCorrectionEnabled = isTimestampCorrectionEnabled_l();
             lockEffectChains_l(effectChains);
         }
 
@@ -8437,9 +8451,7 @@
                     && time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
 
                 mTimestampVerifier.add(position, time, mSampleRate);
-
-                // Correct timestamps
-                if (isTimestampCorrectionEnabled()) {
+                if (timestampCorrectionEnabled) {
                     ALOGVV("TS_BEFORE: %d %lld %lld",
                             id(), (long long)time, (long long)position);
                     auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
@@ -8541,9 +8553,11 @@
                 // from framesIn.
                 // This isn't strictly necessary but helps limit buffer resizing in
                 // RecordBufferConverter.  TODO: remove when no longer needed.
-                framesOut = min(framesOut,
-                        destinationFramesPossible(
-                                framesIn, mSampleRate, activeTrack->sampleRate()));
+                if (audio_is_linear_pcm(activeTrack->format())) {
+                    framesOut = min(framesOut,
+                            destinationFramesPossible(
+                                    framesIn, mSampleRate, activeTrack->sampleRate()));
+                }
 
                 if (activeTrack->isDirect()) {
                     // No RecordBufferConverter used for direct streams. Pass
@@ -9418,7 +9432,7 @@
 {
     // disable AEC and NS if the device is a BT SCO headset supporting those
     // pre processings
-    bool suspend = audio_is_bluetooth_sco_device(inDeviceType()) &&
+    bool suspend = audio_is_bluetooth_sco_device(inDeviceType_l()) &&
                         mAfThreadCallback->btNrecIsOff();
     if (mBtNrecSuspended.exchange(suspend) != suspend) {
         for (size_t i = 0; i < mEffectChains.size(); i++) {
@@ -9529,7 +9543,7 @@
     return {};
 }
 
-void RecordThread::ioConfigChanged(audio_io_config_event_t event, pid_t pid,
+void RecordThread::ioConfigChanged_l(audio_io_config_event_t event, pid_t pid,
                                                  audio_port_handle_t portId) {
     sp<AudioIoDescriptor> desc;
     switch (event) {
@@ -9547,7 +9561,7 @@
         desc = sp<AudioIoDescriptor>::make(mId);
         break;
     }
-    mAfThreadCallback->ioConfigChanged(event, desc, pid);
+    mAfThreadCallback->ioConfigChanged_l(event, desc, pid);
 }
 
 void RecordThread::readInputParameters_l()
@@ -10014,25 +10028,27 @@
 void MmapThread::disconnect()
 {
     ActiveTracks<IAfMmapTrack> activeTracks;
+    audio_port_handle_t localPortId;
     {
         audio_utils::lock_guard _l(mutex());
         for (const sp<IAfMmapTrack>& t : mActiveTracks) {
             activeTracks.add(t);
         }
+        localPortId = mPortId;
     }
     for (const sp<IAfMmapTrack>& t : activeTracks) {
         stop(t->portId());
     }
     // This will decrement references and may cause the destruction of this thread.
     if (isOutput()) {
-        AudioSystem::releaseOutput(mPortId);
+        AudioSystem::releaseOutput(localPortId);
     } else {
-        AudioSystem::releaseInput(mPortId);
+        AudioSystem::releaseInput(localPortId);
     }
 }
 
 
-void MmapThread::configure(const audio_attributes_t* attr,
+void MmapThread::configure_l(const audio_attributes_t* attr,
                                                 audio_stream_type_t streamType __unused,
                                                 audio_session_t sessionId,
                                                 const sp<MmapStreamCallback>& callback,
@@ -10049,6 +10065,7 @@
 status_t MmapThread::createMmapBuffer(int32_t minSizeFrames,
                                   struct audio_mmap_buffer_info *info)
 {
+    audio_utils::lock_guard l(mutex());
     if (mHalStream == 0) {
         return NO_INIT;
     }
@@ -10058,6 +10075,7 @@
 
 status_t MmapThread::getMmapPosition(struct audio_mmap_position* position) const
 {
+    audio_utils::lock_guard l(mutex());
     if (mHalStream == 0) {
         return NO_INIT;
     }
@@ -10085,6 +10103,7 @@
                                          const audio_attributes_t *attr,
                                          audio_port_handle_t *handle)
 {
+    audio_utils::lock_guard l(mutex());
     ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
           client.attributionSource.uid, mStandby, mPortId, *handle);
     if (mHalStream == 0) {
@@ -10095,7 +10114,7 @@
 
     // For the first track, reuse portId and session allocated when the stream was opened.
     if (*handle == mPortId) {
-        acquireWakeLock();
+        acquireWakeLock_l();
         return NO_ERROR;
     }
 
@@ -10105,20 +10124,23 @@
     const AttributionSourceState adjAttributionSource = afutils::checkAttributionSourcePackage(
             client.attributionSource);
 
+    const auto localSessionId = mSessionId;
+    auto localAttr = mAttr;
     if (isOutput()) {
         audio_config_t config = AUDIO_CONFIG_INITIALIZER;
         config.sample_rate = mSampleRate;
         config.channel_mask = mChannelMask;
         config.format = mFormat;
-        audio_stream_type_t stream = streamType();
+        audio_stream_type_t stream = streamType_l();
         audio_output_flags_t flags =
                 (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
         audio_port_handle_t deviceId = mDeviceId;
         std::vector<audio_io_handle_t> secondaryOutputs;
         bool isSpatialized;
         bool isBitPerfect;
-        ret = AudioSystem::getOutputForAttr(&mAttr, &io,
-                                            mSessionId,
+        mutex().unlock();
+        ret = AudioSystem::getOutputForAttr(&localAttr, &io,
+                                            localSessionId,
                                             &stream,
                                             adjAttributionSource,
                                             &config,
@@ -10128,6 +10150,8 @@
                                             &secondaryOutputs,
                                             &isSpatialized,
                                             &isBitPerfect);
+        mutex().lock();
+        mAttr = localAttr;
         ALOGD_IF(!secondaryOutputs.empty(),
                  "MmapThread::start does not support secondary outputs, ignoring them");
     } else {
@@ -10136,14 +10160,17 @@
         config.channel_mask = mChannelMask;
         config.format = mFormat;
         audio_port_handle_t deviceId = mDeviceId;
-        ret = AudioSystem::getInputForAttr(&mAttr, &io,
+        mutex().unlock();
+        ret = AudioSystem::getInputForAttr(&localAttr, &io,
                                               RECORD_RIID_INVALID,
-                                              mSessionId,
+                                              localSessionId,
                                               adjAttributionSource,
                                               &config,
                                               AUDIO_INPUT_FLAG_MMAP_NOIRQ,
                                               &deviceId,
                                               &portId);
+        mutex().lock();
+        // localAttr is const for getInputForAttr.
     }
     // APM should not chose a different input or output stream for the same set of attributes
     // and audo configuration
@@ -10154,18 +10181,20 @@
     }
 
     if (isOutput()) {
+        mutex().unlock();
         ret = AudioSystem::startOutput(portId);
+        mutex().lock();
     } else {
         {
             // Add the track record before starting input so that the silent status for the
             // client can be cached.
-            audio_utils::lock_guard _l(mutex());
             setClientSilencedState_l(portId, false /*silenced*/);
         }
+        mutex().unlock();
         ret = AudioSystem::startInput(portId);
+        mutex().lock();
     }
 
-    audio_utils::lock_guard _l(mutex());
     // abort if start is rejected by audio policy manager
     if (ret != NO_ERROR) {
         ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
@@ -10209,7 +10238,7 @@
     mActiveTracks.add(track);
     sp<IAfEffectChain> chain = getEffectChain_l(mSessionId);
     if (chain != 0) {
-        chain->setStrategy(getStrategyForStream(streamType()));
+        chain->setStrategy(getStrategyForStream(streamType_l()));
         chain->incTrackCnt();
         chain->incActiveTrackCnt();
     }
@@ -10231,18 +10260,17 @@
 status_t MmapThread::stop(audio_port_handle_t handle)
 {
     ALOGV("%s handle %d", __FUNCTION__, handle);
+    audio_utils::lock_guard l(mutex());
 
     if (mHalStream == 0) {
         return NO_INIT;
     }
 
     if (handle == mPortId) {
-        releaseWakeLock();
+        releaseWakeLock_l();
         return NO_ERROR;
     }
 
-    audio_utils::lock_guard _l(mutex());
-
     sp<IAfMmapTrack> track;
     for (const sp<IAfMmapTrack>& t : mActiveTracks) {
         if (handle == t->portId()) {
@@ -10283,8 +10311,10 @@
 }
 
 status_t MmapThread::standby()
+NO_THREAD_SAFETY_ANALYSIS  // clang bug
 {
     ALOGV("%s", __FUNCTION__);
+    audio_utils::lock_guard(mutex());
 
     if (mHalStream == 0) {
         return NO_INIT;
@@ -10298,7 +10328,7 @@
         mThreadSnapshot.onEnd();
         mStandby = true;
     }
-    releaseWakeLock();
+    releaseWakeLock_l();
     return NO_ERROR;
 }
 
@@ -10345,7 +10375,10 @@
 
 bool MmapThread::threadLoop()
 {
-    checkSilentMode_l();
+    {
+        audio_utils::unique_lock _l(mutex());
+        checkSilentMode_l();
+    }
 
     const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));
 
@@ -10385,7 +10418,7 @@
 
         checkInvalidTracks_l();
 
-        mActiveTracks.updatePowerState(this);
+        mActiveTracks.updatePowerState_l(this);
 
         updateMetadata_l();
 
@@ -10442,7 +10475,7 @@
     return {};
 }
 
-void MmapThread::ioConfigChanged(audio_io_config_event_t event, pid_t pid,
+void MmapThread::ioConfigChanged_l(audio_io_config_event_t event, pid_t pid,
                                                audio_port_handle_t portId __unused) {
     sp<AudioIoDescriptor> desc;
     bool isInput = false;
@@ -10464,7 +10497,7 @@
         desc = sp<AudioIoDescriptor>::make(mId);
         break;
     }
-    mAfThreadCallback->ioConfigChanged(event, desc, pid);
+    mAfThreadCallback->ioConfigChanged_l(event, desc, pid);
 }
 
 status_t MmapThread::createAudioPatch_l(const struct audio_patch* patch,
@@ -10581,6 +10614,7 @@
 }
 
 void MmapThread::toAudioPortConfig(struct audio_port_config* config)
+NO_THREAD_SAFETY_ANALYSIS // mAudioHwDev handle access
 {
     ThreadBase::toAudioPortConfig(config);
     if (isOutput()) {
@@ -10698,7 +10732,6 @@
 }
 
 void MmapThread::checkInvalidTracks_l()
-NO_THREAD_SAFETY_ANALYSIS  // release and re-acquire mutex()
 {
     sp<MmapStreamCallback> callback;
     for (const sp<IAfMmapTrack>& track : mActiveTracks) {
@@ -10760,14 +10793,24 @@
         AudioHwDevice *hwDev,  AudioStreamOut *output, bool systemReady)
     : MmapThread(afThreadCallback, id, hwDev, output->stream, systemReady, true /* isOut */),
       mStreamType(AUDIO_STREAM_MUSIC),
-      mStreamVolume(1.0),
-      mStreamMute(false),
       mOutput(output)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id);
     mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
     mMasterVolume = afThreadCallback->masterVolume_l();
     mMasterMute = afThreadCallback->masterMute_l();
+
+    for (int i = AUDIO_STREAM_MIN; i < AUDIO_STREAM_FOR_POLICY_CNT; ++i) {
+        const audio_stream_type_t stream{static_cast<audio_stream_type_t>(i)};
+        mStreamTypes[stream].volume = 0.0f;
+        mStreamTypes[stream].mute = mAfThreadCallback->streamMute_l(stream);
+    }
+    // Audio patch and call assistant volume are always max
+    mStreamTypes[AUDIO_STREAM_PATCH].volume = 1.0f;
+    mStreamTypes[AUDIO_STREAM_PATCH].mute = false;
+    mStreamTypes[AUDIO_STREAM_CALL_ASSISTANT].volume = 1.0f;
+    mStreamTypes[AUDIO_STREAM_CALL_ASSISTANT].mute = false;
+
     if (mAudioHwDev) {
         if (mAudioHwDev->canSetMasterVolume()) {
             mMasterVolume = 1.0;
@@ -10786,7 +10829,8 @@
                                                 audio_port_handle_t deviceId,
                                                 audio_port_handle_t portId)
 {
-    MmapThread::configure(attr, streamType, sessionId, callback, deviceId, portId);
+    audio_utils::lock_guard l(mutex());
+    MmapThread::configure_l(attr, streamType, sessionId, callback, deviceId, portId);
     mStreamType = streamType;
 }
 
@@ -10824,8 +10868,8 @@
 void MmapPlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
 {
     audio_utils::lock_guard _l(mutex());
+    mStreamTypes[stream].volume = value;
     if (stream == mStreamType) {
-        mStreamVolume = value;
         broadcast_l();
     }
 }
@@ -10833,17 +10877,14 @@
 float MmapPlaybackThread::streamVolume(audio_stream_type_t stream) const
 {
     audio_utils::lock_guard _l(mutex());
-    if (stream == mStreamType) {
-        return mStreamVolume;
-    }
-    return 0.0f;
+    return mStreamTypes[stream].volume;
 }
 
 void MmapPlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
 {
     audio_utils::lock_guard _l(mutex());
+    mStreamTypes[stream].mute = muted;
     if (stream == mStreamType) {
-        mStreamMute= muted;
         broadcast_l();
     }
 }
@@ -10883,14 +10924,13 @@
 {
     float volume;
 
-    if (mMasterMute || mStreamMute) {
+    if (mMasterMute || streamMuted_l()) {
         volume = 0;
     } else {
-        volume = mMasterVolume * mStreamVolume;
+        volume = mMasterVolume * streamVolume_l();
     }
 
     if (volume != mHalVolFloat) {
-
         // Convert volumes from float to 8.24
         uint32_t vol = (uint32_t)(volume * (1 << 24));
 
@@ -10924,8 +10964,8 @@
             track->setMetadataHasChanged();
             track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
                 /*muteState=*/{mMasterMute,
-                               mStreamVolume == 0.f,
-                               mStreamMute,
+                               streamVolume_l() == 0.f,
+                               streamMuted_l(),
                                // TODO(b/241533526): adjust logic to include mute from AppOps
                                false /*muteFromPlaybackRestricted*/,
                                false /*muteFromClientVolume*/,
@@ -11038,7 +11078,7 @@
     MmapThread::dumpInternals_l(fd, args);
 
     dprintf(fd, "  Stream type: %d Stream volume: %f HAL volume: %f Stream mute %d\n",
-            mStreamType, mStreamVolume, mHalVolFloat, mStreamMute);
+            mStreamType, streamVolume_l(), mHalVolFloat, streamMuted_l());
     dprintf(fd, "  Master volume: %f Master mute %d\n", mMasterVolume, mMasterMute);
 }
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3105ad7..7fe6143 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -44,6 +44,13 @@
 public:
     static const char *threadTypeToString(type_t type);
 
+    // ThreadBase_ThreadLoop is a virtual mutex (always nullptr) that
+    // guards methods and variables that ONLY run and are accessed
+    // on the single threaded threadLoop().
+    //
+    // As access is by a single thread, the variables are thread safe.
+    static audio_utils::mutex* ThreadBase_ThreadLoop;
+
     IAfThreadCallback* afThreadCallback() const final { return mAfThreadCallback.get(); }
 
     ThreadBase(const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
@@ -51,7 +58,7 @@
     ~ThreadBase() override;
 
     status_t readyToRun() final;
-    void clearPowerManager() final;
+    void clearPowerManager() final EXCLUDES_ThreadBase_Mutex;
 
     // base for record and playback
     enum {
@@ -68,11 +75,9 @@
 
     class ConfigEventData: public RefBase {
     public:
-        virtual ~ConfigEventData() {}
-
         virtual  void dump(char *buffer, size_t size) = 0;
     protected:
-        ConfigEventData() {}
+        ConfigEventData() = default;
     };
 
     // Config event sequence by client if status needed (e.g binder thread calling setParameters()):
@@ -103,14 +108,22 @@
             }
         }
 
-        audio_utils::mutex& mutex() const { return mMutex; }
+        audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::ConfigEvent_Mutex) {
+            return mMutex;
+        }
         const int mType; // event type e.g. CFG_EVENT_IO
         mutable audio_utils::mutex mMutex; // mutex associated with mCondition
         audio_utils::condition_variable mCondition; // condition for status return
+
+        // NO_THREAD_SAFETY_ANALYSIS Can we add GUARDED_BY?
         status_t mStatus; // status communicated to sender
-        bool mWaitStatus; // true if sender is waiting for status
-        bool mRequiresSystemReady; // true if must wait for system ready to enter event queue
-        sp<ConfigEventData> mData;     // event specific parameter data
+
+        bool mWaitStatus GUARDED_BY(mutex()); // true if sender is waiting for status
+        // true if must wait for system ready to enter event queue
+        bool mRequiresSystemReady GUARDED_BY(mutex());
+
+        // NO_THREAD_SAFETY_ANALYSIS Can we add GUARDED_BY?
+        sp<ConfigEventData> mData; // event specific parameter data
 
     protected:
         explicit ConfigEvent(int type, bool requiresSystemReady = false) :
@@ -197,7 +210,7 @@
         }
 
         const struct audio_patch mPatch;
-        audio_patch_handle_t mHandle;
+        audio_patch_handle_t mHandle;  // cannot be const
     };
 
     class CreateAudioPatchConfigEvent : public ConfigEvent {
@@ -219,7 +232,7 @@
             snprintf(buffer, size, "- Patch handle: %u\n", mHandle);
         }
 
-        audio_patch_handle_t mHandle;
+        const audio_patch_handle_t mHandle;
     };
 
     class ReleaseAudioPatchConfigEvent : public ConfigEvent {
@@ -240,7 +253,7 @@
             snprintf(buffer, size, "- Devices: %s", android::toString(mOutDevices).c_str());
         }
 
-        DeviceDescriptorBaseVector mOutDevices;
+        const DeviceDescriptorBaseVector mOutDevices;
     };
 
     class UpdateOutDevicesConfigEvent : public ConfigEvent {
@@ -260,7 +273,7 @@
             snprintf(buffer, size, "- mMaxSharedAudioHistoryMs: %d", mMaxSharedAudioHistoryMs);
         }
 
-        int32_t mMaxSharedAudioHistoryMs;
+        const int32_t mMaxSharedAudioHistoryMs;
     };
 
     class ResizeBufferConfigEvent : public ConfigEvent {
@@ -289,15 +302,14 @@
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
         explicit    PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
-        virtual     ~PMDeathRecipient() {}
 
         // IBinder::DeathRecipient
-        virtual     void        binderDied(const wp<IBinder>& who);
+        void binderDied(const wp<IBinder>& who) final;
 
     private:
         DISALLOW_COPY_AND_ASSIGN(PMDeathRecipient);
 
-        wp<ThreadBase> mThread;
+        const wp<ThreadBase> mThread;
     };
 
     type_t type() const final { return mType; }
@@ -311,8 +323,9 @@
     uint32_t channelCount() const final { return mChannelCount; }
     audio_channel_mask_t hapticChannelMask() const override { return AUDIO_CHANNEL_NONE; }
     uint32_t hapticChannelCount() const override { return 0; }
-    uint32_t latency_l() const override { return 0; }
-    void setVolumeForOutput_l(float /* left */, float /* right */) const override {}
+    uint32_t latency_l() const override { return 0; }  // NO_THREAD_SAFETY_ANALYSIS
+    void setVolumeForOutput_l(float /* left */, float /* right */) const override
+            REQUIRES(mutex()) {}
 
                 // Return's the HAL's frame count i.e. fast mixer buffer size.
     size_t frameCountHAL() const final { return mFrameCount; }
@@ -320,44 +333,49 @@
 
     // Should be "virtual status_t requestExitAndWait()" and override same
     // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
-    void exit() final;
-    status_t setParameters(const String8& keyValuePairs) final;
+    void exit() final EXCLUDES_ThreadBase_Mutex;
+    status_t setParameters(const String8& keyValuePairs) final EXCLUDES_ThreadBase_Mutex;
 
                 // sendConfigEvent_l() must be called with ThreadBase::mutex() held
                 // Can temporarily release the lock if waiting for a reply from
                 // processConfigEvents_l().
-    status_t sendConfigEvent_l(sp<ConfigEvent>& event);
+    status_t sendConfigEvent_l(sp<ConfigEvent>& event) REQUIRES(mutex());
     void sendIoConfigEvent(audio_io_config_event_t event, pid_t pid = 0,
-            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final EXCLUDES_ThreadBase_Mutex;
     void sendIoConfigEvent_l(audio_io_config_event_t event, pid_t pid = 0,
-            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
-    void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) final;
-    void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp) final;
-    status_t sendSetParameterConfigEvent_l(const String8& keyValuePair) final;
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final REQUIRES(mutex());
+    void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) final
+            EXCLUDES_ThreadBase_Mutex;
+    void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp) final
+            REQUIRES(mutex());
+    status_t sendSetParameterConfigEvent_l(const String8& keyValuePair) final REQUIRES(mutex());
     status_t sendCreateAudioPatchConfigEvent(const struct audio_patch* patch,
-            audio_patch_handle_t* handle) final;
-    status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle) final;
+            audio_patch_handle_t* handle) final EXCLUDES_ThreadBase_Mutex;
+    status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle) final
+            EXCLUDES_ThreadBase_Mutex;
     status_t sendUpdateOutDeviceConfigEvent(
-            const DeviceDescriptorBaseVector& outDevices) final;
-    void sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs) final;
-    void sendCheckOutputStageEffectsEvent() final;
-    void sendCheckOutputStageEffectsEvent_l() final;
-    void sendHalLatencyModesChangedEvent_l() final;
+            const DeviceDescriptorBaseVector& outDevices) final EXCLUDES_ThreadBase_Mutex;
+    void sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs) final REQUIRES(mutex());
+    void sendCheckOutputStageEffectsEvent() final EXCLUDES_ThreadBase_Mutex;
+    void sendCheckOutputStageEffectsEvent_l() final REQUIRES(mutex());
+    void sendHalLatencyModesChangedEvent_l() final REQUIRES(mutex());
 
-    void processConfigEvents_l() final;
+    void processConfigEvents_l() final REQUIRES(mutex());
     void setCheckOutputStageEffects() override {}
     void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
     void toAudioPortConfig(struct audio_port_config* config) override;
-    void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) override;
+    void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) override REQUIRES(mutex());
 
     // see note at declaration of mStandby, mOutDevice and mInDevice
     bool inStandby() const override { return mStandby; }
-    const DeviceTypeSet outDeviceTypes() const final {
+    const DeviceTypeSet outDeviceTypes_l() const final REQUIRES(mutex()) {
         return getAudioDeviceTypes(mOutDeviceTypeAddrs);
     }
-    audio_devices_t inDeviceType() const final { return mInDeviceTypeAddr.mType; }
-    DeviceTypeSet getDeviceTypes() const final {
-        return isOutput() ? outDeviceTypes() : DeviceTypeSet({inDeviceType()});
+    audio_devices_t inDeviceType_l() const final REQUIRES(mutex()) {
+        return mInDeviceTypeAddr.mType;
+    }
+    DeviceTypeSet getDeviceTypes_l() const final REQUIRES(mutex()) {
+        return isOutput() ? outDeviceTypes_l() : DeviceTypeSet({inDeviceType_l()});
     }
 
     const AudioDeviceTypeAddrVector& outDeviceTypeAddrs() const final {
@@ -410,23 +428,26 @@
     // get effect chain corresponding to session Id.
     sp<IAfEffectChain> getEffectChain(audio_session_t sessionId) const final;
     // same as getEffectChain() but must be called with ThreadBase mutex locked
-    sp<IAfEffectChain> getEffectChain_l(audio_session_t sessionId) const final;
-    std::vector<int> getEffectIds_l(audio_session_t sessionId) const final;
+    sp<IAfEffectChain> getEffectChain_l(audio_session_t sessionId) const final REQUIRES(mutex());
+    std::vector<int> getEffectIds_l(audio_session_t sessionId) const final REQUIRES(mutex());
 
                 // lock all effect chains Mutexes. Must be called before releasing the
                 // ThreadBase mutex before processing the mixer and effects. This guarantees the
                 // integrity of the chains during the process.
                 // Also sets the parameter 'effectChains' to current value of mEffectChains.
-    void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains) final;
+    void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains) final REQUIRES(mutex());
                 // unlock effect chains after process
     void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains) final;
                 // get a copy of mEffectChains vector
-    Vector<sp<IAfEffectChain>> getEffectChains_l() const final { return mEffectChains; };
+    Vector<sp<IAfEffectChain>> getEffectChains_l() const final REQUIRES(mutex()) {
+        return mEffectChains;
+    }
                 // set audio mode to all effect chains
     void setMode(audio_mode_t mode) final;
                 // get effect module with corresponding ID on specified audio session
     sp<IAfEffectModule> getEffect(audio_session_t sessionId, int effectId) const final;
-    sp<IAfEffectModule> getEffect_l(audio_session_t sessionId, int effectId) const final;
+    sp<IAfEffectModule> getEffect_l(audio_session_t sessionId, int effectId) const final
+            REQUIRES(mutex());
                 // add and effect module. Also creates the effect chain is none exists for
                 // the effects audio session. Only called in a context of moving an effect
                 // from one thread to another
@@ -434,20 +455,22 @@
             REQUIRES(audio_utils::AudioFlinger_Mutex, mutex());
                 // remove and effect module. Also removes the effect chain is this was the last
                 // effect
-    void removeEffect_l(const sp<IAfEffectModule>& effect, bool release = false) final;
+    void removeEffect_l(const sp<IAfEffectModule>& effect, bool release = false) final
+            REQUIRES(mutex());
                 // disconnect an effect handle from module and destroy module if last handle
     void disconnectEffectHandle(IAfEffectHandle* handle, bool unpinIfLast) final;
                 // detach all tracks connected to an auxiliary effect
-    void detachAuxEffect_l(int /* effectId */) override {}
+    void detachAuxEffect_l(int /* effectId */) override REQUIRES(mutex()) {}
     // TODO(b/291317898) - remove hasAudioSession_l below.
-    uint32_t hasAudioSession_l(audio_session_t sessionId) const override = 0;
-    uint32_t hasAudioSession(audio_session_t sessionId) const final {
-                    std::lock_guard _l(mutex());
-                    return hasAudioSession_l(sessionId);
-                }
+    uint32_t hasAudioSession_l(audio_session_t sessionId) const override REQUIRES(mutex()) = 0;
+    uint32_t hasAudioSession(audio_session_t sessionId) const final EXCLUDES_ThreadBase_Mutex {
+        audio_utils::lock_guard _l(mutex());
+        return hasAudioSession_l(sessionId);
+    }
 
                 template <typename T>
-                uint32_t hasAudioSession_l(audio_session_t sessionId, const T& tracks) const {
+    uint32_t hasAudioSession_l(audio_session_t sessionId, const T& tracks) const
+            REQUIRES(mutex()) {
                     uint32_t result = 0;
                     if (getEffectChain_l(sessionId) != 0) {
                         result = EFFECT_SESSION;
@@ -476,9 +499,9 @@
                 // the value returned by default implementation is not important as the
                 // strategy is only meaningful for PlaybackThread which implements this method
     product_strategy_t getStrategyForSession_l(
-            audio_session_t /* sessionId */) const override {
-                    return static_cast<product_strategy_t>(0);
-                }
+            audio_session_t /* sessionId */) const override REQUIRES(mutex()){
+        return static_cast<product_strategy_t>(0);
+    }
 
                 // check if some effects must be suspended/restored when an effect is enabled
                 // or disabled
@@ -497,38 +520,41 @@
 
     sp<IMemory> pipeMemory() const override { return nullptr; }
 
-    void systemReady() final;
+    void systemReady() final EXCLUDES_ThreadBase_Mutex;
 
-    void broadcast_l() final;
+    void broadcast_l() final REQUIRES(mutex());
 
-    bool isTimestampCorrectionEnabled() const override { return false; }
+    bool isTimestampCorrectionEnabled_l() const override REQUIRES(mutex()) { return false; }
 
     bool isMsdDevice() const final { return mIsMsdDevice; }
 
     void dump(int fd, const Vector<String16>& args) override;
 
                 // deliver stats to mediametrics.
-    void sendStatistics(bool force) final;
+    void sendStatistics(bool force) final
+            REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
 
     audio_utils::mutex& mutex() const final RETURN_CAPABILITY(audio_utils::ThreadBase_Mutex) {
         return mMutex;
     }
     mutable audio_utils::mutex mMutex;
 
-    void onEffectEnable(const sp<IAfEffectModule>& effect) final;
-    void onEffectDisable() final;
+    void onEffectEnable(const sp<IAfEffectModule>& effect) final EXCLUDES_ThreadBase_Mutex;
+    void onEffectDisable() final EXCLUDES_ThreadBase_Mutex;
 
                 // invalidateTracksForAudioSession_l must be called with holding mutex().
-    void invalidateTracksForAudioSession_l(audio_session_t /* sessionId */) const override {}
+    void invalidateTracksForAudioSession_l(audio_session_t /* sessionId */) const override
+            REQUIRES(mutex()) {}
                 // Invalidate all the tracks with the given audio session.
-    void invalidateTracksForAudioSession(audio_session_t sessionId) const final {
-                    std::lock_guard _l(mutex());
+    void invalidateTracksForAudioSession(audio_session_t sessionId) const final
+            EXCLUDES_ThreadBase_Mutex {
+        audio_utils::lock_guard _l(mutex());
                     invalidateTracksForAudioSession_l(sessionId);
                 }
 
                 template <typename T>
-                void invalidateTracksForAudioSession_l(audio_session_t sessionId,
-                                                       const T& tracks) const {
+    void invalidateTracksForAudioSession_l(audio_session_t sessionId,
+            const T& tracks) const REQUIRES(mutex()) {
                     for (size_t i = 0; i < tracks.size(); ++i) {
                         const sp<IAfTrackBase>& track = tracks[i];
                         if (sessionId == track->sessionId()) {
@@ -553,41 +579,44 @@
                     effect_uuid_t mType;    // effect type UUID
                 };
 
-                void        acquireWakeLock();
-                virtual void acquireWakeLock_l();
-                void        releaseWakeLock();
-                void        releaseWakeLock_l();
-                void        updateWakeLockUids_l(const SortedVector<uid_t> &uids);
-                void        getPowerManager_l();
+    void acquireWakeLock() EXCLUDES_ThreadBase_Mutex;
+    virtual void acquireWakeLock_l() REQUIRES(mutex());
+    void releaseWakeLock() EXCLUDES_ThreadBase_Mutex;
+    void releaseWakeLock_l() REQUIRES(mutex());
+    void updateWakeLockUids_l(const SortedVector<uid_t> &uids) REQUIRES(mutex());
+    void getPowerManager_l() REQUIRES(mutex());
                 // suspend or restore effects of the specified type (or all if type is NULL)
                 // on a given session. The number of suspend requests is counted and restore
                 // occurs when all suspend requests are cancelled.
-                void setEffectSuspended_l(const effect_uuid_t *type,
+    void setEffectSuspended_l(const effect_uuid_t *type,
                                           bool suspend,
-                                          audio_session_t sessionId) final;
+            audio_session_t sessionId) final REQUIRES(mutex());
                 // updated mSuspendedSessions when an effect is suspended or restored
-                void        updateSuspendedSessions_l(const effect_uuid_t *type,
+    void updateSuspendedSessions_l(const effect_uuid_t *type,
                                                       bool suspend,
-                                                      audio_session_t sessionId);
+            audio_session_t sessionId) REQUIRES(mutex());
                 // check if some effects must be suspended when an effect chain is added
-                void checkSuspendOnAddEffectChain_l(const sp<IAfEffectChain>& chain);
+    void checkSuspendOnAddEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());
 
                 // sends the metadata of the active tracks to the HAL
                 struct MetadataUpdate {
                     std::vector<playback_track_metadata_v7_t> playbackMetadataUpdate;
                     std::vector<record_track_metadata_v7_t>   recordMetadataUpdate;
                 };
-    virtual     MetadataUpdate           updateMetadata_l() = 0;
+    // NO_THREAD_SAFETY_ANALYSIS, updateMetadata_l() should include ThreadBase_ThreadLoop
+    // but MmapThread::start() -> exitStandby_l() -> updateMetadata_l() prevents this.
+    virtual MetadataUpdate updateMetadata_l() REQUIRES(mutex()) = 0;
 
                 String16 getWakeLockTag();
 
-    virtual     void        preExit() { }
-    virtual     void        setMasterMono_l(bool mono __unused) { }
+    virtual void preExit() EXCLUDES_ThreadBase_Mutex {}
+    virtual void setMasterMono_l(bool mono __unused) REQUIRES(mutex()) {}
     virtual     bool        requireMonoBlend() { return false; }
 
                             // called within the threadLoop to obtain timestamp from the HAL.
-    virtual     status_t    threadloop_getHalTimestamp_l(
-                                    ExtendedTimestamp *timestamp __unused) const {
+    virtual status_t threadloop_getHalTimestamp_l(
+            ExtendedTimestamp *timestamp __unused) const
+            REQUIRES(mutex(), ThreadBase_ThreadLoop) {
                                 return INVALID_OPERATION;
                             }
 public:
@@ -595,11 +624,12 @@
                 product_strategy_t getStrategyForStream(audio_stream_type_t stream) const;
 protected:
 
-    virtual     void        onHalLatencyModesChanged_l() {}
+    virtual void onHalLatencyModesChanged_l() REQUIRES(mutex()) {}
 
-    virtual     void        dumpInternals_l(int fd __unused, const Vector<String16>& args __unused)
-                            { }
-    virtual     void        dumpTracks_l(int fd __unused, const Vector<String16>& args __unused) { }
+    virtual void dumpInternals_l(int fd __unused, const Vector<String16>& args __unused)
+            REQUIRES(mutex()) {}
+    virtual void dumpTracks_l(int fd __unused, const Vector<String16>& args __unused)
+            REQUIRES(mutex()) {}
 
                 const type_t            mType;
 
@@ -624,10 +654,14 @@
                                                            // HAL format if Fastmixer is used.
                 audio_format_t          mHALFormat;
                 size_t                  mBufferSize;       // HAL buffer size for read() or write()
-                AudioDeviceTypeAddrVector mOutDeviceTypeAddrs; // output device types and addresses
-                AudioDeviceTypeAddr       mInDeviceTypeAddr;   // input device type and address
-                Vector< sp<ConfigEvent> >     mConfigEvents;
-                Vector< sp<ConfigEvent> >     mPendingConfigEvents; // events awaiting system ready
+
+     // output device types and addresses
+    AudioDeviceTypeAddrVector mOutDeviceTypeAddrs GUARDED_BY(mutex());
+    AudioDeviceTypeAddr mInDeviceTypeAddr GUARDED_BY(mutex());   // input device type and address
+    Vector<sp<ConfigEvent>> mConfigEvents GUARDED_BY(mutex());
+
+    // events awaiting system ready
+    Vector<sp<ConfigEvent>> mPendingConfigEvents GUARDED_BY(mutex());
 
                 // These fields are written and read by thread itself without lock or barrier,
                 // and read by other threads without lock or barrier via standby(), outDeviceTypes()
@@ -637,17 +671,17 @@
                 // with possibility that it might be inconsistent with other information.
                 bool                    mStandby;     // Whether thread is currently in standby.
 
+    // NO_THREAD_SAFETY_ANALYSIS - mPatch and mAudioSource should be guarded by mutex().
                 struct audio_patch      mPatch;
-
                 audio_source_t          mAudioSource;
 
                 const audio_io_handle_t mId;
-                Vector<sp<IAfEffectChain>> mEffectChains;
+    Vector<sp<IAfEffectChain>> mEffectChains GUARDED_BY(mutex());
 
                 static const int        kThreadNameLength = 16; // prctl(PR_SET_NAME) limit
                 char                    mThreadName[kThreadNameLength]; // guaranteed NUL-terminated
-                sp<os::IPowerManager>   mPowerManager;
-                sp<IBinder>             mWakeLockToken;
+    sp<os::IPowerManager> mPowerManager GUARDED_BY(mutex());
+    sp<IBinder> mWakeLockToken GUARDED_BY(mutex());
                 const sp<PMDeathRecipient> mDeathRecipient;
                 // list of suspended effects per session and per type. The first (outer) vector is
                 // keyed by session ID, the second (inner) by type UUID timeLow field
@@ -658,27 +692,31 @@
                 static const size_t     kLogSize = 4 * 1024;
                 sp<NBLog::Writer>       mNBLogWriter;
                 bool                    mSystemReady;
-                ExtendedTimestamp       mTimestamp;
-                TimestampVerifier< // For timestamp statistics.
-                        int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
+
+    // NO_THREAD_SAFETY_ANALYSIS - mTimestamp and mTimestampVerifier should be
+    // accessed under mutex for the RecordThread.
+    ExtendedTimestamp mTimestamp;
+    TimestampVerifier<int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
                 // DIRECT and OFFLOAD threads should reset frame count to zero on stop/flush
                 // TODO: add confirmation checks:
                 // 1) DIRECT threads and linear PCM format really resets to 0?
                 // 2) Is frame count really valid if not linear pcm?
                 // 3) Are all 64 bits of position returned, not just lowest 32 bits?
                 // Timestamp corrected device should be a single device.
-                audio_devices_t         mTimestampCorrectedDevice = AUDIO_DEVICE_NONE;
+
+    audio_devices_t mTimestampCorrectedDevice = AUDIO_DEVICE_NONE;  // CONST set in ctor
 
                 // ThreadLoop statistics per iteration.
-                int64_t                 mLastIoBeginNs = -1;
-                int64_t                 mLastIoEndNs = -1;
+    std::atomic<int64_t> mLastIoBeginNs = -1;  // set in threadLoop, read by dump()
+    int64_t mLastIoEndNs GUARDED_BY(ThreadBase_ThreadLoop) = -1;
 
                 // ThreadSnapshot is thread-safe (internally locked)
                 mediautils::ThreadSnapshot mThreadSnapshot;
 
-                // This should be read under ThreadBase lock (if not on the threadLoop thread).
-                audio_utils::Statistics<double> mIoJitterMs{0.995 /* alpha */};
-                audio_utils::Statistics<double> mProcessTimeMs{0.995 /* alpha */};
+    audio_utils::Statistics<double> mIoJitterMs GUARDED_BY(mutex()) {0.995 /* alpha */};
+    audio_utils::Statistics<double> mProcessTimeMs GUARDED_BY(mutex()) {0.995 /* alpha */};
+
+    // NO_THREAD_SAFETY_ANALYSIS  GUARDED_BY(mutex())
                 audio_utils::Statistics<double> mLatencyMs{0.995 /* alpha */};
                 audio_utils::Statistics<double> mMonopipePipeDepthStats{0.999 /* alpha */};
 
@@ -764,7 +802,8 @@
                     // ThreadBase thread.
                     void            clear();
                     // periodically called in the threadLoop() to update power state uids.
-                    void updatePowerState(const sp<ThreadBase>& thread, bool force = false);
+                    void updatePowerState_l(const sp<ThreadBase>& thread, bool force = false)
+                            REQUIRES(audio_utils::ThreadBase_Mutex);
 
                     /** @return true if one or move active tracks was added or removed since the
                      *          last time this function was called or the vector was created.
@@ -799,11 +838,11 @@
                     bool                mHasChanged = false;
                 };
 
-                SimpleLog mLocalLog;
+                SimpleLog mLocalLog;  // locked internally
 
 private:
-                void dumpBase_l(int fd, const Vector<String16>& args);
-                void dumpEffectChains_l(int fd, const Vector<String16>& args);
+    void dumpBase_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
+    void dumpEffectChains_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
 };
 
 // --- PlaybackThread ---
@@ -836,35 +875,38 @@
     ~PlaybackThread() override;
 
     // Thread virtuals
-    bool threadLoop() final;
+    bool threadLoop() final REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
 
     // RefBase
     void onFirstRef() override;
 
     status_t checkEffectCompatibility_l(
-            const effect_descriptor_t* desc, audio_session_t sessionId) final;
+            const effect_descriptor_t* desc, audio_session_t sessionId) final REQUIRES(mutex());
 
-    void addOutputTrack_l(const sp<IAfTrack>& track) final {
+    void addOutputTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex()) {
         mTracks.add(track);
     }
 
 protected:
     // Code snippets that were lifted up out of threadLoop()
-    virtual     void        threadLoop_mix() = 0;
-    virtual     void        threadLoop_sleepTime() = 0;
-    virtual     ssize_t     threadLoop_write();
-    virtual     void        threadLoop_drain();
-    virtual     void        threadLoop_standby();
-    virtual     void        threadLoop_exit();
-    virtual     void        threadLoop_removeTracks(const Vector<sp<IAfTrack>>& tracksToRemove);
+    virtual void threadLoop_mix() REQUIRES(ThreadBase_ThreadLoop) = 0;
+    virtual void threadLoop_sleepTime() REQUIRES(ThreadBase_ThreadLoop) = 0;
+    virtual ssize_t threadLoop_write() REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_drain() REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_standby() REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_exit() REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_removeTracks(const Vector<sp<IAfTrack>>& tracksToRemove)
+            REQUIRES(ThreadBase_ThreadLoop);
 
                 // prepareTracks_l reads and writes mActiveTracks, and returns
                 // the pending set of tracks to remove via Vector 'tracksToRemove'.  The caller
                 // is responsible for clearing or destroying this Vector later on, when it
                 // is safe to do so. That will drop the final ref count and destroy the tracks.
-    virtual     mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) = 0;
-                void        removeTracks_l(const Vector<sp<IAfTrack>>& tracksToRemove);
-                status_t    handleVoipVolume_l(float *volume);
+    virtual mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove)
+            REQUIRES(mutex(), ThreadBase_ThreadLoop) = 0;
+
+    void removeTracks_l(const Vector<sp<IAfTrack>>& tracksToRemove) REQUIRES(mutex());
+    status_t handleVoipVolume_l(float *volume) REQUIRES(mutex());
 
     // StreamOutHalInterfaceCallback implementation
     virtual     void        onWriteReady();
@@ -877,9 +919,9 @@
 protected:
 
     virtual     bool        waitingAsyncCallback();
-    virtual     bool        waitingAsyncCallback_l();
-    virtual     bool        shouldStandby_l();
-    virtual     void        onAddNewTrack_l();
+    virtual bool waitingAsyncCallback_l() REQUIRES(mutex());
+    virtual bool shouldStandby_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
+    virtual void onAddNewTrack_l() REQUIRES(mutex());
 public:  // AsyncCallbackThread
                 void        onAsyncError(); // error reported by AsyncCallbackThread
 protected:
@@ -888,20 +930,21 @@
             const std::basic_string<uint8_t>& metadataBs) final;
 
     // ThreadBase virtuals
-    virtual     void        preExit();
+    void preExit() final EXCLUDES_ThreadBase_Mutex;
 
     virtual     bool        keepWakeLock() const { return true; }
-    virtual     void        acquireWakeLock_l() {
+    virtual void acquireWakeLock_l() REQUIRES(mutex()) {
                                 ThreadBase::acquireWakeLock_l();
-                                mActiveTracks.updatePowerState(this, true /* force */);
+        mActiveTracks.updatePowerState_l(this, true /* force */);
                             }
 
-    virtual     void        checkOutputStageEffects() {}
+    virtual void checkOutputStageEffects()
+            REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex {}
     virtual     void        setHalLatencyMode_l() {}
 
 
-    void dumpInternals_l(int fd, const Vector<String16>& args) override;
-    void dumpTracks_l(int fd, const Vector<String16>& args) final;
+    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
+    void dumpTracks_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());
 
 public:
 
@@ -910,15 +953,15 @@
                 // return estimated latency in milliseconds, as reported by HAL
     uint32_t latency() const final;
                 // same, but lock must already be held
-    uint32_t latency_l() const final;
+    uint32_t latency_l() const final /* REQUIRES(mutex()) */;  // NO_THREAD_SAFETY_ANALYSIS
 
                 // VolumeInterface
     void setMasterVolume(float value) final;
-    void setMasterBalance(float balance) override;
+    void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex;
     void setMasterMute(bool muted) final;
-    void setStreamVolume(audio_stream_type_t stream, float value) final;
-    void setStreamMute(audio_stream_type_t stream, bool muted) final;
-    float streamVolume(audio_stream_type_t stream) const final;
+    void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
+    void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
+    float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
     void setVolumeForOutput_l(float left, float right) const final;
 
     sp<IAfTrack> createTrack_l(
@@ -949,56 +992,72 @@
         return mActiveTracks.indexOf(track) >= 0;
     }
 
-    AudioStreamOut* getOutput_l() const final { return mOutput; }
-    AudioStreamOut* getOutput() const final;
-    AudioStreamOut* clearOutput() final;
+    AudioStreamOut* getOutput_l() const final REQUIRES(mutex()) { return mOutput; }
+    AudioStreamOut* getOutput() const final EXCLUDES_ThreadBase_Mutex;
+    AudioStreamOut* clearOutput() final EXCLUDES_ThreadBase_Mutex;
+
+    // NO_THREAD_SAFETY_ANALYSIS -- probably needs a lock.
     sp<StreamHalInterface> stream() const final;
 
-                // a very large number of suspend() will eventually wraparound, but unlikely
-    void suspend() final { (void) android_atomic_inc(&mSuspended); }
-    void restore() final
-                                {
-                                    // if restore() is done without suspend(), get back into
-                                    // range so that the next suspend() will operate correctly
-                                    if (android_atomic_dec(&mSuspended) <= 0) {
-                                        android_atomic_release_store(0, &mSuspended);
-                                    }
-                                }
-    bool isSuspended() const final
-                                { return android_atomic_acquire_load(&mSuspended) > 0; }
+    // suspend(), restore(), and isSuspended() are implemented atomically.
+    void suspend() final { ++mSuspended; }
+    void restore() final {
+        // if restore() is done without suspend(), get back into
+        // range so that the next suspend() will operate correctly
+        while (true) {
+            int32_t suspended = mSuspended;
+            if (suspended <= 0) {
+                ALOGW("%s: invalid mSuspended %d <= 0", __func__, suspended);
+                return;
+            }
+            const int32_t desired = suspended - 1;
+            if (mSuspended.compare_exchange_weak(suspended, desired)) return;
+        }
+    }
+    bool isSuspended() const final { return mSuspended > 0; }
 
-    String8 getParameters(const String8& keys);
-    void ioConfigChanged(audio_io_config_event_t event, pid_t pid = 0,
+    String8 getParameters(const String8& keys) EXCLUDES_ThreadBase_Mutex;
+
+    // Hold either the AudioFlinger::mutex or the ThreadBase::mutex
+    void ioConfigChanged_l(audio_io_config_event_t event, pid_t pid = 0,
             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
-    status_t getRenderPosition(uint32_t* halFrames, uint32_t* dspFrames) const final;
+    status_t getRenderPosition(uint32_t* halFrames, uint32_t* dspFrames) const final
+            EXCLUDES_ThreadBase_Mutex;
                 // Consider also removing and passing an explicit mMainBuffer initialization
                 // parameter to AF::IAfTrack::Track().
     float* sinkBuffer() const final {
                     return reinterpret_cast<float *>(mSinkBuffer); };
 
-    void detachAuxEffect_l(int effectId) final;
+    void detachAuxEffect_l(int effectId) final REQUIRES(mutex());
 
-    status_t attachAuxEffect(const sp<IAfTrack>& track, int EffectId) final;
-    status_t attachAuxEffect_l(const sp<IAfTrack>& track, int EffectId) final;
+    status_t attachAuxEffect(const sp<IAfTrack>& track, int EffectId) final
+            EXCLUDES_ThreadBase_Mutex;
+    status_t attachAuxEffect_l(const sp<IAfTrack>& track, int EffectId) final REQUIRES(mutex());
 
-    status_t addEffectChain_l(const sp<IAfEffectChain>& chain) final;
-    size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) final;
-    uint32_t hasAudioSession_l(audio_session_t sessionId) const final {
+    status_t addEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
+    size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
+    uint32_t hasAudioSession_l(audio_session_t sessionId) const final REQUIRES(mutex()) {
                             return ThreadBase::hasAudioSession_l(sessionId, mTracks);
                         }
-    product_strategy_t getStrategyForSession_l(audio_session_t sessionId) const final;
+    product_strategy_t getStrategyForSession_l(audio_session_t sessionId) const final
+            REQUIRES(mutex());
 
 
-    status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) final;
+    status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) final
+            EXCLUDES_ThreadBase_Mutex;
+    // could be static.
     bool isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const final;
 
-                // called with AudioFlinger lock held
-    bool invalidateTracks_l(audio_stream_type_t streamType) final;
-    bool invalidateTracks_l(std::set<audio_port_handle_t>& portIds) final;
+    // Does this require the AudioFlinger mutex as well?
+    bool invalidateTracks_l(audio_stream_type_t streamType) final
+            REQUIRES(mutex());
+    bool invalidateTracks_l(std::set<audio_port_handle_t>& portIds) final
+            REQUIRES(mutex());
     void invalidateTracks(audio_stream_type_t streamType) override;
                 // Invalidate tracks by a set of port ids. The port id will be removed from
                 // the given set if the corresponding track is found and invalidated.
-    void invalidateTracks(std::set<audio_port_handle_t>& portIds) override;
+    void invalidateTracks(std::set<audio_port_handle_t>& portIds) override
+            EXCLUDES_ThreadBase_Mutex;
 
     size_t frameCount() const final { return mNormalFrameCount; }
 
@@ -1006,30 +1065,33 @@
                     return mMixerChannelMask;
                 }
 
-    status_t getTimestamp_l(AudioTimestamp& timestamp) final;
+    status_t getTimestamp_l(AudioTimestamp& timestamp) final
+            REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
-    void addPatchTrack(const sp<IAfPatchTrack>& track) final;
-    void deletePatchTrack(const sp<IAfPatchTrack>& track) final;
+    void addPatchTrack(const sp<IAfPatchTrack>& track) final EXCLUDES_ThreadBase_Mutex;
+    void deletePatchTrack(const sp<IAfPatchTrack>& track) final EXCLUDES_ThreadBase_Mutex;
 
+    // NO_THREAD_SAFETY_ANALYSIS - fix this to use atomics.
     void toAudioPortConfig(struct audio_port_config* config) final;
 
                 // Return the asynchronous signal wait time.
-    int64_t computeWaitTimeNs_l() const override { return INT64_MAX; }
+    int64_t computeWaitTimeNs_l() const override REQUIRES(mutex()) { return INT64_MAX; }
                 // returns true if the track is allowed to be added to the thread.
     bool isTrackAllowed_l(
                                     audio_channel_mask_t channelMask __unused,
                                     audio_format_t format __unused,
                                     audio_session_t sessionId __unused,
-                                    uid_t uid) const override {
+            uid_t uid) const override REQUIRES(mutex()) {
                                 return trackCountForUid_l(uid) < PlaybackThread::kMaxTracksPerUid
                                        && mTracks.size() < PlaybackThread::kMaxTracks;
                             }
 
-    bool isTimestampCorrectionEnabled() const final {
-                                return audio_is_output_devices(mTimestampCorrectedDevice)
-                                        && outDeviceTypes().count(mTimestampCorrectedDevice) != 0;
+    bool isTimestampCorrectionEnabled_l() const final REQUIRES(mutex()) {
+        return audio_is_output_devices(mTimestampCorrectedDevice)
+                && outDeviceTypes_l().count(mTimestampCorrectedDevice) != 0;
                             }
 
+    // NO_THREAD_SAFETY_ANALYSIS - fix this to be atomic.
     bool isStreamInitialized() const final {
                                 return !(mOutput == nullptr || mOutput->stream == nullptr);
                             }
@@ -1046,12 +1108,12 @@
                     return (mHapticChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE;
                 }
 
-    void setDownStreamPatch(const struct audio_patch* patch) final {
-                    std::lock_guard _l(mutex());
+    void setDownStreamPatch(const struct audio_patch* patch) final EXCLUDES_ThreadBase_Mutex {
+        audio_utils::lock_guard _l(mutex());
                     mDownStreamPatch = *patch;
                 }
 
-    IAfTrack* getTrackById_l(audio_port_handle_t trackId) final;
+    IAfTrack* getTrackById_l(audio_port_handle_t trackId) final REQUIRES(mutex());
 
     bool hasMixer() const final {
                     return mType == MIXER || mType == DUPLICATING || mType == SPATIALIZER;
@@ -1074,19 +1136,19 @@
     void stopMelComputation_l() override
             REQUIRES(audio_utils::AudioFlinger_Mutex);
 
-    void setStandby() final {
-                    std::lock_guard _l(mutex());
+    void setStandby() final EXCLUDES_ThreadBase_Mutex {
+        audio_utils::lock_guard _l(mutex());
                     setStandby_l();
                 }
 
-    void setStandby_l() final {
+    void setStandby_l() final REQUIRES(mutex()) {
                     mStandby = true;
                     mHalStarted = false;
                     mKernelPositionOnStandby =
                         mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
                 }
 
-    bool waitForHalStart() final {
+    bool waitForHalStart() final EXCLUDES_ThreadBase_Mutex {
                     audio_utils::unique_lock _l(mutex());
                     static const nsecs_t kWaitHalTimeoutNs = seconds(2);
                     nsecs_t endWaitTimetNs = systemTime() + kWaitHalTimeoutNs;
@@ -1104,10 +1166,17 @@
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
 
-    bool                            mThreadThrottle;     // throttle the thread processing
-    uint32_t                        mThreadThrottleTimeMs; // throttle time for MIXER threads
-    uint32_t                        mThreadThrottleEndMs;  // notify once per throttling
-    uint32_t                        mHalfBufferMs;       // half the buffer size in milliseconds
+    // throttle the thread processing
+    bool mThreadThrottle GUARDED_BY(ThreadBase_ThreadLoop);
+
+    // throttle time for MIXER threads - atomic as read by dump()
+    std::atomic<uint32_t> mThreadThrottleTimeMs;
+
+    // notify once per throttling
+    uint32_t mThreadThrottleEndMs GUARDED_BY(ThreadBase_ThreadLoop);
+
+    // half the buffer size in milliseconds
+    uint32_t mHalfBufferMs GUARDED_BY(ThreadBase_ThreadLoop);
 
     void*                           mSinkBuffer;         // frame size aligned sink buffer
 
@@ -1127,21 +1196,21 @@
     // buffer before downmixing or data conversion to the sink buffer.
 
     // Set to "true" to enable the Mixer Buffer otherwise mixer output goes to sink buffer.
-    bool                            mMixerBufferEnabled;
+    bool mMixerBufferEnabled GUARDED_BY(ThreadBase_ThreadLoop);
 
     // Storage, 32 byte aligned (may make this alignment a requirement later).
     // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
-    void*                           mMixerBuffer;
+    void* mMixerBuffer GUARDED_BY(ThreadBase_ThreadLoop);
 
     // Size of mMixerBuffer in bytes: mNormalFrameCount * #channels * sampsize.
-    size_t                          mMixerBufferSize;
+    size_t mMixerBufferSize GUARDED_BY(ThreadBase_ThreadLoop);
 
     // The audio format of mMixerBuffer. Set to AUDIO_FORMAT_PCM_(FLOAT|16_BIT) only.
-    audio_format_t                  mMixerBufferFormat;
+    audio_format_t mMixerBufferFormat GUARDED_BY(ThreadBase_ThreadLoop);
 
     // An internal flag set to true by MixerThread::prepareTracks_l()
     // when mMixerBuffer contains valid data after mixing.
-    bool                            mMixerBufferValid;
+    bool mMixerBufferValid GUARDED_BY(ThreadBase_ThreadLoop);
 
     // Effects Buffer (mEffectsBuffer*)
     //
@@ -1150,46 +1219,49 @@
     // to the sink buffer.
 
     // Set to "true" to enable the Effects Buffer otherwise effects output goes to sink buffer.
-    bool                            mEffectBufferEnabled;
+    bool mEffectBufferEnabled;
+    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()
 
     // Storage, 32 byte aligned (may make this alignment a requirement later).
     // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
-    void*                           mEffectBuffer;
+    void* mEffectBuffer;
+    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()
 
     // Size of mEffectsBuffer in bytes: mNormalFrameCount * #channels * sampsize.
-    size_t                          mEffectBufferSize;
+    size_t mEffectBufferSize;
+    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()
 
     // The audio format of mEffectsBuffer. Set to AUDIO_FORMAT_PCM_16_BIT only.
-    audio_format_t                  mEffectBufferFormat;
+    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()
+    audio_format_t mEffectBufferFormat;
 
     // An internal flag set to true by MixerThread::prepareTracks_l()
     // when mEffectsBuffer contains valid data after mixing.
     //
     // When this is set, all mixer data is routed into the effects buffer
     // for any processing (including output processing).
-    bool                            mEffectBufferValid;
+    bool mEffectBufferValid GUARDED_BY(ThreadBase_ThreadLoop);
 
     // Set to "true" to enable when data has already copied to sink
-    bool                            mHasDataCopiedToSinkBuffer = false;
+    bool mHasDataCopiedToSinkBuffer GUARDED_BY(ThreadBase_ThreadLoop) = false;
 
     // Frame size aligned buffer used as input and output to all post processing effects
     // except the Spatializer in a SPATIALIZER thread. Non spatialized tracks are mixed into
     // this buffer so that post processing effects can be applied.
-    void*                           mPostSpatializerBuffer = nullptr;
+    void* mPostSpatializerBuffer GUARDED_BY(mutex()) = nullptr;
 
     // Size of mPostSpatializerBuffer in bytes
-    size_t                          mPostSpatializerBufferSize;
-
+    size_t mPostSpatializerBufferSize GUARDED_BY(mutex());
 
     // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
     // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
     // concurrent use of both of them, so Audio Policy Service suspends one of the threads to
     // workaround that restriction.
     // 'volatile' means accessed via atomic operations and no lock.
-    volatile int32_t                mSuspended;
+    std::atomic<int32_t> mSuspended;
 
     int64_t                         mBytesWritten;
-    std::atomic<int64_t>            mFramesWritten; // not reset on standby
+    std::atomic<int64_t> mFramesWritten;  // not reset on standby
     int64_t                         mLastFramesWritten = -1; // track changes in timestamp
                                                              // server frames written.
     int64_t                         mSuspendedFrames; // not reset on standby
@@ -1204,8 +1276,8 @@
     // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a
     // PlaybackThread needs to find out if master-muted, it checks it's local
     // copy rather than the one in AudioFlinger.  This optimization saves a lock.
-    bool                            mMasterMute;
-                void        setMasterMute_l(bool muted) { mMasterMute = muted; }
+    bool mMasterMute GUARDED_BY(mutex());
+    void setMasterMute_l(bool muted) REQUIRES(mutex()) { mMasterMute = muted; }
 
                 auto discontinuityForStandbyOrFlush() const { // call on threadLoop or with lock.
                     return ((mType == DIRECT && !audio_is_linear_pcm(mFormat))
@@ -1224,24 +1296,28 @@
     // No sleep in standby mode; waits on a condition
 
     // Code snippets that are temporarily lifted up out of threadLoop() until the merge
-    virtual void checkSilentMode_l() final;  // consider unification with MMapThread
+
+    // consider unification with MMapThread
+    virtual void checkSilentMode_l() final REQUIRES(mutex());
 
     // Non-trivial for DUPLICATING only
-    virtual     void        saveOutputTracks() { }
-    virtual     void        clearOutputTracks() { }
+    virtual void saveOutputTracks() REQUIRES(ThreadBase_ThreadLoop) {}
+    virtual void clearOutputTracks() REQUIRES(ThreadBase_ThreadLoop) {}
 
     // Cache various calculated values, at threadLoop() entry and after a parameter change
-    virtual     void        cacheParameters_l();
+    virtual void cacheParameters_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
                 void        setCheckOutputStageEffects() override {
                                 mCheckOutputStageEffects.store(true);
                             }
 
-    virtual     uint32_t    correctLatency_l(uint32_t latency) const;
+    virtual uint32_t correctLatency_l(uint32_t latency) const REQUIRES(mutex());
 
     virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
-                                   audio_patch_handle_t *handle);
-    virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
+            audio_patch_handle_t *handle) REQUIRES(mutex());
+    virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle)
+            REQUIRES(mutex());
 
+    // NO_THREAD_SAFETY_ANALYSIS - fix this to use atomics
     bool usesHwAvSync() const final { return mType == DIRECT && mOutput != nullptr
                                     && mHwSupportsPause
                                     && (mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }
@@ -1249,22 +1325,23 @@
                 uint32_t    trackCountForUid_l(uid_t uid) const;
 
                 void        invalidateTracksForAudioSession_l(
-    audio_session_t sessionId) const override {
+            audio_session_t sessionId) const override REQUIRES(mutex()) {
                                 ThreadBase::invalidateTracksForAudioSession_l(sessionId, mTracks);
                             }
 
     DISALLOW_COPY_AND_ASSIGN(PlaybackThread);
 
-    status_t addTrack_l(const sp<IAfTrack>& track) final;
-    bool destroyTrack_l(const sp<IAfTrack>& track) final;
+    status_t addTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex());
+    bool destroyTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex());
 
-    void        removeTrack_l(const sp<IAfTrack>& track);
+    void removeTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex());
 
-    void        readOutputParameters_l();
-    MetadataUpdate          updateMetadata_l() final;
-    virtual void sendMetadataToBackend_l(const StreamOutHalInterface::SourceMetadata& metadata);
+    void readOutputParameters_l() REQUIRES(mutex());
+    MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
+    virtual void sendMetadataToBackend_l(const StreamOutHalInterface::SourceMetadata& metadata)
+            REQUIRES(mutex()) ;
 
-    void        collectTimestamps_l();
+    void collectTimestamps_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
     // The Tracks class manages tracks added and removed from the Thread.
     template <typename T>
@@ -1340,17 +1417,17 @@
     uint32_t                        mSleepTimeUs;
 
     // mixer status returned by prepareTracks_l()
-    mixer_state                     mMixerStatus; // current cycle
+    mixer_state mMixerStatus GUARDED_BY(ThreadBase_ThreadLoop); // current cycle
                                                   // previous cycle when in prepareTracks_l()
-    mixer_state                     mMixerStatusIgnoringFastTracks;
+    mixer_state mMixerStatusIgnoringFastTracks GUARDED_BY(ThreadBase_ThreadLoop);
                                                   // FIXME or a separate ready state per track
 
     // FIXME move these declarations into the specific sub-class that needs them
     // MIXER only
-    uint32_t                        sleepTimeShift;
+    uint32_t sleepTimeShift GUARDED_BY(ThreadBase_ThreadLoop);
 
     // same as AudioFlinger::mStandbyTimeInNsecs except for DIRECT which uses a shorter value
-    nsecs_t                         mStandbyDelayNs;
+    nsecs_t mStandbyDelayNs;  // GUARDED_BY(mutex());
 
     // MIXER only
     nsecs_t                         maxPeriod;
@@ -1358,8 +1435,8 @@
     // DUPLICATING only
     uint32_t                        writeFrames;
 
-    size_t                          mBytesRemaining;
-    size_t                          mCurrentWriteLength;
+    size_t mBytesRemaining GUARDED_BY(ThreadBase_ThreadLoop);
+    size_t mCurrentWriteLength GUARDED_BY(ThreadBase_ThreadLoop);
     bool                            mUseAsyncWrite;
     // mWriteAckSequence contains current write sequence on bits 31-1. The write sequence is
     // incremented each time a write(), a flush() or a standby() occurs.
@@ -1412,7 +1489,7 @@
 
 protected:
                 // accessed by both binder threads and within threadLoop(), lock on mutex needed
-     uint32_t& fastTrackAvailMask_l() final { return mFastTrackAvailMask; }
+     uint32_t& fastTrackAvailMask_l() final REQUIRES(mutex()) { return mFastTrackAvailMask; }
      uint32_t mFastTrackAvailMask;  // bit i set if fast track [i] is available
                 bool        mHwSupportsPause;
                 bool        mHwPaused;
@@ -1481,18 +1558,20 @@
 
     // Thread virtuals
 
-    bool checkForNewParameter_l(const String8& keyValuePair, status_t& status) final;
+    bool checkForNewParameter_l(const String8& keyValuePair, status_t& status) final
+            REQUIRES(mutex());
 
     bool isTrackAllowed_l(
                                     audio_channel_mask_t channelMask, audio_format_t format,
-                                    audio_session_t sessionId, uid_t uid) const final;
+            audio_session_t sessionId, uid_t uid) const final REQUIRES(mutex());
 protected:
-    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) override;
+    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) override
+            REQUIRES(mutex(), ThreadBase_ThreadLoop);
     uint32_t idleSleepTimeUs() const final;
     uint32_t suspendSleepTimeUs() const final;
-    void cacheParameters_l() override;
+    void cacheParameters_l() override REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
-    void acquireWakeLock_l() final {
+    void acquireWakeLock_l() final REQUIRES(mutex()) {
         PlaybackThread::acquireWakeLock_l();
         if (hasFastMixer()) {
             mFastMixer->setBoottimeOffset(
@@ -1500,18 +1579,19 @@
         }
     }
 
-                void        dumpInternals_l(int fd, const Vector<String16>& args) override;
+    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
 
     // threadLoop snippets
-    ssize_t threadLoop_write() override;
-    void threadLoop_standby() override;
-    void threadLoop_mix() override;
-    void threadLoop_sleepTime() override;
-    uint32_t correctLatency_l(uint32_t latency) const final;
+    ssize_t threadLoop_write() override REQUIRES(ThreadBase_ThreadLoop);
+    void threadLoop_standby() override REQUIRES(ThreadBase_ThreadLoop);
+    void threadLoop_mix() override REQUIRES(ThreadBase_ThreadLoop);
+    void threadLoop_sleepTime() override REQUIRES(ThreadBase_ThreadLoop);
+    uint32_t correctLatency_l(uint32_t latency) const final REQUIRES(mutex());
 
     status_t createAudioPatch_l(
-            const struct audio_patch* patch, audio_patch_handle_t* handle) final;
-    status_t releaseAudioPatch_l(const audio_patch_handle_t handle) final;
+            const struct audio_patch* patch, audio_patch_handle_t* handle)
+            final REQUIRES(mutex());
+    status_t releaseAudioPatch_l(const audio_patch_handle_t handle) final REQUIRES(mutex());
 
                 AudioMixer* mAudioMixer;    // normal mixer
 
@@ -1540,7 +1620,7 @@
 
                 // accessible only within the threadLoop(), no locks required
                 //          mFastMixer->sq()    // for mutating and pushing state
-                int32_t     mFastMixerFutex;    // for cold idle
+    int32_t mFastMixerFutex GUARDED_BY(ThreadBase_ThreadLoop);  // for cold idle
 
                 std::atomic_bool mMasterMono;
 public:
@@ -1550,8 +1630,9 @@
                               return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
                             }
 
-                status_t    threadloop_getHalTimestamp_l(
-                                    ExtendedTimestamp *timestamp) const override {
+    status_t threadloop_getHalTimestamp_l(
+            ExtendedTimestamp *timestamp) const override
+            REQUIRES(mutex(), ThreadBase_ThreadLoop) {
                                 if (mNormalSink.get() != nullptr) {
                                     return mNormalSink->getTimestamp(*timestamp);
                                 }
@@ -1575,16 +1656,16 @@
                 // and blending without limiter is idempotent but inefficient to do twice.
     virtual     bool       requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
 
-                void       setMasterBalance(float balance) override {
+    void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex {
                                mMasterBalance.store(balance);
                                if (hasFastMixer()) {
                                    mFastMixer->setMasterBalance(balance);
                                }
                            }
 
-                void       updateHalSupportedLatencyModes_l();
-                void       onHalLatencyModesChanged_l() override;
-                void       setHalLatencyMode_l() override;
+    void updateHalSupportedLatencyModes_l() REQUIRES(mutex());
+    void onHalLatencyModesChanged_l() override REQUIRES(mutex());
+    void setHalLatencyMode_l() override REQUIRES(mutex());
 };
 
 class DirectOutputThread : public PlaybackThread, public virtual IAfDirectOutputThread {
@@ -1599,35 +1680,36 @@
                        const audio_offload_info_t& offloadInfo)
         : DirectOutputThread(afThreadCallback, output, id, DIRECT, systemReady, offloadInfo) { }
 
-    virtual                 ~DirectOutputThread();
+    ~DirectOutputThread() override;
 
     status_t selectPresentation(int presentationId, int programId) final;
 
     // Thread virtuals
 
     virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
-                                                   status_t& status);
+            status_t& status) REQUIRES(mutex());
 
-                void        flushHw_l() override;
+    void flushHw_l() override REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
-                void        setMasterBalance(float balance) override;
+    void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex;
 
 protected:
     virtual     uint32_t    activeSleepTimeUs() const;
     virtual     uint32_t    idleSleepTimeUs() const;
     virtual     uint32_t    suspendSleepTimeUs() const;
-    virtual     void        cacheParameters_l();
+    virtual void cacheParameters_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
-                void        dumpInternals_l(int fd, const Vector<String16>& args) override;
+    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
 
     // threadLoop snippets
-    virtual     mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove);
-    virtual     void        threadLoop_mix();
-    virtual     void        threadLoop_sleepTime();
-    virtual     void        threadLoop_exit();
-    virtual     bool        shouldStandby_l();
+    virtual mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove)
+            REQUIRES(mutex(), ThreadBase_ThreadLoop);
+    virtual void threadLoop_mix() REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_sleepTime() REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_exit() REQUIRES(ThreadBase_ThreadLoop);
+    virtual bool shouldStandby_l() REQUIRES(mutex());
 
-    virtual     void        onAddNewTrack_l();
+    virtual void onAddNewTrack_l() REQUIRES(mutex());
 
     const       audio_offload_info_t mOffloadInfo;
 
@@ -1637,7 +1719,7 @@
     DirectOutputThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
                        audio_io_handle_t id, ThreadBase::type_t type, bool systemReady,
                        const audio_offload_info_t& offloadInfo);
-    void processVolume_l(IAfTrack *track, bool lastTrack);
+    void processVolume_l(IAfTrack *track, bool lastTrack) REQUIRES(mutex());
     bool isTunerStream() const { return (mOffloadInfo.content_id > 0); }
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -1652,7 +1734,7 @@
 public:
     virtual     bool        hasFastMixer() const { return false; }
 
-    virtual     int64_t     computeWaitTimeNs_l() const override;
+    virtual int64_t computeWaitTimeNs_l() const override REQUIRES(mutex());
 
     status_t    threadloop_getHalTimestamp_l(ExtendedTimestamp *timestamp) const override {
                     // For DIRECT and OFFLOAD threads, query the output sink directly.
@@ -1679,19 +1761,20 @@
                   audio_io_handle_t id, bool systemReady,
                   const audio_offload_info_t& offloadInfo);
     virtual                 ~OffloadThread() {};
-                void        flushHw_l() override;
+    void flushHw_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
 protected:
     // threadLoop snippets
-    virtual     mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove);
-    virtual     void        threadLoop_exit();
+    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) final
+            REQUIRES(mutex(), ThreadBase_ThreadLoop);
+    void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
 
-    virtual     bool        waitingAsyncCallback();
-    virtual     bool        waitingAsyncCallback_l();
-    virtual     void        invalidateTracks(audio_stream_type_t streamType);
-                void        invalidateTracks(std::set<audio_port_handle_t>& portIds) override;
+    bool waitingAsyncCallback() final;
+    bool waitingAsyncCallback_l() final REQUIRES(mutex());
+    void invalidateTracks(audio_stream_type_t streamType) final EXCLUDES_ThreadBase_Mutex;
+    void invalidateTracks(std::set<audio_port_handle_t>& portIds) final EXCLUDES_ThreadBase_Mutex;
 
-    virtual     bool        keepWakeLock() const { return (mKeepWakeLock || (mDrainSequence & 1)); }
+    bool keepWakeLock() const final { return (mKeepWakeLock || (mDrainSequence & 1)); }
 
 private:
     size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
@@ -1704,10 +1787,10 @@
     explicit AsyncCallbackThread(const wp<PlaybackThread>& playbackThread);
 
     // Thread virtuals
-    virtual bool        threadLoop();
+    bool threadLoop() final;
 
     // RefBase
-    virtual void        onFirstRef();
+    void onFirstRef() final;
 
             void        exit();
             void        setWriteBlocked(uint32_t sequence);
@@ -1730,7 +1813,9 @@
     mutable audio_utils::mutex mMutex;
     bool                       mAsyncError;
 
-    audio_utils::mutex& mutex() const { return mMutex; }
+    audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::AsyncCallbackThread_Mutex) {
+        return mMutex;
+    }
 };
 
 class DuplicatingThread : public MixerThread, public IAfDuplicatingThread {
@@ -1745,41 +1830,42 @@
     }
 
     // Thread virtuals
-    void addOutputTrack(IAfPlaybackThread* thread) final;
-    void removeOutputTrack(IAfPlaybackThread* thread) final;
+    void addOutputTrack(IAfPlaybackThread* thread) final EXCLUDES_ThreadBase_Mutex;
+    void removeOutputTrack(IAfPlaybackThread* thread) final EXCLUDES_ThreadBase_Mutex;
     uint32_t waitTimeMs() const final { return mWaitTimeMs; }
 
                 void        sendMetadataToBackend_l(
-                        const StreamOutHalInterface::SourceMetadata& metadata) override;
+            const StreamOutHalInterface::SourceMetadata& metadata) final REQUIRES(mutex());
 protected:
     virtual     uint32_t    activeSleepTimeUs() const;
-                void        dumpInternals_l(int fd, const Vector<String16>& args) override;
+    void dumpInternals_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());
 
 private:
-                bool        outputsReady();
+    bool outputsReady() REQUIRES(ThreadBase_ThreadLoop);
 protected:
     // threadLoop snippets
-    virtual     void        threadLoop_mix();
-    virtual     void        threadLoop_sleepTime();
-    virtual     ssize_t     threadLoop_write();
-    virtual     void        threadLoop_standby();
-    virtual     void        cacheParameters_l();
+    void threadLoop_mix() final REQUIRES(ThreadBase_ThreadLoop);
+    void threadLoop_sleepTime() final REQUIRES(ThreadBase_ThreadLoop);
+    ssize_t threadLoop_write() final REQUIRES(ThreadBase_ThreadLoop);
+    void threadLoop_standby() final REQUIRES(ThreadBase_ThreadLoop);
+    void cacheParameters_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
 
 private:
     // called from threadLoop, addOutputTrack, removeOutputTrack
-    virtual     void        updateWaitTime_l();
+    void updateWaitTime_l() REQUIRES(mutex());
 protected:
-    virtual     void        saveOutputTracks();
-    virtual     void        clearOutputTracks();
+    void saveOutputTracks() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
+    void clearOutputTracks() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
 private:
 
                 uint32_t    mWaitTimeMs;
-    SortedVector <sp<IAfOutputTrack>>  outputTracks;
-    SortedVector <sp<IAfOutputTrack>>  mOutputTracks;
+    // NO_THREAD_SAFETY_ANALYSIS  GUARDED_BY(ThreadBase_ThreadLoop)
+    SortedVector <sp<IAfOutputTrack>> outputTracks;
+    SortedVector <sp<IAfOutputTrack>> mOutputTracks GUARDED_BY(mutex());
 public:
     virtual     bool        hasFastMixer() const { return false; }
                 status_t    threadloop_getHalTimestamp_l(
-                                    ExtendedTimestamp *timestamp) const override {
+            ExtendedTimestamp *timestamp) const override REQUIRES(mutex()) {
         if (mOutputTracks.size() > 0) {
             // forward the first OutputTrack's kernel information for timestamp.
             const ExtendedTimestamp trackTimestamp =
@@ -1806,11 +1892,12 @@
 
     bool hasFastMixer() const final { return false; }
 
-    status_t setRequestedLatencyMode(audio_latency_mode_t mode) final;
+    status_t setRequestedLatencyMode(audio_latency_mode_t mode) final EXCLUDES_ThreadBase_Mutex;
 
 protected:
-    void checkOutputStageEffects() final;
-    void setHalLatencyMode_l() final;
+    void checkOutputStageEffects() final
+            REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
+    void setHalLatencyMode_l() final REQUIRES(mutex());
 
 private:
             // Do not request a specific mode by default
@@ -1836,15 +1923,15 @@
     ~RecordThread() override;
 
     // no addTrack_l ?
-    void destroyTrack_l(const sp<IAfRecordTrack>& track) final;
-    void removeTrack_l(const sp<IAfRecordTrack>& track) final;
+    void destroyTrack_l(const sp<IAfRecordTrack>& track) final REQUIRES(mutex());
+    void removeTrack_l(const sp<IAfRecordTrack>& track) final REQUIRES(mutex());
 
     // Thread virtuals
-    bool threadLoop() final;
-    void preExit() final;
+    bool threadLoop() final REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
+    void preExit() final EXCLUDES_ThreadBase_Mutex;
 
     // RefBase
-    void onFirstRef() final;
+    void onFirstRef() final EXCLUDES_ThreadBase_Mutex;
 
     status_t initCheck() const final { return mInput == nullptr ? NO_INIT : NO_ERROR; }
 
@@ -1868,15 +1955,15 @@
                     status_t *status /*non-NULL*/,
                     audio_port_handle_t portId,
                     int32_t maxSharedAudioHistoryMs) final
-            REQUIRES(audio_utils::AudioFlinger_Mutex);
+            REQUIRES(audio_utils::AudioFlinger_Mutex) EXCLUDES_ThreadBase_Mutex;
 
             status_t start(IAfRecordTrack* recordTrack,
                               AudioSystem::sync_event_t event,
-                              audio_session_t triggerSession) final;
+            audio_session_t triggerSession) final EXCLUDES_ThreadBase_Mutex;
 
             // ask the thread to stop the specified track, and
             // return true if the caller should then do it's part of the stopping process
-    bool stop(IAfRecordTrack* recordTrack) final;
+    bool stop(IAfRecordTrack* recordTrack) final EXCLUDES_ThreadBase_Mutex;
     AudioStreamIn* getInput() const final { return mInput; }
     AudioStreamIn* clearInput() final;
 
@@ -1884,27 +1971,30 @@
             virtual sp<StreamHalInterface> stream() const;
 
 
-    virtual bool        checkForNewParameter_l(const String8& keyValuePair,
-                                               status_t& status);
-    virtual void        cacheParameters_l() {}
-    virtual String8     getParameters(const String8& keys);
-    void ioConfigChanged(audio_io_config_event_t event, pid_t pid = 0,
+    virtual bool checkForNewParameter_l(const String8& keyValuePair,
+                                               status_t& status) REQUIRES(mutex());
+    virtual void cacheParameters_l() REQUIRES(mutex(), ThreadBase_ThreadLoop) {}
+    virtual String8 getParameters(const String8& keys) EXCLUDES_ThreadBase_Mutex;
+
+    // Hold either the AudioFlinger::mutex or the ThreadBase::mutex
+    void ioConfigChanged_l(audio_io_config_event_t event, pid_t pid = 0,
             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
     virtual status_t    createAudioPatch_l(const struct audio_patch *patch,
-                                           audio_patch_handle_t *handle);
-    virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
-            void        updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
-            void        resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) override;
+            audio_patch_handle_t *handle) REQUIRES(mutex());
+    virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) REQUIRES(mutex());
+    void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override
+            EXCLUDES_ThreadBase_Mutex;
+    void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) override REQUIRES(mutex());
 
-    void addPatchTrack(const sp<IAfPatchRecord>& record) final;
-    void deletePatchTrack(const sp<IAfPatchRecord>& record) final;
+    void addPatchTrack(const sp<IAfPatchRecord>& record) final EXCLUDES_ThreadBase_Mutex;
+    void deletePatchTrack(const sp<IAfPatchRecord>& record) final EXCLUDES_ThreadBase_Mutex;
 
-            void        readInputParameters_l();
-    uint32_t getInputFramesLost() const final;
+    void readInputParameters_l() REQUIRES(mutex());
+    uint32_t getInputFramesLost() const final EXCLUDES_ThreadBase_Mutex;
 
-    virtual status_t addEffectChain_l(const sp<IAfEffectChain>& chain);
-    virtual size_t removeEffectChain_l(const sp<IAfEffectChain>& chain);
-            uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+    virtual status_t addEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());
+    virtual size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());
+    uint32_t hasAudioSession_l(audio_session_t sessionId) const override REQUIRES(mutex()) {
                          return ThreadBase::hasAudioSession_l(sessionId, mTracks);
                      }
 
@@ -1913,7 +2003,8 @@
             // FIXME replace by Set [and implement Bag/Multiset for other uses].
             KeyedVector<audio_session_t, bool> sessionIds() const;
 
-            status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) override;
+    status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) override
+            EXCLUDES_ThreadBase_Mutex;
             bool     isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const override;
 
     static void syncStartEventCallback(const wp<audioflinger::SyncEvent>& event);
@@ -1922,52 +2013,55 @@
     bool hasFastCapture() const final { return mFastCapture != 0; }
     virtual void        toAudioPortConfig(struct audio_port_config *config);
 
-    virtual status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
-                                                   audio_session_t sessionId);
+    virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc,
+            audio_session_t sessionId) REQUIRES(mutex());
 
-    virtual void        acquireWakeLock_l() {
+    virtual void acquireWakeLock_l() REQUIRES(mutex()) {
                             ThreadBase::acquireWakeLock_l();
-                            mActiveTracks.updatePowerState(this, true /* force */);
+        mActiveTracks.updatePowerState_l(this, true /* force */);
                         }
 
-    void checkBtNrec() final;
+    void checkBtNrec() final EXCLUDES_ThreadBase_Mutex;
 
             // Sets the UID records silence
-    void setRecordSilenced(audio_port_handle_t portId, bool silenced) final;
+    void setRecordSilenced(audio_port_handle_t portId, bool silenced) final
+            EXCLUDES_ThreadBase_Mutex;
 
     status_t getActiveMicrophones(
-            std::vector<media::MicrophoneInfoFw>* activeMicrophones) const final;
-    status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) final;
-    status_t setPreferredMicrophoneFieldDimension(float zoom) final;
+            std::vector<media::MicrophoneInfoFw>* activeMicrophones) const final
+            EXCLUDES_ThreadBase_Mutex;
+    status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) final
+            EXCLUDES_ThreadBase_Mutex;
+    status_t setPreferredMicrophoneFieldDimension(float zoom) final EXCLUDES_ThreadBase_Mutex;
 
-            MetadataUpdate        updateMetadata_l() override;
+    MetadataUpdate updateMetadata_l() override REQUIRES(mutex());
 
     bool fastTrackAvailable() const final { return mFastTrackAvail; }
     void setFastTrackAvailable(bool available) final { mFastTrackAvail = available; }
 
-            bool        isTimestampCorrectionEnabled() const override {
+    bool isTimestampCorrectionEnabled_l() const override REQUIRES(mutex()) {
                             // checks popcount for exactly one device.
                             // Is currently disabled. Before enabling,
                             // verify compressed record timestamps.
                             return audio_is_input_device(mTimestampCorrectedDevice)
-                                    && inDeviceType() == mTimestampCorrectedDevice;
+                && inDeviceType_l() == mTimestampCorrectedDevice;
                         }
 
     status_t shareAudioHistory(const std::string& sharedAudioPackageName,
                                           audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
-            int64_t sharedAudioStartMs = -1) final;
+            int64_t sharedAudioStartMs = -1) final EXCLUDES_ThreadBase_Mutex;
             status_t    shareAudioHistory_l(const std::string& sharedAudioPackageName,
                                           audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
-                                          int64_t sharedAudioStartMs = -1);
-    void resetAudioHistory_l() final;
+            int64_t sharedAudioStartMs = -1) REQUIRES(mutex());
+    void resetAudioHistory_l() final REQUIRES(mutex());
 
     bool isStreamInitialized() const final {
                             return !(mInput == nullptr || mInput->stream == nullptr);
                         }
 
 protected:
-            void        dumpInternals_l(int fd, const Vector<String16>& args) override;
-            void        dumpTracks_l(int fd, const Vector<String16>& args) override;
+    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
+    void dumpTracks_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
 
 private:
             // Enter standby if not already in standby, and set mStandby flag
@@ -1976,10 +2070,10 @@
             // Call the HAL standby method unconditionally, and don't change mStandby flag
             void    inputStandBy();
 
-            void    checkBtNrec_l();
+    void checkBtNrec_l() REQUIRES(mutex());
 
-            int32_t getOldestFront_l();
-            void    updateFronts_l(int32_t offset);
+    int32_t getOldestFront_l() REQUIRES(mutex());
+    void updateFronts_l(int32_t offset) REQUIRES(mutex());
 
             AudioStreamIn                       *mInput;
             Source                              *mSource;
@@ -2065,88 +2159,112 @@
                                       audio_session_t sessionId,
                                       const sp<MmapStreamCallback>& callback,
                                       audio_port_handle_t deviceId,
-                                      audio_port_handle_t portId) override;
+            audio_port_handle_t portId) override EXCLUDES_ThreadBase_Mutex {
+        audio_utils::lock_guard l(mutex());
+        configure_l(attr, streamType, sessionId, callback, deviceId, portId);
+    }
 
-    void disconnect() final;
+    void configure_l(const audio_attributes_t* attr,
+            audio_stream_type_t streamType,
+            audio_session_t sessionId,
+            const sp<MmapStreamCallback>& callback,
+            audio_port_handle_t deviceId,
+            audio_port_handle_t portId) REQUIRES(mutex());
+
+    void disconnect() final EXCLUDES_ThreadBase_Mutex;
 
     // MmapStreamInterface for adapter.
-    status_t createMmapBuffer(int32_t minSizeFrames, struct audio_mmap_buffer_info* info) final;
-    status_t getMmapPosition(struct audio_mmap_position* position) const override;
+    status_t createMmapBuffer(int32_t minSizeFrames, struct audio_mmap_buffer_info* info) final
+            EXCLUDES_ThreadBase_Mutex;
+    status_t getMmapPosition(struct audio_mmap_position* position) const override
+            EXCLUDES_ThreadBase_Mutex;
     status_t start(const AudioClient& client,
                    const audio_attributes_t *attr,
-            audio_port_handle_t* handle) final;
-    status_t stop(audio_port_handle_t handle) final;
-    status_t standby() final;
-    status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const = 0;
-    status_t reportData(const void* buffer, size_t frameCount) override;
+            audio_port_handle_t* handle) final EXCLUDES_ThreadBase_Mutex;
+    status_t stop(audio_port_handle_t handle) final EXCLUDES_ThreadBase_Mutex;
+    status_t standby() final EXCLUDES_ThreadBase_Mutex;
+    status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const
+            EXCLUDES_ThreadBase_Mutex = 0;
+    status_t reportData(const void* buffer, size_t frameCount) override EXCLUDES_ThreadBase_Mutex;
 
     // RefBase
     void onFirstRef() final;
 
     // Thread virtuals
-    bool threadLoop() final;
+    bool threadLoop() final REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
 
     // Not in ThreadBase
-    virtual void threadLoop_exit() final;
-    virtual void threadLoop_standby() final;
-    virtual bool shouldStandby_l() final { return false; }
+    virtual void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
+    virtual void threadLoop_standby() final REQUIRES(ThreadBase_ThreadLoop);
+    virtual bool shouldStandby_l() final REQUIRES(mutex()){ return false; }
     virtual status_t exitStandby_l() REQUIRES(mutex());
 
     status_t initCheck() const final { return mHalStream == nullptr ? NO_INIT : NO_ERROR; }
     size_t frameCount() const final { return mFrameCount; }
-    bool checkForNewParameter_l(const String8& keyValuePair, status_t& status) final;
-    String8 getParameters(const String8& keys) final;
-    void ioConfigChanged(audio_io_config_event_t event, pid_t pid = 0,
-            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
-                void        readHalParameters_l();
-    void cacheParameters_l() final {}
+    bool checkForNewParameter_l(const String8& keyValuePair, status_t& status)
+            final REQUIRES(mutex());
+    String8 getParameters(const String8& keys) final EXCLUDES_ThreadBase_Mutex;
+    void ioConfigChanged_l(audio_io_config_event_t event, pid_t pid = 0,
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final
+            /* holds either AF::mutex or TB::mutex */;
+    void readHalParameters_l() REQUIRES(mutex());
+    void cacheParameters_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop) {}
     status_t createAudioPatch_l(
-            const struct audio_patch* patch, audio_patch_handle_t* handle) final;
-    status_t releaseAudioPatch_l(const audio_patch_handle_t handle) final;
+            const struct audio_patch* patch, audio_patch_handle_t* handle) final
+            REQUIRES(mutex());
+    status_t releaseAudioPatch_l(const audio_patch_handle_t handle) final
+            REQUIRES(mutex());
+    // NO_THREAD_SAFETY_ANALYSIS
     void toAudioPortConfig(struct audio_port_config* config) override;
 
     sp<StreamHalInterface> stream() const final { return mHalStream; }
-    status_t addEffectChain_l(const sp<IAfEffectChain>& chain) final;
-    size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) final;
+    status_t addEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
+    size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
     status_t checkEffectCompatibility_l(
-            const effect_descriptor_t *desc, audio_session_t sessionId) final;
+            const effect_descriptor_t *desc, audio_session_t sessionId) final REQUIRES(mutex());
 
-    uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+    uint32_t hasAudioSession_l(audio_session_t sessionId) const override REQUIRES(mutex()) {
                                 // Note: using mActiveTracks as no mTracks here.
                                 return ThreadBase::hasAudioSession_l(sessionId, mActiveTracks);
                             }
     status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) final;
     bool isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const final;
 
-    virtual void checkSilentMode_l() {} // cannot be const (RecordThread)
-    virtual void processVolume_l() {}
-                void        checkInvalidTracks_l();
+    virtual void checkSilentMode_l() REQUIRES(mutex()) {} // cannot be const (RecordThread)
+    virtual void processVolume_l() REQUIRES(mutex()) {}
+    void checkInvalidTracks_l() REQUIRES(mutex());
 
     // Not in ThreadBase
-    virtual audio_stream_type_t streamType() const { return AUDIO_STREAM_DEFAULT; }
-    virtual void invalidateTracks(audio_stream_type_t /* streamType */) {}
-    void invalidateTracks(std::set<audio_port_handle_t>& /* portIds */) override {}
+    virtual audio_stream_type_t streamType_l() const REQUIRES(mutex()) {
+        return AUDIO_STREAM_DEFAULT;
+    }
+    virtual void invalidateTracks(audio_stream_type_t /* streamType */)
+            EXCLUDES_ThreadBase_Mutex {}
+    void invalidateTracks(std::set<audio_port_handle_t>& /* portIds */) override
+            EXCLUDES_ThreadBase_Mutex {}
 
                 // Sets the UID records silence
     void setRecordSilenced(
-            audio_port_handle_t /* portId */, bool /* silenced */) override {}
+            audio_port_handle_t /* portId */, bool /* silenced */) override
+            EXCLUDES_ThreadBase_Mutex {}
 
     bool isStreamInitialized() const override { return false; }
 
-                void        setClientSilencedState_l(audio_port_handle_t portId, bool silenced) {
+    void setClientSilencedState_l(audio_port_handle_t portId, bool silenced) REQUIRES(mutex()) {
                                 mClientSilencedStates[portId] = silenced;
                             }
 
-                size_t      eraseClientSilencedState_l(audio_port_handle_t portId) {
+    size_t eraseClientSilencedState_l(audio_port_handle_t portId) REQUIRES(mutex()) {
                                 return mClientSilencedStates.erase(portId);
                             }
 
-                bool        isClientSilenced_l(audio_port_handle_t portId) const {
+    bool isClientSilenced_l(audio_port_handle_t portId) const REQUIRES(mutex()) {
                                 const auto it = mClientSilencedStates.find(portId);
                                 return it != mClientSilencedStates.end() ? it->second : false;
                             }
 
-                void        setClientSilencedIfExists_l(audio_port_handle_t portId, bool silenced) {
+    void setClientSilencedIfExists_l(audio_port_handle_t portId, bool silenced)
+            REQUIRES(mutex()) {
                                 const auto it = mClientSilencedStates.find(portId);
                                 if (it != mClientSilencedStates.end()) {
                                     it->second = silenced;
@@ -2154,28 +2272,28 @@
                             }
 
  protected:
-    void dumpInternals_l(int fd, const Vector<String16>& args) override;
-    void dumpTracks_l(int fd, const Vector<String16>& args) final;
+    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
+    void dumpTracks_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());
 
                 /**
                  * @brief mDeviceId  current device port unique identifier
                  */
-                audio_port_handle_t     mDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t mDeviceId GUARDED_BY(mutex()) = AUDIO_PORT_HANDLE_NONE;
 
-                audio_attributes_t      mAttr;
-                audio_session_t         mSessionId;
-                audio_port_handle_t     mPortId;
+    audio_attributes_t mAttr GUARDED_BY(mutex());
+    audio_session_t mSessionId GUARDED_BY(mutex());
+    audio_port_handle_t mPortId GUARDED_BY(mutex());
 
-                wp<MmapStreamCallback>  mCallback;
-                sp<StreamHalInterface>  mHalStream;
-                sp<DeviceHalInterface>  mHalDevice;
-                AudioHwDevice* const    mAudioHwDev;
-                ActiveTracks<IAfMmapTrack> mActiveTracks;
-                float                   mHalVolFloat;
-                std::map<audio_port_handle_t, bool> mClientSilencedStates;
+    wp<MmapStreamCallback> mCallback GUARDED_BY(mutex());
+    sp<StreamHalInterface> mHalStream; // NO_THREAD_SAFETY_ANALYSIS
+    sp<DeviceHalInterface> mHalDevice GUARDED_BY(mutex());
+    AudioHwDevice* const mAudioHwDev GUARDED_BY(mutex());
+    ActiveTracks<IAfMmapTrack> mActiveTracks GUARDED_BY(mutex());
+    float mHalVolFloat GUARDED_BY(mutex());
+    std::map<audio_port_handle_t, bool> mClientSilencedStates GUARDED_BY(mutex());
 
-                int32_t                 mNoCallbackWarningCount;
-     static     constexpr int32_t       kMaxNoCallbackWarnings = 5;
+    int32_t mNoCallbackWarningCount GUARDED_BY(mutex());
+    static constexpr int32_t kMaxNoCallbackWarnings = 5;
 };
 
 class MmapPlaybackThread : public MmapThread, public IAfMmapPlaybackThread,
@@ -2193,28 +2311,31 @@
                                       audio_session_t sessionId,
                                       const sp<MmapStreamCallback>& callback,
                                       audio_port_handle_t deviceId,
-                                      audio_port_handle_t portId) final;
+            audio_port_handle_t portId) final EXCLUDES_ThreadBase_Mutex;
 
-    AudioStreamOut* clearOutput() final;
+    AudioStreamOut* clearOutput() final EXCLUDES_ThreadBase_Mutex;
 
                 // VolumeInterface
     void setMasterVolume(float value) final;
-    void setMasterBalance(float /* value */) final {}  // Needs implementation?
-    void setMasterMute(bool muted) final;
-    void setStreamVolume(audio_stream_type_t stream, float value) final;
-    void setStreamMute(audio_stream_type_t stream, bool muted) final;
-    float streamVolume(audio_stream_type_t stream) const final;
+    // Needs implementation?
+    void setMasterBalance(float /* value */) final EXCLUDES_ThreadBase_Mutex {}
+    void setMasterMute(bool muted) final EXCLUDES_ThreadBase_Mutex;
+    void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
+    void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
+    float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
 
-                void        setMasterMute_l(bool muted) { mMasterMute = muted; }
+    void setMasterMute_l(bool muted) REQUIRES(mutex()) { mMasterMute = muted; }
 
-    void invalidateTracks(audio_stream_type_t streamType) final;
-    void invalidateTracks(std::set<audio_port_handle_t>& portIds) final;
+    void invalidateTracks(audio_stream_type_t streamType) final EXCLUDES_ThreadBase_Mutex;
+    void invalidateTracks(std::set<audio_port_handle_t>& portIds) final EXCLUDES_ThreadBase_Mutex;
 
-    audio_stream_type_t streamType() const final { return mStreamType; }
-    void checkSilentMode_l() final;
-    void processVolume_l() final;
+    audio_stream_type_t streamType_l() const final REQUIRES(mutex()) {
+        return mStreamType;
+    }
+    void checkSilentMode_l() final REQUIRES(mutex());
+    void processVolume_l() final REQUIRES(mutex());
 
-    MetadataUpdate updateMetadata_l() final;
+    MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
 
     void toAudioPortConfig(struct audio_port_config* config) final;
 
@@ -2232,16 +2353,21 @@
             REQUIRES(audio_utils::AudioFlinger_Mutex);
 
 protected:
-    void dumpInternals_l(int fd, const Vector<String16>& args) final;
+    void dumpInternals_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());
+    float streamVolume_l() const REQUIRES(mutex()) {
+                    return mStreamTypes[mStreamType].volume;
+                }
+    bool streamMuted_l() const REQUIRES(mutex()) {
+                    return mStreamTypes[mStreamType].mute;
+                }
 
-                audio_stream_type_t         mStreamType;
-                float                       mMasterVolume;
-                float                       mStreamVolume;
-                bool                        mMasterMute;
-                bool                        mStreamMute;
-                AudioStreamOut*             mOutput;
+    stream_type_t mStreamTypes[AUDIO_STREAM_CNT] GUARDED_BY(mutex());
+    audio_stream_type_t mStreamType GUARDED_BY(mutex());
+    float mMasterVolume GUARDED_BY(mutex());
+    bool mMasterMute GUARDED_BY(mutex());
+    AudioStreamOut* mOutput;  // NO_THREAD_SAFETY_ANALYSIS
 
-                mediautils::atomic_sp<audio_utils::MelProcessor> mMelProcessor;
+    mediautils::atomic_sp<audio_utils::MelProcessor> mMelProcessor;  // locked internally
 };
 
 class MmapCaptureThread : public MmapThread, public IAfMmapCaptureThread
@@ -2254,13 +2380,14 @@
         return sp<IAfMmapCaptureThread>::fromExisting(this);
     }
 
-    AudioStreamIn* clearInput() final;
+    AudioStreamIn* clearInput() final EXCLUDES_ThreadBase_Mutex;
 
     status_t exitStandby_l() REQUIRES(mutex()) final;
 
-    MetadataUpdate updateMetadata_l() final;
-    void processVolume_l() final;
-    void setRecordSilenced(audio_port_handle_t portId, bool silenced) final;
+    MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
+    void processVolume_l() final REQUIRES(mutex());
+    void setRecordSilenced(audio_port_handle_t portId, bool silenced) final
+            EXCLUDES_ThreadBase_Mutex;
 
     void toAudioPortConfig(struct audio_port_config* config) final;
 
@@ -2272,7 +2399,7 @@
 
 protected:
 
-                AudioStreamIn*  mInput;
+    AudioStreamIn* mInput;  // NO_THREAD_SAFETY_ANALYSIS
 };
 
 class BitPerfectThread : public MixerThread {
@@ -2281,13 +2408,15 @@
                      audio_io_handle_t id, bool systemReady);
 
 protected:
-    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) final;
-    void threadLoop_mix() final;
+    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) final
+            REQUIRES(mutex(), ThreadBase_ThreadLoop);
+    void threadLoop_mix() final REQUIRES(ThreadBase_ThreadLoop);
 
 private:
-    bool mIsBitPerfect;
-    float mVolumeLeft = 0.f;
-    float mVolumeRight = 0.f;
+    // These variables are only accessed on the threadLoop; hence need no mutex.
+    bool mIsBitPerfect GUARDED_BY(ThreadBase_ThreadLoop) = false;
+    float mVolumeLeft GUARDED_BY(ThreadBase_ThreadLoop) = 0.f;
+    float mVolumeRight GUARDED_BY(ThreadBase_ThreadLoop) = 0.f;
 };
 
 } // namespace android
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 31246ec..4811586 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -113,8 +113,7 @@
         mChannelCount(isOut ?
                 audio_channel_count_from_out_mask(channelMask) :
                 audio_channel_count_from_in_mask(channelMask)),
-        mFrameSize(audio_has_proportional_frames(format) ?
-                mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
+        mFrameSize(audio_bytes_per_frame(mChannelCount, format)),
         mFrameCount(frameCount),
         mSessionId(sessionId),
         mIsOut(isOut),
@@ -451,6 +450,10 @@
     if (*_aidl_return != OK) {
         return Status::ok();
     }
+
+    // restrict position modulo INT_MAX to avoid integer sanitization abort
+    legacy.mPosition &= INT_MAX;
+
     *timestamp = legacy2aidl_AudioTimestamp_AudioTimestampInternal(legacy).value();
     return Status::ok();
 }
@@ -1170,9 +1173,11 @@
     if (thread != 0) {
         if (isOffloaded()) {
             audio_utils::lock_guard _laf(thread->afThreadCallback()->mutex());
+            const bool nonOffloadableGlobalEffectEnabled =
+                    thread->afThreadCallback()->isNonOffloadableGlobalEffectEnabled_l();
             audio_utils::lock_guard _lth(thread->mutex());
             sp<IAfEffectChain> ec = thread->getEffectChain_l(mSessionId);
-            if (thread->afThreadCallback()->isNonOffloadableGlobalEffectEnabled_l() ||
+            if (nonOffloadableGlobalEffectEnabled ||
                     (ec != 0 && ec->isNonOffloadableEnabled())) {
                 invalidate();
                 return PERMISSION_DENIED;
diff --git a/services/audioflinger/afutils/NBAIO_Tee.cpp b/services/audioflinger/afutils/NBAIO_Tee.cpp
index 49057ce..86fb128 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.cpp
+++ b/services/audioflinger/afutils/NBAIO_Tee.cpp
@@ -43,6 +43,7 @@
  "aftee_Date_ThreadId_C_reason.wav" RecordThread
  "aftee_Date_ThreadId_M_reason.wav" MixerThread (Normal)
  "aftee_Date_ThreadId_F_reason.wav" MixerThread (Fast)
+ "aftee_Date_ThreadId_D_reason.raw" DirectOutputThread (SpdifStreamOut)
  "aftee_Date_ThreadId_TrackId_R_reason.wav" RecordTrack
  "aftee_Date_ThreadId_TrackId_TrackName_T_reason.wav" PlaybackTrack
 
@@ -120,7 +121,7 @@
         return directory.size() > 0 && directory[0] == '/';
     }
 
-    std::string generateFilename(const std::string &suffix) const {
+    std::string generateFilename(const std::string &suffix, audio_format_t format) const {
         char fileTime[sizeof("YYYYmmdd_HHMMSS_\0")];
         struct timeval tv;
         gettimeofday(&tv, nullptr /* struct timezone */);
@@ -130,7 +131,7 @@
             "incorrect fileTime buffer");
         char msec[4];
         (void)snprintf(msec, sizeof(msec), "%03d", (int)(tv.tv_usec / 1000));
-        return mPrefix + fileTime + msec + suffix + ".wav";
+        return mPrefix + fileTime + msec + suffix + (audio_is_linear_pcm(format) ? ".wav" : ".raw");
     }
 
     bool isManagedFilename(const char *name) {
@@ -225,7 +226,7 @@
 NBAIO_Tee::NBAIO_TeeImpl::NBAIO_SinkSource NBAIO_Tee::NBAIO_TeeImpl::makeSinkSource(
         const NBAIO_Format &format, size_t frames, bool *enabled)
 {
-    if (Format_isValid(format) && audio_is_linear_pcm(format.mFormat)) {
+    if (Format_isValid(format) && audio_has_proportional_frames(format.mFormat)) {
         Pipe *pipe = new Pipe(frames, format);
         size_t numCounterOffers = 0;
         const NBAIO_Format offers[1] = {format};
@@ -259,7 +260,7 @@
         audio_format_t format,
         const std::string &suffix)
 {
-    std::string filename = generateFilename(suffix);
+    std::string filename = generateFilename(suffix, format);
 
     if (mThreadPool.launch(std::string("create ") + filename,
             [=]() { return createInternal(reader, sampleRate, channelCount, format, filename); })
@@ -406,6 +407,7 @@
     switch (format) {
     case AUDIO_FORMAT_PCM_8_BIT:
     case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_IEC61937:
         sf_format = SF_FORMAT_PCM_16;
         writeFormat = AUDIO_FORMAT_PCM_16_BIT;
         ALOGV("%s: %s using PCM_16 for format %#x", __func__, filename.c_str(), format);
@@ -424,7 +426,6 @@
         break;
     default:
         // TODO:
-        // handle audio_has_proportional_frames() formats.
         // handle compressed formats as single byte files.
         return BAD_VALUE;
     }
@@ -440,7 +441,7 @@
         .frames = 0,
         .samplerate = (int)sampleRate,
         .channels = (int)channelCount,
-        .format = SF_FORMAT_WAV | sf_format,
+        .format = sf_format | (audio_is_linear_pcm(format) ? SF_FORMAT_WAV : 0 /* RAW */),
     };
     SNDFILE *sf = sf_open(path.c_str(), SFM_WRITE, &info);
     if (sf == nullptr) {
@@ -463,7 +464,7 @@
         }
 
         // Convert input format to writeFormat as needed.
-        if (format != writeFormat) {
+        if (format != writeFormat && audio_is_linear_pcm(format)) {
             memcpy_by_audio_format(
                     buffer, writeFormat, buffer, format, actualRead * info.channels);
         }
diff --git a/services/audioflinger/afutils/NBAIO_Tee.h b/services/audioflinger/afutils/NBAIO_Tee.h
index 17b6175..13335fe 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.h
+++ b/services/audioflinger/afutils/NBAIO_Tee.h
@@ -48,7 +48,7 @@
  *
  * Some AudioFlinger specific notes:
  *
- * 1) Tees capture only linear PCM data.
+ * 1) Tees capture only linear PCM or IEC61937 data.
  * 2) Tees without any data written are considered empty and do not generate
  *    any output files.
  * 2) Once a Tee dumps data, it is considered "emptied" and new data
@@ -58,6 +58,7 @@
  *    WAV integer PCM 32 bit for AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED
  *                               AUDIO_FORMAT_PCM_32_BIT.
  *    WAV float PCM 32 bit for AUDIO_FORMAT_PCM_FLOAT.
+ *    RAW for AUDIO_FORMAT_IEC61937.
  *
  * Input_Thread:
  * 1) Capture buffer is teed when read from the HAL, before resampling for the AudioRecord
@@ -68,8 +69,8 @@
  *    NormalMixer output (if no FastMixer).
  * 2) DuplicatingThreads do not tee any mixed data. Apply a tee on the downstream OutputTrack
  *    or on the upstream playback Tracks.
- * 3) DirectThreads and OffloadThreads do not tee any data. The upstream track
- *    (if linear PCM format) may be teed to discover data.
+ * 3) DirectThreads and OffloadThreads with SpdifStreamOut will tee IEC61937 wrapped data.
+ *    Otherwise, the upstream track (if linear PCM format) may be teed to discover data.
  * 4) MmapThreads are not supported.
  *
  * Tracks:
@@ -198,8 +199,8 @@
 
             // determine number of frames for Tee
             if (frames == 0) {
-                // TODO: consider varying frame count based on type.
-                frames = DEFAULT_TEE_FRAMES;
+                frames = (static_cast<long long>(DEFAULT_TEE_DURATION_MS) * format.mSampleRate)
+                            / MILLIS_PER_SECOND;
             }
 
             // TODO: should we check minimum number of frames?
@@ -260,8 +261,7 @@
         static NBAIO_SinkSource makeSinkSource(
                 const NBAIO_Format &format, size_t frames, bool *enabled);
 
-        // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
-        static constexpr size_t DEFAULT_TEE_FRAMES = 0x200000;
+        static constexpr size_t DEFAULT_TEE_DURATION_MS = 60'000;
 
         // atomic status checking
         std::atomic<bool> mEnabled{false};
diff --git a/services/audioflinger/datapath/Android.bp b/services/audioflinger/datapath/Android.bp
index 58f0422..ee98aef 100644
--- a/services/audioflinger/datapath/Android.bp
+++ b/services/audioflinger/datapath/Android.bp
@@ -55,10 +55,18 @@
     shared_libs: [
         "audioclient-types-aidl-cpp",
         "av-types-aidl-cpp",
+        "libaudioflinger_utils", // NBAIO_Tee
+        "libaudioprocessing",
         "libaudiospdif",
         "libaudioutils",
         "libbase",
+        "libcutils",
         "liblog",
+        "libnbaio",
         "libutils", // refbase
     ],
+
+    include_dirs: [
+        "frameworks/av/services/audioflinger",  // for configuration
+    ],
 }
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index 43e9c0c..0c6a5a1 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
+#include "Configuration.h"
 #include <system/audio.h>
 #include <utils/Log.h>
 
@@ -48,9 +49,9 @@
 {
     struct audio_config customConfig = *config;
 
-    mApplicationFormat = config->format;
-    mApplicationSampleRate = config->sample_rate;
-    mApplicationChannelMask = config->channel_mask;
+    mApplicationConfig.format = config->format;
+    mApplicationConfig.sample_rate = config->sample_rate;
+    mApplicationConfig.channel_mask = config->channel_mask;
 
     // Some data bursts run at a higher sample rate.
     // TODO Move this into the audio_utils as a static method.
@@ -96,6 +97,16 @@
 
     ALOGI("SpdifStreamOut::open() status = %d", status);
 
+#ifdef TEE_SINK
+    if (status == OK) {
+        // Don't use PCM 16-bit format to avoid WAV encoding IEC61937 data.
+        mTee.set(customConfig.sample_rate,
+                audio_channel_count_from_out_mask(customConfig.channel_mask),
+                AUDIO_FORMAT_IEC61937, NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+        mTee.setId(std::string("_") + std::to_string(handle) + "_D");
+    }
+#endif
+
     return status;
 }
 
@@ -113,7 +124,15 @@
 
 ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes)
 {
-    return AudioStreamOut::write(buffer, bytes);
+    const ssize_t written = AudioStreamOut::write(buffer, bytes);
+
+#ifdef TEE_SINK
+    if (written > 0) {
+        mTee.write(reinterpret_cast<const char *>(buffer),
+                written / AudioStreamOut::getFrameSize());
+    }
+#endif
+    return written;
 }
 
 ssize_t SpdifStreamOut::write(const void* buffer, size_t numBytes)
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index c8dc89f..321b172 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -25,6 +25,7 @@
 
 #include "AudioStreamOut.h"
 
+#include <afutils/NBAIO_Tee.h>
 #include <audio_utils/spdif/SPDIFEncoder.h>
 
 namespace android {
@@ -68,22 +69,29 @@
     [[nodiscard]] size_t getFrameSize() const override { return sizeof(int8_t); }
 
     /**
+     * @return audio_config_base_t from the perspective of the application and the AudioFlinger.
+     */
+    [[nodiscard]] audio_config_base_t getAudioProperties() const override {
+        return mApplicationConfig;
+    }
+
+    /**
      * @return format from the perspective of the application and the AudioFlinger.
      */
-    [[nodiscard]] virtual audio_format_t getFormat() const { return mApplicationFormat; }
+    [[nodiscard]] virtual audio_format_t getFormat() const { return mApplicationConfig.format; }
 
     /**
      * The HAL may be running at a higher sample rate if, for example, playing wrapped EAC3.
      * @return sample rate from the perspective of the application and the AudioFlinger.
      */
-    [[nodiscard]] virtual uint32_t getSampleRate() const { return mApplicationSampleRate; }
+    [[nodiscard]] virtual uint32_t getSampleRate() const { return mApplicationConfig.sample_rate; }
 
     /**
      * The HAL is in stereo mode when playing multi-channel compressed audio over HDMI.
      * @return channel mask from the perspective of the application and the AudioFlinger.
      */
     [[nodiscard]] virtual audio_channel_mask_t getChannelMask() const {
-        return mApplicationChannelMask;
+        return mApplicationConfig.channel_mask;
     }
 
     status_t flush() override;
@@ -109,13 +117,15 @@
     };
 
     MySPDIFEncoder       mSpdifEncoder;
-    audio_format_t       mApplicationFormat = AUDIO_FORMAT_DEFAULT;
-    uint32_t             mApplicationSampleRate = 0;
-    audio_channel_mask_t mApplicationChannelMask = AUDIO_CHANNEL_NONE;
+    audio_config_base_t  mApplicationConfig = AUDIO_CONFIG_BASE_INITIALIZER;
 
     ssize_t  writeDataBurst(const void* data, size_t bytes);
     ssize_t  writeInternal(const void* buffer, size_t bytes);
 
+#ifdef TEE_SINK
+    NBAIO_Tee mTee;
+#endif
+
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 80e098b..6c130fd 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -89,6 +89,8 @@
     void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort,
                                             bool force = false);
 
+    status_t readFromParcelable(const media::AudioPortFw& parcelable) override;
+
     void setEncapsulationInfoFromHal(AudioPolicyClientInterface *clientInterface);
 
     void dump(String8 *dst, int spaces, bool verbose = true) const;
@@ -104,7 +106,7 @@
     std::string mTagName; // Unique human readable identifier for a device port found in conf file.
     audio_format_t      mCurrentEncodedFormat;
     bool                mIsDynamic = false;
-    const std::string   mDeclaredAddress; // Original device address
+    std::string         mDeclaredAddress; // Original device address
 };
 
 class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index 8c7a7de..4edd11f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -29,6 +29,8 @@
 
 namespace android {
 
+using media::audio::common::AudioDeviceAddress;
+using media::audio::common::AudioDeviceType;
 using media::audio::common::AudioIoFlags;
 using media::audio::common::AudioPortDeviceExt;
 using media::audio::common::AudioPortExt;
@@ -113,12 +115,17 @@
             ports.emplace(aidlPort.id, devicePort);
 
             if (const auto& deviceExt = aidlPort.ext.get<AudioPortExt::device>();
-                    deviceExt.device.type.connection.empty()) {  // Attached device
+                    deviceExt.device.type.connection.empty() ||
+                    // DeviceHalAidl connects remote submix input with an address.
+                    (deviceExt.device.type.type == AudioDeviceType::IN_SUBMIX &&
+                            deviceExt.device.address != AudioDeviceAddress())) {
+                // Attached device.
                 if (isInput) {
                     attachedInputDevices->add(devicePort);
                 } else {
                     attachedOutputDevices->add(devicePort);
-                    if ((deviceExt.flags & defaultDeviceFlag) != 0) {
+                    if (*defaultOutputDevice == nullptr &&
+                            (deviceExt.flags & defaultDeviceFlag) != 0) {
                         *defaultOutputDevice = devicePort;
                     }
                 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 514601c..fe25693 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -154,6 +154,12 @@
     policyPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
 }
 
+status_t DeviceDescriptor::readFromParcelable(const media::AudioPortFw& parcelable) {
+    RETURN_STATUS_IF_ERROR(DeviceDescriptorBase::readFromParcelable(parcelable));
+    mDeclaredAddress = DeviceDescriptorBase::address();
+    return OK;
+}
+
 void DeviceDescriptor::setEncapsulationInfoFromHal(
         AudioPolicyClientInterface *clientInterface) {
     AudioParameter param(String8(mDeviceTypeAddr.getAddress()));
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
index 7291c5f..2225cfe 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.cpp
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -78,7 +78,13 @@
 
     for (auto &handle : windowHandles) {
         native_handle_t* nh = makeFromAidl(handle);
-        iGBPs.push_back(new H2BGraphicBufferProducer(AImageReader_getHGBPFromHandle(nh)));
+        auto igbp = AImageReader_getHGBPFromHandle(nh);
+        if (igbp == nullptr) {
+            ALOGE("%s: Could not get HGBP from NativeHandle: %s. Skipping.",
+                    __FUNCTION__, handle.toString().c_str());
+            continue;
+        }
+        iGBPs.push_back(new H2BGraphicBufferProducer(igbp));
         native_handle_delete(nh);
     }
     UOutputConfiguration outputConfiguration(
diff --git a/services/camera/libcameraservice/hidl/Utils.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
index b5dddf7..d0302d0 100644
--- a/services/camera/libcameraservice/hidl/Utils.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -88,7 +88,13 @@
     auto &windowHandles = hOutputConfiguration.windowHandles;
     iGBPs.reserve(windowHandles.size());
     for (auto &handle : windowHandles) {
-        iGBPs.push_back(new H2BGraphicBufferProducer(AImageReader_getHGBPFromHandle(handle)));
+        auto igbp = AImageReader_getHGBPFromHandle(handle);
+        if (igbp == nullptr) {
+            ALOGE("%s: Could not get HGBP from native_handle: %p. Skipping.",
+                    __FUNCTION__, handle.getNativeHandle());
+            continue;
+        }
+        iGBPs.push_back(new H2BGraphicBufferProducer(igbp));
     }
     hardware::camera2::params::OutputConfiguration outputConfiguration(
         iGBPs, convertFromHidl(hOutputConfiguration.rotation),
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index d91b788..9aa5d3d 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -40,9 +40,5 @@
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
     strcpy(argv[0], "media.swcodec");
 
-    ::android::hardware::configureRpcThreadpool(64, false);
-
     RegisterCodecServices();
-
-    ::android::hardware::joinRpcThreadpool();
 }
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 1b5255a..f81db53 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -524,8 +524,8 @@
                                      "audiotrack",
                                      // other media
                                      "codec",
-                                     "freeze",
-                                     "judder",
+                                     "videofreeze",
+                                     "videojudder",
                                      "extractor",
                                      "mediadrm",
                                      "mediaparser",
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index e26fd28..af85772 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -46,9 +46,12 @@
 
 inline const char* getCodecType(MediaResourceSubType codecType) {
     switch (codecType) {
-        case MediaResourceSubType::kAudioCodec:         return "Audio";
-        case MediaResourceSubType::kVideoCodec:         return "Video";
-        case MediaResourceSubType::kImageCodec:         return "Image";
+        case MediaResourceSubType::kHwAudioCodec:       return "Hw Audio";
+        case MediaResourceSubType::kSwAudioCodec:       return "Sw Audio";
+        case MediaResourceSubType::kHwVideoCodec:       return "Hw Video";
+        case MediaResourceSubType::kSwVideoCodec:       return "Sw Video";
+        case MediaResourceSubType::kHwImageCodec:       return "Hw Image";
+        case MediaResourceSubType::kSwImageCodec:       return "Sw Image";
         case MediaResourceSubType::kUnspecifiedSubType:
         default:
                                                         return "Unspecified";
@@ -56,39 +59,29 @@
     return "Unspecified";
 }
 
-static CodecBucket getCodecBucket(bool isHardware,
-                                  bool isEncoder,
-                                  MediaResourceSubType codecType) {
-    if (isHardware) {
-        switch (codecType) {
-            case MediaResourceSubType::kAudioCodec:
-                if (isEncoder) return HwAudioEncoder;
-                return HwAudioDecoder;
-            case MediaResourceSubType::kVideoCodec:
-                if (isEncoder) return HwVideoEncoder;
-                return HwVideoDecoder;
-            case MediaResourceSubType::kImageCodec:
-                if (isEncoder) return HwImageEncoder;
-                return HwImageDecoder;
-            case MediaResourceSubType::kUnspecifiedSubType:
-            default:
-                return CodecBucketUnspecified;
-        }
-    } else {
-        switch (codecType) {
-            case MediaResourceSubType::kAudioCodec:
-                if (isEncoder) return SwAudioEncoder;
-                return SwAudioDecoder;
-            case MediaResourceSubType::kVideoCodec:
-                if (isEncoder) return SwVideoEncoder;
-                return SwVideoDecoder;
-            case MediaResourceSubType::kImageCodec:
-                if (isEncoder) return SwImageEncoder;
-                return SwImageDecoder;
-            case MediaResourceSubType::kUnspecifiedSubType:
-            default:
-                return CodecBucketUnspecified;
-        }
+inline bool isHardwareCodec(MediaResourceSubType codecType) {
+    return (codecType == MediaResourceSubType::kHwAudioCodec ||
+            codecType == MediaResourceSubType::kHwVideoCodec ||
+            codecType == MediaResourceSubType::kHwImageCodec);
+}
+
+static CodecBucket getCodecBucket(bool isEncoder, MediaResourceSubType codecType) {
+    switch (codecType) {
+    case MediaResourceSubType::kHwAudioCodec:
+        return isEncoder? HwAudioEncoder : HwAudioDecoder;
+    case MediaResourceSubType::kSwAudioCodec:
+        return isEncoder? SwAudioEncoder : SwAudioDecoder;
+    case MediaResourceSubType::kHwVideoCodec:
+        return isEncoder? HwVideoEncoder : HwVideoDecoder;
+    case MediaResourceSubType::kSwVideoCodec:
+        return isEncoder? SwVideoEncoder : SwVideoDecoder;
+    case MediaResourceSubType::kHwImageCodec:
+        return isEncoder? HwImageEncoder : HwImageDecoder;
+    case MediaResourceSubType::kSwImageCodec:
+        return isEncoder? SwImageEncoder : SwImageDecoder;
+    case MediaResourceSubType::kUnspecifiedSubType:
+    default:
+        return CodecBucketUnspecified;
     }
 
     return CodecBucketUnspecified;
@@ -179,8 +172,10 @@
     std::scoped_lock lock(mLock);
     ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
     if (entry != mClientConfigMap.end() &&
-        (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
-        clientConfig.codecType == MediaResourceSubType::kImageCodec)) {
+        (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
+         clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
+         clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
+         clientConfig.codecType == MediaResourceSubType::kSwImageCodec)) {
         int pid = clientConfig.clientInfo.pid;
         // Update the pixel count for this process
         updatePixelCount(pid, clientConfig.width * (long)clientConfig.height,
@@ -201,13 +196,13 @@
     mClientConfigMap[clientConfig.clientInfo.id] = clientConfig;
 
     // Update the concurrent codec count for this process.
-    CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
-                                             clientConfig.isEncoder,
-                                             clientConfig.codecType);
+    CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType);
     increaseConcurrentCodecs(pid, codecBucket);
 
-    if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
-        clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+    if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
+        clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
+        clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
+        clientConfig.codecType == MediaResourceSubType::kSwImageCodec) {
         // Update the pixel count for this process
         increasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
     }
@@ -236,7 +231,7 @@
          clientConfig.clientInfo.name.c_str(),
          static_cast<int32_t>(clientConfig.codecType),
          clientConfig.isEncoder,
-         clientConfig.isHardware,
+         isHardwareCodec(clientConfig.codecType),
          clientConfig.width, clientConfig.height,
          systemConcurrentCodecs,
          appConcurrentCodecs,
@@ -249,7 +244,7 @@
 
     ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: "
           "Process[pid(%d): uid(%d)] "
-          "Codec: [%s: %ju] is %s %s %s "
+          "Codec: [%s: %ju] is %s %s "
           "Timestamp: %jd "
           "Resolution: %d x %d "
           "ConcurrentCodec[%d]={System: %d App: %d} "
@@ -259,7 +254,6 @@
           pid, clientConfig.clientInfo.uid,
           clientConfig.clientInfo.name.c_str(),
           clientConfig.id,
-          clientConfig.isHardware? "hardware" : "software",
           getCodecType(clientConfig.codecType),
           clientConfig.isEncoder? "encoder" : "decoder",
           clientConfig.timeStamp,
@@ -273,13 +267,13 @@
     std::scoped_lock lock(mLock);
     int pid = clientConfig.clientInfo.pid;
     // Update the concurrent codec count for this process.
-    CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
-                                             clientConfig.isEncoder,
-                                             clientConfig.codecType);
+    CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType);
     decreaseConcurrentCodecs(pid, codecBucket);
 
-    if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
-        clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+    if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
+        clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
+        clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
+        clientConfig.codecType == MediaResourceSubType::kSwImageCodec) {
         // Update the pixel count for this process
         decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
     }
@@ -319,7 +313,7 @@
          clientConfig.clientInfo.name.c_str(),
          static_cast<int32_t>(clientConfig.codecType),
          clientConfig.isEncoder,
-         clientConfig.isHardware,
+         isHardwareCodec(clientConfig.codecType),
          clientConfig.width, clientConfig.height,
          systemConcurrentCodecs,
          appConcurrentCodecs,
@@ -327,7 +321,7 @@
          usageTime);
     ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: "
           "Process[pid(%d): uid(%d)] "
-          "Codec: [%s: %ju] is %s %s %s "
+          "Codec: [%s: %ju] is %s %s "
           "Timestamp: %jd Usage time: %jd "
           "Resolution: %d x %d "
           "ConcurrentCodec[%d]={System: %d App: %d} "
@@ -336,7 +330,6 @@
           pid, clientConfig.clientInfo.uid,
           clientConfig.clientInfo.name.c_str(),
           clientConfig.id,
-          clientConfig.isHardware? "hardware" : "software",
           getCodecType(clientConfig.codecType),
           clientConfig.isEncoder? "encoder" : "decoder",
           clientConfig.timeStamp, usageTime,
@@ -433,9 +426,9 @@
 }
 
 void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
-                        const std::vector<int>& priorities,
-                        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
-                        const PidUidVector& idList, bool reclaimed) {
+                                             const std::vector<int>& priorities,
+                                             const std::vector<ClientInfo>& targetClients,
+                                             bool reclaimed) {
     // Construct the metrics for codec reclaim as a pushed atom.
     // 1. Information about the requester.
     //  - UID and the priority (oom score)
@@ -460,7 +453,7 @@
     //    - UID and the Priority (oom score)
     int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
     if (!reclaimed) {
-      if (clients.size() == 0) {
+      if (targetClients.size() == 0) {
         // No clients to reclaim from
         reclaimStatus =
             MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
@@ -470,10 +463,9 @@
             MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
       }
     }
-    int32_t noOfCodecsReclaimed = clients.size();
+    int32_t noOfCodecsReclaimed = targetClients.size();
     int32_t targetIndex = 1;
-    for (PidUidVector::const_reference id : idList) {
-        int32_t targetUid = id.second;
+    for (const ClientInfo& targetClient : targetClients) {
         int targetPriority = priorities[targetIndex];
         // Post the pushed atom
         int result = stats_write(
@@ -485,7 +477,7 @@
             reclaimStatus,
             noOfCodecsReclaimed,
             targetIndex,
-            targetUid,
+            targetClient.mUid,
             targetPriority);
         ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
               "Requester[pid(%d): uid(%d): priority(%d)] "
@@ -497,7 +489,7 @@
               __func__, callingPid, requesterUid, requesterPriority,
               clientName.c_str(), noOfConcurrentCodecs,
               reclaimStatus, noOfCodecsReclaimed,
-              targetIndex, id.first, targetUid, targetPriority, result);
+              targetIndex, targetClient.mPid, targetClient.mUid, targetPriority, result);
         targetIndex++;
     }
 }
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
index d99c5b1..a9bc34b 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.h
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -135,8 +135,8 @@
     // To be called when after a reclaim event.
     void pushReclaimAtom(const ClientInfoParcel& clientInfo,
                          const std::vector<int>& priorities,
-                         const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
-                         const PidUidVector& idList, bool reclaimed);
+                         const std::vector<ClientInfo>& targetClients,
+                         bool reclaimed);
 
     // Add this pid/uid set to monitor for the process termination state.
     void addPid(int pid, uid_t uid = 0);
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 9552e25..c5eb537 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -168,13 +168,16 @@
         sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
         for (size_t i = 0; i < resources.size(); ++i) {
             switch (resources[i].subType) {
-                case MediaResource::SubType::kAudioCodec:
+                case MediaResource::SubType::kHwAudioCodec:
+                case MediaResource::SubType::kSwAudioCodec:
                     service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
                     break;
-                case MediaResource::SubType::kVideoCodec:
+                case MediaResource::SubType::kHwVideoCodec:
+                case MediaResource::SubType::kSwVideoCodec:
                     service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
                     break;
-                case MediaResource::SubType::kImageCodec:
+                case MediaResource::SubType::kHwImageCodec:
+                case MediaResource::SubType::kSwImageCodec:
                     service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
                     break;
                 case MediaResource::SubType::kUnspecifiedSubType:
@@ -366,7 +369,8 @@
         }
         mCpuBoostCount++;
     } else if (resource.type == MediaResource::Type::kBattery
-            && resource.subType == MediaResource::SubType::kVideoCodec) {
+            && (resource.subType == MediaResource::SubType::kHwVideoCodec
+                || resource.subType == MediaResource::SubType::kSwVideoCodec)) {
         mSystemCB->noteStartVideo(clientInfo.uid);
     }
 }
@@ -380,7 +384,8 @@
             mSystemCB->requestCpusetBoost(false);
         }
     } else if (resource.type == MediaResource::Type::kBattery
-            && resource.subType == MediaResource::SubType::kVideoCodec) {
+            && (resource.subType == MediaResource::SubType::kHwVideoCodec
+                || resource.subType == MediaResource::SubType::kSwVideoCodec)) {
         mSystemCB->noteStopVideo(clientInfo.uid);
     }
 }
@@ -580,16 +585,28 @@
     return Status::ok();
 }
 
-void ResourceManagerService::getClientForResource_l(int callingPid,
-        const MediaResourceParcel *res,
-        PidUidVector* idVector,
-        std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
+void ResourceManagerService::getClientForResource_l(
+        const ResourceRequestInfo& resourceRequestInfo,
+        std::vector<ClientInfo>& clientsInfo) {
+    int callingPid = resourceRequestInfo.mCallingPid;
+    const MediaResourceParcel* res = resourceRequestInfo.mResource;
     if (res == NULL) {
         return;
     }
+
+    // Before looking into other processes, check if we have clients marked for
+    // pending removal in the same process.
+    uid_t uid = 0;
     std::shared_ptr<IResourceManagerClient> client;
-    if (getLowestPriorityBiggestClient_l(callingPid, res->type, res->subType, idVector, &client)) {
-        clients->push_back(client);
+    if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, uid, &client)) {
+        clientsInfo.emplace_back(callingPid, uid, client);
+        return;
+    }
+
+    // Now find client(s) from a lowest priority process that has needed resources.
+    ClientInfo clientInfo;
+    if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) {
+        clientsInfo.push_back(clientInfo);
     }
 }
 
@@ -602,8 +619,7 @@
     mServiceLog->add(log);
     *_aidl_return = false;
 
-    std::vector<std::shared_ptr<IResourceManagerClient>> clients;
-    PidUidVector idVector;
+    std::vector<ClientInfo> targetClients;
     {
         std::scoped_lock lock{mLock};
         if (!mProcessInfo->isPidTrusted(callingPid)) {
@@ -637,98 +653,116 @@
 
         // first pass to handle secure/non-secure codec conflict
         if (secureCodec != NULL) {
+            MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+                                              .subType = secureCodec->subType};
+            ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
             if (!mSupportsMultipleSecureCodecs) {
-                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
-                            secureCodec->subType, &idVector, &clients)) {
+                if (!getAllClients_l(resourceRequestInfo, targetClients)) {
                     return Status::ok();
                 }
             }
             if (!mSupportsSecureWithNonSecureCodec) {
-                if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec,
-                            secureCodec->subType, &idVector, &clients)) {
+                mediaResource.type = MediaResource::Type::kNonSecureCodec;
+                if (!getAllClients_l(resourceRequestInfo, targetClients)) {
                     return Status::ok();
                 }
             }
         }
         if (nonSecureCodec != NULL) {
             if (!mSupportsSecureWithNonSecureCodec) {
-                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
-                        nonSecureCodec->subType, &idVector, &clients)) {
+                MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+                                                  .subType = nonSecureCodec->subType};
+                ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+                if (!getAllClients_l(resourceRequestInfo, targetClients)) {
                     return Status::ok();
                 }
             }
         }
+
         if (drmSession != NULL) {
-            getClientForResource_l(callingPid, drmSession, &idVector, &clients);
-            if (clients.size() == 0) {
+            ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
+            getClientForResource_l(resourceRequestInfo, targetClients);
+            if (targetClients.size() == 0) {
                 return Status::ok();
             }
         }
 
-        if (clients.size() == 0) {
+        if (targetClients.size() == 0 && graphicMemory != nullptr) {
             // if no secure/non-secure codec conflict, run second pass to handle other resources.
-            getClientForResource_l(callingPid, graphicMemory, &idVector, &clients);
+            ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
+            getClientForResource_l(resourceRequestInfo, targetClients);
         }
 
-        if (clients.size() == 0) {
+        if (targetClients.size() == 0) {
             // if we are here, run the third pass to free one codec with the same type.
-            getClientForResource_l(callingPid, secureCodec, &idVector, &clients);
-            getClientForResource_l(callingPid, nonSecureCodec, &idVector, &clients);
+            if (secureCodec != nullptr) {
+                ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
+                getClientForResource_l(resourceRequestInfo, targetClients);
+            }
+            if (nonSecureCodec != nullptr) {
+                ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
+                getClientForResource_l(resourceRequestInfo, targetClients);
+            }
         }
 
-        if (clients.size() == 0) {
+        if (targetClients.size() == 0) {
             // if we are here, run the fourth pass to free one codec with the different type.
-            if (secureCodec != NULL) {
+            if (secureCodec != nullptr) {
                 MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
-                getClientForResource_l(callingPid, &temp, &idVector, &clients);
+                ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+                getClientForResource_l(resourceRequestInfo, targetClients);
             }
-            if (nonSecureCodec != NULL) {
+            if (nonSecureCodec != nullptr) {
                 MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
-                getClientForResource_l(callingPid, &temp, &idVector, &clients);
+                ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+                getClientForResource_l(resourceRequestInfo, targetClients);
             }
         }
     }
 
-    *_aidl_return = reclaimUnconditionallyFrom(clients);
+    *_aidl_return = reclaimUnconditionallyFrom(targetClients);
 
     // Log Reclaim Pushed Atom to statsd
-    pushReclaimAtom(clientInfo, clients, idVector, *_aidl_return);
+    pushReclaimAtom(clientInfo, targetClients, *_aidl_return);
 
     return Status::ok();
 }
 
 void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo,
-                        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
-                        const PidUidVector& idVector, bool reclaimed) {
+                                             const std::vector<ClientInfo>& targetClients,
+                                             bool reclaimed) {
     int32_t callingPid = clientInfo.pid;
     int requesterPriority = -1;
     getPriority_l(callingPid, &requesterPriority);
     std::vector<int> priorities;
     priorities.push_back(requesterPriority);
 
-    for (PidUidVector::const_reference id : idVector) {
+    for (const ClientInfo& targetClient : targetClients) {
         int targetPriority = -1;
-        getPriority_l(id.first, &targetPriority);
+        getPriority_l(targetClient.mPid, &targetPriority);
         priorities.push_back(targetPriority);
     }
-    mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, clients,
-                                             idVector, reclaimed);
+    mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed);
 }
 
 bool ResourceManagerService::reclaimUnconditionallyFrom(
-        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients) {
-    if (clients.size() == 0) {
+        const std::vector<ClientInfo>& targetClients) {
+    if (targetClients.size() == 0) {
         return false;
     }
 
     std::shared_ptr<IResourceManagerClient> failedClient;
-    for (size_t i = 0; i < clients.size(); ++i) {
-        String8 log = String8::format("reclaimResource from client %p", clients[i].get());
+    for (const ClientInfo& targetClient : targetClients) {
+        if (targetClient.mClient == nullptr) {
+            // skip already released clients.
+            continue;
+        }
+        String8 log = String8::format("reclaimResource from client %p", targetClient.mClient.get());
         mServiceLog->add(log);
         bool success;
-        Status status = clients[i]->reclaimResource(&success);
+        Status status = targetClient.mClient->reclaimResource(&success);
         if (!status.isOk() || !success) {
-            failedClient = clients[i];
+            failedClient = targetClient.mClient;
             break;
         }
     }
@@ -886,7 +920,7 @@
     String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
     mServiceLog->add(log);
 
-    std::vector<std::shared_ptr<IResourceManagerClient>> clients;
+    std::vector<ClientInfo> targetClients;
     {
         std::scoped_lock lock{mLock};
         if (!mProcessInfo->isPidTrusted(pid)) {
@@ -904,13 +938,16 @@
                 // Codec resources are segregated by audio, video and image domains.
                 case MediaResource::Type::kSecureCodec:
                 case MediaResource::Type::kNonSecureCodec:
-                    for (MediaResource::SubType subType : {MediaResource::SubType::kAudioCodec,
-                                                           MediaResource::SubType::kVideoCodec,
-                                                           MediaResource::SubType::kImageCodec}) {
+                    for (MediaResource::SubType subType : {MediaResource::SubType::kHwAudioCodec,
+                                                           MediaResource::SubType::kSwAudioCodec,
+                                                           MediaResource::SubType::kHwVideoCodec,
+                                                           MediaResource::SubType::kSwVideoCodec,
+                                                           MediaResource::SubType::kHwImageCodec,
+                                                           MediaResource::SubType::kSwImageCodec}) {
                         std::shared_ptr<IResourceManagerClient> client;
                         uid_t uid = 0;
                         if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) {
-                            clients.push_back(client);
+                            targetClients.emplace_back(pid, uid, client);
                             continue;
                         }
                     }
@@ -921,15 +958,15 @@
                     uid_t uid = 0;
                     if (getBiggestClientPendingRemoval_l(pid, type,
                             MediaResource::SubType::kUnspecifiedSubType, uid, &client)) {
-                        clients.push_back(client);
+                        targetClients.emplace_back(pid, uid, client);
                     }
                     break;
             }
         }
     }
 
-    if (!clients.empty()) {
-        reclaimUnconditionallyFrom(clients);
+    if (!targetClients.empty()) {
+        reclaimUnconditionallyFrom(targetClients);
     }
     return Status::ok();
 }
@@ -946,73 +983,70 @@
     return mProcessInfo->getPriority(newPid, priority);
 }
 
-bool ResourceManagerService::getAllClients_l(int callingPid, MediaResource::Type type,
-        MediaResource::SubType subType,
-        PidUidVector* idVector,
-        std::vector<std::shared_ptr<IResourceManagerClient>>* clients) {
-    std::vector<std::shared_ptr<IResourceManagerClient>> temp;
-    PidUidVector tempIdList;
+bool ResourceManagerService::getAllClients_l(
+        const ResourceRequestInfo& resourceRequestInfo,
+        std::vector<ClientInfo>& clientsInfo) {
+    MediaResource::Type type = resourceRequestInfo.mResource->type;
+    MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
 
     for (auto& [pid, infos] : mMap) {
         for (const auto& [id, info] : infos) {
             if (hasResourceType(type, subType, info.resources)) {
-                if (!isCallingPriorityHigher_l(callingPid, pid)) {
+                if (!isCallingPriorityHigher_l(resourceRequestInfo.mCallingPid, pid)) {
                     // some higher/equal priority process owns the resource,
                     // this request can't be fulfilled.
-                    ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
-                            asString(type), pid);
+                    ALOGE("%s: can't reclaim resource %s from pid %d",
+                          __func__, asString(type), pid);
+                    clientsInfo.clear();
                     return false;
                 }
-                temp.push_back(info.client);
-                tempIdList.emplace_back(pid, info.uid);
+                clientsInfo.emplace_back(pid, info.uid, info.client);
             }
         }
     }
-    if (temp.size() == 0) {
-        ALOGV("getAllClients_l: didn't find any resource %s", asString(type));
-        return true;
+    if (clientsInfo.size() == 0) {
+        ALOGV("%s: didn't find any resource %s", __func__, asString(type));
     }
-
-    clients->insert(std::end(*clients), std::begin(temp), std::end(temp));
-    idVector->insert(std::end(*idVector), std::begin(tempIdList), std::end(tempIdList));
     return true;
 }
 
-bool ResourceManagerService::getLowestPriorityBiggestClient_l(int callingPid,
-        MediaResource::Type type,
-        MediaResource::SubType subType,
-        PidUidVector* idVector,
-        std::shared_ptr<IResourceManagerClient> *client) {
+// Process priority (oom score) based reclaim:
+//   - Find a process with lowest priority (than that of calling process).
+//   - Find the bigegst client (with required resources) from that process.
+bool ResourceManagerService::getLowestPriorityBiggestClient_l(
+        const ResourceRequestInfo& resourceRequestInfo,
+        ClientInfo& clientsInfo) {
+    int callingPid = resourceRequestInfo.mCallingPid;
+    MediaResource::Type type = resourceRequestInfo.mResource->type;
+    MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
     int lowestPriorityPid;
     int lowestPriority;
     int callingPriority;
     uid_t uid = 0;
+    std::shared_ptr<IResourceManagerClient> client;
 
-    // Before looking into other processes, check if we have clients marked for
-    // pending removal in the same process.
-    if (getBiggestClientPendingRemoval_l(callingPid, type, subType, uid, client)) {
-        idVector->emplace_back(callingPid, uid);
-        return true;
-    }
     if (!getPriority_l(callingPid, &callingPriority)) {
-        ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
-                callingPid);
+        ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
         return false;
     }
     if (!getLowestPriorityPid_l(type, subType, &lowestPriorityPid, &lowestPriority)) {
         return false;
     }
     if (lowestPriority <= callingPriority) {
-        ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
-                lowestPriority, callingPriority);
+        ALOGE("%s: lowest priority %d vs caller priority %d",
+              __func__, lowestPriority, callingPriority);
         return false;
     }
 
-    if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, client)) {
+    if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, &client)) {
         return false;
     }
 
-    idVector->emplace_back(lowestPriorityPid, uid);
+    clientsInfo.mPid = lowestPriorityPid;
+    clientsInfo.mUid = uid;
+    clientsInfo.mClient = client;
+    ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
+          __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority);
     return true;
 }
 
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index aa88ac6..de7e4a3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -33,7 +33,6 @@
 namespace android {
 
 class DeathNotifier;
-class ResourceManagerService;
 class ResourceObserverService;
 class ServiceLog;
 struct ProcessInfoInterface;
@@ -61,8 +60,39 @@
     bool pendingRemoval{false};
 };
 
-// vector of <PID, UID>
-typedef std::vector<std::pair<int32_t, uid_t>> PidUidVector;
+/*
+ * Resource request info that encapsulates
+ *  - the calling/requesting process pid.
+ *  - the resource requesting (to be reclaimed from others)
+ */
+struct ResourceRequestInfo {
+    // uid of the calling/requesting process.
+    int mCallingPid = -1;
+    // resources requested.
+    const ::aidl::android::media::MediaResourceParcel* mResource;
+};
+
+/*
+ * Structure that defines the Client - a possible target to relcaim from.
+ * This encapsulates pid, uid of the process and the client.
+ * based on the reclaim policy.
+ */
+struct ClientInfo {
+    // pid of the process.
+    pid_t mPid;
+    // uid of the process.
+    uid_t mUid;
+    // Client to relcaim from.
+    std::shared_ptr<::aidl::android::media::IResourceManagerClient> mClient;
+    ClientInfo(
+        pid_t pid = -1,
+        uid_t uid = -1,
+        const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client = nullptr)
+        : mPid(pid),
+          mUid(uid),
+          mClient(client) {
+    }
+};
 
 typedef std::map<int64_t, ResourceInfo> ResourceInfos;
 typedef std::map<int, ResourceInfos> PidResourceInfosMap;
@@ -134,45 +164,40 @@
     // Reclaims resources from |clients|. Returns true if reclaim succeeded
     // for all clients.
     bool reclaimUnconditionallyFrom(
-        const std::vector<std::shared_ptr<IResourceManagerClient>>& clients);
+        const std::vector<ClientInfo>& targetClients);
 
     // Gets the list of all the clients who own the specified resource type.
     // Returns false if any client belongs to a process with higher priority than the
     // calling process. The clients will remain unchanged if returns false.
-    bool getAllClients_l(int callingPid, MediaResource::Type type, MediaResource::SubType subType,
-            PidUidVector* idList,
-            std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
+    bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+                         std::vector<ClientInfo>& clientsInfo);
 
     // Gets the client who owns specified resource type from lowest possible priority process.
     // Returns false if the calling process priority is not higher than the lowest process
     // priority. The client will remain unchanged if returns false.
-    bool getLowestPriorityBiggestClient_l(int callingPid, MediaResource::Type type,
-            MediaResource::SubType subType, PidUidVector* idList,
-            std::shared_ptr<IResourceManagerClient> *client);
-
-    // Gets lowest priority process that has the specified resource type.
-    // Returns false if failed. The output parameters will remain unchanged if failed.
-    bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType, int *pid,
-                int *priority);
+    bool getLowestPriorityBiggestClient_l(
+        const ResourceRequestInfo& resourceRequestInfo,
+        ClientInfo& clientInfo);
 
     // Gets the client who owns biggest piece of specified resource type from pid.
-    // Returns false with no change to client if there are no clients holdiing resources of thisi
+    // Returns false with no change to client if there are no clients holding resources of this
     // type.
     bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
-            uid_t& uid, std::shared_ptr<IResourceManagerClient> *client,
-            bool pendingRemovalOnly = false);
+                            uid_t& uid, std::shared_ptr<IResourceManagerClient> *client,
+                            bool pendingRemovalOnly = false);
     // Same method as above, but with pendingRemovalOnly as true.
     bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
-            MediaResource::SubType subType, uid_t& uid,
-            std::shared_ptr<IResourceManagerClient> *client);
+                                          MediaResource::SubType subType, uid_t& uid,
+                                          std::shared_ptr<IResourceManagerClient>* client);
 
+    // A helper function that returns true if the callingPid has higher priority than pid.
+    // Returns false otherwise.
     bool isCallingPriorityHigher_l(int callingPid, int pid);
 
-    // A helper function basically calls getLowestPriorityBiggestClient_l and add
+    // A helper function basically calls getLowestPriorityBiggestClient_l and adds
     // the result client to the given Vector.
-    void getClientForResource_l(int callingPid, const MediaResourceParcel *res,
-            PidUidVector* idList,
-            std::vector<std::shared_ptr<IResourceManagerClient>>* clients);
+    void getClientForResource_l(const ResourceRequestInfo& resourceRequestInfo,
+                                std::vector<ClientInfo>& clientsInfo);
 
     void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
     void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
@@ -188,9 +213,14 @@
     void removeProcessInfoOverride_l(int pid);
 
     void pushReclaimAtom(const ClientInfoParcel& clientInfo,
-                         const std::vector<std::shared_ptr<IResourceManagerClient>>& clients,
-                         const PidUidVector& idList, bool reclaimed);
+                         const std::vector<ClientInfo>& targetClients,
+                         bool reclaimed);
 
+    // The following utility functions are used only for testing by ResourceManagerServiceTest
+    // Gets lowest priority process that has the specified resource type.
+    // Returns false if failed. The output parameters will remain unchanged if failed.
+    bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+                                int* lowestPriorityPid, int* lowestPriority);
     // Get the peak concurrent pixel count (associated with the video codecs) for the process.
     long getPeakConcurrentPixelCount(int pid) const;
     // Get the current concurrent pixel count (associated with the video codecs) for the process.
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
index 6c5cecf..72e249f 100644
--- a/services/mediaresourcemanager/ResourceObserverService.cpp
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -41,7 +41,8 @@
 };
 
 static MediaObservableType getObservableType(const MediaResourceParcel& res) {
-    if (res.subType == MediaResourceSubType::kVideoCodec) {
+    if (res.subType == MediaResourceSubType::kHwVideoCodec ||
+        res.subType == MediaResourceSubType::kSwVideoCodec) {
         if (res.type == MediaResourceType::kNonSecureCodec) {
             return MediaObservableType::kVideoNonSecureCodec;
         }
diff --git a/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
index 3c9c8c7..85f1970 100644
--- a/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
@@ -33,33 +33,29 @@
     /**
      * Type of codec (Audio/Video/Image).
      */
-    MediaResourceSubType codecType;
+    MediaResourceSubType codecType = MediaResourceSubType.kUnspecifiedSubType;
 
     /**
      * true if this is an encoder, false if this is a decoder.
      */
-    boolean isEncoder;
-
-    /**
-     * true if this is hardware codec, false otherwise.
-     */
-    boolean isHardware;
+    boolean isEncoder = false;
 
     /*
      * Video Resolution of the codec when it was configured, as width and height (in pixels).
      */
-    int width;
-    int height;
+    int width = 0;
+    int height = 0;
 
     /*
      * Timestamp (in microseconds) when this configuration is created.
      */
-    long timeStamp;
+    long timeStamp = 0;
+
     /*
      * ID associated with the Codec.
      * This will be used by the metrics:
      * - Associate MediaCodecStarted with MediaCodecStopped Atom.
      * - Correlate MediaCodecReported Atom for codec configuration parameters.
      */
-    long id;
+    long id = 0;
 }
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl
index b0f2b71..6f180e9 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceParcel.aidl
@@ -25,18 +25,15 @@
  * {@hide}
  */
 parcelable MediaResourceParcel {
-    // TODO: default enum value is not supported yet.
-    // Set default enum value when b/142739329 is fixed.
-
     /**
      * Type of the media resource.
      */
-    MediaResourceType type;// = MediaResourceTypeEnum::kUnspecified;
+    MediaResourceType type = MediaResourceType.kUnspecified;
 
     /**
      * Sub-type of the media resource.
      */
-    MediaResourceSubType subType;// = MediaResourceSubTypeEnum::kUnspecifiedSubType;
+    MediaResourceSubType subType = MediaResourceSubType.kUnspecifiedSubType;
 
     /**
      * Identifier of the media resource (eg. Drm session id).
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
index 72a0551..311b6c3 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
@@ -24,7 +24,10 @@
 @Backing(type="int")
 enum MediaResourceSubType {
     kUnspecifiedSubType = 0,
-    kAudioCodec = 1,
-    kVideoCodec = 2,
-    kImageCodec = 3,
+    kHwAudioCodec = 1,
+    kSwAudioCodec = 2,
+    kHwVideoCodec = 3,
+    kSwVideoCodec = 4,
+    kHwImageCodec = 5,
+    kSwImageCodec = 6,
 }
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl
index b2bb71b..353e59c 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceType.aidl
@@ -24,10 +24,13 @@
 @Backing(type="int")
 enum MediaResourceType {
     kUnspecified = 0,
+    // Codec resource type as secure or unsecure
     kSecureCodec = 1,
     kNonSecureCodec = 2,
+    // Other Codec resource types understood by the frameworks
     kGraphicMemory = 3,
     kCpuBoost = 4,
     kBattery = 5,
+    // DRM Session resource type
     kDrmSession = 6,
 }
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ae3faea..7452275 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -28,32 +28,32 @@
 private:
     static MediaResource createSecureVideoCodecResource(int amount = 1) {
         return MediaResource(MediaResource::Type::kSecureCodec,
-            MediaResource::SubType::kVideoCodec, amount);
+            MediaResource::SubType::kHwVideoCodec, amount);
     }
 
     static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
         return MediaResource(MediaResource::Type::kNonSecureCodec,
-            MediaResource::SubType::kVideoCodec, amount);
+            MediaResource::SubType::kHwVideoCodec, amount);
     }
 
     static MediaResource createSecureAudioCodecResource(int amount = 1) {
         return MediaResource(MediaResource::Type::kSecureCodec,
-            MediaResource::SubType::kAudioCodec, amount);
+            MediaResource::SubType::kHwAudioCodec, amount);
     }
 
     static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
         return MediaResource(MediaResource::Type::kNonSecureCodec,
-            MediaResource::SubType::kAudioCodec, amount);
+            MediaResource::SubType::kHwAudioCodec, amount);
     }
 
     static MediaResource createSecureImageCodecResource(int amount = 1) {
         return MediaResource(MediaResource::Type::kSecureCodec,
-            MediaResource::SubType::kImageCodec, amount);
+            MediaResource::SubType::kHwImageCodec, amount);
     }
 
     static MediaResource createNonSecureImageCodecResource(int amount = 1) {
         return MediaResource(MediaResource::Type::kNonSecureCodec,
-            MediaResource::SubType::kImageCodec, amount);
+            MediaResource::SubType::kHwImageCodec, amount);
     }
 
     static MediaResource createGraphicMemoryResource(int amount = 1) {
@@ -272,13 +272,15 @@
 
         // test adding new types (including types that differs only in subType)
         resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
-        resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+        resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec,
+                                            MediaResource::SubType::kHwVideoCodec, 1));
         mService->addResource(client1Info, mTestClient1, resources11);
 
         expected.clear();
         expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
         expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
-        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec,
+                                         MediaResource::SubType::kHwVideoCodec, 1));
         expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
         expectEqResourceInfo(infos1.at(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
     }
@@ -476,21 +478,25 @@
 
     void testGetAllClients() {
         addResource();
-        MediaResource::Type type = MediaResource::Type::kSecureCodec;
-        MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
 
-        std::vector<std::shared_ptr<IResourceManagerClient> > clients;
-        PidUidVector idList;
-        EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &idList, &clients));
+        std::vector<ClientInfo> targetClients;
+        MediaResource resource(MediaResource::Type::kSecureCodec,
+                               MediaResource::SubType::kUnspecifiedSubType,
+                               1);
+        ResourceRequestInfo requestInfoHigh { kHighPriorityPid, &resource};
+        ResourceRequestInfo requestInfoMid { kMidPriorityPid, &resource};
+        ResourceRequestInfo requestInfoLow { kLowPriorityPid, &resource};
+
+        EXPECT_FALSE(mService->getAllClients_l(requestInfoLow, targetClients));
         // some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
         // will fail.
-        EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, subType, &idList, &clients));
-        EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, subType, &idList, &clients));
+        EXPECT_FALSE(mService->getAllClients_l(requestInfoMid, targetClients));
+        EXPECT_TRUE(mService->getAllClients_l(requestInfoHigh, targetClients));
 
-        EXPECT_EQ(2u, clients.size());
+        EXPECT_EQ(2u, targetClients.size());
         // (OK to require ordering in clients[], as the pid map is sorted)
-        EXPECT_EQ(mTestClient3, clients[0]);
-        EXPECT_EQ(mTestClient1, clients[1]);
+        EXPECT_EQ(mTestClient3, targetClients[0].mClient);
+        EXPECT_EQ(mTestClient1, targetClients[1].mClient);
     }
 
     void testReclaimResourceSecure() {
@@ -754,23 +760,22 @@
     }
 
     void testGetLowestPriorityBiggestClient() {
-        MediaResource::Type type = MediaResource::Type::kGraphicMemory;
-        MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
-        std::shared_ptr<IResourceManagerClient> client;
-        PidUidVector idList;
-        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
-                &idList, &client));
+        ClientInfo clientInfo;
+        MediaResource resource(MediaResource::Type::kGraphicMemory,
+                               MediaResource::SubType::kUnspecifiedSubType,
+                               1);
+        ResourceRequestInfo requestInfoHigh { kHighPriorityPid, &resource};
+        ResourceRequestInfo requestInfoLow { kLowPriorityPid, &resource};
+        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(requestInfoHigh, clientInfo));
 
         addResource();
 
-        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, subType,
-                &idList, &client));
-        EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
-                &idList, &client));
+        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(requestInfoLow, clientInfo));
+        EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(requestInfoHigh, clientInfo));
 
         // kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
         // mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
-        EXPECT_EQ(mTestClient1, client);
+        EXPECT_EQ(mTestClient1, clientInfo.mClient);
     }
 
     void testGetLowestPriorityPid() {
@@ -811,7 +816,8 @@
 
         // new client request should cause VIDEO_ON
         std::vector<MediaResourceParcel> resources1;
-        resources1.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 1));
+        resources1.push_back(MediaResource(MediaResource::Type::kBattery,
+                                           MediaResource::SubType::kHwVideoCodec, 1));
         ClientInfoParcel client1Info{.pid = static_cast<int32_t>(kTestPid1),
                                      .uid = static_cast<int32_t>(kTestUid1),
                                      .id = getId(mTestClient1),
@@ -826,7 +832,8 @@
 
         // new client request should cause VIDEO_ON
         std::vector<MediaResourceParcel> resources2;
-        resources2.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 2));
+        resources2.push_back(MediaResource(MediaResource::Type::kBattery,
+                                           MediaResource::SubType::kHwVideoCodec, 2));
         ClientInfoParcel client2Info{.pid = static_cast<int32_t>(kTestPid2),
                                      .uid = static_cast<int32_t>(kTestUid2),
                                      .id = getId(mTestClient2),
@@ -1372,9 +1379,9 @@
                                        int64_t id,
                                        const ClientInfoParcel& clientInfo,
                                        ClientConfigParcel& clientConfig) {
-        clientConfig.codecType = MediaResource::SubType::kVideoCodec;
+        clientConfig.codecType = hw? MediaResource::SubType::kHwVideoCodec :
+                                     MediaResource::SubType::kSwVideoCodec;
         clientConfig.isEncoder = encoder;
-        clientConfig.isHardware = hw;
         clientConfig.width = width;
         clientConfig.height = height;
         clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
index 85769d5..3f8ed2a 100644
--- a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -118,22 +118,22 @@
 
 static MediaResource createSecureVideoCodecResource(int amount = 1) {
     return MediaResource(MediaResource::Type::kSecureCodec,
-        MediaResource::SubType::kVideoCodec, amount);
+        MediaResource::SubType::kHwVideoCodec, amount);
 }
 
 static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
     return MediaResource(MediaResource::Type::kNonSecureCodec,
-        MediaResource::SubType::kVideoCodec, amount);
+        MediaResource::SubType::kHwVideoCodec, amount);
 }
 
 static MediaResource createSecureAudioCodecResource(int amount = 1) {
     return MediaResource(MediaResource::Type::kSecureCodec,
-        MediaResource::SubType::kAudioCodec, amount);
+        MediaResource::SubType::kHwAudioCodec, amount);
 }
 
 static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
     return MediaResource(MediaResource::Type::kNonSecureCodec,
-        MediaResource::SubType::kAudioCodec, amount);
+        MediaResource::SubType::kHwAudioCodec, amount);
 }
 
 // Operators for GTest macros.