Merge "Support versions in rule serializers"
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
index ace15bd..7ecd624 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -20,17 +20,19 @@
 
 import java.io.OutputStream;
 import java.util.List;
+import java.util.Optional;
 
 /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
 public class RuleBinarySerializer implements RuleSerializer {
 
     @Override
-    public void serialize(List<Rule> rules, OutputStream outputStream) {
+    public void serialize(
+            List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream) {
         // TODO: Implement stream serializer.
     }
 
     @Override
-    public String serialize(List<Rule> rules) {
+    public String serialize(List<Rule> rules, Optional<Integer> formatVersion) {
         // TODO: Implement text serializer.
         return null;
     }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
index c45f6be..1125f78 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
@@ -20,13 +20,16 @@
 
 import java.io.OutputStream;
 import java.util.List;
+import java.util.Optional;
 
 /** A helper class to serialize rules from the {@link Rule} model. */
 public interface RuleSerializer {
 
     /** Serialize rules to an output stream */
-    void serialize(List<Rule> rules, OutputStream outputStream) throws RuleSerializeException;
+    void serialize(List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
+            throws RuleSerializeException;
 
     /** Serialize rules to a string. */
-    String serialize(List<Rule> rule) throws RuleSerializeException;
+    String serialize(List<Rule> rule, Optional<Integer> formatVersion)
+            throws RuleSerializeException;
 }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
index 5dd7891..254baba 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -29,6 +29,7 @@
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.Optional;
 
 /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
 public class RuleXmlSerializer implements RuleSerializer {
@@ -48,7 +49,8 @@
     private static final String IS_HASHED_VALUE_ATTRIBUTE = "H";
 
     @Override
-    public void serialize(List<Rule> rules, OutputStream outputStream)
+    public void serialize(
+            List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
             throws RuleSerializeException {
         try {
             XmlSerializer xmlSerializer = Xml.newSerializer();
@@ -60,7 +62,8 @@
     }
 
     @Override
-    public String serialize(List<Rule> rules) throws RuleSerializeException {
+    public String serialize(List<Rule> rules, Optional<Integer> formatVersion)
+            throws RuleSerializeException {
         try {
             XmlSerializer xmlSerializer = Xml.newSerializer();
             StringWriter writer = new StringWriter();
@@ -108,8 +111,8 @@
             return;
         }
         xmlSerializer.startTag(NAMESPACE, OPEN_FORMULA_TAG);
-        serializeAttributeValue(CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()),
-                xmlSerializer);
+        serializeAttributeValue(
+                CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()), xmlSerializer);
         for (Formula formula : compoundFormula.getFormulas()) {
             serializeFormula(formula, xmlSerializer);
         }
@@ -122,24 +125,30 @@
             return;
         }
         xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG);
-        serializeAttributeValue(KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()),
-                xmlSerializer);
+        serializeAttributeValue(
+                KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()), xmlSerializer);
         if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) {
-            serializeAttributeValue(VALUE_ATTRIBUTE,
-                    ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), xmlSerializer);
-            serializeAttributeValue(IS_HASHED_VALUE_ATTRIBUTE,
+            serializeAttributeValue(
+                    VALUE_ATTRIBUTE,
+                    ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(),
+                    xmlSerializer);
+            serializeAttributeValue(
+                    IS_HASHED_VALUE_ATTRIBUTE,
                     String.valueOf(
                             ((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()),
                     xmlSerializer);
         } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) {
-            serializeAttributeValue(OPERATOR_ATTRIBUTE,
+            serializeAttributeValue(
+                    OPERATOR_ATTRIBUTE,
                     String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()),
                     xmlSerializer);
-            serializeAttributeValue(VALUE_ATTRIBUTE,
+            serializeAttributeValue(
+                    VALUE_ATTRIBUTE,
                     String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()),
                     xmlSerializer);
         } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) {
-            serializeAttributeValue(VALUE_ATTRIBUTE,
+            serializeAttributeValue(
+                    VALUE_ATTRIBUTE,
                     String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()),
                     xmlSerializer);
         } else {
@@ -149,9 +158,8 @@
         xmlSerializer.endTag(NAMESPACE, ATOMIC_FORMULA_TAG);
     }
 
-    private void serializeAttributeValue(String attribute, String value,
-            XmlSerializer xmlSerializer)
-            throws IOException {
+    private void serializeAttributeValue(
+            String attribute, String value, XmlSerializer xmlSerializer) throws IOException {
         if (value == null) {
             return;
         }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
index 40e89ba..180de2f 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
@@ -38,6 +38,7 @@
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Optional;
 
 @RunWith(JUnit4.class)
 public class RuleXmlSerializerTest {
@@ -48,7 +49,9 @@
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         String expectedRules = "<RL />";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
@@ -56,53 +59,74 @@
     @Test
     public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
         Rule rule1 = null;
-        Rule rule2 = new Rule(
-                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
-                        /* isHashedValue= */ false),
-                Rule.DENY);
+        Rule rule2 =
+                new Rule(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.PACKAGE_NAME,
+                                "com.app.test",
+                                /* isHashedValue= */ false),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Arrays.asList(rule1, rule2));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
 
     @Test
     public void testXmlStream_serializeValidOpenFormula() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.NOT,
-                Collections.singletonList(
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false))), Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         OutputStream outputStream = new ByteArrayOutputStream();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        xmlSerializer.serialize(Collections.singletonList(rule), outputStream);
+        xmlSerializer.serialize(
+                Collections.singletonList(rule),
+                /* formatVersion= */ Optional.empty(),
+                outputStream);
 
         String actualRules = outputStream.toString();
         assertEquals(expectedRules, actualRules);
@@ -110,39 +134,60 @@
 
     @Test
     public void testXmlString_serializeValidOpenFormula_notConnector() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.NOT,
-                Collections.singletonList(
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false))), Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
 
     @Test
     public void testXmlString_serializeValidOpenFormula_andConnector() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.AND,
-                Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false),
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
-                                "test_cert", /* isHashedValue= */ false))), Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                "test_cert",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
@@ -152,31 +197,47 @@
         appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
         appCertificateAttrs.put("V", "test_cert");
         appCertificateAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
 
     @Test
     public void testXmlString_serializeValidOpenFormula_orConnector() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.OR,
-                Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false),
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
-                                "test_cert", /* isHashedValue= */ false))), Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.OR,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                "test_cert",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
@@ -186,89 +247,117 @@
         appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
         appCertificateAttrs.put("V", "test_cert");
         appCertificateAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
 
     @Test
     public void testXmlString_serializeValidAtomicFormula_stringValue() throws Exception {
-        Rule rule = new Rule(
-                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
-                        /* isHashedValue= */ false),
-                Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.PACKAGE_NAME,
+                                "com.app.test",
+                                /* isHashedValue= */ false),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
 
     @Test
     public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception {
-        Rule rule = new Rule(
-                new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
-                Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.IntAtomicFormula(
+                                AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> versionCodeAttrs = new LinkedHashMap<>();
         versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE));
         versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ));
         versionCodeAttrs.put("V", "1");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
 
     @Test
     public void testXmlString_serializeValidAtomicFormula_booleanValue() throws Exception {
-        Rule rule = new Rule(
-                new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
-                Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> preInstalledAttrs = new LinkedHashMap<>();
         preInstalledAttrs.put("K", String.valueOf(AtomicFormula.PRE_INSTALLED));
         preInstalledAttrs.put("V", "true");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        String actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, actualRules);
     }
@@ -282,11 +371,14 @@
         assertExpectException(
                 RuleSerializeException.class,
                 /* expectedExceptionMessageRegex */ "Invalid formula type",
-                () -> xmlSerializer.serialize(Collections.singletonList(rule)));
+                () ->
+                        xmlSerializer.serialize(
+                                Collections.singletonList(rule),
+                                /* formatVersion= */ Optional.empty()));
     }
 
-    private String generateTagWithAttribute(String tag, Map<String, String> attributeValues,
-            boolean closed) {
+    private String generateTagWithAttribute(
+            String tag, Map<String, String> attributeValues, boolean closed) {
         StringBuilder res = new StringBuilder("<");
         res.append(tag);
         for (String attribute : attributeValues.keySet()) {