Merge "Move engine loading out from the AudioPolicyManager"
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index de501ee..abacd3c 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -110,7 +110,7 @@
     status_t getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
             AudioDeviceTypeAddrVector &devices) const override;
 
-    engineConfig::ParsingResult loadAudioPolicyEngineConfig();
+    engineConfig::ParsingResult loadAudioPolicyEngineConfig(const std::string& xmlFilePath = "");
 
     const ProductStrategyMap &getProductStrategies() const { return mProductStrategies; }
 
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 83a8e4d..fe5cd9f 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -115,7 +115,7 @@
     return PRODUCT_STRATEGY_NONE;
 }
 
-engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
+engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
 {
     auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
         // Ensure name unicity to prevent duplicate
@@ -163,8 +163,9 @@
         return stat(path, &fileStat) == 0 && S_ISREG(fileStat.st_mode);
     };
 
-    auto result = fileExists(engineConfig::DEFAULT_PATH) ?
-            engineConfig::parse(engineConfig::DEFAULT_PATH) : engineConfig::ParsingResult{};
+    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;
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index 57174c7..9c156ab 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <string>
 #include <utility>
 
 #include <AudioPolicyManagerObserver.h>
@@ -46,6 +47,13 @@
 {
 public:
     /**
+     * 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.
+     */
+    virtual status_t loadFromXmlConfigWithFallback(const std::string& xmlFilePath = "") = 0;
+
+    /**
      * Checks if the engine was correctly initialized.
      *
      * @return NO_ERROR if initialization has been done correctly, error code otherwise..
diff --git a/services/audiopolicy/engineconfigurable/src/Collection.h b/services/audiopolicy/engineconfigurable/src/Collection.h
index 02b41cb..4640515 100644
--- a/services/audiopolicy/engineconfigurable/src/Collection.h
+++ b/services/audiopolicy/engineconfigurable/src/Collection.h
@@ -53,6 +53,10 @@
     {
         collectionSupported();
     }
+    ~Collection()
+    {
+        clear();
+    }
 
     /**
      * Add a policy element to the collection. Policy elements are streams, strategies, input
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index a802646..257d1fc 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -68,16 +68,15 @@
 
 Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
 {
-    status_t loadResult = loadAudioPolicyEngineConfig();
+}
+
+status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
+{
+    status_t loadResult = loadAudioPolicyEngineConfig(xmlFilePath);
     if (loadResult < 0) {
         ALOGE("Policy Engine configuration is invalid.");
     }
-}
-
-Engine::~Engine()
-{
-    mStreamCollection.clear();
-    mInputSourceCollection.clear();
+    return loadResult;
 }
 
 status_t Engine::initCheck()
@@ -179,9 +178,9 @@
     return EngineBase::setDeviceConnectionState(device, state);
 }
 
-status_t Engine::loadAudioPolicyEngineConfig()
+status_t Engine::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
 {
-    auto result = EngineBase::loadAudioPolicyEngineConfig();
+    auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath);
 
     // Custom XML Parsing
     auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
@@ -401,5 +400,3 @@
 
 } // namespace audio_policy
 } // namespace android
-
-
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 001dde9..d5083f0 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -33,12 +33,17 @@
 {
 public:
     Engine();
-    virtual ~Engine();
+    virtual ~Engine() = default;
 
     template <class RequestedInterface>
     RequestedInterface *queryInterface();
 
     ///
+    /// from EngineInterface
+    ///
+    android::status_t loadFromXmlConfigWithFallback(const std::string& xmlFilePath = "") override;
+
+    ///
     /// from EngineBase
     ///
     android::status_t initCheck() override;
@@ -118,7 +123,7 @@
     template <typename Property, typename Key>
     bool setPropertyForKey(const Property &property, const Key &key);
 
-    status_t loadAudioPolicyEngineConfig();
+    status_t loadAudioPolicyEngineConfig(const std::string& xmlFilePath);
 
     DeviceVector getCachedDevices(product_strategy_t ps) const;
 
@@ -136,4 +141,3 @@
 } // namespace audio_policy
 
 } // namespace android
-
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index e72249f..0fa0e0e 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -59,9 +59,8 @@
     return legacyStrategy;
 }
 
-Engine::Engine()
-{
-    auto result = EngineBase::loadAudioPolicyEngineConfig();
+status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath) {
+    auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath);
     ALOGE_IF(result.nbSkippedElement != 0,
              "Policy Engine configuration is partially invalid, skipped %zu elements",
              result.nbSkippedElement);
@@ -70,6 +69,8 @@
     for (const auto &strategy : legacyStrategy) {
         mLegacyStrategyMap[getProductStrategyByName(strategy.name)] = strategy.id;
     }
+
+    return OK;
 }
 
 status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config)
@@ -795,5 +796,3 @@
 
 } // namespace audio_policy
 } // namespace android
-
-
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index be9f4cc..fde9802 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -45,9 +45,14 @@
 class Engine : public EngineBase
 {
 public:
-    Engine();
+    Engine() = default;
     virtual ~Engine() = default;
 
+    ///
+    /// from EngineInterface
+    ///
+    status_t loadFromXmlConfigWithFallback(const std::string& xmlFilePath = "") override;
+
 private:
     ///
     /// from EngineBase, so from EngineInterface
@@ -102,4 +107,3 @@
 };
 } // namespace audio_policy
 } // namespace android
-
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 3dbb177..8154944 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5608,10 +5608,12 @@
 }
 
 AudioPolicyManager::AudioPolicyManager(const sp<const AudioPolicyConfig>& config,
+                                       EngineInstance&& engine,
                                        AudioPolicyClientInterface *clientInterface)
     :
     mUidCached(AID_AUDIOSERVER), // no need to call getuid(), there's only one of us running.
     mConfig(config),
+    mEngine(std::move(engine)),
     mpClientInterface(clientInterface),
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
@@ -5626,18 +5628,8 @@
 }
 
 status_t AudioPolicyManager::initialize() {
-    {
-        auto engLib = EngineLibrary::load(
-                        "libaudiopolicyengine" + mConfig->getEngineLibraryNameSuffix() + ".so");
-        if (!engLib) {
-            ALOGE("%s: Failed to load the engine library", __FUNCTION__);
-            return NO_INIT;
-        }
-        mEngine = engLib->createEngine();
-        if (mEngine == nullptr) {
-            ALOGE("%s: Failed to instantiate the APM engine", __FUNCTION__);
-            return NO_INIT;
-        }
+    if (mEngine == nullptr) {
+        return NO_INIT;
     }
     mEngine->setObserver(this);
     status_t status = mEngine->initCheck();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a52f2c6..bb41f85 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -94,6 +94,7 @@
 
 public:
         AudioPolicyManager(const sp<const AudioPolicyConfig>& config,
+                           EngineInstance&& engine,
                            AudioPolicyClientInterface *clientInterface);
         virtual ~AudioPolicyManager();
 
@@ -902,6 +903,7 @@
 
         const uid_t mUidCached;                         // AID_AUDIOSERVER
         sp<const AudioPolicyConfig> mConfig;
+        EngineInstance mEngine;                         // Audio Policy Engine instance
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
         // list of descriptors for outputs currently opened
@@ -954,9 +956,6 @@
 
         uint32_t nextAudioPortGeneration();
 
-        // Audio Policy Engine Interface.
-        EngineInstance mEngine;
-
         // Surround formats that are enabled manually. Taken into account when
         // "encoded surround" is forced into "manual" mode.
         std::unordered_set<audio_format_t> mManualSurroundFormats;
diff --git a/services/audiopolicy/managerdefault/EngineLibrary.cpp b/services/audiopolicy/managerdefault/EngineLibrary.cpp
index ef699aa..939fbc5 100644
--- a/services/audiopolicy/managerdefault/EngineLibrary.cpp
+++ b/services/audiopolicy/managerdefault/EngineLibrary.cpp
@@ -23,9 +23,27 @@
 
 namespace android {
 
-// static
-std::shared_ptr<EngineLibrary> EngineLibrary::load(std::string libraryPath)
+EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
+        const std::string& configXmlFilePath)
 {
+    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->createEngineUsingXmlConfig(configXmlFilePath);
+    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)
+{
+    std::string libraryPath = "libaudiopolicyengine" + librarySuffix + ".so";
     std::shared_ptr<EngineLibrary> engLib(new EngineLibrary());
     return engLib->init(std::move(libraryPath)) ? engLib : nullptr;
 }
@@ -35,6 +53,20 @@
     close();
 }
 
+EngineInstance EngineLibrary::createEngineUsingXmlConfig(const std::string& xmlFilePath) {
+    auto instance = createEngine();
+    if (instance != nullptr) {
+        if (status_t status = instance->loadFromXmlConfigWithFallback(xmlFilePath);
+                status == OK) {
+            return instance;
+        } else {
+            ALOGE("%s: loading of the engine config with XML configuration file \"%s\" failed: %d",
+                    __func__, xmlFilePath.empty() ? "default" : xmlFilePath.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 f143916..dc138a1 100644
--- a/services/audiopolicy/managerdefault/EngineLibrary.h
+++ b/services/audiopolicy/managerdefault/EngineLibrary.h
@@ -26,9 +26,12 @@
 
 using EngineInstance = std::unique_ptr<EngineInterface, std::function<void (EngineInterface*)>>;
 
+EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
+        const std::string& configXmlFilePath = "");
+
 class EngineLibrary : public std::enable_shared_from_this<EngineLibrary> {
 public:
-    static std::shared_ptr<EngineLibrary> load(std::string libraryPath);
+    static std::shared_ptr<EngineLibrary> load(const std::string& librarySuffix);
     ~EngineLibrary();
 
     EngineLibrary(const EngineLibrary&) = delete;
@@ -36,11 +39,12 @@
     EngineLibrary& operator=(const EngineLibrary&) = delete;
     EngineLibrary& operator=(EngineLibrary&&) = delete;
 
-    EngineInstance createEngine();
+    EngineInstance createEngineUsingXmlConfig(const std::string& xmlFilePath);
 
 private:
     EngineLibrary() = default;
     bool init(std::string libraryPath);
+    EngineInstance createEngine();
     void close();
 
     void *mLibraryHandle = nullptr;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b343f34..930631a 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -180,8 +180,10 @@
 
 static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
 {
+    auto config = AudioPolicyConfig::loadFromApmXmlConfigWithFallback();  // This can't fail.
     AudioPolicyManager *apm = new AudioPolicyManager(
-            AudioPolicyConfig::loadFromApmXmlConfigWithFallback(), clientInterface);
+            config, loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
+            clientInterface);
     status_t status = apm->initialize();
     if (status != NO_ERROR) {
         delete apm;
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 9ad9849..31ee252 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -22,10 +22,12 @@
 class AudioPolicyTestManager : public AudioPolicyManager {
   public:
     explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
-            : AudioPolicyManager(AudioPolicyConfig::createDefault(), clientInterface) {}
+            : AudioPolicyTestManager(AudioPolicyConfig::createDefault(), clientInterface) {}
     AudioPolicyTestManager(const sp<const AudioPolicyConfig>& config,
             AudioPolicyClientInterface *clientInterface)
-            : AudioPolicyManager(config, clientInterface) {}
+            : AudioPolicyManager(config,
+                    loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
+                    clientInterface) {}
     using AudioPolicyManager::getConfig;
     using AudioPolicyManager::initialize;
     using AudioPolicyManager::getOutputs;