Merge changes I37711f42,I2212cdc5

* changes:
  SyncEvent: modernize C++
  AudioFlinger: Refactor SyncEvent
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 3b06245..7262d64 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -18,6 +18,8 @@
 
 #include <algorithm>
 #include <map>
+#include <sstream>
+#include <regex>
 #include <utility>
 #include <vector>
 
@@ -50,6 +52,7 @@
 using ::android::status_t;
 using ::android::base::unexpected;
 
+using media::audio::common::AudioAttributes;
 using media::audio::common::AudioChannelLayout;
 using media::audio::common::AudioConfig;
 using media::audio::common::AudioConfigBase;
@@ -62,6 +65,7 @@
 using media::audio::common::AudioEncapsulationMetadataType;
 using media::audio::common::AudioEncapsulationMode;
 using media::audio::common::AudioEncapsulationType;
+using media::audio::common::AudioFlag;
 using media::audio::common::AudioFormatDescription;
 using media::audio::common::AudioFormatType;
 using media::audio::common::AudioGain;
@@ -95,6 +99,26 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Converters
 
+namespace {
+
+bool isVendorExtension(const std::string& s) {
+    // Must be the same as defined in AudioAttributes.aidl and {Playback|Record}TrackMetadata.aidl
+    static const std::regex vendorExtension("VX_[A-Z0-9]{3,}_[_A-Z0-9]+");
+    return std::regex_match(s.begin(), s.end(), vendorExtension);
+}
+
+std::vector<std::string> splitString(const std::string& s, char separator) {
+    std::istringstream iss(s);
+    std::string t;
+    std::vector<std::string> result;
+    while (std::getline(iss, t, separator)) {
+        result.push_back(std::move(t));
+    }
+    return result;
+}
+
+}  // namespace
+
 ::android::status_t aidl2legacy_string(std::string_view aidl, char* dest, size_t maxSize) {
     if (aidl.size() > maxSize - 1) {
         return BAD_VALUE;
@@ -1799,6 +1823,172 @@
     return unexpected(BAD_VALUE);
 }
 
+namespace {
+
+// TODO(b/281850726): Expose publicly once android.media.AudioFlag is removed.
+// Until that, `legacy2aidl_audio_flags_mask_t_AudioFlag` function is ambiguous.
+
+ConversionResult<audio_flags_mask_t>
+aidl2legacy_AudioFlag_audio_flags_mask_t(AudioFlag aidl) {
+    switch (aidl) {
+        case AudioFlag::NONE:
+            return AUDIO_FLAG_NONE;
+        case AudioFlag::AUDIBILITY_ENFORCED:
+            return AUDIO_FLAG_AUDIBILITY_ENFORCED;
+        // The is no AudioFlag::SECURE, see the comment in the AudioFlag.aidl
+        //  return AUDIO_FLAG_SECURE;
+        case AudioFlag::SCO:
+            return AUDIO_FLAG_SCO;
+        case AudioFlag::BEACON:
+            return AUDIO_FLAG_BEACON;
+        case AudioFlag::HW_AV_SYNC:
+            return AUDIO_FLAG_HW_AV_SYNC;
+        case AudioFlag::HW_HOTWORD:
+            return AUDIO_FLAG_HW_HOTWORD;
+        case AudioFlag::BYPASS_INTERRUPTION_POLICY:
+            return AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
+        case AudioFlag::BYPASS_MUTE:
+            return AUDIO_FLAG_BYPASS_MUTE;
+        case AudioFlag::LOW_LATENCY:
+            return AUDIO_FLAG_LOW_LATENCY;
+        case AudioFlag::DEEP_BUFFER:
+            return AUDIO_FLAG_DEEP_BUFFER;
+        case AudioFlag::NO_MEDIA_PROJECTION:
+            return AUDIO_FLAG_NO_MEDIA_PROJECTION;
+        case AudioFlag::MUTE_HAPTIC:
+            return AUDIO_FLAG_MUTE_HAPTIC;
+        case AudioFlag::NO_SYSTEM_CAPTURE:
+            return AUDIO_FLAG_NO_SYSTEM_CAPTURE;
+        case AudioFlag::CAPTURE_PRIVATE:
+            return AUDIO_FLAG_CAPTURE_PRIVATE;
+        case AudioFlag::CONTENT_SPATIALIZED:
+            return AUDIO_FLAG_CONTENT_SPATIALIZED;
+        case AudioFlag::NEVER_SPATIALIZE:
+            return AUDIO_FLAG_NEVER_SPATIALIZE;
+        case AudioFlag::CALL_REDIRECTION:
+            return AUDIO_FLAG_CALL_REDIRECTION;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioFlag>
+legacy2aidl_audio_flags_mask_t_AudioFlag(audio_flags_mask_t legacy) {
+    switch (legacy) {
+        case AUDIO_FLAG_NONE:
+            return AudioFlag::NONE;
+        case AUDIO_FLAG_AUDIBILITY_ENFORCED:
+            return AudioFlag::AUDIBILITY_ENFORCED;
+        case AUDIO_FLAG_SECURE:
+            return unexpected(BAD_VALUE);
+        case AUDIO_FLAG_SCO:
+            return AudioFlag::SCO;
+        case AUDIO_FLAG_BEACON:
+            return AudioFlag::BEACON;
+        case AUDIO_FLAG_HW_AV_SYNC:
+            return AudioFlag::HW_AV_SYNC;
+        case AUDIO_FLAG_HW_HOTWORD:
+            return AudioFlag::HW_HOTWORD;
+        case AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY:
+            return AudioFlag::BYPASS_INTERRUPTION_POLICY;
+        case AUDIO_FLAG_BYPASS_MUTE:
+            return AudioFlag::BYPASS_MUTE;
+        case AUDIO_FLAG_LOW_LATENCY:
+            return AudioFlag::LOW_LATENCY;
+        case AUDIO_FLAG_DEEP_BUFFER:
+            return AudioFlag::DEEP_BUFFER;
+        case AUDIO_FLAG_NO_MEDIA_PROJECTION:
+            return AudioFlag::NO_MEDIA_PROJECTION;
+        case AUDIO_FLAG_MUTE_HAPTIC:
+            return AudioFlag::MUTE_HAPTIC;
+        case AUDIO_FLAG_NO_SYSTEM_CAPTURE:
+            return AudioFlag::NO_SYSTEM_CAPTURE;
+        case AUDIO_FLAG_CAPTURE_PRIVATE:
+            return AudioFlag::CAPTURE_PRIVATE;
+        case AUDIO_FLAG_CONTENT_SPATIALIZED:
+            return AudioFlag::CONTENT_SPATIALIZED;
+        case AUDIO_FLAG_NEVER_SPATIALIZE:
+            return AudioFlag::NEVER_SPATIALIZE;
+        case AUDIO_FLAG_CALL_REDIRECTION:
+            return AudioFlag::CALL_REDIRECTION;
+    }
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_flags_mask_t>
+aidl2legacy_int32_t_audio_flags_mask_t_mask(int32_t aidl) {
+    return convertBitmask<audio_flags_mask_t, int32_t, audio_flags_mask_t, AudioFlag>(
+            aidl, aidl2legacy_AudioFlag_audio_flags_mask_t, indexToEnum_bitmask<AudioFlag>,
+            enumToMask_bitmask<audio_flags_mask_t, audio_flags_mask_t>);
+}
+
+ConversionResult<int32_t>
+legacy2aidl_audio_flags_mask_t_int32_t_mask(audio_flags_mask_t legacy) {
+    return convertBitmask<int32_t, audio_flags_mask_t, AudioFlag, audio_flags_mask_t>(
+            legacy, legacy2aidl_audio_flags_mask_t_AudioFlag,
+            indexToEnum_bitmask<audio_flags_mask_t>,
+            enumToMask_bitmask<int32_t, AudioFlag>);
+}
+
+}  // namespace
+
+ConversionResult<std::string>
+aidl2legacy_AudioTags_string(const std::vector<std::string>& aidl) {
+    std::ostringstream tagsBuffer;
+    bool hasValue = false;
+    for (const auto& tag : aidl) {
+        if (hasValue) {
+            tagsBuffer << AUDIO_ATTRIBUTES_TAGS_SEPARATOR;
+        }
+        if (isVendorExtension(tag)) {
+            // Note: with the current regex for vendor tags: VX_[A-Z0-9]{3,}_[_A-Z0-9]+
+            // it's impossible to create a vendor tag that would contain the separator, but in case
+            // the criteria changes, we double check it here.
+            if (strchr(tag.c_str(), AUDIO_ATTRIBUTES_TAGS_SEPARATOR) == nullptr) {
+                tagsBuffer << tag;
+                hasValue = true;
+            } else {
+                ALOGE("Vendor extension tag is ill-formed: \"%s\"", tag.c_str());
+                return unexpected(BAD_VALUE);
+            }
+        }
+    }
+    return tagsBuffer.str();
+}
+
+ConversionResult<std::vector<std::string>>
+legacy2aidl_string_AudioTags(const std::string& legacy) {
+    auto allTags = splitString(legacy, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+    std::vector<std::string> result;
+    std::copy_if(std::make_move_iterator(allTags.begin()), std::make_move_iterator(allTags.end()),
+                    std::back_inserter(result), isVendorExtension);
+    return result;
+}
+
+ConversionResult<audio_attributes_t>
+aidl2legacy_AudioAttributes_audio_attributes_t(const AudioAttributes& aidl) {
+    audio_attributes_t legacy;
+    legacy.content_type = VALUE_OR_RETURN(
+            aidl2legacy_AudioContentType_audio_content_type_t(aidl.contentType));
+    legacy.usage = VALUE_OR_RETURN(aidl2legacy_AudioUsage_audio_usage_t(aidl.usage));
+    legacy.source = VALUE_OR_RETURN(aidl2legacy_AudioSource_audio_source_t(aidl.source));
+    legacy.flags = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_flags_mask_t_mask(aidl.flags));
+    auto tagsString = VALUE_OR_RETURN(aidl2legacy_AudioTags_string(aidl.tags));
+    RETURN_IF_ERROR(aidl2legacy_string(tagsString, legacy.tags, sizeof(legacy.tags)));
+    return legacy;
+}
+
+ConversionResult<AudioAttributes>
+legacy2aidl_audio_attributes_t_AudioAttributes(const audio_attributes_t& legacy) {
+    AudioAttributes aidl;
+    aidl.contentType = VALUE_OR_RETURN(
+            legacy2aidl_audio_content_type_t_AudioContentType(legacy.content_type));
+    aidl.usage = VALUE_OR_RETURN(legacy2aidl_audio_usage_t_AudioUsage(legacy.usage));
+    aidl.source = VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSource(legacy.source));
+    aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_flags_mask_t_int32_t_mask(legacy.flags));
+    auto tagsString = VALUE_OR_RETURN(legacy2aidl_string(legacy.tags, sizeof(legacy.tags)));
+    aidl.tags = VALUE_OR_RETURN(legacy2aidl_string_AudioTags(tagsString));
+    return aidl;
+}
 
 ConversionResult<audio_encapsulation_mode_t>
 aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(AudioEncapsulationMode aidl) {
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index bc9d4d5..fc57f72 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -37,6 +37,7 @@
 #define PREFIX(f) <f>
 #endif
 
+#include PREFIX(android/media/audio/common/AudioAttributes.h)
 #include PREFIX(android/media/audio/common/AudioChannelLayout.h)
 #include PREFIX(android/media/audio/common/AudioConfig.h)
 #include PREFIX(android/media/audio/common/AudioConfigBase.h)
@@ -46,6 +47,7 @@
 #include PREFIX(android/media/audio/common/AudioEncapsulationMetadataType.h)
 #include PREFIX(android/media/audio/common/AudioEncapsulationMode.h)
 #include PREFIX(android/media/audio/common/AudioEncapsulationType.h)
+#include PREFIX(android/media/audio/common/AudioFlag.h)
 #include PREFIX(android/media/audio/common/AudioFormatDescription.h)
 #include PREFIX(android/media/audio/common/AudioGain.h)
 #include PREFIX(android/media/audio/common/AudioGainConfig.h)
@@ -355,6 +357,16 @@
 ConversionResult<media::audio::common::AudioUsage> legacy2aidl_audio_usage_t_AudioUsage(
         audio_usage_t legacy);
 
+ConversionResult<std::string>
+aidl2legacy_AudioTags_string(const std::vector<std::string>& aidl);
+ConversionResult<std::vector<std::string>>
+legacy2aidl_string_AudioTags(const std::string& legacy);
+
+ConversionResult<audio_attributes_t>
+aidl2legacy_AudioAttributes_audio_attributes_t(const media::audio::common::AudioAttributes& aidl);
+ConversionResult<media::audio::common::AudioAttributes>
+legacy2aidl_audio_attributes_t_AudioAttributes(const audio_attributes_t& legacy);
+
 ConversionResult<audio_uuid_t> aidl2legacy_AudioUuid_audio_uuid_t(
         const media::audio::common::AudioUuid &aidl);
 ConversionResult<media::audio::common::AudioUuid> legacy2aidl_audio_uuid_t_AudioUuid(
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
index f49f681..656d76a 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
@@ -119,6 +119,20 @@
 }
 
 /**
+ * A generic template that helps convert containers of convertible types without
+ * using an intermediate container.
+ */
+template<typename InputContainer, typename OutputContainer, typename Func>
+::android::status_t convertContainer(const InputContainer& input, OutputContainer* output,
+        const Func& itemConversion) {
+    auto ins = std::inserter(*output, output->begin());
+    for (const auto& item : input) {
+        *ins = VALUE_OR_RETURN_STATUS(itemConversion(item));
+    }
+    return ::android::OK;
+}
+
+/**
  * A generic template that helps convert containers of convertible types.
  */
 template<typename OutputContainer, typename InputContainer, typename Func>
@@ -208,6 +222,34 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Utilities for handling bitmasks.
+// Some AIDL enums are specified using bit indices, for example:
+//   `AidlEnum { FOO = 0, BAR = 1, BAZ = 2' }`
+// while corresponding legacy types universally uses actual bitmasks, for example:
+//   `enum legacy_enum_t { LEGACY_FOO = 1 << 0, LEGACY_BAR = 1 << 1, LEGACY_BAZ = 1 << 2 }`
+// There is also the third type used to store the resulting mask, which is combined
+// from individual bits. In AIDL this is typically an int (`int32_t`), in legacy types this
+// is often the enum type itself (although, strictly this is not correct since masks are not
+// declared as part of the enum type). The bit index value always has an integer type.
+//
+// `indexToEnum_index` constructs an instance of the enum from an index,
+// for example `AidlEnum::BAR` from `1`.
+// `indexToEnum_bitmask` produces a corresponding legacy bitmask enum instance,
+// for example, `LEGACY_BAR` (`2`) from `1`.
+// `enumToMask_bitmask` simply casts an enum type to a bitmask type.
+// `enumToMask_index` creates a mask from an enum type which specifies an index.
+//
+// All these functions can be plugged into `convertBitmask`. For example, to implement
+// conversion from `AidlEnum` to `legacy_enum_t`, with a mask stored in `int32_t`,
+// the following call needs to be made:
+//   convertBitmask<legacy_enum_t /*DestMask*/, int32_t /*SrcMask*/,
+//                  legacy_enum_t /*DestEnum*/, AidlEnum /*SrcEnum*/>(
+//     maskField /*int32_t*/, aidl2legacy_AidlEnum_legacy_enum_t /*enumConversion*/,
+//     indexToEnum_index<AidlEnum> /*srcIndexToEnum*/,
+//     enumToMask_bitmask<legacy_enum_t, legacy_enum_t> /*destEnumToMask*/)
+//
+// The only extra function needed is for mapping between corresponding enum values
+// of the AidlEnum and the legacy_enum_t. Note that the mapping is between values
+// of enums, for example, `AidlEnum::BAZ` maps to `LEGACY_BAZ` and vice versa.
 
 template<typename Enum>
 Enum indexToEnum_index(int index) {
diff --git a/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp b/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp
index c505e60..056698f 100644
--- a/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp
+++ b/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp
@@ -19,6 +19,7 @@
 
 #include <gtest/gtest.h>
 
+#include <media/AidlConversionCppNdk.h>
 #include <media/AidlConversionNdk.h>
 
 namespace {
@@ -89,3 +90,42 @@
     ASSERT_EQ(1, convBack.value().tags.size());
     EXPECT_EQ(initial.tags[1], convBack.value().tags[0]);
 }
+
+class AudioTagsRoundTripTest : public testing::TestWithParam<std::vector<std::string>>
+{
+};
+TEST_P(AudioTagsRoundTripTest, Aidl2Legacy2Aidl) {
+    const auto& initial = GetParam();
+    auto conv = aidl2legacy_AudioTags_string(initial);
+    ASSERT_TRUE(conv.ok());
+    auto convBack = legacy2aidl_string_AudioTags(conv.value());
+    ASSERT_TRUE(convBack.ok());
+    EXPECT_EQ(initial, convBack.value());
+}
+INSTANTIATE_TEST_SUITE_P(AudioTagsRoundTrip, AudioTagsRoundTripTest,
+        testing::Values(std::vector<std::string>{},
+                std::vector<std::string>{"VX_GOOGLE_41"},
+                std::vector<std::string>{"VX_GOOGLE_41", "VX_GOOGLE_42"}));
+
+TEST(AudioTags, NonVendorTags) {
+    const std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+    const std::vector<std::string> initial{
+        "random_string", "random" + separator + "string", "VX_GOOGLE_42"};
+    auto conv = aidl2legacy_AudioTags_string(initial);
+    ASSERT_TRUE(conv.ok());
+    EXPECT_EQ("VX_GOOGLE_42", conv.value());
+}
+
+TEST(AudioTags, IllFormedAidlTag) {
+    const std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+    const std::vector<std::string> initial{"VX_GOOGLE" + separator + "42", "VX_GOOGLE_42"};
+    auto conv = aidl2legacy_AudioTags_string(initial);
+    // Note: with the current regex for vendor tags: VX_[A-Z0-9]{3,}_[_A-Z0-9]+
+    // it's impossible to create a vendor tag that would contain the separator, but in case
+    // the criteria changes, we ensure that either such tags get filtered out or an error happens.
+    if (conv.ok()) {
+        EXPECT_EQ("VX_GOOGLE_42", conv.value());
+    } else {
+        EXPECT_FALSE(conv.ok()) << conv.value();
+    }
+}
diff --git a/media/audioaidlconversion/tests/audio_aidl_ndk_cpp_conversion_tests.cpp b/media/audioaidlconversion/tests/audio_aidl_ndk_cpp_conversion_tests.cpp
index 735a14b..206c35b 100644
--- a/media/audioaidlconversion/tests/audio_aidl_ndk_cpp_conversion_tests.cpp
+++ b/media/audioaidlconversion/tests/audio_aidl_ndk_cpp_conversion_tests.cpp
@@ -125,3 +125,12 @@
 INSTANTIATE_TEST_SUITE_P(AudioFormatDescriptionRoundTrip, AudioFormatDescriptionRoundTripTest,
         testing::Values(make_AFD_Invalid(), make_AFD_Default(), make_AFD_Pcm16Bit(),
                 make_AFD_Bitstream(), make_AFD_Encap(), make_AFD_Encap_with_Enc()));
+
+TEST(AudioPortRoundTripTest, Ndk2Cpp2Ndk) {
+    const AudioPort initial;
+    auto conv = ndk2cpp_AudioPort(initial);
+    ASSERT_TRUE(conv.ok());
+    auto convBack = cpp2ndk_AudioPort(conv.value());
+    ASSERT_TRUE(convBack.ok());
+    EXPECT_EQ(initial, convBack.value());
+}
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 3125e311..308acd0 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -135,11 +135,8 @@
 }
 
 status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
-    auto convertAudioPortFromMap = [](const Ports::value_type& pair) {
-        return ndk2cpp_AudioPort(pair.second);
-    };
-    return ::aidl::android::convertRange(mPorts.begin(), mPorts.end(), ports->begin(),
-            convertAudioPortFromMap);
+    return ::aidl::android::convertContainer(mPorts, ports,
+            [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
 }
 
 status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
index 8345cd2..c8cce96 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
@@ -83,24 +83,15 @@
     if (name == nullptr || device == nullptr) {
         return BAD_VALUE;
     }
-
-    // FIXME: Remove this call and the check for the supported module names
-    // after implementing retrieval of module names on the framework side.
-    // Currently it is still using the legacy XML config.
-    std::vector<std::string> deviceNames;
-    if (status_t status = getDeviceNames(&deviceNames); status != OK) {
-        return status;
-    }
     std::shared_ptr<IModule> service;
-    if (std::find(deviceNames.begin(), deviceNames.end(), name) != deviceNames.end()) {
-        if (strcmp(name, "primary") == 0) name = "default";
-        auto serviceName = std::string(IModule::descriptor) + "/" + name;
-        service = IModule::fromBinder(
-                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
-        ALOGE_IF(service == nullptr, "%s fromBinder %s failed", __func__, serviceName.c_str());
+    if (strcmp(name, "primary") == 0) name = "default";
+    auto serviceName = std::string(IModule::descriptor) + "/" + name;
+    service = IModule::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+    if (service == nullptr) {
+        ALOGE("%s fromBinder %s failed", __func__, serviceName.c_str());
+        return NO_INIT;
     }
-    // If the service is a nullptr, the device object will not be really functional,
-    // but will not crash either.
     *device = sp<DeviceHalAidl>::make(name, service);
     return OK;
 }
diff --git a/media/libeffects/factory/Android.bp b/media/libeffects/factory/Android.bp
index f56abbd..d94093e 100644
--- a/media/libeffects/factory/Android.bp
+++ b/media/libeffects/factory/Android.bp
@@ -21,6 +21,7 @@
     vendor: true,
     srcs: [
          "EffectsFactory.c",
+         "EffectsConfigLoader.c",
          "EffectsFactoryState.c",
          "EffectsXmlConfigLoader.cpp",
     ],
diff --git a/media/libeffects/factory/EffectsConfigLoader.c b/media/libeffects/factory/EffectsConfigLoader.c
new file mode 100644
index 0000000..a1de7b3
--- /dev/null
+++ b/media/libeffects/factory/EffectsConfigLoader.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectsFactoryConfigLoader"
+//#define LOG_NDEBUG 0
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <log/log.h>
+
+#include <system/audio_effects/audio_effects_conf.h>
+
+#include "EffectsConfigLoader.h"
+#include "EffectsFactoryState.h"
+
+/////////////////////////////////////////////////
+//      Local functions prototypes
+/////////////////////////////////////////////////
+
+static int loadEffectConfigFile(const char *path);
+static int loadLibraries(cnode *root);
+static int loadLibrary(cnode *root, const char *name);
+static int loadEffects(cnode *root);
+static int loadEffect(cnode *node);
+// To get and add the effect pointed by the passed node to the gSubEffectList
+static int addSubEffect(cnode *root);
+static lib_entry_t *getLibrary(const char *path);
+
+static lib_entry_t *gCachedLibrary;  // last library accessed by getLibrary()
+
+int EffectLoadEffectConfig()
+{
+    if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+        return loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+    } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+        return loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+    }
+    return 0;
+}
+
+int loadEffectConfigFile(const char *path)
+{
+    cnode *root;
+    char *data;
+
+    data = load_file(path, NULL);
+    if (data == NULL) {
+        return -ENODEV;
+    }
+    root = config_node("", "");
+    config_load(root, data);
+    loadLibraries(root);
+    loadEffects(root);
+    config_free(root);
+    free(root);
+    free(data);
+
+    return 0;
+}
+
+int loadLibraries(cnode *root)
+{
+    cnode *node;
+
+    node = config_find(root, LIBRARIES_TAG);
+    if (node == NULL) {
+        return -ENOENT;
+    }
+    node = node->first_child;
+    while (node) {
+        loadLibrary(node, node->name);
+        node = node->next;
+    }
+    return 0;
+}
+
+#ifdef __LP64__
+// audio_effects.conf always specifies 32 bit lib path: convert to 64 bit path if needed
+static const char *kLibraryPathRoot[] =
+        {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
+#else
+static const char *kLibraryPathRoot[] =
+        {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
+#endif
+
+static const int kLibraryPathRootSize =
+        (sizeof(kLibraryPathRoot) / sizeof(kLibraryPathRoot[0]));
+
+// Checks if the library path passed as lib_path_in can be opened and if not
+// tries in standard effect library directories with just the library name and returns correct path
+// in lib_path_out
+int checkLibraryPath(const char *lib_path_in, char *lib_path_out) {
+    char *str;
+    const char *lib_name;
+    size_t len;
+
+    if (lib_path_in == NULL || lib_path_out == NULL) {
+        return -EINVAL;
+    }
+
+    strlcpy(lib_path_out, lib_path_in, PATH_MAX);
+
+    // Try exact path first
+    str = strstr(lib_path_out, "/lib/soundfx/");
+    if (str == NULL) {
+        return -EINVAL;
+    }
+
+    // Extract library name from input path
+    len = str - lib_path_out;
+    lib_name = lib_path_in + len + strlen("/lib/soundfx/");
+
+    // Then try with library name and standard path names in order of preference
+    for (int i = 0; i < kLibraryPathRootSize; i++) {
+        char path[PATH_MAX];
+
+        snprintf(path,
+                 PATH_MAX,
+                 "%s/%s",
+                 kLibraryPathRoot[i],
+                 lib_name);
+        if (F_OK == access(path, 0)) {
+            strlcpy(lib_path_out, path, PATH_MAX);
+            ALOGW_IF(strncmp(lib_path_out, lib_path_in, PATH_MAX) != 0,
+                "checkLibraryPath() corrected library path %s to %s", lib_path_in, lib_path_out);
+            return 0;
+        }
+    }
+    return -EINVAL;
+}
+
+
+
+int loadLibrary(cnode *root, const char *name)
+{
+    cnode *node;
+    void *hdl = NULL;
+    audio_effect_library_t *desc;
+    list_elem_t *e;
+    lib_entry_t *l;
+    char path[PATH_MAX];
+
+    node = config_find(root, PATH_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+
+    if (checkLibraryPath((const char *)node->value, path) != 0) {
+        ALOGW("loadLibrary() could not find library %s", path);
+        goto error;
+    }
+
+    hdl = dlopen(path, RTLD_NOW);
+    if (hdl == NULL) {
+        ALOGW("loadLibrary() failed to open %s", path);
+        goto error;
+    }
+
+    desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
+    if (desc == NULL) {
+        ALOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
+        goto error;
+    }
+
+    if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
+        ALOGW("getLibrary() bad tag %08x in lib info struct", desc->tag);
+        goto error;
+    }
+
+    if (EFFECT_API_VERSION_MAJOR(desc->version) !=
+            EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
+        ALOGW("loadLibrary() bad lib version %08x", desc->version);
+        goto error;
+    }
+
+    // add entry for library in gLibraryList
+    l = malloc(sizeof(lib_entry_t));
+    l->name = strndup(name, PATH_MAX);
+    l->path = strndup(path, PATH_MAX);
+    l->handle = hdl;
+    l->desc = desc;
+    l->effects = NULL;
+    pthread_mutex_init(&l->lock, NULL);
+
+    e = malloc(sizeof(list_elem_t));
+    e->object = l;
+    pthread_mutex_lock(&gLibLock);
+    e->next = gLibraryList;
+    gLibraryList = e;
+    pthread_mutex_unlock(&gLibLock);
+    ALOGV("getLibrary() linked library %p for path %s", l, path);
+
+    return 0;
+
+error:
+    if (hdl != NULL) {
+        dlclose(hdl);
+    }
+    //add entry for library errors in gLibraryFailedList
+    lib_failed_entry_t *fl = malloc(sizeof(lib_failed_entry_t));
+    fl->name = strndup(name, PATH_MAX);
+    fl->path = strndup(path, PATH_MAX);
+
+    list_elem_t *fe = malloc(sizeof(list_elem_t));
+    fe->object = fl;
+    fe->next = gLibraryFailedList;
+    gLibraryFailedList = fe;
+    ALOGV("getLibrary() linked error in library %p for path %s", fl, path);
+
+    return -EINVAL;
+}
+
+// This will find the library and UUID tags of the sub effect pointed by the
+// node, gets the effect descriptor and lib_entry_t and adds the subeffect -
+// sub_entry_t to the gSubEffectList
+int addSubEffect(cnode *root)
+{
+    ALOGV("addSubEffect");
+    cnode *node;
+    effect_uuid_t uuid;
+    effect_descriptor_t *d;
+    lib_entry_t *l;
+    list_elem_t *e;
+    node = config_find(root, LIBRARY_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+    l = getLibrary(node->value);
+    if (l == NULL) {
+        ALOGW("addSubEffect() could not get library %s", node->value);
+        return -EINVAL;
+    }
+    node = config_find(root, UUID_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+    if (stringToUuid(node->value, &uuid) != 0) {
+        ALOGW("addSubEffect() invalid uuid %s", node->value);
+        return -EINVAL;
+    }
+    d = malloc(sizeof(effect_descriptor_t));
+    if (l->desc->get_descriptor(&uuid, d) != 0) {
+        char s[40];
+        uuidToString(&uuid, s, 40);
+        ALOGW("Error querying effect %s on lib %s", s, l->name);
+        free(d);
+        return -EINVAL;
+    }
+#if (LOG_NDEBUG==0)
+    char s[512];
+    dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
+    ALOGV("addSubEffect() read descriptor %p:%s",d, s);
+#endif
+    if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
+            EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
+        ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
+        free(d);
+        return -EINVAL;
+    }
+    sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t));
+    sub_effect->object = d;
+    // lib_entry_t is stored since the sub effects are not linked to the library
+    sub_effect->lib = l;
+    e = malloc(sizeof(list_elem_t));
+    e->object = sub_effect;
+    e->next = gSubEffectList->sub_elem;
+    gSubEffectList->sub_elem = e;
+    ALOGV("addSubEffect end");
+    return 0;
+}
+
+int loadEffects(cnode *root)
+{
+    cnode *node;
+
+    node = config_find(root, EFFECTS_TAG);
+    if (node == NULL) {
+        return -ENOENT;
+    }
+    node = node->first_child;
+    while (node) {
+        loadEffect(node);
+        node = node->next;
+    }
+    return 0;
+}
+
+int loadEffect(cnode *root)
+{
+    cnode *node;
+    effect_uuid_t uuid;
+    lib_entry_t *l;
+    effect_descriptor_t *d;
+    list_elem_t *e;
+
+    node = config_find(root, LIBRARY_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+
+    l = getLibrary(node->value);
+    if (l == NULL) {
+        ALOGW("loadEffect() could not get library %s", node->value);
+        return -EINVAL;
+    }
+
+    node = config_find(root, UUID_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+    if (stringToUuid(node->value, &uuid) != 0) {
+        ALOGW("loadEffect() invalid uuid %s", node->value);
+        return -EINVAL;
+    }
+    lib_entry_t *tmp;
+    bool skip = false;
+    if (findEffect(NULL, &uuid, &tmp, NULL) == 0) {
+        ALOGW("skipping duplicate uuid %s %s", node->value,
+                node->next ? "and its sub-effects" : "");
+        skip = true;
+    }
+
+    d = malloc(sizeof(effect_descriptor_t));
+    if (l->desc->get_descriptor(&uuid, d) != 0) {
+        char s[40];
+        uuidToString(&uuid, s, 40);
+        ALOGW("Error querying effect %s on lib %s", s, l->name);
+        free(d);
+        return -EINVAL;
+    }
+#if (LOG_NDEBUG==0)
+    char s[512];
+    dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
+    ALOGV("loadEffect() read descriptor %p:%s",d, s);
+#endif
+    if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
+            EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
+        ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
+        free(d);
+        return -EINVAL;
+    }
+    e = malloc(sizeof(list_elem_t));
+    e->object = d;
+    if (skip) {
+        e->next = gSkippedEffects;
+        gSkippedEffects = e;
+        return -EINVAL;
+    } else {
+        e->next = l->effects;
+        l->effects = e;
+    }
+
+    // After the UUID node in the config_tree, if node->next is valid,
+    // that would be sub effect node.
+    // Find the sub effects and add them to the gSubEffectList
+    node = node->next;
+    int count = 2;
+    bool hwSubefx = false, swSubefx = false;
+    list_sub_elem_t *sube = NULL;
+    if (node != NULL) {
+        ALOGV("Adding the effect to gEffectSubList as there are sub effects");
+        sube = malloc(sizeof(list_sub_elem_t));
+        sube->object = d;
+        sube->sub_elem = NULL;
+        sube->next = gSubEffectList;
+        gSubEffectList = sube;
+    }
+    while (node != NULL && count) {
+       if (addSubEffect(node)) {
+           ALOGW("loadEffect() could not add subEffect %s", node->value);
+           // Change the gSubEffectList to point to older list;
+           gSubEffectList = sube->next;
+           free(sube->sub_elem);// Free an already added sub effect
+           sube->sub_elem = NULL;
+           free(sube);
+           return -ENOENT;
+       }
+       sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object;
+       effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object);
+       // Since we return a stub descriptor for the proxy during
+       // get_descriptor call,we replace it with the correspoding
+       // sw effect descriptor, but with Proxy UUID
+       // check for Sw desc
+        if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) ==
+                                           EFFECT_FLAG_HW_ACC_TUNNEL)) {
+             swSubefx = true;
+             *d = *subEffectDesc;
+             d->uuid = uuid;
+             ALOGV("loadEffect() Changed the Proxy desc");
+       } else
+           hwSubefx = true;
+       count--;
+       node = node->next;
+    }
+    // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc
+    if (hwSubefx && swSubefx) {
+        d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+    }
+    return 0;
+}
+
+lib_entry_t *getLibrary(const char *name)
+{
+    list_elem_t *e;
+
+    if (gCachedLibrary &&
+            !strncmp(gCachedLibrary->name, name, PATH_MAX)) {
+        return gCachedLibrary;
+    }
+
+    e = gLibraryList;
+    while (e) {
+        lib_entry_t *l = (lib_entry_t *)e->object;
+        if (!strcmp(l->name, name)) {
+            gCachedLibrary = l;
+            return l;
+        }
+        e = e->next;
+    }
+
+    return NULL;
+}
diff --git a/media/libeffects/factory/EffectsConfigLoader.h b/media/libeffects/factory/EffectsConfigLoader.h
new file mode 100644
index 0000000..3f82609
--- /dev/null
+++ b/media/libeffects/factory/EffectsConfigLoader.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_EFFECTSCONFIGLOADER_H
+#define ANDROID_EFFECTSCONFIGLOADER_H
+
+#include <cutils/compiler.h>
+#include "EffectsFactoryState.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/** Parses the platform effect configuration
+ * and stores its content in the global EffectFactoryState. */
+ANDROID_API
+int EffectLoadEffectConfig();
+
+
+#ifdef  __cplusplus
+} // extern "C"
+#endif
+
+#endif  // ANDROID_EFFECTSCONFIGLOADER_H
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 38ba4b0..dcdf634 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -26,6 +26,7 @@
 
 #include <media/EffectsFactoryApi.h>
 
+#include "EffectsConfigLoader.h"
 #include "EffectsFactoryState.h"
 #include "EffectsXmlConfigLoader.h"
 
@@ -463,7 +464,8 @@
     } else {
         gConfigNbElemSkipped = EffectLoadXmlEffectConfig(NULL);
         if (gConfigNbElemSkipped < 0) {
-            ALOGE("Failed to load XML effect configuration with status %zd", gConfigNbElemSkipped);
+            ALOGW("Failed to load XML effect configuration, fallback to .conf");
+            EffectLoadEffectConfig();
         } else if (gConfigNbElemSkipped > 0) {
             ALOGE("Effect config is partially invalid, skipped %zd elements", gConfigNbElemSkipped);
         }
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index f24c15c..9bff136 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -26,6 +26,7 @@
 
 #include <media/EffectsConfig.h>
 
+#include "EffectsConfigLoader.h"
 #include "EffectsFactoryState.h"
 #include "EffectsXmlConfigLoader.h"
 
diff --git a/media/libeffects/factory/test/DumpConfig.cpp b/media/libeffects/factory/test/DumpConfig.cpp
index 1fecf06..331826f 100644
--- a/media/libeffects/factory/test/DumpConfig.cpp
+++ b/media/libeffects/factory/test/DumpConfig.cpp
@@ -14,37 +14,49 @@
  * limitations under the License.
  */
 
-#include <media/EffectsFactoryApi.h>
-#include <unistd.h>
+#include <getopt.h>
 
+#include <media/EffectsFactoryApi.h>
 #include "EffectsXmlConfigLoader.h"
+#include "EffectsConfigLoader.h"
 
 int main(int argc, char* argv[]) {
-    char* path = nullptr;
-    if ((argc == 2 || argc == 3) && strcmp(argv[1], "--xml") == 0) {
-        if (argc == 3) {
-            path = argv[2];
-            fprintf(stderr, "Dumping XML effect config file: %s\n", path);
-        } else {
-            fprintf(stderr, "Dumping default XML effect config file.\n");
+    const char* const short_opts = "lx:h";
+    const option long_opts[] = {{"legacy", no_argument, nullptr, 'l'},
+                                {"xml", optional_argument, nullptr, 'x'},
+                                {"help", no_argument, nullptr, 'h'}};
+
+    const auto opt = getopt_long(argc, argv, short_opts, long_opts, nullptr);
+    switch (opt) {
+        case 'l': { // -l or --legacy
+            printf("Dumping legacy effect config file\n");
+            if (EffectLoadEffectConfig() < 0) {
+                fprintf(stderr, "loadEffectConfig failed, see logcat for detail.\n");
+                return 1;
+            }
+            return EffectDumpEffects(STDOUT_FILENO);
         }
-    } else {
-        fprintf(stderr, "Invalid arguments.\nUsage: %s [--xml [FILE]]\n", argv[0]);
-        return 1;
-    }
-
-    ssize_t ret = EffectLoadXmlEffectConfig(path);
-    if (ret < 0) {
-        fprintf(stderr, "loadXmlEffectConfig failed, see logcat for detail.\n");
-        return 2;
-    }
-    if (ret > 0) {
-        fprintf(stderr, "Partially failed to load config. Skipped %zu elements, "
-                "see logcat for detail.\n", (size_t)ret);
-    }
-
-    if (EffectDumpEffects(STDOUT_FILENO) != 0) {
-        fprintf(stderr, "Effect dump failed, see logcat for detail.\n");
-        return 4;
+        case 'x': { // -x or --xml
+            printf("Dumping effect config file: %s\n", (optarg == NULL) ? "default" : optarg);
+            ssize_t ret = EffectLoadXmlEffectConfig(optarg);
+            if (ret < 0) {
+                fprintf(stderr, "loadXmlEffectConfig failed, see logcat for detail.\n");
+                return 1;
+            }
+            if (ret > 0) {
+                printf("Partially failed to load config. Skipped %zu elements.\n",
+                        (size_t)ret);
+            }
+            return EffectDumpEffects(STDOUT_FILENO);
+        }
+        case 'h': // -h or --help
+        default: {
+            printf("Usage: %s\n"
+                   "--legacy (or -l):        Legacy audio effect config file to load\n"
+                   "--xml (or -x) <FILE>:    Audio effect config file to load\n"
+                   "--help (or -h):          Show this help\n",
+                   argv[0]);
+            return 0;
+        }
     }
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c02573e..94851fb 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -155,6 +155,7 @@
 static const char *kCodecLatencyUnknown = "android.media.mediacodec.latency.unknown";
 static const char *kCodecQueueSecureInputBufferError = "android.media.mediacodec.queueSecureInputBufferError";
 static const char *kCodecQueueInputBufferError = "android.media.mediacodec.queueInputBufferError";
+static const char *kCodecComponentColorFormat = "android.media.mediacodec.component-color-format";
 
 static const char *kCodecNumLowLatencyModeOn = "android.media.mediacodec.low-latency.on";  /* 0..n */
 static const char *kCodecNumLowLatencyModeOff = "android.media.mediacodec.low-latency.off";  /* 0..n */
@@ -1129,7 +1130,7 @@
     // Video rendering quality metrics
     {
         const VideoRenderQualityMetrics &m = mVideoRenderQualityTracker.getMetrics();
-        if (m.frameRenderedCount > 0) {
+        if (m.frameReleasedCount > 0) {
             mediametrics_setInt64(mMetricsHandle, kCodecFirstRenderTimeUs, m.firstRenderTimeUs);
             mediametrics_setInt64(mMetricsHandle, kCodecFramesReleased, m.frameReleasedCount);
             mediametrics_setInt64(mMetricsHandle, kCodecFramesRendered, m.frameRenderedCount);
@@ -1534,7 +1535,11 @@
                 ALOGE("processRenderedFrames: no media time found");
                 continue;
             }
-            mVideoRenderQualityTracker.onFrameRendered(mediaTimeUs, renderTimeNs);
+            // Tunneled frames use INT64_MAX to indicate end-of-stream, so don't report it as a
+            // rendered frame.
+            if (!mTunneled || mediaTimeUs != INT64_MAX) {
+                mVideoRenderQualityTracker.onFrameRendered(mediaTimeUs, renderTimeNs);
+            }
         }
     }
 }
@@ -3807,6 +3812,14 @@
                         if (interestingFormat->findInt32("level", &level)) {
                             mediametrics_setInt32(mMetricsHandle, kCodecLevel, level);
                         }
+                        sp<AMessage> uncompressedFormat =
+                                (mFlags & kFlagIsEncoder) ? mInputFormat : mOutputFormat;
+                        int32_t componentColorFormat  = -1;
+                        if (uncompressedFormat->findInt32("android._color-format",
+                                &componentColorFormat)) {
+                            mediametrics_setInt32(mMetricsHandle,
+                                    kCodecComponentColorFormat, componentColorFormat);
+                        }
                         updateHdrMetrics(true /* isConfig */);
                         int32_t codecMaxInputSize = -1;
                         if (mInputFormat->findInt32(KEY_MAX_INPUT_SIZE, &codecMaxInputSize)) {
@@ -5818,6 +5831,10 @@
     }
 
     if (err == OK) {
+        if (mTunneled && (flags & (BUFFER_FLAG_DECODE_ONLY | BUFFER_FLAG_END_OF_STREAM)) == 0) {
+            mVideoRenderQualityTracker.onTunnelFrameQueued(timeUs);
+        }
+
         // synchronization boundary for getBufferAndFormat
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
@@ -5900,7 +5917,7 @@
     }
 
     if (render && buffer->size() != 0) {
-        int64_t mediaTimeUs = -1;
+        int64_t mediaTimeUs = INT64_MIN;
         buffer->meta()->findInt64("timeUs", &mediaTimeUs);
 
         bool noRenderTime = false;
@@ -5931,8 +5948,11 @@
         // If rendering to the screen, then schedule a time in the future to poll to see if this
         // frame was ever rendered to seed onFrameRendered callbacks.
         if (mIsSurfaceToDisplay) {
-            noRenderTime ? mVideoRenderQualityTracker.onFrameReleased(mediaTimeUs)
-                         : mVideoRenderQualityTracker.onFrameReleased(mediaTimeUs, renderTimeNs);
+            if (mediaTimeUs != INT64_MIN) {
+                noRenderTime ? mVideoRenderQualityTracker.onFrameReleased(mediaTimeUs)
+                             : mVideoRenderQualityTracker.onFrameReleased(mediaTimeUs,
+                                                                          renderTimeNs);
+            }
             // can't initialize this in the constructor because the Looper parent class needs to be
             // initialized first
             if (mMsgPollForRenderedBuffers == nullptr) {
@@ -5963,9 +5983,10 @@
         }
     } else {
         if (mIsSurfaceToDisplay) {
-            int64_t mediaTimeUs = -1;
-            buffer->meta()->findInt64("timeUs", &mediaTimeUs);
-            mVideoRenderQualityTracker.onFrameSkipped(mediaTimeUs);
+            int64_t mediaTimeUs = INT64_MIN;
+            if (buffer->meta()->findInt64("timeUs", &mediaTimeUs)) {
+                mVideoRenderQualityTracker.onFrameSkipped(mediaTimeUs);
+            }
         }
         mBufferChannel->discardBuffer(buffer);
     }
diff --git a/media/libstagefright/VideoRenderQualityTracker.cpp b/media/libstagefright/VideoRenderQualityTracker.cpp
index 1072cdd..df25ead 100644
--- a/media/libstagefright/VideoRenderQualityTracker.cpp
+++ b/media/libstagefright/VideoRenderQualityTracker.cpp
@@ -87,6 +87,25 @@
     clear();
 }
 
+void VideoRenderQualityTracker::onTunnelFrameQueued(int64_t contentTimeUs) {
+    if (!mConfiguration.enabled) {
+        return;
+    }
+
+    // Since P-frames are queued out of order, hold onto the P-frame until we can track it in
+    // render order. This only works because it depends on today's encoding algorithms that only
+    // allow B-frames to refer to ONE P-frame that comes after it. If the cardinality of P-frames
+    // in a single mini-GOP is increased, this algorithm breaks down.
+    if (mTunnelFrameQueuedContentTimeUs == -1) {
+        mTunnelFrameQueuedContentTimeUs = contentTimeUs;
+    } else if (contentTimeUs < mTunnelFrameQueuedContentTimeUs) {
+        onFrameReleased(contentTimeUs, 0);
+    } else {
+        onFrameReleased(mTunnelFrameQueuedContentTimeUs, 0);
+        mTunnelFrameQueuedContentTimeUs = contentTimeUs;
+    }
+}
+
 void VideoRenderQualityTracker::onFrameSkipped(int64_t contentTimeUs) {
     if (!mConfiguration.enabled) {
         return;
@@ -137,6 +156,13 @@
     }
     mPendingSkippedFrameContentTimeUsList = {};
 
+    // We can render a pending queued frame if it's the last frame of the video, so release it
+    // immediately.
+    if (contentTimeUs == mTunnelFrameQueuedContentTimeUs && mTunnelFrameQueuedContentTimeUs != -1) {
+        onFrameReleased(mTunnelFrameQueuedContentTimeUs, 0);
+        mTunnelFrameQueuedContentTimeUs = -1;
+    }
+
     static const FrameInfo noFrame = {-1, -1};
     FrameInfo nextExpectedFrame = noFrame;
     while (!mNextExpectedRenderedFrameQueue.empty()) {
@@ -211,6 +237,7 @@
     // discontinuity. While stuttering or freezing could be found in the next few frames, the impact
     // to the user is is minimal, so better to just keep things simple and don't bother.
     mNextExpectedRenderedFrameQueue = {};
+    mTunnelFrameQueuedContentTimeUs = -1;
 
     // Ignore any frames that were skipped just prior to the discontinuity.
     mPendingSkippedFrameContentTimeUsList = {};
diff --git a/media/libstagefright/include/media/stagefright/MediaHistogram.h b/media/libstagefright/include/media/stagefright/MediaHistogram.h
index da8415a..50fa258 100644
--- a/media/libstagefright/include/media/stagefright/MediaHistogram.h
+++ b/media/libstagefright/include/media/stagefright/MediaHistogram.h
@@ -197,13 +197,11 @@
         for (int i = 0; i < mBucketLimits.size(); ++i) {
             ss << ',' << mBucketLimits[i];
         }
-        ss << ',' << mCeiling;
     } else {
         ss << mFloor;
-        for (int i = 0; i < mBuckets.size(); ++i) {
+        for (int i = 1; i <= mBuckets.size(); ++i) {
             ss << ',' << (mFloor + i * mWidth);
         }
-        ss << ',' << mCeiling;
     }
     return ss.str();
 }
diff --git a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index ec25a36..8bfead9 100644
--- a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -150,6 +150,9 @@
     VideoRenderQualityTracker();
     VideoRenderQualityTracker(const Configuration &configuration);
 
+    // Called when a tunnel mode frame has been queued.
+    void onTunnelFrameQueued(int64_t contentTimeUs);
+
     // Called when the app has intentionally decided not to render this frame.
     void onFrameSkipped(int64_t contentTimeUs);
 
@@ -277,6 +280,11 @@
     // checking to see if the next expected frame is rendered. If not, it is considered dropped.
     std::queue<FrameInfo> mNextExpectedRenderedFrameQueue;
 
+    // When B-frames are present in the stream, a P-frame will be queued before the B-frame even
+    // though it is rendered after. Therefore, the P-frame is held here and not inserted into
+    // mNextExpectedRenderedFrameQueue until it should be inserted to maintain render order.
+    int64_t mTunnelFrameQueuedContentTimeUs;
+
     // Frame durations derived from timestamps encoded into the content stream. These are the
     // durations that each frame is supposed to be rendered for.
     FrameDurationUs mContentFrameDurationUs;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ddc87fe..74ae9a4 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -842,6 +842,8 @@
     for (const auto& vibratorInfo : mAudioVibratorInfos) {
         dprintf(fd, "  - %s\n", vibratorInfo.toString().c_str());
     }
+    dprintf(fd, "Bluetooth latency modes are %senabled\n",
+            mBluetoothLatencyModesEnabled ? "" : "not ");
 }
 
 void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args __unused)
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 76a51d3..06db915 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6321,6 +6321,12 @@
     } else {
         dprintf(fd, "  No FastMixer\n");
     }
+
+     dprintf(fd, "Bluetooth latency modes are %senabled\n",
+            mBluetoothLatencyModesEnabled ? "" : "not ");
+     dprintf(fd, "HAL does %ssupport Bluetooth latency modes\n", mOutput != nullptr &&
+             mOutput->audioHwDev->supportsBluetoothVariableLatency() ? "" : "not ");
+     dprintf(fd, "Supported latency modes: %s\n", toString(mSupportedLatencyModes).c_str());
 }
 
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index a2a9e8e..d5b6a98 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -67,7 +67,7 @@
                                 pid_t creatorPid,
                                 uid_t uid,
                                 bool isOut,
-                                alloc_type alloc = ALLOC_CBLK,
+                                const alloc_type alloc = ALLOC_CBLK,
                                 track_type type = TYPE_DEFAULT,
                                 audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
                                 std::string metricsId = {});
@@ -352,6 +352,7 @@
                                     // this could be a track type if needed later
 
     const wp<ThreadBase> mThread;
+    const alloc_type     mAllocType;
     /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
     sp<IMemory>         mCblkMemory;
     audio_track_cblk_t* mCblk;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 696d852..d3bf699 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -90,12 +90,13 @@
             pid_t creatorPid,
             uid_t clientUid,
             bool isOut,
-            alloc_type alloc,
+            const alloc_type alloc,
             track_type type,
             audio_port_handle_t portId,
             std::string metricsId)
     :   RefBase(),
         mThread(thread),
+        mAllocType(alloc),
         mClient(client),
         mCblk(NULL),
         // mBuffer, mBufferSize
@@ -277,6 +278,10 @@
         // relying on the automatic clear() at end of scope.
         mClient.clear();
     }
+    if (mAllocType == ALLOC_LOCAL) {
+        free(mBuffer);
+        mBuffer = nullptr;
+    }
     // flush the binder command buffer
     IPCThreadState::self()->flushCommands();
 }
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index 1d570b7..8b76842 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -7,9 +7,13 @@
     default_applicable_licenses: ["frameworks_av_license"],
 }
 
-cc_library_static {
+cc_library {
     name: "libaudiopolicycomponents",
 
+    defaults: [
+        "latest_android_media_audio_common_types_cpp_shared",
+    ],
+
     srcs: [
         "src/AudioCollections.cpp",
         "src/AudioInputDescriptor.cpp",
@@ -31,7 +35,11 @@
         "src/TypeConverter.cpp",
     ],
     shared_libs: [
+        "audioclient-types-aidl-cpp",
+        "audiopolicy-types-aidl-cpp",
+        "libaudioclient_aidl_conversion",
         "libaudiofoundation",
+        "libaudiopolicy",
         "libbase",
         "libcutils",
         "libhidlbase",
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 876911d..febccac 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -424,6 +424,15 @@
     bool supportsAllDevices(const DeviceVector &devices) const;
 
     /**
+     * @brief supportsAtLeastOne checks if any device in devices is currently supported
+     * @param devices to be checked against
+     * @return true if the device is weakly supported by type (e.g. for non bus / rsubmix devices),
+     *         true if the device is supported (both type and address) for bus / remote submix
+     *         false otherwise
+     */
+    bool supportsAtLeastOne(const DeviceVector &devices) const;
+
+    /**
      * @brief supportsDevicesForPlayback
      * @param devices to be checked against
      * @return true if the devices is a supported combo for playback
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 32c78a1..1f6002f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -23,6 +23,7 @@
 
 #include <DeviceDescriptor.h>
 #include <HwModule.h>
+#include <android/media/AudioPolicyConfig.h>
 #include <error/Result.h>
 #include <utils/StrongPointer.h>
 #include <utils/RefBase.h>
@@ -42,6 +43,8 @@
     // Surround formats, with an optional list of subformats that are equivalent from users' POV.
     using SurroundFormats = std::unordered_map<audio_format_t, std::unordered_set<audio_format_t>>;
 
+    // The source used to indicate the configuration from the AIDL HAL.
+    static const constexpr char* const kAidlConfigSource = "AIDL HAL";
     // The source used to indicate the default fallback configuration.
     static const constexpr char* const kDefaultConfigSource = "AudioPolicyConfig::setDefault";
     // The suffix of the "engine default" implementation shared library name.
@@ -49,6 +52,9 @@
 
     // Creates the default (fallback) configuration.
     static sp<const AudioPolicyConfig> createDefault();
+    // Attempts to load the configuration from the AIDL config falls back to default on failure.
+    static sp<const AudioPolicyConfig> loadFromApmAidlConfigWithFallback(
+            const media::AudioPolicyConfig& aidl);
     // Attempts to load the configuration from the XML file, falls back to default on failure.
     // If the XML file path is not provided, uses `audio_get_audio_policy_config_file` function.
     static sp<const AudioPolicyConfig> loadFromApmXmlConfigWithFallback(
@@ -140,6 +146,7 @@
     AudioPolicyConfig() = default;
 
     void augmentData();
+    status_t loadFromAidl(const media::AudioPolicyConfig& aidl);
     status_t loadFromXml(const std::string& xmlFilePath, bool forVts);
 
     std::string mSource;  // Not kDefaultConfigSource. Empty source means an empty config.
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 92292e1..7e29e10 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -138,7 +138,7 @@
      */
     status_t setUserIdDeviceAffinities(int userId, const AudioDeviceTypeAddrVector& devices);
     status_t removeUserIdDeviceAffinities(int userId);
-    status_t getDevicesForUserId(int userId, Vector<AudioDeviceTypeAddr>& devices) const;
+    status_t getDevicesForUserId(int userId, AudioDeviceTypeAddrVector& devices) const;
 
     void dump(String8 *dst) const;
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 436fcc1..e994758 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -39,7 +39,8 @@
 class HwModule : public RefBase
 {
 public:
-    explicit HwModule(const char *name, uint32_t halVersionMajor = 0, uint32_t halVersionMinor = 0);
+    explicit HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor);
+    HwModule(const char *name, uint32_t halVersion = 0);
     ~HwModule();
 
     const char *getName() const { return mName.string(); }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 09ca989..ac1f8b2 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -389,6 +389,11 @@
     return supportedDevices().containsAllDevices(devices);
 }
 
+bool SwAudioOutputDescriptor::supportsAtLeastOne(const DeviceVector &devices) const
+{
+    return filterSupportedDevices(devices).size() > 0;
+}
+
 bool SwAudioOutputDescriptor::supportsDevicesForPlayback(const DeviceVector &devices) const
 {
     // No considering duplicated output
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index 42c76e2..e214ae9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -19,6 +19,9 @@
 #include <AudioPolicyConfig.h>
 #include <IOProfile.h>
 #include <Serializer.h>
+#include <hardware/audio.h>
+#include <media/AidlConversion.h>
+#include <media/AidlConversionUtil.h>
 #include <media/AudioProfile.h>
 #include <system/audio.h>
 #include <system/audio_config.h>
@@ -26,6 +29,142 @@
 
 namespace android {
 
+using media::audio::common::AudioIoFlags;
+using media::audio::common::AudioPortDeviceExt;
+using media::audio::common::AudioPortExt;
+
+namespace {
+
+ConversionResult<sp<PolicyAudioPort>>
+aidl2legacy_portId_PolicyAudioPort(int32_t portId,
+        const std::unordered_map<int32_t, sp<PolicyAudioPort>>& ports) {
+    if (auto it = ports.find(portId); it != ports.end()) {
+        return it->second;
+    }
+    return base::unexpected(BAD_VALUE);
+}
+
+ConversionResult<sp<AudioRoute>>
+aidl2legacy_AudioRoute(const media::AudioRoute& aidl,
+        const std::unordered_map<int32_t, sp<PolicyAudioPort>>& ports) {
+    auto legacy = sp<AudioRoute>::make(aidl.isExclusive ? AUDIO_ROUTE_MUX : AUDIO_ROUTE_MIX);
+    auto legacySink = VALUE_OR_RETURN(aidl2legacy_portId_PolicyAudioPort(aidl.sinkPortId, ports));
+    legacy->setSink(legacySink);
+    PolicyAudioPortVector legacySources;
+    for (int32_t portId : aidl.sourcePortIds) {
+        sp<PolicyAudioPort> legacyPort = VALUE_OR_RETURN(
+                aidl2legacy_portId_PolicyAudioPort(portId, ports));
+        legacySources.add(legacyPort);
+    }
+    legacy->setSources(legacySources);
+    legacySink->addRoute(legacy);
+    for (const auto& legacySource : legacySources) {
+        legacySource->addRoute(legacy);
+    }
+    return legacy;
+}
+
+status_t aidl2legacy_AudioHwModule_HwModule(const media::AudioHwModule& aidl,
+        sp<HwModule>* legacy,
+        DeviceVector* attachedInputDevices, DeviceVector* attachedOutputDevices,
+        sp<DeviceDescriptor>* defaultOutputDevice) {
+    *legacy = sp<HwModule>::make(aidl.name.c_str(), AUDIO_DEVICE_API_VERSION_CURRENT);
+    audio_module_handle_t legacyHandle = VALUE_OR_RETURN_STATUS(
+            aidl2legacy_int32_t_audio_module_handle_t(aidl.handle));
+    (*legacy)->setHandle(legacyHandle);
+    IOProfileCollection mixPorts;
+    DeviceVector devicePorts;
+    const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+    std::unordered_map<int32_t, sp<PolicyAudioPort>> ports;
+    for (const auto& aidlPort : aidl.ports) {
+        const bool isInput = aidlPort.flags.getTag() == AudioIoFlags::input;
+        audio_port_v7 legacyPort = VALUE_OR_RETURN_STATUS(
+                aidl2legacy_AudioPort_audio_port_v7(aidlPort, isInput));
+        // This conversion fills out both 'hal' and 'sys' parts.
+        media::AudioPortFw fwPort = VALUE_OR_RETURN_STATUS(
+                legacy2aidl_audio_port_v7_AudioPortFw(legacyPort));
+        // Since audio_port_v7 lacks some fields, for example, 'maxOpen/ActiveCount',
+        // replace the converted data with the actual data from the HAL.
+        fwPort.hal = aidlPort;
+        if (aidlPort.ext.getTag() == AudioPortExt::mix) {
+            auto mixPort = sp<IOProfile>::make("", AUDIO_PORT_ROLE_NONE);
+            RETURN_STATUS_IF_ERROR(mixPort->readFromParcelable(fwPort));
+            sortAudioProfiles(mixPort->getAudioProfiles());
+            mixPorts.add(mixPort);
+            ports.emplace(aidlPort.id, mixPort);
+        } else if (aidlPort.ext.getTag() == AudioPortExt::device) {
+            // In the legacy XML, device ports use 'tagName' instead of 'AudioPort.name'.
+            auto devicePort =
+                    sp<DeviceDescriptor>::make(AUDIO_DEVICE_NONE, aidlPort.name);
+            RETURN_STATUS_IF_ERROR(devicePort->readFromParcelable(fwPort));
+            devicePort->setName("");
+            auto& profiles = devicePort->getAudioProfiles();
+            if (profiles.empty()) {
+                profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
+            } else {
+                sortAudioProfiles(profiles);
+            }
+            devicePorts.add(devicePort);
+            ports.emplace(aidlPort.id, devicePort);
+
+            if (const auto& deviceExt = aidlPort.ext.get<AudioPortExt::device>();
+                    deviceExt.device.type.connection.empty()) {  // Attached device
+                if (isInput) {
+                    attachedInputDevices->add(devicePort);
+                } else {
+                    attachedOutputDevices->add(devicePort);
+                    if ((deviceExt.flags & defaultDeviceFlag) != 0) {
+                        *defaultOutputDevice = devicePort;
+                    }
+                }
+            }
+        } else {
+            return BAD_VALUE;
+        }
+    }
+    (*legacy)->setProfiles(mixPorts);
+    (*legacy)->setDeclaredDevices(devicePorts);
+    AudioRouteVector routes;
+    for (const auto& aidlRoute : aidl.routes) {
+        sp<AudioRoute> legacy = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioRoute(aidlRoute, ports));
+        routes.add(legacy);
+    }
+    (*legacy)->setRoutes(routes);
+    return OK;
+}
+
+status_t aidl2legacy_AudioHwModules_HwModuleCollection(
+        const std::vector<media::AudioHwModule>& aidl,
+        HwModuleCollection* legacyModules, DeviceVector* attachedInputDevices,
+        DeviceVector* attachedOutputDevices, sp<DeviceDescriptor>* defaultOutputDevice) {
+    for (const auto& aidlModule : aidl) {
+        sp<HwModule> legacy;
+        RETURN_STATUS_IF_ERROR(aidl2legacy_AudioHwModule_HwModule(aidlModule, &legacy,
+                        attachedInputDevices, attachedOutputDevices, defaultOutputDevice));
+        legacyModules->add(legacy);
+    }
+    return OK;
+}
+
+using SurroundFormatFamily = AudioPolicyConfig::SurroundFormats::value_type;
+ConversionResult<SurroundFormatFamily>
+aidl2legacy_SurroundFormatFamily(const media::SurroundSoundConfig::SurroundFormatFamily& aidl) {
+    audio_format_t legacyPrimary = VALUE_OR_RETURN(
+            aidl2legacy_AudioFormatDescription_audio_format_t(aidl.primaryFormat));
+    std::unordered_set<audio_format_t> legacySubs = VALUE_OR_RETURN(
+            convertContainer<std::unordered_set<audio_format_t>>(
+                    aidl.subFormats, aidl2legacy_AudioFormatDescription_audio_format_t));
+    return std::make_pair(legacyPrimary, legacySubs);
+}
+
+ConversionResult<AudioPolicyConfig::SurroundFormats>
+aidl2legacy_SurroundSoundConfig_SurroundFormats(const media::SurroundSoundConfig& aidl) {
+    return convertContainer<AudioPolicyConfig::SurroundFormats>(aidl.formatFamilies,
+            aidl2legacy_SurroundFormatFamily);
+};
+
+}  // namespace
+
 // static
 sp<const AudioPolicyConfig> AudioPolicyConfig::createDefault() {
     auto config = sp<AudioPolicyConfig>::make();
@@ -34,6 +173,16 @@
 }
 
 // static
+sp<const AudioPolicyConfig> AudioPolicyConfig::loadFromApmAidlConfigWithFallback(
+        const media::AudioPolicyConfig& aidl) {
+    auto config = sp<AudioPolicyConfig>::make();
+    if (status_t status = config->loadFromAidl(aidl); status == NO_ERROR) {
+        return config;
+    }
+    return createDefault();
+}
+
+// static
 sp<const AudioPolicyConfig> AudioPolicyConfig::loadFromApmXmlConfigWithFallback(
         const std::string& xmlFilePath) {
     const std::string filePath =
@@ -100,6 +249,18 @@
     }
 }
 
+status_t AudioPolicyConfig::loadFromAidl(const media::AudioPolicyConfig& aidl) {
+    RETURN_STATUS_IF_ERROR(aidl2legacy_AudioHwModules_HwModuleCollection(aidl.modules,
+                    &mHwModules, &mInputDevices, &mOutputDevices, &mDefaultOutputDevice));
+    mIsCallScreenModeSupported = std::find(aidl.supportedModes.begin(), aidl.supportedModes.end(),
+            media::audio::common::AudioMode::CALL_SCREEN) != aidl.supportedModes.end();
+    mSurroundFormats = VALUE_OR_RETURN_STATUS(
+            aidl2legacy_SurroundSoundConfig_SurroundFormats(aidl.surroundSoundConfig));
+    mSource = kAidlConfigSource;
+    // No need to augmentData() as AIDL HAL must provide correct mic addresses.
+    return NO_ERROR;
+}
+
 status_t AudioPolicyConfig::loadFromXml(const std::string& xmlFilePath, bool forVts) {
     if (xmlFilePath.empty()) {
         ALOGE("Audio policy configuration file name is empty");
@@ -131,7 +292,8 @@
     mOutputDevices.add(mDefaultOutputDevice);
     mInputDevices.add(defaultInputDevice);
 
-    sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
+    sp<HwModule> module = new HwModule(
+            AUDIO_HARDWARE_MODULE_ID_PRIMARY, AUDIO_DEVICE_API_VERSION_2_0);
     mHwModules.add(module);
 
     sp<OutputProfile> outProfile = new OutputProfile("primary");
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 4cfdaad..631fff8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -640,7 +640,7 @@
 }
 
 status_t AudioPolicyMixCollection::getDevicesForUserId(int userId,
-        Vector<AudioDeviceTypeAddr>& devices) const {
+        AudioDeviceTypeAddrVector& devices) const {
     // for each player mix:
     // find rules that don't exclude this userId, and add the device to the list
     for (size_t i = 0; i < size(); i++) {
@@ -658,7 +658,7 @@
             }
         }
         if (ruleAllowsUserId) {
-            devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
+            devices.push_back(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
         }
     }
     return NO_ERROR;
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 418b7eb..5f14ee4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -33,6 +33,13 @@
     setHalVersion(halVersionMajor, halVersionMinor);
 }
 
+HwModule::HwModule(const char *name, uint32_t halVersion)
+    : mName(String8(name)),
+      mHandle(AUDIO_MODULE_HANDLE_NONE),
+      mHalVersion(halVersion)
+{
+}
+
 HwModule::~HwModule()
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index 50c5eab..6c46c54 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -51,10 +51,10 @@
         "libaudiopolicyengine_common_headers",
     ],
     static_libs: [
-        "libaudiopolicycomponents",
         "libaudiopolicyengine_config",
     ],
     shared_libs: [
         "libaudiofoundation",
+        "libaudiopolicycomponents",
     ],
 }
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index bac51f5..b9c94a4 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <functional>
+
+#include <android/media/audio/common/AudioHalEngineConfig.h>
 #include <EngineConfig.h>
 #include <EngineInterface.h>
 #include <ProductStrategy.h>
@@ -113,6 +116,9 @@
     status_t getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
             AudioDeviceTypeAddrVector &devices) const override;
 
+    engineConfig::ParsingResult loadAudioPolicyEngineConfig(
+            const media::audio::common::AudioHalEngineConfig& aidlConfig);
+
     engineConfig::ParsingResult loadAudioPolicyEngineConfig(const std::string& xmlFilePath = "");
 
     const ProductStrategyMap &getProductStrategies() const { return mProductStrategies; }
@@ -176,6 +182,8 @@
         const DeviceVector& availableOutputDevices, product_strategy_t strategy) const;
 
 private:
+    engineConfig::ParsingResult processParsingResult(engineConfig::ParsingResult&& rawResult);
+
     /**
      * Get media devices as the given role
      *
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 7d6a308..218aff8 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -115,10 +115,53 @@
     return PRODUCT_STRATEGY_NONE;
 }
 
+engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(
+        const media::audio::common::AudioHalEngineConfig& aidlConfig)
+{
+    engineConfig::ParsingResult result = engineConfig::convert(aidlConfig);
+    if (result.parsedConfig == nullptr) {
+        ALOGE("%s: There was an error parsing AIDL data", __func__);
+        result = {std::make_unique<engineConfig::Config>(gDefaultEngineConfig), 1};
+    } else {
+        // It is allowed for the HAL to return an empty list of strategies.
+        if (result.parsedConfig->productStrategies.empty()) {
+            result.parsedConfig->productStrategies = gDefaultEngineConfig.productStrategies;
+        }
+    }
+    return processParsingResult(std::move(result));
+}
+
 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
 {
+    auto fileExists = [](const char* path) {
+        struct stat fileStat;
+        return stat(path, &fileStat) == 0 && S_ISREG(fileStat.st_mode);
+    };
+    const std::string filePath = xmlFilePath.empty() ? engineConfig::DEFAULT_PATH : xmlFilePath;
+    engineConfig::ParsingResult result =
+            fileExists(filePath.c_str()) ?
+            engineConfig::parse(filePath.c_str()) : engineConfig::ParsingResult{};
+    if (result.parsedConfig == nullptr) {
+        ALOGD("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
+        engineConfig::Config config = gDefaultEngineConfig;
+        android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
+        result = {std::make_unique<engineConfig::Config>(config),
+                  static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
+    } else {
+        // Append for internal use only volume groups (e.g. rerouting/patch)
+        result.parsedConfig->volumeGroups.insert(
+                    std::end(result.parsedConfig->volumeGroups),
+                    std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
+    }
+    ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
+    return processParsingResult(std::move(result));
+}
+
+engineConfig::ParsingResult EngineBase::processParsingResult(
+        engineConfig::ParsingResult&& rawResult)
+{
     auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
-        // Ensure name unicity to prevent duplicate
+        // Ensure volume group name uniqueness.
         LOG_ALWAYS_FATAL_IF(std::any_of(std::begin(volumeGroups), std::end(volumeGroups),
                                      [&volumeConfig](const auto &volumeGroup) {
                 return volumeConfig.name == volumeGroup.second->getName(); }),
@@ -158,42 +201,21 @@
         });
         return iter != end(volumeGroups);
     };
-    auto fileExists = [](const char* path) {
-        struct stat fileStat;
-        return stat(path, &fileStat) == 0 && S_ISREG(fileStat.st_mode);
-    };
 
-    const std::string filePath = xmlFilePath.empty() ? engineConfig::DEFAULT_PATH : xmlFilePath;
-    auto result = fileExists(filePath.c_str()) ?
-            engineConfig::parse(filePath.c_str()) : engineConfig::ParsingResult{};
-    if (result.parsedConfig == nullptr) {
-        ALOGD("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
-        engineConfig::Config config = gDefaultEngineConfig;
-        android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
-        result = {std::make_unique<engineConfig::Config>(config),
-                  static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
-    } else {
-        // Append for internal use only volume groups (e.g. rerouting/patch)
-        result.parsedConfig->volumeGroups.insert(
-                    std::end(result.parsedConfig->volumeGroups),
-                    std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
-    }
+    auto result = std::move(rawResult);
     // Append for internal use only strategies (e.g. rerouting/patch)
     result.parsedConfig->productStrategies.insert(
                 std::end(result.parsedConfig->productStrategies),
                 std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
 
-
-    ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
-
     engineConfig::VolumeGroup defaultVolumeConfig;
     engineConfig::VolumeGroup defaultSystemVolumeConfig;
     for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
         // save default volume config for streams not defined in configuration
-        if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
+        if (volumeConfig.name.compare(audio_stream_type_to_string(AUDIO_STREAM_MUSIC)) == 0) {
             defaultVolumeConfig = volumeConfig;
         }
-        if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {
+        if (volumeConfig.name.compare(audio_stream_type_to_string(AUDIO_STREAM_PATCH)) == 0) {
             defaultSystemVolumeConfig = volumeConfig;
         }
         loadVolumeConfig(mVolumeGroups, volumeConfig);
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
index 459cc78..12597de 100644
--- a/services/audiopolicy/engine/config/Android.bp
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -22,11 +22,13 @@
         "-Wextra",
     ],
     shared_libs: [
-        "libmedia_helper",
-        "libxml2",
-        "libutils",
-        "liblog",
+        "libaudio_aidl_conversion_common_cpp",
+        "libaudiopolicycomponents",
         "libcutils",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+        "libxml2",
     ],
     header_libs: [
         "libaudio_system_headers",
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index 4de16c5..119dbd6 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -16,10 +16,11 @@
 
 #pragma once
 
-#include <system/audio.h>
-
 #include <string>
 #include <vector>
+
+#include <android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio.h>
 #include <utils/Errors.h>
 
 struct _xmlNode;
@@ -116,6 +117,7 @@
  */
 ParsingResult parse(const char* path = DEFAULT_PATH);
 android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups);
+ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig);
 // Exposed for testing.
 android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups);
 
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index ac117f0..ca78ce7 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -14,26 +14,30 @@
  * limitations under the License.
  */
 
+#include <cstdint>
+#include <istream>
+#include <map>
+#include <sstream>
+#include <stdarg.h>
+#include <string>
+#include <string>
+#include <vector>
+
 #define LOG_TAG "APM::AudioPolicyEngine/Config"
 //#define LOG_NDEBUG 0
 
 #include "EngineConfig.h"
+#include <TypeConverter.h>
+#include <Volume.h>
 #include <cutils/properties.h>
+#include <libxml/parser.h>
+#include <libxml/xinclude.h>
+#include <media/AidlConversion.h>
+#include <media/AidlConversionUtil.h>
 #include <media/TypeConverter.h>
 #include <media/convert.h>
 #include <system/audio_config.h>
 #include <utils/Log.h>
-#include <libxml/parser.h>
-#include <libxml/xinclude.h>
-#include <string>
-#include <vector>
-#include <map>
-#include <sstream>
-#include <istream>
-
-#include <cstdint>
-#include <stdarg.h>
-#include <string>
 
 namespace android {
 
@@ -45,6 +49,85 @@
 static const char *const gReferenceElementName = "reference";
 static const char *const gReferenceAttributeName = "name";
 
+namespace {
+
+ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
+        const media::audio::common::AudioHalAttributesGroup& aidl) {
+    AttributesGroup legacy;
+    legacy.stream = VALUE_OR_RETURN(
+            aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
+    legacy.volumeGroup = aidl.volumeGroupName;
+    legacy.attributesVect = VALUE_OR_RETURN(convertContainer<AttributesVector>(
+                    aidl.attributes, aidl2legacy_AudioAttributes_audio_attributes_t));
+    return legacy;
+}
+
+ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
+        const media::audio::common::AudioHalProductStrategy& aidl) {
+    ProductStrategy legacy;
+    legacy.name = "strategy_" + std::to_string(aidl.id);
+    legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
+                    aidl.attributesGroups,
+                    aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
+    return legacy;
+}
+
+ConversionResult<std::string> legacy_device_category_to_string(device_category legacy) {
+    std::string s;
+    if (DeviceCategoryConverter::toString(legacy, s)) {
+        return s;
+    }
+    return base::unexpected(BAD_VALUE);
+}
+
+ConversionResult<std::string> aidl2legacy_DeviceCategory(
+        const media::audio::common::AudioHalVolumeCurve::DeviceCategory aidl) {
+    using DeviceCategory = media::audio::common::AudioHalVolumeCurve::DeviceCategory;
+    switch (aidl) {
+        case DeviceCategory::HEADSET:
+            return legacy_device_category_to_string(DEVICE_CATEGORY_HEADSET);
+        case DeviceCategory::SPEAKER:
+            return legacy_device_category_to_string(DEVICE_CATEGORY_SPEAKER);
+        case DeviceCategory::EARPIECE:
+            return legacy_device_category_to_string(DEVICE_CATEGORY_EARPIECE);
+        case DeviceCategory::EXT_MEDIA:
+            return legacy_device_category_to_string(DEVICE_CATEGORY_EXT_MEDIA);
+        case DeviceCategory::HEARING_AID:
+            return legacy_device_category_to_string(DEVICE_CATEGORY_HEARING_AID);
+    }
+    return base::unexpected(BAD_VALUE);
+}
+
+ConversionResult<CurvePoint> aidl2legacy_AudioHalCurvePoint_CurvePoint(
+        const media::audio::common::AudioHalVolumeCurve::CurvePoint& aidl) {
+    CurvePoint legacy;
+    legacy.index = VALUE_OR_RETURN(convertIntegral<int>(aidl.index));
+    legacy.attenuationInMb = aidl.attenuationMb;
+    return legacy;
+}
+
+ConversionResult<VolumeCurve> aidl2legacy_AudioHalVolumeCurve_VolumeCurve(
+        const media::audio::common::AudioHalVolumeCurve& aidl) {
+    VolumeCurve legacy;
+    legacy.deviceCategory = VALUE_OR_RETURN(aidl2legacy_DeviceCategory(aidl.deviceCategory));
+    legacy.curvePoints = VALUE_OR_RETURN(convertContainer<CurvePoints>(
+                    aidl.curvePoints, aidl2legacy_AudioHalCurvePoint_CurvePoint));
+    return legacy;
+}
+
+ConversionResult<VolumeGroup> aidl2legacy_AudioHalVolumeGroup_VolumeGroup(
+        const media::audio::common::AudioHalVolumeGroup& aidl) {
+    VolumeGroup legacy;
+    legacy.name = aidl.name;
+    legacy.indexMin = aidl.minIndex;
+    legacy.indexMax = aidl.maxIndex;
+    legacy.volumeCurves = VALUE_OR_RETURN(convertContainer<VolumeCurves>(
+                    aidl.volumeCurves, aidl2legacy_AudioHalVolumeCurve_VolumeCurve));
+    return legacy;
+}
+
+}  // namespace
+
 template<typename E, typename C>
 struct BaseSerializerTraits {
     typedef E Element;
@@ -724,5 +807,25 @@
     }
 }
 
+ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig) {
+    auto config = std::make_unique<engineConfig::Config>();
+    config->version = 1.0f;
+    if (auto conv = convertContainer<engineConfig::ProductStrategies>(
+                    aidlConfig.productStrategies,
+                    aidl2legacy_AudioHalProductStrategy_ProductStrategy); conv.ok()) {
+        config->productStrategies = std::move(conv.value());
+    } else {
+        return ParsingResult{};
+    }
+    if (auto conv = convertContainer<engineConfig::VolumeGroups>(
+                    aidlConfig.volumeGroups,
+                    aidl2legacy_AudioHalVolumeGroup_VolumeGroup); conv.ok()) {
+        config->volumeGroups = std::move(conv.value());
+    } else {
+        return ParsingResult{};
+    }
+    return {.parsedConfig=std::move(config), .nbSkippedElement=0};
+ }
+
 } // namespace engineConfig
 } // namespace android
diff --git a/services/audiopolicy/engine/config/tests/Android.bp b/services/audiopolicy/engine/config/tests/Android.bp
index 5791f17..5d1aa16 100644
--- a/services/audiopolicy/engine/config/tests/Android.bp
+++ b/services/audiopolicy/engine/config/tests/Android.bp
@@ -11,6 +11,7 @@
     name: "audiopolicy_engineconfig_tests",
 
     shared_libs: [
+        "libaudiopolicycomponents",
         "libbase",
         "liblog",
         "libmedia_helper",
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index dd7ac1a..70461ad 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -20,6 +20,7 @@
 #include <utility>
 
 #include <AudioPolicyManagerObserver.h>
+#include <android/media/audio/common/AudioHalEngineConfig.h>
 #include <media/AudioProductStrategy.h>
 #include <media/AudioVolumeGroup.h>
 #include <IVolumeCurves.h>
@@ -47,6 +48,14 @@
 {
 public:
     /**
+     * Loads the engine configuration from AIDL configuration data.
+     * If loading failed, tries to fall back to some default configuration. If fallback
+     * is impossible, returns an error.
+     */
+    virtual status_t loadFromHalConfigWithFallback(
+            const media::audio::common::AudioHalEngineConfig& config) = 0;
+
+    /**
      * Loads the engine configuration from the specified or the default config file.
      * If loading failed, tries to fall back to some default configuration. If fallback
      * is impossible, returns an error.
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index dc8d9cf..eb2e2f4 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -35,14 +35,15 @@
         "libaudiopolicyengineconfigurable_interface_headers",
     ],
     static_libs: [
-        "libaudiopolicycomponents",
         "libaudiopolicyengine_common",
         "libaudiopolicyengine_config",
         "libaudiopolicyengineconfigurable_pfwwrapper",
 
     ],
   shared_libs: [
+        "libaudio_aidl_conversion_common_cpp",
         "libaudiofoundation",
+        "libaudiopolicycomponents",
         "libbase",
         "liblog",
         "libcutils",
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
index 0398fc7..f7159c5 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
@@ -31,11 +31,11 @@
         "libaudiopolicyengineconfigurable_interface_headers",
     ],
     static_libs: [
-        "libaudiopolicycomponents",
         "libaudiopolicyengine_common",
         "libpfw_utility",
     ],
     shared_libs: [
+        "libaudiopolicycomponents",
         "libaudiopolicyengineconfigurable",
         "liblog",
         "libutils",
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 2eb0177..ccd4316 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -70,6 +70,12 @@
 {
 }
 
+status_t Engine::loadFromHalConfigWithFallback(
+        const media::audio::common::AudioHalEngineConfig& config __unused) {
+    // b/242678729. Need to implement for the configurable engine.
+    return INVALID_OPERATION;
+}
+
 status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
 {
     status_t loadResult = loadAudioPolicyEngineConfig(xmlFilePath);
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index b964cd6..4f3e620 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -41,12 +41,15 @@
     ///
     /// from EngineInterface
     ///
-    android::status_t loadFromXmlConfigWithFallback(const std::string& xmlFilePath = "") override;
+    status_t loadFromHalConfigWithFallback(
+            const media::audio::common::AudioHalEngineConfig& config) override;
+
+    status_t loadFromXmlConfigWithFallback(const std::string& xmlFilePath = "") override;
 
     ///
     /// from EngineBase
     ///
-    android::status_t initCheck() override;
+    status_t initCheck() override;
 
     status_t setPhoneState(audio_mode_t mode) override;
 
@@ -56,8 +59,8 @@
 
     audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const override;
 
-    android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
-                                               audio_policy_dev_state_t state) override;
+    status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                      audio_policy_dev_state_t state) override;
 
     DeviceVector getOutputDevicesForAttributes(const audio_attributes_t &attr,
                                                const sp<DeviceDescriptor> &preferedDevice = nullptr,
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 4671fe9..7d4ccab 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -25,12 +25,13 @@
         "libaudiopolicyengine_interface_headers",
     ],
     static_libs: [
-        "libaudiopolicycomponents",
         "libaudiopolicyengine_common",
         "libaudiopolicyengine_config",
     ],
     shared_libs: [
+        "libaudio_aidl_conversion_common_cpp",
         "libaudiofoundation",
+        "libaudiopolicycomponents",
         "libbase",
         "liblog",
         "libcutils",
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 88cbb7d..15f7842 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -35,10 +35,7 @@
 #include <utils/String8.h>
 #include <utils/Log.h>
 
-namespace android
-{
-namespace audio_policy
-{
+namespace android::audio_policy {
 
 struct legacy_strategy_map { const char *name; legacy_strategy id; };
 static const std::vector<legacy_strategy_map>& getLegacyStrategy() {
@@ -59,8 +56,18 @@
     return legacyStrategy;
 }
 
+status_t Engine::loadFromHalConfigWithFallback(
+        const media::audio::common::AudioHalEngineConfig& aidlConfig) {
+    return loadWithFallback(aidlConfig);
+}
+
 status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath) {
-    auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath);
+    return loadWithFallback(xmlFilePath);
+}
+
+template<typename T>
+status_t Engine::loadWithFallback(const T& configSource) {
+    auto result = EngineBase::loadAudioPolicyEngineConfig(configSource);
     ALOGE_IF(result.nbSkippedElement != 0,
              "Policy Engine configuration is partially invalid, skipped %zu elements",
              result.nbSkippedElement);
@@ -73,6 +80,7 @@
     return OK;
 }
 
+
 status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config)
 {
     switch(usage) {
@@ -844,5 +852,4 @@
                                            AUDIO_FORMAT_DEFAULT);
 }
 
-} // namespace audio_policy
-} // namespace android
+} // namespace android::audio_policy
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 8410560..878bca9 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -47,10 +47,14 @@
 public:
     Engine() = default;
     virtual ~Engine() = default;
+    Engine(const Engine &object) = delete;
+    Engine &operator=(const Engine &object) = delete;
 
     ///
     /// from EngineInterface
     ///
+    status_t loadFromHalConfigWithFallback(
+            const media::audio::common::AudioHalEngineConfig& config) override;
     status_t loadFromXmlConfigWithFallback(const std::string& xmlFilePath = "") override;
 
 private:
@@ -79,9 +83,8 @@
     DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const override;
 
 private:
-    /* Copy facilities are put private to disable copy. */
-    Engine(const Engine &object);
-    Engine &operator=(const Engine &object);
+    template<typename T>
+    status_t loadWithFallback(const T& configSource);
 
     status_t setDefaultDevice(audio_devices_t device);
 
diff --git a/services/audiopolicy/fuzzer/Android.bp b/services/audiopolicy/fuzzer/Android.bp
index 621f643..c4b3751 100644
--- a/services/audiopolicy/fuzzer/Android.bp
+++ b/services/audiopolicy/fuzzer/Android.bp
@@ -38,6 +38,7 @@
         "capture_state_listener-aidl-cpp",
         "libaudioclient",
         "libaudiofoundation",
+        "libaudiopolicycomponents",
         "libbase",
         "libcutils",
         "libhidlbase",
@@ -54,7 +55,6 @@
     ],
     static_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "libaudiopolicycomponents",
     ],
     header_libs: [
         "libaudiopolicycommon",
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index 6e34eb0..a1785da 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -23,6 +23,7 @@
 
     shared_libs: [
         "libaudiofoundation",
+        "libaudiopolicycomponents",
         "libcutils",
         "libdl",
         "libutils",
@@ -49,8 +50,6 @@
         "libaudiopolicymanager_interface_headers",
     ],
 
-    static_libs: ["libaudiopolicycomponents"],
-
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f093e68..75dc3f1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3782,6 +3782,44 @@
     return true;
 }
 
+void AudioPolicyManager::changeOutputDevicesMuteState(
+        const AudioDeviceTypeAddrVector& devices) {
+    ALOGVV("%s() num devices %zu", __func__, devices.size());
+
+    std::vector<sp<SwAudioOutputDescriptor>> outputs =
+            getSoftwareOutputsForDevices(devices);
+
+    for (size_t i = 0; i < outputs.size(); i++) {
+        sp<SwAudioOutputDescriptor> outputDesc = outputs[i];
+        DeviceVector prevDevices = outputDesc->devices();
+        checkDeviceMuteStrategies(outputDesc, prevDevices, 0 /* delayMs */);
+    }
+}
+
+std::vector<sp<SwAudioOutputDescriptor>> AudioPolicyManager::getSoftwareOutputsForDevices(
+        const AudioDeviceTypeAddrVector& devices) const
+{
+    std::vector<sp<SwAudioOutputDescriptor>> outputs;
+    DeviceVector deviceDescriptors;
+    for (size_t j = 0; j < devices.size(); j++) {
+        sp<DeviceDescriptor> desc = mHwModules.getDeviceDescriptor(
+                devices[j].mType, devices[j].getAddress(), String8(), AUDIO_FORMAT_DEFAULT);
+        if (desc == nullptr || !audio_is_output_device(devices[j].mType)) {
+            ALOGE("%s: device type %#x address %s not supported or not an output device",
+                __func__, devices[j].mType, devices[j].getAddress());
+                    continue;
+        }
+        deviceDescriptors.add(desc);
+    }
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        if (!mOutputs.valueAt(i)->supportsAtLeastOne(deviceDescriptors)) {
+            continue;
+        }
+        outputs.push_back(mOutputs.valueAt(i));
+    }
+    return outputs;
+}
+
 status_t AudioPolicyManager::setUidDeviceAffinities(uid_t uid,
         const AudioDeviceTypeAddrVector& devices) {
     ALOGV("%s() uid=%d num devices %zu", __FUNCTION__, uid, devices.size());
@@ -3848,7 +3886,8 @@
     return NO_ERROR;
 }
 
-void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
+void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs,
+    bool skipDelays)
 {
     uint32_t waitMs = 0;
     bool wasLeUnicastActive = isLeUnicastActive();
@@ -3874,8 +3913,8 @@
                 continue;
             }
             waitMs = setOutputDevices(outputDesc, newDevices, forceRouting, delayMs, nullptr,
-                                      true /*requiresMuteCheck*/,
-                                      !forceRouting /*requiresVolumeCheck*/);
+                                      !skipDelays /*requiresMuteCheck*/,
+                                      !forceRouting /*requiresVolumeCheck*/, skipDelays);
             // Only apply special touch sound delay once
             delayMs = 0;
         }
@@ -4060,13 +4099,18 @@
 
     // reevaluate outputs for all devices
     checkForDeviceAndOutputChanges();
-    updateCallAndOutputRouting();
+    changeOutputDevicesMuteState(devices);
+    updateCallAndOutputRouting(false /* forceVolumeReeval */, 0 /* delayMs */,
+        true /* skipDelays */);
+    changeOutputDevicesMuteState(devices);
 
     return NO_ERROR;
 }
 
 status_t AudioPolicyManager::removeUserIdDeviceAffinities(int userId) {
     ALOGV("%s() userId=%d", __FUNCTION__, userId);
+    AudioDeviceTypeAddrVector devices;
+    mPolicyMixes.getDevicesForUserId(userId, devices);
     status_t status = mPolicyMixes.removeUserIdDeviceAffinities(userId);
     if (status != NO_ERROR) {
         ALOGE("%s() Could not remove all device affinities fo userId = %d",
@@ -4076,7 +4120,10 @@
 
     // reevaluate outputs for all devices
     checkForDeviceAndOutputChanges();
-    updateCallAndOutputRouting();
+    changeOutputDevicesMuteState(devices);
+    updateCallAndOutputRouting(false /* forceVolumeReeval */, 0 /* delayMs */,
+        true /* skipDelays */);
+    changeOutputDevicesMuteState(devices);
 
     return NO_ERROR;
 }
@@ -7315,7 +7362,8 @@
                                               bool force,
                                               int delayMs,
                                               audio_patch_handle_t *patchHandle,
-                                              bool requiresMuteCheck, bool requiresVolumeCheck)
+                                              bool requiresMuteCheck, bool requiresVolumeCheck,
+                                              bool skipMuteDelay)
 {
     // TODO(b/262404095): Consider if the output need to be reopened.
     ALOGV("%s device %s delayMs %d", __func__, devices.toString().c_str(), delayMs);
@@ -7323,9 +7371,9 @@
 
     if (outputDesc->isDuplicated()) {
         muteWaitMs = setOutputDevices(outputDesc->subOutput1(), devices, force, delayMs,
-                nullptr /* patchHandle */, requiresMuteCheck);
+                nullptr /* patchHandle */, requiresMuteCheck, skipMuteDelay);
         muteWaitMs += setOutputDevices(outputDesc->subOutput2(), devices, force, delayMs,
-                nullptr /* patchHandle */, requiresMuteCheck);
+                nullptr /* patchHandle */, requiresMuteCheck, skipMuteDelay);
         return muteWaitMs;
     }
 
@@ -7391,12 +7439,16 @@
 
         // Add half reported latency to delayMs when muteWaitMs is null in order
         // to avoid disordered sequence of muting volume and changing devices.
-        installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(),
-                muteWaitMs == 0 ? (delayMs + (outputDesc->latency() / 2)) : delayMs);
+        int actualDelayMs = !skipMuteDelay && muteWaitMs == 0
+                ? (delayMs + (outputDesc->latency() / 2)) : delayMs;
+        installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), actualDelayMs);
     }
 
-    // update stream volumes according to new device
-    applyStreamVolumes(outputDesc, filteredDevices.types(), delayMs);
+    // Since the mute is skip, also skip the apply stream volume as that will be applied externally
+    if (!skipMuteDelay) {
+        // update stream volumes according to new device
+        applyStreamVolumes(outputDesc, filteredDevices.types(), delayMs);
+    }
 
     return muteWaitMs;
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 88bafef..5f4c829 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -535,8 +535,9 @@
          *        and currently active, allow to have proper drain and avoid pops
          * @param requiresVolumeCheck true if called requires to reapply volume if the routing did
          * not change (but the output is still routed).
+         * @param skipMuteDelay if true will skip mute delay when installing audio patch
          * @return the number of ms we have slept to allow new routing to take effect in certain
-         * cases.
+         *        cases.
          */
         uint32_t setOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
                                   const DeviceVector &device,
@@ -544,7 +545,8 @@
                                   int delayMs = 0,
                                   audio_patch_handle_t *patchHandle = NULL,
                                   bool requiresMuteCheck = true,
-                                  bool requiresVolumeCheck = false);
+                                  bool requiresVolumeCheck = false,
+                                  bool skipMuteDelay = false);
         status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
                                    int delayMs = 0,
                                    audio_patch_handle_t *patchHandle = NULL);
@@ -647,8 +649,10 @@
         /**
          * @brief updates routing for all outputs (including call if call in progress).
          * @param delayMs delay for unmuting if required
+         * @param skipDelays if true all the delays will be skip while updating routing
          */
-        void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0);
+        void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0,
+                bool skipDelays = false);
 
         bool isCallRxAudioSource(const sp<SourceClientDescriptor> &source) {
             return mCallRxSourceClient != nullptr && source == mCallRxSourceClient;
@@ -1241,6 +1245,21 @@
                 const char* context,
                 bool matchAddress = true);
 
+        /**
+         * @brief changeOutputDevicesMuteState mute/unmute devices using checkDeviceMuteStrategies
+         * @param devices devices to mute/unmute
+         */
+        void changeOutputDevicesMuteState(const AudioDeviceTypeAddrVector& devices);
+
+        /**
+         * @brief Returns a vector of software output descriptor that support the queried devices
+         * @param devices devices to query
+         * @param openOutputs open outputs where the devices are supported as determined by
+         *      SwAudioOutputDescriptor::supportsAtLeastOne
+         */
+        std::vector<sp<SwAudioOutputDescriptor>> getSoftwareOutputsForDevices(
+                const AudioDeviceTypeAddrVector& devices) const;
+
         bool isScoRequestedForComm() const;
 
         bool isHearingAidUsedForComm() const;
diff --git a/services/audiopolicy/managerdefault/EngineLibrary.cpp b/services/audiopolicy/managerdefault/EngineLibrary.cpp
index 939fbc5..ab77941 100644
--- a/services/audiopolicy/managerdefault/EngineLibrary.cpp
+++ b/services/audiopolicy/managerdefault/EngineLibrary.cpp
@@ -40,6 +40,23 @@
     return engine;
 }
 
+EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
+        const media::audio::common::AudioHalEngineConfig& config)
+{
+    auto engLib = EngineLibrary::load(librarySuffix);
+    if (!engLib) {
+        ALOGE("%s: Failed to load the engine library, suffix \"%s\"",
+                __func__, librarySuffix.c_str());
+        return nullptr;
+    }
+    auto engine = engLib->createEngineUsingHalConfig(config);
+    if (engine == nullptr) {
+        ALOGE("%s: Failed to instantiate the APM engine", __func__);
+        return nullptr;
+    }
+    return engine;
+}
+
 // static
 std::shared_ptr<EngineLibrary> EngineLibrary::load(const std::string& librarySuffix)
 {
@@ -53,7 +70,8 @@
     close();
 }
 
-EngineInstance EngineLibrary::createEngineUsingXmlConfig(const std::string& xmlFilePath) {
+EngineInstance EngineLibrary::createEngineUsingXmlConfig(const std::string& xmlFilePath)
+{
     auto instance = createEngine();
     if (instance != nullptr) {
         if (status_t status = instance->loadFromXmlConfigWithFallback(xmlFilePath);
@@ -67,6 +85,21 @@
     return nullptr;
 }
 
+EngineInstance EngineLibrary::createEngineUsingHalConfig(
+        const media::audio::common::AudioHalEngineConfig& config)
+{
+    auto instance = createEngine();
+    if (instance != nullptr) {
+        if (status_t status = instance->loadFromHalConfigWithFallback(config); status == OK) {
+            return instance;
+        } else {
+            ALOGE("%s: loading of the engine config with HAL configuration \"%s\" failed: %d",
+                    __func__, config.toString().c_str(), status);
+        }
+    }
+    return nullptr;
+}
+
 bool EngineLibrary::init(std::string libraryPath)
 {
     mLibraryHandle = dlopen(libraryPath.c_str(), 0);
diff --git a/services/audiopolicy/managerdefault/EngineLibrary.h b/services/audiopolicy/managerdefault/EngineLibrary.h
index dc138a1..4710e34 100644
--- a/services/audiopolicy/managerdefault/EngineLibrary.h
+++ b/services/audiopolicy/managerdefault/EngineLibrary.h
@@ -21,6 +21,7 @@
 #include <string>
 
 #include <EngineInterface.h>
+#include <android/media/audio/common/AudioHalEngineConfig.h>
 
 namespace android {
 
@@ -28,6 +29,8 @@
 
 EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
         const std::string& configXmlFilePath = "");
+EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
+        const media::audio::common::AudioHalEngineConfig& config);
 
 class EngineLibrary : public std::enable_shared_from_this<EngineLibrary> {
 public:
@@ -40,6 +43,8 @@
     EngineLibrary& operator=(EngineLibrary&&) = delete;
 
     EngineInstance createEngineUsingXmlConfig(const std::string& xmlFilePath);
+    EngineInstance createEngineUsingHalConfig(
+            const media::audio::common::AudioHalEngineConfig& config);
 
 private:
     EngineLibrary() = default;
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 2f677da..f4fc8f1 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -35,6 +35,7 @@
         "libaudiofoundation",
         "libaudiohal",
         "libaudiopolicy",
+        "libaudiopolicycomponents",
         "libaudiopolicymanagerdefault",
         "libaudiousecasevalidation",
         "libaudioutils",
@@ -66,7 +67,6 @@
     ],
 
     static_libs: [
-        "libaudiopolicycomponents",
         "framework-permission-aidl-cpp",
     ],
 
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 7febd2f..70a1785 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -48,7 +48,13 @@
         mDefaultDeviceEffectFuture =
                 std::async(std::launch::async, &AudioPolicyEffects::initDefaultDeviceEffects, this);
     } else if (loadResult < 0) {
-        ALOGE("Failed to query effect configuration with status %d", loadResult);
+        ALOGW("Failed to query effect configuration, fallback to load .conf");
+        // load automatic audio effect modules
+        if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+            loadAudioEffectConfigLegacy(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+        } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+            loadAudioEffectConfigLegacy(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+        }
     } else if (loadResult > 0) {
         ALOGE("Effect config is partially invalid, skipped %d elements", loadResult);
     }
@@ -947,6 +953,34 @@
     return skippedElements;
 }
 
+status_t AudioPolicyEffects::loadAudioEffectConfigLegacy(const char *path)
+{
+    cnode *root;
+    char *data;
+
+    data = (char *)load_file(path, NULL);
+    if (data == NULL) {
+        return -ENODEV;
+    }
+    root = config_node("", "");
+    config_load(root, data);
+
+    Vector <EffectDesc *> effects;
+    loadEffects(root, effects);
+    loadInputEffectConfigurations(root, effects);
+    loadStreamEffectConfigurations(root, effects);
+
+    for (size_t i = 0; i < effects.size(); i++) {
+        delete effects[i];
+    }
+
+    config_free(root);
+    free(root);
+    free(data);
+
+    return NO_ERROR;
+}
+
 void AudioPolicyEffects::initDefaultDeviceEffects()
 {
     Mutex::Autolock _l(mLock);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 80b0f91..9f65a96 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -39,7 +39,12 @@
  *
  * This class manages all effects attached to input and output streams in AudioPolicyService.
  * The effect configurations can be queried in several ways:
- * With HIDL HAL, the configuration file `audio_effects.xml` will be loaded by libAudioHal.
+ *
+ * With HIDL HAL, the configuration file `audio_effects.xml` will be loaded by libAudioHal. If this
+ * file does not exist, AudioPolicyEffects class will fallback to load configuration from
+ * `/vendor/etc/audio_effects.conf` (AUDIO_EFFECT_VENDOR_CONFIG_FILE). If this file also does not
+ * exist, the configuration will be loaded from the file `/system/etc/audio_effects.conf`.
+ *
  * With AIDL HAL, the configuration will be queried with the method `IFactory::queryProcessing()`.
  */
 class AudioPolicyEffects : public RefBase
@@ -47,7 +52,7 @@
 
 public:
 
-    // The constructor will parse audio_effects.xml
+    // The constructor will parse audio_effects.conf
     // First it will look whether vendor specific file exists,
     // otherwise it will parse the system default file.
     explicit AudioPolicyEffects(const sp<EffectsFactoryHalInterface>& effectsFactoryHal);
@@ -116,7 +121,7 @@
     void initDefaultDeviceEffects();
 
     // class to store the description of an effects and its parameters
-    // as defined in audio_effects.xml
+    // as defined in audio_effects.conf
     class EffectDesc {
     public:
         EffectDesc(const char *name,
@@ -230,7 +235,8 @@
     static const char *kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1]; //+1 required as streams start from -1
     audio_stream_type_t streamNameToEnum(const char *name);
 
-    // Parse audio_effects.xml
+    // Parse audio_effects.conf
+    status_t loadAudioEffectConfigLegacy(const char *path);
     status_t loadAudioEffectConfig(const sp<EffectsFactoryHalInterface>& effectsFactoryHal);
 
     // Load all effects descriptors in configuration file
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 9367949..234104d 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -186,10 +186,23 @@
 
 static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
 {
-    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();  // This can't fail.
-    AudioPolicyManager *apm = new AudioPolicyManager(
-            config, loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
-            clientInterface);
+    AudioPolicyManager *apm = nullptr;
+    media::AudioPolicyConfig apmConfig;
+    if (status_t status = clientInterface->getAudioPolicyConfig(&apmConfig); status == OK) {
+        auto config = AudioPolicyConfig::loadFromApmAidlConfigWithFallback(apmConfig);
+        LOG_ALWAYS_FATAL_IF(config->getEngineLibraryNameSuffix() !=
+                AudioPolicyConfig::kDefaultEngineLibraryNameSuffix,
+                "Only default engine is currently supported with the AIDL HAL");
+        apm = new AudioPolicyManager(config,
+                loadApmEngineLibraryAndCreateEngine(
+                        config->getEngineLibraryNameSuffix(), apmConfig.engineConfig),
+                clientInterface);
+    } else {
+        auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();  // This can't fail.
+        apm = new AudioPolicyManager(config,
+                loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
+                clientInterface);
+    }
     status_t status = apm->initialize();
     if (status != NO_ERROR) {
         delete apm;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 6cac9f9..4710a8a 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -1072,7 +1072,7 @@
     Mutex mNotificationClientsLock;
     DefaultKeyedVector<int64_t, sp<NotificationClient>> mNotificationClients
         GUARDED_BY(mNotificationClientsLock);
-    // Manage all effects configured in audio_effects.xml
+    // Manage all effects configured in audio_effects.conf
     // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
     // those can call back into AudioPolicyService methods and try to acquire the mutex
     sp<AudioPolicyEffects> mAudioPolicyEffects GUARDED_BY(mLock);
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 285b354..a4a0cd4 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -78,6 +78,7 @@
         "libaudioclient",
         "libaudioclient_aidl_conversion",
         "libaudiofoundation",
+        "libaudiopolicycomponents",
         "libaudiopolicymanagerdefault",
         "libcutils",
         "liblog",
@@ -89,8 +90,6 @@
         "libxml2",
     ],
 
-    static_libs: ["libaudiopolicycomponents"],
-
     header_libs: [
         "libaudiopolicyengine_interface_headers",
         "libaudiopolicymanager_interface_headers",
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index ad4cfce..ea76bcd 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -648,6 +648,12 @@
     }
     AStatsEvent_writeInt32(event, resolutionChangeCount);
 
+    int32_t componentColorFormat = -1;
+    if (item->getInt32("android.media.mediacodec.component-color-format", &componentColorFormat)) {
+        metrics_proto.set_component_color_format(componentColorFormat);
+    }
+    AStatsEvent_writeInt32(event, componentColorFormat);
+
     int64_t firstRenderTimeUs = -1;
     item->getInt64("android.media.mediacodec.first-render-time-us", &firstRenderTimeUs);
     int64_t framesReleased = -1;