Decouple the configuration from the AudioPolicyManager

Promote AudioPolicyConfig to a full class, not just a "view"
on the APM data. This allows separating initialization of
the APM config from the initialization of the APM itself.
Thus, the APM receives a fully initialized config upon
its creation, regardless of the way the config data has been
obtained.

Bug: 205884982
Test: atest audiopolicy_tests
Test: atest audiosystem_tests
Test: atest audio_health_tests
Test: m audiopolicy_fuzzer
(cherry picked from https://android-review.googlesource.com/q/commit:b0fbc1b40ddebb274b7a0bea811440507c357d82)
Merged-In: I334d16e762499a0292540e6abae4e177480d6235
Change-Id: I334d16e762499a0292540e6abae4e177480d6235
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index 92a5628..1d570b7 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -15,6 +15,7 @@
         "src/AudioInputDescriptor.cpp",
         "src/AudioOutputDescriptor.cpp",
         "src/AudioPatch.cpp",
+        "src/AudioPolicyConfig.cpp",
         "src/AudioPolicyMix.cpp",
         "src/AudioProfileVectorHelper.cpp",
         "src/AudioRoute.cpp",
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index a62d3f0..b24fce8 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,62 +16,56 @@
 
 #pragma once
 
+#include <string>
 #include <unordered_map>
 #include <unordered_set>
+#include <vector>
 
-#include <AudioPatch.h>
 #include <DeviceDescriptor.h>
-#include <IOProfile.h>
 #include <HwModule.h>
-#include <PolicyAudioPort.h>
-#include <AudioInputDescriptor.h>
-#include <AudioOutputDescriptor.h>
-#include <AudioPolicyMix.h>
-#include <EffectDescriptor.h>
-#include <SoundTriggerSession.h>
-#include <media/AudioProfile.h>
+#include <error/Result.h>
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
 
 namespace android {
 
-// This class gathers together various bits of AudioPolicyManager
-// configuration, which are usually filled out as a result of parsing
-// the audio_policy_configuration.xml file.
+// This class gathers together various bits of AudioPolicyManager configuration. It can be filled
+// out either as a result of parsing the audio_policy_configuration.xml file, from the HAL data, or
+// to default fallback data.
 //
-// Note that AudioPolicyConfig doesn't own some of the data,
-// it simply proxies access to the fields of AudioPolicyManager
-// class. Be careful about the fields that are references,
-// e.g. 'mOutputDevices'. This also means that it's impossible
-// to implement "deep copying" of this class without re-designing it.
-class AudioPolicyConfig
+// The data in this class is immutable once loaded, this is why a pointer to a const is returned
+// from the factory methods. However, this does not prevent modifications of data bits that
+// are held inside collections, for example, individual modules, devices, etc.
+class AudioPolicyConfig : public RefBase
 {
 public:
-    AudioPolicyConfig(HwModuleCollection &hwModules,
-                      DeviceVector &outputDevices,
-                      DeviceVector &inputDevices,
-                      sp<DeviceDescriptor> &defaultOutputDevice)
-        : mHwModules(hwModules),
-          mOutputDevices(outputDevices),
-          mInputDevices(inputDevices),
-          mDefaultOutputDevice(defaultOutputDevice) {
-        clear();
-    }
+    // 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>>;
 
-    void clear() {
-        mSource = {};
-        mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
-        mHwModules.clear();
-        mOutputDevices.clear();
-        mInputDevices.clear();
-        mDefaultOutputDevice.clear();
-        mIsSpeakerDrcEnabled = false;
-        mIsCallScreenModeSupported = false;
-        mSurroundFormats.clear();
-    }
+    // The source used to indicate the default fallback configuration.
+    static const constexpr char* const kDefaultConfigSource = "AudioPolicyConfig::setDefault";
+
+    // Creates the default (fallback) configuration.
+    static sp<const AudioPolicyConfig> createDefault();
+    // 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(
+            const std::string& xmlFilePath = "");
+    // The factory method to use in APM tests which craft the configuration manually.
+    static sp<AudioPolicyConfig> createWritableForTests();
+    // The factory method to use in APM tests which use a custom XML file.
+    static error::Result<sp<AudioPolicyConfig>> loadFromCustomXmlConfigForTests(
+            const std::string& xmlFilePath);
+    // The factory method to use in VTS tests. If the 'configPath' is empty,
+    // it is determined automatically from the list of known config paths.
+    static error::Result<sp<AudioPolicyConfig>> loadFromCustomXmlConfigForVtsTests(
+            const std::string& configPath, const std::string& xmlFileName);
+
+    ~AudioPolicyConfig() = default;
 
     const std::string& getSource() const {
         return mSource;
     }
-
     void setSource(const std::string& file) {
         mSource = file;
     }
@@ -79,16 +73,24 @@
     const std::string& getEngineLibraryNameSuffix() const {
         return mEngineLibraryNameSuffix;
     }
-
     void setEngineLibraryNameSuffix(const std::string& suffix) {
         mEngineLibraryNameSuffix = suffix;
     }
 
+    const HwModuleCollection& getHwModules() const { return mHwModules; }
     void setHwModules(const HwModuleCollection &hwModules)
     {
         mHwModules = hwModules;
     }
 
+    const DeviceVector& getInputDevices() const
+    {
+        return mInputDevices;
+    }
+    const DeviceVector& getOutputDevices() const
+    {
+        return mOutputDevices;
+    }
     void addDevice(const sp<DeviceDescriptor> &device)
     {
         if (audio_is_output_device(device->type())) {
@@ -97,128 +99,70 @@
             mInputDevices.add(device);
         }
     }
-
     void addInputDevices(const DeviceVector &inputDevices)
     {
         mInputDevices.add(inputDevices);
     }
-
     void addOutputDevices(const DeviceVector &outputDevices)
     {
         mOutputDevices.add(outputDevices);
     }
 
-    bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
+    const sp<DeviceDescriptor>& getDefaultOutputDevice() const { return mDefaultOutputDevice; }
+    void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
+    {
+        mDefaultOutputDevice = defaultDevice;
+    }
 
+    bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
     void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
     {
         mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
     }
 
     bool isCallScreenModeSupported() const { return mIsCallScreenModeSupported; }
-
     void setCallScreenModeSupported(bool isCallScreenModeSupported)
     {
         mIsCallScreenModeSupported = isCallScreenModeSupported;
     }
 
-
-    const HwModuleCollection getHwModules() const { return mHwModules; }
-
-    const DeviceVector &getInputDevices() const
-    {
-        return mInputDevices;
-    }
-
-    const DeviceVector &getOutputDevices() const
-    {
-        return mOutputDevices;
-    }
-
-    void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
-    {
-        mDefaultOutputDevice = defaultDevice;
-    }
-
-    const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevice; }
-
-    void setDefault(void)
-    {
-        mSource = "AudioPolicyConfig::setDefault";
-        mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
-        mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
-        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
-        sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
-        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
-        sp<AudioProfile> micProfile = new AudioProfile(
-                AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
-        defaultInputDevice->addAudioProfile(micProfile);
-        mOutputDevices.add(mDefaultOutputDevice);
-        mInputDevices.add(defaultInputDevice);
-
-        sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
-        mHwModules.add(module);
-
-        sp<OutputProfile> outProfile = new OutputProfile("primary");
-        outProfile->addAudioProfile(
-                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
-        outProfile->addSupportedDevice(mDefaultOutputDevice);
-        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
-        module->addOutputProfile(outProfile);
-
-        sp<InputProfile> inProfile = new InputProfile("primary");
-        inProfile->addAudioProfile(micProfile);
-        inProfile->addSupportedDevice(defaultInputDevice);
-        module->addInputProfile(inProfile);
-
-        setDefaultSurroundFormats();
-    }
-
-    // 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>>;
-
     const SurroundFormats &getSurroundFormats() const
     {
         return mSurroundFormats;
     }
-
+    void setDefaultSurroundFormats();
     void setSurroundFormats(const SurroundFormats &surroundFormats)
     {
         mSurroundFormats = surroundFormats;
     }
-
-    void setDefaultSurroundFormats()
+    void setSurroundFormats(SurroundFormats &&surroundFormats)
     {
-        mSurroundFormats = {
-            {AUDIO_FORMAT_AC3, {}},
-            {AUDIO_FORMAT_E_AC3, {}},
-            {AUDIO_FORMAT_DTS, {}},
-            {AUDIO_FORMAT_DTS_HD, {}},
-            {AUDIO_FORMAT_DTS_HD_MA, {}},
-            {AUDIO_FORMAT_DTS_UHD, {}},
-            {AUDIO_FORMAT_DTS_UHD_P2, {}},
-            {AUDIO_FORMAT_AAC_LC, {
-                    AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
-                    AUDIO_FORMAT_AAC_XHE}},
-            {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
-            {AUDIO_FORMAT_E_AC3_JOC, {}},
-            {AUDIO_FORMAT_AC4, {}}};
+        mSurroundFormats = std::move(surroundFormats);
     }
 
+    void setDefault();
+
 private:
+    friend class sp<AudioPolicyConfig>;
+
     static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
 
-    std::string mSource;
-    std::string mEngineLibraryNameSuffix;
-    HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
-    DeviceVector &mOutputDevices;
-    DeviceVector &mInputDevices;
-    sp<DeviceDescriptor> &mDefaultOutputDevice;
+    AudioPolicyConfig() = default;
+
+    void augmentData();
+    status_t loadFromXml(const std::string& xmlFilePath, bool forVts);
+
+    std::string mSource;  // Not kDefaultConfigSource. Empty source means an empty config.
+    std::string mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
+    HwModuleCollection mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
+    DeviceVector mOutputDevices;
+    DeviceVector mInputDevices;
+    sp<DeviceDescriptor> mDefaultOutputDevice;
     // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
     // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
     // Note: remove also speaker_drc_enabled from global configuration of XML config file.
-    bool mIsSpeakerDrcEnabled;
-    bool mIsCallScreenModeSupported;
+    bool mIsSpeakerDrcEnabled = false;
+    bool mIsCallScreenModeSupported = false;
     SurroundFormats mSurroundFormats;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
new file mode 100644
index 0000000..575a6c5
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2009 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 "APM_Config"
+
+#include <AudioPolicyConfig.h>
+#include <IOProfile.h>
+#include <Serializer.h>
+#include <media/AudioProfile.h>
+#include <system/audio.h>
+#include <system/audio_config.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// static
+sp<const AudioPolicyConfig> AudioPolicyConfig::createDefault() {
+    auto config = sp<AudioPolicyConfig>::make();
+    config->setDefault();
+    return config;
+}
+
+// static
+sp<const AudioPolicyConfig> AudioPolicyConfig::loadFromApmXmlConfigWithFallback(
+        const std::string& xmlFilePath) {
+    const std::string filePath =
+            xmlFilePath.empty() ? audio_get_audio_policy_config_file() : xmlFilePath;
+    auto config = sp<AudioPolicyConfig>::make();
+    if (status_t status = config->loadFromXml(filePath, false /*forVts*/); status == NO_ERROR) {
+        return config;
+    } else {
+        return createDefault();
+    }
+}
+
+// static
+sp<AudioPolicyConfig> AudioPolicyConfig::createWritableForTests() {
+    return sp<AudioPolicyConfig>::make();
+}
+
+// static
+error::Result<sp<AudioPolicyConfig>> AudioPolicyConfig::loadFromCustomXmlConfigForTests(
+        const std::string& xmlFilePath) {
+    auto config = sp<AudioPolicyConfig>::make();
+    if (status_t status = config->loadFromXml(xmlFilePath, false /*forVts*/); status == NO_ERROR) {
+        return config;
+    } else {
+        return base::unexpected(status);
+    }
+}
+
+// static
+error::Result<sp<AudioPolicyConfig>> AudioPolicyConfig::loadFromCustomXmlConfigForVtsTests(
+        const std::string& configPath, const std::string& xmlFileName) {
+    auto filePath = configPath;
+    if (filePath.empty()) {
+        for (const auto& location : audio_get_configuration_paths()) {
+            std::string path = location + '/' + xmlFileName;
+            if (access(path.c_str(), F_OK) == 0) {
+                filePath = location;
+                break;
+            }
+        }
+    }
+    if (filePath.empty()) {
+        ALOGE("Did not find a config file \"%s\" among known config paths", xmlFileName.c_str());
+        return base::unexpected(BAD_VALUE);
+    }
+    auto config = sp<AudioPolicyConfig>::make();
+    if (status_t status = config->loadFromXml(filePath + "/" + xmlFileName, true /*forVts*/);
+            status == NO_ERROR) {
+        return config;
+    } else {
+        return base::unexpected(status);
+    }
+}
+
+void AudioPolicyConfig::augmentData() {
+    // If microphones address is empty, set it according to device type
+    for (size_t i = 0; i < mInputDevices.size(); i++) {
+        if (mInputDevices[i]->address().empty()) {
+            if (mInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+                mInputDevices[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
+            } else if (mInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
+                mInputDevices[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
+            }
+        }
+    }
+}
+
+status_t AudioPolicyConfig::loadFromXml(const std::string& xmlFilePath, bool forVts) {
+    if (xmlFilePath.empty()) {
+        ALOGE("Audio policy configuration file name is empty");
+        return BAD_VALUE;
+    }
+    status_t status = forVts ? deserializeAudioPolicyFileForVts(xmlFilePath.c_str(), this)
+            : deserializeAudioPolicyFile(xmlFilePath.c_str(), this);
+    if (status == NO_ERROR) {
+        mSource = xmlFilePath;
+        augmentData();
+    } else {
+        ALOGE("Could not load audio policy from the configuration file \"%s\": %d",
+                xmlFilePath.c_str(), status);
+    }
+    return status;
+}
+
+void AudioPolicyConfig::setDefault() {
+    mSource = kDefaultConfigSource;
+    mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
+
+    mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
+    mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
+    sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
+    defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
+    sp<AudioProfile> micProfile = new AudioProfile(
+            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
+    defaultInputDevice->addAudioProfile(micProfile);
+    mOutputDevices.add(mDefaultOutputDevice);
+    mInputDevices.add(defaultInputDevice);
+
+    sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
+    mHwModules.add(module);
+
+    sp<OutputProfile> outProfile = new OutputProfile("primary");
+    outProfile->addAudioProfile(
+            new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
+    outProfile->addSupportedDevice(mDefaultOutputDevice);
+    outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
+    module->addOutputProfile(outProfile);
+
+    sp<InputProfile> inProfile = new InputProfile("primary");
+    inProfile->addAudioProfile(micProfile);
+    inProfile->addSupportedDevice(defaultInputDevice);
+    module->addInputProfile(inProfile);
+
+    setDefaultSurroundFormats();
+    augmentData();
+}
+
+void AudioPolicyConfig::setDefaultSurroundFormats() {
+    mSurroundFormats = {
+        {AUDIO_FORMAT_AC3, {}},
+        {AUDIO_FORMAT_E_AC3, {}},
+        {AUDIO_FORMAT_DTS, {}},
+        {AUDIO_FORMAT_DTS_HD, {}},
+        {AUDIO_FORMAT_DTS_HD_MA, {}},
+        {AUDIO_FORMAT_DTS_UHD, {}},
+        {AUDIO_FORMAT_DTS_UHD_P2, {}},
+        {AUDIO_FORMAT_AAC_LC, {
+                AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
+                AUDIO_FORMAT_AAC_XHE}},
+        {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
+        {AUDIO_FORMAT_E_AC3_JOC, {}},
+        {AUDIO_FORMAT_AC4, {}}};
+}
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index d446e96..1b48dc3 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -29,6 +29,7 @@
 #include <utils/StrongPointer.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include "IOProfile.h"
 #include "Serializer.h"
 #include "TypeConverter.h"
 
@@ -907,7 +908,6 @@
 {
     PolicySerializer serializer;
     status_t status = serializer.deserialize(fileName, config);
-    if (status != OK) config->clear();
     return status;
 }
 
@@ -915,7 +915,6 @@
 {
     PolicySerializer serializer;
     status_t status = serializer.deserialize(fileName, config, true /*ignoreVendorExtensions*/);
-    if (status != OK) config->clear();
     return status;
 }
 
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 14f565b..8793085 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -216,8 +216,9 @@
     virtual void process();
 
    protected:
+    sp<AudioPolicyConfig> mConfig{AudioPolicyConfig::createWritableForTests()};
     std::unique_ptr<AudioPolicyManagerTestClient> mClient{new AudioPolicyManagerTestClient};
-    std::unique_ptr<AudioPolicyTestManager> mManager{new AudioPolicyTestManager(mClient.get())};
+    std::unique_ptr<AudioPolicyTestManager> mManager;
     FuzzedDataProvider *mFdp;
 };
 
@@ -230,7 +231,10 @@
     }
     // init code
     SetUpManagerConfig();
-
+    if (mConfig == nullptr) {
+        return false;
+    }
+    mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get()));
     if (mManager->initialize() != NO_ERROR) {
         return false;
     }
@@ -240,7 +244,7 @@
     return true;
 }
 
-void AudioPolicyManagerFuzzer::SetUpManagerConfig() { mManager->getConfig().setDefault(); }
+void AudioPolicyManagerFuzzer::SetUpManagerConfig() { mConfig->setDefault(); }
 
 bool AudioPolicyManagerFuzzer::getOutputForAttr(
     audio_port_handle_t *selectedDeviceId, audio_format_t format, audio_channel_mask_t channelMask,
@@ -408,7 +412,11 @@
 }
 
 void AudioPolicyManagerFuzzerWithConfigurationFile::SetUpManagerConfig() {
-    deserializeAudioPolicyFile(getConfigFile().c_str(), &mManager->getConfig());
+    const std::string configFilePath = getConfigFile();
+    auto result = AudioPolicyConfig::loadFromCustomXmlConfigForTests(configFilePath);
+    mConfig = result.ok() ? mConfig = result.value() : nullptr;
+    ALOGE_IF(!result.ok(), "%s: Failed to deserialize \"%s\": %d",
+            __func__, configFilePath.c_str(), result.error());
 }
 
 void AudioPolicyManagerFuzzerWithConfigurationFile::traverseAndFuzzXML(xmlDocPtr pDoc,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b678662..b558fed 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1330,7 +1330,7 @@
 
     *selectedDeviceId = getFirstDeviceId(outputDevices);
     for (auto &outputDevice : outputDevices) {
-        if (outputDevice->getId() == getConfig().getDefaultOutputDevice()->getId()) {
+        if (outputDevice->getId() == mConfig->getDefaultOutputDevice()->getId()) {
             *selectedDeviceId = outputDevice->getId();
             break;
         }
@@ -1915,7 +1915,8 @@
 }
 
 bool AudioPolicyManager::msdHasPatchesToAllDevices(const AudioDeviceTypeAddrVector& devices) {
-    DeviceVector devicesToCheck = mOutputDevicesAll.getDevicesFromDeviceTypeAddrVec(devices);
+    DeviceVector devicesToCheck =
+            mConfig->getOutputDevices().getDevicesFromDeviceTypeAddrVec(devices);
     AudioPatchCollection msdPatches = getMsdOutputPatches();
     for (size_t i = 0; i < msdPatches.size(); i++) {
         const auto& patch = msdPatches[i];
@@ -4106,13 +4107,13 @@
     dst->appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
     dst->appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
     dst->appendFormat(" Communication Strategy id: %d\n", mCommunnicationStrategy);
-    dst->appendFormat(" Config source: %s\n", mConfig.getSource().c_str()); // getConfig not const
+    dst->appendFormat(" Config source: %s\n", mConfig->getSource().c_str());
 
     dst->append("\n");
     mAvailableOutputDevices.dump(dst, String8("Available output"), 1);
     dst->append("\n");
     mAvailableInputDevices.dump(dst, String8("Available input"), 1);
-    mHwModulesAll.dump(dst);
+    mHwModules.dump(dst);
     mOutputs.dump(dst);
     mInputs.dump(dst);
     mEffects.dump(dst, 1);
@@ -4619,7 +4620,7 @@
         return OK;
     };
 
-    for (const auto& module : mHwModulesAll) {
+    for (const auto& module : mHwModules) {
         for (const auto& dev : module->getDeclaredDevices()) {
             if (role == media::AudioPortRole::NONE ||
                     ((role == media::AudioPortRole::SOURCE)
@@ -5526,10 +5527,10 @@
     size_t formatsWritten = 0;
     size_t formatsMax = *numSurroundFormats;
 
-    *numSurroundFormats = mConfig.getSurroundFormats().size();
+    *numSurroundFormats = mConfig->getSurroundFormats().size();
     audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
             AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
-    for (const auto& format: mConfig.getSurroundFormats()) {
+    for (const auto& format: mConfig->getSurroundFormats()) {
         if (formatsWritten < formatsMax) {
             surroundFormats[formatsWritten] = format.first;
             bool formatEnabled = true;
@@ -5582,10 +5583,10 @@
         formatset.insert(encodedFormats.begin(), encodedFormats.end());
         // Filter the formats which are supported by the vendor hardware.
         for (auto it = formatset.begin(); it != formatset.end(); ++it) {
-            if (mConfig.getSurroundFormats().count(*it) != 0) {
+            if (mConfig->getSurroundFormats().count(*it) != 0) {
                 formats.insert(*it);
             } else {
-                for (const auto& pair : mConfig.getSurroundFormats()) {
+                for (const auto& pair : mConfig->getSurroundFormats()) {
                     if (pair.second.count(*it) != 0) {
                         formats.insert(pair.first);
                         break;
@@ -5606,8 +5607,8 @@
 status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
 {
     ALOGV("%s() format 0x%X enabled %d", __func__, audioFormat, enabled);
-    const auto& formatIter = mConfig.getSurroundFormats().find(audioFormat);
-    if (formatIter == mConfig.getSurroundFormats().end()) {
+    const auto& formatIter = mConfig->getSurroundFormats().find(audioFormat);
+    if (formatIter == mConfig->getSurroundFormats().end()) {
         ALOGW("%s() format 0x%X is not a known surround format", __func__, audioFormat);
         return BAD_VALUE;
     }
@@ -5762,7 +5763,7 @@
 
 bool AudioPolicyManager::isCallScreenModeSupported()
 {
-    return getConfig().isCallScreenModeSupported();
+    return mConfig->isCallScreenModeSupported();
 }
 
 
@@ -5995,26 +5996,14 @@
     return mAudioPortGeneration++;
 }
 
-static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
-    if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();
-            !audioPolicyXmlConfigFile.empty()) {
-        status_t ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile.c_str(), &config);
-        if (ret == NO_ERROR) {
-            config.setSource(audioPolicyXmlConfigFile);
-        }
-        return ret;
-    }
-    return BAD_VALUE;
-}
-
-AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface,
-                                       bool /*forTesting*/)
+AudioPolicyManager::AudioPolicyManager(const sp<const AudioPolicyConfig>& config,
+                                       AudioPolicyClientInterface *clientInterface)
     :
     mUidCached(AID_AUDIOSERVER), // no need to call getuid(), there's only one of us running.
+    mConfig(config),
     mpClientInterface(clientInterface),
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
-    mConfig(mHwModulesAll, mOutputDevicesAll, mInputDevicesAll, mDefaultOutputDevice),
     mAudioPortGeneration(1),
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
@@ -6025,23 +6014,10 @@
 {
 }
 
-AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
-        : AudioPolicyManager(clientInterface, false /*forTesting*/)
-{
-    loadConfig();
-}
-
-void AudioPolicyManager::loadConfig() {
-    if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
-        ALOGE("could not load audio policy configuration file, setting defaults");
-        getConfig().setDefault();
-    }
-}
-
 status_t AudioPolicyManager::initialize() {
     {
         auto engLib = EngineLibrary::load(
-                        "libaudiopolicyengine" + getConfig().getEngineLibraryNameSuffix() + ".so");
+                        "libaudiopolicyengine" + mConfig->getEngineLibraryNameSuffix() + ".so");
         if (!engLib) {
             ALOGE("%s: Failed to load the engine library", __FUNCTION__);
             return NO_INIT;
@@ -6059,31 +6035,22 @@
         return status;
     }
 
-    // If microphones address is empty, set it according to device type
-    for (size_t i = 0; i < mInputDevicesAll.size(); i++) {
-        if (mInputDevicesAll[i]->address().empty()) {
-            if (mInputDevicesAll[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                mInputDevicesAll[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
-            } else if (mInputDevicesAll[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
-                mInputDevicesAll[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
-            }
-        }
-    }
-
     // The actual device selection cache will be updated when calling `updateDevicesAndOutputs`
     // at the end of this function.
     mEngine->initializeDeviceSelectionCache();
     mCommunnicationStrategy = mEngine->getProductStrategyForAttributes(
         mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL));
 
-    // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
+    // after parsing the config, mConfig contain all known devices;
     // open all output streams needed to access attached devices
     onNewAudioModulesAvailableInt(nullptr /*newDevices*/);
 
     // make sure default device is reachable
-    if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
-        ALOGE_IF(mDefaultOutputDevice != 0, "Default device %s is unreachable",
-                 mDefaultOutputDevice->toString().c_str());
+    if (const auto defaultOutputDevice = mConfig->getDefaultOutputDevice();
+            defaultOutputDevice == nullptr ||
+            !mAvailableOutputDevices.contains(defaultOutputDevice)) {
+        ALOGE_IF(defaultOutputDevice != nullptr, "Default device %s is unreachable",
+                 defaultOutputDevice->toString().c_str());
         status = NO_INIT;
     }
     ALOGW_IF(mPrimaryOutput == nullptr, "The policy configuration does not declare a primary output");
@@ -6108,8 +6075,8 @@
    mOutputs.clear();
    mInputs.clear();
    mHwModules.clear();
-   mHwModulesAll.clear();
    mManualSurroundFormats.clear();
+   mConfig.clear();
 }
 
 status_t AudioPolicyManager::initCheck()
@@ -6131,7 +6098,7 @@
 
 void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
 {
-    for (const auto& hwModule : mHwModulesAll) {
+    for (const auto& hwModule : mConfig->getHwModules()) {
         if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
             continue;
         }
@@ -6160,10 +6127,10 @@
             }
 
             const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
-            DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
+            DeviceVector availProfileDevices = supportedDevices.filter(mConfig->getOutputDevices());
             sp<DeviceDescriptor> supportedDevice = 0;
-            if (supportedDevices.contains(mDefaultOutputDevice)) {
-                supportedDevice = mDefaultOutputDevice;
+            if (supportedDevices.contains(mConfig->getDefaultOutputDevice())) {
+                supportedDevice = mConfig->getDefaultOutputDevice();
             } else {
                 // choose first device present in profile's SupportedDevices also part of
                 // mAvailableOutputDevices.
@@ -6172,7 +6139,7 @@
                 }
                 supportedDevice = availProfileDevices.itemAt(0);
             }
-            if (!mOutputDevicesAll.contains(supportedDevice)) {
+            if (!mConfig->getOutputDevices().contains(supportedDevice)) {
                 continue;
             }
             sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
@@ -6227,7 +6194,7 @@
             // chose first device present in profile's SupportedDevices also part of
             // available input devices
             const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
-            DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
+            DeviceVector availProfileDevices = supportedDevices.filter(mConfig->getInputDevices());
             if (availProfileDevices.isEmpty()) {
                 ALOGV("%s: Input device list is empty! for profile %s",
                     __func__, inProfile->getTagName().c_str());
@@ -7987,7 +7954,7 @@
     std::unordered_set<audio_format_t> enforcedSurround(
             devDesc->encodedFormats().begin(), devDesc->encodedFormats().end());
     std::unordered_set<audio_format_t> allSurround;  // A flat set of all known surround formats
-    for (const auto& pair : mConfig.getSurroundFormats()) {
+    for (const auto& pair : mConfig->getSurroundFormats()) {
         allSurround.insert(pair.first);
         for (const auto& subformat : pair.second) allSurround.insert(subformat);
     }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index dc82d54..b2ac181 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -94,7 +94,8 @@
 {
 
 public:
-        explicit AudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+        AudioPolicyManager(const sp<const AudioPolicyConfig>& config,
+                           AudioPolicyClientInterface *clientInterface);
         virtual ~AudioPolicyManager();
 
         // AudioPolicyInterface
@@ -427,19 +428,7 @@
         status_t initialize();
 
 protected:
-        // A constructor that allows more fine-grained control over initialization process,
-        // used in automatic tests.
-        AudioPolicyManager(AudioPolicyClientInterface *clientInterface, bool forTesting);
-
-        // These methods should be used when finer control over APM initialization
-        // is needed, e.g. in tests. Must be used in conjunction with the constructor
-        // that only performs fields initialization. The public constructor comprises
-        // these steps in the following sequence:
-        //   - field initializing constructor;
-        //   - loadConfig;
-        //   - initialize.
-        AudioPolicyConfig& getConfig() { return mConfig; }
-        void loadConfig();
+        const AudioPolicyConfig& getConfig() const { return *(mConfig.get()); }
 
         // From AudioPolicyManagerObserver
         virtual const AudioPatchCollection &getAudioPatches() const
@@ -473,7 +462,7 @@
         }
         virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const
         {
-            return mDefaultOutputDevice;
+            return mConfig->getDefaultOutputDevice();
         }
 
         std::vector<volume_group_t> getVolumeGroups() const
@@ -932,6 +921,7 @@
                 sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs);
 
         const uid_t mUidCached;                         // AID_AUDIOSERVER
+        sp<const AudioPolicyConfig> mConfig;
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
         // list of descriptors for outputs currently opened
@@ -944,8 +934,6 @@
         SwAudioOutputCollection mPreviousOutputs;
         AudioInputCollection mInputs;     // list of input descriptors
 
-        DeviceVector  mOutputDevicesAll; // all output devices from the config
-        DeviceVector  mInputDevicesAll;  // all input devices from the config
         DeviceVector  mAvailableOutputDevices; // all available output devices
         DeviceVector  mAvailableInputDevices;  // all available input devices
 
@@ -955,11 +943,7 @@
         bool    mA2dpSuspended;  // true if A2DP output is suspended
 
         EffectDescriptorCollection mEffects;  // list of registered audio effects
-        sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
         HwModuleCollection mHwModules; // contains modules that have been loaded successfully
-        HwModuleCollection mHwModulesAll; // contains all modules declared in the config
-
-        AudioPolicyConfig mConfig;
 
         std::atomic<uint32_t> mAudioPortGeneration;
 
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 10403fa..2f677da 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -52,8 +52,9 @@
         "libsensor",
         "libsensorprivacy",
         "libshmemcompat",
-        "libutils",
         "libstagefright_foundation",
+        "libutils",
+        "libxml2",
         "audioclient-types-aidl-cpp",
         "audioflinger-aidl-cpp",
         "audiopolicy-aidl-cpp",
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index e5b1c91..7757f37 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -46,6 +46,7 @@
 
 #include <system/audio.h>
 #include <system/audio_policy.h>
+#include <AudioPolicyConfig.h>
 #include <AudioPolicyManager.h>
 
 namespace android {
@@ -185,7 +186,8 @@
 
 static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
 {
-    AudioPolicyManager *apm = new AudioPolicyManager(clientInterface);
+    AudioPolicyManager *apm = new AudioPolicyManager(
+            AudioPolicyConfig::loadFromApmXmlConfigWithFallback(), 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 bf82680..285b354 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -19,19 +19,20 @@
     ],
 
     shared_libs: [
+        "framework-permission-aidl-cpp",
         "libaudioclient",
         "libaudiofoundation",
         "libaudiopolicy",
         "libaudiopolicymanagerdefault",
         "libbase",
+        "libbinder",
+        "libcutils",
         "libhidlbase",
         "liblog",
         "libmedia_helper",
         "libutils",
         "libcutils",
         "libxml2",
-        "framework-permission-aidl-cpp",
-        "libbinder",
     ],
 
     static_libs: [
@@ -73,17 +74,19 @@
     require_root: true,
 
     shared_libs: [
-        "libaudiofoundation",
+        "audioclient-types-aidl-cpp",
         "libaudioclient",
+        "libaudioclient_aidl_conversion",
+        "libaudiofoundation",
         "libaudiopolicymanagerdefault",
+        "libcutils",
         "liblog",
         "libmedia_helper",
-        "libutils",
-        "libaudioclient_aidl_conversion",
-        "libstagefright_foundation",
         "libshmemcompat",
         "libshmemutil",
-        "audioclient-types-aidl-cpp",
+        "libstagefright_foundation",
+        "libutils",
+        "libxml2",
     ],
 
     static_libs: ["libaudiopolicycomponents"],
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 2a7a060..9ad9849 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -22,9 +22,11 @@
 class AudioPolicyTestManager : public AudioPolicyManager {
   public:
     explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
-            : AudioPolicyManager(clientInterface, true /*forTesting*/) { }
+            : AudioPolicyManager(AudioPolicyConfig::createDefault(), clientInterface) {}
+    AudioPolicyTestManager(const sp<const AudioPolicyConfig>& config,
+            AudioPolicyClientInterface *clientInterface)
+            : AudioPolicyManager(config, clientInterface) {}
     using AudioPolicyManager::getConfig;
-    using AudioPolicyManager::loadConfig;
     using AudioPolicyManager::initialize;
     using AudioPolicyManager::getOutputs;
     using AudioPolicyManager::getAvailableOutputDevices;
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index 798332c..70a3022 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -21,6 +21,7 @@
 
 #include <gtest/gtest.h>
 
+#include <AudioPolicyConfig.h>
 #include <media/AudioSystem.h>
 #include <media/TypeConverter.h>
 #include <system/audio.h>
@@ -65,19 +66,17 @@
     }
     free(audioPorts);
 
-    AudioPolicyManagerTestClient client;
-    AudioPolicyTestManager manager(&client);
-    manager.loadConfig();
-    ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();
+    ASSERT_NE(AudioPolicyConfig::kDefaultConfigSource, config->getSource());
 
-    for (auto desc : manager.getConfig().getInputDevices()) {
+    for (const auto& desc : config->getInputDevices()) {
         if (attachedDevices.find(desc->type()) == attachedDevices.end()) {
             std::string deviceType;
             (void)DeviceConverter::toString(desc->type(), deviceType);
             ADD_FAILURE() << "Input device \"" << deviceType << "\" not found";
         }
     }
-    for (auto desc : manager.getConfig().getOutputDevices()) {
+    for (const auto& desc : config->getOutputDevices()) {
         if (attachedDevices.find(desc->type()) == attachedDevices.end()) {
             std::string deviceType;
             (void)DeviceConverter::toString(desc->type(), deviceType);
@@ -87,13 +86,13 @@
 }
 
 TEST(AudioHealthTest, ConnectSupportedDevice) {
+    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();
+    ASSERT_NE(AudioPolicyConfig::kDefaultConfigSource, config->getSource());
     AudioPolicyManagerTestClient client;
-    AudioPolicyTestManager manager(&client);
-    manager.loadConfig();
-    ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+    AudioPolicyTestManager manager(config, &client);
 
     DeviceVector devices;
-    for (const auto& hwModule : manager.getConfig().getHwModules()) {
+    for (const auto& hwModule : config->getHwModules()) {
         for (const auto& profile : hwModule->getOutputProfiles()) {
             devices.merge(profile->getSupportedDevices());
         }
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 412ab19..97a1e0d 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -92,11 +92,44 @@
 
 } // namespace
 
+TEST(AudioPolicyConfigTest, DefaultConfigForTestsIsEmpty) {
+    auto config = AudioPolicyConfig::createWritableForTests();
+    EXPECT_TRUE(config->getSource().empty());
+    EXPECT_TRUE(config->getHwModules().isEmpty());
+    EXPECT_TRUE(config->getInputDevices().isEmpty());
+    EXPECT_TRUE(config->getOutputDevices().isEmpty());
+}
+
+TEST(AudioPolicyConfigTest, FallbackToDefault) {
+    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback(
+            base::GetExecutableDirectory() + "/test_invalid_audio_policy_configuration.xml");
+    EXPECT_EQ(AudioPolicyConfig::kDefaultConfigSource, config->getSource());
+}
+
+TEST(AudioPolicyConfigTest, LoadForTests) {
+    {
+        auto result = AudioPolicyConfig::loadFromCustomXmlConfigForTests(
+                base::GetExecutableDirectory() + "/test_invalid_audio_policy_configuration.xml");
+        EXPECT_FALSE(result.ok());
+    }
+    {
+        const std::string source =
+                base::GetExecutableDirectory() + "/test_audio_policy_configuration.xml";
+        auto result = AudioPolicyConfig::loadFromCustomXmlConfigForTests(source);
+        ASSERT_TRUE(result.ok());
+        EXPECT_EQ(source, result.value()->getSource());
+        EXPECT_FALSE(result.value()->getHwModules().isEmpty());
+        EXPECT_FALSE(result.value()->getInputDevices().isEmpty());
+        EXPECT_FALSE(result.value()->getOutputDevices().isEmpty());
+    }
+}
+
 TEST(AudioPolicyManagerTestInit, EngineFailure) {
     AudioPolicyTestClient client;
-    AudioPolicyTestManager manager(&client);
-    manager.getConfig().setDefault();
-    manager.getConfig().setEngineLibraryNameSuffix("non-existent");
+    auto config = AudioPolicyConfig::createWritableForTests();
+    config->setDefault();
+    config->setEngineLibraryNameSuffix("non-existent");
+    AudioPolicyTestManager manager(config, &client);
     ASSERT_EQ(NO_INIT, manager.initialize());
     ASSERT_EQ(NO_INIT, manager.initCheck());
 }
@@ -104,41 +137,12 @@
 TEST(AudioPolicyManagerTestInit, ClientFailure) {
     AudioPolicyTestClient client;
     AudioPolicyTestManager manager(&client);
-    manager.getConfig().setDefault();
     // Since the default client fails to open anything,
     // APM should indicate that the initialization didn't succeed.
     ASSERT_EQ(NO_INIT, manager.initialize());
     ASSERT_EQ(NO_INIT, manager.initCheck());
 }
 
-// Verifies that a failure while loading a config doesn't leave
-// APM config in a "dirty" state. Since AudioPolicyConfig object
-// is a proxy for the data hosted by APM, it isn't possible
-// to "deep copy" it, and thus we have to test its elements
-// individually.
-TEST(AudioPolicyManagerTestInit, ConfigLoadingIsTransactional) {
-    AudioPolicyTestClient client;
-    AudioPolicyTestManager manager(&client);
-    ASSERT_TRUE(manager.getConfig().getHwModules().isEmpty());
-    ASSERT_TRUE(manager.getConfig().getInputDevices().isEmpty());
-    ASSERT_TRUE(manager.getConfig().getOutputDevices().isEmpty());
-    status_t status = deserializeAudioPolicyFile(
-            (base::GetExecutableDirectory() +
-                    "/test_invalid_audio_policy_configuration.xml").c_str(),
-            &manager.getConfig());
-    ASSERT_NE(NO_ERROR, status);
-    EXPECT_TRUE(manager.getConfig().getHwModules().isEmpty());
-    EXPECT_TRUE(manager.getConfig().getInputDevices().isEmpty());
-    EXPECT_TRUE(manager.getConfig().getOutputDevices().isEmpty());
-    status = deserializeAudioPolicyFile(
-            (base::GetExecutableDirectory() + "/test_audio_policy_configuration.xml").c_str(),
-            &manager.getConfig());
-    ASSERT_EQ(NO_ERROR, status);
-    EXPECT_FALSE(manager.getConfig().getHwModules().isEmpty());
-    EXPECT_FALSE(manager.getConfig().getInputDevices().isEmpty());
-    EXPECT_FALSE(manager.getConfig().getOutputDevices().isEmpty());
-}
-
 
 class PatchCountCheck {
   public:
@@ -200,6 +204,7 @@
     static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch* patch);
     virtual AudioPolicyManagerTestClient* getClient() { return new AudioPolicyManagerTestClient; }
 
+    sp<AudioPolicyConfig> mConfig;
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
     std::unique_ptr<AudioPolicyTestManager> mManager;
 
@@ -208,8 +213,8 @@
 
 void AudioPolicyManagerTest::SetUp() {
     mClient.reset(getClient());
-    mManager.reset(new AudioPolicyTestManager(mClient.get()));
     ASSERT_NO_FATAL_FAILURE(SetUpManagerConfig());  // Subclasses may want to customize the config.
+    mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get()));
     ASSERT_EQ(NO_ERROR, mManager->initialize());
     ASSERT_EQ(NO_ERROR, mManager->initCheck());
 }
@@ -220,7 +225,8 @@
 }
 
 void AudioPolicyManagerTest::SetUpManagerConfig() {
-    mManager->getConfig().setDefault();
+    mConfig = AudioPolicyConfig::createWritableForTests();
+    mConfig->setDefault();
 }
 
 void AudioPolicyManagerTest::dumpToLog() {
@@ -467,7 +473,6 @@
 void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
     // TODO: Consider using Serializer to load part of the config from a string.
     ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTest::SetUpManagerConfig());
-    AudioPolicyConfig& config = mManager->getConfig();
     mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
     sp<AudioProfile> pcmOutputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, k48000SamplingRate);
@@ -483,26 +488,26 @@
     sp<AudioProfile> pcmInputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
     mMsdInputDevice->addAudioProfile(pcmInputProfile);
-    config.addDevice(mMsdOutputDevice);
-    config.addDevice(mMsdInputDevice);
+    mConfig->addDevice(mMsdOutputDevice);
+    mConfig->addDevice(mMsdInputDevice);
 
     if (mExpectedAudioPatchCount == 2) {
         // Add SPDIF device with PCM output profile as a second device for dual MSD audio patching.
         mSpdifDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPDIF);
         mSpdifDevice->addAudioProfile(pcmOutputProfile);
-        config.addDevice(mSpdifDevice);
+        mConfig->addDevice(mSpdifDevice);
 
         sp<OutputProfile> spdifOutputProfile = new OutputProfile("spdif output");
         spdifOutputProfile->addAudioProfile(pcmOutputProfile);
         spdifOutputProfile->addSupportedDevice(mSpdifDevice);
-        config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+        mConfig->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
                 addOutputProfile(spdifOutputProfile);
     }
 
     sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
-    HwModuleCollection modules = config.getHwModules();
+    HwModuleCollection modules = mConfig->getHwModules();
     modules.add(msdModule);
-    config.setHwModules(modules);
+    mConfig->setHwModules(modules);
 
     sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
     msdOutputProfile->addAudioProfile(pcmOutputProfile);
@@ -530,15 +535,15 @@
     // of streams that are not supported by MSD.
     sp<AudioProfile> dtsOutputProfile = new AudioProfile(
             AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, k48000SamplingRate);
-    config.getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
+    mConfig->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
     sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile("encoded");
     primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
     primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
-    primaryEncodedOutputProfile->addSupportedDevice(config.getDefaultOutputDevice());
-    config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+    primaryEncodedOutputProfile->addSupportedDevice(mConfig->getDefaultOutputDevice());
+    mConfig->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
             addOutputProfile(primaryEncodedOutputProfile);
 
-    mDefaultOutputDevice = config.getDefaultOutputDevice();
+    mDefaultOutputDevice = mConfig->getDefaultOutputDevice();
     if (mExpectedAudioPatchCount == 2) {
         mSpdifDevice->addAudioProfile(dtsOutputProfile);
         primaryEncodedOutputProfile->addSupportedDevice(mSpdifDevice);
@@ -549,12 +554,12 @@
     sp<AudioProfile> iec958InputProfile = new AudioProfile(
             AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_INDEX_MASK_24, k48000SamplingRate);
     mHdmiInputDevice->addAudioProfile(iec958InputProfile);
-    config.addDevice(mHdmiInputDevice);
+    mConfig->addDevice(mHdmiInputDevice);
     sp<InputProfile> hdmiInputProfile = new InputProfile("hdmi input");
     hdmiInputProfile->addAudioProfile(iec958InputProfile);
     hdmiInputProfile->setFlags(AUDIO_INPUT_FLAG_DIRECT);
     hdmiInputProfile->addSupportedDevice(mHdmiInputDevice);
-    config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+    mConfig->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
             addInputProfile(hdmiInputProfile);
 }
 
@@ -721,7 +726,7 @@
     int countDirectProfilesPrimary = 0;
     const auto& primary = mManager->getConfig().getHwModules()
             .getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
-    for (const auto outputProfile : primary->getOutputProfiles()) {
+    for (const auto& outputProfile : primary->getOutputProfiles()) {
         if (outputProfile->asAudioPort()->isDirectOutput()) {
             countDirectProfilesPrimary += outputProfile->asAudioPort()->getAudioProfiles().size();
         }
@@ -731,7 +736,7 @@
     int countDirectProfilesMsd = 0;
     const auto& msd = mManager->getConfig().getHwModules()
             .getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
-    for (const auto outputProfile : msd->getOutputProfiles()) {
+    for (const auto& outputProfile : msd->getOutputProfiles()) {
         if (outputProfile->asAudioPort()->isDirectOutput()) {
             countDirectProfilesMsd += outputProfile->asAudioPort()->getAudioProfiles().size();
         }
@@ -922,9 +927,9 @@
         sExecutableDir + "test_audio_policy_configuration.xml";
 
 void AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig() {
-    status_t status = deserializeAudioPolicyFile(getConfigFile().c_str(), &mManager->getConfig());
-    ASSERT_EQ(NO_ERROR, status);
-    mManager->getConfig().setSource(getConfigFile());
+    auto result = AudioPolicyConfig::loadFromCustomXmlConfigForTests(getConfigFile());
+    ASSERT_TRUE(result.ok());
+    mConfig = result.value();
 }
 
 TEST_F(AudioPolicyManagerTestWithConfigurationFile, InitSuccess) {