VintfObject::checkCompatibility loads XMLs from the device correctly.

Previously:
- When getFrameworkCompatibilityMatrix() is called, the Target FCM version
is always loaded from the device, but not from the update package.
This can potentially break a vendor-only OTA that updates the Target FCM
version, because the FCM from device isn't loaded with the correct Target FCM
version.

In this CL, I refactored checkCompatibility logic so that the
VintfObjectAfterUpdate object applies the updated VINTF metadata as an
overlay on top of the original VintfObject.

Test: vintf_object_test
Test: manual OTA
Bug: 118635062
Change-Id: Ib04ba09d4a07c8e5d1e4ac64194e956b37e1f76f
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: ");