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

Commit 97d0375f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 5a910978 a00ba07a
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