Merge changes from topic "kernel_config_arch"

* changes:
  Add tests for kernel config fragments in fwk comp mat.
  Do not allow first <kernel> version to have non-empty <condition>.
  Remove unused CompatibilityMatrix::findKernel
  Improve error messages in parse_xml.cpp
  Match /proc/config.gz with fwk comp mat <kernel> fragments
  Add <conditions> to <kernel> in framework compat mat
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 509ca1d..f320861 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -36,19 +36,6 @@
     return true;
 }
 
-const MatrixKernel *CompatibilityMatrix::findKernel(const KernelVersion &v) const {
-    if (mType != SchemaType::FRAMEWORK) {
-        return nullptr;
-    }
-    for (const MatrixKernel &matrixKernel : framework.mKernels) {
-        if (matrixKernel.minLts().version == v.version &&
-            matrixKernel.minLts().majorRev == v.majorRev) {
-            return matrixKernel.minLts().minorRev <= v.minorRev ? &matrixKernel : nullptr;
-        }
-    }
-    return nullptr;
-}
-
 SchemaType CompatibilityMatrix::type() const {
     return mType;
 }
diff --git a/RuntimeInfo.cpp b/RuntimeInfo.cpp
index b29a146..0bcb363 100644
--- a/RuntimeInfo.cpp
+++ b/RuntimeInfo.cpp
@@ -69,6 +69,38 @@
     return mBootAvbVersion;
 }
 
+bool RuntimeInfo::matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
+                                     std::string* error) const {
+    for (const KernelConfig& matrixConfig : matrixConfigs) {
+        const std::string& key = matrixConfig.first;
+        auto it = this->mKernelConfigs.find(key);
+        if (it == this->mKernelConfigs.end()) {
+            // special case: <value type="tristate">n</value> matches if the config doesn't exist.
+            if (matrixConfig.second == KernelConfigTypedValue::gMissingConfig) {
+                continue;
+            }
+            if (error != nullptr) {
+                *error = "Missing config " + key;
+            }
+            return false;
+        }
+        const std::string& kernelValue = it->second;
+        if (!matrixConfig.second.matchValue(kernelValue)) {
+            if (error != nullptr) {
+                *error = "For config " + key + ", value = " + kernelValue + " but required " +
+                         to_string(matrixConfig.second);
+            }
+            return false;
+        }
+    }
+    return true;
+}
+
+bool RuntimeInfo::matchKernelVersion(const KernelVersion& minLts) const {
+    return minLts.version == mKernelVersion.version && minLts.majorRev == mKernelVersion.majorRev &&
+           minLts.minorRev <= mKernelVersion.minorRev;
+}
+
 bool RuntimeInfo::checkCompatibility(const CompatibilityMatrix &mat,
             std::string *error) const {
     if (mat.mType != SchemaType::FRAMEWORK) {
@@ -86,36 +118,46 @@
         return false;
     }
 
-    // mat.mSepolicy.sepolicyVersion() is checked against static HalManifest.device.mSepolicyVersion
+    // mat.mSepolicy.sepolicyVersion() is checked against static
+    // HalManifest.device.mSepolicyVersion in HalManifest::checkCompatibility.
 
-    const MatrixKernel *matrixKernel = mat.findKernel(this->mKernelVersion);
-    if (matrixKernel == nullptr) {
+    bool foundMatchedKernelVersion = false;
+    bool foundMatchedConditions = false;
+    for (const MatrixKernel& matrixKernel : mat.framework.mKernels) {
+        if (!matchKernelVersion(matrixKernel.minLts())) {
+            continue;
+        }
+        foundMatchedKernelVersion = true;
+        // ignore this fragment if not all conditions are met.
+        if (!matchKernelConfigs(matrixKernel.conditions(), error)) {
+            continue;
+        }
+        foundMatchedConditions = true;
+        if (!matchKernelConfigs(matrixKernel.configs(), error)) {
+            return false;
+        }
+    }
+    if (!foundMatchedKernelVersion) {
         if (error != nullptr) {
-            *error = "Cannot find suitable kernel entry for " + to_string(mKernelVersion);
+            std::stringstream ss;
+            ss << "Framework is incompatible with kernel version " << mKernelVersion
+               << ", compatible kernel versions are";
+            for (const MatrixKernel& matrixKernel : mat.framework.mKernels)
+                ss << " " << matrixKernel.minLts();
+            *error = ss.str();
         }
         return false;
     }
-    for (const KernelConfig &matrixConfig : matrixKernel->configs()) {
-        const std::string &key = matrixConfig.first;
-        auto it = this->mKernelConfigs.find(key);
-        if (it == this->mKernelConfigs.end()) {
-            // special case: <value type="tristate">n</value> matches if the config doesn't exist.
-            if (matrixConfig.second == KernelConfigTypedValue::gMissingConfig) {
-                continue;
-            }
-            if (error != nullptr) {
-                *error = "Missing config " + key;
-            }
-            return false;
+    if (!foundMatchedConditions) {
+        // This should not happen because first <conditions> for each <kernel> must be
+        // empty. Reject here for inconsistency.
+        if (error != nullptr) {
+            error->insert(0, "Framework match kernel version with unmet conditions:");
         }
-        const std::string &kernelValue = it->second;
-        if (!matrixConfig.second.matchValue(kernelValue)) {
-            if (error != nullptr) {
-                *error = "For config " + key + ", value = " + kernelValue
-                        + " but required " + to_string(matrixConfig.second);
-            }
-            return false;
-        }
+        return false;
+    }
+    if (error != nullptr) {
+        error->clear();
     }
 
     const Version &matAvb = mat.framework.mAvbMetaVersion;
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 94b8004..36aac51 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -58,9 +58,6 @@
     bool add(MatrixHal &&hal);
     bool add(MatrixKernel &&kernel);
 
-    // Find a MatrixKernel entry that has version v. nullptr if not found.
-    const MatrixKernel *findKernel(const KernelVersion &v) const;
-
     status_t fetchAllInformation(const std::string &path);
 
     friend struct HalManifest;
diff --git a/include/vintf/MatrixKernel.h b/include/vintf/MatrixKernel.h
index 4b261a6..f0990a8 100644
--- a/include/vintf/MatrixKernel.h
+++ b/include/vintf/MatrixKernel.h
@@ -35,7 +35,8 @@
 
 using KernelConfig = std::pair<KernelConfigKey, KernelConfigTypedValue>;
 
-// A kernel entry to a compatibility matrix
+// A <kernel> entry to a compatibility matrix represents a fragment of kernel
+// config requirements.
 struct MatrixKernel {
 
     MatrixKernel() {}
@@ -50,12 +51,18 @@
     // for (const KernelConfig &config : kernel.configs()) {...}
     const std::vector<KernelConfig> &configs() const { return mConfigs; }
 
-private:
+    // Return an iterable on all kernel config conditions. Use it as follows:
+    // for (const KernelConfig &config : kernel.conditions()) {...}
+    const std::vector<KernelConfig>& conditions() const { return mConditions; }
+
+   private:
     friend struct MatrixKernelConverter;
+    friend struct MatrixKernelConditionsConverter;
     friend class AssembleVintf;
 
     KernelVersion mMinLts;
     std::vector<KernelConfig> mConfigs;
+    std::vector<KernelConfig> mConditions;
 };
 
 } // namespace vintf
diff --git a/include/vintf/RuntimeInfo.h b/include/vintf/RuntimeInfo.h
index 4e34f64..6b510fb 100644
--- a/include/vintf/RuntimeInfo.h
+++ b/include/vintf/RuntimeInfo.h
@@ -25,6 +25,9 @@
 
 #include <utils/Errors.h>
 
+#include "MatrixKernel.h"
+#include "Version.h"
+
 namespace android {
 namespace vintf {
 
@@ -79,6 +82,13 @@
 
     status_t fetchAllInformation();
 
+    // mKernelVersion = x'.y'.z', minLts = x.y.z,
+    // match if x == x' , y == y' , and z <= z'.
+    bool matchKernelVersion(const KernelVersion& minLts) const;
+    // return true if all kernel configs in matrixConfigs matches.
+    bool matchKernelConfigs(const std::vector<KernelConfig>& matrixConfigs,
+                            std::string* error = nullptr) const;
+
     // /proc/config.gz
     // Key: CONFIG_xxx; Value: the value after = sign.
     std::map<std::string, std::string> mKernelConfigs;
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 3c840da..259fd4e 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -244,8 +244,8 @@
         std::string attrText;
         bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
         if (!ret) {
-            mLastError = "Could not find/parse attr with name \"" + attrName + "\" for element <"
-                    + elementName() + ">";
+            mLastError = "Could not find/parse attr with name \"" + attrName + "\" and value \"" +
+                         attrText + "\" for element <" + elementName() + ">";
         }
         return ret;
     }
@@ -549,14 +549,31 @@
 
 const MatrixHalConverter matrixHalConverter{};
 
+struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> {
+    std::string elementName() const override { return "conditions"; }
+    void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root,
+                    DocType* d) const override {
+        appendChildren(root, kernelConfigConverter, conds, d);
+    }
+    bool buildObject(std::vector<KernelConfig>* object, NodeType* root) const override {
+        return parseChildren(root, kernelConfigConverter, object);
+    }
+};
+
+const MatrixKernelConditionsConverter matrixKernelConditionsConverter{};
+
 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
     std::string elementName() const override { return "kernel"; }
     void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override {
         appendAttr(root, "version", kernel.mMinLts);
+        if (!kernel.mConditions.empty()) {
+            appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d));
+        }
         appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
     }
     bool buildObject(MatrixKernel *object, NodeType *root) const override {
         if (!parseAttr(root, "version", &object->mMinLts) ||
+            !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions) ||
             !parseChildren(root, kernelConfigConverter, &object->mConfigs)) {
             return false;
         }
@@ -870,6 +887,21 @@
                 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion)) {
                 return false;
             }
+
+            std::set<Version> seenKernelVersions;
+            for (const auto& kernel : object->framework.mKernels) {
+                Version minLts(kernel.minLts().version, kernel.minLts().majorRev);
+                if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) {
+                    continue;
+                }
+                if (!kernel.conditions().empty()) {
+                    this->mLastError = "First <kernel> for version " + to_string(minLts) +
+                                       " must have empty <conditions> for backwards compatibility.";
+                    return false;
+                }
+                seenKernelVersions.insert(minLts);
+            }
+
         } else if (object->mType == SchemaType::DEVICE) {
             // <vndk> can be missing because it can be determined at build time, not hard-coded
             // in the XML file.
diff --git a/test/main.cpp b/test/main.cpp
index d8cfaf3..94a4d8e 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -100,6 +100,7 @@
     bool isValid(const ManifestHal &mh) {
         return mh.isValid();
     }
+    std::vector<MatrixKernel>& getKernels(CompatibilityMatrix& cm) { return cm.framework.mKernels; }
 
     std::map<std::string, HalInterface> testHalInterfaces() {
         HalInterface intf;
@@ -709,6 +710,12 @@
     }
 
     {
+        MatrixKernel kernel(KernelVersion{3, 18, 60}, 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;
@@ -1534,6 +1541,366 @@
 #endif  // LIBVINTF_HOST
 }
 
+TEST_F(LibVintfTest, KernelConfigConditionTest) {
+    std::string xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARM</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_FOO</key>\n"
+        "            <value type=\"tristate\">y</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "        <sepolicy-version>25.0</sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb>\n"
+        "        <vbmeta-version>2.1</vbmeta-version>\n"
+        "    </avb>\n"
+        "</compatibility-matrix>\n";
+
+    CompatibilityMatrix cm;
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    const auto& kernels = getKernels(cm);
+    ASSERT_GE(kernels.size(), 2u);
+    ASSERT_TRUE(kernels[0].conditions().empty());
+    const auto& kernel = kernels[1];
+    const auto& cond = kernel.conditions();
+    ASSERT_FALSE(cond.empty());
+    EXPECT_EQ("CONFIG_ARM", cond.begin()->first);
+    EXPECT_EQ(KernelConfigTypedValue(Tristate::YES), cond.begin()->second);
+    EXPECT_FALSE(kernel.configs().empty());
+
+    EXPECT_EQ(xml, gCompatibilityMatrixConverter(cm));
+}
+
+TEST_F(LibVintfTest, KernelConfigConditionEmptyTest) {
+    std::string xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"4.4.0\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARM</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "    </kernel>\n"
+        "</compatibility-matrix>\n";
+
+    CompatibilityMatrix cm;
+    EXPECT_FALSE(gCompatibilityMatrixConverter(&cm, xml))
+        << "Should not accept first kernel version with non-empty conditions";
+    EXPECT_EQ(
+        "First <kernel> for version 3.18 must have empty <conditions> "
+        "for backwards compatibility.",
+        gCompatibilityMatrixConverter.lastError());
+}
+
+TEST_F(LibVintfTest, KernelConfigConditionMatch) {
+    RuntimeInfo runtime = testRuntimeInfo();
+    std::string error;
+    std::string xml;
+    CompatibilityMatrix cm;
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "            <value type=\"int\">24</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_TRUE(runtime.checkCompatibility(cm, &error)) << error;
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "            <value type=\"int\">26</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_FALSE(runtime.checkCompatibility(cm, &error))
+        << "conditions met, so CONFIG_ARCH_MMAP_RND_BITS should not match";
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">n</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "            <value type=\"int\">26</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_TRUE(runtime.checkCompatibility(cm, &error)) << error;
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "                <value type=\"int\">24</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+        "            <value type=\"int\">0xdead000000000000</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_TRUE(runtime.checkCompatibility(cm, &error));
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "                <value type=\"int\">24</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+        "            <value type=\"int\">0xbeaf000000000000</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_FALSE(runtime.checkCompatibility(cm, &error))
+        << "conditions have 'and' relationship, so CONFIG_ILLEGAL_POINTER_VALUE should not match";
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\"/>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "                <value type=\"int\">26</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+        "            <value type=\"int\">0xbeaf000000000000</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_TRUE(runtime.checkCompatibility(cm, &error)) << error;
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <config>\n"
+        "            <key>CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES</key>\n"
+        "            <value type=\"string\"/>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+        "            <value type=\"int\">0xdead000000000000</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "                <value type=\"int\">24</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ANDROID_BINDER_DEVICES</key>\n"
+        "            <value type=\"string\">binder,hwbinder</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_TRUE(runtime.checkCompatibility(cm, &error)) << error;
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <config>\n"
+        "            <key>CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES</key>\n"
+        "            <value type=\"string\"/>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+        "            <value type=\"int\">0xbeaf000000000000</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "                <value type=\"int\">24</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ANDROID_BINDER_DEVICES</key>\n"
+        "            <value type=\"string\">binder,hwbinder</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_FALSE(runtime.checkCompatibility(cm, &error)) << "all fragments should be used.";
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <config>\n"
+        "            <key>CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES</key>\n"
+        "            <value type=\"string\"/>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_64BIT</key>\n"
+        "                <value type=\"tristate\">y</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ILLEGAL_POINTER_VALUE</key>\n"
+        "            <value type=\"int\">0xdead000000000000</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <kernel version=\"3.18.22\">\n"
+        "        <conditions>\n"
+        "            <config>\n"
+        "                <key>CONFIG_ARCH_MMAP_RND_BITS</key>\n"
+        "                <value type=\"int\">24</value>\n"
+        "            </config>\n"
+        "        </conditions>\n"
+        "        <config>\n"
+        "            <key>CONFIG_ANDROID_BINDER_DEVICES</key>\n"
+        "            <value type=\"string\">binder</value>\n"
+        "        </config>\n"
+        "    </kernel>\n"
+        "    <sepolicy>\n"
+        "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
+        "    </sepolicy>\n"
+        "    <avb><vbmeta-version>2.1</vbmeta-version></avb>\n"
+        "</compatibility-matrix>\n";
+
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
+        << gCompatibilityMatrixConverter.lastError();
+    EXPECT_FALSE(runtime.checkCompatibility(cm, &error)) << "all fragments should be used";
+}
+
 // Run KernelConfigParserInvalidTest on processComments = {true, false}
 class KernelConfigParserInvalidTest : public ::testing::TestWithParam<bool> {};