Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a00ba07a authored by Omer Nebil Yaveroglu's avatar Omer Nebil Yaveroglu
Browse files

Modify RuleXmlSerializer to output the rules in the indexing friendly order.

Bug: 145488708
Test: atest FrameworksServicesTests:RuleBinarySerializerTest
Change-Id: I1e1292c6ca86b6634efdbcf147a68c0a1f577da9
parent f8047648
Loading
Loading
Loading
Loading
+28 −4
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.server.integrity.serializer;

import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;

import android.content.integrity.AtomicFormula;
import android.content.integrity.CompoundFormula;
import android.content.integrity.Formula;
@@ -29,6 +33,7 @@ import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
@@ -75,13 +80,32 @@ public class RuleXmlSerializer implements RuleSerializer {
        }
    }

    private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException {
    private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer)
            throws RuleSerializeException {
        try {
            // Determine the indexing groups and the order of the rules within each indexed group.
            Map<Integer, List<Rule>> indexedRules =
                    RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules);

            // Write the XML formatted rules in order.
            xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG);

            serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), xmlSerializer);
            serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), xmlSerializer);
            serializeRuleList(indexedRules.get(NOT_INDEXED), xmlSerializer);

            xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
            xmlSerializer.endDocument();
        } catch (Exception e) {
            throw new RuleSerializeException(e.getMessage(), e);
        }
    }

    private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer)
            throws IOException {
        for (Rule rule : rules) {
            serializeRule(rule, xmlSerializer);
        }
        xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
        xmlSerializer.endDocument();
    }

    private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException {
+163 −27
Original line number Diff line number Diff line
@@ -44,48 +44,66 @@ import java.util.Optional;
@RunWith(JUnit4.class)
public class RuleXmlSerializerTest {

    private static final String SAMPLE_INSTALLER_NAME = "com.test.installer";
    private static final String SAMPLE_INSTALLER_CERT = "installer_cert";

    @Test
    public void testXmlString_serializeEmptyRule() throws Exception {
        Rule rule = null;
    public void testXmlString_serializeEmptyRuleList() throws Exception {
        RuleSerializer xmlSerializer = new RuleXmlSerializer();
        String expectedRules = "<RL />";

        byte[] actualRules =
                xmlSerializer.serialize(
                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
                        Collections.emptyList(), /* formatVersion= */ Optional.empty());

        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
    }

    @Test
    public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
        Rule rule1 = null;
        Rule rule2 =
    public void testXmlString_serializeMultipleRules_indexingOrderPreserved() throws Exception {
        String packageNameA = "aaa";
        String packageNameB = "bbb";
        String packageNameC = "ccc";
        String appCert1 = "cert1";
        String appCert2 = "cert2";
        String appCert3 = "cert3";
        Rule installerRule =
                new Rule(
                        new CompoundFormula(
                                CompoundFormula.AND,
                                Arrays.asList(
                                        new AtomicFormula.StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                "com.app.test",
                                                AtomicFormula.INSTALLER_NAME,
                                                SAMPLE_INSTALLER_NAME,
                                                /* isHashedValue= */ false),
                                        new AtomicFormula.StringAtomicFormula(
                                                AtomicFormula.INSTALLER_CERTIFICATE,
                                                SAMPLE_INSTALLER_CERT,
                                                /* 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>";

        RuleSerializer xmlSerializer = new RuleXmlSerializer();
        byte[] actualRules =
                xmlSerializer.serialize(
                        Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty());
                        Arrays.asList(
                                installerRule,
                                getRuleWithAppCertificateAndSampleInstallerName(appCert1),
                                getRuleWithPackageNameAndSampleInstallerName(packageNameB),
                                getRuleWithAppCertificateAndSampleInstallerName(appCert3),
                                getRuleWithPackageNameAndSampleInstallerName(packageNameC),
                                getRuleWithAppCertificateAndSampleInstallerName(appCert2),
                                getRuleWithPackageNameAndSampleInstallerName(packageNameA)),
                        /* formatVersion= */ Optional.empty());

        String expectedRules = "<RL>"
                + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameA)
                + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameB)
                + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameC)
                + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert1)
                + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert2)
                + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert3)
                + getSerializedCompoundRuleWithSampleInstallerNameAndCert()
                + "</RL>";

        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
    }
@@ -371,7 +389,7 @@ public class RuleXmlSerializerTest {

        assertExpectException(
                RuleSerializeException.class,
                /* expectedExceptionMessageRegex */ "Invalid formula type",
                /* expectedExceptionMessageRegex */ "Malformed rule identified.",
                () ->
                        xmlSerializer.serialize(
                                Collections.singletonList(rule),
@@ -393,6 +411,124 @@ public class RuleXmlSerializerTest {
        return res.toString();
    }

    private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) {
        return new Rule(
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new AtomicFormula.StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        packageName,
                                        /* isHashedValue= */ false),
                                new AtomicFormula.StringAtomicFormula(
                                        AtomicFormula.INSTALLER_NAME,
                                        SAMPLE_INSTALLER_NAME,
                                        /* isHashedValue= */ false))),
                Rule.DENY);
    }

    private String getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(
            String packageName) {

        Map<String, String> packageNameAttrs = new LinkedHashMap<>();
        packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
        packageNameAttrs.put("V", packageName);
        packageNameAttrs.put("H", "false");

        Map<String, String> installerNameAttrs = new LinkedHashMap<>();
        installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME));
        installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME);
        installerNameAttrs.put("H", "false");

        return 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", installerNameAttrs, /* closed= */ true)
                + "</OF>"
                + "</R>";
    }


    private Rule getRuleWithAppCertificateAndSampleInstallerName(String certificate) {
        return new Rule(
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new AtomicFormula.StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        certificate,
                                        /* isHashedValue= */ false),
                                new AtomicFormula.StringAtomicFormula(
                                        AtomicFormula.INSTALLER_NAME,
                                        SAMPLE_INSTALLER_NAME,
                                        /* isHashedValue= */ false))),
                Rule.DENY);
    }

    private String getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(
            String appCert) {

        Map<String, String> packageNameAttrs = new LinkedHashMap<>();
        packageNameAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
        packageNameAttrs.put("V", appCert);
        packageNameAttrs.put("H", "false");

        Map<String, String> installerNameAttrs = new LinkedHashMap<>();
        installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME));
        installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME);
        installerNameAttrs.put("H", "false");

        return 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", installerNameAttrs, /* closed= */ true)
                + "</OF>"
                + "</R>";
    }

    private String getSerializedCompoundRuleWithSampleInstallerNameAndCert() {
        Map<String, String> installerNameAttrs = new LinkedHashMap<>();
        installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME));
        installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME);
        installerNameAttrs.put("H", "false");

        Map<String, String> installerCertAttrs = new LinkedHashMap<>();
        installerCertAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_CERTIFICATE));
        installerCertAttrs.put("V", SAMPLE_INSTALLER_CERT);
        installerCertAttrs.put("H", "false");

        return 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", installerNameAttrs, /* closed= */ true)
                + generateTagWithAttribute(
                        /* tag= */ "AF", installerCertAttrs, /* closed= */ true)
                + "</OF>"
                + "</R>";
    }

    private Formula getInvalidFormula() {
        return new Formula() {
            @Override