Loading services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +48 −15 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.integrity.CompoundFormula; import android.content.integrity.Formula; import android.content.integrity.Rule; import com.android.internal.util.Preconditions; import com.android.server.integrity.IntegrityUtils; import com.android.server.integrity.model.BitOutputStream; Loading @@ -46,10 +47,17 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; /** A helper class to serialize rules from the {@link Rule} model to Binary representation. */ public class RuleBinarySerializer implements RuleSerializer { // The parsing time seems acceptable for 100 rules based on the tests in go/ic-rule-file-format. private static final int INDEXING_BLOCK_SIZE = 100; private static final String START_INDEXING_KEY = "START_KEY"; private static final String END_INDEXING_KEY = "END_KEY"; // Get the byte representation for a list of rules. @Override public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion) Loading @@ -66,25 +74,34 @@ public class RuleBinarySerializer implements RuleSerializer { // Get the byte representation for a list of rules, and write them to an output stream. @Override public void serialize( List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream) List<Rule> rules, Optional<Integer> formatVersion, OutputStream originalOutputStream) throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. Map<Integer, List<Rule>> indexedRules = Map<Integer, TreeMap<String, List<Rule>>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); ByteTrackedOutputStream outputStream = new ByteTrackedOutputStream(originalOutputStream); serializeRuleFileMetadata(formatVersion, outputStream); serializeIndexedRules(indexedRules.get(PACKAGE_NAME_INDEXED), outputStream); serializeIndexedRules(indexedRules.get(APP_CERTIFICATE_INDEXED), outputStream); serializeIndexedRules(indexedRules.get(NOT_INDEXED), outputStream); Map<String, Long> packageNameIndexes = serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), outputStream); Map<String, Long> appCertificateIndexes = serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), outputStream); Map<String, Long> unindexedRulesIndex = serializeRuleList(indexedRules.get(NOT_INDEXED), outputStream); // TODO(b/145493956): Write these indexes into a index file provided by integrity file // manager. } catch (Exception e) { throw new RuleSerializeException(e.getMessage(), e); } } private void serializeRuleFileMetadata( Optional<Integer> formatVersion, OutputStream outputStream) throws IOException { private void serializeRuleFileMetadata(Optional<Integer> formatVersion, ByteTrackedOutputStream outputStream) throws IOException { int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION); BitOutputStream bitOutputStream = new BitOutputStream(); Loading @@ -92,18 +109,34 @@ public class RuleBinarySerializer implements RuleSerializer { outputStream.write(bitOutputStream.toByteArray()); } private void serializeIndexedRules(List<Rule> rules, OutputStream outputStream) private Map<String, Long> serializeRuleList(TreeMap<String, List<Rule>> rulesMap, ByteTrackedOutputStream outputStream) throws IOException { if (rules == null) { return; } Preconditions.checkArgument(rulesMap != null, "serializeRuleList should never be called with null rule list."); BitOutputStream bitOutputStream = new BitOutputStream(); for (Rule rule : rules) { Map<String, Long> indexMapping = new TreeMap(); long indexTracker = 0; indexMapping.put(START_INDEXING_KEY, outputStream.getWrittenBytesCount()); for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) { if (indexTracker >= INDEXING_BLOCK_SIZE) { indexMapping.put(entry.getKey(), outputStream.getWrittenBytesCount()); indexTracker = 0; } for (Rule rule : entry.getValue()) { bitOutputStream.clear(); serializeRule(rule, bitOutputStream); outputStream.write(bitOutputStream.toByteArray()); indexTracker++; } } indexMapping.put(END_INDEXING_KEY, outputStream.getWrittenBytesCount()); return indexMapping; } private void serializeRule(Rule rule, BitOutputStream bitOutputStream) { if (rule == null) { Loading services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java +8 −24 Original line number Diff line number Diff line Loading @@ -38,23 +38,19 @@ class RuleIndexingDetailsIdentifier { private static final String DEFAULT_RULE_KEY = "N/A"; /** * Splits a given rule list into three indexing categories and returns a sorted list of rules * per each index. * * The sorting guarantees an order based on the key but the rules that have the same key * can be in arbitrary order. For example, given the rules of [package_name_a_rule_1, * package_name_a_rule_2, package_name_b_rule_3, package_name_b_rule_4], the method will * guarantee that package_name_b rules (i.e., 3 and 4) will never come before package_name_a * rules (i.e., 1 and 2). However, we do not care about the ordering between rule 1 and 2. * We also do not care about the ordering between rule 3 and 4. * Splits a given rule list into three indexing categories. Each rule category is returned as a * TreeMap that is sorted by their indexing keys -- where keys correspond to package name for * PACKAGE_NAME_INDEXED rules, app certificate for APP_CERTIFICATE_INDEXED rules and N/A for * NOT_INDEXED rules. */ public static Map<Integer, List<Rule>> splitRulesIntoIndexBuckets(List<Rule> rules) { public static Map<Integer, TreeMap<String, List<Rule>>> splitRulesIntoIndexBuckets( List<Rule> rules) { if (rules == null) { throw new IllegalArgumentException( "Index buckets cannot be created for null rule list."); } Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); Map<Integer, TreeMap<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); typeOrganizedRuleMap.put(NOT_INDEXED, new TreeMap()); typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new TreeMap()); typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new TreeMap()); Loading Loading @@ -87,19 +83,7 @@ class RuleIndexingDetailsIdentifier { .add(rule); } // Per indexing type, create the sorted rule set based on their key. Map<Integer, List<Rule>> orderedListPerIndexingType = new HashMap<>(); for (Integer indexingKey : typeOrganizedRuleMap.keySet()) { List<Rule> sortedRules = new ArrayList(); for (Map.Entry<String, List<Rule>> entry : typeOrganizedRuleMap.get(indexingKey).entrySet()) { sortedRules.addAll(entry.getValue()); } orderedListPerIndexingType.put(indexingKey, sortedRules); } return orderedListPerIndexingType; return typeOrganizedRuleMap; } private static RuleIndexingDetails getIndexingDetails(Formula formula) { Loading services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +8 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */ public class RuleXmlSerializer implements RuleSerializer { Loading Loading @@ -84,7 +85,7 @@ public class RuleXmlSerializer implements RuleSerializer { throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. Map<Integer, List<Rule>> indexedRules = Map<Integer, TreeMap<String, List<Rule>>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); // Write the XML formatted rules in order. Loading @@ -101,12 +102,15 @@ public class RuleXmlSerializer implements RuleSerializer { } } private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer) private void serializeRuleList(TreeMap<String, List<Rule>> rulesMap, XmlSerializer xmlSerializer) throws IOException { for (Rule rule : rules) { for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) { for (Rule rule : entry.getValue()) { serializeRule(rule, xmlSerializer); } } } private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException { if (rule == null) { Loading services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java +42 −19 Original line number Diff line number Diff line Loading @@ -38,8 +38,10 @@ import org.junit.runners.JUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; /** Unit tests for {@link RuleIndexingDetailsIdentifier}. */ @RunWith(JUnit4.class) Loading Loading @@ -138,14 +140,16 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_PACKAGE_NAME); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); // Verify the resulting map content. assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(NOT_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(PACKAGE_NAME_INDEXED)).containsExactly(RULE_WITH_PACKAGE_NAME); assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly(SAMPLE_PACKAGE_NAME); assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME)) .containsExactly(RULE_WITH_PACKAGE_NAME); } @Test Loading @@ -153,13 +157,16 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_APP_CERTIFICATE); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(NOT_INDEXED)).isEmpty(); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).containsExactly(RULE_WITH_APP_CERTIFICATE); assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()) .containsExactly(SAMPLE_APP_CERTIFICATE); assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE)) .containsExactly(RULE_WITH_APP_CERTIFICATE); } @Test Loading @@ -167,13 +174,14 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS); assertThat(result.get(NOT_INDEXED).get("N/A")) .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS); } @Test Loading @@ -181,13 +189,14 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS); assertThat(result.get(NOT_INDEXED).get("N/A")) .containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS); } @Test Loading @@ -206,13 +215,13 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(negatedRule); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(NOT_INDEXED)).containsExactly(negatedRule); assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(negatedRule); } @Test Loading @@ -234,22 +243,36 @@ public class RuleIndexingDetailsIdentifierTest { ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); // We check asserts this way to ensure ordering based on package name. assertThat(result.get(PACKAGE_NAME_INDEXED).get(0)).isEqualTo(packageNameRuleA); assertThat(result.get(PACKAGE_NAME_INDEXED).get(1)).isEqualTo(packageNameRuleB); assertThat(result.get(PACKAGE_NAME_INDEXED).get(2)).isEqualTo(packageNameRuleC); assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly("aaa", "bbb", "ccc"); Iterator<String> keySetIterator = result.get(PACKAGE_NAME_INDEXED).keySet().iterator(); assertThat(keySetIterator.next()).isEqualTo("aaa"); assertThat(keySetIterator.next()).isEqualTo("bbb"); assertThat(keySetIterator.next()).isEqualTo("ccc"); assertThat(result.get(PACKAGE_NAME_INDEXED).get("aaa")).containsExactly(packageNameRuleA); assertThat(result.get(PACKAGE_NAME_INDEXED).get("bbb")).containsExactly(packageNameRuleB); assertThat(result.get(PACKAGE_NAME_INDEXED).get("ccc")).containsExactly(packageNameRuleC); // We check asserts this way to ensure ordering based on app certificate. assertThat(result.get(APP_CERTIFICATE_INDEXED).get(0)).isEqualTo(certificateRule1); assertThat(result.get(APP_CERTIFICATE_INDEXED).get(1)).isEqualTo(certificateRule2); assertThat(result.get(APP_CERTIFICATE_INDEXED).get(2)).isEqualTo(certificateRule3); assertThat(result.get(NOT_INDEXED)) assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()).containsExactly("cert1", "cert2", "cert3"); keySetIterator = result.get(APP_CERTIFICATE_INDEXED).keySet().iterator(); assertThat(keySetIterator.next()).isEqualTo("cert1"); assertThat(keySetIterator.next()).isEqualTo("cert2"); assertThat(keySetIterator.next()).isEqualTo("cert3"); assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert1")).containsExactly( certificateRule1); assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert2")).containsExactly( certificateRule2); assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert3")).containsExactly( certificateRule3); assertThat(result.get(NOT_INDEXED).get("N/A")) .containsExactly( RULE_WITH_INSTALLER_RESTRICTIONS, RULE_WITH_NONSTRING_RESTRICTIONS); Loading Loading
services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +48 −15 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.integrity.CompoundFormula; import android.content.integrity.Formula; import android.content.integrity.Rule; import com.android.internal.util.Preconditions; import com.android.server.integrity.IntegrityUtils; import com.android.server.integrity.model.BitOutputStream; Loading @@ -46,10 +47,17 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; /** A helper class to serialize rules from the {@link Rule} model to Binary representation. */ public class RuleBinarySerializer implements RuleSerializer { // The parsing time seems acceptable for 100 rules based on the tests in go/ic-rule-file-format. private static final int INDEXING_BLOCK_SIZE = 100; private static final String START_INDEXING_KEY = "START_KEY"; private static final String END_INDEXING_KEY = "END_KEY"; // Get the byte representation for a list of rules. @Override public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion) Loading @@ -66,25 +74,34 @@ public class RuleBinarySerializer implements RuleSerializer { // Get the byte representation for a list of rules, and write them to an output stream. @Override public void serialize( List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream) List<Rule> rules, Optional<Integer> formatVersion, OutputStream originalOutputStream) throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. Map<Integer, List<Rule>> indexedRules = Map<Integer, TreeMap<String, List<Rule>>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); ByteTrackedOutputStream outputStream = new ByteTrackedOutputStream(originalOutputStream); serializeRuleFileMetadata(formatVersion, outputStream); serializeIndexedRules(indexedRules.get(PACKAGE_NAME_INDEXED), outputStream); serializeIndexedRules(indexedRules.get(APP_CERTIFICATE_INDEXED), outputStream); serializeIndexedRules(indexedRules.get(NOT_INDEXED), outputStream); Map<String, Long> packageNameIndexes = serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), outputStream); Map<String, Long> appCertificateIndexes = serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), outputStream); Map<String, Long> unindexedRulesIndex = serializeRuleList(indexedRules.get(NOT_INDEXED), outputStream); // TODO(b/145493956): Write these indexes into a index file provided by integrity file // manager. } catch (Exception e) { throw new RuleSerializeException(e.getMessage(), e); } } private void serializeRuleFileMetadata( Optional<Integer> formatVersion, OutputStream outputStream) throws IOException { private void serializeRuleFileMetadata(Optional<Integer> formatVersion, ByteTrackedOutputStream outputStream) throws IOException { int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION); BitOutputStream bitOutputStream = new BitOutputStream(); Loading @@ -92,18 +109,34 @@ public class RuleBinarySerializer implements RuleSerializer { outputStream.write(bitOutputStream.toByteArray()); } private void serializeIndexedRules(List<Rule> rules, OutputStream outputStream) private Map<String, Long> serializeRuleList(TreeMap<String, List<Rule>> rulesMap, ByteTrackedOutputStream outputStream) throws IOException { if (rules == null) { return; } Preconditions.checkArgument(rulesMap != null, "serializeRuleList should never be called with null rule list."); BitOutputStream bitOutputStream = new BitOutputStream(); for (Rule rule : rules) { Map<String, Long> indexMapping = new TreeMap(); long indexTracker = 0; indexMapping.put(START_INDEXING_KEY, outputStream.getWrittenBytesCount()); for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) { if (indexTracker >= INDEXING_BLOCK_SIZE) { indexMapping.put(entry.getKey(), outputStream.getWrittenBytesCount()); indexTracker = 0; } for (Rule rule : entry.getValue()) { bitOutputStream.clear(); serializeRule(rule, bitOutputStream); outputStream.write(bitOutputStream.toByteArray()); indexTracker++; } } indexMapping.put(END_INDEXING_KEY, outputStream.getWrittenBytesCount()); return indexMapping; } private void serializeRule(Rule rule, BitOutputStream bitOutputStream) { if (rule == null) { Loading
services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java +8 −24 Original line number Diff line number Diff line Loading @@ -38,23 +38,19 @@ class RuleIndexingDetailsIdentifier { private static final String DEFAULT_RULE_KEY = "N/A"; /** * Splits a given rule list into three indexing categories and returns a sorted list of rules * per each index. * * The sorting guarantees an order based on the key but the rules that have the same key * can be in arbitrary order. For example, given the rules of [package_name_a_rule_1, * package_name_a_rule_2, package_name_b_rule_3, package_name_b_rule_4], the method will * guarantee that package_name_b rules (i.e., 3 and 4) will never come before package_name_a * rules (i.e., 1 and 2). However, we do not care about the ordering between rule 1 and 2. * We also do not care about the ordering between rule 3 and 4. * Splits a given rule list into three indexing categories. Each rule category is returned as a * TreeMap that is sorted by their indexing keys -- where keys correspond to package name for * PACKAGE_NAME_INDEXED rules, app certificate for APP_CERTIFICATE_INDEXED rules and N/A for * NOT_INDEXED rules. */ public static Map<Integer, List<Rule>> splitRulesIntoIndexBuckets(List<Rule> rules) { public static Map<Integer, TreeMap<String, List<Rule>>> splitRulesIntoIndexBuckets( List<Rule> rules) { if (rules == null) { throw new IllegalArgumentException( "Index buckets cannot be created for null rule list."); } Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); Map<Integer, TreeMap<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); typeOrganizedRuleMap.put(NOT_INDEXED, new TreeMap()); typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new TreeMap()); typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new TreeMap()); Loading Loading @@ -87,19 +83,7 @@ class RuleIndexingDetailsIdentifier { .add(rule); } // Per indexing type, create the sorted rule set based on their key. Map<Integer, List<Rule>> orderedListPerIndexingType = new HashMap<>(); for (Integer indexingKey : typeOrganizedRuleMap.keySet()) { List<Rule> sortedRules = new ArrayList(); for (Map.Entry<String, List<Rule>> entry : typeOrganizedRuleMap.get(indexingKey).entrySet()) { sortedRules.addAll(entry.getValue()); } orderedListPerIndexingType.put(indexingKey, sortedRules); } return orderedListPerIndexingType; return typeOrganizedRuleMap; } private static RuleIndexingDetails getIndexingDetails(Formula formula) { Loading
services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +8 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */ public class RuleXmlSerializer implements RuleSerializer { Loading Loading @@ -84,7 +85,7 @@ public class RuleXmlSerializer implements RuleSerializer { throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. Map<Integer, List<Rule>> indexedRules = Map<Integer, TreeMap<String, List<Rule>>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); // Write the XML formatted rules in order. Loading @@ -101,12 +102,15 @@ public class RuleXmlSerializer implements RuleSerializer { } } private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer) private void serializeRuleList(TreeMap<String, List<Rule>> rulesMap, XmlSerializer xmlSerializer) throws IOException { for (Rule rule : rules) { for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) { for (Rule rule : entry.getValue()) { serializeRule(rule, xmlSerializer); } } } private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException { if (rule == null) { Loading
services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java +42 −19 Original line number Diff line number Diff line Loading @@ -38,8 +38,10 @@ import org.junit.runners.JUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; /** Unit tests for {@link RuleIndexingDetailsIdentifier}. */ @RunWith(JUnit4.class) Loading Loading @@ -138,14 +140,16 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_PACKAGE_NAME); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); // Verify the resulting map content. assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(NOT_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(PACKAGE_NAME_INDEXED)).containsExactly(RULE_WITH_PACKAGE_NAME); assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly(SAMPLE_PACKAGE_NAME); assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME)) .containsExactly(RULE_WITH_PACKAGE_NAME); } @Test Loading @@ -153,13 +157,16 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_APP_CERTIFICATE); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(NOT_INDEXED)).isEmpty(); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).containsExactly(RULE_WITH_APP_CERTIFICATE); assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()) .containsExactly(SAMPLE_APP_CERTIFICATE); assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE)) .containsExactly(RULE_WITH_APP_CERTIFICATE); } @Test Loading @@ -167,13 +174,14 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS); assertThat(result.get(NOT_INDEXED).get("N/A")) .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS); } @Test Loading @@ -181,13 +189,14 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS); assertThat(result.get(NOT_INDEXED).get("N/A")) .containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS); } @Test Loading @@ -206,13 +215,13 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(negatedRule); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); assertThat(result.get(NOT_INDEXED)).containsExactly(negatedRule); assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(negatedRule); } @Test Loading @@ -234,22 +243,36 @@ public class RuleIndexingDetailsIdentifierTest { ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList); Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); // We check asserts this way to ensure ordering based on package name. assertThat(result.get(PACKAGE_NAME_INDEXED).get(0)).isEqualTo(packageNameRuleA); assertThat(result.get(PACKAGE_NAME_INDEXED).get(1)).isEqualTo(packageNameRuleB); assertThat(result.get(PACKAGE_NAME_INDEXED).get(2)).isEqualTo(packageNameRuleC); assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly("aaa", "bbb", "ccc"); Iterator<String> keySetIterator = result.get(PACKAGE_NAME_INDEXED).keySet().iterator(); assertThat(keySetIterator.next()).isEqualTo("aaa"); assertThat(keySetIterator.next()).isEqualTo("bbb"); assertThat(keySetIterator.next()).isEqualTo("ccc"); assertThat(result.get(PACKAGE_NAME_INDEXED).get("aaa")).containsExactly(packageNameRuleA); assertThat(result.get(PACKAGE_NAME_INDEXED).get("bbb")).containsExactly(packageNameRuleB); assertThat(result.get(PACKAGE_NAME_INDEXED).get("ccc")).containsExactly(packageNameRuleC); // We check asserts this way to ensure ordering based on app certificate. assertThat(result.get(APP_CERTIFICATE_INDEXED).get(0)).isEqualTo(certificateRule1); assertThat(result.get(APP_CERTIFICATE_INDEXED).get(1)).isEqualTo(certificateRule2); assertThat(result.get(APP_CERTIFICATE_INDEXED).get(2)).isEqualTo(certificateRule3); assertThat(result.get(NOT_INDEXED)) assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()).containsExactly("cert1", "cert2", "cert3"); keySetIterator = result.get(APP_CERTIFICATE_INDEXED).keySet().iterator(); assertThat(keySetIterator.next()).isEqualTo("cert1"); assertThat(keySetIterator.next()).isEqualTo("cert2"); assertThat(keySetIterator.next()).isEqualTo("cert3"); assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert1")).containsExactly( certificateRule1); assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert2")).containsExactly( certificateRule2); assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert3")).containsExactly( certificateRule3); assertThat(result.get(NOT_INDEXED).get("N/A")) .containsExactly( RULE_WITH_INSTALLER_RESTRICTIONS, RULE_WITH_NONSTRING_RESTRICTIONS); Loading