VintfObject::checkCompatibility loads XMLs from the device correctly. am: 12e23c23ab
am: d633b3b5c0

Change-Id: I9d27f4fbbb87f0c5130fde5977e4bb8f26dc1f69
diff --git a/VintfObject.cpp b/VintfObject.cpp
index f39b933..a1d4a6c 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -16,11 +16,6 @@
 
 #include "VintfObject.h"
 
-#include "CompatibilityMatrix.h"
-#include "parse_string.h"
-#include "parse_xml.h"
-#include "utils.h"
-
 #include <dirent.h>
 
 #include <functional>
@@ -29,6 +24,12 @@
 
 #include <android-base/logging.h>
 
+#include "CompatibilityMatrix.h"
+#include "VintfObjectAfterUpdate.h"
+#include "parse_string.h"
+#include "parse_xml.h"
+#include "utils.h"
+
 using std::placeholders::_1;
 using std::placeholders::_2;
 
@@ -146,7 +147,7 @@
     }
 
     return Get(&mFrameworkMatrix, skipCache,
-               std::bind(&CompatibilityMatrix::fetchAllInformation, _1, mFileSystem.get(),
+               std::bind(&CompatibilityMatrix::fetchAllInformation, _1, getFileSystem().get(),
                          kSystemLegacyMatrix, _2));
 }
 
@@ -166,7 +167,7 @@
 
     // TODO(b/70628538): Do not infer from Shipping API level.
     if (deviceLevel == Level::UNSPECIFIED) {
-        auto shippingApi = mPropertyFetcher->getUintProperty("ro.product.first_api_level", 0u);
+        auto shippingApi = getPropertyFetcher()->getUintProperty("ro.product.first_api_level", 0u);
         if (shippingApi != 0u) {
             deviceLevel = details::convertFromApiLevel(shippingApi);
         }
@@ -205,7 +206,7 @@
 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);
+    status_t err = getFileSystem()->listFiles(directory, &fileNames, error);
     // if the directory isn't there, that's okay
     if (err == NAME_NOT_FOUND) return OK;
     if (err != OK) return err;
@@ -264,7 +265,7 @@
     }
 
     // Use legacy /vendor/manifest.xml
-    return out->fetchAllInformation(mFileSystem.get(), kVendorLegacyManifest, error);
+    return out->fetchAllInformation(getFileSystem().get(), kVendorLegacyManifest, error);
 }
 
 // "out" is written to iff return status is OK.
@@ -279,7 +280,7 @@
     status_t status;
 
     std::string productModel;
-    productModel = mPropertyFetcher->getProperty("ro.boot.product.hardware.sku", "");
+    productModel = getPropertyFetcher()->getProperty("ro.boot.product.hardware.sku", "");
 
     if (!productModel.empty()) {
         status =
@@ -315,7 +316,7 @@
 status_t VintfObject::fetchOneHalManifest(const std::string& path, HalManifest* out,
                                           std::string* error) {
     HalManifest ret;
-    status_t status = ret.fetchAllInformation(mFileSystem.get(), path, error);
+    status_t status = ret.fetchAllInformation(getFileSystem().get(), path, error);
     if (status == OK) {
         *out = std::move(ret);
     }
@@ -324,20 +325,20 @@
 
 status_t VintfObject::fetchDeviceMatrix(CompatibilityMatrix* out, std::string* error) {
     CompatibilityMatrix etcMatrix;
-    if (etcMatrix.fetchAllInformation(mFileSystem.get(), kVendorMatrix, error) == OK) {
+    if (etcMatrix.fetchAllInformation(getFileSystem().get(), kVendorMatrix, error) == OK) {
         *out = std::move(etcMatrix);
         return OK;
     }
-    return out->fetchAllInformation(mFileSystem.get(), kVendorLegacyMatrix, error);
+    return out->fetchAllInformation(getFileSystem().get(), kVendorLegacyMatrix, error);
 }
 
 status_t VintfObject::fetchFrameworkHalManifest(HalManifest* out, std::string* error) {
     HalManifest etcManifest;
-    if (etcManifest.fetchAllInformation(mFileSystem.get(), kSystemManifest, error) == OK) {
+    if (etcManifest.fetchAllInformation(getFileSystem().get(), kSystemManifest, error) == OK) {
         *out = std::move(etcManifest);
         return addDirectoryManifests(kSystemManifestFragmentDir, out, error);
     }
-    return out->fetchAllInformation(mFileSystem.get(), kSystemLegacyManifest, error);
+    return out->fetchAllInformation(getFileSystem().get(), kSystemLegacyManifest, error);
 }
 
 static void appendLine(std::string* error, const std::string& message) {
@@ -352,7 +353,7 @@
     std::vector<std::string> fileNames;
     std::vector<Named<CompatibilityMatrix>> results;
 
-    if (mFileSystem->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
+    if (getFileSystem()->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
         return {};
     }
     for (const std::string& fileName : fileNames) {
@@ -360,7 +361,7 @@
 
         std::string content;
         std::string fetchError;
-        status_t status = mFileSystem->fetch(path, &content, &fetchError);
+        status_t status = getFileSystem()->fetch(path, &content, &fetchError);
         if (status != OK) {
             appendLine(error, "Framework Matrix: Ignore file " + path + ": " + fetchError);
             continue;
@@ -403,7 +404,7 @@
     }
 
     if (mDeviceRuntimeInfo.object == nullptr) {
-        mDeviceRuntimeInfo.object = mRuntimeInfoFactory->make_shared();
+        mDeviceRuntimeInfo.object = getRuntimeInfoFactory()->make_shared();
     }
 
     status_t status = mDeviceRuntimeInfo.object->fetchAllInformation(flags);
@@ -435,72 +436,36 @@
     return "";
 }
 
-template<typename T>
-static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
-        std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
+template <typename T>
+static ParseStatus tryParse(const std::string& xml, const XmlConverter<T>& parse,
+                            VintfObjectAfterUpdate* afterUpdate) {
     std::shared_ptr<T> ret = std::make_shared<T>();
     if (!parse(ret.get(), xml, nullptr /* error */)) {
         return ParseStatus::PARSE_ERROR;
     }
-    if (ret->type() == SchemaType::FRAMEWORK) {
-        if (fwk->get() != nullptr) {
+    if (!afterUpdate->set(ret)) {
+        if (ret->type() == SchemaType::FRAMEWORK) {
             return ParseStatus::DUPLICATED_FWK_ENTRY;
-        }
-        *fwk = std::move(ret);
-    } else if (ret->type() == SchemaType::DEVICE) {
-        if (dev->get() != nullptr) {
+        } else if (ret->type() == SchemaType::DEVICE) {
             return ParseStatus::DUPLICATED_DEV_ENTRY;
         }
-        *dev = std::move(ret);
+        LOG(FATAL) << "unknown SchemaType: "
+                   << static_cast<std::underlying_type_t<SchemaType>>(ret->type());
     }
     return ParseStatus::OK;
 }
 
-template <typename T, typename GetFunction>
-static status_t getMissing(const std::shared_ptr<T>& pkg, std::shared_ptr<const T>* updated,
-                           GetFunction getFunction) {
-    if (pkg != nullptr) {
-        *updated = pkg;
-    } else {
-        *updated = getFunction();
-    }
-    return OK;
-}
-
-struct PackageInfo {
-    struct Pair {
-        std::shared_ptr<HalManifest>         manifest;
-        std::shared_ptr<CompatibilityMatrix> matrix;
-    };
-    Pair dev;
-    Pair fwk;
-};
-
-struct UpdatedInfo {
-    struct Pair {
-        std::shared_ptr<const HalManifest>         manifest;
-        std::shared_ptr<const CompatibilityMatrix> matrix;
-    };
-    Pair dev;
-    Pair fwk;
-    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.
+// Simulate applying xmls to VintfObject, then checkCompatibility as usual.
 int32_t VintfObject::checkCompatibility(const std::vector<std::string>& xmls, std::string* error,
                                         CheckFlags::Type flags) {
-    status_t status;
-    ParseStatus parseStatus;
-    PackageInfo pkg; // All information from package.
-    UpdatedInfo updated; // All files and runtime info after the update.
+    VintfObjectAfterUpdate afterUpdate(this);
+    ParseStatus parseStatus = ParseStatus::OK;
 
     // parse all information from package
     for (const auto &xml : xmls) {
-        parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
+        parseStatus = tryParse(xml, gHalManifestConverter, &afterUpdate);
         if (parseStatus == ParseStatus::OK) {
             continue; // work on next one
         }
@@ -508,7 +473,7 @@
             appendLine(error, toString(parseStatus) + " manifest");
             return ALREADY_EXISTS;
         }
-        parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
+        parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &afterUpdate);
         if (parseStatus == ParseStatus::OK) {
             continue; // work on next one
         }
@@ -520,52 +485,31 @@
         return BAD_VALUE;
     }
 
-    // get missing info from device
-    if ((status = getMissing(
-             pkg.fwk.manifest, &updated.fwk.manifest,
-             std::bind(&VintfObject::getFrameworkHalManifest, this, true /* skipCache */))) != OK) {
-        return status;
-    }
-    if ((status = getMissing(
-             pkg.dev.manifest, &updated.dev.manifest,
-             std::bind(&VintfObject::getDeviceHalManifest, this, true /* skipCache */))) != OK) {
-        return status;
-    }
-    if ((status = getMissing(pkg.fwk.matrix, &updated.fwk.matrix,
-                             std::bind(&VintfObject::getFrameworkCompatibilityMatrix, this,
-                                       true /* skipCache */))) != OK) {
-        return status;
-    }
-    if ((status = getMissing(pkg.dev.matrix, &updated.dev.matrix,
-                             std::bind(&VintfObject::getDeviceCompatibilityMatrix, this,
-                                       true /* skipCache */))) != OK) {
-        return status;
-    }
+    return afterUpdate.checkCompatibility(error, flags);
+}
 
-    if (flags.isRuntimeInfoEnabled()) {
-        updated.runtimeInfo = getRuntimeInfo(true /* skipCache */);
-    }
-
-    // null checks for files and runtime info after the update
-    if (updated.fwk.manifest == nullptr) {
+int32_t VintfObject::checkCompatibility(std::string* error, CheckFlags::Type flags) {
+    status_t status = OK;
+    // null checks for files and runtime info
+    if (getFrameworkHalManifest() == nullptr) {
         appendLine(error, "No framework manifest file from device or from update package");
         status = NO_INIT;
     }
-    if (updated.dev.manifest == nullptr) {
+    if (getDeviceHalManifest() == nullptr) {
         appendLine(error, "No device manifest file from device or from update package");
         status = NO_INIT;
     }
-    if (updated.fwk.matrix == nullptr) {
+    if (getFrameworkCompatibilityMatrix() == nullptr) {
         appendLine(error, "No framework matrix file from device or from update package");
         status = NO_INIT;
     }
-    if (updated.dev.matrix == nullptr) {
+    if (getDeviceCompatibilityMatrix() == nullptr) {
         appendLine(error, "No device matrix file from device or from update package");
         status = NO_INIT;
     }
 
     if (flags.isRuntimeInfoEnabled()) {
-        if (updated.runtimeInfo == nullptr) {
+        if (getRuntimeInfo() == nullptr) {
             appendLine(error, "No runtime info from device");
             status = NO_INIT;
         }
@@ -573,14 +517,14 @@
     if (status != OK) return status;
 
     // compatiblity check.
-    if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
+    if (!getDeviceHalManifest()->checkCompatibility(*getFrameworkCompatibilityMatrix(), error)) {
         if (error) {
             error->insert(0,
                           "Device manifest and framework compatibility matrix are incompatible: ");
         }
         return INCOMPATIBLE;
     }
-    if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
+    if (!getFrameworkHalManifest()->checkCompatibility(*getDeviceCompatibilityMatrix(), error)) {
         if (error) {
             error->insert(0,
                           "Framework manifest and device compatibility matrix are incompatible: ");
@@ -589,7 +533,8 @@
     }
 
     if (flags.isRuntimeInfoEnabled()) {
-        if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, flags)) {
+        if (!getRuntimeInfo()->checkCompatibility(*getFrameworkCompatibilityMatrix(), error,
+                                                  flags)) {
             if (error) {
                 error->insert(0,
                               "Runtime info and framework compatibility matrix are incompatible: ");
diff --git a/VintfObjectAfterUpdate.h b/VintfObjectAfterUpdate.h
new file mode 100644
index 0000000..964b2bb
--- /dev/null
+++ b/VintfObjectAfterUpdate.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "SchemaType.h"
+#include "VintfObject.h"
+
+namespace android {
+namespace vintf {
+namespace details {
+/**
+ * Simulate the state of VintfObject after an update.
+ *
+ * - Old metadata is stored in parent VintfObject.
+ * - New (updated) metadata is stored in this VintfObjectAfterUpdate
+ * - Dependencies are from the given VintfObject (dep) before construction.
+ */
+class VintfObjectAfterUpdate : public VintfObject {
+   public:
+    /* Use dependencies from the object dep. */
+    VintfObjectAfterUpdate(VintfObject* dep) : mDependency(dep) {}
+
+    std::shared_ptr<const HalManifest> getDeviceHalManifest(bool skipCache = false) override {
+        if (mDeviceManifest != nullptr) return mDeviceManifest;
+        return VintfObject::getDeviceHalManifest(skipCache);
+    }
+
+    std::shared_ptr<const HalManifest> getFrameworkHalManifest(bool skipCache = false) override {
+        if (mFrameworkManifest != nullptr) return mFrameworkManifest;
+        return VintfObject::getFrameworkHalManifest(skipCache);
+    }
+
+    std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(
+        bool skipCache = false) override {
+        if (mDeviceMatrix != nullptr) return mDeviceMatrix;
+        return VintfObject::getDeviceCompatibilityMatrix(skipCache);
+    }
+
+    std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(
+        bool skipCache = false) override {
+        if (mFrameworkMatrix != nullptr) return mFrameworkMatrix;
+        return VintfObject::getFrameworkCompatibilityMatrix(skipCache);
+    }
+
+    const std::unique_ptr<FileSystem>& getFileSystem() override {
+        return mDependency->getFileSystem();
+    }
+
+    const std::unique_ptr<details::PropertyFetcher>& getPropertyFetcher() override {
+        return mDependency->getPropertyFetcher();
+    }
+
+    const std::unique_ptr<details::ObjectFactory<RuntimeInfo>>& getRuntimeInfoFactory() override {
+        return mDependency->getRuntimeInfoFactory();
+    }
+
+    bool set(const std::shared_ptr<HalManifest>& o) {
+        return set(o, &mDeviceManifest, &mFrameworkManifest);
+    }
+
+    bool set(const std::shared_ptr<CompatibilityMatrix>& o) {
+        return set(o, &mDeviceMatrix, &mFrameworkMatrix);
+    }
+
+   private:
+    VintfObject* mDependency = nullptr;
+    std::shared_ptr<HalManifest> mDeviceManifest;
+    std::shared_ptr<HalManifest> mFrameworkManifest;
+    std::shared_ptr<CompatibilityMatrix> mDeviceMatrix;
+    std::shared_ptr<CompatibilityMatrix> mFrameworkMatrix;
+
+    template <typename T>
+    bool set(const std::shared_ptr<T>& o, std::shared_ptr<T>* dev, std::shared_ptr<T>* fwk) {
+        if (o->type() == SchemaType::DEVICE) {
+            if (*dev != nullptr) return false;
+            *dev = o;
+            return true;
+        } else if (o->type() == SchemaType::FRAMEWORK) {
+            if (*fwk != nullptr) return false;
+            *fwk = o;
+            return true;
+        }
+        return false;
+    }
+};
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/check_vintf.cpp b/check_vintf.cpp
index 48d0bb4..ef54e21 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -224,8 +224,7 @@
     hostPropertyFetcher->setProperties(props);
     VintfObject vintfObject(std::make_unique<HostFileSystem>(rootdir),
                             nullptr /* runtime info factory */, std::move(hostPropertyFetcher));
-    return vintfObject.checkCompatibility({} /* packageInfo */, error,
-                                          CheckFlags::DISABLE_RUNTIME_INFO);
+    return vintfObject.checkCompatibility(error, CheckFlags::DISABLE_RUNTIME_INFO);
 }
 
 }  // namespace details
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index e96a3b5..cebf7f7 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -33,6 +33,7 @@
 template <typename T>
 class ObjectFactory;
 class PropertyFetcher;
+class VintfObjectAfterUpdate;
 
 template <typename T>
 struct LockedSharedPtr {
@@ -89,24 +90,26 @@
     VintfObject(std::unique_ptr<FileSystem>&& = nullptr,
                 std::unique_ptr<details::ObjectFactory<RuntimeInfo>>&& = nullptr,
                 std::unique_ptr<details::PropertyFetcher>&& = nullptr);
+    virtual ~VintfObject() = default;
 
     /*
      * Return the API that access the device-side HAL manifests built from component pieces on the
      * vendor partition.
      */
-    std::shared_ptr<const HalManifest> getDeviceHalManifest(bool skipCache = false);
+    virtual std::shared_ptr<const HalManifest> getDeviceHalManifest(bool skipCache = false);
 
     /*
      * Return the API that access the framework-side HAL manifest built from component pieces on the
      * system partition.
      */
-    std::shared_ptr<const HalManifest> getFrameworkHalManifest(bool skipCache = false);
+    virtual std::shared_ptr<const HalManifest> getFrameworkHalManifest(bool skipCache = false);
 
     /*
      * Return the API that access the device-side compatibility matrix built from component pieces
      * on the vendor partition.
      */
-    std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(bool skipCache = false);
+    virtual std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(
+        bool skipCache = false);
 
     /*
      * Return the API that access the framework-side compatibility matrix built from component
@@ -115,7 +118,7 @@
      * This automatically selects the right compatibility matrix according to the target-level
      * specified by the device.
      */
-    std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(
+    virtual std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(
         bool skipCache = false);
 
     /*
@@ -138,8 +141,6 @@
      * 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.
      *
@@ -147,8 +148,7 @@
      *         > 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,
+    int32_t checkCompatibility(std::string* error = nullptr,
                                CheckFlags::Type flags = CheckFlags::ENABLE_ALL_CHECKS);
 
     /**
@@ -210,9 +210,14 @@
     friend class testing::VintfObjectTestBase;
     friend class testing::VintfObjectRuntimeInfoTest;
     friend class testing::VintfObjectCompatibleTest;
-    const std::unique_ptr<FileSystem>& getFileSystem();
-    const std::unique_ptr<details::PropertyFetcher>& getPropertyFetcher();
-    const std::unique_ptr<details::ObjectFactory<RuntimeInfo>>& getRuntimeInfoFactory();
+
+    // Expose functions to simulate dependency injection.
+    friend class details::VintfObjectAfterUpdate;
+
+   protected:
+    virtual const std::unique_ptr<FileSystem>& getFileSystem();
+    virtual const std::unique_ptr<details::PropertyFetcher>& getPropertyFetcher();
+    virtual const std::unique_ptr<details::ObjectFactory<RuntimeInfo>>& getRuntimeInfoFactory();
 
    public:
     /*
@@ -322,6 +327,10 @@
     status_t fetchOneHalManifest(const std::string& path, HalManifest* out,
                                  std::string* error = nullptr);
     status_t fetchFrameworkHalManifest(HalManifest* out, std::string* error = nullptr);
+    // Helper to CheckCompatibility with dependency injection.
+    int32_t checkCompatibility(const std::vector<std::string>& packageInfo,
+                               std::string* error = nullptr,
+                               CheckFlags::Type flags = CheckFlags::ENABLE_ALL_CHECKS);
 
     static bool IsHalDeprecated(const MatrixHal& oldMatrixHal,
                                 const CompatibilityMatrix& targetMatrix,
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 6563cb0..349426f 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -281,6 +281,52 @@
     "    </hal>\n"
     "</compatibility-matrix>\n"};
 
+//
+// Set of metadata at different FCM version that has requirements
+//
+
+const std::vector<std::string> systemMatrixRequire = {
+    // 1.xml
+    "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
+    "    <hal format=\"hidl\" optional=\"false\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <version>1.0</version>\n"
+    "        <interface>\n"
+    "            <name>IFoo</name>\n"
+    "            <instance>default</instance>\n"
+    "        </interface>\n"
+    "    </hal>\n"
+    "</compatibility-matrix>\n",
+    // 2.xml
+    "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n"
+    "    <hal format=\"hidl\" optional=\"false\">\n"
+    "        <name>android.hardware.bar</name>\n"
+    "        <version>1.0</version>\n"
+    "        <interface>\n"
+    "            <name>IBar</name>\n"
+    "            <instance>default</instance>\n"
+    "        </interface>\n"
+    "    </hal>\n"
+    "</compatibility-matrix>\n"};
+
+const std::string vendorManifestRequire1 =
+    "<manifest version=\"1.0\" type=\"device\" target-level=\"1\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <fqname>@1.0::IFoo/default</fqname>\n"
+    "    </hal>\n"
+    "</manifest>\n";
+
+const std::string vendorManifestRequire2 =
+    "<manifest version=\"1.0\" type=\"device\" target-level=\"2\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.bar</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <fqname>@1.0::IBar/default</fqname>\n"
+    "    </hal>\n"
+    "</manifest>\n";
+
 class VintfObjectTestBase : public ::testing::Test {
    protected:
     MockFileSystem& fetcher() {
@@ -979,6 +1025,9 @@
         return "compatibility_matrix." + std::to_string(static_cast<Level>(i)) + ".xml";
     }
     void SetUpMockSystemMatrices(const std::vector<std::string>& xmls) {
+        EXPECT_CALL(fetcher(), listFiles(_, _, _))
+            .Times(AnyNumber())
+            .WillRepeatedly(Return(::android::OK));
         EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
             .WillRepeatedly(Invoke([=](const auto&, auto* out, auto*) {
                 size_t i = 1;
@@ -989,10 +1038,6 @@
                 }
                 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);
@@ -1251,6 +1296,40 @@
     EXPECT_NOT_IN(FAKE_KERNEL("4.0.0", "D3"), xml) << "\nOld requirements must not change";
 }
 
+class VintfObjectPartialUpdateTest : public MultiMatrixTest {
+   protected:
+    void SetUp() override {
+        MultiMatrixTest::SetUp();
+        setFakeProperties();
+    }
+};
+
+TEST_F(VintfObjectPartialUpdateTest, DeviceCompatibility) {
+    setupMockFetcher(vendorManifestRequire1, "", systemManifestXml1, vendorMatrixXml1,
+                     productModel);
+    SetUpMockSystemMatrices(systemMatrixRequire);
+
+    expectSystemManifest();
+    expectVendorMatrix();
+    expectVendorManifest();
+
+    std::string error;
+    EXPECT_TRUE(checkCompatibility({}, &error)) << error;
+}
+
+TEST_F(VintfObjectPartialUpdateTest, VendorOnlyCompatible) {
+    setupMockFetcher("", "", systemManifestXml1, vendorMatrixXml1, productModel);
+    SetUpMockSystemMatrices(systemMatrixRequire);
+
+    expectSystemManifest();
+    expectVendorMatrix();
+    // Should not load vendor manifest from device
+    expectVendorManifest(0);
+
+    std::string error;
+    EXPECT_TRUE(checkCompatibility({vendorManifestRequire2}, &error)) << error;
+}
+
 }  // namespace testing
 }  // namespace vintf
 }  // namespace android