Add VintfObject::CheckDeprecation().

This API reads all framework matrices at different FCM version,
and consider a service instance as "deprecated" if all of the
following is true:

1. instance is in an "old matrix"
2. instance is not in the "new matrix"
3. instance is registered through service manager /
   in device manifest
4. No instance with the same package/major version/interface/
   instance name but a higher minor version is:
   4.1 in the "new matrix"; and
   4.2 registered through service manager / in device manifest.

Test: vintf_object_test
Test: vts_treble_vintf_test
Bug: 69425186
Change-Id: I316ba9510688fc927b8f0675ed8db5e29d5036dd
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 90b446d..7c55181 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -17,6 +17,7 @@
 #include "VintfObject.h"
 
 #include "CompatibilityMatrix.h"
+#include "parse_string.h"
 #include "parse_xml.h"
 #include "utils.h"
 
@@ -567,6 +568,144 @@
                                        disabledChecks);
 }
 
+bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal,
+                                  const CompatibilityMatrix& targetMatrix,
+                                  const IsInstanceInUse& isInstanceInUse, std::string* error) {
+    for (const VersionRange& range : oldMatrixHal.versionRanges) {
+        for (const HalInterface& interface : iterateValues(oldMatrixHal.interfaces)) {
+            for (const std::string& instance : interface.instances) {
+                if (isInstanceDeprecated(oldMatrixHal.name, range.minVer(), interface.name,
+                                         instance, targetMatrix, isInstanceInUse, error)) {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+// If isInstanceInUse(package@x.y::interface/instance), return true iff:
+// 1. package@x.?::interface/instance is not in targetMatrix; OR
+// 2. package@x.z::interface/instance is in targetMatrix but
+// !isInstanceInUse(package@x.z::interface/instance)
+bool VintfObject::isInstanceDeprecated(const std::string& package, Version version,
+                                       const std::string& interface, const std::string& instance,
+                                       const CompatibilityMatrix& targetMatrix,
+                                       const IsInstanceInUse& isInstanceInUse,
+                                       std::string* error) {
+    bool oldVersionIsServed;
+    Version servedVersion;
+    std::tie(oldVersionIsServed, servedVersion) =
+        isInstanceInUse(package, version, interface, instance);
+    if (oldVersionIsServed) {
+        // Find any package@x.? in target matrix, and check if instance is in target matrix.
+        const MatrixHal* targetMatrixHal;
+        const VersionRange* targetMatrixRange;
+        std::tie(targetMatrixHal, targetMatrixRange) =
+            targetMatrix.getHalWithMajorVersion(package, version.majorVer);
+        if (targetMatrixHal == nullptr || targetMatrixRange == nullptr) {
+            if (error) {
+                *error = package + "@" + to_string(servedVersion) +
+                         "is deprecated in compatibility matrix at FCM Version " +
+                         to_string(targetMatrix.level()) + "; it should not be served.";
+            }
+            return true;
+        }
+
+        const auto& targetMatrixInstances = targetMatrixHal->getInstances(interface);
+        if (targetMatrixInstances.find(instance) == targetMatrixInstances.end()) {
+            if (error) {
+                *error += package + "@" + to_string(servedVersion) + "::" + interface + "/" +
+                          instance + " is deprecated at FCM version " +
+                          to_string(targetMatrix.level()) + "; it should be not be served.\n";
+            }
+            return true;
+        }
+
+        // Assuming that targetMatrix requires @x.u-v, require that at least @x.u is served.
+        bool targetVersionServed;
+        std::tie(targetVersionServed, std::ignore) =
+            isInstanceInUse(package, targetMatrixRange->minVer(), interface, instance);
+
+        if (!targetVersionServed) {
+            if (error) {
+                *error += package + "@" + to_string(servedVersion) + " is deprecated; " +
+                          "require at least " + to_string(targetMatrixRange->minVer()) + "\n";
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+int32_t VintfObject::CheckDeprecation(const IsInstanceInUse& isInstanceInUse,
+                                      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();
+    if (deviceManifest == nullptr) {
+        if (error) *error = "No device manifest.";
+        return NAME_NOT_FOUND;
+    }
+    Level deviceLevel = deviceManifest->level();
+    if (deviceLevel == Level::UNSPECIFIED) {
+        if (error) *error = "Device manifest does not specify Shipping FCM Version.";
+        return BAD_VALUE;
+    }
+
+    const CompatibilityMatrix* targetMatrix = nullptr;
+    for (const auto& namedMatrix : matrixFragments) {
+        if (namedMatrix.object.level() == deviceLevel) {
+            targetMatrix = &namedMatrix.object;
+        }
+    }
+    if (targetMatrix == nullptr) {
+        if (error)
+            *error = "Cannot find framework matrix at FCM version " + to_string(deviceLevel) + ".";
+        return NAME_NOT_FOUND;
+    }
+
+    bool hasDeprecatedHals = false;
+    for (const auto& namedMatrix : matrixFragments) {
+        if (namedMatrix.object.level() == Level::UNSPECIFIED) continue;
+        if (namedMatrix.object.level() >= deviceLevel) continue;
+
+        const auto& oldMatrix = namedMatrix.object;
+        for (const MatrixHal& hal : oldMatrix.getHals()) {
+            hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, isInstanceInUse, error);
+        }
+    }
+
+    return hasDeprecatedHals ? DEPRECATED : NO_DEPRECATED_HALS;
+}
+
+int32_t VintfObject::CheckDeprecation(std::string* error) {
+    auto deviceManifest = GetDeviceHalManifest();
+    IsInstanceInUse inManifest = [&deviceManifest](const std::string& package, Version version,
+                                                    const std::string& interface,
+                                                    const std::string& instance) {
+        const ManifestHal* hal = deviceManifest->getHal(package, version);
+        if (hal == nullptr) {
+            return std::make_pair(false, Version{});
+        }
+        const auto& instances = hal->getInstances(interface);
+        if (instances.find(instance) == instances.end()) {
+            return std::make_pair(false, Version{});
+        }
+
+        for (Version v : hal->versions) {
+            if (v.minorAtLeast(version)) {
+                return std::make_pair(true, v);
+            }
+        }
+        return std::make_pair(false, Version{});
+    };
+    return CheckDeprecation(inManifest, error);
+}
 
 } // namespace vintf
 } // namespace android