VintfObject::verify() will fetch data from device

- If no info is provided then all data is fetched from device.
- Add hook to mock retrieving files from device.
- Add test.
- Print more detailed messages on AVB failures.

Test: Ran vintf_object_test and libvintf_test
Bug: 37863689
Bug: 36814984
Change-Id: Ia33f4e2e73c863bc0f8f68f5ed61c30df8eff53d
Merged-In: Ia33f4e2e73c863bc0f8f68f5ed61c30df8eff53d
diff --git a/Android.bp b/Android.bp
index 728efc0..47b9863 100644
--- a/Android.bp
+++ b/Android.bp
@@ -46,6 +46,7 @@
         "MatrixKernel.cpp",
         "TransportArch.cpp",
         "VintfObject.cpp",
+        "utils.cpp",
     ],
 
     target: {
@@ -89,3 +90,43 @@
         "assemble_vintf.cpp"
     ],
 }
+
+cc_library {
+    name: "libvintftest",
+    host_supported: true,
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libselinux",
+        "libtinyxml2",
+    ],
+    export_include_dirs: ["include/vintf", "include", "test", "."],
+    local_include_dirs: ["include/vintf", "test", "."],
+
+    srcs: [
+        "parse_string.cpp",
+        "parse_xml.cpp",
+        "CompatibilityMatrix.cpp",
+        "HalManifest.cpp",
+        "KernelConfigTypedValue.cpp",
+        "RuntimeInfo.cpp",
+        "ManifestHal.cpp",
+        "MatrixHal.cpp",
+        "MatrixKernel.cpp",
+        "TransportArch.cpp",
+        "VintfObject.cpp",
+        "test/RuntimeInfo-fake.cpp",
+        "test/utils-fake.cpp",
+    ],
+
+    target: {
+        android: {
+            shared_libs: [
+                "libcutils",
+                "libutils",
+                "libz"
+            ],
+            cflags: ["-DLIBVINTF_TARGET"],
+        },
+    }
+}
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 1ef6edc..342f032 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -176,9 +176,9 @@
     const RuntimeInfo *runtimeInfo;
 };
 
-// Parse all information from package;
-// Get missing information from the device;
-// Do compatibility check.
+// Checks given compatibility info against info on the device. If no
+// compatability info is given then the device info will be checked against
+// itself.
 int32_t checkCompatibility(const std::vector<std::string> &xmls, bool mount,
         std::function<status_t(void)> mountSystem,
         std::function<status_t(void)> umountSystem,
@@ -194,11 +194,6 @@
     PackageInfo pkg; // All information from package.
     UpdatedInfo updated; // All files and runtime info after the update.
 
-    if (xmls.empty()) {
-        ADD_MESSAGE("nothing to update");
-        return BAD_VALUE;
-    }
-
     // parse all information from package
     for (const auto &xml : xmls) {
         parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
@@ -232,10 +227,18 @@
             std::bind(GetDeviceHalManifest, true /* skipCache */))) != OK) {
         return status;
     }
+    if ((status = getMissing(
+             pkg.fwk.matrix.get(), mount, mountVendor, umountVendor, &updated.fwk.matrix,
+             std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
+        OK) {
+        return status;
+    }
+    if ((status = getMissing(
+             pkg.dev.matrix.get(), mount, mountSystem, umountSystem, &updated.dev.matrix,
+             std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
+        return status;
+    }
     updated.runtimeInfo = GetRuntimeInfo(true /* skipCache */);
-    // TODO(b/37321309) get matrices from the device as well.
-    updated.fwk.matrix = pkg.fwk.matrix.get();
-    updated.dev.matrix = pkg.dev.matrix.get();
 
     // null checks for files and runtime info after the update
     // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
diff --git a/test/Android.bp b/test/Android.bp
index 2895ebc..f6053ea 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -30,3 +30,26 @@
         "-g",
     ],
 }
+
+cc_test {
+    name: "vintf_object_test",
+    host_supported: true,
+    native_coverage: true,
+    srcs: [
+        "vintf_object_tests.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libvintftest",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/test/AndroidTest.xml b/test/AndroidTest.xml
new file mode 100644
index 0000000..41f408a
--- /dev/null
+++ b/test/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for vintf_object_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="vintf_object_test->/data/local/tmp/vintf_object_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vintf_object_test" />
+    </test>
+</configuration>
diff --git a/test/RuntimeInfo-fake.cpp b/test/RuntimeInfo-fake.cpp
new file mode 100644
index 0000000..4fc568a
--- /dev/null
+++ b/test/RuntimeInfo-fake.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include "RuntimeInfo.h"
+
+namespace android {
+namespace vintf {
+
+// Fake implementation used for testing.
+status_t RuntimeInfo::fetchAllInformation() {
+    mOsName = "Linux";
+    mNodeName = "localhost";
+    mOsRelease = "3.18.31-g936f9a479d0f";
+    mKernelVersion = {3, 18, 31};
+    mOsVersion = "#4 SMP PREEMPT Wed Feb 1 18:10:52 PST 2017";
+    mHardwareId = "aarch64";
+    mKernelSepolicyVersion = 30;
+    mKernelConfigs = {{"CONFIG_64BIT", "y"},
+                      {"CONFIG_ANDROID_BINDER_DEVICES", "\"binder,hwbinder\""},
+                      {"CONFIG_ARCH_MMAP_RND_BITS", "24"},
+                      {"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", "\"\""},
+                      {"CONFIG_ILLEGAL_POINTER_VALUE", "0xdead000000000000"}};
+
+    return OK;
+}
+
+}  // namespace vintf
+}  // namespace android
diff --git a/test/utils-fake.cpp b/test/utils-fake.cpp
new file mode 100644
index 0000000..586017e
--- /dev/null
+++ b/test/utils-fake.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+
+namespace android {
+namespace vintf {
+namespace details {
+
+// Do not create the MockFileFetcher here as InitGoogleMock must be called
+// first.
+FileFetcher* gFetcher = nullptr;
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/test/utils-fake.h b/test/utils-fake.h
new file mode 100644
index 0000000..d0c687e
--- /dev/null
+++ b/test/utils-fake.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+
+#include "utils.h"
+
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::Invoke;
+
+namespace android {
+namespace vintf {
+namespace details {
+
+class MockFileFetcher : public FileFetcher {
+   public:
+    MockFileFetcher() {
+        // By default call through to the original.
+        ON_CALL(*this, fetch(_, _)).WillByDefault(Invoke(&real_, &FileFetcher::fetch));
+    }
+
+    MOCK_METHOD2(fetch, status_t(const std::string& path, std::string& fetched));
+
+   private:
+    FileFetcher real_;
+};
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
new file mode 100644
index 0000000..27b3f0a
--- /dev/null
+++ b/test/vintf_object_tests.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "utils-fake.h"
+#include "vintf/VintfObject.h"
+
+using namespace ::testing;
+using namespace ::android::vintf;
+using namespace ::android::vintf::details;
+
+//
+// Set of Xml1 metadata compatible with each other.
+//
+
+const std::string systemMatrixXml1 =
+    "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\" optional=\"false\">\n"
+    "        <name>android.hardware.camera</name>\n"
+    "        <version>2.0-5</version>\n"
+    "        <version>3.4-16</version>\n"
+    "    </hal>\n"
+    "    <hal format=\"hidl\" optional=\"false\">\n"
+    "        <name>android.hardware.nfc</name>\n"
+    "        <version>1.0</version>\n"
+    "        <version>2.0</version>\n"
+    "    </hal>\n"
+    "    <hal format=\"hidl\" optional=\"true\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <version>1.0</version>\n"
+    "    </hal>\n"
+    "    <kernel version=\"3.18.31\"></kernel>\n"
+    "    <sepolicy>\n"
+    "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+    "        <sepolicy-version>25.5</sepolicy-version>\n"
+    "        <sepolicy-version>26.0-3</sepolicy-version>\n"
+    "    </sepolicy>\n"
+    "    <avb>\n"
+    "        <vbmeta-version>0.0</vbmeta-version>\n"
+    "    </avb>\n"
+    "</compatibility-matrix>\n";
+
+const std::string vendorManifestXml1 =
+    "<manifest version=\"1.0\" type=\"device\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.camera</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <version>3.5</version>\n"
+    "        <interface>\n"
+    "            <name>IBetterCamera</name>\n"
+    "            <instance>camera</instance>\n"
+    "        </interface>\n"
+    "        <interface>\n"
+    "            <name>ICamera</name>\n"
+    "            <instance>default</instance>\n"
+    "            <instance>legacy/0</instance>\n"
+    "        </interface>\n"
+    "    </hal>\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.nfc</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <version>1.0</version>\n"
+    "        <version>2.0</version>\n"
+    "        <interface>\n"
+    "            <name>INfc</name>\n"
+    "            <instance>nfc_nci</instance>\n"
+    "        </interface>\n"
+    "    </hal>\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.nfc</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <version>2.0</version>\n"
+    "        <interface>\n"
+    "            <name>INfc</name>\n"
+    "            <instance>default</instance>\n"
+    "        </interface>\n"
+    "    </hal>\n"
+    "    <sepolicy>\n"
+    "        <version>25.5</version>\n"
+    "    </sepolicy>\n"
+    "</manifest>\n";
+
+const std::string systemManifestXml1 =
+    "<manifest version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hidl.manager</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <version>1.0</version>\n"
+    "        <interface>\n"
+    "            <name>IServiceManager</name>\n"
+    "            <instance>default</instance>\n"
+    "        </interface>\n"
+    "    </hal>\n"
+    "    <vndk>\n"
+    "        <version>25.0.5</version>\n"
+    "        <library>libbase.so</library>\n"
+    "        <library>libjpeg.so</library>\n"
+    "    </vndk>\n"
+    "</manifest>\n";
+
+const std::string vendorMatrixXml1 =
+    "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
+    "    <hal format=\"hidl\" optional=\"false\">\n"
+    "        <name>android.hidl.manager</name>\n"
+    "        <version>1.0</version>\n"
+    "    </hal>\n"
+    "    <vndk>\n"
+    "        <version>25.0.1-5</version>\n"
+    "        <library>libbase.so</library>\n"
+    "        <library>libjpeg.so</library>\n"
+    "    </vndk>\n"
+    "</compatibility-matrix>\n";
+
+//
+// Set of Xml2 metadata compatible with each other.
+//
+
+const std::string systemMatrixXml2 =
+    "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <version>1.0</version>\n"
+    "    </hal>\n"
+    "    <kernel version=\"3.18.31\"></kernel>\n"
+    "    <sepolicy>\n"
+    "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+    "        <sepolicy-version>25.5</sepolicy-version>\n"
+    "        <sepolicy-version>26.0-3</sepolicy-version>\n"
+    "    </sepolicy>\n"
+    "    <avb>\n"
+    "        <vbmeta-version>0.0</vbmeta-version>\n"
+    "    </avb>\n"
+    "</compatibility-matrix>\n";
+
+const std::string vendorManifestXml2 =
+    "<manifest version=\"1.0\" type=\"device\">"
+    "    <hal>"
+    "        <name>android.hardware.foo</name>"
+    "        <transport>hwbinder</transport>"
+    "        <version>1.0</version>"
+    "    </hal>"
+    "    <sepolicy>\n"
+    "        <version>25.5</version>\n"
+    "    </sepolicy>\n"
+    "</manifest>";
+
+// Setup the MockFileFetcher used by the fetchAllInformation template
+// so it returns the given metadata info instead of fetching from device.
+void setupMockFetcher(const std::string& vendorManifestXml, const std::string& systemMatrixXml,
+                      const std::string& systemManifestXml, const std::string& vendorMatrixXml) {
+    MockFileFetcher* fetcher = static_cast<MockFileFetcher*>(gFetcher);
+
+    ON_CALL(*fetcher, fetch(StrEq("/vendor/manifest.xml"), _))
+        .WillByDefault(Invoke([vendorManifestXml](const std::string& path, std::string& fetched) {
+            (void)path;
+            fetched = vendorManifestXml;
+            return 0;
+        }));
+    ON_CALL(*fetcher, fetch(StrEq("/system/manifest.xml"), _))
+        .WillByDefault(Invoke([systemManifestXml](const std::string& path, std::string& fetched) {
+            (void)path;
+            fetched = systemManifestXml;
+            return 0;
+        }));
+    ON_CALL(*fetcher, fetch(StrEq("/vendor/compatibility_matrix.xml"), _))
+        .WillByDefault(Invoke([vendorMatrixXml](const std::string& path, std::string& fetched) {
+            (void)path;
+            fetched = vendorMatrixXml;
+            return 0;
+        }));
+    ON_CALL(*fetcher, fetch(StrEq("/system/compatibility_matrix.xml"), _))
+        .WillByDefault(Invoke([systemMatrixXml](const std::string& path, std::string& fetched) {
+            (void)path;
+            fetched = systemMatrixXml;
+            return 0;
+        }));
+}
+
+// Test fixture that provides compatible metadata from the mock device.
+class VintfObjectCompatibleTest : public testing::Test {
+   protected:
+    virtual void SetUp() {
+        setupMockFetcher(vendorManifestXml1, systemMatrixXml1, systemManifestXml1,
+                         vendorMatrixXml1);
+    }
+};
+
+// Tests that local info is checked.
+TEST_F(VintfObjectCompatibleTest, TestDeviceCompatibility) {
+    std::string error;
+    std::vector<std::string> packageInfo;
+
+    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+
+    ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
+    // Check that nothing was ignored.
+    ASSERT_STREQ(error.c_str(), "");
+}
+
+// Tests that input info is checked against device and passes.
+TEST_F(VintfObjectCompatibleTest, TestInputVsDeviceSuccess) {
+    std::string error;
+    std::vector<std::string> packageInfo = {systemMatrixXml1};
+
+    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+
+    ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
+    ASSERT_STREQ(error.c_str(), "");
+}
+
+// Tests that input info is checked against device and fails.
+TEST_F(VintfObjectCompatibleTest, TestInputVsDeviceFail) {
+    std::string error;
+    std::vector<std::string> packageInfo = {systemMatrixXml2};
+
+    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+
+    ASSERT_EQ(result, 1) << "Should have failed:" << error.c_str();
+    ASSERT_STREQ(error.c_str(),
+                 "Device manifest and framework compatibility matrix are incompatible: HALs "
+                 "incompatible. android.hardware.foo");
+}
+
+// Tests that complementary info is checked against itself.
+TEST_F(VintfObjectCompatibleTest, TestInputSuccess) {
+    std::string error;
+    std::vector<std::string> packageInfo = {systemMatrixXml2, vendorManifestXml2};
+
+    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+
+    ASSERT_EQ(result, 0) << "Failed message:" << error.c_str();
+    ASSERT_STREQ(error.c_str(), "");
+}
+
+// Test fixture that provides incompatible metadata from the mock device.
+class VintfObjectIncompatibleTest : public testing::Test {
+   protected:
+    virtual void SetUp() {
+        setupMockFetcher(vendorManifestXml1, systemMatrixXml2, systemManifestXml1,
+                         vendorMatrixXml1);
+    }
+};
+
+// Fetch all metadata from device and ensure that it fails.
+TEST_F(VintfObjectIncompatibleTest, TestDeviceCompatibility) {
+    std::string error;
+    std::vector<std::string> packageInfo;
+
+    MockFileFetcher* fetcher = static_cast<MockFileFetcher*>(gFetcher);
+    EXPECT_CALL(*fetcher, fetch(StrEq("/vendor/manifest.xml"), _));
+    EXPECT_CALL(*fetcher, fetch(StrEq("/system/manifest.xml"), _));
+    EXPECT_CALL(*fetcher, fetch(StrEq("/vendor/compatibility_matrix.xml"), _));
+    EXPECT_CALL(*fetcher, fetch(StrEq("/system/compatibility_matrix.xml"), _));
+
+    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+
+    ASSERT_EQ(result, 1) << "Should have failed:" << error.c_str();
+}
+
+// Pass in new metadata that fixes the incompatibility.
+TEST_F(VintfObjectIncompatibleTest, TestInputVsDeviceSuccess) {
+    std::string error;
+    std::vector<std::string> packageInfo = {systemMatrixXml1};
+
+    MockFileFetcher* fetcher = static_cast<MockFileFetcher*>(gFetcher);
+    EXPECT_CALL(*fetcher, fetch(StrEq("/vendor/manifest.xml"), _));
+    EXPECT_CALL(*fetcher, fetch(StrEq("/system/manifest.xml"), _));
+    EXPECT_CALL(*fetcher, fetch(StrEq("/vendor/compatibility_matrix.xml"), _));
+    EXPECT_CALL(*fetcher, fetch(StrEq("/system/compatibility_matrix.xml"), _)).Times(0);
+
+    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+
+    ASSERT_EQ(result, 0) << "Failed message:" << error.c_str();
+    ASSERT_STREQ(error.c_str(), "");
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleMock(&argc, argv);
+
+    NiceMock<MockFileFetcher> fetcher;
+    gFetcher = static_cast<FileFetcher*>(&fetcher);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/utils.cpp b/utils.cpp
new file mode 100644
index 0000000..3c4d2e7
--- /dev/null
+++ b/utils.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+
+namespace android {
+namespace vintf {
+namespace details {
+
+FileFetcher fetcher;
+FileFetcher* gFetcher = &fetcher;
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/utils.h b/utils.h
index 3c06817..2c5f813 100644
--- a/utils.h
+++ b/utils.h
@@ -30,18 +30,48 @@
 namespace vintf {
 namespace details {
 
-template<typename T>
-status_t fetchAllInformation(const std::string &path,
-        const XmlConverter<T> &converter, T *outObject) {
-    std::ifstream in;
-    in.open(path);
-    if (!in.is_open()) {
-        LOG(WARNING) << "Cannot open " << path;
-        return INVALID_OPERATION;
+// Return the file from the given location as a string.
+//
+// This class can be used to create a mock for overriding.
+class FileFetcher {
+   public:
+    virtual ~FileFetcher() {}
+    virtual status_t fetch(const std::string& path, std::string& fetched) {
+        std::ifstream in;
+
+        in.open(path);
+        if (!in.is_open()) {
+            LOG(WARNING) << "Cannot open " << path;
+            return INVALID_OPERATION;
+        }
+
+        std::stringstream ss;
+        ss << in.rdbuf();
+        fetched = ss.str();
+
+        return OK;
     }
-    std::stringstream ss;
-    ss << in.rdbuf();
-    bool success = converter(outObject, ss.str());
+};
+
+extern FileFetcher* gFetcher;
+
+template <typename T>
+status_t fetchAllInformation(const std::string& path, const XmlConverter<T>& converter,
+                             T* outObject) {
+    std::string info;
+
+    if (gFetcher == nullptr) {
+        // Should never happen.
+        return NO_INIT;
+    }
+
+    status_t result = gFetcher->fetch(path, info);
+
+    if (result != OK) {
+        return result;
+    }
+
+    bool success = converter(outObject, info);
     if (!success) {
         LOG(ERROR) << "Illformed file: " << path << ": "
                    << converter.lastError();