assemble_vintf: add --no-kernel-requirements option

When specified, <config> under <kernel> will not be written to the
output matrix, and kernel minor revision will be set to zero.
These requirements are added in P but is verified against the running
kernel (instead of the incoming kernel). This incorrect behavior
in recovery forces us to drop these requirements during OTA.

These requirements are still checked by VTS.

Bug: 111840577
Test: libvintf_test
Change-Id: Id0d7851f5cc11fbd8e6e2928ce377769855445db
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index ea8c9b3..b54b971 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -678,6 +678,12 @@
         return true;
     }
 
+    bool setNoKernelRequirements() override {
+        mSerializeFlags |= SerializeFlag::NO_KERNEL_CONFIGS;
+        mSerializeFlags |= SerializeFlag::NO_KERNEL_MINOR_REVISION;
+        return true;
+    }
+
    private:
     std::vector<NamedIstream> mInFiles;
     Ostream mOutRef;
diff --git a/assemble_vintf_main.cpp b/assemble_vintf_main.cpp
index e84aaaf..2733261 100644
--- a/assemble_vintf_main.cpp
+++ b/assemble_vintf_main.cpp
@@ -63,7 +63,10 @@
                  "               Output has only <hal> entries. Cannot be used with -n.\n"
                  "    -n, --no-hals\n"
                  "               Output has no <hal> entries (but all other entries).\n"
-                 "               Cannot be used with -l.\n";
+                 "               Cannot be used with -l.\n"
+                 "    --no-kernel-requirements\n"
+                 "               Output has no <config> entries in <kernel>, and kernel minor\n"
+                 "               version is set to zero. (For example, 3.18.0).\n";
 }
 
 int main(int argc, char** argv) {
@@ -71,6 +74,7 @@
     const struct option longopts[] = {{"kernel", required_argument, NULL, 'k'},
                                       {"hals-only", no_argument, NULL, 'l'},
                                       {"no-hals", no_argument, NULL, 'n'},
+                                      {"no-kernel-requirements", no_argument, NULL, 'K'},
                                       {0, 0, 0, 0}};
 
     std::string outFilePath;
@@ -126,6 +130,12 @@
                 }
             } break;
 
+            case 'K': {
+                if (!assembleVintf->setNoKernelRequirements()) {
+                    return 1;
+                }
+            } break;
+
             case 'h':
             default: {
                 help();
diff --git a/include-test/vintf/AssembleVintf.h b/include-test/vintf/AssembleVintf.h
index ac6d2af..56b4811 100644
--- a/include-test/vintf/AssembleVintf.h
+++ b/include-test/vintf/AssembleVintf.h
@@ -38,6 +38,7 @@
     virtual ~AssembleVintf() = default;
     virtual bool setHalsOnly() = 0;
     virtual bool setNoHals() = 0;
+    virtual bool setNoKernelRequirements() = 0;
     virtual void setOutputMatrix() = 0;
     virtual bool assemble() = 0;
 
diff --git a/include/vintf/parse_xml.h b/include/vintf/parse_xml.h
index 578e15b..744a2e7 100644
--- a/include/vintf/parse_xml.h
+++ b/include/vintf/parse_xml.h
@@ -32,6 +32,8 @@
     NO_XMLFILES = 1 << 5,
     NO_SSDK = 1 << 6,
     NO_FQNAME = 1 << 7,
+    NO_KERNEL_CONFIGS = 1 << 8,
+    NO_KERNEL_MINOR_REVISION = 1 << 9,
 
     EVERYTHING = 0,
     HALS_ONLY = ~(NO_HALS | NO_FQNAME),  // <hal> with <fqname>
diff --git a/parse_xml.cpp b/parse_xml.cpp
index fbac04e..7947fc3 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -601,12 +601,23 @@
 
 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);
+    void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d) const override {
+        mutateNode(kernel, root, d, SerializeFlag::EVERYTHING);
+    }
+    void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d,
+                    SerializeFlags flags) const override {
+        KernelVersion kv = kernel.mMinLts;
+        if (flags & SerializeFlag::NO_KERNEL_MINOR_REVISION) {
+            kv.minorRev = 0u;
+        }
+        appendAttr(root, "version", kv);
+
         if (!kernel.mConditions.empty()) {
             appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d));
         }
-        appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
+        if (!(flags & SerializeFlag::NO_KERNEL_CONFIGS)) {
+            appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
+        }
     }
     bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
         if (!parseAttr(root, "version", &object->mMinLts, error) ||
@@ -1023,7 +1034,7 @@
         }
         if (m.mType == SchemaType::FRAMEWORK) {
             if (!(flags & SerializeFlag::NO_KERNEL)) {
-                appendChildren(root, matrixKernelConverter, m.framework.mKernels, d);
+                appendChildren(root, matrixKernelConverter, m.framework.mKernels, d, flags);
             }
             if (!(flags & SerializeFlag::NO_SEPOLICY)) {
                 if (!(m.framework.mSepolicy == Sepolicy{})) {