APM: Implementing configuration loading from AIDL HAL

The main change is to utilize 'getAudioPolicyConfig'
to receive the HAL-provided configuration from
the AudioFlinger and initialize runtime structures
from it.

Accompanying changes:
 - made `libaudiopolicycomponents` a shared library;
 - added or moved around necessary conversion functions;

Bug: 205884982
Test: run CF with AIDL HAL and compare APM dump A/B
Test: m audiopolicy_fuzzer
Test: atest audio_health_tests
Test: atest audio_aidl_ndk_conversion_tests
Change-Id: I7d0f48bf4d9d4bdaa46246aa4dfbcc49e835c6b6
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 0cfd128..ff141eb 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;
@@ -1791,6 +1815,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 ec1f75c..9636677 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)
@@ -350,6 +352,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 3079d91..8f764b5 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -128,11 +128,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/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index 3df23f1..972de02 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",
@@ -30,7 +34,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/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/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/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index 42c76e2..38e2cc7 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,22 @@
     }
 }
 
+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));
+    // TODO(b/205884982): Remove after landing aosp/2353423.
+    if (mSurroundFormats.empty()) {
+        setDefaultSurroundFormats();
+    }
+    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 +296,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/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 abacd3c..5f4080e 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>
@@ -110,6 +113,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; }
@@ -167,6 +173,8 @@
     void updateDeviceSelectionCache() override;
 
 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 fe5cd9f..dcdf693 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 8036eea..d3f701a 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;
@@ -110,6 +111,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 9c156ab..5c37409 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 44f1d7c..f07ce82 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 d5083f0..903ab34 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 0fa0e0e..e2f42da 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) {
@@ -794,5 +802,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 fde9802..66225a1 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:
@@ -78,9 +82,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/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 8c541f6..734bf9e 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -35,6 +35,7 @@
         "libaudiofoundation",
         "libaudiohal",
         "libaudiopolicy",
+        "libaudiopolicycomponents",
         "libaudiopolicymanagerdefault",
         "libaudioutils",
         "libbinder",
@@ -65,7 +66,6 @@
     ],
 
     static_libs: [
-        "libaudiopolicycomponents",
         "framework-permission-aidl-cpp",
     ],
 
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 930631a..50c2c46 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -180,10 +180,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/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 8499c1c..b9ee8dd 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -74,6 +74,7 @@
         "libaudioclient",
         "libaudioclient_aidl_conversion",
         "libaudiofoundation",
+        "libaudiopolicycomponents",
         "libaudiopolicymanagerdefault",
         "libcutils",
         "liblog",
@@ -85,8 +86,6 @@
         "libxml2",
     ],
 
-    static_libs: ["libaudiopolicycomponents"],
-
     header_libs: [
         "libaudiopolicyengine_interface_headers",
         "libaudiopolicymanager_interface_headers",