Effect factory: Load config from /odm, /vendor or /system

The effect framework only supports loading its config from /vendor/etc/.

As the audioeffects.conf supported to be loaded from /system and we want
to ease transition to xml,
As the audio policy config and the effect HW modules are can be loaded
from {"/odm/etc", "/vendor/etc", "/system/etc"},

Search for the audio effects xml config in /odm, then /vendor then
/vendor.

Bug: 38184704
Change-Id: I92a4e182fd16659eee2cf6481f8c2a646bf4f427
Test: media.audio_flinger dumpsys with config in /vendor and /system
      are identical
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 97462f8..18c406d 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <functional>
 #include <string>
+#include <unistd.h>
 
 #include <tinyxml2.h>
 #include <log/log.h>
@@ -85,7 +86,7 @@
 constexpr std::enable_if<false, Enum> STREAM_NAME_MAP;
 
 /** All output stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
  */
 template <>
 constexpr std::pair<audio_stream_type_t, const char*> STREAM_NAME_MAP<audio_stream_type_t>[] = {
@@ -102,7 +103,7 @@
 };
 
 /** All input stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
  */
 template <>
 constexpr std::pair<audio_source_t, const char*> STREAM_NAME_MAP<audio_source_t>[] = {
@@ -142,7 +143,7 @@
 }
 
 /** Find an element in a collection by its name.
- * @return nullptr if not found, the ellements address if found.
+ * @return nullptr if not found, the element address if found.
  */
 template <class T>
 T* findByName(const char* name, std::vector<T>& collection) {
@@ -249,15 +250,14 @@
     return true;
 }
 
-}; // namespace
-
-ParsingResult parse(const char* path) {
+/** Internal version of the public parse(const char* path) with precondition `path != nullptr`. */
+ParsingResult parseWithPath(const char* path) {
     XMLDocument doc;
     doc.LoadFile(path);
     if (doc.Error()) {
         ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s %s", path,
               doc.ErrorID(), doc.GetErrorStr1(), doc.GetErrorStr2());
-        return {nullptr, 0};
+        return {nullptr, 0, path};
     }
 
     auto config = std::make_unique<Config>();
@@ -295,7 +295,29 @@
             }
         }
     }
-    return {std::move(config), nbSkippedElements};
+    return {std::move(config), nbSkippedElements, path};
+}
+
+}; // namespace
+
+ParsingResult parse(const char* path) {
+    if (path != nullptr) {
+        return parseWithPath(path);
+    }
+
+    for (std::string location : DEFAULT_LOCATIONS) {
+        std::string defaultPath = location + '/' + DEFAULT_NAME;
+        if (access(defaultPath.c_str(), R_OK) != 0) {
+            continue;
+        }
+        auto result = parseWithPath(defaultPath.c_str());
+        if (result.parsedConfig != nullptr) {
+            return result;
+        }
+    }
+
+    ALOGE("Could not parse effect configuration in any of the default locations.");
+    return {nullptr, 0, nullptr};
 }
 
 } // namespace effectsConfig