audiopolicy: engine: use apm XML config file for volume curves

This CL removes the hard coded volume table in the engine and
use as a fallback for compatibility reason the apm config file
to load the volume tables.

Bug: 124767636
Test: dumpsys media.audio_policy & diff with previous version

Change-Id: I0392aad730c67ee79f898093fd1b4f64e26ab3fd
Signed-off-by: Francois Gaffie <francois.gaffie@renault.com>
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index c2a1da7..0ec63e1 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -182,8 +182,8 @@
 private:
     KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
     std::map<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
-    /*const*/ int mIndexMin; /**< min volume index. */
-    /*const*/ int mIndexMax; /**< max volume index. */
+    int mIndexMin; /**< min volume index. */
+    int mIndexMax; /**< max volume index. */
     const bool mCanBeMuted = true; /**< true is the stream can be muted. */
 
     const audio_stream_type_t mStream; /**< Keep it for legacy. */
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 2449b61..6e2ab4c 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -139,7 +139,10 @@
     auto result = engineConfig::parse();
     if (result.parsedConfig == nullptr) {
         ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
-        result = {std::make_unique<engineConfig::Config>(gDefaultEngineConfig), 0};
+        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)};
     }
     ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
     loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies);
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index 86a59b0..f1642c5 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -131,131 +131,11 @@
     }
 };
 
-const engineConfig::VolumeGroups gVolumeGroups = {
-    {"voice_call", "AUDIO_STREAM_VOICE_CALL", 1, 10,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -4200}, {33, -2800}, {66, -1400}, {100, 0} } },
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -2400}, {33, -1600}, {66, -800}, {100, 0} } },
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -2700}, {33, -1800}, {66, -900}, {100, 0} } },
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } },
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } },
-     },
-    },
-    {"system", "AUDIO_STREAM_SYSTEM", 0, 100,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {1, -3000}, {33, -2600}, {66, -2200}, {100, -1800} } },
-         {"DEVICE_CATEGORY_SPEAKER", { {1, -5100}, {57, -2800}, {71, -2500}, {85, -2300}, {100, -2100} } },
-         {"DEVICE_CATEGORY_EARPIECE", { {1, -2400}, {33, -1800}, {66, -1200}, {100, -600} } },
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -2100}, {100, -1000} } }, // DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"ring", "AUDIO_STREAM_RING", 0, 100,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {1, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } },
-         {"DEVICE_CATEGORY_EARPIECE", { {1, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -2100}, {100, -1000} } }, // DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"music", "AUDIO_STREAM_MUSIC", 0, 40,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"alarm", "AUDIO_STREAM_ALARM", 0, 100,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {0, -5800}, {20, -4000}, {60, -2100}, {100, -1000} } }, // DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {0, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"notification", "AUDIO_STREAM_NOTIFICATION", 0, 100,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {1, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {1, -4680}, {42, -2070}, {85, -540}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {1, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -2100}, {100, -1000} } }, // DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -4950}, {33, -3350}, {66, -1700}, {100, 0} } }, // DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE
-     },
-    },
-    {"bluetooth_sco", "AUDIO_STREAM_BLUETOOTH_SCO", 1, 10,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -4200}, {33, -2800}, {66, -1400}, {100, 0} } },
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -2400}, {33, -1600}, {66, -800}, {100, 0} } },
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -4200}, {33, -2800}, {66, -1400}, {100, 0} } },
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"enforced_audible", "AUDIO_STREAM_ENFORCED_AUDIBLE", 0, 100,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {1, -3000}, {33, -2600}, {66, -2200}, {100, -1800} } },
-         {"DEVICE_CATEGORY_SPEAKER", { {1, -3400}, {71, -2400}, {100, -2000} } },
-         {"DEVICE_CATEGORY_EARPIECE", { {1, -2400}, {33, -1800}, {66, -1200}, {100, -600} } }, // DEFAULT_SYSTEM_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -2100}, {100, -1000} } }, // DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"dtmf", "AUDIO_STREAM_DTMF", 0, 100,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {1, -3000}, {33, -2600}, {66, -2200}, {100, -1800} } },
-         {"DEVICE_CATEGORY_SPEAKER", { {1, -4000}, {71, -2400}, {100, -1400} } }, // DEFAULT_SYSTEM_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {1, -2400}, {33, -1800}, {66, -1200}, {100, -600} } }, // DEFAULT_SYSTEM_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {1, -5800}, {20, -4000}, {60, -2100}, {100, -1000} } }, // DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {1, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"tts", "AUDIO_STREAM_TTS", 0, 16,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -9600}, {100, -9600} } }, // SILENT_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -9600}, {100, -9600} } }, // SILENT_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {0, -9600}, {100, -9600} } }, // SILENT_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {0, -9600}, {100, -9600} } }, // SILENT_VOLUME_CURVE
-     },
-    },
-    {"accessibility", "AUDIO_STREAM_ACCESSIBILITY", 1, 40,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {0, -5800}, {20, -4000}, {60, -1700}, {100, 0} } }, // DEFAULT_NON_MUTABLE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {0, -12700}, {20, -8000}, {60, -4000}, {100, 0} } }, // DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE
-     },
-    },
-    {"rerouting", "AUDIO_STREAM_REROUTING", 0, 1,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-     },
-    },
-    {"patch", "AUDIO_STREAM_PATCH", 0, 1,
-     {
-         {"DEVICE_CATEGORY_HEADSET", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_SPEAKER", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EARPIECE", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_EXT_MEDIA", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-         {"DEVICE_CATEGORY_HEARING_AID", { {0, -0}, {100, 0} } }, // FULL_SCALE_VOLUME_CURVE
-     },
-    },
-};
-
 const engineConfig::Config gDefaultEngineConfig = {
     1.0,
     gOrderedStrategies,
     {},
     {},
-    gVolumeGroups
+    {}
 };
 } // namespace android
diff --git a/services/audiopolicy/engine/config/Android.mk b/services/audiopolicy/engine/config/Android.mk
index fe7d961..0b292a5 100644
--- a/services/audiopolicy/engine/config/Android.mk
+++ b/services/audiopolicy/engine/config/Android.mk
@@ -23,7 +23,8 @@
     libandroidicu \
     libxml2 \
     libutils \
-    liblog
+    liblog \
+    libcutils
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index f7caad2..a188115 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -113,6 +113,7 @@
  * @return audio policy usage @see Config
  */
 ParsingResult parse(const char* path = DEFAULT_PATH);
+android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups);
 
 } // namespace engineConfig
 } // namespace android
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 227ebd8..00fbac4 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -19,6 +19,7 @@
 
 #include "EngineConfig.h"
 #include <policy.h>
+#include <cutils/properties.h>
 #include <media/TypeConverter.h>
 #include <media/convert.h>
 #include <utils/Log.h>
@@ -26,6 +27,7 @@
 #include <libxml/xinclude.h>
 #include <string>
 #include <vector>
+#include <map>
 #include <sstream>
 #include <istream>
 
@@ -506,6 +508,84 @@
     return NO_ERROR;
 }
 
+static constexpr const char *legacyVolumecollectionTag = "volumes";
+static constexpr const char *legacyVolumeTag = "volume";
+
+status_t deserializeLegacyVolume(_xmlDoc *doc, const _xmlNode *cur,
+                                 std::map<std::string, VolumeCurves> &legacyVolumes)
+{
+    std::string streamTypeLiteral = getXmlAttribute(cur, "stream");
+    if (streamTypeLiteral.empty()) {
+        ALOGE("%s: No attribute stream found", __func__);
+        return BAD_VALUE;
+    }
+    std::string deviceCategoryLiteral = getXmlAttribute(cur, "deviceCategory");
+    if (deviceCategoryLiteral.empty()) {
+        ALOGE("%s: No attribute deviceCategory found", __func__);
+        return BAD_VALUE;
+    }
+    std::string referenceName = getXmlAttribute(cur, "ref");
+    const xmlNode *ref = NULL;
+    if (!referenceName.empty()) {
+        getReference(xmlDocGetRootElement(doc), ref, referenceName, legacyVolumecollectionTag);
+        if (ref == NULL) {
+            ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str());
+            return BAD_VALUE;
+        }
+        ALOGV("%s: reference found for %s", __func__, referenceName.c_str());
+    }
+    CurvePoints curvePoints;
+    for (const xmlNode *child = referenceName.empty() ?
+         cur->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) {
+        if (!xmlStrcmp(child->name, (const xmlChar *)VolumeTraits::volumePointTag)) {
+            xmlCharUnique pointXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree);
+            if (pointXml == NULL) {
+                return BAD_VALUE;
+            }
+            ALOGV("%s: %s=%s", __func__, legacyVolumeTag,
+                  reinterpret_cast<const char*>(pointXml.get()));
+            std::vector<int> point;
+            collectionFromString<DefaultTraits<int>>(
+                        reinterpret_cast<const char*>(pointXml.get()), point, ",");
+            if (point.size() != 2) {
+                ALOGE("%s: Invalid %s: %s", __func__, VolumeTraits::volumePointTag,
+                      reinterpret_cast<const char*>(pointXml.get()));
+                return BAD_VALUE;
+            }
+            curvePoints.push_back({point[0], point[1]});
+        }
+    }
+    legacyVolumes[streamTypeLiteral].push_back({ deviceCategoryLiteral, curvePoints });
+    return NO_ERROR;
+}
+
+static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *cur,
+                                                  VolumeGroups &volumeGroups,
+                                                  size_t &nbSkippedElement)
+{
+    std::map<std::string, VolumeCurves> legacyVolumeMap;
+    for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+        if (xmlStrcmp(cur->name, (const xmlChar *)legacyVolumecollectionTag)) {
+            continue;
+        }
+        const xmlNode *child = cur->xmlChildrenNode;
+        for (; child != NULL; child = child->next) {
+            if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) {
+
+                status_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap);
+                if (status != NO_ERROR) {
+                    nbSkippedElement += 1;
+                }
+            }
+        }
+    }
+    for (const auto &volumeMapIter : legacyVolumeMap) {
+        volumeGroups.push_back({ volumeMapIter.first, volumeMapIter.first, 0, 100,
+                                 volumeMapIter.second });
+    }
+    return NO_ERROR;
+}
+
 ParsingResult parse(const char* path) {
     xmlDocPtr doc;
     doc = xmlParseFile(path);
@@ -543,5 +623,60 @@
     return {std::move(config), nbSkippedElements};
 }
 
+android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) {
+    xmlDocPtr doc;
+    doc = xmlParseFile(path);
+    if (doc == NULL) {
+        ALOGE("%s: Could not parse document %s", __FUNCTION__, path);
+        return BAD_VALUE;
+    }
+    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    if (cur == NULL) {
+        ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
+        xmlFreeDoc(doc);
+        return BAD_VALUE;
+    }
+    if (xmlXIncludeProcess(doc) < 0) {
+        ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
+        return BAD_VALUE;
+    }
+    size_t nbSkippedElements = 0;
+    return deserializeLegacyVolumeCollection(doc, cur, volumeGroups, nbSkippedElements);
+}
+
+static const char *kConfigLocationList[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+static const int gApmXmlConfigFilePathMaxLength = 128;
+
+static constexpr const char *apmXmlConfigFileName = "audio_policy_configuration.xml";
+static constexpr const char *apmA2dpOffloadDisabledXmlConfigFileName =
+        "audio_policy_configuration_a2dp_offload_disabled.xml";
+
+android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups) {
+    char audioPolicyXmlConfigFile[gApmXmlConfigFilePathMaxLength];
+    std::vector<const char *> fileNames;
+    status_t ret;
+
+    if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false) &&
+            property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
+        // A2DP offload supported but disabled: try to use special XML file
+        fileNames.push_back(apmA2dpOffloadDisabledXmlConfigFileName);
+    }
+    fileNames.push_back(apmXmlConfigFileName);
+
+    for (const char* fileName : fileNames) {
+        for (int i = 0; i < kConfigLocationListSize; i++) {
+            snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
+                     "%s/%s", kConfigLocationList[i], fileName);
+            ret = parseLegacyVolumeFile(audioPolicyXmlConfigFile, volumeGroups);
+            if (ret == NO_ERROR) {
+                return ret;
+            }
+        }
+    }
+    return BAD_VALUE;
+}
+
 } // namespace engineConfig
 } // namespace android