Cleanup global FileFetcher

This global instance is modifiable everywhere and
is hard to maintain. It also contains references as
out-variables, which is not the standard.

Clean it up by refactoring it into a public (i.e.
not in details namespace) class, FileSystem.

Introduce VintfObject::InitFileSystem that allows
the behavior to be changed before any files are read.

Bug: 37999212
Test: host and target libvintf_test, vintf_object_test

Change-Id: I1c64b31fd37119450be89dfd1d2bfe76a71ccf3d
Merged-In: I1c64b31fd37119450be89dfd1d2bfe76a71ccf3d
diff --git a/Android.bp b/Android.bp
index cb3a4f8..38a3bd2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -32,6 +32,7 @@
         "parse_string.cpp",
         "parse_xml.cpp",
         "CompatibilityMatrix.cpp",
+        "FileSystem.cpp",
         "HalManifest.cpp",
         "HalInterface.cpp",
         "KernelConfigTypedValue.cpp",
@@ -42,12 +43,12 @@
         "MatrixHal.cpp",
         "MatrixInstance.cpp",
         "MatrixKernel.cpp",
+        "PropertyFetcher.cpp",
         "Regex.cpp",
         "SystemSdk.cpp",
         "TransportArch.cpp",
         "VintfObject.cpp",
         "XmlFile.cpp",
-        "utils-common.cpp",
     ],
     shared_libs: [
         "libbase",
diff --git a/FileSystem.cpp b/FileSystem.cpp
new file mode 100644
index 0000000..5b871ee
--- /dev/null
+++ b/FileSystem.cpp
@@ -0,0 +1,104 @@
+
+/*
+ * Copyright (C) 2018 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 <vintf/FileSystem.h>
+
+#include <dirent.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+namespace android {
+namespace vintf {
+namespace details {
+
+static std::mutex sFileSystemMutex;
+static std::unique_ptr<FileSystem> sFileSystem{};
+
+bool initFileSystem(std::unique_ptr<FileSystem>&& value) {
+    std::lock_guard<std::mutex> lock(sFileSystemMutex);
+    if (sFileSystem != nullptr) return false;
+    sFileSystem = std::move(value);
+    return true;
+}
+
+FileSystem& getFileSystem() {
+    std::lock_guard<std::mutex> lock(sFileSystemMutex);
+    if (sFileSystem == nullptr) {
+#ifdef LIBVINTF_TARGET
+        sFileSystem = std::make_unique<details::FileSystemImpl>();
+#else
+        sFileSystem = std::make_unique<details::FileSystemNoOp>();
+#endif
+    }
+    return *sFileSystem;
+}
+
+status_t FileSystemImpl::fetch(const std::string& path, std::string* fetched,
+                               std::string* error) const {
+    std::ifstream in;
+
+    errno = 0;
+    in.open(path);
+    if (!in || errno != 0) {
+        if (error) {
+            *error = "Cannot open " + path + ": " + strerror(errno);
+        }
+        return -errno;
+    }
+
+    std::stringstream ss;
+    ss << in.rdbuf();
+    *fetched = ss.str();
+
+    return -errno;
+}
+
+status_t FileSystemImpl::listFiles(const std::string& path, std::vector<std::string>* out,
+                                   std::string* error) const {
+    errno = 0;
+    DIR* dirp = opendir(path.c_str());
+    if (!dirp || errno != 0) {
+        if (error) {
+            *error = "Cannot open " + path + ": " + strerror(errno);
+        }
+        return -errno;
+    }
+
+    std::unique_ptr<DIR, decltype(&closedir)> dir(dirp, closedir);
+    dirent* dp;
+    while ((dp = readdir(dir.get())) != nullptr) {
+        if (dp->d_type != DT_DIR) {
+            out->push_back(dp->d_name);
+        }
+    }
+    return -errno;
+}
+
+status_t FileSystemNoOp::fetch(const std::string&, std::string*, std::string*) const {
+    return NAME_NOT_FOUND;
+}
+
+status_t FileSystemNoOp::listFiles(const std::string&, std::vector<std::string>*,
+                                   std::string*) const {
+    return NAME_NOT_FOUND;
+}
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/utils-common.cpp b/PropertyFetcher.cpp
similarity index 95%
rename from utils-common.cpp
rename to PropertyFetcher.cpp
index 3e7e736..28caee3 100644
--- a/utils-common.cpp
+++ b/PropertyFetcher.cpp
@@ -17,8 +17,6 @@
 
 #include "utils.h"
 
-// Default implementations for classes defined in utils.h
-
 namespace android {
 namespace vintf {
 namespace details {
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 38ef0df..0e757ca 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -165,7 +165,7 @@
 status_t VintfObject::AddDirectoryManifests(const std::string& directory, HalManifest* manifest,
                                             std::string* error) {
     std::vector<std::string> fileNames;
-    status_t err = details::gFetcher->listFiles(directory, &fileNames, error);
+    status_t err = details::getFileSystem().listFiles(directory, &fileNames, error);
     // if the directory isn't there, that's okay
     if (err == NAME_NOT_FOUND) return OK;
     if (err != OK) return err;
@@ -304,7 +304,7 @@
     std::vector<std::string> fileNames;
     std::vector<Named<CompatibilityMatrix>> results;
 
-    if (details::gFetcher->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
+    if (details::getFileSystem().listFiles(kSystemVintfDir, &fileNames, error) != OK) {
         return {};
     }
     for (const std::string& fileName : fileNames) {
@@ -312,7 +312,7 @@
 
         std::string content;
         std::string fetchError;
-        status_t status = details::gFetcher->fetch(path, content, &fetchError);
+        status_t status = details::getFileSystem().fetch(path, &content, &fetchError);
         if (status != OK) {
             if (error) {
                 *error += "Framework Matrix: Ignore file " + path + ": " + fetchError + "\n";
@@ -753,5 +753,9 @@
     return CheckDeprecation(inManifest, error);
 }
 
+bool VintfObject::InitFileSystem(std::unique_ptr<FileSystem>&& fileSystem) {
+    return details::initFileSystem(std::move(fileSystem));
+}
+
 } // namespace vintf
 } // namespace android
diff --git a/check_vintf.cpp b/check_vintf.cpp
index 6acc311..c85cbe3 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -43,37 +43,33 @@
 // command line arguments
 using Args = std::multimap<Option, std::string>;
 
-class HostFileFetcher : public FileFetcher {
+class HostFileSystem : public FileSystem {
    public:
-    void setRootDir(const std::string& rootdir) {
+    HostFileSystem(const std::string& rootdir) {
         mRootDir = rootdir;
         if (!mRootDir.empty() && mRootDir.back() != '/') {
             mRootDir.push_back('/');
         }
     }
-    virtual status_t fetch(const std::string& path, std::string& fetched, std::string* error) {
-        return HostFileFetcher::fetchInternal(path, fetched, error);
+    status_t fetch(const std::string& path, std::string* fetched,
+                   std::string* error) const override {
+        status_t status = mImpl.fetch(mRootDir + path, fetched, error);
+        std::cerr << "Debug: Fetch '" << mRootDir << path << "': " << toString(status) << std::endl;
+        return status;
     }
-    virtual status_t fetch(const std::string& path, std::string& fetched) {
-        return HostFileFetcher::fetchInternal(path, fetched, nullptr);
-    }
-    virtual status_t listFiles(const std::string& path, std::vector<std::string>* out,
-                               std::string* error) {
-        status_t status = FileFetcher::listFiles(mRootDir + path, out, error);
+    status_t listFiles(const std::string& path, std::vector<std::string>* out,
+                       std::string* error) const override {
+        status_t status = mImpl.listFiles(mRootDir + path, out, error);
         std::cerr << "Debug: List '" << mRootDir << path << "': " << toString(status) << std::endl;
         return status;
     }
 
    private:
-    status_t fetchInternal(const std::string& path, std::string& fetched, std::string* error) {
-        status_t status = FileFetcher::fetchInternal(mRootDir + path, fetched, error);
-        std::cerr << "Debug: Fetch '" << mRootDir << path << "': " << toString(status) << std::endl;
-        return status;
-    }
     static std::string toString(status_t status) {
         return status == OK ? "SUCCESS" : strerror(-status);
     }
     std::string mRootDir;
+    FileSystemImpl mImpl;
 };
 
 class PresetPropertyFetcher : public PropertyFetcher {
@@ -112,9 +108,6 @@
 };
 
 // globals
-static HostFileFetcher hostFileFetcher;
-FileFetcher* gFetcher = &hostFileFetcher;
-
 static PartitionMounter partitionMounter;
 PartitionMounter* gPartitionMounter = &partitionMounter;
 
@@ -131,7 +124,7 @@
 std::unique_ptr<T> readObject(const std::string& path, const XmlConverter<T>& converter) {
     std::string xml;
     std::string error;
-    status_t err = details::gFetcher->fetch(path, xml, &error);
+    status_t err = details::getFileSystem().fetch(path, &xml, &error);
     if (err != OK) {
         std::cerr << "Error: Cannot read '" << path << "' (" << strerror(-err) << "): " << error
                   << std::endl;
@@ -146,6 +139,11 @@
 }
 
 int checkCompatibilityForFiles(const std::string& manifestPath, const std::string& matrixPath) {
+    if (!VintfObject::InitFileSystem(std::make_unique<FileSystemImpl>())) {
+        std::cerr << "Cannot initialize FileSystem object." << std::endl;
+        return NO_INIT;
+    }
+
     auto manifest = readObject(manifestPath, gHalManifestConverter);
     auto matrix = readObject(matrixPath, gCompatibilityMatrixConverter);
     if (manifest == nullptr || matrix == nullptr) {
@@ -242,7 +240,10 @@
 }
 
 int checkAllFiles(const std::string& rootdir, const Properties& props, std::string* error) {
-    hostFileFetcher.setRootDir(rootdir);
+    if (!VintfObject::InitFileSystem(std::make_unique<HostFileSystem>(rootdir))) {
+        std::cerr << "Cannot initialize FileSystem object." << std::endl;
+        return NO_INIT;
+    }
     hostPropertyFetcher.setProperties(props);
 
     return VintfObject::CheckCompatibility({} /* packageInfo */, error, DISABLE_RUNTIME_INFO);
diff --git a/include/vintf/FileSystem.h b/include/vintf/FileSystem.h
new file mode 100644
index 0000000..202557d
--- /dev/null
+++ b/include/vintf/FileSystem.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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_VINTF_FILE_SYSTEM_H
+#define ANDROID_VINTF_FILE_SYSTEM_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/Errors.h>
+#include <vintf/RuntimeInfo.h>
+#include <vintf/parse_xml.h>
+
+namespace android {
+namespace vintf {
+
+// Queries the file system in the correct way. Files can come from
+// an actual file system, a sub-directory, or from ADB, depending on the
+// implementation.
+//
+// This class can be used to create a mock for overriding.
+class FileSystem {
+   public:
+    virtual ~FileSystem(){};
+    // Return NAME_NOT_FOUND if file is not found,
+    //        OK if file is retrieved and written to "fetched".
+    virtual status_t fetch(const std::string& path, std::string* fetched,
+                           std::string* error) const = 0;
+    // Return NAME_NOT_FOUND if directory is not found,
+    //        OK if file names are retrieved and written to out.
+    virtual status_t listFiles(const std::string& path, std::vector<std::string>* out,
+                               std::string* error) const = 0;
+};
+
+namespace details {
+
+// Initialize the global instance.
+__attribute__((warn_unused_result)) bool initFileSystem(std::unique_ptr<FileSystem>&& value);
+
+// Return the instance provided through init(), or a default implementation
+// if init() is not called. The default implementation queries the actual
+// file system on the device and does nothing on host.
+// Once get(), cannot be init()-ed again.
+FileSystem& getFileSystem();
+
+// Class that actually queries the file system.
+class FileSystemImpl : public FileSystem {
+   public:
+    status_t fetch(const std::string&, std::string*, std::string*) const;
+    status_t listFiles(const std::string&, std::vector<std::string>*, std::string*) const;
+};
+
+// Class that does nothing.
+class FileSystemNoOp : public FileSystem {
+   public:
+    status_t fetch(const std::string&, std::string*, std::string*) const;
+    status_t listFiles(const std::string&, std::vector<std::string>*, std::string*) const;
+};
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
+
+#endif
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 38b20b3..875a25a 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -21,6 +21,7 @@
 
 #include "CompatibilityMatrix.h"
 #include "DisabledChecks.h"
+#include "FileSystem.h"
 #include "HalManifest.h"
 #include "Named.h"
 #include "RuntimeInfo.h"
@@ -148,6 +149,14 @@
      */
     static int32_t CheckDeprecation(std::string* error = nullptr);
 
+    // Specify how the file system should be queried.
+    // Can only be initialized before VintfObject is queried, preferably in main().
+    static bool InitFileSystem(std::unique_ptr<FileSystem>&&);
+
+   protected:
+   private:
+    static std::unique_ptr<FileSystem> sInstance;
+
    private:
     static status_t GetCombinedFrameworkMatrix(
         const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out,
diff --git a/test/utils-fake.cpp b/test/utils-fake.cpp
index 38f6ab0..a04ba79 100644
--- a/test/utils-fake.cpp
+++ b/test/utils-fake.cpp
@@ -22,8 +22,6 @@
 
 // Do not create the mock objects here as InitGoogleMock must be called
 // first.
-FileFetcher* gFetcher = nullptr;
-
 PartitionMounter* gPartitionMounter = nullptr;
 
 ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory = nullptr;
diff --git a/test/utils-fake.h b/test/utils-fake.h
index 0253bca..f07ae48 100644
--- a/test/utils-fake.h
+++ b/test/utils-fake.h
@@ -27,28 +27,20 @@
 namespace vintf {
 namespace details {
 
-class MockFileFetcher : public FileFetcher {
+class MockFileSystem : public FileSystem {
    public:
-    MockFileFetcher() {
-        // By default call through to the original.
-        ON_CALL(*this, fetch(_, _)).WillByDefault(Invoke([this](const auto& path, auto& fetched) {
-            return real_.fetchInternal(path, fetched, nullptr);
-        }));
-        ON_CALL(*this, listFiles(_, _, _))
-            .WillByDefault(
-                Invoke([this](const std::string& path, std::vector<std::string>* out,
-                              std::string* error) { return real_.listFiles(path, out, error); }));
+    MockFileSystem() {}
+
+    MOCK_CONST_METHOD2(fetch, status_t(const std::string& path, std::string& fetched));
+    MOCK_CONST_METHOD3(listFiles,
+                       status_t(const std::string&, std::vector<std::string>*, std::string*));
+
+    status_t fetch(const std::string& path, std::string* fetched, std::string*) const override {
+        // Call the mocked function
+        return fetch(path, *fetched);
     }
-
-    MOCK_METHOD2(fetch, status_t(const std::string& path, std::string& fetched));
-    MOCK_METHOD3(listFiles, status_t(const std::string&, std::vector<std::string>*, std::string*));
-
-    status_t fetch(const std::string& path, std::string& fetched, std::string*) override final {
-        return fetch(path, fetched);
-    }
-
    private:
-    FileFetcher real_;
+    FileSystemImpl mImpl;
 };
 
 class MockPartitionMounter : public PartitionMounter {
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 2baeee3..77d62cb 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -275,67 +275,67 @@
     "    </hal>\n"
     "</compatibility-matrix>\n"};
 
-// Setup the MockFileFetcher used by the fetchAllInformation template
+static MockPartitionMounter& mounter() {
+    return *static_cast<MockPartitionMounter*>(gPartitionMounter);
+}
+static MockFileSystem& fetcher() {
+    return static_cast<MockFileSystem&>(details::getFileSystem());
+}
+
+// Setup the MockFileSystem 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,
                       const std::string& productModel) {
-    MockFileFetcher* fetcher = static_cast<MockFileFetcher*>(gFetcher);
-
-    ON_CALL(*fetcher, listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+    ON_CALL(fetcher(), listFiles(StrEq(kVendorManifestFragmentDir), _, _))
         .WillByDefault(Return(::android::OK));
-    ON_CALL(*fetcher, listFiles(StrEq(kSystemManifestFragmentDir), _, _))
+    ON_CALL(fetcher(), listFiles(StrEq(kSystemManifestFragmentDir), _, _))
         .WillByDefault(Return(::android::OK));
-    ON_CALL(*fetcher, listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+    ON_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
         .WillByDefault(Return(::android::OK));
 
     if (!productModel.empty()) {
-        ON_CALL(*fetcher, fetch(StrEq(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml"), _))
+        ON_CALL(fetcher(),
+                fetch(StrEq(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml"), _))
             .WillByDefault(Return(::android::NAME_NOT_FOUND));
-        ON_CALL(*fetcher, fetch(StrEq(kOdmVintfDir + "manifest_" + productModel + ".xml"), _))
+        ON_CALL(fetcher(), fetch(StrEq(kOdmVintfDir + "manifest_" + productModel + ".xml"), _))
             .WillByDefault(Return(::android::NAME_NOT_FOUND));
     }
-    ON_CALL(*fetcher, fetch(StrEq(kOdmLegacyManifest), _))
+    ON_CALL(fetcher(), fetch(StrEq(kOdmLegacyManifest), _))
         .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    ON_CALL(*fetcher, fetch(StrEq(kOdmManifest), _))
+    ON_CALL(fetcher(), fetch(StrEq(kOdmManifest), _))
         .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    ON_CALL(*fetcher, fetch(StrEq(kVendorManifest), _))
+    ON_CALL(fetcher(), fetch(StrEq(kVendorManifest), _))
         .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    ON_CALL(*fetcher, fetch(StrEq(kVendorLegacyManifest), _))
+    ON_CALL(fetcher(), fetch(StrEq(kVendorLegacyManifest), _))
         .WillByDefault(Invoke([vendorManifestXml](const std::string& path, std::string& fetched) {
             (void)path;
             fetched = vendorManifestXml;
             return 0;
         }));
-    ON_CALL(*fetcher, fetch(StrEq(kSystemManifest), _))
+    ON_CALL(fetcher(), fetch(StrEq(kSystemManifest), _))
         .WillByDefault(Invoke([systemManifestXml](const std::string& path, std::string& fetched) {
             (void)path;
             fetched = systemManifestXml;
             return 0;
         }));
-    ON_CALL(*fetcher, fetch(StrEq(kVendorMatrix), _))
+    ON_CALL(fetcher(), fetch(StrEq(kVendorMatrix), _))
         .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    ON_CALL(*fetcher, fetch(StrEq(kVendorLegacyMatrix), _))
+    ON_CALL(fetcher(), fetch(StrEq(kVendorLegacyMatrix), _))
         .WillByDefault(Invoke([vendorMatrixXml](const std::string& path, std::string& fetched) {
             (void)path;
             fetched = vendorMatrixXml;
             return 0;
         }));
-    ON_CALL(*fetcher, fetch(StrEq(kSystemLegacyMatrix), _))
+    ON_CALL(fetcher(), fetch(StrEq(kSystemLegacyMatrix), _))
         .WillByDefault(Invoke([systemMatrixXml](const std::string& path, std::string& fetched) {
             (void)path;
             fetched = systemMatrixXml;
             return 0;
         }));
     // Don't list /system/etc/vintf unless otherwise specified.
-    ON_CALL(*fetcher, listFiles(StrEq(kSystemVintfDir), _, _)).WillByDefault(Return(::android::OK));
-}
-
-static MockPartitionMounter &mounter() {
-    return *static_cast<MockPartitionMounter *>(gPartitionMounter);
-}
-static MockFileFetcher &fetcher() {
-    return *static_cast<MockFileFetcher*>(gFetcher);
+    ON_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
+        .WillByDefault(Return(::android::OK));
 }
 
 class VintfObjectTestBase : public testing::Test {
@@ -1230,8 +1230,10 @@
 int main(int argc, char** argv) {
     ::testing::InitGoogleMock(&argc, argv);
 
-    NiceMock<MockFileFetcher> fetcher;
-    gFetcher = &fetcher;
+    if (!VintfObject::InitFileSystem(std::make_unique<NiceMock<MockFileSystem>>())) {
+        LOG(FATAL) << "Cannot set mock file system because it is already initialized.";
+        return 1;
+    }
 
     NiceMock<MockPartitionMounter> mounter;
     gPartitionMounter = &mounter;
diff --git a/utils.cpp b/utils.cpp
index 5b2bb7d..c6425d8 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -17,6 +17,7 @@
 #include "utils.h"
 
 #ifdef LIBVINTF_TARGET
+#include <android-base/logging.h>
 #include <android-base/properties.h>
 #endif
 
@@ -24,9 +25,6 @@
 namespace vintf {
 namespace details {
 
-static FileFetcher fetcher;
-FileFetcher* gFetcher = &fetcher;
-
 static PartitionMounter partitionMounter;
 PartitionMounter* gPartitionMounter = &partitionMounter;
 
diff --git a/utils.h b/utils.h
index 783d40b..e33d283 100644
--- a/utils.h
+++ b/utils.h
@@ -17,14 +17,11 @@
 #ifndef ANDROID_VINTF_UTILS_H
 #define ANDROID_VINTF_UTILS_H
 
-#include <dirent.h>
-
-#include <fstream>
-#include <iostream>
 #include <memory>
-#include <sstream>
+#include <mutex>
 
 #include <utils/Errors.h>
+#include <vintf/FileSystem.h>
 #include <vintf/RuntimeInfo.h>
 #include <vintf/parse_xml.h>
 
@@ -32,57 +29,6 @@
 namespace vintf {
 namespace details {
 
-// 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() {}
-    status_t fetchInternal(const std::string& path, std::string& fetched, std::string* error) {
-        std::ifstream in;
-
-        in.open(path);
-        if (!in.is_open()) {
-            if (error) {
-                *error = "Cannot open " + path;
-            }
-            return NAME_NOT_FOUND;
-        }
-
-        std::stringstream ss;
-        ss << in.rdbuf();
-        fetched = ss.str();
-
-        return OK;
-    }
-    virtual status_t fetch(const std::string& path, std::string& fetched, std::string* error) {
-        return fetchInternal(path, fetched, error);
-    }
-    virtual status_t fetch(const std::string& path, std::string& fetched) {
-        return fetchInternal(path, fetched, nullptr);
-    }
-    virtual status_t listFiles(const std::string& path, std::vector<std::string>* out,
-                               std::string* error) {
-        std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
-        if (!dir) {
-            if (error) {
-                *error = "Cannot open " + path;
-            }
-            return NAME_NOT_FOUND;
-        }
-
-        dirent* dp;
-        while ((dp = readdir(dir.get())) != nullptr) {
-            if (dp->d_type != DT_DIR) {
-                out->push_back(dp->d_name);
-            }
-        }
-        return OK;
-    }
-};
-
-extern FileFetcher* gFetcher;
-
 class PartitionMounter {
    public:
     virtual ~PartitionMounter() {}
@@ -99,12 +45,7 @@
                              T* outObject, std::string* error = nullptr) {
     std::string info;
 
-    if (gFetcher == nullptr) {
-        // Should never happen.
-        return NO_INIT;
-    }
-
-    status_t result = gFetcher->fetch(path, info, error);
+    status_t result = getFileSystem().fetch(path, &info, error);
 
     if (result != OK) {
         return result;