Merge pi-platform-release to stage-aosp-master - DO NOT MERGE

Change-Id: I7fa131aed75b430648b4f7de8ba5b2b9effd1f2c
diff --git a/Android.bp b/Android.bp
index ad750d0..4689832 100644
--- a/Android.bp
+++ b/Android.bp
@@ -21,6 +21,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wextra-semi",
     ],
 
     target: {
@@ -30,14 +31,16 @@
     }
 }
 
-cc_library_static {
-    name: "libvintf_common",
+cc_library {
+    name: "libvintf",
     defaults: ["libvintf-defaults"],
     host_supported: true,
+    recovery_available: true,
     srcs: [
         "parse_string.cpp",
         "parse_xml.cpp",
         "CompatibilityMatrix.cpp",
+        "FileSystem.cpp",
         "HalManifest.cpp",
         "HalInterface.cpp",
         "KernelConfigTypedValue.cpp",
@@ -48,12 +51,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",
@@ -84,33 +87,6 @@
     }
 }
 
-// libvintf_common + utils.cpp
-cc_library {
-    name: "libvintf",
-    host_supported: true,
-    defaults: ["libvintf-defaults"],
-    shared_libs: [
-        "libbase",
-        "libhidl-gen-utils",
-        "liblog",
-        "libselinux",
-        "libtinyxml2",
-        "libz",
-    ],
-    export_include_dirs: ["include"],
-    local_include_dirs: ["include/vintf"],
-
-    srcs: [
-        "utils.cpp",
-    ],
-
-    export_shared_lib_headers: [
-        "libhidl-gen-utils",
-    ],
-
-    whole_static_libs: ["libvintf_common"],
-}
-
 cc_binary {
     name: "vintf",
     defaults: ["libvintf-defaults"],
@@ -130,7 +106,7 @@
     static_libs: [
         "libbase",
         "libhidl-gen-utils",
-        "libvintf_common",
+        "libvintf",
         "libutils",
         "libtinyxml2",
     ],
@@ -168,3 +144,19 @@
         "assemble_vintf_main.cpp"
     ],
 }
+
+cc_library_static {
+    name: "libvintf_recovery",
+    recovery_available: true,
+    defaults: ["libvintf-defaults"],
+    srcs: ["VintfObjectRecovery.cpp"],
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include/vintf"],
+    static_libs: [
+        "libbase",
+        "libvintf",
+        "libhidl-gen-utils",
+        "libfs_mgr",
+    ],
+    export_static_lib_headers: ["libhidl-gen-utils"],
+}
diff --git a/Android.mk b/Android.mk
index 640074b..91c7e0d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2017 The Android Open Source Project
+# 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.
@@ -12,22 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libvintf_recovery
-LOCAL_SRC_FILES := VintfObjectRecovery.cpp
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/vintf
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_STATIC_LIBRARIES := \
-    libbase \
-    libvintf \
-    libhidl-gen-utils \
-    libfs_mgr
-
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libhidl-gen-utils
-
-include $(BUILD_STATIC_LIBRARY)
-
 $(call dist-for-goals,dist_files,$(HOST_OUT_EXECUTABLES)/checkvintf)
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index ef7c8ba..cc8db31 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -39,8 +39,8 @@
 namespace vintf {
 
 static const std::string gConfigPrefix = "android-base-";
-static const std::string gConfigSuffix = ".cfg";
-static const std::string gBaseConfig = "android-base.cfg";
+static const std::string gConfigSuffix = ".config";
+static const std::string gBaseConfig = "android-base.config";
 
 // An input stream with a name.
 // The input stream may be an actual file, or a stringstream for testing.
@@ -89,11 +89,13 @@
     }
 
     template <typename T>
-    bool getFlag(const std::string& key, T* value) const {
+    bool getFlag(const std::string& key, T* value, bool log = true) const {
         std::string envValue = getEnv(key);
         if (envValue.empty()) {
-            std::cerr << "Warning: " << key << " is missing, defaulted to " << (*value) << "."
-                      << std::endl;
+            if (log) {
+                std::cerr << "Warning: " << key << " is missing, defaulted to " << (*value) << "."
+                          << std::endl;
+            }
             return true;
         }
 
@@ -193,7 +195,8 @@
             }
             std::cerr << "'" << fname << "' (in " << path
                       << ") is not a valid kernel config file name. Must match regex: "
-                      << "android-base(-[0-9a-zA-Z-]+)?\\.cfg" << std::endl;
+                      << "android-base(-[0-9a-zA-Z-]+)?\\" << gConfigSuffix
+                      << std::endl;
             return nullptr;
         }
         sub.insert(0, "CONFIG_");
@@ -250,7 +253,7 @@
         }
 
         if (!foundCommonConfig) {
-            std::cerr << "No android-base.cfg is found in these paths:" << std::endl;
+            std::cerr << "No " << gBaseConfig << " is found in these paths:" << std::endl;
             for (auto& namedStream : *streams) {
                 std::cerr << "    " << namedStream.name() << std::endl;
             }
@@ -299,39 +302,65 @@
     using HalManifests = Schemas<HalManifest>;
     using CompatibilityMatrices = Schemas<CompatibilityMatrix>;
 
+    template <typename M>
+    void outputInputs(const Schemas<M>& inputs) {
+        out() << "<!--" << std::endl;
+        out() << "    Input:" << std::endl;
+        for (const auto& e : inputs) {
+            if (!e.name.empty()) {
+                out() << "        " << base::Basename(e.name) << std::endl;
+            }
+        }
+        out() << "-->" << std::endl;
+    }
+
     bool assembleHalManifest(HalManifests* halManifests) {
         std::string error;
         HalManifest* halManifest = &halManifests->front().object;
         for (auto it = halManifests->begin() + 1; it != halManifests->end(); ++it) {
             const std::string& path = it->name;
-            HalManifest& halToAdd = it->object;
+            HalManifest& manifestToAdd = it->object;
 
-            if (halToAdd.level() != Level::UNSPECIFIED) {
+            if (manifestToAdd.level() != Level::UNSPECIFIED) {
                 if (halManifest->level() == Level::UNSPECIFIED) {
-                    halManifest->mLevel = halToAdd.level();
-                } else if (halManifest->level() != halToAdd.level()) {
+                    halManifest->mLevel = manifestToAdd.level();
+                } else if (halManifest->level() != manifestToAdd.level()) {
                     std::cerr << "Inconsistent FCM Version in HAL manifests:" << std::endl
                               << "    File '" << halManifests->front().name << "' has level "
                               << halManifest->level() << std::endl
-                              << "    File '" << path << "' has level " << halToAdd.level()
+                              << "    File '" << path << "' has level " << manifestToAdd.level()
                               << std::endl;
                     return false;
                 }
             }
 
-            if (!halManifest->addAllHals(&halToAdd, &error)) {
+            // TODO(b/78943004): add everything
+            if (!halManifest->addAllHals(&manifestToAdd, &error)) {
                 std::cerr << "File \"" << path << "\" cannot be added: conflict on HAL \"" << error
                           << "\" with an existing HAL. See <hal> with the same name "
                           << "in previously parsed files or previously declared in this file."
                           << std::endl;
                 return false;
             }
+
+            // Check that manifestToAdd is empty.
+            if (!manifestToAdd.empty()) {
+                std::cerr
+                    << "File \"" << path << "\" contains extraneous entries and attributes. "
+                    << "This is currently unsupported (b/78943004); it can only contain "
+                    << "<hal>s and attribute \"type\" and \"version\". Only the first input "
+                    << "file to assemble_vintf can contain other things. "
+                    << "Remaining entries and attributes are:" << std::endl
+                    << gHalManifestConverter(
+                           manifestToAdd,
+                           SerializeFlags::EVERYTHING.disableMetaVersion().disableSchemaType());
+                return false;
+            }
         }
 
         if (halManifest->mType == SchemaType::DEVICE) {
-            if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
-                return false;
-            }
+            (void)getFlagIfUnset("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion);
+
             if (!setDeviceFcmVersion(halManifest)) {
                 return false;
             }
@@ -347,6 +376,8 @@
             }
         }
 
+        outputInputs(*halManifests);
+
         if (mOutputMatrix) {
             CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix();
             if (!halManifest->checkCompatibility(generatedMatrix, &error)) {
@@ -381,6 +412,7 @@
         return true;
     }
 
+    // Parse --kernel arguments and write to output matrix.
     bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) {
         for (auto& pair : mKernels) {
             std::vector<ConditionedConfig> conditionedConfigs;
@@ -391,7 +423,11 @@
                 MatrixKernel kernel(KernelVersion{pair.first}, std::move(conditionedConfig.second));
                 if (conditionedConfig.first != nullptr)
                     kernel.mConditions.push_back(std::move(*conditionedConfig.first));
-                matrix->framework.mKernels.push_back(std::move(kernel));
+                std::string error;
+                if (!matrix->addKernel(std::move(kernel), &error)) {
+                    std::cerr << "Error:" << error << std::endl;
+                    return false;
+                };
             }
         }
         return true;
@@ -453,7 +489,24 @@
         std::string error;
         CompatibilityMatrix* matrix = nullptr;
         std::unique_ptr<HalManifest> checkManifest;
+        std::unique_ptr<CompatibilityMatrix> builtMatrix;
+
+        if (mCheckFile != nullptr) {
+            checkManifest = std::make_unique<HalManifest>();
+            if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile), &error)) {
+                std::cerr << "Cannot parse check file as a HAL manifest: " << error << std::endl;
+                return false;
+            }
+        }
+
         if (matrices->front().object.mType == SchemaType::DEVICE) {
+            if (matrices->size() > 1) {
+                std::cerr
+                    << "assemble_vintf does not support merging device compatibilility matrices."
+                    << std::endl;
+                return false;
+            }
+
             matrix = &matrices->front().object;
 
             auto vndkVersion = base::Trim(getEnv("REQUIRED_VNDK_VERSION"));
@@ -475,24 +528,20 @@
         }
 
         if (matrices->front().object.mType == SchemaType::FRAMEWORK) {
-            Level deviceLevel = Level::UNSPECIFIED;
-            if (mCheckFile != nullptr) {
-                checkManifest = std::make_unique<HalManifest>();
-                if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile), &error)) {
-                    std::cerr << "Cannot parse check file as a HAL manifest: " << error
-                              << std::endl;
-                    return false;
-                }
-                deviceLevel = checkManifest->level();
-            }
-
+            Level deviceLevel =
+                checkManifest != nullptr ? checkManifest->level() : Level::UNSPECIFIED;
             if (deviceLevel == Level::UNSPECIFIED) {
-                // For GSI build, legacy devices that do not have a HAL manifest,
-                // and devices in development, merge all compatibility matrices.
                 deviceLevel = getLowestFcmVersion(*matrices);
+                if (checkManifest != nullptr && deviceLevel != Level::UNSPECIFIED) {
+                    std::cerr << "Warning: No Target FCM Version for device. Assuming \""
+                              << to_string(deviceLevel)
+                              << "\" when building final framework compatibility matrix."
+                              << std::endl;
+                }
             }
+            builtMatrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error);
+            matrix = builtMatrix.get();
 
-            matrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error);
             if (matrix == nullptr) {
                 std::cerr << error << std::endl;
                 return false;
@@ -527,19 +576,14 @@
             }
 
             getFlagIfUnset("POLICYVERS", &matrix->framework.mSepolicy.mKernelSepolicyVersion,
-                           deviceLevel == Level::UNSPECIFIED /* log */);
+                           false /* log */);
             getFlagIfUnset("FRAMEWORK_VBMETA_VERSION", &matrix->framework.mAvbMetaVersion,
-                           deviceLevel == Level::UNSPECIFIED /* log */);
-
-            out() << "<!--" << std::endl;
-            out() << "    Input:" << std::endl;
-            for (const auto& e : *matrices) {
-                if (!e.name.empty()) {
-                    out() << "        " << base::Basename(e.name) << std::endl;
-                }
-            }
-            out() << "-->" << std::endl;
+                           false /* log */);
+            // Hard-override existing AVB version
+            getFlag("FRAMEWORK_VBMETA_VERSION_OVERRIDE", &matrix->framework.mAvbMetaVersion,
+                    false /* log */);
         }
+        outputInputs(*matrices);
         out() << gCompatibilityMatrixConverter(*matrix, mSerializeFlags);
         out().flush();
 
@@ -649,14 +693,29 @@
     void setOutputMatrix() override { mOutputMatrix = true; }
 
     bool setHalsOnly() override {
-        if (mSerializeFlags) return false;
-        mSerializeFlags |= SerializeFlag::HALS_ONLY;
+        if (mHasSetHalsOnlyFlag) {
+            std::cerr << "Error: Cannot set --hals-only with --no-hals." << std::endl;
+            return false;
+        }
+        // Just override it with HALS_ONLY because other flags that modify mSerializeFlags
+        // does not interfere with this (except --no-hals).
+        mSerializeFlags = SerializeFlags::HALS_ONLY;
+        mHasSetHalsOnlyFlag = true;
         return true;
     }
 
     bool setNoHals() override {
-        if (mSerializeFlags) return false;
-        mSerializeFlags |= SerializeFlag::NO_HALS;
+        if (mHasSetHalsOnlyFlag) {
+            std::cerr << "Error: Cannot set --hals-only with --no-hals." << std::endl;
+            return false;
+        }
+        mSerializeFlags = mSerializeFlags.disableHals();
+        mHasSetHalsOnlyFlag = true;
+        return true;
+    }
+
+    bool setNoKernelRequirements() override {
+        mSerializeFlags = mSerializeFlags.disableKernelConfigs().disableKernelMinorRevision();
         return true;
     }
 
@@ -665,7 +724,8 @@
     Ostream mOutRef;
     Istream mCheckFile;
     bool mOutputMatrix = false;
-    SerializeFlags mSerializeFlags = SerializeFlag::EVERYTHING;
+    bool mHasSetHalsOnlyFlag = false;
+    SerializeFlags::Type mSerializeFlags = SerializeFlags::EVERYTHING;
     std::map<KernelVersion, std::vector<NamedIstream>> mKernels;
     std::map<std::string, std::string> mFakeEnv;
 };
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 338e5be..290ebf9 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -19,6 +19,8 @@
 #include <iostream>
 #include <utility>
 
+#include <android-base/strings.h>
+
 #include "parse_string.h"
 #include "parse_xml.h"
 #include "utils.h"
@@ -26,14 +28,59 @@
 namespace android {
 namespace vintf {
 
-bool CompatibilityMatrix::add(MatrixHal &&hal) {
-    return HalGroup<MatrixHal>::add(std::move(hal));
-}
-
-bool CompatibilityMatrix::add(MatrixKernel &&kernel) {
+bool CompatibilityMatrix::addKernel(MatrixKernel&& kernel, std::string* error) {
     if (mType != SchemaType::FRAMEWORK) {
+        if (error) {
+            *error = "Cannot add <kernel> to a " + to_string(mType) + " compatibility matrix.";
+        }
         return false;
     }
+
+    auto it = framework.mKernels.begin();
+    for (; it != framework.mKernels.end(); ++it) {
+        if (it->minLts() == kernel.minLts()) {
+            break;
+        }
+        if (it->minLts().version == kernel.minLts().version &&
+            it->minLts().majorRev == kernel.minLts().majorRev) {
+            if (error) {
+                *error = "Kernel version mismatch; cannot add " + to_string(kernel.minLts()) +
+                         " because " + to_string(it->minLts()) + " was added.";
+            }
+            return false;
+        }
+    }
+
+    bool seenVersion = it != framework.mKernels.end();
+
+    if (seenVersion) {
+        // If no conditions, must be the first among the same minLts
+        // because O libvintf only checks the first <kernel> tag that version matches.
+        if (kernel.conditions().empty()) {
+            // Found first <kernel> with the same minLts.
+            // Append config if it does not have <condition>s, else error.
+            if (it->conditions().empty()) {
+                const auto& configs = kernel.configs();
+                it->mConfigs.insert(it->mConfigs.end(), configs.begin(), configs.end());
+            } else {
+                if (error) {
+                    *error =
+                        "Base compatibility matrix has <condition> for the first <kernel> "
+                        "with minlts " +
+                        to_string(kernel.minLts()) + " for unknown reason.";
+                }
+                return false;
+            }
+            return true;
+        }
+    } else {
+        // First <kernel> of a minLts must not have <condition>'s for backwards compatibility
+        // with O libvintf.
+        if (!kernel.conditions().empty()) {
+            framework.mKernels.push_back(MatrixKernel(KernelVersion{kernel.minLts()}, {}));
+        }
+    }
+
     framework.mKernels.push_back(std::move(kernel));
     return true;
 }
@@ -52,8 +99,10 @@
     return {1, 0};
 }
 
-status_t CompatibilityMatrix::fetchAllInformation(const std::string& path, std::string* error) {
-    return details::fetchAllInformation(path, gCompatibilityMatrixConverter, this, error);
+status_t CompatibilityMatrix::fetchAllInformation(const FileSystem* fileSystem,
+                                                  const std::string& path, std::string* error) {
+    return details::fetchAllInformation(fileSystem, path, gCompatibilityMatrixConverter, this,
+                                        error);
 }
 
 std::string CompatibilityMatrix::getXmlSchemaPath(const std::string& xmlFileName,
@@ -194,6 +243,27 @@
     return true;
 }
 
+// Merge Kernel.
+// Add <kernel> from exact "level", then optionally add <kernel> from high levels to low levels.
+// For example, (each letter is a kernel version x.y.z)
+// 1.xml: A1, B1
+// 2.xml: B2, C2, D2
+// 3.xml: D3, E3
+// Then the combined 1.xml should have
+// A1, B1 (from 1.xml, required), C2, D2, E3 (optional, use earliest possible).
+bool CompatibilityMatrix::addAllKernels(CompatibilityMatrix* other, std::string* error) {
+    for (MatrixKernel& kernel : other->framework.mKernels) {
+        KernelVersion ver = kernel.minLts();
+        if (!addKernel(std::move(kernel), error)) {
+            if (error) {
+                *error = "Cannot add kernel version " + to_string(ver) + ": " + *error;
+            }
+            return false;
+        }
+    }
+    return true;
+}
+
 bool CompatibilityMatrix::addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error) {
     if (other == nullptr || other->level() <= level()) {
         return true;
@@ -214,9 +284,9 @@
         }
 
         KernelVersion minLts = kernelToAdd.minLts();
-        if (!add(std::move(kernelToAdd))) {
+        if (!addKernel(std::move(kernelToAdd), error)) {
             if (error) {
-                *error = "Cannot add " + to_string(minLts) + " for unknown reason.";
+                *error = "Cannot add " + to_string(minLts) + ": " + *error;
             }
             return false;
         }
@@ -224,6 +294,34 @@
     return true;
 }
 
+template <typename T>
+static bool mergeField(T* dst, T* src) {
+    static const T kEmpty{};
+    if (*dst == *src) {
+        return true;  // no conflict
+    }
+    if (*src == kEmpty) {
+        return true;
+    }
+    if (*dst == kEmpty) {
+        *dst = std::move(*src);
+        return true;
+    }
+    return false;
+}
+
+bool CompatibilityMatrix::addSepolicy(CompatibilityMatrix* other, std::string* error) {
+    bool success = mergeField(&this->framework.mSepolicy, &other->framework.mSepolicy);
+    if (!success && error) *error = "<sepolicy> is already defined";
+    return success;
+}
+
+bool CompatibilityMatrix::addAvbMetaVersion(CompatibilityMatrix* other, std::string* error) {
+    bool success = mergeField(&this->framework.mAvbMetaVersion, &other->framework.mAvbMetaVersion);
+    if (!success && error) *error = "<avb><vbmeta-version> is already defined";
+    return success;
+}
+
 bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
            lft.mXmlFiles == rgt.mXmlFiles &&
@@ -241,175 +339,83 @@
              lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
 }
 
-// Find compatibility_matrix.empty.xml (which has unspecified level) and use it
-// as a base matrix.
-CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
-    std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
-    std::vector<CompatibilityMatrix*> matricesUnspecified;
-    std::vector<CompatibilityMatrix*> matricesEmpty;
+std::unique_ptr<CompatibilityMatrix> CompatibilityMatrix::combine(
+    Level deviceLevel, std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
+    // Check type.
+    for (const auto& e : *matrices) {
+        if (e.object.type() != SchemaType::FRAMEWORK) {
+            if (error) {
+                *error = "File \"" + e.name + "\" is not a framework compatibility matrix.";
+                return nullptr;
+            }
+        }
+    }
+
+    // Matrices with unspecified (empty) level are auto-filled with deviceLevel.
     for (auto& e : *matrices) {
         if (e.object.level() == Level::UNSPECIFIED) {
-            matricesUnspecified.push_back(&e.object);
-
-            if (!e.object.mHals.empty()) {
-                continue;
-            }
-
-            if (!e.object.mXmlFiles.empty()) {
-                continue;
-            }
-
-            matricesEmpty.push_back(&e.object);
+            e.object.mLevel = deviceLevel;
         }
     }
 
-    if (matricesEmpty.size() > 1) {
-        if (error) {
-            *error =
-                "Error: multiple framework compatibility matrix files have "
-                "unspecified level; there should only be one such file.\n";
-            for (auto& e : *matrices) {
-                if (e.object.level() == Level::UNSPECIFIED) {
-                    *error += "    " + e.name + "\n";
-                }
-            }
+    // Add from low to high FCM version so that optional <kernel> requirements are added correctly.
+    // See comment in addAllAsOptional.
+    std::sort(matrices->begin(), matrices->end(),
+              [](const auto& x, const auto& y) { return x.object.level() < y.object.level(); });
+
+    auto baseMatrix = std::make_unique<CompatibilityMatrix>();
+    baseMatrix->mLevel = deviceLevel;
+    baseMatrix->mType = SchemaType::FRAMEWORK;
+
+    std::vector<std::string> parsedFiles;
+    for (auto& e : *matrices) {
+        if (e.object.level() < deviceLevel) {
+            continue;
         }
-        return nullptr;
+
+        bool success = false;
+        if (e.object.level() == deviceLevel) {
+            success = baseMatrix->addAll(&e, error);
+        } else {
+            success = baseMatrix->addAllAsOptional(&e, error);
+        }
+        if (!success) {
+            if (error) {
+                *error = "Conflict when merging \"" + e.name + "\": " + *error + "\n" +
+                         "Previous files:\n" + base::Join(parsedFiles, "\n");
+            }
+            return nullptr;
+        }
+        parsedFiles.push_back(e.name);
     }
-    if (matricesEmpty.size() == 1) {
-        return matricesEmpty.front();
-    }
-    if (!matricesUnspecified.empty()) {
-        return matricesUnspecified.front();
-    }
-    auto matrix = &matrices->emplace(matrices->end())->object;
-    matrix->mType = SchemaType::FRAMEWORK;
-    matrix->mLevel = Level::UNSPECIFIED;
-    return matrix;
+
+    return baseMatrix;
 }
 
-// Check if there are two files declaring level="1", for example, because
-// combine() use this assumption to simplify a lot of logic.
-static bool checkDuplicateLevels(const std::vector<Named<CompatibilityMatrix>>& matrices,
-                                 std::string* error) {
-    std::map<Level, const std::string*> existingLevels;
-    for (const auto& e : matrices) {
-        if (e.object.level() == Level::UNSPECIFIED &&
-            existingLevels.find(e.object.level()) != existingLevels.end()) {
-            if (error) {
-                *error = "Conflict of levels: file \"" +
-                         *existingLevels.find(e.object.level())->second + "\" and \"" + e.name +
-                         " both have level " + to_string(e.object.level());
-            }
-            return false;
+bool CompatibilityMatrix::addAll(Named<CompatibilityMatrix>* inputMatrix, std::string* error) {
+    if (!addAllHals(&inputMatrix->object, error) || !addAllXmlFiles(&inputMatrix->object, error) ||
+        !addAllKernels(&inputMatrix->object, error) || !addSepolicy(&inputMatrix->object, error) ||
+        !addAvbMetaVersion(&inputMatrix->object, error)) {
+        if (error) {
+            *error = "File \"" + inputMatrix->name + "\" cannot be added: " + *error + ".";
         }
-        existingLevels.emplace(e.object.level(), &e.name);
     }
     return true;
 }
 
-CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
-                                                  std::vector<Named<CompatibilityMatrix>>* matrices,
-                                                  std::string* error) {
-    if (!checkDuplicateLevels(*matrices, error)) {
-        return nullptr;
-    }
-
-    CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
-    if (matrix == nullptr) {
-        return nullptr;
-    }
-
-    matrix->mLevel = deviceLevel;
-
-    for (auto& e : *matrices) {
-        if (&e.object != matrix &&
-            (e.object.level() == deviceLevel || e.object.level() == Level::UNSPECIFIED)) {
-            if (!matrix->addAllHals(&e.object, error)) {
-                if (error) {
-                    *error = "File \"" + e.name + "\" cannot be added: HAL " + *error +
-                             " has a conflict.";
-                }
-                return nullptr;
-            }
-
-            if (!matrix->addAllXmlFiles(&e.object, error)) {
-                if (error) {
-                    *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
-                             " has a conflict.";
-                }
-                return nullptr;
-            }
+bool CompatibilityMatrix::addAllAsOptional(Named<CompatibilityMatrix>* inputMatrix,
+                                           std::string* error) {
+    if (!addAllHalsAsOptional(&inputMatrix->object, error) ||
+        !addAllXmlFilesAsOptional(&inputMatrix->object, error) ||
+        !addAllKernelsAsOptional(&inputMatrix->object, error)) {
+        if (error) {
+            *error = "File \"" + inputMatrix->name + "\" cannot be added: " + *error;
         }
+        return false;
     }
-
-    for (auto& e : *matrices) {
-        if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
-            e.object.level() > deviceLevel) {
-            if (!matrix->addAllHalsAsOptional(&e.object, error)) {
-                if (error) {
-                    *error = "File \"" + e.name + "\" cannot be added: " + *error +
-                             ". See <hal> with the same name " +
-                             "in previously parsed files or previously declared in this file.";
-                }
-                return nullptr;
-            }
-
-            if (!matrix->addAllXmlFilesAsOptional(&e.object, error)) {
-                if (error) {
-                    *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
-                             " has a conflict.";
-                }
-                return nullptr;
-            }
-        }
-    }
-
-    // Add <kernel> from exact "level", then optionally add <kernel> from high levels to low levels.
-    // For example, (each letter is a kernel version x.y.z)
-    // 1.xml: A1, B1
-    // 2.xml: B2, C2, D2
-    // 3.xml: D3, E3
-    // Then the combined 1.xml should have
-    // A1, B1 (from 1.xml, required), C2, D2, E3 (optional, use earliest possible).
-    for (auto& e : *matrices) {
-        if (&e.object != matrix && e.object.level() == deviceLevel &&
-            e.object.type() == SchemaType::FRAMEWORK) {
-            for (MatrixKernel& kernel : e.object.framework.mKernels) {
-                KernelVersion ver = kernel.minLts();
-                if (!matrix->add(std::move(kernel))) {
-                    if (error) {
-                        *error = "Cannot add kernel version " + to_string(ver) +
-                                 " from FCM version " + to_string(deviceLevel);
-                    }
-                    return nullptr;
-                }
-            }
-        }
-    }
-
-    // There is only one file per level, hence a map is used instead of a multimap. Also, there is
-    // no good ordering (i.e. priority) for multiple files with the same level.
-    std::map<Level, Named<CompatibilityMatrix>*> matricesMap;
-    for (auto& e : *matrices) {
-        if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
-            e.object.level() > deviceLevel && e.object.type() == SchemaType::FRAMEWORK) {
-            matricesMap.emplace(e.object.level(), &e);
-        }
-    }
-
-    for (auto&& pair : matricesMap) {
-        if (!matrix->addAllKernelsAsOptional(&pair.second->object, error)) {
-            if (error) {
-                *error = "Cannot add new kernel versions from FCM version " +
-                         to_string(pair.first) + " (" + pair.second->name + ")" +
-                         " to FCM version " + to_string(deviceLevel) + ": " + *error;
-            }
-            return nullptr;
-        }
-    }
-
-    return matrix;
+    // ignore <sepolicy> requirement from higher level
+    // ignore <avb> requirement from higher level
+    return true;
 }
 
 bool CompatibilityMatrix::forEachInstanceOfVersion(
@@ -439,5 +445,9 @@
     return found;
 }
 
+std::string CompatibilityMatrix::getVendorNdkVersion() const {
+    return type() == SchemaType::DEVICE ? device.mVendorNdk.version() : "";
+}
+
 } // namespace vintf
 } // namespace android
diff --git a/FileSystem.cpp b/FileSystem.cpp
new file mode 100644
index 0000000..c239488
--- /dev/null
+++ b/FileSystem.cpp
@@ -0,0 +1,103 @@
+
+/*
+ * 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 {
+
+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;
+}
+
+FileSystemUnderPath::FileSystemUnderPath(const std::string& rootdir) {
+    mRootDir = rootdir;
+    if (!mRootDir.empty() && mRootDir.back() != '/') {
+        mRootDir.push_back('/');
+    }
+}
+
+status_t FileSystemUnderPath::fetch(const std::string& path, std::string* fetched,
+                                    std::string* error) const {
+    return mImpl.fetch(mRootDir + path, fetched, error);
+}
+
+status_t FileSystemUnderPath::listFiles(const std::string& path, std::vector<std::string>* out,
+                                        std::string* error) const {
+    return mImpl.listFiles(mRootDir + path, out, error);
+}
+
+const std::string& FileSystemUnderPath::getRootDir() const {
+    return mRootDir;
+}
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/HalManifest.cpp b/HalManifest.cpp
index d1230cb..b795136 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -124,7 +124,7 @@
 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
     std::set<std::string> names{};
     forEachInstance([&names](const ManifestInstance& e) {
-        names.insert(toFQNameString(e.interface(), e.version()));
+        names.insert(toFQNameString(e.package(), e.version()));
         return true;
     });
     return names;
@@ -360,8 +360,9 @@
     return matrix;
 }
 
-status_t HalManifest::fetchAllInformation(const std::string& path, std::string* error) {
-    return details::fetchAllInformation(path, gHalManifestConverter, this, error);
+status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
+                                          std::string* error) {
+    return details::fetchAllInformation(fileSystem, path, gHalManifestConverter, this, error);
 }
 
 SchemaType HalManifest::type() const {
@@ -446,5 +447,28 @@
     return found;
 }
 
+bool HalManifest::insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch,
+                                 HalFormat format, std::string* error) {
+    for (ManifestHal& hal : getHals()) {
+        if (hal.name == fqInstance.getPackage() && hal.format == format &&
+            hal.transport() == transport && hal.arch() == arch) {
+            return hal.insertInstance(fqInstance, error);
+        }
+    }
+
+    ManifestHal hal;
+    hal.name = fqInstance.getPackage();
+    hal.format = format;
+    hal.transportArch = TransportArch(transport, arch);
+    if (!hal.insertInstance(fqInstance, error)) return false;
+    return add(std::move(hal));
+}
+
+bool HalManifest::empty() const {
+    HalManifest emptyManifest;
+    emptyManifest.setType(type());
+    return (*this) == emptyManifest;
+}
+
 } // namespace vintf
 } // namespace android
diff --git a/ManifestHal.cpp b/ManifestHal.cpp
index 2d0e246..9b48a6f 100644
--- a/ManifestHal.cpp
+++ b/ManifestHal.cpp
@@ -96,55 +96,67 @@
     });
 }
 
-static bool verifyInstances(const std::set<FqInstance>& fqInstances, std::string* error) {
-    for (const FqInstance& fqInstance : fqInstances) {
-        if (fqInstance.hasPackage()) {
-            if (error) *error = "Should not specify package: \"" + fqInstance.string() + "\"";
-            return false;
+bool ManifestHal::verifyInstance(const FqInstance& fqInstance, std::string* error) const {
+    if (fqInstance.hasPackage() && fqInstance.getPackage() != this->getName()) {
+        if (error) {
+            *error = "Should not add \"" + fqInstance.string() + "\" to a HAL with name " +
+                     this->getName();
         }
-        if (!fqInstance.hasVersion()) {
-            if (error) *error = "Should specify version: \"" + fqInstance.string() + "\"";
-            return false;
-        }
-        if (!fqInstance.hasInterface()) {
-            if (error) *error = "Should specify interface: \"" + fqInstance.string() + "\"";
-            return false;
-        }
-        if (!fqInstance.hasInstance()) {
-            if (error) *error = "Should specify instance: \"" + fqInstance.string() + "\"";
-            return false;
-        }
+        return false;
+    }
+    if (!fqInstance.hasVersion()) {
+        if (error) *error = "Should specify version: \"" + fqInstance.string() + "\"";
+        return false;
+    }
+    if (!fqInstance.hasInterface()) {
+        if (error) *error = "Should specify interface: \"" + fqInstance.string() + "\"";
+        return false;
+    }
+    if (!fqInstance.hasInstance()) {
+        if (error) *error = "Should specify instance: \"" + fqInstance.string() + "\"";
+        return false;
     }
     return true;
 }
 
 bool ManifestHal::insertInstances(const std::set<FqInstance>& fqInstances, std::string* error) {
-    if (!verifyInstances(fqInstances, error)) {
-        return false;
-    }
-
     for (const FqInstance& e : fqInstances) {
-        FqInstance withPackage;
-        if (!withPackage.setTo(this->getName(), e.getMajorVersion(), e.getMinorVersion(),
-                               e.getInterface(), e.getInstance())) {
-            if (error) {
-                *error = "Cannot create FqInstance with package='" + this->getName() +
-                         "', version='" + to_string(Version(e.getVersion())) + "', interface='" +
-                         e.getInterface() + "', instance='" + e.getInstance() + "'";
-            }
+        if (!insertInstance(e, error)) {
             return false;
         }
-        mAdditionalInstances.emplace(std::move(withPackage), this->transportArch, this->format);
     }
-
     return true;
 }
 
-void ManifestHal::insertLegacyInstance(const std::string& interface, const std::string& instance) {
-    auto it = interfaces.find(interface);
-    if (it == interfaces.end())
-        it = interfaces.emplace(interface, HalInterface{interface, {}}).first;
-    it->second.insertInstance(instance, false /* isRegex */);
+bool ManifestHal::insertInstance(const FqInstance& e, std::string* error) {
+    if (!verifyInstance(e, error)) {
+        return false;
+    }
+
+    size_t minorVer = e.getMinorVersion();
+    for (auto it = mAdditionalInstances.begin(); it != mAdditionalInstances.end();) {
+        if (it->version().majorVer == e.getMajorVersion() && it->interface() == e.getInterface() &&
+            it->instance() == e.getInstance()) {
+            minorVer = std::max(minorVer, it->version().minorVer);
+            it = mAdditionalInstances.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    FqInstance toAdd;
+    if (!toAdd.setTo(this->getName(), e.getMajorVersion(), minorVer, e.getInterface(),
+                     e.getInstance())) {
+        if (error) {
+            *error = "Cannot create FqInstance with package='" + this->getName() + "', version='" +
+                     to_string(Version(e.getMajorVersion(), minorVer)) + "', interface='" +
+                     e.getInterface() + "', instance='" + e.getInstance() + "'";
+        }
+        return false;
+    }
+
+    mAdditionalInstances.emplace(std::move(toAdd), this->transportArch, this->format);
+    return true;
 }
 
 } // namespace vintf
diff --git a/ManifestInstance.cpp b/ManifestInstance.cpp
index 8bcf531..320ba3f 100644
--- a/ManifestInstance.cpp
+++ b/ManifestInstance.cpp
@@ -30,11 +30,11 @@
 
 ManifestInstance::ManifestInstance(const ManifestInstance&) = default;
 
-ManifestInstance::ManifestInstance(ManifestInstance&&) = default;
+ManifestInstance::ManifestInstance(ManifestInstance&&) noexcept = default;
 
 ManifestInstance& ManifestInstance::operator=(const ManifestInstance&) = default;
 
-ManifestInstance& ManifestInstance::operator=(ManifestInstance&&) = default;
+ManifestInstance& ManifestInstance::operator=(ManifestInstance&&) noexcept = default;
 
 ManifestInstance::ManifestInstance(FqInstance&& fqInstance, TransportArch&& ta, HalFormat fmt)
     : mFqInstance(std::move(fqInstance)), mTransportArch(std::move(ta)), mHalFormat(fmt) {}
diff --git a/MatrixInstance.cpp b/MatrixInstance.cpp
index e4e731e..f6eb548 100644
--- a/MatrixInstance.cpp
+++ b/MatrixInstance.cpp
@@ -27,11 +27,11 @@
 
 MatrixInstance::MatrixInstance(const MatrixInstance&) = default;
 
-MatrixInstance::MatrixInstance(MatrixInstance&&) = default;
+MatrixInstance::MatrixInstance(MatrixInstance&&) noexcept = default;
 
 MatrixInstance& MatrixInstance::operator=(const MatrixInstance&) = default;
 
-MatrixInstance& MatrixInstance::operator=(MatrixInstance&&) = default;
+MatrixInstance& MatrixInstance::operator=(MatrixInstance&&) noexcept = default;
 
 MatrixInstance::MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional,
                                bool isRegex)
diff --git a/PropertyFetcher.cpp b/PropertyFetcher.cpp
new file mode 100644
index 0000000..d406262
--- /dev/null
+++ b/PropertyFetcher.cpp
@@ -0,0 +1,57 @@
+
+/*
+ * 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"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+namespace android {
+namespace vintf {
+namespace details {
+
+std::string PropertyFetcherNoOp::getProperty(const std::string&,
+                                             const std::string& defaultValue) const {
+    return defaultValue;
+}
+
+uint64_t PropertyFetcherNoOp::getUintProperty(const std::string&, uint64_t,
+                                              uint64_t defaultValue) const {
+    return defaultValue;
+}
+
+bool PropertyFetcherNoOp::getBoolProperty(const std::string&, bool defaultValue) const {
+    return defaultValue;
+}
+
+std::string PropertyFetcherImpl::getProperty(const std::string& key,
+                                             const std::string& defaultValue) const {
+    return android::base::GetProperty(key, defaultValue);
+}
+
+uint64_t PropertyFetcherImpl::getUintProperty(const std::string& key, uint64_t defaultValue,
+                                              uint64_t max) const {
+    return android::base::GetUintProperty(key, defaultValue, max);
+}
+
+bool PropertyFetcherImpl::getBoolProperty(const std::string& key, bool defaultValue) const {
+    return android::base::GetBoolProperty(key, defaultValue);
+}
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/RuntimeInfo.cpp b/RuntimeInfo.cpp
index 63a8c18..2338cd2 100644
--- a/RuntimeInfo.cpp
+++ b/RuntimeInfo.cpp
@@ -102,7 +102,7 @@
 }
 
 bool RuntimeInfo::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
-                                     DisabledChecks disabledChecks) const {
+                                     CheckFlags::Type flags) const {
     if (mat.mType != SchemaType::FRAMEWORK) {
         if (error != nullptr) {
             *error = "Should not check runtime info against " + to_string(mat.mType)
@@ -122,46 +122,48 @@
     // mat.mSepolicy.sepolicyVersion() is checked against static
     // HalManifest.device.mSepolicyVersion in HalManifest::checkCompatibility.
 
-    bool foundMatchedKernelVersion = false;
-    bool foundMatchedConditions = false;
-    for (const MatrixKernel& matrixKernel : mat.framework.mKernels) {
-        if (!matchKernelVersion(matrixKernel.minLts())) {
-            continue;
+    if (flags.isKernelEnabled()) {
+        bool foundMatchedKernelVersion = false;
+        bool foundMatchedConditions = false;
+        for (const MatrixKernel& matrixKernel : mat.framework.mKernels) {
+            if (!matchKernelVersion(matrixKernel.minLts())) {
+                continue;
+            }
+            foundMatchedKernelVersion = true;
+            // ignore this fragment if not all conditions are met.
+            if (!matchKernelConfigs(matrixKernel.conditions(), error)) {
+                continue;
+            }
+            foundMatchedConditions = true;
+            if (!matchKernelConfigs(matrixKernel.configs(), error)) {
+                return false;
+            }
         }
-        foundMatchedKernelVersion = true;
-        // ignore this fragment if not all conditions are met.
-        if (!matchKernelConfigs(matrixKernel.conditions(), error)) {
-            continue;
-        }
-        foundMatchedConditions = true;
-        if (!matchKernelConfigs(matrixKernel.configs(), error)) {
+        if (!foundMatchedKernelVersion) {
+            if (error != nullptr) {
+                std::stringstream ss;
+                ss << "Framework is incompatible with kernel version " << mKernelVersion
+                   << ", compatible kernel versions are";
+                for (const MatrixKernel& matrixKernel : mat.framework.mKernels)
+                    ss << " " << matrixKernel.minLts();
+                *error = ss.str();
+            }
             return false;
         }
-    }
-    if (!foundMatchedKernelVersion) {
-        if (error != nullptr) {
-            std::stringstream ss;
-            ss << "Framework is incompatible with kernel version " << mKernelVersion
-               << ", compatible kernel versions are";
-            for (const MatrixKernel& matrixKernel : mat.framework.mKernels)
-                ss << " " << matrixKernel.minLts();
-            *error = ss.str();
+        if (!foundMatchedConditions) {
+            // This should not happen because first <conditions> for each <kernel> must be
+            // empty. Reject here for inconsistency.
+            if (error != nullptr) {
+                error->insert(0, "Framework match kernel version with unmet conditions:");
+            }
+            return false;
         }
-        return false;
-    }
-    if (!foundMatchedConditions) {
-        // This should not happen because first <conditions> for each <kernel> must be
-        // empty. Reject here for inconsistency.
         if (error != nullptr) {
-            error->insert(0, "Framework match kernel version with unmet conditions:");
+            error->clear();
         }
-        return false;
-    }
-    if (error != nullptr) {
-        error->clear();
     }
 
-    if ((disabledChecks & DISABLE_AVB_CHECK) == 0) {
+    if (flags.isAvbEnabled()) {
         const Version& matAvb = mat.framework.mAvbMetaVersion;
         if (mBootAvbVersion.majorVer != matAvb.majorVer ||
             mBootAvbVersion.minorVer < matAvb.minorVer) {
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 604f7cb..aed9745 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -37,18 +37,11 @@
 
 using namespace details;
 
-template <typename T>
-struct LockedSharedPtr {
-    std::shared_ptr<T> object;
-    std::mutex mutex;
-    bool fetchedOnce = false;
-};
-
-struct LockedRuntimeInfoCache {
-    std::shared_ptr<RuntimeInfo> object;
-    std::mutex mutex;
-    RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
-};
+#ifdef LIBVINTF_TARGET
+static constexpr bool kIsTarget = true;
+#else
+static constexpr bool kIsTarget = false;
+#endif
 
 template <typename T, typename F>
 static std::shared_ptr<const T> Get(
@@ -68,51 +61,102 @@
     return ptr->object;
 }
 
-// static
+static std::unique_ptr<FileSystem> createDefaultFileSystem() {
+    std::unique_ptr<FileSystem> fileSystem;
+    if (kIsTarget) {
+        fileSystem = std::make_unique<details::FileSystemImpl>();
+    } else {
+        fileSystem = std::make_unique<details::FileSystemNoOp>();
+    }
+    return fileSystem;
+}
+
+static std::unique_ptr<PropertyFetcher> createDefaultPropertyFetcher() {
+    std::unique_ptr<PropertyFetcher> propertyFetcher;
+    if (kIsTarget) {
+        propertyFetcher = std::make_unique<details::PropertyFetcherImpl>();
+    } else {
+        propertyFetcher = std::make_unique<details::PropertyFetcherNoOp>();
+    }
+    return propertyFetcher;
+}
+
+VintfObject::VintfObject(std::unique_ptr<FileSystem>&& fileSystem,
+                         std::unique_ptr<details::PartitionMounter>&& partitionMounter,
+                         std::unique_ptr<details::ObjectFactory<RuntimeInfo>>&& runtimeInfoFactory,
+                         std::unique_ptr<details::PropertyFetcher>&& propertyFetcher)
+    : mFileSystem(fileSystem ? std::move(fileSystem) : createDefaultFileSystem()),
+      mPartitionMounter(partitionMounter ? std::move(partitionMounter)
+                                         : std::make_unique<details::PartitionMounter>()),
+      mRuntimeInfoFactory(runtimeInfoFactory
+                              ? std::move(runtimeInfoFactory)
+                              : std::make_unique<details::ObjectFactory<RuntimeInfo>>()),
+      mPropertyFetcher(propertyFetcher ? std::move(propertyFetcher)
+                                       : createDefaultPropertyFetcher()) {}
+
+details::LockedSharedPtr<VintfObject> VintfObject::sInstance{};
+std::shared_ptr<VintfObject> VintfObject::GetInstance() {
+    std::unique_lock<std::mutex> lock(sInstance.mutex);
+    if (sInstance.object == nullptr) {
+        sInstance.object = std::make_shared<VintfObject>();
+    }
+    return sInstance.object;
+}
+
 std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
-    static LockedSharedPtr<HalManifest> gVendorManifest;
-    return Get(&gVendorManifest, skipCache, &VintfObject::FetchDeviceHalManifest);
+    return GetInstance()->getDeviceHalManifest(skipCache);
 }
 
-// static
+std::shared_ptr<const HalManifest> VintfObject::getDeviceHalManifest(bool skipCache) {
+    return Get(&mDeviceManifest, skipCache,
+               std::bind(&VintfObject::fetchDeviceHalManifest, this, _1, _2));
+}
+
 std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
-    static LockedSharedPtr<HalManifest> gFrameworkManifest;
-    return Get(&gFrameworkManifest, skipCache, &VintfObject::FetchFrameworkHalManifest);
+    return GetInstance()->getFrameworkHalManifest(skipCache);
 }
 
+std::shared_ptr<const HalManifest> VintfObject::getFrameworkHalManifest(bool skipCache) {
+    return Get(&mFrameworkManifest, skipCache,
+               std::bind(&VintfObject::fetchFrameworkHalManifest, this, _1, _2));
+}
 
-// static
 std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
-    static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
-    return Get(&gDeviceMatrix, skipCache, &VintfObject::FetchDeviceMatrix);
+    return GetInstance()->getDeviceCompatibilityMatrix(skipCache);
 }
 
-// static
+std::shared_ptr<const CompatibilityMatrix> VintfObject::getDeviceCompatibilityMatrix(
+    bool skipCache) {
+    return Get(&mDeviceMatrix, skipCache, std::bind(&VintfObject::fetchDeviceMatrix, this, _1, _2));
+}
+
 std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
-    static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
-    static LockedSharedPtr<CompatibilityMatrix> gCombinedFrameworkMatrix;
-    static std::mutex gFrameworkCompatibilityMatrixMutex;
+    return GetInstance()->getFrameworkCompatibilityMatrix(skipCache);
+}
 
+std::shared_ptr<const CompatibilityMatrix> VintfObject::getFrameworkCompatibilityMatrix(
+    bool skipCache) {
     // To avoid deadlock, get device manifest before any locks.
-    auto deviceManifest = GetDeviceHalManifest();
+    auto deviceManifest = getDeviceHalManifest();
 
-    std::unique_lock<std::mutex> _lock(gFrameworkCompatibilityMatrixMutex);
+    std::unique_lock<std::mutex> _lock(mFrameworkCompatibilityMatrixMutex);
 
     auto combined =
-        Get(&gCombinedFrameworkMatrix, skipCache,
-            std::bind(&VintfObject::GetCombinedFrameworkMatrix, deviceManifest, _1, _2));
+        Get(&mCombinedFrameworkMatrix, skipCache,
+            std::bind(&VintfObject::getCombinedFrameworkMatrix, this, deviceManifest, _1, _2));
     if (combined != nullptr) {
         return combined;
     }
 
-    return Get(&gFrameworkMatrix, skipCache,
-               std::bind(&CompatibilityMatrix::fetchAllInformation, _1, kSystemLegacyMatrix, _2));
+    return Get(&mFrameworkMatrix, skipCache,
+               std::bind(&CompatibilityMatrix::fetchAllInformation, _1, mFileSystem.get(),
+                         kSystemLegacyMatrix, _2));
 }
 
-status_t VintfObject::GetCombinedFrameworkMatrix(
+status_t VintfObject::getCombinedFrameworkMatrix(
     const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out,
     std::string* error) {
-    auto matrixFragments = GetAllFrameworkMatrixLevels(error);
+    auto matrixFragments = getAllFrameworkMatrixLevels(error);
     if (matrixFragments.empty()) {
         return NAME_NOT_FOUND;
     }
@@ -125,7 +169,7 @@
 
     // TODO(b/70628538): Do not infer from Shipping API level.
     if (deviceLevel == Level::UNSPECIFIED) {
-        auto shippingApi = getPropertyFetcher().getUintProperty("ro.product.first_api_level", 0u);
+        auto shippingApi = mPropertyFetcher->getUintProperty("ro.product.first_api_level", 0u);
         if (shippingApi != 0u) {
             deviceLevel = details::convertFromApiLevel(shippingApi);
         }
@@ -152,8 +196,7 @@
         return NAME_NOT_FOUND;
     }
 
-    CompatibilityMatrix* combined =
-        CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error);
+    auto combined = CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error);
     if (combined == nullptr) {
         return BAD_VALUE;
     }
@@ -161,21 +204,50 @@
     return OK;
 }
 
+// Load and combine all of the manifests in a directory
+status_t VintfObject::addDirectoryManifests(const std::string& directory, HalManifest* manifest,
+                                            std::string* error) {
+    std::vector<std::string> fileNames;
+    status_t err = mFileSystem->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;
+
+    for (const std::string& file : fileNames) {
+        // Only adds HALs because all other things are added by libvintf
+        // itself for now.
+        HalManifest fragmentManifest;
+        err = fetchOneHalManifest(directory + file, &fragmentManifest, error);
+        if (err != OK) return err;
+
+        manifest->addAllHals(&fragmentManifest);
+    }
+
+    return OK;
+}
+
 // Priority for loading vendor manifest:
-// 1. /vendor/etc/vintf/manifest.xml + ODM manifest
-// 2. /vendor/etc/vintf/manifest.xml
-// 3. ODM manifest
-// 4. /vendor/manifest.xml
+// 1. /vendor/etc/vintf/manifest.xml + device fragments + ODM manifest (optional) + odm fragments
+// 2. /vendor/etc/vintf/manifest.xml + device fragments
+// 3. ODM manifest (optional) + odm fragments
+// 4. /vendor/manifest.xml (legacy, no fragments)
 // where:
 // A + B means adding <hal> tags from B to A (so that <hal>s from B can override A)
-status_t VintfObject::FetchDeviceHalManifest(HalManifest* out, std::string* error) {
-    status_t vendorStatus = FetchOneHalManifest(kVendorManifest, out, error);
+status_t VintfObject::fetchDeviceHalManifest(HalManifest* out, std::string* error) {
+    status_t vendorStatus = fetchOneHalManifest(kVendorManifest, out, error);
     if (vendorStatus != OK && vendorStatus != NAME_NOT_FOUND) {
         return vendorStatus;
     }
 
+    if (vendorStatus == OK) {
+        status_t fragmentStatus = addDirectoryManifests(kVendorManifestFragmentDir, out, error);
+        if (fragmentStatus != OK) {
+            return fragmentStatus;
+        }
+    }
+
     HalManifest odmManifest;
-    status_t odmStatus = FetchOdmHalManifest(&odmManifest, error);
+    status_t odmStatus = fetchOdmHalManifest(&odmManifest, error);
     if (odmStatus != OK && odmStatus != NAME_NOT_FOUND) {
         return odmStatus;
     }
@@ -184,17 +256,17 @@
         if (odmStatus == OK) {
             out->addAllHals(&odmManifest);
         }
-        return OK;
+        return addDirectoryManifests(kOdmManifestFragmentDir, out, error);
     }
 
     // vendorStatus != OK, "out" is not changed.
     if (odmStatus == OK) {
         *out = std::move(odmManifest);
-        return OK;
+        return addDirectoryManifests(kOdmManifestFragmentDir, out, error);
     }
 
     // Use legacy /vendor/manifest.xml
-    return out->fetchAllInformation(kVendorLegacyManifest, error);
+    return out->fetchAllInformation(mFileSystem.get(), kVendorLegacyManifest, error);
 }
 
 // "out" is written to iff return status is OK.
@@ -205,34 +277,34 @@
 // 4. /odm/etc/manifest.xml
 // where:
 // {sku} is the value of ro.boot.product.hardware.sku
-status_t VintfObject::FetchOdmHalManifest(HalManifest* out, std::string* error) {
+status_t VintfObject::fetchOdmHalManifest(HalManifest* out, std::string* error) {
     status_t status;
 
     std::string productModel;
-    productModel = getPropertyFetcher().getProperty("ro.boot.product.hardware.sku", "");
+    productModel = mPropertyFetcher->getProperty("ro.boot.product.hardware.sku", "");
 
     if (!productModel.empty()) {
         status =
-            FetchOneHalManifest(kOdmVintfDir + "manifest_" + productModel + ".xml", out, error);
+            fetchOneHalManifest(kOdmVintfDir + "manifest_" + productModel + ".xml", out, error);
         if (status == OK || status != NAME_NOT_FOUND) {
             return status;
         }
     }
 
-    status = FetchOneHalManifest(kOdmManifest, out, error);
+    status = fetchOneHalManifest(kOdmManifest, out, error);
     if (status == OK || status != NAME_NOT_FOUND) {
         return status;
     }
 
     if (!productModel.empty()) {
-        status = FetchOneHalManifest(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml", out,
+        status = fetchOneHalManifest(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml", out,
                                      error);
         if (status == OK || status != NAME_NOT_FOUND) {
             return status;
         }
     }
 
-    status = FetchOneHalManifest(kOdmLegacyManifest, out, error);
+    status = fetchOneHalManifest(kOdmLegacyManifest, out, error);
     if (status == OK || status != NAME_NOT_FOUND) {
         return status;
     }
@@ -242,40 +314,40 @@
 
 // Fetch one manifest.xml file. "out" is written to iff return status is OK.
 // Returns NAME_NOT_FOUND if file is missing.
-status_t VintfObject::FetchOneHalManifest(const std::string& path, HalManifest* out,
+status_t VintfObject::fetchOneHalManifest(const std::string& path, HalManifest* out,
                                           std::string* error) {
     HalManifest ret;
-    status_t status = ret.fetchAllInformation(path, error);
+    status_t status = ret.fetchAllInformation(mFileSystem.get(), path, error);
     if (status == OK) {
         *out = std::move(ret);
     }
     return status;
 }
 
-status_t VintfObject::FetchDeviceMatrix(CompatibilityMatrix* out, std::string* error) {
+status_t VintfObject::fetchDeviceMatrix(CompatibilityMatrix* out, std::string* error) {
     CompatibilityMatrix etcMatrix;
-    if (etcMatrix.fetchAllInformation(kVendorMatrix, error) == OK) {
+    if (etcMatrix.fetchAllInformation(mFileSystem.get(), kVendorMatrix, error) == OK) {
         *out = std::move(etcMatrix);
         return OK;
     }
-    return out->fetchAllInformation(kVendorLegacyMatrix, error);
+    return out->fetchAllInformation(mFileSystem.get(), kVendorLegacyMatrix, error);
 }
 
-status_t VintfObject::FetchFrameworkHalManifest(HalManifest* out, std::string* error) {
+status_t VintfObject::fetchFrameworkHalManifest(HalManifest* out, std::string* error) {
     HalManifest etcManifest;
-    if (etcManifest.fetchAllInformation(kSystemManifest, error) == OK) {
+    if (etcManifest.fetchAllInformation(mFileSystem.get(), kSystemManifest, error) == OK) {
         *out = std::move(etcManifest);
-        return OK;
+        return addDirectoryManifests(kSystemManifestFragmentDir, out, error);
     }
-    return out->fetchAllInformation(kSystemLegacyManifest, error);
+    return out->fetchAllInformation(mFileSystem.get(), kSystemLegacyManifest, error);
 }
 
-std::vector<Named<CompatibilityMatrix>> VintfObject::GetAllFrameworkMatrixLevels(
+std::vector<Named<CompatibilityMatrix>> VintfObject::getAllFrameworkMatrixLevels(
     std::string* error) {
     std::vector<std::string> fileNames;
     std::vector<Named<CompatibilityMatrix>> results;
 
-    if (details::gFetcher->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
+    if (mFileSystem->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
         return {};
     }
     for (const std::string& fileName : fileNames) {
@@ -283,7 +355,7 @@
 
         std::string content;
         std::string fetchError;
-        status_t status = details::gFetcher->fetch(path, content, &fetchError);
+        status_t status = mFileSystem->fetch(path, &content, &fetchError);
         if (status != OK) {
             if (error) {
                 *error += "Framework Matrix: Ignore file " + path + ": " + fetchError + "\n";
@@ -316,28 +388,30 @@
     return results;
 }
 
-// static
 std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
                                                                RuntimeInfo::FetchFlags flags) {
-    static LockedRuntimeInfoCache gDeviceRuntimeInfo;
-    std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
+    return GetInstance()->getRuntimeInfo(skipCache, flags);
+}
+std::shared_ptr<const RuntimeInfo> VintfObject::getRuntimeInfo(bool skipCache,
+                                                               RuntimeInfo::FetchFlags flags) {
+    std::unique_lock<std::mutex> _lock(mDeviceRuntimeInfo.mutex);
 
     if (!skipCache) {
-        flags &= (~gDeviceRuntimeInfo.fetchedFlags);
+        flags &= (~mDeviceRuntimeInfo.fetchedFlags);
     }
 
-    if (gDeviceRuntimeInfo.object == nullptr) {
-        gDeviceRuntimeInfo.object = details::gRuntimeInfoFactory->make_shared();
+    if (mDeviceRuntimeInfo.object == nullptr) {
+        mDeviceRuntimeInfo.object = mRuntimeInfoFactory->make_shared();
     }
 
-    status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
+    status_t status = mDeviceRuntimeInfo.object->fetchAllInformation(flags);
     if (status != OK) {
-        gDeviceRuntimeInfo.fetchedFlags &= (~flags);  // mark the fields as "not fetched"
+        mDeviceRuntimeInfo.fetchedFlags &= (~flags);  // mark the fields as "not fetched"
         return nullptr;
     }
 
-    gDeviceRuntimeInfo.fetchedFlags |= flags;
-    return gDeviceRuntimeInfo.object;
+    mDeviceRuntimeInfo.fetchedFlags |= flags;
+    return mDeviceRuntimeInfo.object;
 }
 
 namespace details {
@@ -380,27 +454,32 @@
     return ParseStatus::OK;
 }
 
-template<typename T, typename GetFunction>
-static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
-        std::function<status_t(void)> mountFunction,
-        std::shared_ptr<const T>* updated,
-        GetFunction getFunction) {
+static void appendLine(std::string* error, const std::string& message) {
+    if (error != nullptr) {
+        if (!error->empty()) *error += "\n";
+        *error += message;
+    }
+}
+
+template <typename T, typename GetFunction>
+static status_t getMissing(const std::string& msg, const std::shared_ptr<T>& pkg, bool mount,
+                           std::function<status_t(void)> mountFunction,
+                           std::shared_ptr<const T>* updated, GetFunction getFunction,
+                           std::string* error) {
     if (pkg != nullptr) {
         *updated = pkg;
     } else {
         if (mount) {
-            (void)mountFunction(); // ignore mount errors
+            status_t mountStatus = mountFunction();
+            if (mountStatus != OK) {
+                appendLine(error, "warning: mount " + msg + " failed: " + strerror(-mountStatus));
+            }
         }
         *updated = getFunction();
     }
     return OK;
 }
 
-#define ADD_MESSAGE(__error__)  \
-    if (error != nullptr) {     \
-        *error += (__error__);  \
-    }                           \
-
 struct PackageInfo {
     struct Pair {
         std::shared_ptr<HalManifest>         manifest;
@@ -420,12 +499,13 @@
     std::shared_ptr<const RuntimeInfo> runtimeInfo;
 };
 
+}  // namespace details
+
 // 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,
-                           const PartitionMounter& mounter, std::string* error,
-                           DisabledChecks disabledChecks) {
+int32_t VintfObject::checkCompatibility(const std::vector<std::string>& xmls, bool mount,
+                                        std::string* error, CheckFlags::Type flags) {
     status_t status;
     ParseStatus parseStatus;
     PackageInfo pkg; // All information from package.
@@ -438,7 +518,7 @@
             continue; // work on next one
         }
         if (parseStatus != ParseStatus::PARSE_ERROR) {
-            ADD_MESSAGE(toString(parseStatus) + " manifest");
+            appendLine(error, toString(parseStatus) + " manifest");
             return ALREADY_EXISTS;
         }
         parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
@@ -446,72 +526,84 @@
             continue; // work on next one
         }
         if (parseStatus != ParseStatus::PARSE_ERROR) {
-            ADD_MESSAGE(toString(parseStatus) + " matrix");
+            appendLine(error, toString(parseStatus) + " matrix");
             return ALREADY_EXISTS;
         }
-        ADD_MESSAGE(toString(parseStatus)); // parse error
+        appendLine(error, toString(parseStatus));  // parse error
         return BAD_VALUE;
     }
 
     // get missing info from device
     // use functions instead of std::bind because std::bind doesn't work well with mock objects
-    auto mountSystem = [&mounter] { return mounter.mountSystem(); };
-    auto mountVendor = [&mounter] { return mounter.mountVendor(); };
+    auto mountSystem = [this] { return this->mPartitionMounter->mountSystem(); };
+    auto mountVendor = [this] { return this->mPartitionMounter->mountVendor(); };
     if ((status = getMissing(
-             pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
-             std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
+             "system", pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
+             std::bind(&VintfObject::getFrameworkHalManifest, this, true /* skipCache */),
+             error)) != OK) {
+        return status;
+    }
+    if ((status =
+             getMissing("vendor", pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
+                        std::bind(&VintfObject::getDeviceHalManifest, this, true /* skipCache */),
+                        error)) != OK) {
         return status;
     }
     if ((status = getMissing(
-             pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
-             std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
+             "system", pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
+             std::bind(&VintfObject::getFrameworkCompatibilityMatrix, this, true /* skipCache */),
+             error)) != OK) {
         return status;
     }
     if ((status = getMissing(
-             pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
-             std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
-        OK) {
-        return status;
-    }
-    if ((status = getMissing(
-             pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
-             std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
+             "vendor", pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
+             std::bind(&VintfObject::getDeviceCompatibilityMatrix, this, true /* skipCache */),
+             error)) != OK) {
         return status;
     }
 
     if (mount) {
-        (void)mounter.umountSystem(); // ignore errors
-        (void)mounter.umountVendor(); // ignore errors
+        status_t umountStatus = mPartitionMounter->umountSystem();
+        if (umountStatus != OK) {
+            appendLine(error,
+                       std::string{"warning: umount system failed: "} + strerror(-umountStatus));
+        }
+        umountStatus = mPartitionMounter->umountVendor();
+        if (umountStatus != OK) {
+            appendLine(error,
+                       std::string{"warning: umount vendor failed: "} + strerror(-umountStatus));
+        }
     }
 
-    if ((disabledChecks & DISABLE_RUNTIME_INFO) == 0) {
-        updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
+    if (flags.isRuntimeInfoEnabled()) {
+        updated.runtimeInfo = getRuntimeInfo(true /* skipCache */);
     }
 
     // null checks for files and runtime info after the update
     if (updated.fwk.manifest == nullptr) {
-        ADD_MESSAGE("No framework manifest file from device or from update package");
-        return NO_INIT;
+        appendLine(error, "No framework manifest file from device or from update package");
+        status = NO_INIT;
     }
     if (updated.dev.manifest == nullptr) {
-        ADD_MESSAGE("No device manifest file from device or from update package");
-        return NO_INIT;
+        appendLine(error, "No device manifest file from device or from update package");
+        status = NO_INIT;
     }
     if (updated.fwk.matrix == nullptr) {
-        ADD_MESSAGE("No framework matrix file from device or from update package");
-        return NO_INIT;
+        appendLine(error, "No framework matrix file from device or from update package");
+        status = NO_INIT;
     }
     if (updated.dev.matrix == nullptr) {
-        ADD_MESSAGE("No device matrix file from device or from update package");
-        return NO_INIT;
+        appendLine(error, "No device matrix file from device or from update package");
+        status = NO_INIT;
     }
 
-    if ((disabledChecks & DISABLE_RUNTIME_INFO) == 0) {
+    if (flags.isRuntimeInfoEnabled()) {
         if (updated.runtimeInfo == nullptr) {
-            ADD_MESSAGE("No runtime info from device");
-            return NO_INIT;
+            appendLine(error, "No runtime info from device");
+            status = NO_INIT;
         }
     }
+    if (status != OK) return status;
 
     // compatiblity check.
     if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
@@ -529,8 +621,8 @@
         return INCOMPATIBLE;
     }
 
-    if ((disabledChecks & DISABLE_RUNTIME_INFO) == 0) {
-        if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
+    if (flags.isRuntimeInfoEnabled()) {
+        if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, flags)) {
             if (error) {
                 error->insert(0,
                               "Runtime info and framework compatibility matrix are incompatible: ");
@@ -542,6 +634,8 @@
     return COMPATIBLE;
 }
 
+namespace details {
+
 const std::string kSystemVintfDir = "/system/etc/vintf/";
 const std::string kVendorVintfDir = "/vendor/etc/vintf/";
 const std::string kOdmVintfDir = "/odm/etc/vintf/";
@@ -551,6 +645,10 @@
 const std::string kVendorMatrix = kVendorVintfDir + "compatibility_matrix.xml";
 const std::string kOdmManifest = kOdmVintfDir + "manifest.xml";
 
+const std::string kVendorManifestFragmentDir = kVendorVintfDir + "manifest/";
+const std::string kSystemManifestFragmentDir = kSystemVintfDir + "manifest/";
+const std::string kOdmManifestFragmentDir = kOdmVintfDir + "manifest/";
+
 const std::string kVendorLegacyManifest = "/vendor/manifest.xml";
 const std::string kVendorLegacyMatrix = "/vendor/compatibility_matrix.xml";
 const std::string kSystemLegacyManifest = "/system/manifest.xml";
@@ -566,21 +664,24 @@
     };
 }
 
-} // namespace details
+}  // namespace details
 
-// static
 int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
-                                        DisabledChecks disabledChecks) {
-    return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
-                                       disabledChecks);
+                                        CheckFlags::Type flags) {
+    return GetInstance()->checkCompatibility(xmls, error, flags);
 }
 
-bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal,
+int32_t VintfObject::checkCompatibility(const std::vector<std::string>& xmls, std::string* error,
+                                        CheckFlags::Type flags) {
+    return checkCompatibility(xmls, false /* mount */, error, flags);
+}
+
+bool VintfObject::IsHalDeprecated(const MatrixHal& oldMatrixHal,
                                   const CompatibilityMatrix& targetMatrix,
                                   const ListInstances& listInstances, std::string* error) {
     bool isDeprecated = false;
     oldMatrixHal.forEachInstance([&](const MatrixInstance& oldMatrixInstance) {
-        if (isInstanceDeprecated(oldMatrixInstance, targetMatrix, listInstances, error)) {
+        if (IsInstanceDeprecated(oldMatrixInstance, targetMatrix, listInstances, error)) {
             isDeprecated = true;
         }
         return !isDeprecated;  // continue if no deprecated instance is found.
@@ -594,7 +695,7 @@
 // 1. package@x.?::interface/servedInstance is not in targetMatrix; OR
 // 2. package@x.z::interface/servedInstance is in targetMatrix but
 //    servedInstance is not in listInstances(package@x.z::interface)
-bool VintfObject::isInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
+bool VintfObject::IsInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
                                        const CompatibilityMatrix& targetMatrix,
                                        const ListInstances& listInstances, std::string* error) {
     const std::string& package = oldMatrixInstance.package();
@@ -659,13 +760,16 @@
 }
 
 int32_t VintfObject::CheckDeprecation(const ListInstances& listInstances, std::string* error) {
-    auto matrixFragments = GetAllFrameworkMatrixLevels(error);
+    return GetInstance()->checkDeprecation(listInstances, error);
+}
+int32_t VintfObject::checkDeprecation(const ListInstances& listInstances, std::string* error) {
+    auto matrixFragments = getAllFrameworkMatrixLevels(error);
     if (matrixFragments.empty()) {
         if (error && error->empty())
             *error = "Cannot get framework matrix for each FCM version for unknown error.";
         return NAME_NOT_FOUND;
     }
-    auto deviceManifest = GetDeviceHalManifest();
+    auto deviceManifest = getDeviceHalManifest();
     if (deviceManifest == nullptr) {
         if (error) *error = "No device manifest.";
         return NAME_NOT_FOUND;
@@ -695,7 +799,7 @@
 
         const auto& oldMatrix = namedMatrix.object;
         for (const MatrixHal& hal : oldMatrix.getHals()) {
-            hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, listInstances, error);
+            hasDeprecatedHals |= IsHalDeprecated(hal, *targetMatrix, listInstances, error);
         }
     }
 
@@ -703,8 +807,11 @@
 }
 
 int32_t VintfObject::CheckDeprecation(std::string* error) {
+    return GetInstance()->checkDeprecation(error);
+}
+int32_t VintfObject::checkDeprecation(std::string* error) {
     using namespace std::placeholders;
-    auto deviceManifest = GetDeviceHalManifest();
+    auto deviceManifest = getDeviceHalManifest();
     ListInstances inManifest =
         [&deviceManifest](const std::string& package, Version version, const std::string& interface,
                           const std::vector<std::string>& /* hintInstances */) {
@@ -717,7 +824,23 @@
                 });
             return ret;
         };
-    return CheckDeprecation(inManifest, error);
+    return checkDeprecation(inManifest, error);
+}
+
+const std::unique_ptr<FileSystem>& VintfObject::getFileSystem() {
+    return mFileSystem;
+}
+
+const std::unique_ptr<PartitionMounter>& VintfObject::getPartitionMounter() {
+    return mPartitionMounter;
+}
+
+const std::unique_ptr<PropertyFetcher>& VintfObject::getPropertyFetcher() {
+    return mPropertyFetcher;
+}
+
+const std::unique_ptr<details::ObjectFactory<RuntimeInfo>>& VintfObject::getRuntimeInfoFactory() {
+    return mRuntimeInfoFactory;
 }
 
 } // namespace vintf
diff --git a/VintfObjectRecovery.cpp b/VintfObjectRecovery.cpp
index 9d7cab7..3303980 100644
--- a/VintfObjectRecovery.cpp
+++ b/VintfObjectRecovery.cpp
@@ -16,8 +16,11 @@
 
 #include "VintfObjectRecovery.h"
 
-#include <sys/mount.h>
 #include <fs_mgr.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <android-base/strings.h>
 
 #include "utils.h"
 
@@ -25,14 +28,20 @@
 namespace vintf {
 
 namespace details {
+using android::base::StartsWith;
 using FstabMgr = std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)>;
 
-static status_t mountAt(const FstabMgr &fstab, const char* path, const char* mount_point) {
+static const char* const kSystemImageRootDir = "/mnt/system";
+static const char* const kVendorImageRootDir = "/mnt/vendor";
+
+static status_t mountAt(const FstabMgr& fstab, const char* path, const char* mountPoint) {
+    mkdir(mountPoint, 0755);  // in case it doesn't already exist
+
     fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), path);
     if (rec == nullptr) {
         return UNKNOWN_ERROR;
     }
-    int result = mount(rec->blk_device, mount_point, rec->fs_type, rec->flags, rec->fs_options);
+    int result = mount(rec->blk_device, mountPoint, rec->fs_type, rec->flags, rec->fs_options);
     return result == 0 ? OK : -errno;
 }
 
@@ -42,36 +51,54 @@
 
 class RecoveryPartitionMounter : public PartitionMounter {
    public:
+    RecoveryPartitionMounter() : fstab_(defaultFstabMgr()) {}
     status_t mountSystem() const override {
-        FstabMgr fstab = defaultFstabMgr();
-        if (fstab == NULL) {
-            return UNKNOWN_ERROR;
-        }
-        if (getPropertyFetcher().getBoolProperty("ro.build.system_root_image", false)) {
-            return mountAt(fstab, "/", "/system_root");
+        if (!fstab_) return UNKNOWN_ERROR;
+        if (fs_mgr_get_entry_for_mount_point(fstab_.get(), "/system") == nullptr) {
+            return mount("/", kSystemImageRootDir);
         } else {
-            return mountAt(fstab, "/system", "/system");
+            return mount("/system", kSystemImageRootDir);
         }
     }
 
-    status_t mountVendor() const override {
-        FstabMgr fstab = defaultFstabMgr();
-        if (fstab == NULL) {
-            return UNKNOWN_ERROR;
-        }
-        return mountAt(fstab, "/vendor", "/vendor");
+    status_t mountVendor() const override { return mount("/vendor", kVendorImageRootDir); }
+
+    status_t umountSystem() const override { return umount(kSystemImageRootDir); }
+
+    status_t umountVendor() const override { return umount(kVendorImageRootDir); }
+
+   private:
+    FstabMgr fstab_;
+
+    status_t mount(const char* path, const char* mountPoint) const {
+        if (!fstab_) return UNKNOWN_ERROR;
+        return mountAt(fstab_, path, mountPoint);
+    }
+};
+
+class RecoveryFileSystem : public FileSystem {
+   public:
+    RecoveryFileSystem() = default;
+
+    status_t fetch(const std::string& path, std::string* fetched, std::string* error) const {
+        return getFileSystem(path).fetch(path, fetched, error);
     }
 
-    status_t umountSystem() const override {
-        if (getPropertyFetcher().getBoolProperty("ro.build.system_root_image", false)) {
-            return umount("/system_root");
-        } else {
-            return umount("/system");
-        }
+    status_t listFiles(const std::string& path, std::vector<std::string>* out,
+                       std::string* error) const {
+        return getFileSystem(path).listFiles(path, out, error);
     }
 
-    status_t umountVendor() const override {
-        return umount("/vendor");
+   private:
+    FileSystemUnderPath mSystemFileSystem{"/mnt/system"};
+    FileSystemUnderPath mMntFileSystem{"/mnt"};
+
+    const FileSystemUnderPath& getFileSystem(const std::string& path) const {
+        // /system files are under /mnt/system/system because system.img contains the root dir.
+        if (StartsWith(path, "/system")) {
+            return mSystemFileSystem;
+        }
+        return mMntFileSystem;
     }
 };
 
@@ -80,8 +107,13 @@
 // static
 int32_t VintfObjectRecovery::CheckCompatibility(
         const std::vector<std::string> &xmls, std::string *error) {
-    static details::RecoveryPartitionMounter mounter;
-    return details::checkCompatibility(xmls, true /* mount */, mounter, error);
+    auto propertyFetcher = std::make_unique<details::PropertyFetcherImpl>();
+    auto mounter = std::make_unique<details::RecoveryPartitionMounter>();
+    auto fileSystem = std::make_unique<details::RecoveryFileSystem>();
+    auto vintfObject = std::make_unique<VintfObject>(std::move(fileSystem), std::move(mounter),
+                                                     nullptr /* runtime info factory */,
+                                                     std::move(propertyFetcher));
+    return vintfObject->checkCompatibility(xmls, true /* mount */, error);
 }
 
 
diff --git a/assemble_vintf_main.cpp b/assemble_vintf_main.cpp
index 45e6dc2..2733261 100644
--- a/assemble_vintf_main.cpp
+++ b/assemble_vintf_main.cpp
@@ -34,7 +34,8 @@
                  "               A list of input files. Format is automatically detected for the\n"
                  "               first file, and the remaining files must have the same format.\n"
                  "               Files other than the first file should only have <hal> defined;\n"
-                 "               other entries are ignored.\n"
+                 "               other entries are ignored. Argument may also be specified\n"
+                 "               multiple times.\n"
                  "    -o <output file>\n"
                  "               Optional output file. If not specified, write to stdout.\n"
                  "    -m\n"
@@ -43,24 +44,29 @@
                  "               a framework compatibility matrix is generated. This flag\n"
                  "               is ignored when input is a compatibility matrix.\n"
                  "    -c [<check file>]\n"
-                 "               After writing the output file, check compatibility between\n"
-                 "               output file and check file.\n"
-                 "               If -c is set but the check file is not specified, a warning\n"
-                 "               message is written to stderr. Return 0.\n"
-                 "               If the check file is specified but is not compatible, an error\n"
-                 "               message is written to stderr. Return 1.\n"
-                 "    --kernel=<version>:<android-base.cfg>[:<android-base-arch.cfg>[...]]\n"
+                 "               The path of the \"check file\"; for example, this is the path\n"
+                 "               of the device manifest for framework compatibility matrix.\n"
+                 "               After writing the output file, the program checks against\n"
+                 "               the \"check file\", depending on environment variables.\n"
+                 "               - PRODUCT_ENFORCE_VINTF_MANIFEST=true: check compatibility\n"
+                 "               - VINTF_ENFORCE_NO_UNUSED_HALS  =true: check unused HALs\n"
+                 "               If any check fails, an error message is written to stderr.\n"
+                 "               Return 1.\n"
+                 "    --kernel=<version>:<android-base.config>[:<android-base-arch.config>[...]]\n"
                  "               Add a kernel entry to framework compatibility matrix.\n"
                  "               Ignored for other input format.\n"
-                 "               <version> has format: 3.18\n"
-                 "               <android-base.cfg> is the location of android-base.cfg\n"
-                 "               <android-base-arch.cfg> is the location of an optional\n"
+                 "               <version> has format: 3.18.0\n"
+                 "               <android-base.config> is the location of android-base.config\n"
+                 "               <android-base-arch.config> is the location of an optional\n"
                  "               arch-specific config fragment, more than one may be specified\n"
                  "    -l, --hals-only\n"
                  "               Output has only <hal> entries. Cannot be used with -n.\n"
                  "    -n, --no-hals\n"
                  "               Output has no <hal> entries (but all other entries).\n"
-                 "               Cannot be used with -l.\n";
+                 "               Cannot be used with -l.\n"
+                 "    --no-kernel-requirements\n"
+                 "               Output has no <config> entries in <kernel>, and kernel minor\n"
+                 "               version is set to zero. (For example, 3.18.0).\n";
 }
 
 int main(int argc, char** argv) {
@@ -68,6 +74,7 @@
     const struct option longopts[] = {{"kernel", required_argument, NULL, 'k'},
                                       {"hals-only", no_argument, NULL, 'l'},
                                       {"no-hals", no_argument, NULL, 'n'},
+                                      {"no-kernel-requirements", no_argument, NULL, 'K'},
                                       {0, 0, 0, 0}};
 
     std::string outFilePath;
@@ -123,6 +130,12 @@
                 }
             } break;
 
+            case 'K': {
+                if (!assembleVintf->setNoKernelRequirements()) {
+                    return 1;
+                }
+            } break;
+
             case 'h':
             default: {
                 help();
diff --git a/check_vintf.cpp b/check_vintf.cpp
index 6acc311..7e51e6c 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -43,37 +43,28 @@
 // command line arguments
 using Args = std::multimap<Option, std::string>;
 
-class HostFileFetcher : public FileFetcher {
+class HostFileSystem : public FileSystemUnderPath {
    public:
-    void setRootDir(const std::string& rootdir) {
-        mRootDir = rootdir;
-        if (!mRootDir.empty() && mRootDir.back() != '/') {
-            mRootDir.push_back('/');
-        }
+    HostFileSystem(const std::string& rootdir) : FileSystemUnderPath(rootdir) {}
+    status_t fetch(const std::string& path, std::string* fetched,
+                   std::string* error) const override {
+        status_t status = FileSystemUnderPath::fetch(path, fetched, error);
+        std::cerr << "Debug: Fetch '" << getRootDir() << path << "': " << toString(status)
+                  << std::endl;
+        return status;
     }
-    virtual status_t fetch(const std::string& path, std::string& fetched, std::string* error) {
-        return HostFileFetcher::fetchInternal(path, fetched, error);
-    }
-    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);
-        std::cerr << "Debug: List '" << mRootDir << path << "': " << toString(status) << std::endl;
+    status_t listFiles(const std::string& path, std::vector<std::string>* out,
+                       std::string* error) const override {
+        status_t status = FileSystemUnderPath::listFiles(path, out, error);
+        std::cerr << "Debug: List '" << getRootDir() << 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;
 };
 
 class PresetPropertyFetcher : public PropertyFetcher {
@@ -111,27 +102,13 @@
     std::map<std::string, std::string> mProps;
 };
 
-// globals
-static HostFileFetcher hostFileFetcher;
-FileFetcher* gFetcher = &hostFileFetcher;
-
-static PartitionMounter partitionMounter;
-PartitionMounter* gPartitionMounter = &partitionMounter;
-
-static ObjectFactory<RuntimeInfo> runtimeInfoFactory;
-ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory = &runtimeInfoFactory;
-
-static PresetPropertyFetcher hostPropertyFetcher;
-const PropertyFetcher& getPropertyFetcher() {
-    return hostPropertyFetcher;
-}
-
 // helper functions
 template <typename T>
-std::unique_ptr<T> readObject(const std::string& path, const XmlConverter<T>& converter) {
+std::unique_ptr<T> readObject(FileSystem* fileSystem, 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 = fileSystem->fetch(path, &xml, &error);
     if (err != OK) {
         std::cerr << "Error: Cannot read '" << path << "' (" << strerror(-err) << "): " << error
                   << std::endl;
@@ -146,8 +123,9 @@
 }
 
 int checkCompatibilityForFiles(const std::string& manifestPath, const std::string& matrixPath) {
-    auto manifest = readObject(manifestPath, gHalManifestConverter);
-    auto matrix = readObject(matrixPath, gCompatibilityMatrixConverter);
+    auto fileSystem = std::make_unique<FileSystemImpl>();
+    auto manifest = readObject(fileSystem.get(), manifestPath, gHalManifestConverter);
+    auto matrix = readObject(fileSystem.get(), matrixPath, gCompatibilityMatrixConverter);
     if (manifest == nullptr || matrix == nullptr) {
         return -1;
     }
@@ -242,10 +220,13 @@
 }
 
 int checkAllFiles(const std::string& rootdir, const Properties& props, std::string* error) {
-    hostFileFetcher.setRootDir(rootdir);
-    hostPropertyFetcher.setProperties(props);
-
-    return VintfObject::CheckCompatibility({} /* packageInfo */, error, DISABLE_RUNTIME_INFO);
+    auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
+    hostPropertyFetcher->setProperties(props);
+    VintfObject vintfObject(std::make_unique<HostFileSystem>(rootdir),
+                            nullptr /* partition mounter */, nullptr /* runtime info factory */,
+                            std::move(hostPropertyFetcher));
+    return vintfObject.checkCompatibility({} /* packageInfo */, error,
+                                          CheckFlags::DISABLE_RUNTIME_INFO);
 }
 
 }  // namespace details
diff --git a/include-test/vintf/AssembleVintf.h b/include-test/vintf/AssembleVintf.h
index ac6d2af..56b4811 100644
--- a/include-test/vintf/AssembleVintf.h
+++ b/include-test/vintf/AssembleVintf.h
@@ -38,6 +38,7 @@
     virtual ~AssembleVintf() = default;
     virtual bool setHalsOnly() = 0;
     virtual bool setNoHals() = 0;
+    virtual bool setNoKernelRequirements() = 0;
     virtual void setOutputMatrix() = 0;
     virtual bool assemble() = 0;
 
diff --git a/include/vintf/Arch.h b/include/vintf/Arch.h
index 77d1c37..3e69a42 100644
--- a/include/vintf/Arch.h
+++ b/include/vintf/Arch.h
@@ -58,6 +58,24 @@
     return (lft = lft | rgt);
 }
 
+// Returns true if lft defines all bitnesses in rgt, otherwise false.
+inline constexpr bool contains(Arch lft, Arch rgt) {
+    return !(~static_cast<size_t>(lft) & static_cast<size_t>(rgt));
+}
+
+static_assert(contains(Arch::ARCH_32_64, Arch::ARCH_32_64), "bad contains(Arch, Arch)");
+static_assert(contains(Arch::ARCH_32_64, Arch::ARCH_64), "bad contains(Arch, Arch)");
+static_assert(contains(Arch::ARCH_32_64, Arch::ARCH_32), "bad contains(Arch, Arch)");
+static_assert(contains(Arch::ARCH_32_64, Arch::ARCH_EMPTY), "bad contains(Arch, Arch)");
+static_assert(contains(Arch::ARCH_32, Arch::ARCH_EMPTY), "bad contains(Arch, Arch)");
+static_assert(contains(Arch::ARCH_64, Arch::ARCH_EMPTY), "bad contains(Arch, Arch)");
+static_assert(!contains(Arch::ARCH_32, Arch::ARCH_32_64), "bad contains(Arch, Arch)");
+static_assert(!contains(Arch::ARCH_64, Arch::ARCH_32_64), "bad contains(Arch, Arch)");
+static_assert(!contains(Arch::ARCH_32, Arch::ARCH_64), "bad contains(Arch, Arch)");
+static_assert(!contains(Arch::ARCH_64, Arch::ARCH_32), "bad contains(Arch, Arch)");
+static_assert(!contains(Arch::ARCH_EMPTY, Arch::ARCH_32), "bad contains(Arch, Arch)");
+static_assert(!contains(Arch::ARCH_EMPTY, Arch::ARCH_64), "bad contains(Arch, Arch)");
+
 } // namespace vintf
 } // namespace android
 
diff --git a/include/vintf/CheckFlags.h b/include/vintf/CheckFlags.h
new file mode 100644
index 0000000..d63a809
--- /dev/null
+++ b/include/vintf/CheckFlags.h
@@ -0,0 +1,63 @@
+/*
+ * 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_VINTF_DISABLED_CHECKS_H_
+#define ANDROID_VINTF_DISABLED_CHECKS_H_
+
+namespace android {
+namespace vintf {
+
+namespace CheckFlags {
+
+// Flags for *::checkCompatibility functions.
+class Type {
+   public:
+#define VINTF_CHECK_FLAGS_FIELD(name, bit)                                      \
+    constexpr Type enable##name() const { return Type(mValue | (1 << bit)); }   \
+    constexpr Type disable##name() const { return Type(mValue & ~(1 << bit)); } \
+    constexpr bool is##name##Enabled() const { return mValue & (1 << bit); }
+
+    VINTF_CHECK_FLAGS_FIELD(Avb, 0)
+    VINTF_CHECK_FLAGS_FIELD(RuntimeInfo, 1)
+    VINTF_CHECK_FLAGS_FIELD(Kernel, 2)
+#undef VINTF_CHECK_FLAGS_FIELD
+
+    explicit constexpr Type(int32_t value) : mValue(value) {}
+
+   private:
+    int32_t mValue;
+};
+
+constexpr Type ENABLE_ALL_CHECKS{~0};
+constexpr Type DISABLE_ALL_CHECKS{0};
+// Disable AVB version check in RuntimeInfo::checkCompatibility
+constexpr Type DISABLE_AVB_CHECK = ENABLE_ALL_CHECKS.disableAvb();
+// Disable RuntimeInfo <-> Framework Matrix check. This implies DISABLE_AVB_CHECK.
+constexpr Type DISABLE_RUNTIME_INFO = ENABLE_ALL_CHECKS.disableRuntimeInfo();
+
+// tests
+static_assert(ENABLE_ALL_CHECKS.isAvbEnabled(), "");
+static_assert(ENABLE_ALL_CHECKS.isRuntimeInfoEnabled(), "");
+static_assert(!DISABLE_AVB_CHECK.isAvbEnabled(), "");
+static_assert(DISABLE_AVB_CHECK.isRuntimeInfoEnabled(), "");
+static_assert(DISABLE_RUNTIME_INFO.isAvbEnabled(), "");
+static_assert(!DISABLE_RUNTIME_INFO.isRuntimeInfoEnabled(), "");
+
+}  // namespace CheckFlags
+}  // namespace vintf
+}  // namespace android
+
+#endif  // ANDROID_VINTF_DISABLED_CHECKS_H_
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index a43d493..feb8ac8 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -18,10 +18,12 @@
 #define ANDROID_VINTF_COMPATIBILITY_MATRIX_H
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include <utils/Errors.h>
 
+#include "FileSystem.h"
 #include "HalGroup.h"
 #include "Level.h"
 #include "MapValueIterator.h"
@@ -42,7 +44,7 @@
 // Compatibility matrix defines what hardware does the framework requires.
 struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<MatrixXmlFile> {
     // Create a framework compatibility matrix.
-    CompatibilityMatrix() : mType(SchemaType::FRAMEWORK) {};
+    CompatibilityMatrix() : mType(SchemaType::FRAMEWORK) {}
 
     SchemaType type() const;
     Level level() const;
@@ -63,9 +65,26 @@
         const std::string& package, const Version& expectVersion,
         const std::function<bool(const MatrixInstance&)>& func) const override;
 
+    std::string getVendorNdkVersion() const;
+
    private:
-    bool add(MatrixHal &&hal);
-    bool add(MatrixKernel &&kernel);
+    // Add everything in inputMatrix to "this" as requirements.
+    bool addAll(Named<CompatibilityMatrix>* inputMatrix, std::string* error);
+
+    // Add all <kernel> from other to "this". Error if there is a conflict.
+    bool addAllKernels(CompatibilityMatrix* other, std::string* error);
+
+    // Add a <kernel> tag to "this". Error if there is a conflict.
+    bool addKernel(MatrixKernel&& kernel, std::string* error);
+
+    // Merge <sepolicy> with other's <sepolicy>. Error if there is a conflict.
+    bool addSepolicy(CompatibilityMatrix* other, std::string* error);
+
+    // Merge <avb><vbmeta-version> with other's <avb><vbmeta-version>. Error if there is a conflict.
+    bool addAvbMetaVersion(CompatibilityMatrix* other, std::string* error);
+
+    // Add everything in inputMatrix to "this" as optional.
+    bool addAllAsOptional(Named<CompatibilityMatrix>* inputMatrix, std::string* error);
 
     // Add all HALs as optional HALs from "other". This function moves MatrixHal objects
     // from "other".
@@ -78,21 +97,22 @@
     // Similar to addAllHalsAsOptional but on <kernel> entries.
     bool addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error);
 
-    status_t fetchAllInformation(const std::string& path, std::string* error = nullptr);
-
-    // Combine a subset of "matrices". For each CompatibilityMatrix in matrices,
-    // - If level() == UNSPECIFIED, use it as the base matrix (for non-HAL, non-XML-file
-    //   requirements).
+    // Combine a set of framework compatibility matrices. For each CompatibilityMatrix in matrices
+    // (in the order of level(), where UNSPECIFIED (empty) is treated as deviceLevel)
     // - If level() < deviceLevel, ignore
-    // - If level() == deviceLevel, all HAL versions and XML files are added as is
-    //   (optionality is kept)
-    // - If level() > deviceLevel, all HAL versions and XML files are added as optional.
-    // Return a pointer into one of the elements in "matrices".
-    static CompatibilityMatrix* combine(Level deviceLevel,
-                                        std::vector<Named<CompatibilityMatrix>>* matrices,
-                                        std::string* error);
-    static CompatibilityMatrix* findOrInsertBaseMatrix(
-        std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error);
+    // - If level() == UNSPECIFIED or level() == deviceLevel,
+    //   - Add as hard requirements. See combineSameFcmVersion
+    // - If level() > deviceLevel,
+    //   - all <hal> versions and <xmlfile>s are added as optional.
+    //   - <kernel minlts="x.y.z"> is added only if x.y does not exist in a file
+    //     with lower level()
+    //   - <sepolicy>, <avb><vbmeta-version> is ignored
+    // Return the combined matrix, nullptr if any error (e.g. conflict of information).
+    static std::unique_ptr<CompatibilityMatrix> combine(
+        Level deviceLevel, std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error);
+
+    status_t fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
+                                 std::string* error = nullptr);
 
     MatrixHal* splitInstance(MatrixHal* existingHal, const std::string& interface,
                              const std::string& instance, bool isRegex);
diff --git a/include/vintf/DisabledChecks.h b/include/vintf/DisabledChecks.h
deleted file mode 100644
index 43ff2b5..0000000
--- a/include/vintf/DisabledChecks.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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_VINTF_DISABLED_CHECKS_H_
-#define ANDROID_VINTF_DISABLED_CHECKS_H_
-
-namespace android {
-namespace vintf {
-
-// Flags for *::checkCompatibility functions.
-enum DisabledChecks : int32_t {
-    ENABLE_ALL_CHECKS = 0,
-    // Disable AVB version check in RuntimeInfo::checkCompatibility
-    DISABLE_AVB_CHECK = 1 << 0,
-    // Disable RuntimeInfo <-> Framework Matrix check. This implies DISABLE_AVB_CHECK.
-    DISABLE_RUNTIME_INFO = 1 << 1,
-};
-
-}  // namespace vintf
-}  // namespace android
-
-#endif  // ANDROID_VINTF_DISABLED_CHECKS_H_
diff --git a/include/vintf/FileSystem.h b/include/vintf/FileSystem.h
new file mode 100644
index 0000000..5a98a6e
--- /dev/null
+++ b/include/vintf/FileSystem.h
@@ -0,0 +1,85 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include <utils/Errors.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 {
+
+// 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;
+};
+
+// The root is mounted to a given path.
+class FileSystemUnderPath : public FileSystem {
+   public:
+    FileSystemUnderPath(const std::string& rootdir);
+    virtual status_t fetch(const std::string& path, std::string* fetched,
+                           std::string* error) const override;
+    virtual status_t listFiles(const std::string& path, std::vector<std::string>* out,
+                               std::string* error) const override;
+
+   protected:
+    const std::string& getRootDir() const;
+
+   private:
+    std::string mRootDir;
+    FileSystemImpl mImpl;
+};
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
+
+#endif
diff --git a/include/vintf/HalGroup.h b/include/vintf/HalGroup.h
index f59e495..5cad867 100644
--- a/include/vintf/HalGroup.h
+++ b/include/vintf/HalGroup.h
@@ -39,20 +39,21 @@
         for (auto& pair : other->mHals) {
             if (!add(std::move(pair.second))) {
                 if (error) {
-                    *error = pair.first;
+                    *error = "HAL \"" + pair.first + "\" has a conflict.";
                 }
                 return false;
             }
         }
+        other->mHals.clear();
         return true;
     }
 
     // Add an hal to this HalGroup so that it can be constructed programatically.
     virtual bool add(Hal&& hal) { return addInternal(std::move(hal)) != nullptr; }
 
+   protected:
     // Get all hals with the given name (e.g "android.hardware.camera").
     // There could be multiple hals that matches the same given name.
-    // TODO(b/74247301) Deprecated; use forEachInstanceOfPackage instead.
     std::vector<const Hal*> getHals(const std::string& name) const {
         std::vector<const Hal*> ret;
         auto range = mHals.equal_range(name);
@@ -65,7 +66,6 @@
     // Get all hals with the given name (e.g "android.hardware.camera").
     // There could be multiple hals that matches the same given name.
     // Non-const version of the above getHals() method.
-    // TODO(b/74247301) Deprecated; use forEachInstanceOfPackage instead.
     std::vector<Hal*> getHals(const std::string& name) {
         std::vector<Hal*> ret;
         auto range = mHals.equal_range(name);
@@ -75,6 +75,7 @@
         return ret;
     }
 
+   public:
     // Apply func to all instances.
     bool forEachInstance(const std::function<bool(const InstanceType&)>& func) const {
         for (const auto& hal : getHals()) {
@@ -143,11 +144,13 @@
     // override this to filter for add.
     virtual bool shouldAdd(const Hal&) const { return true; }
 
-    // Return an iterable to all ManifestHal objects. Call it as follows:
+    // Return an iterable to all Hal objects. Call it as follows:
     // for (const auto& e : vm.getHals()) { }
-    ConstMultiMapValueIterable<std::string, Hal> getHals() const {
-        return ConstMultiMapValueIterable<std::string, Hal>(mHals);
-    }
+    ConstMultiMapValueIterable<std::string, Hal> getHals() const { return iterateValues(mHals); }
+
+    // Return an iterable to all Hal objects. Call it as follows:
+    // for (const auto& e : vm.getHals()) { }
+    MultiMapValueIterable<std::string, Hal> getHals() { return iterateValues(mHals); }
 
     // Get any HAL component based on the component name. Return any one
     // if multiple. Return nullptr if the component does not exist. This is only
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index 7a436a6..9b88c6a 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -23,6 +23,7 @@
 #include <string>
 #include <vector>
 
+#include "FileSystem.h"
 #include "HalGroup.h"
 #include "Level.h"
 #include "ManifestHal.h"
@@ -119,6 +120,12 @@
     bool hasInstance(const std::string& halName, const Version& version,
                      const std::string& interfaceName, const std::string& instance) const;
 
+    // Insert the given instance. After inserting it, the instance will be available via
+    // forEachInstance* functions. This modifies the manifest.
+    // Return whether this operation is successful.
+    bool insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch, HalFormat fmt,
+                        std::string* error = nullptr);
+
    protected:
     // Check before add()
     bool shouldAdd(const ManifestHal& toAdd) const override;
@@ -132,7 +139,8 @@
     friend std::string dump(const HalManifest &vm);
     friend bool operator==(const HalManifest &lft, const HalManifest &rgt);
 
-    status_t fetchAllInformation(const std::string& path, std::string* error = nullptr);
+    status_t fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
+                                 std::string* error = nullptr);
 
     details::Instances expandInstances(const std::string& name) const;
     // Check if all instances in matrixHal is supported in this manifest.
@@ -153,6 +161,9 @@
     // (instance in manifest) => (instance in matrix).
     std::set<std::string> checkUnusedHals(const CompatibilityMatrix& mat) const;
 
+    // Check that manifest has no entries.
+    bool empty() const;
+
     SchemaType mType;
     Level mLevel = Level::UNSPECIFIED;
     // version attribute. Default is 1.0 for manifests created programatically.
diff --git a/include/vintf/ManifestHal.h b/include/vintf/ManifestHal.h
index ad7be3b..3a798a8 100644
--- a/include/vintf/ManifestHal.h
+++ b/include/vintf/ManifestHal.h
@@ -60,6 +60,8 @@
         return transportArch.transport;
     }
 
+    inline Arch arch() const { return transportArch.arch; }
+
     inline const std::string& getName() const { return name; }
     bool forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const;
 
@@ -70,8 +72,6 @@
     // a HAL is disabled on certain products.
     bool isDisabledHal() const;
 
-    // insert instance to <interface> <instance>.
-    void insertLegacyInstance(const std::string& interface, const std::string& instance);
    private:
     friend struct LibVintfTest;
     friend struct ManifestHalConverter;
@@ -93,7 +93,11 @@
     // Existing instances will be ignored.
     // Pre: all instances to be inserted must satisfy
     // !hasPackage() && hasVersion() && hasInterface() && hasInstance()
+    bool insertInstance(const FqInstance& fqInstance, std::string* error = nullptr);
     bool insertInstances(const std::set<FqInstance>& fqInstances, std::string* error = nullptr);
+
+    // Verify instance before inserting.
+    bool verifyInstance(const FqInstance& fqInstance, std::string* error = nullptr) const;
 };
 
 } // namespace vintf
diff --git a/include/vintf/ManifestInstance.h b/include/vintf/ManifestInstance.h
index 4eefd65..7ddca42 100644
--- a/include/vintf/ManifestInstance.h
+++ b/include/vintf/ManifestInstance.h
@@ -32,9 +32,9 @@
    public:
     ManifestInstance();
     ManifestInstance(const ManifestInstance&);
-    ManifestInstance(ManifestInstance&&);
+    ManifestInstance(ManifestInstance&&) noexcept;
     ManifestInstance& operator=(const ManifestInstance&);
-    ManifestInstance& operator=(ManifestInstance&&);
+    ManifestInstance& operator=(ManifestInstance&&) noexcept;
 
     using VersionType = Version;
     ManifestInstance(FqInstance&& fqInstance, TransportArch&& ta, HalFormat fmt);
diff --git a/include/vintf/MapValueIterator.h b/include/vintf/MapValueIterator.h
index c9bf4b2..b44c661 100644
--- a/include/vintf/MapValueIterator.h
+++ b/include/vintf/MapValueIterator.h
@@ -52,7 +52,7 @@
         inline IteratorImpl &operator++()    {
             mIter++;
             return *this;
-        };
+        }
         inline IteratorImpl  operator++(int) {
             IteratorImpl i = *this;
             mIter++;
@@ -120,6 +120,10 @@
 using ConstMapValueIterable = typename MapIterTypes<std::map<K, V>>::ConstValueIterable;
 template<typename K, typename V>
 using ConstMultiMapValueIterable = typename MapIterTypes<std::multimap<K, V>>::ConstValueIterable;
+template <typename K, typename V>
+using MapValueIterable = typename MapIterTypes<std::map<K, V>>::ValueIterable;
+template <typename K, typename V>
+using MultiMapValueIterable = typename MapIterTypes<std::multimap<K, V>>::ValueIterable;
 
 template<typename K, typename V>
 ConstMapValueIterable<K, V> iterateValues(const std::map<K, V> &map) {
@@ -129,6 +133,14 @@
 ConstMultiMapValueIterable<K, V> iterateValues(const std::multimap<K, V> &map) {
     return map;
 }
+template <typename K, typename V>
+MapValueIterable<K, V> iterateValues(std::map<K, V>& map) {
+    return map;
+}
+template <typename K, typename V>
+MultiMapValueIterable<K, V> iterateValues(std::multimap<K, V>& map) {
+    return map;
+}
 
 template <typename K, typename V>
 typename MapIterTypes<std::multimap<K, V>>::template RangeImpl<true> iterateValues(
diff --git a/include/vintf/MatrixInstance.h b/include/vintf/MatrixInstance.h
index c34500c..5429f0c 100644
--- a/include/vintf/MatrixInstance.h
+++ b/include/vintf/MatrixInstance.h
@@ -30,9 +30,9 @@
    public:
     MatrixInstance();
     MatrixInstance(const MatrixInstance&);
-    MatrixInstance(MatrixInstance&&);
+    MatrixInstance(MatrixInstance&&) noexcept;
     MatrixInstance& operator=(const MatrixInstance&);
-    MatrixInstance& operator=(MatrixInstance&&);
+    MatrixInstance& operator=(MatrixInstance&&) noexcept;
 
     using VersionType = VersionRange;
     // fqInstance.version is ignored. Version range is provided separately.
diff --git a/include/vintf/MatrixKernel.h b/include/vintf/MatrixKernel.h
index cee7e32..14cf5bf 100644
--- a/include/vintf/MatrixKernel.h
+++ b/include/vintf/MatrixKernel.h
@@ -58,6 +58,7 @@
    private:
     friend struct MatrixKernelConverter;
     friend struct MatrixKernelConditionsConverter;
+    friend struct CompatibilityMatrix;
     friend class AssembleVintfImpl;
 
     KernelVersion mMinLts;
diff --git a/include/vintf/RuntimeInfo.h b/include/vintf/RuntimeInfo.h
index 6ba8a22..c48942e 100644
--- a/include/vintf/RuntimeInfo.h
+++ b/include/vintf/RuntimeInfo.h
@@ -25,7 +25,7 @@
 
 #include <utils/Errors.h>
 
-#include "DisabledChecks.h"
+#include "CheckFlags.h"
 #include "MatrixKernel.h"
 #include "Version.h"
 
@@ -73,7 +73,7 @@
     //   not when RuntimeInfo::checkCompatibility is called.
     // - avb-vbmetaversion matches related sysprops
     bool checkCompatibility(const CompatibilityMatrix& mat, std::string* error = nullptr,
-                            DisabledChecks disabledChecks = ENABLE_ALL_CHECKS) const;
+                            CheckFlags::Type flags = CheckFlags::ENABLE_ALL_CHECKS) const;
 
     using FetchFlags = uint32_t;
     enum FetchFlag : FetchFlags {
diff --git a/include/vintf/SerializeFlags.h b/include/vintf/SerializeFlags.h
new file mode 100644
index 0000000..909a331
--- /dev/null
+++ b/include/vintf/SerializeFlags.h
@@ -0,0 +1,91 @@
+/*
+ * 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_VINTF_SERIALIZE_FLAGS_H
+#define ANDROID_VINTF_SERIALIZE_FLAGS_H
+
+#include <stdint.h>
+
+namespace android {
+namespace vintf {
+
+namespace SerializeFlags {
+
+class Type {
+   public:
+    explicit constexpr Type(uint32_t value) : mValue(value) {}
+
+#define VINTF_SERIALIZE_FLAGS_FIELD(name, bit)                                  \
+    constexpr Type enable##name() const { return Type(mValue | (1 << bit)); }   \
+    constexpr Type disable##name() const { return Type(mValue & ~(1 << bit)); } \
+    constexpr bool is##name##Enabled() const { return mValue & (1 << bit); }
+
+    VINTF_SERIALIZE_FLAGS_FIELD(Hals, 0)
+    VINTF_SERIALIZE_FLAGS_FIELD(Avb, 1)
+    VINTF_SERIALIZE_FLAGS_FIELD(Sepolicy, 2)
+    VINTF_SERIALIZE_FLAGS_FIELD(Vndk, 3)
+    VINTF_SERIALIZE_FLAGS_FIELD(Kernel, 4)
+    VINTF_SERIALIZE_FLAGS_FIELD(XmlFiles, 5)
+    VINTF_SERIALIZE_FLAGS_FIELD(Ssdk, 6)
+    VINTF_SERIALIZE_FLAGS_FIELD(Fqname, 7)
+    VINTF_SERIALIZE_FLAGS_FIELD(KernelConfigs, 8)
+    VINTF_SERIALIZE_FLAGS_FIELD(KernelMinorRevision, 9)
+    VINTF_SERIALIZE_FLAGS_FIELD(MetaVersion, 10)
+    VINTF_SERIALIZE_FLAGS_FIELD(SchemaType, 11)
+
+#undef VINTF_SERIALIZE_FLAGS_FIELD
+
+   private:
+    uint32_t mValue;
+};
+
+constexpr Type EVERYTHING = Type(~0);
+constexpr Type NO_HALS = EVERYTHING.disableHals();
+constexpr Type NO_AVB = EVERYTHING.disableAvb();
+constexpr Type NO_SEPOLICY = EVERYTHING.disableSepolicy();
+constexpr Type NO_VNDK = EVERYTHING.disableVndk();
+constexpr Type NO_KERNEL = EVERYTHING.disableKernel();
+constexpr Type NO_XMLFILES = EVERYTHING.disableXmlFiles();
+constexpr Type NO_SSDK = EVERYTHING.disableSsdk();
+constexpr Type NO_FQNAME = EVERYTHING.disableFqname();
+constexpr Type NO_KERNEL_CONFIGS = EVERYTHING.disableKernelConfigs();
+constexpr Type NO_KERNEL_MINOR_REVISION = EVERYTHING.disableKernelMinorRevision();
+
+constexpr Type NO_TAGS = Type(0).enableMetaVersion().enableSchemaType();
+constexpr Type HALS_ONLY = NO_TAGS.enableHals().enableFqname();  // <hal> with <fqname>
+constexpr Type XMLFILES_ONLY = NO_TAGS.enableXmlFiles();
+constexpr Type SEPOLICY_ONLY = NO_TAGS.enableSepolicy();
+constexpr Type VNDK_ONLY = NO_TAGS.enableVndk();
+constexpr Type HALS_NO_FQNAME = NO_TAGS.enableHals();  // <hal> without <fqname>
+constexpr Type SSDK_ONLY = NO_TAGS.enableSsdk();
+
+// tests
+static_assert(EVERYTHING.isHalsEnabled(), "");
+static_assert(EVERYTHING.isMetaVersionEnabled(), "");
+static_assert(!NO_HALS.isHalsEnabled(), "");
+static_assert(NO_HALS.isAvbEnabled(), "");
+static_assert(NO_HALS.isMetaVersionEnabled(), "");
+static_assert(!NO_TAGS.isHalsEnabled(), "");
+static_assert(NO_TAGS.isMetaVersionEnabled(), "");
+static_assert(HALS_ONLY.isHalsEnabled(), "");
+static_assert(!HALS_ONLY.isAvbEnabled(), "");
+static_assert(HALS_ONLY.isMetaVersionEnabled(), "");
+
+}  // namespace SerializeFlags
+}  // namespace vintf
+}  // namespace android
+
+#endif  // ANDROID_VINTF_SERIALIZE_FLAGS_H
diff --git a/include/vintf/TransportArch.h b/include/vintf/TransportArch.h
index b1d9352..51630de 100644
--- a/include/vintf/TransportArch.h
+++ b/include/vintf/TransportArch.h
@@ -28,6 +28,9 @@
     Transport transport = Transport::EMPTY;
     Arch arch = Arch::ARCH_EMPTY;
 
+    TransportArch() = default;
+    TransportArch(Transport t, Arch a) : transport(t), arch(a) {}
+
     inline bool operator==(const TransportArch& other) const {
         return transport == other.transport && arch == other.arch;
     }
diff --git a/include/vintf/VersionRange.h b/include/vintf/VersionRange.h
index 6c5690b..570d163 100644
--- a/include/vintf/VersionRange.h
+++ b/include/vintf/VersionRange.h
@@ -30,14 +30,13 @@
 
 // A version range with the same major version, e.g. 2.3-7
 struct VersionRange {
-    VersionRange() : VersionRange(0u, 0u, 0u) {};
-    VersionRange(size_t mjV, size_t miV)
-            : VersionRange(mjV, miV, miV) {};
+    VersionRange() : VersionRange(0u, 0u, 0u) {}
+    VersionRange(size_t mjV, size_t miV) : VersionRange(mjV, miV, miV) {}
     VersionRange(size_t mjV, size_t miM, size_t mxM)
             : majorVer(mjV), minMinor(miM), maxMinor(mxM) {}
     inline Version minVer() const { return Version(majorVer, minMinor); }
     inline Version maxVer() const { return Version(majorVer, maxMinor); }
-    inline bool isSingleVersion() const { return minMinor == maxMinor; };
+    inline bool isSingleVersion() const { return minMinor == maxMinor; }
 
     inline bool operator==(const VersionRange &other) const {
         return majorVer == other.majorVer
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 56581f8..50c1fed 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -19,14 +19,42 @@
 
 #include <memory>
 
+#include "CheckFlags.h"
 #include "CompatibilityMatrix.h"
-#include "DisabledChecks.h"
+#include "FileSystem.h"
 #include "HalManifest.h"
 #include "Named.h"
 #include "RuntimeInfo.h"
 
 namespace android {
 namespace vintf {
+
+namespace details {
+class PartitionMounter;
+template <typename T>
+class ObjectFactory;
+class PropertyFetcher;
+
+template <typename T>
+struct LockedSharedPtr {
+    std::shared_ptr<T> object;
+    std::mutex mutex;
+    bool fetchedOnce = false;
+};
+
+struct LockedRuntimeInfoCache {
+    std::shared_ptr<RuntimeInfo> object;
+    std::mutex mutex;
+    RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
+};
+}  // namespace details
+
+namespace testing {
+class VintfObjectTestBase;
+class VintfObjectRuntimeInfoTest;
+class VintfObjectCompatibleTest;
+}  // namespace testing
+
 /*
  * The top level class for libvintf.
  * An overall diagram of the public API:
@@ -50,7 +78,155 @@
  * again from the device.
  */
 class VintfObject {
-public:
+   public:
+    /**
+     * A VintfObject that fetches from root and cache results, unless skipCache is specified.
+     * Dependencies can be injected via arguments. If nullptr is provided, the default behavior
+     * is used.
+     * - FileSystem fetch from "/" for target and fetch no files for host
+     * - PartitionMounter does nothing for both target and host
+     * - ObjectFactory<RuntimeInfo> fetches default RuntimeInfo for target and nothing for host
+     * - PropertyFetcher fetches properties for target and nothing for host
+     */
+    VintfObject(std::unique_ptr<FileSystem>&& = nullptr,
+                std::unique_ptr<details::PartitionMounter>&& = nullptr,
+                std::unique_ptr<details::ObjectFactory<RuntimeInfo>>&& = nullptr,
+                std::unique_ptr<details::PropertyFetcher>&& = nullptr);
+
+    /*
+     * Return the API that access the device-side HAL manifest stored
+     * in /vendor/manifest.xml.
+     */
+    std::shared_ptr<const HalManifest> getDeviceHalManifest(bool skipCache = false);
+
+    /*
+     * Return the API that access the framework-side HAL manifest stored
+     * in /system/manfiest.xml.
+     */
+    std::shared_ptr<const HalManifest> getFrameworkHalManifest(bool skipCache = false);
+
+    /*
+     * Return the API that access the device-side compatibility matrix stored
+     * in /vendor/compatibility_matrix.xml.
+     */
+    std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(bool skipCache = false);
+
+    /*
+     * Return the API that access the framework-side compatibility matrix stored
+     * in /system/compatibility_matrix.xml.
+     */
+    std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(
+        bool skipCache = false);
+
+    /*
+     * Return the API that access device runtime info.
+     *
+     * {skipCache == true, flags == ALL}: re-fetch everything
+     * {skipCache == false, flags == ALL}: fetch everything if not previously fetched
+     * {skipCache == true, flags == selected info}: re-fetch selected information
+     *                                if not previously fetched.
+     * {skipCache == false, flags == selected info}: fetch selected information
+     *                                if not previously fetched.
+     *
+     * @param skipCache do not fetch if previously fetched
+     * @param flags bitwise-or of RuntimeInfo::FetchFlag
+     */
+    std::shared_ptr<const RuntimeInfo> getRuntimeInfo(
+        bool skipCache = false, RuntimeInfo::FetchFlags flags = RuntimeInfo::FetchFlag::ALL);
+
+    /**
+     * Check compatibility, given a set of manifests / matrices in packageInfo.
+     * They will be checked against the manifests / matrices on the device.
+     *
+     * @param packageInfo a list of XMLs of HalManifest /
+     * CompatibilityMatrix objects.
+     * @param error error message
+     * @param flags flags to disable certain checks. See CheckFlags.
+     *
+     * @return = 0 if success (compatible)
+     *         > 0 if incompatible
+     *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     */
+    int32_t checkCompatibility(const std::vector<std::string>& packageInfo,
+                               std::string* error = nullptr,
+                               CheckFlags::Type flags = CheckFlags::ENABLE_ALL_CHECKS);
+
+    /**
+     * A std::function that abstracts a list of "provided" instance names. Given package, version
+     * and interface, the function returns a list of instance names that matches.
+     * This function can represent a manifest, an IServiceManager, etc.
+     * If the source is passthrough service manager, a list of instance names cannot be provided.
+     * Instead, the function should call getService on each of the "hintInstances", and
+     * return those instances for which getService does not return a nullptr. This means that for
+     * passthrough HALs, the deprecation on <regex-instance>s cannot be enforced; only <instance>s
+     * can be enforced.
+     */
+    using ListInstances = std::function<std::vector<std::pair<std::string, Version>>(
+        const std::string& package, Version version, const std::string& interface,
+        const std::vector<std::string>& hintInstances)>;
+    /**
+     * Check deprecation on framework matrices with a provided predicate.
+     *
+     * @param listInstances predicate that takes parameter in this format:
+     *        android.hardware.foo@1.0::IFoo
+     *        and returns {{"default", version}...} if HAL is in use, where version =
+     *        first version in interfaceChain where package + major version matches.
+     *
+     * @return = 0 if success (no deprecated HALs)
+     *         > 0 if there is at least one deprecated HAL
+     *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     */
+    int32_t checkDeprecation(const ListInstances& listInstances, std::string* error = nullptr);
+
+    /**
+     * Check deprecation on existing VINTF metadata. Use Device Manifest as the
+     * predicate to check if a HAL is in use.
+     *
+     * @return = 0 if success (no deprecated HALs)
+     *         > 0 if there is at least one deprecated HAL
+     *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     */
+    int32_t checkDeprecation(std::string* error = nullptr);
+
+   private:
+    const std::unique_ptr<FileSystem> mFileSystem;
+    const std::unique_ptr<details::PartitionMounter> mPartitionMounter;
+    const std::unique_ptr<details::ObjectFactory<RuntimeInfo>> mRuntimeInfoFactory;
+    const std::unique_ptr<details::PropertyFetcher> mPropertyFetcher;
+
+    details::LockedSharedPtr<HalManifest> mDeviceManifest;
+    details::LockedSharedPtr<HalManifest> mFrameworkManifest;
+    details::LockedSharedPtr<CompatibilityMatrix> mDeviceMatrix;
+
+    // Parent lock of the following fields. It should be acquired before locking the child locks.
+    std::mutex mFrameworkCompatibilityMatrixMutex;
+    details::LockedSharedPtr<CompatibilityMatrix> mFrameworkMatrix;
+    details::LockedSharedPtr<CompatibilityMatrix> mCombinedFrameworkMatrix;
+    // End of mFrameworkCompatibilityMatrixMutex
+
+    details::LockedRuntimeInfoCache mDeviceRuntimeInfo;
+
+    // Expose functions for testing and recovery
+    friend class VintfObjectRecovery;
+    friend class testing::VintfObjectTestBase;
+    friend class testing::VintfObjectRuntimeInfoTest;
+    friend class testing::VintfObjectCompatibleTest;
+    int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount, std::string* error,
+                               CheckFlags::Type flags = CheckFlags::ENABLE_ALL_CHECKS);
+    const std::unique_ptr<FileSystem>& getFileSystem();
+    const std::unique_ptr<details::PartitionMounter>& getPartitionMounter();
+    const std::unique_ptr<details::PropertyFetcher>& getPropertyFetcher();
+    const std::unique_ptr<details::ObjectFactory<RuntimeInfo>>& getRuntimeInfoFactory();
+
+   public:
+    /*
+     * Get global instance. By default, this fetches from root and cache results,
+     * unless skipCache is specified.
+     */
+    static std::shared_ptr<VintfObject> GetInstance();
+
+    // Static variants of member functions.
+
     /*
      * Return the API that access the device-side HAL manifest stored
      * in /vendor/manifest.xml.
@@ -100,7 +276,7 @@
      * @param packageInfo a list of XMLs of HalManifest /
      * CompatibilityMatrix objects.
      * @param error error message
-     * @param disabledChecks flags to disable certain checks. See DisabledChecks.
+     * @param flags flags to disable certain checks. See CheckFlags.
      *
      * @return = 0 if success (compatible)
      *         > 0 if incompatible
@@ -108,22 +284,9 @@
      */
     static int32_t CheckCompatibility(const std::vector<std::string>& packageInfo,
                                       std::string* error = nullptr,
-                                      DisabledChecks disabledChecks = ENABLE_ALL_CHECKS);
+                                      CheckFlags::Type flags = CheckFlags::ENABLE_ALL_CHECKS);
 
     /**
-     * A std::function that abstracts a list of "provided" instance names. Given package, version
-     * and interface, the function returns a list of instance names that matches.
-     * This function can represent a manifest, an IServiceManager, etc.
-     * If the source is passthrough service manager, a list of instance names cannot be provided.
-     * Instead, the function should call getService on each of the "hintInstances", and
-     * return those instances for which getService does not return a nullptr. This means that for
-     * passthrough HALs, the deprecation on <regex-instance>s cannot be enforced; only <instance>s
-     * can be enforced.
-     */
-    using ListInstances = std::function<std::vector<std::pair<std::string, Version>>(
-        const std::string& package, Version version, const std::string& interface,
-        const std::vector<std::string>& hintInstances)>;
-    /**
      * Check deprecation on framework matrices with a provided predicate.
      *
      * @param listInstances predicate that takes parameter in this format:
@@ -149,22 +312,25 @@
     static int32_t CheckDeprecation(std::string* error = nullptr);
 
    private:
-    static status_t GetCombinedFrameworkMatrix(
-        const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out,
-        std::string* error = nullptr);
-    static std::vector<Named<CompatibilityMatrix>> GetAllFrameworkMatrixLevels(
-        std::string* error = nullptr);
-    static status_t FetchDeviceHalManifest(HalManifest* out, std::string* error = nullptr);
-    static status_t FetchDeviceMatrix(CompatibilityMatrix* out, std::string* error = nullptr);
-    static status_t FetchOdmHalManifest(HalManifest* out, std::string* error = nullptr);
-    static status_t FetchOneHalManifest(const std::string& path, HalManifest* out,
-                                        std::string* error = nullptr);
-    static status_t FetchFrameworkHalManifest(HalManifest* out, std::string* error = nullptr);
+    static details::LockedSharedPtr<VintfObject> sInstance;
 
-    static bool isHalDeprecated(const MatrixHal& oldMatrixHal,
+    status_t getCombinedFrameworkMatrix(const std::shared_ptr<const HalManifest>& deviceManifest,
+                                        CompatibilityMatrix* out, std::string* error = nullptr);
+    std::vector<Named<CompatibilityMatrix>> getAllFrameworkMatrixLevels(
+        std::string* error = nullptr);
+    status_t addDirectoryManifests(const std::string& directory, HalManifest* manifests,
+                                   std::string* error = nullptr);
+    status_t fetchDeviceHalManifest(HalManifest* out, std::string* error = nullptr);
+    status_t fetchDeviceMatrix(CompatibilityMatrix* out, std::string* error = nullptr);
+    status_t fetchOdmHalManifest(HalManifest* out, std::string* error = nullptr);
+    status_t fetchOneHalManifest(const std::string& path, HalManifest* out,
+                                 std::string* error = nullptr);
+    status_t fetchFrameworkHalManifest(HalManifest* out, std::string* error = nullptr);
+
+    static bool IsHalDeprecated(const MatrixHal& oldMatrixHal,
                                 const CompatibilityMatrix& targetMatrix,
                                 const ListInstances& listInstances, std::string* error);
-    static bool isInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
+    static bool IsInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
                                      const CompatibilityMatrix& targetMatrix,
                                      const ListInstances& listInstances, std::string* error);
 };
@@ -177,12 +343,8 @@
     DEPRECATED = 1,
 };
 
-// exposed for testing and VintfObjectRecovery.
+// exposed for testing.
 namespace details {
-class PartitionMounter;
-int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
-                           const PartitionMounter& partitionMounter, std::string* error,
-                           DisabledChecks disabledChecks = ENABLE_ALL_CHECKS);
 
 extern const std::string kSystemVintfDir;
 extern const std::string kVendorVintfDir;
@@ -193,6 +355,9 @@
 extern const std::string kSystemManifest;
 extern const std::string kVendorMatrix;
 extern const std::string kOdmManifest;
+extern const std::string kVendorManifestFragmentDir;
+extern const std::string kSystemManifestFragmentDir;
+extern const std::string kOdmManifestFragmentDir;
 extern const std::string kVendorLegacyManifest;
 extern const std::string kVendorLegacyMatrix;
 extern const std::string kSystemLegacyManifest;
diff --git a/include/vintf/Vndk.h b/include/vintf/Vndk.h
index 05fcac9..53998f4 100644
--- a/include/vintf/Vndk.h
+++ b/include/vintf/Vndk.h
@@ -33,7 +33,7 @@
     VndkVersionRange(size_t s, size_t v, size_t pi, size_t pa)
         : sdk(s), vndk(v), patchMin(pi), patchMax(pa) {}
 
-    inline bool isSingleVersion() const { return patchMin == patchMax; };
+    inline bool isSingleVersion() const { return patchMin == patchMax; }
 
     size_t sdk;
     size_t vndk;
diff --git a/include/vintf/XmlFileGroup.h b/include/vintf/XmlFileGroup.h
index 524efc9..dd15647 100644
--- a/include/vintf/XmlFileGroup.h
+++ b/include/vintf/XmlFileGroup.h
@@ -62,7 +62,7 @@
         for (auto& pair : other->mXmlFiles) {
             if (!addXmlFile(std::move(pair.second))) {
                 if (error) {
-                    *error = pair.first;
+                    *error = "XML File \"" + pair.first + "\" has a conflict.";
                 }
                 return false;
             }
diff --git a/include/vintf/parse_xml.h b/include/vintf/parse_xml.h
index 578e15b..4fe1626 100644
--- a/include/vintf/parse_xml.h
+++ b/include/vintf/parse_xml.h
@@ -19,29 +19,11 @@
 
 #include "CompatibilityMatrix.h"
 #include "HalManifest.h"
+#include "SerializeFlags.h"
 
 namespace android {
 namespace vintf {
 
-enum SerializeFlag : uint32_t {
-    NO_HALS = 1 << 0,
-    NO_AVB = 1 << 1,
-    NO_SEPOLICY = 1 << 2,
-    NO_VNDK = 1 << 3,
-    NO_KERNEL = 1 << 4,
-    NO_XMLFILES = 1 << 5,
-    NO_SSDK = 1 << 6,
-    NO_FQNAME = 1 << 7,
-
-    EVERYTHING = 0,
-    HALS_ONLY = ~(NO_HALS | NO_FQNAME),  // <hal> with <fqname>
-    XMLFILES_ONLY = ~NO_XMLFILES,
-    SEPOLICY_ONLY = ~NO_SEPOLICY,
-    VNDK_ONLY = ~NO_VNDK,
-    HALS_NO_FQNAME = ~NO_HALS,  // <hal> without <fqname>
-};
-using SerializeFlags = uint32_t;
-
 template<typename Object>
 struct XmlConverter {
     XmlConverter() {}
@@ -50,10 +32,12 @@
     virtual const std::string &lastError() const = 0;
 
     // deprecated. Use operator() instead.
-    virtual std::string serialize(const Object& o, SerializeFlags flags = EVERYTHING) const = 0;
+    virtual std::string serialize(
+        const Object& o, SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const = 0;
 
     // Serialize an object to XML.
-    virtual std::string operator()(const Object& o, SerializeFlags flags = EVERYTHING) const = 0;
+    virtual std::string operator()(
+        const Object& o, SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const = 0;
 
     // deprecated. Use operator() instead. These APIs sets lastError(). Kept for testing.
     virtual bool deserialize(Object* o, const std::string& xml) = 0;
diff --git a/main.cpp b/main.cpp
index c501bf7..baac511 100644
--- a/main.cpp
+++ b/main.cpp
@@ -266,10 +266,9 @@
         std::cout << std::endl;
     }
 
-    SerializeFlags flags = SerializeFlag::EVERYTHING;
+    SerializeFlags::Type flags = SerializeFlags::EVERYTHING;
     if (!options.verbose) {
-        flags |= SerializeFlag::NO_HALS;
-        flags |= SerializeFlag::NO_KERNEL;
+        flags = flags.disableHals().disableKernel();
     }
     std::cout << "======== Device HAL Manifest =========" << std::endl;
     if (vm != nullptr) std::cout << gHalManifestConverter(*vm, flags);
diff --git a/parse_string.cpp b/parse_string.cpp
index b99ba61..e3310f3 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -196,6 +196,11 @@
 }
 
 bool parseKernelConfigTypedValue(const std::string& s, KernelConfigTypedValue* kctv) {
+    if (s.size() > 1 && s[0] == '"' && s.back() == '"') {
+        kctv->mType = KernelConfigType::STRING;
+        kctv->mStringValue = s.substr(1, s.size()-2);
+        return true;
+    }
     if (parseKernelConfigInt(s, &kctv->mIntegerValue)) {
         kctv->mType = KernelConfigType::INTEGER;
         return true;
@@ -205,9 +210,7 @@
         return true;
     }
     // Do not test for KernelConfigType::RANGE.
-    kctv->mType = KernelConfigType::STRING;
-    kctv->mStringValue = s;
-    return true;
+    return false;
 }
 
 bool parse(const std::string &s, Version *ver) {
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 27f31c9..0cc514d 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -141,7 +141,7 @@
 
     // sub-types should implement these.
     virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
-    virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags) const {
+    virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags::Type) const {
         mutateNode(o, n, d);
     }
     virtual bool buildObject(Object* o, NodeType* n, std::string* error) const = 0;
@@ -150,12 +150,12 @@
     // convenience methods for user
     inline const std::string& lastError() const override { return mLastError; }
     inline NodeType* serialize(const Object& o, DocType* d,
-                               SerializeFlags flags = EVERYTHING) const {
+                               SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const {
         NodeType *root = createNode(this->elementName(), d);
         this->mutateNode(o, root, d, flags);
         return root;
     }
-    inline std::string serialize(const Object& o, SerializeFlags flags) const override {
+    inline std::string serialize(const Object& o, SerializeFlags::Type flags) const override {
         DocType *doc = createDocument();
         appendChild(doc, serialize(o, doc, flags));
         std::string s = printDocument(doc);
@@ -192,7 +192,7 @@
     inline NodeType *operator()(const Object &o, DocType *d) const {
         return serialize(o, d);
     }
-    inline std::string operator()(const Object& o, SerializeFlags flags) const override {
+    inline std::string operator()(const Object& o, SerializeFlags::Type flags) const override {
         return serialize(o, flags);
     }
     inline bool operator()(Object* o, NodeType* node) { return deserialize(o, node); }
@@ -234,7 +234,7 @@
     template <typename T, typename Array>
     inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv,
                                const Array& array, DocType* d,
-                               SerializeFlags flags = SerializeFlag::EVERYTHING) const {
+                               SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const {
         for (const T &t : array) {
             appendChild(parent, conv.serialize(t, d, flags));
         }
@@ -393,8 +393,9 @@
     virtual bool buildObject(Object* object, NodeType* root, std::string* error) const override {
         return this->parseText(root, object, error);
     }
-    virtual std::string elementName() const { return mElementName; };
-private:
+    virtual std::string elementName() const { return mElementName; }
+
+   private:
     std::string mElementName;
 };
 
@@ -600,12 +601,23 @@
 
 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
     std::string elementName() const override { return "kernel"; }
-    void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override {
-        appendAttr(root, "version", kernel.mMinLts);
+    void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d) const override {
+        mutateNode(kernel, root, d, SerializeFlags::EVERYTHING);
+    }
+    void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d,
+                    SerializeFlags::Type flags) const override {
+        KernelVersion kv = kernel.mMinLts;
+        if (!flags.isKernelMinorRevisionEnabled()) {
+            kv.minorRev = 0u;
+        }
+        appendAttr(root, "version", kv);
+
         if (!kernel.mConditions.empty()) {
             appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d));
         }
-        appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
+        if (flags.isKernelConfigsEnabled()) {
+            appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
+        }
     }
     bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
         if (!parseAttr(root, "version", &object->mMinLts, error) ||
@@ -625,10 +637,10 @@
 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
     std::string elementName() const override { return "hal"; }
     void mutateNode(const ManifestHal& m, NodeType* root, DocType* d) const override {
-        mutateNode(m, root, d, SerializeFlag::EVERYTHING);
+        mutateNode(m, root, d, SerializeFlags::EVERYTHING);
     }
     void mutateNode(const ManifestHal& hal, NodeType* root, DocType* d,
-                    SerializeFlags flags) const override {
+                    SerializeFlags::Type flags) const override {
         appendAttr(root, "format", hal.format);
         appendTextElement(root, "name", hal.name, d);
         appendChild(root, transportArchConverter(hal.transportArch, d));
@@ -638,7 +650,7 @@
             appendAttr(root, "override", hal.isOverride());
         }
 
-        if (!(flags & SerializeFlag::NO_FQNAME)) {
+        if (flags.isFqnameEnabled()) {
             std::set<FqInstance> fqInstances;
             hal.forEachInstance([&fqInstances](const auto& manifestInstance) {
                 fqInstances.emplace(manifestInstance.getFqInstanceNoPackage());
@@ -705,6 +717,12 @@
         if (!parseChildren(root, fqInstanceConverter, &fqInstances, error)) {
             return false;
         }
+        for (const auto& e : fqInstances) {
+            if (e.hasPackage()) {
+                *error = "Should not specify package: \"" + e.string() + "\"";
+                return false;
+            }
+        }
         if (!object->insertInstances(fqInstances, error)) {
             return false;
         }
@@ -843,25 +861,31 @@
 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
     std::string elementName() const override { return "manifest"; }
     void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
-        mutateNode(m, root, d, SerializeFlag::EVERYTHING);
+        mutateNode(m, root, d, SerializeFlags::EVERYTHING);
     }
     void mutateNode(const HalManifest& m, NodeType* root, DocType* d,
-                    SerializeFlags flags) const override {
-        appendAttr(root, "version", m.getMetaVersion());
-        appendAttr(root, "type", m.mType);
+                    SerializeFlags::Type flags) const override {
+        if (flags.isMetaVersionEnabled()) {
+            appendAttr(root, "version", m.getMetaVersion());
+        }
+        if (flags.isSchemaTypeEnabled()) {
+            appendAttr(root, "type", m.mType);
+        }
 
-        if (!(flags & SerializeFlag::NO_HALS)) {
+        if (flags.isHalsEnabled()) {
             appendChildren(root, manifestHalConverter, m.getHals(), d, flags);
         }
         if (m.mType == SchemaType::DEVICE) {
-            if (!(flags & SerializeFlag::NO_SEPOLICY)) {
-                appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
+            if (flags.isSepolicyEnabled()) {
+                if (m.device.mSepolicyVersion != Version{}) {
+                    appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
+                }
             }
             if (m.mLevel != Level::UNSPECIFIED) {
                 this->appendAttr(root, "target-level", m.mLevel);
             }
         } else if (m.mType == SchemaType::FRAMEWORK) {
-            if (!(flags & SerializeFlag::NO_VNDK)) {
+            if (flags.isVndkEnabled()) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
                 appendChildren(root, vndkConverter, m.framework.mVndks, d);
@@ -869,14 +893,14 @@
 
                 appendChildren(root, vendorNdkConverter, m.framework.mVendorNdks, d);
             }
-            if (!(flags & SerializeFlag::NO_SSDK)) {
+            if (flags.isSsdkEnabled()) {
                 if (!m.framework.mSystemSdk.empty()) {
                     appendChild(root, systemSdkConverter(m.framework.mSystemSdk, d));
                 }
             }
         }
 
-        if (!(flags & SerializeFlag::NO_XMLFILES)) {
+        if (flags.isXmlFilesEnabled()) {
             appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d);
         }
     }
@@ -1004,26 +1028,30 @@
 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
     std::string elementName() const override { return "compatibility-matrix"; }
     void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
-        mutateNode(m, root, d, SerializeFlag::EVERYTHING);
+        mutateNode(m, root, d, SerializeFlags::EVERYTHING);
     }
     void mutateNode(const CompatibilityMatrix& m, NodeType* root, DocType* d,
-                    SerializeFlags flags) const override {
-        appendAttr(root, "version", m.getMinimumMetaVersion());
-        appendAttr(root, "type", m.mType);
+                    SerializeFlags::Type flags) const override {
+        if (flags.isMetaVersionEnabled()) {
+            appendAttr(root, "version", m.getMinimumMetaVersion());
+        }
+        if (flags.isSchemaTypeEnabled()) {
+            appendAttr(root, "type", m.mType);
+        }
 
-        if (!(flags & SerializeFlag::NO_HALS)) {
+        if (flags.isHalsEnabled()) {
             appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d);
         }
         if (m.mType == SchemaType::FRAMEWORK) {
-            if (!(flags & SerializeFlag::NO_KERNEL)) {
-                appendChildren(root, matrixKernelConverter, m.framework.mKernels, d);
+            if (flags.isKernelEnabled()) {
+                appendChildren(root, matrixKernelConverter, m.framework.mKernels, d, flags);
             }
-            if (!(flags & SerializeFlag::NO_SEPOLICY)) {
+            if (flags.isSepolicyEnabled()) {
                 if (!(m.framework.mSepolicy == Sepolicy{})) {
                     appendChild(root, sepolicyConverter(m.framework.mSepolicy, d));
                 }
             }
-            if (!(flags & SerializeFlag::NO_AVB)) {
+            if (flags.isAvbEnabled()) {
                 if (!(m.framework.mAvbMetaVersion == Version{})) {
                     appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d));
                 }
@@ -1032,7 +1060,7 @@
                 this->appendAttr(root, "level", m.mLevel);
             }
         } else if (m.mType == SchemaType::DEVICE) {
-            if (!(flags & SerializeFlag::NO_VNDK)) {
+            if (flags.isVndkEnabled()) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
                 if (!(m.device.mVndk == Vndk{})) {
@@ -1045,14 +1073,14 @@
                 }
             }
 
-            if (!(flags & SerializeFlag::NO_SSDK)) {
+            if (flags.isSsdkEnabled()) {
                 if (!m.device.mSystemSdk.empty()) {
                     appendChild(root, systemSdkConverter(m.device.mSystemSdk, d));
                 }
             }
         }
 
-        if (!(flags & SerializeFlag::NO_XMLFILES)) {
+        if (flags.isXmlFilesEnabled()) {
             appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d);
         }
     }
diff --git a/test/Android.bp b/test/Android.bp
index 4dd6480..2246c12 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -66,7 +66,7 @@
     static_libs: [
         "libgtest",
         "libgmock",
-        "libvintf_common",
+        "libvintf",
         "libhidl-gen-utils",
         "libz",
     ],
diff --git a/test/AssembleVintfTest.cpp b/test/AssembleVintfTest.cpp
index 33acc1e..9b7bc29 100644
--- a/test/AssembleVintfTest.cpp
+++ b/test/AssembleVintfTest.cpp
@@ -79,12 +79,12 @@
         {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
         {"FRAMEWORK_VBMETA_VERSION", "1.0"},
     });
-    getInstance()->addKernelConfigInputStream({3, 18, 0}, "android-base.cfg",
+    getInstance()->addKernelConfigInputStream({3, 18, 0}, "android-base.config",
                                               makeStream(kernel318));
-    getInstance()->addKernelConfigInputStream({3, 18, 0}, "android-base-arm64.cfg",
+    getInstance()->addKernelConfigInputStream({3, 18, 0}, "android-base-arm64.config",
                                               makeStream(kernel318_64));
-    getInstance()->addKernelConfigInputStream({4, 4, 0}, "android-base.cfg", makeStream(kernel44));
-    getInstance()->addKernelConfigInputStream({4, 4, 0}, "android-base-arm64.cfg",
+    getInstance()->addKernelConfigInputStream({4, 4, 0}, "android-base.config", makeStream(kernel44));
+    getInstance()->addKernelConfigInputStream({4, 4, 0}, "android-base-arm64.config",
                                               makeStream(kernel44_64));
 
     EXPECT_TRUE(getInstance()->assemble());
@@ -458,5 +458,85 @@
     EXPECT_FALSE(getInstance()->assemble());
 }
 
+TEST_F(AssembleVintfTest, DeviceFrameworkMatrixMultiple) {
+    setFakeEnvs({{"POLICYVERS", "30"},
+                 {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+                 {"PLATFORM_SEPOLICY_COMPAT_VERSIONS", "26.0 27.0"},
+                 {"FRAMEWORK_VBMETA_VERSION", "1.0"},
+                 {"PRODUCT_ENFORCE_VINTF_MANIFEST", "true"}});
+    getInstance()->setCheckInputStream(makeStream(gEmptyOutManifest));
+
+    addInput("compatibility_matrix.foobar.xml",
+             "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+             "    <hal format=\"hidl\" optional=\"true\">\n"
+             "        <name>vendor.foo.bar</name>\n"
+             "        <version>1.0</version>\n"
+             "        <interface>\n"
+             "            <name>IFoo</name>\n"
+             "            <instance>default</instance>\n"
+             "        </interface>\n"
+             "    </hal>\n"
+             "</compatibility-matrix>");
+
+    addInput("compatibility_matrix.bazquux.xml",
+             "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+             "    <hal format=\"hidl\" optional=\"true\">\n"
+             "        <name>vendor.baz.quux</name>\n"
+             "        <version>1.0</version>\n"
+             "        <interface>\n"
+             "            <name>IBaz</name>\n"
+             "            <instance>default</instance>\n"
+             "        </interface>\n"
+             "    </hal>\n"
+             "</compatibility-matrix>");
+
+    EXPECT_TRUE(getInstance()->assemble());
+    EXPECT_IN(
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <hal format=\"hidl\" optional=\"true\">\n"
+        "        <name>vendor.baz.quux</name>\n"
+        "        <version>1.0</version>\n"
+        "        <interface>\n"
+        "            <name>IBaz</name>\n"
+        "            <instance>default</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\" optional=\"true\">\n"
+        "        <name>vendor.foo.bar</name>\n"
+        "        <version>1.0</version>\n"
+        "        <interface>\n"
+        "            <name>IFoo</name>\n"
+        "            <instance>default</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "        <sepolicy-version>26.0</sepolicy-version>\n"
+        "        <sepolicy-version>27.0</sepolicy-version>\n"
+        "        <sepolicy-version>10000.0</sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb>\n"
+        "        <vbmeta-version>1.0</vbmeta-version>\n"
+        "    </avb>\n"
+        "</compatibility-matrix>",
+        getOutput());
+}
+
+TEST_F(AssembleVintfTest, OutputFileMatrixTest) {
+    const std::string kFile = "file_name_1.xml";
+    const std::string kMatrix = "<compatibility-matrix version=\"1.0\" type=\"framework\"/>";
+    addInput(kFile, kMatrix);
+    EXPECT_TRUE(getInstance()->assemble());
+    EXPECT_IN(kFile, getOutput());
+}
+
+TEST_F(AssembleVintfTest, OutputFileManifestTest) {
+    const std::string kFile = "file_name_1.xml";
+    std::string kManifest = "<manifest version=\"1.0\" type=\"device\" target-level=\"1\"/>";
+    addInput(kFile, kManifest);
+    EXPECT_TRUE(getInstance()->assemble());
+    EXPECT_IN(kFile, getOutput());
+}
+
 }  // namespace vintf
 }  // namespace android
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index 5fbd1b7..a3a98b8 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -59,7 +59,10 @@
         return cm.add(std::move(hal));
     }
     bool add(CompatibilityMatrix &cm, MatrixKernel &&kernel) {
-        return cm.add(std::move(kernel));
+        std::string error;
+        bool success = cm.addKernel(std::move(kernel), &error);
+        EXPECT_EQ(success, error == "") << "success: " << success << ", error: " << error;
+        return success;
     }
     bool add(HalManifest &vm, ManifestHal &&hal) {
         return vm.add(std::move(hal));
@@ -98,9 +101,15 @@
     MatrixHal *getAnyHal(CompatibilityMatrix &cm, const std::string &name) {
         return cm.getAnyHal(name);
     }
-    ConstMultiMapValueIterable<std::string, ManifestHal> getHals(HalManifest &vm) {
+    ConstMultiMapValueIterable<std::string, ManifestHal> getHals(const HalManifest& vm) {
         return vm.getHals();
     }
+    std::vector<const ManifestHal*> getHals(const HalManifest& vm, const std::string& name) {
+        return vm.getHals(name);
+    }
+    std::vector<const MatrixHal*> getHals(const CompatibilityMatrix& cm, const std::string& name) {
+        return cm.getHals(name);
+    }
     bool isValid(const ManifestHal &mh) {
         return mh.isValid();
     }
@@ -254,7 +263,7 @@
 TEST_F(LibVintfTest, HalManifestConverter) {
     HalManifest vm = testDeviceManifest();
     std::string xml =
-        gHalManifestConverter(vm, SerializeFlag::HALS_NO_FQNAME & SerializeFlag::SEPOLICY_ONLY);
+        gHalManifestConverter(vm, SerializeFlags::NO_TAGS.enableHals().enableSepolicy());
     EXPECT_EQ(xml,
         "<manifest version=\"1.0\" type=\"device\">\n"
         "    <hal format=\"hidl\">\n"
@@ -291,8 +300,7 @@
 
 TEST_F(LibVintfTest, HalManifestConverterFramework) {
     HalManifest vm = testFrameworkManfiest();
-    std::string xml =
-        gHalManifestConverter(vm, SerializeFlag::HALS_NO_FQNAME & SerializeFlag::VNDK_ONLY);
+    std::string xml = gHalManifestConverter(vm, SerializeFlags::NO_TAGS.enableHals().enableVndk());
     EXPECT_EQ(xml,
         "<manifest version=\"1.0\" type=\"framework\">\n"
         "    <hal format=\"hidl\">\n"
@@ -741,11 +749,11 @@
                                              {Version(1, 0), Version(2, 1)},
                                              {Transport::PASSTHROUGH, Arch::ARCH_32_64},
                                              {{"INfc", {"INfc", {"default"}}}}};
-    auto cameraHals = vm.getHals("android.hardware.camera");
+    auto cameraHals = getHals(vm, "android.hardware.camera");
     EXPECT_EQ((int)cameraHals.size(), 2);
     EXPECT_EQ(*cameraHals[0], expectedCameraHalV1_2);
     EXPECT_EQ(*cameraHals[1], expectedCameraHalV2_0);
-    auto nfcHals = vm.getHals("android.hardware.nfc");
+    auto nfcHals = getHals(vm, "android.hardware.nfc");
     EXPECT_EQ((int)nfcHals.size(), 1);
     EXPECT_EQ(*nfcHals[0], expectedNfcHal);
 }
@@ -775,10 +783,10 @@
                                          {{VersionRange(4, 5, 6), VersionRange(10, 11, 12)}},
                                          true /* optional */,
                                          testHalInterfaces()};
-    auto cameraHals = cm.getHals("android.hardware.camera");
+    auto cameraHals = getHals(cm, "android.hardware.camera");
     EXPECT_EQ((int)cameraHals.size(), 1);
     EXPECT_EQ(*cameraHals[0], expectedCameraHal);
-    auto nfcHals = cm.getHals("android.hardware.nfc");
+    auto nfcHals = getHals(cm, "android.hardware.nfc");
     EXPECT_EQ((int)nfcHals.size(), 1);
     EXPECT_EQ(*nfcHals[0], expectedNfcHal);
 }
@@ -927,7 +935,7 @@
     std::string error;
     EXPECT_FALSE(ki.checkCompatibility(cm, &error));
     EXPECT_STREQ(error.c_str(), "AVB version 2.1 does not match framework matrix 1.0");
-    EXPECT_TRUE(ki.checkCompatibility(cm, &error, DISABLE_AVB_CHECK)) << error;
+    EXPECT_TRUE(ki.checkCompatibility(cm, &error, CheckFlags::DISABLE_AVB_CHECK)) << error;
 }
 
 // This is the test extracted from VINTF Object doc
@@ -1279,9 +1287,8 @@
 
 TEST_F(LibVintfTest, HalManifestConverterXmlFile) {
     HalManifest vm = testDeviceManifestWithXmlFile();
-    std::string xml =
-        gHalManifestConverter(vm, SerializeFlag::HALS_NO_FQNAME & SerializeFlag::SEPOLICY_ONLY &
-                                      SerializeFlag::XMLFILES_ONLY);
+    std::string xml = gHalManifestConverter(
+        vm, SerializeFlags::NO_TAGS.enableHals().enableSepolicy().enableXmlFiles());
     EXPECT_EQ(xml,
               "<manifest version=\"1.0\" type=\"device\">\n"
               "    <hal format=\"hidl\">\n"
@@ -1323,7 +1330,7 @@
 TEST_F(LibVintfTest, CompatibilityMatrixConverterXmlFile) {
     CompatibilityMatrix cm;
     addXmlFile(cm, "media_profile", {1, 0});
-    std::string xml = gCompatibilityMatrixConverter(cm, SerializeFlag::XMLFILES_ONLY);
+    std::string xml = gCompatibilityMatrixConverter(cm, SerializeFlags::XMLFILES_ONLY);
     EXPECT_EQ(xml,
               "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
               "    <xmlfile format=\"dtd\" optional=\"true\">\n"
@@ -1496,7 +1503,7 @@
 }
 
 TEST_F(LibVintfTest, KernelConfigParser2) {
-    // usage in android-base.cfg
+    // usage in android-base.config
     const std::string data =
         "# CONFIG_NOT_SET is not set\n"
         "CONFIG_ONE=1\n"
@@ -1516,7 +1523,7 @@
 }
 
 TEST_F(LibVintfTest, KernelConfigParserSpace) {
-    // usage in android-base.cfg
+    // usage in android-base.config
     const std::string data =
         "   #   CONFIG_NOT_SET is not set   \n"
         "  CONFIG_ONE=1   # 'tis a one!\n"
@@ -2106,7 +2113,7 @@
         << gCompatibilityMatrixConverter.lastError();
 
     EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
-    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
     EXPECT_EQ(xml,
               "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
               "    <hal format=\"hidl\" optional=\"true\">\n"
@@ -2155,7 +2162,7 @@
         << gCompatibilityMatrixConverter.lastError();
 
     EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
-    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
     EXPECT_EQ(xml,
               "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
               "    <hal format=\"hidl\" optional=\"false\">\n"
@@ -2205,7 +2212,7 @@
         << gCompatibilityMatrixConverter.lastError();
 
     EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
-    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
     EXPECT_EQ(xml,
               "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
               "    <hal format=\"hidl\" optional=\"false\">\n"
@@ -2255,7 +2262,7 @@
         << gCompatibilityMatrixConverter.lastError();
 
     EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
-    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
     EXPECT_EQ(xml,
               "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
               "    <hal format=\"hidl\" optional=\"false\">\n"
@@ -2317,7 +2324,7 @@
 
         EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
 
-        xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+        xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
         EXPECT_EQ(xml,
                   "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
                   "    <hal format=\"hidl\" optional=\"false\">\n"
@@ -2360,7 +2367,7 @@
 
         EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
 
-        xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+        xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
         EXPECT_EQ(xml,
                   "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
                   "    <hal format=\"hidl\" optional=\"false\">\n"
@@ -2443,7 +2450,7 @@
         << gCompatibilityMatrixConverter.lastError();
 
     EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
-    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::HALS_ONLY);
     EXPECT_EQ(
         "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
         "    <hal format=\"hidl\" optional=\"false\">\n"
@@ -2503,7 +2510,7 @@
         << gCompatibilityMatrixConverter.lastError();
 
     EXPECT_TRUE(addAllXmlFilesAsOptional(&cm1, &cm2, &error)) << error;
-    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::XMLFILES_ONLY);
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlags::XMLFILES_ONLY);
     EXPECT_EQ(xml,
               "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
               "    <xmlfile format=\"xsd\" optional=\"true\">\n"
@@ -2536,6 +2543,8 @@
         << gCompatibilityMatrixConverter.lastError();
     EXPECT_EQ(xml, gCompatibilityMatrixConverter(cm));
 
+    EXPECT_EQ("P", cm.getVendorNdkVersion());
+
     {
         HalManifest manifest;
         xml =
@@ -2658,10 +2667,10 @@
         "    </hal>\n"
         "</manifest>\n";
     EXPECT_TRUE(gHalManifestConverter(&manifest, xml)) << gHalManifestConverter.lastError();
-    const auto& foo = manifest.getHals("android.hardware.foo");
+    const auto& foo = getHals(manifest, "android.hardware.foo");
     ASSERT_FALSE(foo.empty());
     EXPECT_TRUE(foo.front()->isOverride());
-    const auto& bar = manifest.getHals("android.hardware.bar");
+    const auto& bar = getHals(manifest, "android.hardware.bar");
     ASSERT_FALSE(bar.empty());
     EXPECT_FALSE(bar.front()->isOverride());
 }
@@ -2688,7 +2697,7 @@
     EXPECT_TRUE(gHalManifestConverter(&newManifest, xml)) << gHalManifestConverter.lastError();
 
     manifest.addAllHals(&newManifest);
-    EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlag::HALS_NO_FQNAME));
+    EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlags::HALS_NO_FQNAME));
 }
 
 TEST_F(LibVintfTest, ManifestAddOverrideHalSimpleOverride) {
@@ -2719,7 +2728,7 @@
     EXPECT_TRUE(gHalManifestConverter(&newManifest, xml)) << gHalManifestConverter.lastError();
 
     manifest.addAllHals(&newManifest);
-    EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlag::HALS_NO_FQNAME));
+    EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlags::HALS_NO_FQNAME));
 }
 
 // Existing major versions should be removed.
@@ -2789,7 +2798,7 @@
         "        </interface>\n"
         "    </hal>\n"
         "</manifest>\n",
-        gHalManifestConverter(manifest, SerializeFlag::HALS_NO_FQNAME));
+        gHalManifestConverter(manifest, SerializeFlags::HALS_NO_FQNAME));
 }
 
 TEST_F(LibVintfTest, ManifestAddOverrideHalMultiVersion2) {
@@ -2826,7 +2835,7 @@
     EXPECT_TRUE(gHalManifestConverter(&newManifest, xml)) << gHalManifestConverter.lastError();
 
     manifest.addAllHals(&newManifest);
-    EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlag::HALS_NO_FQNAME));
+    EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlags::HALS_NO_FQNAME));
 }
 
 // if no <versions>, remove all existing <hal> with given <name>.
@@ -2885,7 +2894,7 @@
         "        <transport>hwbinder</transport>\n"
         "    </hal>\n"
         "</manifest>\n",
-        gHalManifestConverter(manifest, SerializeFlag::HALS_ONLY));
+        gHalManifestConverter(manifest, SerializeFlags::HALS_ONLY));
 }
 
 // Make sure missing tags in old VINTF files does not cause incompatibilities.
@@ -2919,7 +2928,7 @@
         "</compatibility-matrix>\n";
     EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
         << gCompatibilityMatrixConverter.lastError();
-    EXPECT_EQ(xml, gCompatibilityMatrixConverter(cm, ~SerializeFlag::NO_SSDK));
+    EXPECT_EQ(xml, gCompatibilityMatrixConverter(cm, SerializeFlags::SSDK_ONLY));
 
     {
         HalManifest manifest;
@@ -2931,7 +2940,7 @@
             "    </system-sdk>\n"
             "</manifest>\n";
         EXPECT_TRUE(gHalManifestConverter(&manifest, xml)) << gHalManifestConverter.lastError();
-        EXPECT_EQ(xml, gHalManifestConverter(manifest, ~SerializeFlag::NO_SSDK));
+        EXPECT_EQ(xml, gHalManifestConverter(manifest, SerializeFlags::SSDK_ONLY));
 
         EXPECT_TRUE(manifest.checkCompatibility(cm, &error)) << error;
     }
@@ -3112,13 +3121,13 @@
         "</manifest>\n";
     ASSERT_TRUE(gHalManifestConverter(&manifest, xml, &error)) << error;
 
-    auto foo = manifest.getHals("android.hardware.foo");
+    auto foo = getHals(manifest, "android.hardware.foo");
     ASSERT_EQ(1u, foo.size());
     EXPECT_TRUE(foo.front()->isDisabledHal());
-    auto bar = manifest.getHals("android.hardware.bar");
+    auto bar = getHals(manifest, "android.hardware.bar");
     ASSERT_EQ(1u, bar.size());
     EXPECT_FALSE(bar.front()->isDisabledHal());
-    auto baz = manifest.getHals("android.hardware.baz");
+    auto baz = getHals(manifest, "android.hardware.baz");
     ASSERT_EQ(1u, baz.size());
     EXPECT_FALSE(baz.front()->isDisabledHal());
 }
@@ -3427,6 +3436,12 @@
     EXPECT_FALSE(regex.matches("legacy/0sss"));
 }
 
+TEST_F(LibVintfTest, ManifestGetHalNamesAndVersions) {
+    HalManifest vm = testDeviceManifest();
+    EXPECT_EQ(vm.getHalNamesAndVersions(),
+              std::set<std::string>({"android.hardware.camera@2.0", "android.hardware.nfc@1.0"}));
+}
+
 } // namespace vintf
 } // namespace android
 
diff --git a/test/utils-fake.cpp b/test/utils-fake.cpp
index 38f6ab0..ce82cd4 100644
--- a/test/utils-fake.cpp
+++ b/test/utils-fake.cpp
@@ -20,14 +20,6 @@
 namespace vintf {
 namespace details {
 
-// Do not create the mock objects here as InitGoogleMock must be called
-// first.
-FileFetcher* gFetcher = nullptr;
-
-PartitionMounter* gPartitionMounter = nullptr;
-
-ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory = nullptr;
-
 MockPropertyFetcher::MockPropertyFetcher() {
     using namespace ::testing;
     using namespace std::placeholders;
@@ -35,11 +27,6 @@
         .WillByDefault(Invoke(std::bind(&PropertyFetcher::getProperty, real_, _1, _2)));
 }
 
-MockPropertyFetcher* gPropertyFetcher = nullptr;
-const PropertyFetcher& getPropertyFetcher() {
-    return *gPropertyFetcher;
-}
-
 }  // namespace details
 }  // namespace vintf
 }  // namespace android
diff --git a/test/utils-fake.h b/test/utils-fake.h
index 0253bca..653c3b9 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 {
@@ -116,11 +108,12 @@
    public:
     MockPropertyFetcher();
     MOCK_CONST_METHOD2(getProperty, std::string(const std::string&, const std::string&));
+    MOCK_CONST_METHOD2(getBoolProperty, bool(const std::string&, bool));
+    MOCK_CONST_METHOD3(getUintProperty, uint64_t(const std::string&, uint64_t, uint64_t));
 
    private:
-    PropertyFetcher real_;
+    PropertyFetcherImpl real_;
 };
-extern MockPropertyFetcher* gPropertyFetcher;
 
 }  // namespace details
 }  // namespace vintf
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 86d43a4..34cee2d 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -29,8 +29,6 @@
 #include <hidl-util/FQName.h>
 
 using namespace ::testing;
-using namespace ::android::vintf;
-using namespace ::android::vintf::details;
 
 using android::FqInstance;
 
@@ -41,6 +39,12 @@
 #define EXPECT_IN(sub, str) EXPECT_TRUE(In((sub), (str)))
 #define EXPECT_NOT_IN(sub, str) EXPECT_FALSE(In((sub), (str)))
 
+namespace android {
+namespace vintf {
+namespace testing {
+
+using namespace ::android::vintf::details;
+
 //
 // Set of Xml1 metadata compatible with each other.
 //
@@ -277,69 +281,90 @@
     "    </hal>\n"
     "</compatibility-matrix>\n"};
 
-// 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,
-                      const std::string& productModel) {
-    MockFileFetcher* fetcher = static_cast<MockFileFetcher*>(gFetcher);
-
-    if (!productModel.empty()) {
-        ON_CALL(*fetcher, fetch(StrEq(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml"), _))
-            .WillByDefault(Return(::android::NAME_NOT_FOUND));
-        ON_CALL(*fetcher, fetch(StrEq(kOdmVintfDir + "manifest_" + productModel + ".xml"), _))
-            .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    }
-    ON_CALL(*fetcher, fetch(StrEq(kOdmLegacyManifest), _))
-        .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    ON_CALL(*fetcher, fetch(StrEq(kOdmManifest), _))
-        .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    ON_CALL(*fetcher, fetch(StrEq(kVendorManifest), _))
-        .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    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), _))
-        .WillByDefault(Invoke([systemManifestXml](const std::string& path, std::string& fetched) {
-            (void)path;
-            fetched = systemManifestXml;
-            return 0;
-        }));
-    ON_CALL(*fetcher, fetch(StrEq(kVendorMatrix), _))
-        .WillByDefault(Return(::android::NAME_NOT_FOUND));
-    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), _))
-        .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);
-}
-
-class VintfObjectTestBase : public testing::Test {
+class VintfObjectTestBase : public ::testing::Test {
    protected:
-    virtual void SetUp() {
+    MockPartitionMounter& mounter() {
+        return static_cast<MockPartitionMounter&>(*vintfObject->getPartitionMounter());
+    }
+    MockFileSystem& fetcher() {
+        return static_cast<MockFileSystem&>(*vintfObject->getFileSystem());
+    }
+    MockPropertyFetcher& propertyFetcher() {
+        return static_cast<MockPropertyFetcher&>(*vintfObject->getPropertyFetcher());
+    }
+
+    // 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) {
+        ON_CALL(fetcher(), listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+            .WillByDefault(Return(::android::OK));
+        ON_CALL(fetcher(), listFiles(StrEq(kSystemManifestFragmentDir), _, _))
+            .WillByDefault(Return(::android::OK));
+        ON_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+            .WillByDefault(Return(::android::OK));
+
+        if (!productModel.empty()) {
+            ON_CALL(fetcher(),
+                    fetch(StrEq(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml"), _))
+                .WillByDefault(Return(::android::NAME_NOT_FOUND));
+            ON_CALL(fetcher(), fetch(StrEq(kOdmVintfDir + "manifest_" + productModel + ".xml"), _))
+                .WillByDefault(Return(::android::NAME_NOT_FOUND));
+        }
+        ON_CALL(fetcher(), fetch(StrEq(kOdmLegacyManifest), _))
+            .WillByDefault(Return(::android::NAME_NOT_FOUND));
+        ON_CALL(fetcher(), fetch(StrEq(kOdmManifest), _))
+            .WillByDefault(Return(::android::NAME_NOT_FOUND));
+        ON_CALL(fetcher(), fetch(StrEq(kVendorManifest), _))
+            .WillByDefault(Return(::android::NAME_NOT_FOUND));
+        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), _))
+            .WillByDefault(
+                Invoke([systemManifestXml](const std::string& path, std::string& fetched) {
+                    (void)path;
+                    fetched = systemManifestXml;
+                    return 0;
+                }));
+        ON_CALL(fetcher(), fetch(StrEq(kVendorMatrix), _))
+            .WillByDefault(Return(::android::NAME_NOT_FOUND));
+        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), _))
+            .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));
+    }
+
+    void setFakeProperties() {
         productModel = "fake_sku";
-        ON_CALL(*gPropertyFetcher, getProperty("ro.boot.product.hardware.sku", _))
+        ON_CALL(propertyFetcher(), getProperty("ro.boot.product.hardware.sku", _))
             .WillByDefault(Return(productModel));
     }
+
+    virtual void SetUp() {
+        vintfObject =
+            std::make_unique<VintfObject>(std::make_unique<NiceMock<MockFileSystem>>(),
+                                          std::make_unique<NiceMock<MockPartitionMounter>>(),
+                                          std::make_unique<NiceMock<MockRuntimeInfoFactory>>(
+                                              std::make_shared<NiceMock<MockRuntimeInfo>>()),
+                                          std::make_unique<NiceMock<MockPropertyFetcher>>());
+    }
     virtual void TearDown() {
         Mock::VerifyAndClear(&mounter());
         Mock::VerifyAndClear(&fetcher());
@@ -406,6 +431,7 @@
     }
 
     std::string productModel;
+    std::unique_ptr<VintfObject> vintfObject;
 };
 
 // Test fixture that provides compatible metadata from the mock device.
@@ -413,10 +439,16 @@
    protected:
     virtual void SetUp() {
         VintfObjectTestBase::SetUp();
+        setFakeProperties();
         mounter().reset();
         setupMockFetcher(vendorManifestXml1, systemMatrixXml1, systemManifestXml1, vendorMatrixXml1,
                          productModel);
     }
+
+    // Access to private method for force mounting.
+    int checkCompatibility(const std::vector<std::string>& xmls, bool mount, std::string* error) {
+        return vintfObject->checkCompatibility(xmls, mount, error);
+    }
 };
 
 // Tests that local info is checked.
@@ -433,7 +465,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(0);
     EXPECT_CALL(mounter(), umountVendor()).Times(0);
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     // Check that nothing was ignored.
@@ -451,7 +483,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(2);
     EXPECT_CALL(mounter(), umountVendor()).Times(1);
 
-    int result = details::checkCompatibility(packageInfo, true /* mount */, mounter(), &error);
+    int result = checkCompatibility(packageInfo, true /* mount */, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     EXPECT_FALSE(mounter().systemMounted());
@@ -472,7 +504,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(0);
     EXPECT_CALL(mounter(), umountVendor()).Times(0);
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     ASSERT_STREQ(error.c_str(), "");
@@ -489,7 +521,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(2);
     EXPECT_CALL(mounter(), umountVendor()).Times(1);
 
-    int result = details::checkCompatibility(packageInfo, true /* mount */, mounter(), &error);
+    int result = checkCompatibility(packageInfo, true /* mount */, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     EXPECT_FALSE(mounter().systemMounted());
@@ -501,7 +533,7 @@
     std::string error;
     std::vector<std::string> packageInfo = {systemMatrixXml2};
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 1) << "Should have failed:" << error.c_str();
     EXPECT_IN(
@@ -516,7 +548,7 @@
     std::string error;
     std::vector<std::string> packageInfo = {systemMatrixXml2, vendorManifestXml2};
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 0) << "Failed message:" << error.c_str();
     ASSERT_STREQ(error.c_str(), "");
@@ -535,7 +567,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(0);
     EXPECT_CALL(mounter(), umountVendor()).Times(0);
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     ASSERT_STREQ(error.c_str(), "");
@@ -552,7 +584,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(2);
     EXPECT_CALL(mounter(), umountVendor()).Times(1);
 
-    int result = details::checkCompatibility(packageInfo, true /* mount */, mounter(), &error);
+    int result = checkCompatibility(packageInfo, true /* mount */, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     EXPECT_FALSE(mounter().systemMounted());
@@ -573,7 +605,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(0);
     EXPECT_CALL(mounter(), umountVendor()).Times(0);
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     ASSERT_STREQ(error.c_str(), "");
@@ -591,7 +623,7 @@
     EXPECT_CALL(mounter(), mountVendor()).Times(0);
     EXPECT_CALL(mounter(), umountVendor()).Times(1);
 
-    int result = details::checkCompatibility(packageInfo, true /* mount */, mounter(), &error);
+    int result = checkCompatibility(packageInfo, true /* mount */, &error);
 
     ASSERT_EQ(result, 0) << "Fail message:" << error.c_str();
     EXPECT_FALSE(mounter().systemMounted());
@@ -603,6 +635,7 @@
    protected:
     virtual void SetUp() {
         VintfObjectTestBase::SetUp();
+        setFakeProperties();
         mounter().reset();
         setupMockFetcher(vendorManifestXml1, systemMatrixXml2, systemManifestXml1, vendorMatrixXml1,
                          productModel);
@@ -619,7 +652,7 @@
     expectVendorMatrix();
     expectSystemMatrix();
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 1) << "Should have failed:" << error.c_str();
 }
@@ -634,28 +667,28 @@
     expectVendorMatrix();
     expectSystemMatrix(0);
 
-    int result = VintfObject::CheckCompatibility(packageInfo, &error);
+    int result = vintfObject->checkCompatibility(packageInfo, &error);
 
     ASSERT_EQ(result, 0) << "Failed message:" << error.c_str();
     ASSERT_STREQ(error.c_str(), "");
 }
 
-static MockRuntimeInfoFactory& runtimeInfoFactory() {
-    return *static_cast<MockRuntimeInfoFactory*>(gRuntimeInfoFactory);
-}
-
 // Test fixture that provides compatible metadata from the mock device.
-class VintfObjectRuntimeInfoTest : public testing::Test {
+class VintfObjectRuntimeInfoTest : public VintfObjectTestBase {
    protected:
     virtual void SetUp() {
+        VintfObjectTestBase::SetUp();
         // clear fetch flags
         runtimeInfoFactory().getInfo()->failNextFetch();
-        VintfObject::GetRuntimeInfo(true /* skipCache */, RuntimeInfo::FetchFlag::ALL);
+        vintfObject->getRuntimeInfo(true /* skipCache */, RuntimeInfo::FetchFlag::ALL);
     }
     virtual void TearDown() {
         Mock::VerifyAndClear(&runtimeInfoFactory());
         Mock::VerifyAndClear(runtimeInfoFactory().getInfo().get());
     }
+    MockRuntimeInfoFactory& runtimeInfoFactory() {
+        return static_cast<MockRuntimeInfoFactory&>(*vintfObject->getRuntimeInfoFactory());
+    }
 };
 
 TEST_F(VintfObjectRuntimeInfoTest, GetRuntimeInfo) {
@@ -672,18 +705,28 @@
     EXPECT_CALL(*runtimeInfoFactory().getInfo(), fetchAllInformation(RuntimeInfo::FetchFlag::ALL));
     EXPECT_CALL(*runtimeInfoFactory().getInfo(), fetchAllInformation(RuntimeInfo::FetchFlag::NONE));
 
-    VintfObject::GetRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::CPU_VERSION);
-    VintfObject::GetRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::CPU_VERSION);
-    VintfObject::GetRuntimeInfo(true /* skipCache */, RuntimeInfo::FetchFlag::CPU_VERSION);
-    VintfObject::GetRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::ALL);
-    VintfObject::GetRuntimeInfo(true /* skipCache */, RuntimeInfo::FetchFlag::ALL);
-    VintfObject::GetRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::ALL);
+    vintfObject->getRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::CPU_VERSION);
+    vintfObject->getRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::CPU_VERSION);
+    vintfObject->getRuntimeInfo(true /* skipCache */, RuntimeInfo::FetchFlag::CPU_VERSION);
+    vintfObject->getRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::ALL);
+    vintfObject->getRuntimeInfo(true /* skipCache */, RuntimeInfo::FetchFlag::ALL);
+    vintfObject->getRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::ALL);
 }
 
 // Test fixture that provides incompatible metadata from the mock device.
 class VintfObjectTest : public VintfObjectTestBase {
    protected:
-    virtual void SetUp() {}
+    virtual void SetUp() {
+        VintfObjectTestBase::SetUp();
+
+        // By default use empty filesystem
+        EXPECT_CALL(fetcher(), listFiles(_, _, _))
+            .Times(AnyNumber())
+            .WillRepeatedly(Return(::android::OK));
+        EXPECT_CALL(fetcher(), fetch(_, _))
+            .Times(AnyNumber())
+            .WillRepeatedly(Return(::android::NAME_NOT_FOUND));
+    }
 };
 
 // Test framework compatibility matrix is combined at runtime
@@ -700,9 +743,10 @@
                 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\"/>");
     expectFetch(kSystemVintfDir + "compatibility_matrix.empty.xml",
                 "<compatibility-matrix version=\"1.0\" type=\"framework\"/>");
+    expectFetch(kVendorManifest, "<manifest version=\"1.0\" type=\"device\" />\n");
     expectSystemMatrix(0);
 
-    EXPECT_NE(nullptr, VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */));
+    EXPECT_NE(nullptr, vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */));
 }
 
 const std::string vendorEtcManifest =
@@ -794,7 +838,7 @@
     }
     void noOdmManifest() { expectFileNotExist(StartsWith("/odm/")); }
     std::shared_ptr<const HalManifest> get() {
-        return VintfObject::GetDeviceHalManifest(true /* skipCache */);
+        return vintfObject->getDeviceHalManifest(true /* skipCache */);
     }
 };
 
@@ -850,6 +894,7 @@
 class OdmManifestTest : public VintfObjectTestBase {
    protected:
     virtual void SetUp() override {
+        VintfObjectTestBase::SetUp();
         // Assume /vendor/etc/vintf/manifest.xml does not exist to simplify
         // testing logic.
         expectFileNotExist(StrEq(kVendorManifest));
@@ -859,7 +904,7 @@
         expectFileNotExist(StartsWith("/odm/"));
     }
     std::shared_ptr<const HalManifest> get() {
-        return VintfObject::GetDeviceHalManifest(true /* skipCache */);
+        return vintfObject->getDeviceHalManifest(true /* skipCache */);
     }
 };
 
@@ -923,6 +968,7 @@
 class DeprecateTest : public VintfObjectTestBase {
    protected:
     virtual void SetUp() override {
+        VintfObjectTestBase::SetUp();
         EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
             .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) {
                 *out = {
@@ -931,6 +977,10 @@
                 };
                 return ::android::OK;
             }));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
         expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml", systemMatrixLevel1);
         expectFetch(kSystemVintfDir + "compatibility_matrix.2.xml", systemMatrixLevel2);
         expectSystemMatrix(0);
@@ -941,7 +991,7 @@
 
         // Update the device manifest cache because CheckDeprecate does not fetch
         // device manifest again if cache exist.
-        VintfObject::GetDeviceHalManifest(true /* skipCache */);
+        vintfObject->getDeviceHalManifest(true /* skipCache */);
     }
 
 };
@@ -952,7 +1002,7 @@
         "android.hardware.major@2.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(NO_DEPRECATED_HALS, VintfObject::CheckDeprecation(pred, &error)) << error;
+    EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, &error)) << error;
 }
 
 TEST_F(DeprecateTest, CheckRemoved) {
@@ -962,7 +1012,7 @@
         "android.hardware.major@2.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+    EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
         << "removed@1.0 should be deprecated. " << error;
 }
 
@@ -972,7 +1022,7 @@
         "android.hardware.major@2.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+    EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
         << "minor@1.0 should be deprecated. " << error;
 }
 
@@ -983,7 +1033,7 @@
         "android.hardware.major@2.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+    EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
         << "minor@1.0::IMinor/legacy should be deprecated. " << error;
 }
 
@@ -994,7 +1044,7 @@
         "android.hardware.major@2.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+    EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
         << "minor@1.1::IMinor/legacy should be deprecated. " << error;
 }
 
@@ -1005,7 +1055,7 @@
         "android.hardware.major@2.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+    EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
         << "major@1.0 should be deprecated. " << error;
 }
 
@@ -1015,7 +1065,7 @@
         "android.hardware.major@1.0::IMajor/default",
     });
     std::string error;
-    EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+    EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
         << "major@1.0 should be deprecated. " << error;
 }
 
@@ -1035,6 +1085,10 @@
                 }
                 return ::android::OK;
             }));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
         size_t i = 1;
         for (const auto& content : xmls) {
             expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content);
@@ -1046,18 +1100,21 @@
     void expectTargetFcmVersion(size_t level) {
         expectFetch(kVendorManifest, "<manifest version=\"1.0\" type=\"device\" target-level=\"" +
                                          to_string(static_cast<Level>(level)) + "\"/>");
-        VintfObject::GetDeviceHalManifest(true /* skipCache */);
+        vintfObject->getDeviceHalManifest(true /* skipCache */);
     }
 };
 
 class RegexTest : public MultiMatrixTest {
    protected:
-    virtual void SetUp() { SetUpMockSystemMatrices(systemMatrixRegexXmls); }
+    virtual void SetUp() {
+        MultiMatrixTest::SetUp();
+        SetUpMockSystemMatrices(systemMatrixRegexXmls);
+    }
 };
 
 TEST_F(RegexTest, CombineLevel1) {
     expectTargetFcmVersion(1);
-    auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
+    auto matrix = vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */);
     ASSERT_NE(nullptr, matrix);
     std::string xml = gCompatibilityMatrixConverter(*matrix);
 
@@ -1112,7 +1169,7 @@
 
 TEST_F(RegexTest, CombineLevel2) {
     expectTargetFcmVersion(2);
-    auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
+    auto matrix = vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */);
     ASSERT_NE(nullptr, matrix);
     std::string xml = gCompatibilityMatrixConverter(*matrix);
 
@@ -1164,7 +1221,7 @@
         "android.hardware.regex@1.1::IRegex/regex_common/0",
         "android.hardware.regex@2.0::IRegex/default",
     });
-    EXPECT_EQ(NO_DEPRECATED_HALS, VintfObject::CheckDeprecation(pred, &error)) << error;
+    EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, &error)) << error;
 
     for (const auto& deprecated : {
              "android.hardware.regex@1.0::IRegex/default",
@@ -1180,7 +1237,7 @@
             "android.hardware.regex@2.0::IRegex/default",
         });
         error.clear();
-        EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+        EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
             << deprecated << " should be deprecated. " << error;
     }
 }
@@ -1194,7 +1251,7 @@
         "android.hardware.regex@2.0::IRegex/regex/2.0/1",
         "android.hardware.regex@2.0::IRegex/default",
     });
-    EXPECT_EQ(NO_DEPRECATED_HALS, VintfObject::CheckDeprecation(pred, &error)) << error;
+    EXPECT_EQ(NO_DEPRECATED_HALS, vintfObject->checkDeprecation(pred, &error)) << error;
 
     for (const auto& deprecated : {
              "android.hardware.regex@1.0::IRegex/default",
@@ -1214,7 +1271,7 @@
         });
 
         error.clear();
-        EXPECT_EQ(DEPRECATED, VintfObject::CheckDeprecation(pred, &error))
+        EXPECT_EQ(DEPRECATED, vintfObject->checkDeprecation(pred, &error))
             << deprecated << " should be deprecated.";
     }
 }
@@ -1258,7 +1315,7 @@
     SetUpMockSystemMatrices({systemMatrixKernelXmls[0], systemMatrixKernelXmls[1]});
 
     expectTargetFcmVersion(1);
-    auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
+    auto matrix = vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */);
     ASSERT_NE(nullptr, matrix);
     std::string xml = gCompatibilityMatrixConverter(*matrix);
 
@@ -1276,7 +1333,7 @@
     SetUpMockSystemMatrices({systemMatrixKernelXmls});
 
     expectTargetFcmVersion(1);
-    auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
+    auto matrix = vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */);
     ASSERT_NE(nullptr, matrix);
     std::string xml = gCompatibilityMatrixConverter(*matrix);
 
@@ -1290,21 +1347,11 @@
     EXPECT_NOT_IN(FAKE_KERNEL("4.0.0", "D3"), xml) << "\nOld requirements must not change";
 }
 
+}  // namespace testing
+}  // namespace vintf
+}  // namespace android
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleMock(&argc, argv);
-
-    NiceMock<MockFileFetcher> fetcher;
-    gFetcher = &fetcher;
-
-    NiceMock<MockPartitionMounter> mounter;
-    gPartitionMounter = &mounter;
-
-    NiceMock<MockRuntimeInfoFactory> runtimeInfoFactory(
-        std::make_shared<NiceMock<MockRuntimeInfo>>());
-    gRuntimeInfoFactory = &runtimeInfoFactory;
-
-    NiceMock<MockPropertyFetcher> properties;
-    gPropertyFetcher = &properties;
-
     return RUN_ALL_TESTS();
 }
diff --git a/utils-common.cpp b/utils-common.cpp
deleted file mode 100644
index 3e7e736..0000000
--- a/utils-common.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-
-/*
- * 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"
-
-// Default implementations for classes defined in utils.h
-
-namespace android {
-namespace vintf {
-namespace details {
-
-std::string PropertyFetcher::getProperty(const std::string&,
-                                         const std::string& defaultValue) const {
-    return defaultValue;
-}
-
-uint64_t PropertyFetcher::getUintProperty(const std::string&, uint64_t,
-                                          uint64_t defaultValue) const {
-    return defaultValue;
-}
-
-bool PropertyFetcher::getBoolProperty(const std::string&, bool defaultValue) const {
-    return defaultValue;
-}
-
-}  // namespace details
-}  // namespace vintf
-}  // namespace android
diff --git a/utils.cpp b/utils.cpp
deleted file mode 100644
index 5b2bb7d..0000000
--- a/utils.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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"
-
-#ifdef LIBVINTF_TARGET
-#include <android-base/properties.h>
-#endif
-
-namespace android {
-namespace vintf {
-namespace details {
-
-static FileFetcher fetcher;
-FileFetcher* gFetcher = &fetcher;
-
-static PartitionMounter partitionMounter;
-PartitionMounter* gPartitionMounter = &partitionMounter;
-
-static ObjectFactory<RuntimeInfo> runtimeInfoFactory;
-ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory = &runtimeInfoFactory;
-
-#ifdef LIBVINTF_TARGET
-class DevicePropertyFetcher : public PropertyFetcher {
-   public:
-    std::string getProperty(const std::string& key,
-                            const std::string& defaultValue) const override {
-        return android::base::GetProperty(key, defaultValue);
-    }
-    uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
-                             uint64_t max) const override {
-        return android::base::GetUintProperty(key, defaultValue, max);
-    }
-    bool getBoolProperty(const std::string& key, bool defaultValue) const override {
-        return android::base::GetBoolProperty(key, defaultValue);
-    }
-};
-const PropertyFetcher& getPropertyFetcher() {
-    static DevicePropertyFetcher fetcher;
-    return fetcher;
-}
-#else
-const PropertyFetcher& getPropertyFetcher() {
-    static PropertyFetcher fetcher;
-    return fetcher;
-}
-#endif
-
-}  // namespace details
-}  // namespace vintf
-}  // namespace android
diff --git a/utils.h b/utils.h
index 783d40b..8ccda3e 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() {}
@@ -92,19 +38,11 @@
     virtual status_t umountVendor() const { return OK; }
 };
 
-extern PartitionMounter* gPartitionMounter;
-
 template <typename T>
-status_t fetchAllInformation(const std::string& path, const XmlConverter<T>& converter,
-                             T* outObject, std::string* error = nullptr) {
+status_t fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
+                             const XmlConverter<T>& converter, T* outObject, std::string* error) {
     std::string info;
-
-    if (gFetcher == nullptr) {
-        // Should never happen.
-        return NO_INIT;
-    }
-
-    status_t result = gFetcher->fetch(path, info, error);
+    status_t result = fileSystem->fetch(path, &info, error);
 
     if (result != OK) {
         return result;
@@ -126,7 +64,6 @@
     virtual ~ObjectFactory() = default;
     virtual std::shared_ptr<T> make_shared() const { return std::make_shared<T>(); }
 };
-extern ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory;
 
 // TODO(b/70628538): Do not infer from Shipping API level.
 inline Level convertFromApiLevel(size_t apiLevel) {
@@ -145,13 +82,29 @@
    public:
     virtual ~PropertyFetcher() = default;
     virtual std::string getProperty(const std::string& key,
+                                    const std::string& defaultValue = "") const = 0;
+    virtual uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
+                                     uint64_t max = UINT64_MAX) const = 0;
+    virtual bool getBoolProperty(const std::string& key, bool defaultValue) const = 0;
+};
+
+class PropertyFetcherImpl : public PropertyFetcher {
+   public:
+    virtual std::string getProperty(const std::string& key,
                                     const std::string& defaultValue = "") const;
     virtual uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
                                      uint64_t max = UINT64_MAX) const;
     virtual bool getBoolProperty(const std::string& key, bool defaultValue) const;
 };
 
-const PropertyFetcher& getPropertyFetcher();
+class PropertyFetcherNoOp : public PropertyFetcher {
+   public:
+    virtual std::string getProperty(const std::string& key,
+                                    const std::string& defaultValue = "") const override;
+    virtual uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
+                                     uint64_t max = UINT64_MAX) const override;
+    virtual bool getBoolProperty(const std::string& key, bool defaultValue) const override;
+};
 
 }  // namespace details
 }  // namespace vintf