Merge "Modify the RuleBinaryParser to only parse the ranges that are within the index ranges."
This commit is contained in:
committed by
Android (Google) Code Review
commit
3ac0f19a6a
@@ -39,6 +39,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -153,14 +154,19 @@ public class IntegrityFileManager {
|
||||
throws IOException, RuleParseException {
|
||||
synchronized (RULES_LOCK) {
|
||||
// Try to identify indexes from the index file.
|
||||
List<RuleIndexRange> ruleReadingIndexes =
|
||||
mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
|
||||
List<RuleIndexRange> ruleReadingIndexes;
|
||||
try {
|
||||
ruleReadingIndexes =
|
||||
mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Error identifying the rule indexes. Trying unindexed.", e);
|
||||
ruleReadingIndexes = Collections.emptyList();
|
||||
}
|
||||
|
||||
// Read the rules based on the index information.
|
||||
// TODO(b/145493956): Provide the identified indexes to the rule reader.
|
||||
// Read the rules based on the index information when available.
|
||||
try (FileInputStream inputStream =
|
||||
new FileInputStream(new File(mRulesDir, RULES_FILE))) {
|
||||
List<Rule> rules = mRuleParser.parse(inputStream);
|
||||
List<Rule> rules = mRuleParser.parse(inputStream, ruleReadingIndexes);
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.server.integrity.model.BitTrackedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** A helper class to parse rules into the {@link Rule} model from Binary representation. */
|
||||
@@ -51,28 +52,40 @@ public class RuleBinaryParser implements RuleParser {
|
||||
public List<Rule> parse(byte[] ruleBytes) throws RuleParseException {
|
||||
try {
|
||||
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(ruleBytes);
|
||||
return parseRules(bitTrackedInputStream);
|
||||
return parseRules(bitTrackedInputStream, /* indexRanges= */ Collections.emptyList());
|
||||
} catch (Exception e) {
|
||||
throw new RuleParseException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Rule> parse(InputStream inputStream) throws RuleParseException {
|
||||
public List<Rule> parse(InputStream inputStream, List<RuleIndexRange> indexRanges)
|
||||
throws RuleParseException {
|
||||
try {
|
||||
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(inputStream);
|
||||
return parseRules(bitTrackedInputStream);
|
||||
return parseRules(bitTrackedInputStream, indexRanges);
|
||||
} catch (Exception e) {
|
||||
throw new RuleParseException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Rule> parseRules(BitTrackedInputStream bitTrackedInputStream) throws IOException {
|
||||
List<Rule> parsedRules = new ArrayList<>();
|
||||
private List<Rule> parseRules(
|
||||
BitTrackedInputStream bitTrackedInputStream,
|
||||
List<RuleIndexRange> indexRanges)
|
||||
throws IOException {
|
||||
|
||||
// Read the rule binary file format version.
|
||||
bitTrackedInputStream.getNext(FORMAT_VERSION_BITS);
|
||||
|
||||
return indexRanges.isEmpty()
|
||||
? parseAllRules(bitTrackedInputStream)
|
||||
: parseIndexedRules(bitTrackedInputStream, indexRanges);
|
||||
}
|
||||
|
||||
private List<Rule> parseAllRules(BitTrackedInputStream bitTrackedInputStream)
|
||||
throws IOException {
|
||||
List<Rule> parsedRules = new ArrayList<>();
|
||||
|
||||
while (bitTrackedInputStream.hasNext()) {
|
||||
if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) {
|
||||
parsedRules.add(parseRule(bitTrackedInputStream));
|
||||
@@ -82,6 +95,27 @@ public class RuleBinaryParser implements RuleParser {
|
||||
return parsedRules;
|
||||
}
|
||||
|
||||
private List<Rule> parseIndexedRules(
|
||||
BitTrackedInputStream bitTrackedInputStream, List<RuleIndexRange> indexRanges)
|
||||
throws IOException {
|
||||
List<Rule> parsedRules = new ArrayList<>();
|
||||
|
||||
for (RuleIndexRange range : indexRanges) {
|
||||
// Skip the rules that are not in the range.
|
||||
bitTrackedInputStream.setCursorToByteLocation(range.getStartIndex());
|
||||
|
||||
// Read the rules until we reach the end index.
|
||||
while (bitTrackedInputStream.hasNext()
|
||||
&& bitTrackedInputStream.getReadBitsCount() < range.getEndIndex()) {
|
||||
if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) {
|
||||
parsedRules.add(parseRule(bitTrackedInputStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parsedRules;
|
||||
}
|
||||
|
||||
private Rule parseRule(BitTrackedInputStream bitTrackedInputStream) throws IOException {
|
||||
Formula formula = parseFormula(bitTrackedInputStream);
|
||||
int effect = bitTrackedInputStream.getNext(EFFECT_BITS);
|
||||
|
||||
@@ -28,5 +28,6 @@ public interface RuleParser {
|
||||
List<Rule> parse(byte[] ruleBytes) throws RuleParseException;
|
||||
|
||||
/** Parse rules from an input stream. */
|
||||
List<Rule> parse(InputStream inputStream) throws RuleParseException;
|
||||
List<Rule> parse(InputStream inputStream, List<RuleIndexRange> ruleIndexRanges)
|
||||
throws RuleParseException;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ public final class RuleXmlParser implements RuleParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Rule> parse(InputStream inputStream) throws RuleParseException {
|
||||
public List<Rule> parse(InputStream inputStream, List<RuleIndexRange> indexRanges)
|
||||
throws RuleParseException {
|
||||
try {
|
||||
XmlPullParser xmlPullParser = Xml.newPullParser();
|
||||
xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
|
||||
|
||||
@@ -48,6 +48,7 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -97,8 +98,10 @@ public class RuleBinaryParserTest {
|
||||
private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
|
||||
getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
|
||||
|
||||
private static final List<RuleIndexRange> NO_INDEXING = Collections.emptyList();
|
||||
|
||||
@Test
|
||||
public void testBinaryStream_validCompoundFormula() throws Exception {
|
||||
public void testBinaryStream_validCompoundFormula_noIndexing() throws Exception {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -131,13 +134,13 @@ public class RuleBinaryParserTest {
|
||||
/* isHashedValue= */ false))),
|
||||
Rule.DENY);
|
||||
|
||||
List<Rule> rules = binaryParser.parse(inputStream);
|
||||
List<Rule> rules = binaryParser.parse(inputStream, NO_INDEXING);
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validCompoundFormula_notConnector() throws Exception {
|
||||
public void testBinaryString_validCompoundFormula_notConnector_noIndexing() throws Exception {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -175,7 +178,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validCompoundFormula_andConnector() throws Exception {
|
||||
public void testBinaryString_validCompoundFormula_andConnector_noIndexing() throws Exception {
|
||||
String packageName = "com.test.app";
|
||||
String appCertificate = "test_cert";
|
||||
String ruleBits =
|
||||
@@ -223,7 +226,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validCompoundFormula_orConnector() throws Exception {
|
||||
public void testBinaryString_validCompoundFormula_orConnector_noIndexing() throws Exception {
|
||||
String packageName = "com.test.app";
|
||||
String appCertificate = "test_cert";
|
||||
String ruleBits =
|
||||
@@ -272,7 +275,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validAtomicFormula_stringValue() throws Exception {
|
||||
public void testBinaryString_validAtomicFormula_stringValue_noIndexing() throws Exception {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -304,7 +307,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validAtomicFormula_hashedValue() throws Exception {
|
||||
public void testBinaryString_validAtomicFormula_hashedValue_noIndexing() throws Exception {
|
||||
String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -337,7 +340,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validAtomicFormula_integerValue() throws Exception {
|
||||
public void testBinaryString_validAtomicFormula_integerValue_noIndexing() throws Exception {
|
||||
int versionCode = 1;
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -365,7 +368,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_validAtomicFormula_booleanValue() throws Exception {
|
||||
public void testBinaryString_validAtomicFormula_booleanValue_noIndexing() throws Exception {
|
||||
String isPreInstalled = "1";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -392,7 +395,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidAtomicFormula() throws Exception {
|
||||
public void testBinaryString_invalidAtomicFormula_noIndexing() {
|
||||
int versionCode = 1;
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -415,7 +418,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_withNoRuleList() throws RuleParseException {
|
||||
public void testBinaryString_withNoRuleList_noIndexing() throws RuleParseException {
|
||||
ByteBuffer rule = ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length);
|
||||
rule.put(DEFAULT_FORMAT_VERSION_BYTES);
|
||||
RuleParser binaryParser = new RuleBinaryParser();
|
||||
@@ -426,7 +429,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_withEmptyRule() throws RuleParseException {
|
||||
public void testBinaryString_withEmptyRule_noIndexing() {
|
||||
String ruleBits = START_BIT;
|
||||
byte[] ruleBytes = getBytes(ruleBits);
|
||||
ByteBuffer rule =
|
||||
@@ -442,7 +445,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas() throws Exception {
|
||||
public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas_noIndexing() {
|
||||
String packageName = "com.test.app";
|
||||
String appCertificate = "test_cert";
|
||||
String ruleBits =
|
||||
@@ -478,7 +481,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidRule_invalidOperator() throws Exception {
|
||||
public void testBinaryString_invalidRule_invalidOperator_noIndexing() {
|
||||
int versionCode = 1;
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -506,7 +509,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidRule_invalidEffect() throws Exception {
|
||||
public void testBinaryString_invalidRule_invalidEffect_noIndexing() {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -536,7 +539,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidRule_invalidConnector() throws Exception {
|
||||
public void testBinaryString_invalidRule_invalidConnector_noIndexing() {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -566,7 +569,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidRule_invalidKey() throws Exception {
|
||||
public void testBinaryString_invalidRule_invalidKey_noIndexing() {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -596,7 +599,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidRule_invalidSeparator() throws Exception {
|
||||
public void testBinaryString_invalidRule_invalidSeparator_noIndexing() {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -626,7 +629,7 @@ public class RuleBinaryParserTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryString_invalidRule_invalidEndMarker() throws Exception {
|
||||
public void testBinaryString_invalidRule_invalidEndMarker_noIndexing() {
|
||||
String packageName = "com.test.app";
|
||||
String ruleBits =
|
||||
START_BIT
|
||||
@@ -653,4 +656,65 @@ public class RuleBinaryParserTest {
|
||||
/* expectedExceptionMessageRegex */ "A rule must end with a '1' bit",
|
||||
() -> binaryParser.parse(rule.array()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryStream_multipleRules_indexingIdentifiesParsesIndexRangeCorrectly()
|
||||
throws Exception {
|
||||
String packageName2 = "com.test.2";
|
||||
|
||||
byte[] ruleBytes1 = getBytes(getRulesWithPackageName("com.test.1"));
|
||||
byte[] ruleBytes2 = getBytes(getRulesWithPackageName(packageName2));
|
||||
byte[] ruleBytes3 = getBytes(getRulesWithPackageName("com.test.3"));
|
||||
|
||||
ByteBuffer rule =
|
||||
ByteBuffer.allocate(
|
||||
DEFAULT_FORMAT_VERSION_BYTES.length
|
||||
+ ruleBytes1.length
|
||||
+ ruleBytes2.length
|
||||
+ ruleBytes3.length);
|
||||
rule.put(DEFAULT_FORMAT_VERSION_BYTES);
|
||||
rule.put(ruleBytes1);
|
||||
rule.put(ruleBytes2);
|
||||
rule.put(ruleBytes3);
|
||||
InputStream inputStream = new ByteArrayInputStream(rule.array());
|
||||
|
||||
RuleParser binaryParser = new RuleBinaryParser();
|
||||
|
||||
List<RuleIndexRange> indexRanges = new ArrayList<>();
|
||||
indexRanges.add(
|
||||
new RuleIndexRange(
|
||||
DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes1.length,
|
||||
DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes1.length
|
||||
+ ruleBytes2.length));
|
||||
List<Rule> rules = binaryParser.parse(inputStream, indexRanges);
|
||||
|
||||
Rule expectedRule =
|
||||
new Rule(
|
||||
new CompoundFormula(
|
||||
CompoundFormula.NOT,
|
||||
Collections.singletonList(
|
||||
new AtomicFormula.StringAtomicFormula(
|
||||
AtomicFormula.PACKAGE_NAME,
|
||||
packageName2,
|
||||
/* isHashedValue= */ false))),
|
||||
Rule.DENY);
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
|
||||
private static String getRulesWithPackageName(String packageName) {
|
||||
return START_BIT
|
||||
+ COMPOUND_FORMULA_START_BITS
|
||||
+ NOT
|
||||
+ ATOMIC_FORMULA_START_BITS
|
||||
+ PACKAGE_NAME
|
||||
+ EQ
|
||||
+ IS_NOT_HASHED
|
||||
+ getBits(packageName.length(), VALUE_SIZE_BITS)
|
||||
+ getValueBits(packageName)
|
||||
+ COMPOUND_FORMULA_END_BITS
|
||||
+ DENY
|
||||
+ END_BIT;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class RuleXmlParserTest {
|
||||
/* isHashedValue= */ false))),
|
||||
Rule.DENY);
|
||||
|
||||
List<Rule> rules = xmlParser.parse(inputStream);
|
||||
List<Rule> rules = xmlParser.parse(inputStream, Collections.emptyList());
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
@@ -623,7 +623,7 @@ public class RuleXmlParserTest {
|
||||
assertExpectException(
|
||||
RuleParseException.class,
|
||||
/* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
|
||||
() -> xmlParser.parse(inputStream));
|
||||
() -> xmlParser.parse(inputStream, Collections.emptyList()));
|
||||
}
|
||||
|
||||
private String generateTagWithAttribute(
|
||||
|
||||
Reference in New Issue
Block a user