Add <vndk> entry to framework manifest and device comp-mat.

Bug: 36400653

Test: libvintf_test
Change-Id: Ie727d4806ad74a72511354a901fca09ea9ae67c4
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 007471a..262b4da 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -25,6 +25,7 @@
 #include "MapValueIterator.h"
 #include "Sepolicy.h"
 #include "SchemaType.h"
+#include "Vndk.h"
 
 namespace android {
 namespace vintf {
@@ -64,6 +65,11 @@
         std::vector<MatrixKernel> mKernels;
         Sepolicy mSepolicy;
     } framework;
+
+    // entries only for device compatibility matrix.
+    struct {
+        Vndk mVndk;
+    } device;
 };
 
 } // namespace vintf
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index 7618a1e..493936e 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -27,6 +27,7 @@
 #include "MapValueIterator.h"
 #include "SchemaType.h"
 #include "Version.h"
+#include "Vndk.h"
 
 namespace android {
 namespace vintf {
@@ -116,6 +117,11 @@
     struct {
         Version mSepolicyVersion;
     } device;
+
+    // entries for framework hal manifest only
+    struct {
+        std::vector<Vndk> mVndks;
+    } framework;
 };
 
 
diff --git a/include/vintf/Vndk.h b/include/vintf/Vndk.h
new file mode 100644
index 0000000..3288b40
--- /dev/null
+++ b/include/vintf/Vndk.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_VINTF_VNDK_H
+#define ANDROID_VINTF_VNDK_H
+
+#include <set>
+#include <string>
+
+namespace android {
+namespace vintf {
+
+struct VndkVersionRange {
+
+    VndkVersionRange() : VndkVersionRange(0u, 0u, 0u) {}
+    VndkVersionRange(size_t s, size_t v, size_t p)
+        : VndkVersionRange(s, v, p, p) {}
+    VndkVersionRange(size_t s, size_t v, size_t pi, size_t pa)
+        : sdk(s), vndk(v), patchMin(pi), patchMax(pa) {}
+
+    inline bool isSingleVersion() const { return patchMin == patchMax; };
+
+    size_t sdk;
+    size_t vndk;
+    size_t patchMin;
+    size_t patchMax;
+};
+
+struct Vndk {
+
+private:
+    friend struct VndkConverter;
+    friend struct HalManifestConverter;
+    friend struct LibVintfTest;
+    VndkVersionRange mVersionRange;
+    std::set<std::string> mLibraries;
+};
+
+} // namespace vintf
+} // namespace android
+
+#endif // ANDROID_VINTF_VNDK_H
diff --git a/include/vintf/parse_string.h b/include/vintf/parse_string.h
index 15775e4..d816908 100644
--- a/include/vintf/parse_string.h
+++ b/include/vintf/parse_string.h
@@ -37,6 +37,7 @@
 std::ostream &operator<<(std::ostream &os, const ManifestHal &hal);
 std::ostream &operator<<(std::ostream &os, const Version &ver);
 std::ostream &operator<<(std::ostream &os, const VersionRange &vr);
+std::ostream &operator<<(std::ostream &os, const VndkVersionRange &vr);
 std::ostream &operator<<(std::ostream &os, const KernelVersion &ver);
 std::ostream &operator<<(std::ostream &os, const TransportArch &ta);
 std::ostream &operator<<(std::ostream &os, const ManifestHal &hal);
@@ -61,6 +62,7 @@
 bool parse(const std::string &s, KernelSepolicyVersion *ksv);
 bool parse(const std::string &s, Version *ver);
 bool parse(const std::string &s, VersionRange *vr);
+bool parse(const std::string &s, VndkVersionRange *vr);
 bool parse(const std::string &s, KernelVersion *ver);
 // if return true, ta->isValid() must be true.
 bool parse(const std::string &s, TransportArch *ta);
diff --git a/parse_string.cpp b/parse_string.cpp
index 20daad9..4c1e9a1 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -215,6 +215,36 @@
     return os << vr.minVer() << "-" << vr.maxMinor;
 }
 
+bool parse(const std::string &s, VndkVersionRange *vr) {
+    std::vector<std::string> v = SplitString(s, '-');
+    if (v.size() != 1 && v.size() != 2) {
+        return false;
+    }
+    std::vector<std::string> minVector = SplitString(v[0], '.');
+    if (minVector.size() != 3) {
+        return false;
+    }
+    if (!ParseUint(minVector[0], &vr->sdk) ||
+        !ParseUint(minVector[1], &vr->vndk) ||
+        !ParseUint(minVector[2], &vr->patchMin)) {
+        return false;
+    }
+    if (v.size() == 1) {
+        vr->patchMax = vr->patchMin;
+        return true;
+    } else {
+        return ParseUint(v[1], &vr->patchMax);
+    }
+}
+
+std::ostream &operator<<(std::ostream &os, const VndkVersionRange &vr) {
+    os << vr.sdk << "." << vr.vndk << "." << vr.patchMin;
+    if (!vr.isSingleVersion()) {
+        os << "-" << vr.patchMax;
+    }
+    return os;
+}
+
 bool parse(const std::string &s, KernelVersion *kernelVersion) {
     std::vector<std::string> v = SplitString(s, '.');
     if (v.size() != 3) {
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 1d2acbd..1435c4e 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -316,6 +316,23 @@
         return true;
     }
 
+    template <typename T>
+    inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::set<T> *s) const {
+        std::vector<T> vec;
+        if (!parseChildren(root, conv, &vec)) {
+            return false;
+        }
+        s->clear();
+        s->insert(vec.begin(), vec.end());
+        if (s->size() != vec.size()) {
+            mLastError = "Duplicated elements <" + conv.elementName() + "> in element <"
+                    + this->elementName() + ">";
+            s->clear();
+            return false;
+        }
+        return true;
+    }
+
     inline bool parseText(NodeType *node, std::string *s) const {
         *s = getText(node);
         return true;
@@ -544,6 +561,26 @@
 };
 const SepolicyConverter sepolicyConverter{};
 
+const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
+const XmlTextConverter<std::string> vndkLibraryConverter{"library"};
+
+struct VndkConverter : public XmlNodeConverter<Vndk> {
+    std::string elementName() const override { return "vndk"; }
+    void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override {
+        appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d));
+        appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
+    }
+    bool buildObject(Vndk *object, NodeType *root) const override {
+        if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange) ||
+            !parseChildren(root, vndkLibraryConverter, &object->mLibraries)) {
+            return false;
+        }
+        return true;
+    }
+};
+
+const VndkConverter vndkConverter{};
+
 struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
     std::string elementName() const override { return "sepolicy"; }
     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
@@ -563,6 +600,8 @@
         appendChildren(root, manifestHalConverter, m.getHals(), d);
         if (m.mType == SchemaType::DEVICE) {
             appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
+        } else if (m.mType == SchemaType::FRAMEWORK) {
+            appendChildren(root, vndkConverter, m.framework.mVndks, d);
         }
     }
     bool buildObject(HalManifest *object, NodeType *root) const override {
@@ -584,6 +623,17 @@
                     &object->device.mSepolicyVersion)) {
                 return false;
             }
+        } else if (object->mType == SchemaType::FRAMEWORK) {
+            if (!parseChildren(root, vndkConverter, &object->framework.mVndks)) {
+                return false;
+            }
+            for (const auto &vndk : object->framework.mVndks) {
+                if (!vndk.mVersionRange.isSingleVersion()) {
+                    this->mLastError = "vndk.version " + to_string(vndk.mVersionRange)
+                            + " cannot be a range for manifests";
+                    return false;
+                }
+            }
         }
         for (auto &&hal : hals) {
             if (!object->add(std::move(hal))) {
@@ -622,6 +672,10 @@
                 !parseChild(root, sepolicyConverter, &object->framework.mSepolicy)) {
                 return false;
             }
+        } else if (object->mType == SchemaType::DEVICE) {
+            if (!parseChild(root, vndkConverter, &object->device.mVndk)) {
+                return false;
+            }
         }
 
         if (version != CompatibilityMatrix::kVersion) {
diff --git a/test/main.cpp b/test/main.cpp
index f73c2db..0a636c8 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -66,7 +66,7 @@
     bool isValid(const ManifestHal &mh) {
         return mh.isValid();
     }
-    HalManifest testHalManifest() {
+    HalManifest testDeviceManifest() {
         HalManifest vm;
         vm.mType = SchemaType::DEVICE;
         vm.device.mSepolicyVersion = {25, 0};
@@ -92,6 +92,28 @@
 
         return vm;
     }
+    HalManifest testFrameworkManfiest() {
+        HalManifest vm;
+        vm.mType = SchemaType::FRAMEWORK;
+        vm.add(ManifestHal{
+            .format = HalFormat::HIDL,
+            .name = "android.hidl.manager",
+            .versions = {Version(1, 0)},
+            .transportArch = {Transport::HWBINDER, Arch::ARCH_EMPTY},
+            .interfaces = {
+                {"IServiceManager", {"IServiceManager", {"default"}}},
+            }
+        });
+        Vndk vndk2505;
+        vndk2505.mVersionRange = {25, 0, 5};
+        vndk2505.mLibraries = { "libjpeg.so", "libbase.so" };
+        Vndk vndk2513;
+        vndk2513.mVersionRange = {25, 1, 3};
+        vndk2513.mLibraries = { "libjpeg.so", "libbase.so", "libtinyxml2.so" };
+        vm.framework.mVndks = { std::move(vndk2505), std::move(vndk2513) };
+
+        return vm;
+    }
     RuntimeInfo testRuntimeInfo() {
         RuntimeInfo info;
         info.mOsName = "Linux";
@@ -114,7 +136,7 @@
 
 
 TEST_F(LibVintfTest, Stringify) {
-    HalManifest vm = testHalManifest();
+    HalManifest vm = testDeviceManifest();
     EXPECT_EQ(dump(vm), "hidl/android.hardware.camera/hwbinder/2.0:"
                         "hidl/android.hardware.nfc/passthrough32+64/1.0");
 
@@ -129,7 +151,7 @@
 }
 
 TEST_F(LibVintfTest, HalManifestConverter) {
-    HalManifest vm = testHalManifest();
+    HalManifest vm = testDeviceManifest();
     std::string xml = gHalManifestConverter(vm);
     EXPECT_EQ(xml,
         "<manifest version=\"1.0\" type=\"device\">\n"
@@ -162,6 +184,36 @@
         "</manifest>\n");
 }
 
+TEST_F(LibVintfTest, HalManifestConverterFramework) {
+    HalManifest vm = testFrameworkManfiest();
+    std::string xml = gHalManifestConverter(vm);
+    EXPECT_EQ(xml,
+        "<manifest version=\"1.0\" type=\"framework\">\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>android.hidl.manager</name>\n"
+        "        <transport>hwbinder</transport>\n"
+        "        <version>1.0</version>\n"
+        "        <interface>\n"
+        "            <name>IServiceManager</name>\n"
+        "            <instance>default</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <vndk>\n"
+        "        <version>25.0.5</version>\n"
+        "        <library>libbase.so</library>\n"
+        "        <library>libjpeg.so</library>\n"
+        "    </vndk>\n"
+        "    <vndk>\n"
+        "        <version>25.1.3</version>\n"
+        "        <library>libbase.so</library>\n"
+        "        <library>libjpeg.so</library>\n"
+        "        <library>libtinyxml2.so</library>\n"
+        "    </vndk>\n"
+        "</manifest>\n");
+    HalManifest vm2;
+    EXPECT_TRUE(gHalManifestConverter(&vm2, xml));
+}
+
 TEST_F(LibVintfTest, HalManifestOptional) {
     HalManifest vm;
     EXPECT_TRUE(gHalManifestConverter(&vm,
@@ -184,7 +236,7 @@
 }
 
 TEST_F(LibVintfTest, HalManifestInstances) {
-    HalManifest vm = testHalManifest();
+    HalManifest vm = testDeviceManifest();
     EXPECT_EQ(vm.getInstances("android.hardware.camera", "ICamera"),
             std::set<std::string>({"default", "legacy/0"}));
     EXPECT_EQ(vm.getInstances("android.hardware.camera", "IBetterCamera"),
@@ -387,13 +439,13 @@
 }
 
 TEST_F(LibVintfTest, HalManifestGetHalNames) {
-    HalManifest vm = testHalManifest();
+    HalManifest vm = testDeviceManifest();
     EXPECT_EQ(vm.getHalNames(), std::set<std::string>(
                   {"android.hardware.camera", "android.hardware.nfc"}));
 }
 
 TEST_F(LibVintfTest, HalManifestGetInterfaceNames) {
-    HalManifest vm = testHalManifest();
+    HalManifest vm = testDeviceManifest();
     EXPECT_EQ(vm.getInterfaceNames("android.hardware.camera"),
               std::set<std::string>({"ICamera", "IBetterCamera"}));
     EXPECT_EQ(vm.getInterfaceNames("android.hardware.nfc"),
@@ -401,7 +453,7 @@
 }
 
 TEST_F(LibVintfTest, HalManifestGetHal) {
-    HalManifest vm = testHalManifest();
+    HalManifest vm = testDeviceManifest();
     EXPECT_NE(getHal(vm, "android.hardware.camera"), nullptr);
     EXPECT_EQ(getHal(vm, "non-existent"), nullptr);