HalManifest rejects names invalid to FqInstance

With the legacy package name + version + interface name
+ instance name format, if the names can't fit into
an FqInstance (e.g. interface name does not start with I),
forEachInstance silently drops the instance.

Detect this early so that such HAL manifests are considered invalid.
If a device relies on this behavior and contains invalid characters in
the names, it will encounter a build / runtime error.

Test: libvintf_test
Bug: 175821740

Change-Id: I2a7e3e9a5d2784a245560bcbf2f8abb512fdb0e1
diff --git a/ManifestHal.cpp b/ManifestHal.cpp
index cb60331..6bc86d3 100644
--- a/ManifestHal.cpp
+++ b/ManifestHal.cpp
@@ -15,15 +15,19 @@
  */
 
 #include "ManifestHal.h"
+
 #include <unordered_set>
 
 #include "MapValueIterator.h"
 #include "constants-private.h"
 #include "parse_string.h"
+#include "utils.h"
 
 namespace android {
 namespace vintf {
 
+using details::canConvertToFqInstance;
+
 bool ManifestHal::isValid(std::string* error) const {
     if (error) {
         error->clear();
@@ -38,13 +42,29 @@
         }
         success = false;
         if (error) {
-            *error += "Duplicated major version: " + to_string(v) + " vs. " + to_string(it->second);
+            *error += "Duplicated major version: " + to_string(v) + " vs. " +
+                      to_string(it->second) + ".\n";
         }
     }
+
+    // Check legacy instances (i.e. <version> + <interface> + <instance>) can be
+    // converted into FqInstance because forEachInstance relies on FqInstance.
+    for (const auto& v : versions) {
+        for (const auto& intf : iterateValues(interfaces)) {
+            intf.forEachInstance(
+                [&](const auto& interface, const auto& instance, bool /* isRegex */) {
+                    if (!canConvertToFqInstance(getName(), v, interface, instance, format, error)) {
+                        success = false;
+                    }
+                    return true;  // continue
+                });
+        }
+    }
+
     std::string transportArchError;
     if (!transportArch.isValid(&transportArchError)) {
         success = false;
-        if (error) *error += transportArchError;
+        if (error) *error += transportArchError + "\n";
     }
     return success;
 }