Audio V4: Move common test code in common folder

The previous patch made the test independent of the HAL version
As a result, move them in the version common folder.

Note that this patch is separated from the previous patch to ease
review.

Bug: 38184704
Test: compile
Change-Id: I98a46eb0b88ea786656200ab613afd2d36ed222d
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/audio/common/all-versions/test/OWNERS b/audio/common/all-versions/test/OWNERS
new file mode 100644
index 0000000..6a26ae7
--- /dev/null
+++ b/audio/common/all-versions/test/OWNERS
@@ -0,0 +1,2 @@
+yim@google.com
+zhuoyao@google.com
diff --git a/audio/common/all-versions/test/utility/Android.bp b/audio/common/all-versions/test/utility/Android.bp
new file mode 100644
index 0000000..b796acc
--- /dev/null
+++ b/audio/common/all-versions/test/utility/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_library_static {
+    name: "android.hardware.audio.common.test.utility",
+    defaults : ["hidl_defaults"],
+    srcs: ["src/ValidateXml.cpp"],
+    cflags: [
+        "-O0",
+        "-g",
+        "-Wextra",
+    ],
+    local_include_dirs: ["include/utility"],
+    export_include_dirs: ["include"],
+    shared_libs: ["libxml2", "liblog"],
+    static_libs: ["libgtest"],
+    export_static_lib_headers: ["libgtest"],
+}
+
diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
new file mode 100644
index 0000000..11e1c24
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
+
+#include <algorithm>
+#include <initializer_list>
+
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+namespace detail {
+
+// This is a detail namespace, thus it is OK to import a class as nobody else is
+// allowed to use it
+using ::android::hardware::Return;
+
+template <class T>
+inline ::testing::AssertionResult assertIsOk(const char* expr, const Return<T>& ret) {
+    return ::testing::AssertionResult(ret.isOk())
+           << "Expected: " << expr << "\n to be an OK Return but it is not: " << ret.description();
+}
+
+// Call continuation if the provided result isOk
+template <class T, class Continuation>
+inline ::testing::AssertionResult continueIfIsOk(const char* expr, const Return<T>& ret,
+                                                 Continuation continuation) {
+    auto isOkStatus = assertIsOk(expr, ret);
+    return !isOkStatus ? isOkStatus : continuation();
+}
+
+// Expect two equal Results
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               Result expected, Result result) {
+    return ::testing::AssertionResult(expected == result)
+           << "Value of: " << r_expr << "\n  Actual: " << ::testing::PrintToString(result)
+           << "\nExpected: " << e_expr << "\nWhich is: " << ::testing::PrintToString(expected);
+}
+
+// Expect two equal Results one being wrapped in an OK Return
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               Result expected, const Return<Result>& ret) {
+    return continueIfIsOk(r_expr, ret,
+                          [&] { return assertResult(e_expr, r_expr, expected, Result{ret}); });
+}
+
+// Expect a Result to be part of a list of Results
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               const std::initializer_list<Result>& expected,
+                                               Result result) {
+    if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
+        return ::testing::AssertionSuccess();  // result is in expected
+    }
+    return ::testing::AssertionFailure()
+           << "Value of: " << r_expr << "\n  Actual: " << ::testing::PrintToString(result)
+           << "\nExpected one of: " << e_expr
+           << "\n       Which is: " << ::testing::PrintToString(expected);
+}
+
+// Expect a Result wrapped in an OK Return to be part of a list of Results
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               const std::initializer_list<Result>& expected,
+                                               const Return<Result>& ret) {
+    return continueIfIsOk(r_expr, ret,
+                          [&] { return assertResult(e_expr, r_expr, expected, Result{ret}); });
+}
+
+inline ::testing::AssertionResult assertOk(const char* expr, const Return<void>& ret) {
+    return assertIsOk(expr, ret);
+}
+
+template <class Result>
+inline ::testing::AssertionResult assertOk(const char* expr, Result result) {
+    return ::testing::AssertionResult(result == Result::OK)
+           << "Expected success: " << expr << "\nActual: " << ::testing::PrintToString(result);
+}
+
+template <class Result>
+inline ::testing::AssertionResult assertOk(const char* expr, const Return<Result>& ret) {
+    return continueIfIsOk(expr, ret, [&] { return assertOk(expr, Result{ret}); });
+}
+}  // namespace detail
+
+#define ASSERT_IS_OK(ret) ASSERT_PRED_FORMAT1(detail::assertIsOk, ret)
+#define EXPECT_IS_OK(ret) EXPECT_PRED_FORMAT1(detail::assertIsOk, ret)
+
+// Test anything provided is and contains only OK
+#define ASSERT_OK(ret) ASSERT_PRED_FORMAT1(detail::assertOk, ret)
+#define EXPECT_OK(ret) EXPECT_PRED_FORMAT1(detail::assertOk, ret)
+
+#define ASSERT_RESULT(expected, ret) ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
+#define EXPECT_RESULT(expected, ret) EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
diff --git a/audio/common/all-versions/test/utility/include/utility/Documentation.h b/audio/common/all-versions/test/utility/include/utility/Documentation.h
new file mode 100644
index 0000000..e10cf79
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/Documentation.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+namespace doc {
+namespace detail {
+const char* getTestName() {
+    return ::testing::UnitTest::GetInstance()->current_test_info()->name();
+}
+}  // namespace detail
+
+/** Document the current test case.
+ * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test
+ * will output:
+ *   <testcase name="debugDump" status="run" time="6"
+ *             classname="AudioPrimaryHidlTest"
+               description="Dump the state of the hal." />
+ * see
+ https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information
+ */
+void test(const std::string& testCaseDocumentation) {
+    ::testing::Test::RecordProperty("description", testCaseDocumentation);
+}
+
+/** Document why a test was not fully run. Usually due to an optional feature
+ * not implemented. */
+void partialTest(const std::string& reason) {
+    LOG(INFO) << "Test " << detail::getTestName() << " partially run: " << reason;
+    ::testing::Test::RecordProperty("partialyRunTest", reason);
+}
+
+/** Add a note to the test. */
+void note(const std::string& note) {
+    LOG(INFO) << "Test " << detail::getTestName() << " noted: " << note;
+    ::testing::Test::RecordProperty("note", note);
+}
+}  // namespace doc
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
new file mode 100644
index 0000000..81d92c2
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
+
+#include <functional>
+#include <list>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+/** Register callback for static object destruction
+ * Avoid destroying static objects after main return.
+ * Post main return destruction leads to incorrect gtest timing measurements as
+ * well as harder debuging if anything goes wrong during destruction. */
+class Environment : public ::testing::Environment {
+   public:
+    using TearDownFunc = std::function<void()>;
+    void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_back(std::move(tearDown)); }
+
+   private:
+    void TearDown() override {
+        // Call the tear downs in reverse order of insertion
+        for (auto& tearDown : tearDowns) {
+            tearDown();
+        }
+    }
+    std::list<TearDownFunc> tearDowns;
+};
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
new file mode 100644
index 0000000..88a67e0
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef AUDIO_HAL_VERSION
+#error "AUDIO_HAL_VERSION must be set before including this file."
+#endif
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
+
+#include <iosfwd>
+#include <utility>
+
+/** @file Use HIDL generated toString methods to pretty print gtest errors
+ *        Unfortunately Gtest does not offer a template to specialize, only
+ *        overloading PrintTo.
+ *  @note that this overload can NOT be template because
+ *        the fallback is already template, resulting in ambiguity.
+ *  @note that the overload MUST be in the exact namespace
+ *        the type is declared in, as per the ADL rules.
+ */
+
+namespace android {
+namespace hardware {
+namespace audio {
+
+#define DEFINE_GTEST_PRINT_TO(T) \
+    inline void PrintTo(const T& val, ::std::ostream* os) { *os << toString(val); }
+
+namespace AUDIO_HAL_VERSION {
+DEFINE_GTEST_PRINT_TO(Result)
+}  // namespace AUDIO_HAL_VERSION
+
+namespace common {
+namespace AUDIO_HAL_VERSION {
+DEFINE_GTEST_PRINT_TO(AudioConfig)
+DEFINE_GTEST_PRINT_TO(AudioDevice)
+DEFINE_GTEST_PRINT_TO(AudioChannelMask)
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace common
+
+#undef DEFINE_GTEST_PRINT_TO
+
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
diff --git a/audio/common/all-versions/test/utility/include/utility/ReturnIn.h b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
new file mode 100644
index 0000000..2b92a21
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
+
+#include <tuple>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+namespace detail {
+// Helper class to generate the HIDL synchronous callback
+template <class... ResultStore>
+class ReturnIn {
+   public:
+    // Provide to the constructor the variables where the output parameters must be copied
+    // TODO: take pointers to match google output parameter style ?
+    ReturnIn(ResultStore&... ts) : results(ts...) {}
+    // Synchronous callback
+    template <class... Results>
+    void operator()(Results&&... results) {
+        set(std::forward<Results>(results)...);
+    }
+
+   private:
+    // Recursively set all output parameters
+    template <class Head, class... Tail>
+    void set(Head&& head, Tail&&... tail) {
+        std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results) = std::forward<Head>(head);
+        set(tail...);
+    }
+    // Trivial case
+    void set() {}
+
+    // All variables to set are stored here
+    std::tuple<ResultStore&...> results;
+};
+}  // namespace detail
+
+// Generate the HIDL synchronous callback with a copy policy
+// Input: the variables (lvalue reference) where to save the return values
+// Output: the callback to provide to a HIDL call with a synchronous callback
+// The output parameters *will be copied* do not use this function if you have
+// a zero copy policy
+template <class... ResultStore>
+detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) {
+    return {ts...};
+}
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
diff --git a/audio/common/all-versions/test/utility/include/utility/ValidateXml.h b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h
new file mode 100644
index 0000000..95080d1
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+/** Validate the provided XmlFile with the provided xsdFile.
+ * Intended to use with ASSERT_PRED_FORMAT2 as such:
+ *   ASSERT_PRED_FORMAT2(validateXml, pathToXml, pathToXsd);
+ * See ASSERT_VALID_XML for a helper macro.
+ */
+::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
+                                       const char* xmlFilePath, const char* xsdFilePath);
+
+/** Helper gtest ASSERT to test XML validity against an XSD. */
+#define ASSERT_VALID_XML(xmlFilePath, xsdFilePath)                                      \
+    ASSERT_PRED_FORMAT2(::android::hardware::audio::common::test::utility::validateXml, \
+                        xmlFilePath, xsdFilePath)
+
+/** Helper gtest EXPECT to test XML validity against an XSD. */
+#define EXPECT_VALID_XML(xmlFilePath, xsdFilePath)                                      \
+    EXPECT_PRED_FORMAT2(::android::hardware::audio::common::test::utility::validateXml, \
+                        xmlFilePath, xsdFilePath)
+
+/** Validate an XML according to an xsd.
+ * The XML file must be in at least one of the provided locations.
+ * If multiple are found, all are validated.
+ */
+::testing::AssertionResult validateXmlMultipleLocations(
+    const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr,
+    const char* xmlFileName, std::vector<const char*> xmlFileLocations, const char* xsdFilePath);
+
+/** ASSERT that an XML is valid according to an xsd.
+ * The XML file must be in at least one of the provided locations.
+ * If multiple are found, all are validated.
+ */
+#define ASSERT_ONE_VALID_XML_MULTIPLE_LOCATIONS(xmlFileName, xmlFileLocations, xsdFilePath) \
+    ASSERT_PRED_FORMAT3(                                                                    \
+        ::android::hardware::audio::common::test::utility::validateXmlMultipleLocations,    \
+        xmlFileName, xmlFileLocations, xsdFilePath)
+
+/** EXPECT an XML to be valid according to an xsd.
+ * The XML file must be in at least one of the provided locations.
+ * If multiple are found, all are validated.
+ */
+#define EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(xmlFileName, xmlFileLocations, xsdFilePath) \
+    EXPECT_PRED_FORMAT3(                                                                    \
+        ::android::hardware::audio::common::test::utility::validateXmlMultipleLocations,    \
+        xmlFileName, xmlFileLocations, xsdFilePath)
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
new file mode 100644
index 0000000..5030af5
--- /dev/null
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017 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 "ValidateAudioConfig"
+#include <utils/Log.h>
+
+#include <numeric>
+
+#define LIBXML_SCHEMAS_ENABLED
+#include <libxml/xmlschemastypes.h>
+#define LIBXML_XINCLUDE_ENABLED
+#include <libxml/xinclude.h>
+
+#include <memory>
+#include <string>
+
+#include "ValidateXml.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+/** Map libxml2 structures to their corresponding deleters. */
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlSchema> = xmlSchemaFree;
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+template <>
+constexpr auto xmlDeleter<xmlSchemaParserCtxt> = xmlSchemaFreeParserCtxt;
+template <>
+constexpr auto xmlDeleter<xmlSchemaValidCtxt> = xmlSchemaFreeValidCtxt;
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T* t) {
+    // Wrap deleter in lambda to enable empty base optimization
+    auto deleter = [](T* t) { xmlDeleter<T>(t); };
+    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
+
+/** Class that handles libxml2 initialization and cleanup. NOT THREAD SAFE*/
+struct Libxml2Global {
+    Libxml2Global() {
+        xmlLineNumbersDefault(1);  // Better error message
+        xmlSetGenericErrorFunc(this, errorCb);
+    }
+    ~Libxml2Global() {
+        // TODO: check if all those cleanup are needed
+        xmlSetGenericErrorFunc(nullptr, nullptr);
+        xmlSchemaCleanupTypes();
+        xmlCleanupParser();
+        xmlCleanupThreads();
+    }
+
+    const std::string& getErrors() { return errors; }
+
+   private:
+    static void errorCb(void* ctxt, const char* msg, ...) {
+        auto* self = static_cast<Libxml2Global*>(ctxt);
+        va_list args;
+        va_start(args, msg);
+
+        char* formatedMsg;
+        if (vasprintf(&formatedMsg, msg, args) >= 0) {
+            LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", formatedMsg);
+            self->errors += "Error: ";
+            self->errors += formatedMsg;
+        }
+        free(formatedMsg);
+
+        va_end(args);
+    }
+    std::string errors;
+};
+
+::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
+                                       const char* xmlFilePath, const char* xsdFilePath) {
+    Libxml2Global libxml2;
+
+    auto context = [&]() {
+        return std::string() + "  While validating: " + xmlFilePathExpr +
+               "\n          Which is: " + xmlFilePath + "\nAgainst the schema: " + xsdFilePathExpr +
+               "\n          Which is: " + xsdFilePath + "\nLibxml2 errors:\n" + libxml2.getErrors();
+    };
+
+    auto schemaParserCtxt = make_xmlUnique(xmlSchemaNewParserCtxt(xsdFilePath));
+    auto schema = make_xmlUnique(xmlSchemaParse(schemaParserCtxt.get()));
+    if (schema == nullptr) {
+        return ::testing::AssertionFailure() << "Failed to parse schema (xsd)\n" << context();
+    }
+
+    auto doc = make_xmlUnique(xmlReadFile(xmlFilePath, nullptr, 0));
+    if (doc == nullptr) {
+        return ::testing::AssertionFailure() << "Failed to parse xml\n" << context();
+    }
+
+    if (xmlXIncludeProcess(doc.get()) == -1) {
+        return ::testing::AssertionFailure() << "Failed to resolve xincludes in xml\n" << context();
+    }
+
+    auto schemaCtxt = make_xmlUnique(xmlSchemaNewValidCtxt(schema.get()));
+    int ret = xmlSchemaValidateDoc(schemaCtxt.get(), doc.get());
+    if (ret > 0) {
+        return ::testing::AssertionFailure() << "XML is not valid according to the xsd\n"
+                                             << context();
+    }
+    if (ret < 0) {
+        return ::testing::AssertionFailure() << "Internal or API error\n" << context();
+    }
+
+    return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult validateXmlMultipleLocations(
+    const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr,
+    const char* xmlFileName, std::vector<const char*> xmlFileLocations, const char* xsdFilePath) {
+    using namespace std::string_literals;
+
+    std::vector<std::string> errors;
+    std::vector<std::string> foundFiles;
+
+    for (const char* location : xmlFileLocations) {
+        std::string xmlFilePath = location + "/"s + xmlFileName;
+        if (access(xmlFilePath.c_str(), F_OK) != 0) {
+            // If the file does not exist ignore this location and fallback on the next one
+            continue;
+        }
+        foundFiles.push_back("    " + xmlFilePath + '\n');
+        auto result = validateXml("xmlFilePath", xsdFilePathExpr, xmlFilePath.c_str(), xsdFilePath);
+        if (!result) {
+            errors.push_back(result.message());
+        }
+    }
+
+    if (foundFiles.empty()) {
+        errors.push_back("No xml file found in provided locations.\n");
+    }
+
+    return ::testing::AssertionResult(errors.empty())
+           << errors.size() << " error" << (errors.size() == 1 ? " " : "s ")
+           << std::accumulate(begin(errors), end(errors), "occurred during xml validation:\n"s)
+           << "     While validating all: " << xmlFileNameExpr
+           << "\n                 Which is: " << xmlFileName
+           << "\n In the following folders: " << xmlFileLocationsExpr
+           << "\n                 Which is: " << ::testing::PrintToString(xmlFileLocations);
+}
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android