Implement compatibility check

So that VendorManifest and KernelInfo can check against
a certain CompatibilityMatrix.

* VendorManifest::checkIncompatibility: return component
  names that doesn't work with the given compatibility
  matrix.
* KernelInfo::checkCompatibility: check security_policyvers()
  and config items from /proc/config.gz.

Bug: 34633352
Test: libvintf_test

Change-Id: I88de1a89c23581330d50b4285ac4dfc2b6714e29
diff --git a/test/main.cpp b/test/main.cpp
index def1ac8..3aa2e14 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -19,6 +19,7 @@
 #include <vintf/parse_string.h>
 #include <vintf/parse_xml.h>
 #include <vintf/CompatibilityMatrix.h>
+#include <vintf/KernelInfo.h>
 #include <vintf/VendorManifest.h>
 
 #include <android-base/logging.h>
@@ -67,6 +68,24 @@
 
         return vm;
     }
+    KernelInfo testKernelInfo() {
+        KernelInfo info;
+        info.mOsName = "Linux";
+        info.mNodeName = "localhost";
+        info.mOsRelease = "3.18.31-g936f9a479d0f";
+        info.mKernelVersion = {3, 18, 31};
+        info.mOsVersion = "#4 SMP PREEMPT Wed Feb 1 18:10:52 PST 2017";
+        info.mHardwareId = "aarch64";
+        info.mKernelSepolicyVersion = 30;
+        info.kernelConfigs = {
+            {"CONFIG_64BIT", "y"},
+            {"CONFIG_ANDROID_BINDER_DEVICES", "\"binder,hwbinder\""},
+            {"CONFIG_ARCH_MMAP_RND_BITS", "24"},
+            {"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", "\"\""},
+            {"CONFIG_ILLEGAL_POINTER_VALUE", "0xdead000000000000"}
+        };
+        return info;
+    }
 };
 
 
@@ -302,6 +321,91 @@
     }
 }
 
+TEST_F(LibVintfTest, KernelInfo) {
+    KernelInfo ki = testKernelInfo();
+    using KernelConfigs = std::vector<KernelConfig>;
+    const KernelConfigs configs {
+            KernelConfig{"CONFIG_64BIT", Tristate::YES},
+            KernelConfig{"CONFIG_ANDROID_BINDER_DEVICES", "binder,hwbinder"},
+            KernelConfig{"CONFIG_ARCH_MMAP_RND_BITS", 24},
+            KernelConfig{"CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES", ""},
+            KernelConfig{"CONFIG_ILLEGAL_POINTER_VALUE", 0xdead000000000000},
+            KernelConfig{"CONFIG_NOTEXIST", Tristate::NO},
+    };
+
+    auto testMatrix = [&] (MatrixKernel &&kernel) {
+        CompatibilityMatrix cm;
+        add(cm, std::move(kernel));
+        set(cm, {30, {1, 3}});
+        return cm;
+    };
+
+    std::string error;
+
+    {
+        MatrixKernel kernel(KernelVersion{4, 4, 1}, KernelConfigs(configs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_FALSE(ki.checkCompatibility(cm)) << "Kernel version shouldn't match";
+    }
+
+    {
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, KernelConfigs(configs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_TRUE(ki.checkCompatibility(cm, &error)) << error;
+    }
+
+    {
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, KernelConfigs(configs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        set(cm, Sepolicy{22, {1, 3}});
+        EXPECT_FALSE(ki.checkCompatibility(cm, &error))
+            << "kernel-sepolicy-version shouldn't match";
+        set(cm, Sepolicy{40, {1, 3}});
+        EXPECT_FALSE(ki.checkCompatibility(cm, &error))
+            << "kernel-sepolicy-version shouldn't match";
+    }
+
+    {
+        KernelConfigs newConfigs(configs);
+        newConfigs[0] = KernelConfig{"CONFIG_64BIT", Tristate::NO};
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, std::move(newConfigs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_FALSE(ki.checkCompatibility(cm)) << "Value shouldn't match for tristate";
+    }
+
+    {
+        KernelConfigs newConfigs(configs);
+        newConfigs[0] = KernelConfig{"CONFIG_64BIT", 20};
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, std::move(newConfigs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_FALSE(ki.checkCompatibility(cm)) << "Type shouldn't match";
+    }
+
+    {
+        KernelConfigs newConfigs(configs);
+        newConfigs[1] = KernelConfig{"CONFIG_ANDROID_BINDER_DEVICES", "binder"};
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, std::move(newConfigs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_FALSE(ki.checkCompatibility(cm)) << "Value shouldn't match for string";
+    }
+
+    {
+        KernelConfigs newConfigs(configs);
+        newConfigs[1] = KernelConfig{"CONFIG_ANDROID_BINDER_DEVICES", Tristate::YES};
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, std::move(newConfigs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_FALSE(ki.checkCompatibility(cm)) << "Type shouldn't match";
+    }
+
+    {
+        KernelConfigs newConfigs(configs);
+        newConfigs[2] = KernelConfig{"CONFIG_ARCH_MMAP_RND_BITS", 30};
+        MatrixKernel kernel(KernelVersion{3, 18, 22}, std::move(newConfigs));
+        CompatibilityMatrix cm = testMatrix(std::move(kernel));
+        EXPECT_FALSE(ki.checkCompatibility(cm)) << "Value shouldn't match for integer";
+    }
+}
+
 } // namespace vintf
 } // namespace android