Add matrix.kernel.level.

Indicates at which level is the kernel requirement from.

Also fix tests now that matrix.kernel.level is serialized.

Bug: 139309488
Test: vintf_object_test
Test: libvintf_test

Change-Id: Ic65b0a2a95a2311b480753a139f3029e87848786
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 7c52296..faba552 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -255,6 +255,9 @@
 // A1, B1 (from 1.xml, required), C2, D2, E3 (optional, use earliest possible).
 bool CompatibilityMatrix::addAllKernels(CompatibilityMatrix* other, std::string* error) {
     for (MatrixKernel& kernel : other->framework.mKernels) {
+        if (kernel.getSourceMatrixLevel() == Level::UNSPECIFIED) {
+            kernel.setSourceMatrixLevel(other->level());
+        }
         KernelVersion ver = kernel.minLts();
         if (!addKernel(std::move(kernel), error)) {
             if (error) {
@@ -285,7 +288,9 @@
             continue;
         }
 
-        (void)kernelToAdd.setSourceMatrixLevel(other->level());
+        if (kernelToAdd.getSourceMatrixLevel() == Level::UNSPECIFIED) {
+            kernelToAdd.setSourceMatrixLevel(other->level());
+        }
 
         KernelVersion minLts = kernelToAdd.minLts();
         if (!addKernel(std::move(kernelToAdd), error)) {
diff --git a/MatrixKernel.cpp b/MatrixKernel.cpp
index 0caaec5..30953d6 100644
--- a/MatrixKernel.cpp
+++ b/MatrixKernel.cpp
@@ -27,10 +27,8 @@
     return true;
 }
 
-bool MatrixKernel::setSourceMatrixLevel(Level level) {
-    if (mSourceMatrixLevel != Level::UNSPECIFIED) return false;
+void MatrixKernel::setSourceMatrixLevel(Level level) {
     mSourceMatrixLevel = level;
-    return true;
 }
 
 Level MatrixKernel::getSourceMatrixLevel() const {
diff --git a/include/vintf/MatrixKernel.h b/include/vintf/MatrixKernel.h
index a10251a..3a33d1a 100644
--- a/include/vintf/MatrixKernel.h
+++ b/include/vintf/MatrixKernel.h
@@ -62,7 +62,7 @@
     friend struct CompatibilityMatrix;
     friend class AssembleVintfImpl;
 
-    bool setSourceMatrixLevel(Level level);
+    void setSourceMatrixLevel(Level level);
     Level getSourceMatrixLevel() const;
 
     KernelVersion mMinLts;
@@ -70,9 +70,7 @@
     std::vector<KernelConfig> mConditions;
 
     // The "level" field of compatibility matrix that this <kernel> tag is
-    // originally from. Note: this field is *NOT* emitted in the serialized
-    // form, which means this information is lost when the combined
-    // compatibility matrix is serialized.
+    // originally from.
     // If UNSPECIFIED, this value should be retrieved from the parent
     // CompatibilityMatrix object.
     Level mSourceMatrixLevel = Level::UNSPECIFIED;
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 9b2da7f..e42f9f7 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -656,6 +656,10 @@
         }
         appendAttr(root, "version", kv);
 
+        if (kernel.getSourceMatrixLevel() != Level::UNSPECIFIED) {
+            appendAttr(root, "level", kernel.getSourceMatrixLevel());
+        }
+
         if (!kernel.mConditions.empty()) {
             appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d));
         }
@@ -664,12 +668,15 @@
         }
     }
     bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
+        Level sourceMatrixLevel = Level::UNSPECIFIED;
         if (!parseAttr(root, "version", &object->mMinLts, error) ||
+            !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &sourceMatrixLevel, error) ||
             !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions,
                                 error) ||
             !parseChildren(root, matrixKernelConfigConverter, &object->mConfigs, error)) {
             return false;
         }
+        object->setSourceMatrixLevel(sourceMatrixLevel);
         return true;
     }
 };
diff --git a/test/AssembleVintfTest.cpp b/test/AssembleVintfTest.cpp
index 042b115..3f6a2c3 100644
--- a/test/AssembleVintfTest.cpp
+++ b/test/AssembleVintfTest.cpp
@@ -144,7 +144,6 @@
 
 TEST_F(AssembleVintfTest, FrameworkMatrix) {
     std::string tail =
-        "    <kernel version=\"3.18.0\">\n"
         "        <config>\n"
         "            <key>CONFIG_FOO</key>\n"
         "            <value type=\"tristate\">y</value>\n"
@@ -160,7 +159,9 @@
         "</compatibility-matrix>\n";
 
     std::string xmlEmpty =
-        "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\">\n" + tail;
+        "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\">\n"
+        "    <kernel version=\"3.18.0\">\n" +
+        tail;
 
     std::string xml1 =
         "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"1\">\n"
@@ -246,7 +247,8 @@
         "            <name>IFoo</name>\n"
         "            <instance>default</instance>\n"
         "        </interface>\n"
-        "    </hal>\n" +
+        "    </hal>\n"
+        "    <kernel version=\"3.18.0\" level=\"1\">\n" +
             tail,
         getOutput());
 
@@ -263,7 +265,8 @@
         "            <name>IFoo</name>\n"
         "            <instance>default</instance>\n"
         "        </interface>\n"
-        "    </hal>\n" +
+        "    </hal>\n"
+        "    <kernel version=\"3.18.0\" level=\"2\">\n" +
             tail,
         getOutput());
 
@@ -279,7 +282,8 @@
         "            <name>IFoo</name>\n"
         "            <instance>default</instance>\n"
         "        </interface>\n"
-        "    </hal>\n" +
+        "    </hal>\n"
+        "    <kernel version=\"3.18.0\" level=\"3\">\n" +
             tail,
         getOutput());
 }
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index 5fdf227..c22220b 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -3986,7 +3986,7 @@
 // <kernel> without <conditions> always comes first
 TEST_F(FrameworkCompatibilityMatrixCombineTest, KernelNoConditions) {
     std::string conditionedKernel =
-        "    <kernel version=\"3.18.5\">\n"
+        "    <kernel version=\"3.18.5\" level=\"1\">\n"
         "        <conditions>\n"
         "            <config>\n"
         "                <key>CONFIG_ARM</key>\n"
@@ -3999,7 +3999,7 @@
         "        </config>\n"
         "    </kernel>\n";
     std::string simpleKernel =
-        "    <kernel version=\"3.18.5\">\n"
+        "    <kernel version=\"3.18.5\" level=\"1\">\n"
         "        <config>\n"
         "            <key>CONFIG_BAR</key>\n"
         "            <value type=\"tristate\">y</value>\n"
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index fadec1a..6a8e22e 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -1334,8 +1334,8 @@
 // Set of framework matrices of different FCM version with <kernel>.
 //
 
-#define FAKE_KERNEL(__version__, __key__)                   \
-    "    <kernel version=\"" __version__ "\">\n"            \
+#define FAKE_KERNEL(__version__, __key__, __level__)                   \
+    "    <kernel version=\"" __version__ "\" level=\"" #__level__ "\">\n"            \
     "        <config>\n"                                    \
     "            <key>CONFIG_" __key__ "</key>\n"           \
     "            <value type=\"tristate\">y</value>\n"      \
@@ -1345,19 +1345,19 @@
 const static std::vector<std::string> systemMatrixKernelXmls = {
     // 1.xml
     "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"1\">\n"
-    FAKE_KERNEL("1.0.0", "A1")
-    FAKE_KERNEL("2.0.0", "B1")
+    FAKE_KERNEL("1.0.0", "A1", 1)
+    FAKE_KERNEL("2.0.0", "B1", 1)
     "</compatibility-matrix>\n",
     // 2.xml
     "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"2\">\n"
-    FAKE_KERNEL("2.0.0", "B2")
-    FAKE_KERNEL("3.0.0", "C2")
-    FAKE_KERNEL("4.0.0", "D2")
+    FAKE_KERNEL("2.0.0", "B2", 2)
+    FAKE_KERNEL("3.0.0", "C2", 2)
+    FAKE_KERNEL("4.0.0", "D2", 2)
     "</compatibility-matrix>\n",
     // 3.xml
     "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"3\">\n"
-    FAKE_KERNEL("4.0.0", "D3")
-    FAKE_KERNEL("5.0.0", "E3")
+    FAKE_KERNEL("4.0.0", "D3", 3)
+    FAKE_KERNEL("5.0.0", "E3", 3)
     "</compatibility-matrix>\n",
 };
 
@@ -1373,12 +1373,12 @@
     ASSERT_NE(nullptr, matrix);
     std::string xml = gCompatibilityMatrixConverter(*matrix);
 
-    EXPECT_IN(FAKE_KERNEL("1.0.0", "A1"), xml) << "\nOld requirements must not change.";
-    EXPECT_IN(FAKE_KERNEL("2.0.0", "B1"), xml) << "\nOld requirements must not change.";
-    EXPECT_IN(FAKE_KERNEL("3.0.0", "C2"), xml) << "\nShould see <kernel> from new matrices";
-    EXPECT_IN(FAKE_KERNEL("4.0.0", "D2"), xml) << "\nShould see <kernel> from new matrices";
+    EXPECT_IN(FAKE_KERNEL("1.0.0", "A1", 1), xml) << "\nOld requirements must not change.";
+    EXPECT_IN(FAKE_KERNEL("2.0.0", "B1", 1), xml) << "\nOld requirements must not change.";
+    EXPECT_IN(FAKE_KERNEL("3.0.0", "C2", 2), xml) << "\nShould see <kernel> from new matrices";
+    EXPECT_IN(FAKE_KERNEL("4.0.0", "D2", 2), xml) << "\nShould see <kernel> from new matrices";
 
-    EXPECT_NOT_IN(FAKE_KERNEL("2.0.0", "B2"), xml) << "\nOld requirements must not change";
+    EXPECT_NOT_IN(FAKE_KERNEL("2.0.0", "B2", 2), xml) << "\nOld requirements must not change";
 }
 
 // Assume that we are developing level 3. Test that old <kernel> requirements should
@@ -1391,14 +1391,14 @@
     ASSERT_NE(nullptr, matrix);
     std::string xml = gCompatibilityMatrixConverter(*matrix);
 
-    EXPECT_IN(FAKE_KERNEL("1.0.0", "A1"), xml) << "\nOld requirements must not change.";
-    EXPECT_IN(FAKE_KERNEL("2.0.0", "B1"), xml) << "\nOld requirements must not change.";
-    EXPECT_IN(FAKE_KERNEL("3.0.0", "C2"), xml) << "\nOld requirements must not change.";
-    EXPECT_IN(FAKE_KERNEL("4.0.0", "D2"), xml) << "\nOld requirements must not change.";
-    EXPECT_IN(FAKE_KERNEL("5.0.0", "E3"), xml) << "\nShould see <kernel> from new matrices";
+    EXPECT_IN(FAKE_KERNEL("1.0.0", "A1", 1), xml) << "\nOld requirements must not change.";
+    EXPECT_IN(FAKE_KERNEL("2.0.0", "B1", 1), xml) << "\nOld requirements must not change.";
+    EXPECT_IN(FAKE_KERNEL("3.0.0", "C2", 2), xml) << "\nOld requirements must not change.";
+    EXPECT_IN(FAKE_KERNEL("4.0.0", "D2", 2), xml) << "\nOld requirements must not change.";
+    EXPECT_IN(FAKE_KERNEL("5.0.0", "E3", 3), xml) << "\nShould see <kernel> from new matrices";
 
-    EXPECT_NOT_IN(FAKE_KERNEL("2.0.0", "B2"), xml) << "\nOld requirements must not change";
-    EXPECT_NOT_IN(FAKE_KERNEL("4.0.0", "D3"), xml) << "\nOld requirements must not change";
+    EXPECT_NOT_IN(FAKE_KERNEL("2.0.0", "B2", 2), xml) << "\nOld requirements must not change";
+    EXPECT_NOT_IN(FAKE_KERNEL("4.0.0", "D3", 3), xml) << "\nOld requirements must not change";
 }
 
 class VintfObjectPartialUpdateTest : public MultiMatrixTest {