Add bitness info to <transport>.

Only valid for transport == passthrough or toggled.
Example:
<transport>hwbinder</transport>
<transport arch="64">passthrough</transport>
<transport arch="32+64">passthrough</transport>
<transport arch="32">passthrough</transport>

Allow transport tag to be missing (for native HALs like GLES).

Bug: 35966597
Test: libvintf_test
Change-Id: I80928a5d46f3097ed18f2894e46762127b29bd4c
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 4004792..d3838f8 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -316,6 +316,10 @@
         return true;
     }
 
+    template <typename T>
+    inline bool parseText(NodeType *node, T *s) const {
+        return ::android::vintf::parse(getText(node), s);
+    }
 protected:
     mutable std::string mLastError;
 };
@@ -347,10 +351,33 @@
 
 const XmlTextConverter<VersionRange> versionRangeConverter{"version"};
 
-const XmlTextConverter<Transport> transportConverter{"transport"};
-
 const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
 
+struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
+    std::string elementName() const override { return "transport"; }
+    void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override {
+        if (object.arch != Arch::ARCH_EMPTY) {
+            appendAttr(root, "arch", object.arch);
+        }
+        appendText(root, ::android::vintf::to_string(object.transport), d);
+    }
+    bool buildObject(TransportArch *object, NodeType *root) const override {
+        if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch) ||
+            !parseText(root, &object->transport)) {
+            return false;
+        }
+        if (!object->isValid()) {
+            this->mLastError = "transport == " + ::android::vintf::to_string(object->transport) +
+                    " and arch == " + ::android::vintf::to_string(object->arch) +
+                    " is not a valid combination.";
+            return false;
+        }
+        return true;
+    }
+};
+
+const TransportArchConverter transportArchConverter{};
+
 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
     std::string elementName() const override { return "value"; }
     void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override {
@@ -474,7 +501,9 @@
     void mutateNode(const ManifestHal &hal, NodeType *root, DocType *d) const override {
         appendAttr(root, "format", hal.format);
         appendTextElement(root, "name", hal.name, d);
-        appendChild(root, transportConverter(hal.transport, d));
+        if (!hal.transportArch.empty()) {
+            appendChild(root, transportArchConverter(hal.transportArch, d));
+        }
         if (hal.impl.implLevel != ImplLevel::EMPTY) {
             appendChild(root, halImplementationConverter(hal.impl, d));
         }
@@ -485,7 +514,7 @@
         std::vector<ManifestHalInterface> interfaces;
         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
             !parseTextElement(root, "name", &object->name) ||
-            !parseChild(root, transportConverter, &object->transport) ||
+            !parseChild(root, transportArchConverter, &object->transportArch) ||
             !parseOptionalChild(root, halImplementationConverter, {}, &object->impl) ||
             !parseChildren(root, versionConverter, &object->versions) ||
             !parseChildren(root, manfiestHalInterfaceConverter, &interfaces)) {
@@ -500,7 +529,11 @@
                 return false;
             }
         }
-        return object->isValid();
+        if (!object->isValid()) {
+            this->mLastError = "'" + object->name + "' is not a valid Manifest HAL.";
+            return false;
+        }
+        return true;
     }
 };