HalManifest::checkIncompatibleHals uses instances API.

Now that <hal> is not the smallest unit of a manifest,
the compatibility check logic is updated accordingly.

Test: libvintf_test
Test: vintf_object_test
Bug: 73556059

Change-Id: Ief73afc61bace0dcc3d02410c16c7e261fa63315
Merged-In: Ief73afc61bace0dcc3d02410c16c7e261fa63315
diff --git a/parse_string.cpp b/parse_string.cpp
index 2aa3c1b..51ca009 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -395,16 +395,22 @@
               << (req.optional ? kOptional : kRequired);
 }
 
-static std::string expandInstances(const MatrixHal& req, const VersionRange& vr) {
+static std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) {
     std::string s;
-    bool first = true;
+    size_t count = 0;
     for (const auto& interface : iterateValues(req.interfaces)) {
         for (const auto& instance : interface.instances) {
-            if (!first) s += " AND ";
+            if (count > 0) s += " AND ";
             s += toFQNameString(vr, interface.name, instance);
-            first = false;
+            count++;
         }
     }
+    if (count == 0) {
+        s += "@" + to_string(vr);
+    }
+    if (count >= 2 && brace) {
+        s = "(" + s + ")";
+    }
     return s;
 }
 
@@ -414,14 +420,14 @@
     }
     if (req.versionRanges.size() == 1 && req.interfaces.size() == 1 &&
         req.interfaces.begin()->second.instances.size() == 1) {
-        return {expandInstances(req, req.versionRanges.front())};
+        return {expandInstances(req, req.versionRanges.front(), false /* brace */)};
     }
     std::vector<std::string> ss;
     for (const auto& vr : req.versionRanges) {
         if (!ss.empty()) {
             ss.back() += " OR";
         }
-        ss.push_back("(" + expandInstances(req, vr) + ")");
+        ss.push_back(expandInstances(req, vr, true /* brace */));
     }
     return ss;
 }