diff options
7 files changed, 934 insertions, 92 deletions
diff --git a/services/core/java/com/android/server/integrity/model/BitInputStream.java b/services/core/java/com/android/server/integrity/model/BitInputStream.java new file mode 100644 index 000000000000..09bc7e8b9861 --- /dev/null +++ b/services/core/java/com/android/server/integrity/model/BitInputStream.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.model; + +/** A wrapper class for reading a stream of bits. */ +public class BitInputStream { + + private byte[] mRuleBytes; + private long mBitPointer; + + public BitInputStream(byte[] ruleBytes) { + this.mRuleBytes = ruleBytes; + this.mBitPointer = 0; + } + + /** + * Read the next number of bits from the stream. + * + * @param numOfBits The number of bits to read. + * @return The value read from the stream. + */ + public int getNext(int numOfBits) { + int component = 0; + int count = 0; + + int idx = (int) (mBitPointer / 8); + int offset = 7 - (int) (mBitPointer % 8); + + while (count++ < numOfBits) { + if (idx >= mRuleBytes.length) { + throw new IllegalArgumentException(String.format("Invalid byte index: %d", idx)); + } + + component <<= 1; + component |= (mRuleBytes[idx] >>> offset) & 1; + + offset--; + if (offset == -1) { + idx++; + offset = 7; + } + } + + mBitPointer += numOfBits; + return component; + } + + /** Check if there are bits left in the stream. */ + public boolean hasNext() { + return mBitPointer / 8 < mRuleBytes.length; + } +} diff --git a/services/core/java/com/android/server/integrity/model/ComponentBitSize.java b/services/core/java/com/android/server/integrity/model/ComponentBitSize.java new file mode 100644 index 000000000000..d47ce2df45e1 --- /dev/null +++ b/services/core/java/com/android/server/integrity/model/ComponentBitSize.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.model; + +import android.content.integrity.Rule; + +/** + * A helper class containing information about the binary representation of different {@link Rule} + * components. + */ +public final class ComponentBitSize { + public static final int FORMAT_VERSION_BITS = 5; + public static final int EFFECT_BITS = 3; + public static final int KEY_BITS = 4; + public static final int OPERATOR_BITS = 3; + public static final int CONNECTOR_BITS = 2; + public static final int SEPARATOR_BITS = 2; + public static final int VALUE_SIZE_BITS = 5; + public static final int IS_HASHED_BITS = 1; + + public static final int ATOMIC_FORMULA_START = 0; + public static final int COMPOUND_FORMULA_START = 1; + public static final int COMPOUND_FORMULA_END = 2; + + public static final int DEFAULT_FORMAT_VERSION = 1; + public static final int SIGNAL_BIT = 1; +} diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java index 54c0bd85d897..8aa0751af11c 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -16,23 +16,132 @@ package com.android.server.integrity.parser; +import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS; +import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS; +import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS; +import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS; +import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.SIGNAL_BIT; +import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; + +import android.content.integrity.AtomicFormula; +import android.content.integrity.CompoundFormula; +import android.content.integrity.Formula; import android.content.integrity.Rule; +import com.android.server.integrity.model.BitInputStream; + import java.io.InputStream; +import java.util.ArrayList; import java.util.List; /** A helper class to parse rules into the {@link Rule} model from Binary representation. */ public class RuleBinaryParser implements RuleParser { @Override - public List<Rule> parse(byte[] ruleBytes) throws RuleParseException { - // TODO: Implement binary text parser. - return null; + public List<Rule> parse(byte[] ruleBytes) throws RuleParseException { + try { + BitInputStream bitInputStream = new BitInputStream(ruleBytes); + return parseRules(bitInputStream); + } catch (Exception e) { + throw new RuleParseException(e.getMessage(), e); + } } @Override public List<Rule> parse(InputStream inputStream) throws RuleParseException { - // TODO: Implement stream parser. - return null; + try { + byte[] ruleBytes = new byte[inputStream.available()]; + inputStream.read(ruleBytes); + return parse(ruleBytes); + } catch (Exception e) { + throw new RuleParseException(e.getMessage(), e); + } + } + + private List<Rule> parseRules(BitInputStream bitInputStream) { + List<Rule> parsedRules = new ArrayList<>(); + + // Read the rule binary file format version. + bitInputStream.getNext(FORMAT_VERSION_BITS); + + while (bitInputStream.hasNext()) { + if (bitInputStream.getNext(SIGNAL_BIT) == 1) { + parsedRules.add(parseRule(bitInputStream)); + } + } + + return parsedRules; + } + + private Rule parseRule(BitInputStream bitInputStream) { + Formula formula = parseFormula(bitInputStream); + int effect = bitInputStream.getNext(EFFECT_BITS); + + if (bitInputStream.getNext(SIGNAL_BIT) != 1) { + throw new IllegalArgumentException("A rule must end with a '1' bit."); + } + + return new Rule(formula, effect); + } + + private Formula parseFormula(BitInputStream bitInputStream) { + int separator = bitInputStream.getNext(SEPARATOR_BITS); + switch (separator) { + case ATOMIC_FORMULA_START: + return parseAtomicFormula(bitInputStream); + case COMPOUND_FORMULA_START: + return parseCompoundFormula(bitInputStream); + case COMPOUND_FORMULA_END: + return null; + default: + throw new IllegalArgumentException( + String.format("Unknown formula separator: %s", separator)); + } + } + + private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) { + int connector = bitInputStream.getNext(CONNECTOR_BITS); + List<Formula> formulas = new ArrayList<>(); + + Formula parsedFormula = parseFormula(bitInputStream); + while (parsedFormula != null) { + formulas.add(parsedFormula); + parsedFormula = parseFormula(bitInputStream); + } + + return new CompoundFormula(connector, formulas); + } + + private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) { + int key = bitInputStream.getNext(KEY_BITS); + int operator = bitInputStream.getNext(OPERATOR_BITS); + + boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1; + int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS); + StringBuilder value = new StringBuilder(); + while (valueSize-- > 0) { + value.append((char) bitInputStream.getNext(/* numOfBits= */ 8)); + } + + switch (key) { + case AtomicFormula.PACKAGE_NAME: + case AtomicFormula.APP_CERTIFICATE: + case AtomicFormula.INSTALLER_NAME: + case AtomicFormula.INSTALLER_CERTIFICATE: + return new AtomicFormula.StringAtomicFormula(key, value.toString(), isHashedValue); + case AtomicFormula.VERSION_CODE: + return new AtomicFormula.IntAtomicFormula( + key, operator, Integer.parseInt(value.toString())); + case AtomicFormula.PRE_INSTALLED: + return new AtomicFormula.BooleanAtomicFormula(key, value.toString().equals("1")); + default: + throw new IllegalArgumentException(String.format("Unknown key: %d", key)); + } } } diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java index 2e99d0f92109..d405583442bd 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java @@ -41,7 +41,7 @@ public final class RuleXmlParser implements RuleParser { private static final String NAMESPACE = ""; private static final String RULE_LIST_TAG = "RL"; private static final String RULE_TAG = "R"; - private static final String OPEN_FORMULA_TAG = "OF"; + private static final String COMPOUND_FORMULA_TAG = "OF"; private static final String ATOMIC_FORMULA_TAG = "AF"; private static final String EFFECT_ATTRIBUTE = "E"; private static final String KEY_ATTRIBUTE = "K"; @@ -118,8 +118,8 @@ public final class RuleXmlParser implements RuleParser { if (eventType == XmlPullParser.START_TAG) { switch (nodeName) { - case OPEN_FORMULA_TAG: - formula = parseOpenFormula(parser); + case COMPOUND_FORMULA_TAG: + formula = parseCompoundFormula(parser); break; case ATOMIC_FORMULA_TAG: formula = parseAtomicFormula(parser); @@ -137,7 +137,7 @@ public final class RuleXmlParser implements RuleParser { return new Rule(formula, effect); } - private static Formula parseOpenFormula(XmlPullParser parser) + private static Formula parseCompoundFormula(XmlPullParser parser) throws IOException, XmlPullParserException { int connector = Integer.parseInt(extractAttributeValue(parser, CONNECTOR_ATTRIBUTE).orElse("-1")); @@ -147,7 +147,8 @@ public final class RuleXmlParser implements RuleParser { while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { String nodeName = parser.getName(); - if (eventType == XmlPullParser.END_TAG && parser.getName().equals(OPEN_FORMULA_TAG)) { + if (eventType == XmlPullParser.END_TAG + && parser.getName().equals(COMPOUND_FORMULA_TAG)) { break; } @@ -156,8 +157,8 @@ public final class RuleXmlParser implements RuleParser { case ATOMIC_FORMULA_TAG: formulas.add(parseAtomicFormula(parser)); break; - case OPEN_FORMULA_TAG: - formulas.add(parseOpenFormula(parser)); + case COMPOUND_FORMULA_TAG: + formulas.add(parseCompoundFormula(parser)); break; default: throw new RuntimeException( 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 f782f7173da2..b988fd4c40f1 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -16,6 +16,18 @@ package com.android.server.integrity.serializer; +import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION; +import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS; +import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS; +import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS; +import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; + import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Formula; @@ -32,20 +44,6 @@ import java.util.Optional; /** A helper class to serialize rules from the {@link Rule} model to Binary representation. */ public class RuleBinarySerializer implements RuleSerializer { - public static final int FORMAT_VERSION_BITS = 5; - public static final int EFFECT_BITS = 3; - public static final int KEY_BITS = 4; - public static final int OPERATOR_BITS = 3; - public static final int CONNECTOR_BITS = 2; - public static final int SEPARATOR_BITS = 2; - public static final int VALUE_SIZE_BITS = 5; - - public static final int ATOMIC_FORMULA_START = 0; - public static final int COMPOUND_FORMULA_START = 1; - public static final int COMPOUND_FORMULA_END = 2; - - public static final int DEFAULT_FORMAT_VERSION = 1; - // Get the byte representation for a list of rules, and write them to an output stream. @Override public void serialize( diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java new file mode 100644 index 000000000000..88b6d70688ad --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java @@ -0,0 +1,628 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.parser; + +import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION; +import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS; +import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS; +import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS; +import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; +import static com.android.server.integrity.utils.TestUtils.getBits; +import static com.android.server.integrity.utils.TestUtils.getBytes; +import static com.android.server.integrity.utils.TestUtils.getValueBits; +import static com.android.server.testutils.TestUtils.assertExpectException; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.integrity.AtomicFormula; +import android.content.integrity.CompoundFormula; +import android.content.integrity.Rule; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@RunWith(JUnit4.class) +public class RuleBinaryParserTest { + + private static final String COMPOUND_FORMULA_START_BITS = + getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS); + private static final String COMPOUND_FORMULA_END_BITS = + getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS); + private static final String ATOMIC_FORMULA_START_BITS = + getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS); + private static final int INVALID_FORMULA_SEPARATOR_VALUE = 3; + private static final String INVALID_FORMULA_SEPARATOR_BITS = + getBits(INVALID_FORMULA_SEPARATOR_VALUE, SEPARATOR_BITS); + + private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS); + private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS); + private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS); + private static final int INVALID_CONNECTOR_VALUE = 3; + private static final String INVALID_CONNECTOR = + getBits(INVALID_CONNECTOR_VALUE, CONNECTOR_BITS); + + private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS); + private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS); + private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS); + private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS); + private static final int INVALID_KEY_VALUE = 6; + private static final String INVALID_KEY = getBits(INVALID_KEY_VALUE, KEY_BITS); + + private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS); + private static final int INVALID_OPERATOR_VALUE = 5; + private static final String INVALID_OPERATOR = getBits(INVALID_OPERATOR_VALUE, OPERATOR_BITS); + + private static final String IS_NOT_HASHED = "0"; + + private static final String DENY = getBits(Rule.DENY, EFFECT_BITS); + private static final int INVALID_EFFECT_VALUE = 5; + private static final String INVALID_EFFECT = getBits(INVALID_EFFECT_VALUE, EFFECT_BITS); + + private static final String START_BIT = "1"; + private static final String END_BIT = "1"; + private static final String INVALID_MARKER_BIT = "0"; + + private static final byte[] DEFAULT_FORMAT_VERSION_BYTES = + getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS)); + + @Test + public void testBinaryStream_validCompoundFormula() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + 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; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + InputStream inputStream = new ByteArrayInputStream(rule.array()); + Rule expectedRule = + new Rule( + new CompoundFormula( + CompoundFormula.NOT, + Collections.singletonList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false))), + Rule.DENY); + + List<Rule> rules = binaryParser.parse(inputStream); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_validCompoundFormula_notConnector() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + 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; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + Rule expectedRule = + new Rule( + new CompoundFormula( + CompoundFormula.NOT, + Collections.singletonList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false))), + Rule.DENY); + + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_validCompoundFormula_andConnector() throws Exception { + String packageName = "com.test.app"; + String appCertificate = "test_cert"; + String ruleBits = + START_BIT + + COMPOUND_FORMULA_START_BITS + + AND + + ATOMIC_FORMULA_START_BITS + + PACKAGE_NAME + + EQ + + IS_NOT_HASHED + + getBits(packageName.length(), VALUE_SIZE_BITS) + + getValueBits(packageName) + + ATOMIC_FORMULA_START_BITS + + APP_CERTIFICATE + + EQ + + IS_NOT_HASHED + + getBits(appCertificate.length(), VALUE_SIZE_BITS) + + getValueBits(appCertificate) + + COMPOUND_FORMULA_END_BITS + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + Rule expectedRule = + new Rule( + new CompoundFormula( + CompoundFormula.AND, + Arrays.asList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false), + new AtomicFormula.StringAtomicFormula( + AtomicFormula.APP_CERTIFICATE, + appCertificate, + /* isHashedValue= */ false))), + Rule.DENY); + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_validCompoundFormula_orConnector() throws Exception { + String packageName = "com.test.app"; + String appCertificate = "test_cert"; + String ruleBits = + START_BIT + + COMPOUND_FORMULA_START_BITS + + OR + + ATOMIC_FORMULA_START_BITS + + PACKAGE_NAME + + EQ + + IS_NOT_HASHED + + getBits(packageName.length(), VALUE_SIZE_BITS) + + getValueBits(packageName) + + ATOMIC_FORMULA_START_BITS + + APP_CERTIFICATE + + EQ + + IS_NOT_HASHED + + getBits(appCertificate.length(), VALUE_SIZE_BITS) + + getValueBits(appCertificate) + + COMPOUND_FORMULA_END_BITS + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + Rule expectedRule = + new Rule( + new CompoundFormula( + CompoundFormula.OR, + Arrays.asList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false), + new AtomicFormula.StringAtomicFormula( + AtomicFormula.APP_CERTIFICATE, + appCertificate, + /* isHashedValue= */ false))), + Rule.DENY); + + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_validAtomicFormula_stringValue() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + START_BIT + + ATOMIC_FORMULA_START_BITS + + PACKAGE_NAME + + EQ + + IS_NOT_HASHED + + getBits(packageName.length(), VALUE_SIZE_BITS) + + getValueBits(packageName) + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + Rule expectedRule = + new Rule( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false), + Rule.DENY); + + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_validAtomicFormula_integerValue() throws Exception { + String versionCode = "1"; + String ruleBits = + START_BIT + + ATOMIC_FORMULA_START_BITS + + VERSION_CODE + + EQ + + IS_NOT_HASHED + + getBits(versionCode.length(), VALUE_SIZE_BITS) + + getValueBits(versionCode) + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + Rule expectedRule = + new Rule( + new AtomicFormula.IntAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), + Rule.DENY); + + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_validAtomicFormula_booleanValue() throws Exception { + String isPreInstalled = "1"; + String ruleBits = + START_BIT + + ATOMIC_FORMULA_START_BITS + + PRE_INSTALLED + + EQ + + IS_NOT_HASHED + + getBits(isPreInstalled.length(), VALUE_SIZE_BITS) + + getValueBits(isPreInstalled) + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + Rule expectedRule = + new Rule( + new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + Rule.DENY); + + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEqualTo(Collections.singletonList(expectedRule)); + } + + @Test + public void testBinaryString_invalidAtomicFormula() throws Exception { + String versionCode = "test"; + String ruleBits = + START_BIT + + ATOMIC_FORMULA_START_BITS + + VERSION_CODE + + EQ + + IS_NOT_HASHED + + getBits(versionCode.length(), VALUE_SIZE_BITS) + + getValueBits(versionCode) + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ "For input string:", + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_withNoRuleList() throws RuleParseException { + ByteBuffer rule = ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + RuleParser binaryParser = new RuleBinaryParser(); + + List<Rule> rules = binaryParser.parse(rule.array()); + + assertThat(rules).isEmpty(); + } + + @Test + public void testBinaryString_withEmptyRule() throws RuleParseException { + String ruleBits = START_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ "Invalid byte index", + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas() throws Exception { + String packageName = "com.test.app"; + String appCertificate = "test_cert"; + String ruleBits = + 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) + + ATOMIC_FORMULA_START_BITS + + APP_CERTIFICATE + + EQ + + IS_NOT_HASHED + + getBits(appCertificate.length(), VALUE_SIZE_BITS) + + getValueBits(appCertificate) + + COMPOUND_FORMULA_END_BITS + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only", + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidRule_invalidOperator() throws Exception { + String versionCode = "1"; + String ruleBits = + START_BIT + + COMPOUND_FORMULA_START_BITS + + NOT + + ATOMIC_FORMULA_START_BITS + + VERSION_CODE + + INVALID_OPERATOR + + IS_NOT_HASHED + + getBits(versionCode.length(), VALUE_SIZE_BITS) + + getValueBits(versionCode) + + COMPOUND_FORMULA_END_BITS + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ String.format( + "Unknown operator: %d", INVALID_OPERATOR_VALUE), + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidRule_invalidEffect() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + 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 + + INVALID_EFFECT + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ String.format( + "Unknown effect: %d", INVALID_EFFECT_VALUE), + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidRule_invalidConnector() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + START_BIT + + COMPOUND_FORMULA_START_BITS + + INVALID_CONNECTOR + + 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; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ String.format( + "Unknown connector: %d", INVALID_CONNECTOR_VALUE), + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidRule_invalidKey() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + START_BIT + + COMPOUND_FORMULA_START_BITS + + NOT + + ATOMIC_FORMULA_START_BITS + + INVALID_KEY + + EQ + + IS_NOT_HASHED + + getBits(packageName.length(), VALUE_SIZE_BITS) + + getValueBits(packageName) + + COMPOUND_FORMULA_END_BITS + + DENY + + END_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ String.format( + "Unknown key: %d", INVALID_KEY_VALUE), + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidRule_invalidSeparator() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + START_BIT + + INVALID_FORMULA_SEPARATOR_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; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ String.format( + "Unknown formula separator: %d", INVALID_FORMULA_SEPARATOR_VALUE), + () -> binaryParser.parse(rule.array())); + } + + @Test + public void testBinaryString_invalidRule_invalidEndMarker() throws Exception { + String packageName = "com.test.app"; + String ruleBits = + 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 + + INVALID_MARKER_BIT; + byte[] ruleBytes = getBytes(ruleBits); + ByteBuffer rule = + ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length); + rule.put(DEFAULT_FORMAT_VERSION_BYTES); + rule.put(ruleBytes); + RuleParser binaryParser = new RuleBinaryParser(); + + assertExpectException( + RuleParseException.class, + /* expectedExceptionMessageRegex */ "A rule must end with a '1' bit", + () -> binaryParser.parse(rule.array())); + } +} diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java index a43dbd77031a..901277ded5dd 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java @@ -16,6 +16,17 @@ package com.android.server.integrity.serializer; +import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END; +import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START; +import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION; +import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS; +import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS; +import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS; +import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS; +import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; import static com.android.server.integrity.utils.TestUtils.getBits; import static com.android.server.integrity.utils.TestUtils.getBytes; import static com.android.server.integrity.utils.TestUtils.getValueBits; @@ -43,45 +54,33 @@ import java.util.Optional; @RunWith(JUnit4.class) public class RuleBinarySerializerTest { - private static final String COMPOUND_FORMULA_START = - getBits( - RuleBinarySerializer.COMPOUND_FORMULA_START, - RuleBinarySerializer.SEPARATOR_BITS); - private static final String COMPOUND_FORMULA_END = - getBits(RuleBinarySerializer.COMPOUND_FORMULA_END, RuleBinarySerializer.SEPARATOR_BITS); - private static final String ATOMIC_FORMULA_START = - getBits(RuleBinarySerializer.ATOMIC_FORMULA_START, RuleBinarySerializer.SEPARATOR_BITS); - - private static final String NOT = - getBits(CompoundFormula.NOT, RuleBinarySerializer.CONNECTOR_BITS); - private static final String AND = - getBits(CompoundFormula.AND, RuleBinarySerializer.CONNECTOR_BITS); - private static final String OR = - getBits(CompoundFormula.OR, RuleBinarySerializer.CONNECTOR_BITS); - - private static final String PACKAGE_NAME = - getBits(AtomicFormula.PACKAGE_NAME, RuleBinarySerializer.KEY_BITS); - private static final String APP_CERTIFICATE = - getBits(AtomicFormula.APP_CERTIFICATE, RuleBinarySerializer.KEY_BITS); - private static final String VERSION_CODE = - getBits(AtomicFormula.VERSION_CODE, RuleBinarySerializer.KEY_BITS); - private static final String PRE_INSTALLED = - getBits(AtomicFormula.PRE_INSTALLED, RuleBinarySerializer.KEY_BITS); - - private static final String EQ = getBits(AtomicFormula.EQ, RuleBinarySerializer.OPERATOR_BITS); + private static final String COMPOUND_FORMULA_START_BITS = + getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS); + private static final String COMPOUND_FORMULA_END_BITS = + getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS); + private static final String ATOMIC_FORMULA_START_BITS = + getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS); + + private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS); + private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS); + private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS); + + private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS); + private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS); + private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS); + private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS); + + private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS); private static final String IS_NOT_HASHED = "0"; - private static final String DENY = getBits(Rule.DENY, RuleBinarySerializer.EFFECT_BITS); + private static final String DENY = getBits(Rule.DENY, EFFECT_BITS); private static final String START_BIT = "1"; private static final String END_BIT = "1"; - private static final byte[] DEFAULT_FORMAT_VERSION = - getBytes( - getBits( - RuleBinarySerializer.DEFAULT_FORMAT_VERSION, - RuleBinarySerializer.FORMAT_VERSION_BITS)); + private static final byte[] DEFAULT_FORMAT_VERSION_BYTES = + getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS)); @Test public void testBinaryString_serializeEmptyRule() throws Exception { @@ -114,19 +113,19 @@ public class RuleBinarySerializerTest { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); String expectedBits = START_BIT - + COMPOUND_FORMULA_START + + COMPOUND_FORMULA_START_BITS + NOT - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + PACKAGE_NAME + EQ + IS_NOT_HASHED - + getBits(packageName.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(packageName.length(), VALUE_SIZE_BITS) + getValueBits(packageName) - + COMPOUND_FORMULA_END + + COMPOUND_FORMULA_END_BITS + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -155,19 +154,19 @@ public class RuleBinarySerializerTest { RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = START_BIT - + COMPOUND_FORMULA_START + + COMPOUND_FORMULA_START_BITS + NOT - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + PACKAGE_NAME + EQ + IS_NOT_HASHED - + getBits(packageName.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(packageName.length(), VALUE_SIZE_BITS) + getValueBits(packageName) - + COMPOUND_FORMULA_END + + COMPOUND_FORMULA_END_BITS + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -199,25 +198,25 @@ public class RuleBinarySerializerTest { RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = START_BIT - + COMPOUND_FORMULA_START + + COMPOUND_FORMULA_START_BITS + AND - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + PACKAGE_NAME + EQ + IS_NOT_HASHED - + getBits(packageName.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(packageName.length(), VALUE_SIZE_BITS) + getValueBits(packageName) - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + APP_CERTIFICATE + EQ + IS_NOT_HASHED - + getBits(appCertificate.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(appCertificate.length(), VALUE_SIZE_BITS) + getValueBits(appCertificate) - + COMPOUND_FORMULA_END + + COMPOUND_FORMULA_END_BITS + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -249,25 +248,25 @@ public class RuleBinarySerializerTest { RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = START_BIT - + COMPOUND_FORMULA_START + + COMPOUND_FORMULA_START_BITS + OR - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + PACKAGE_NAME + EQ + IS_NOT_HASHED - + getBits(packageName.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(packageName.length(), VALUE_SIZE_BITS) + getValueBits(packageName) - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + APP_CERTIFICATE + EQ + IS_NOT_HASHED - + getBits(appCertificate.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(appCertificate.length(), VALUE_SIZE_BITS) + getValueBits(appCertificate) - + COMPOUND_FORMULA_END + + COMPOUND_FORMULA_END_BITS + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -291,16 +290,16 @@ public class RuleBinarySerializerTest { RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = START_BIT - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + PACKAGE_NAME + EQ + IS_NOT_HASHED - + getBits(packageName.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(packageName.length(), VALUE_SIZE_BITS) + getValueBits(packageName) + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -324,16 +323,16 @@ public class RuleBinarySerializerTest { RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = START_BIT - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ + IS_NOT_HASHED - + getBits(versionCode.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(versionCode.length(), VALUE_SIZE_BITS) + getValueBits(versionCode) + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -354,16 +353,16 @@ public class RuleBinarySerializerTest { RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = START_BIT - + ATOMIC_FORMULA_START + + ATOMIC_FORMULA_START_BITS + PRE_INSTALLED + EQ + IS_NOT_HASHED - + getBits(preInstalled.length(), RuleBinarySerializer.VALUE_SIZE_BITS) + + getBits(preInstalled.length(), VALUE_SIZE_BITS) + getValueBits(preInstalled) + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION); + byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); byteArrayOutputStream.write(getBytes(expectedBits)); byte[] expectedRules = byteArrayOutputStream.toByteArray(); @@ -393,7 +392,7 @@ public class RuleBinarySerializerTest { public void testBinaryString_serializeFormatVersion() throws Exception { int formatVersion = 1; RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = getBits(formatVersion, RuleBinarySerializer.FORMAT_VERSION_BITS); + String expectedBits = getBits(formatVersion, FORMAT_VERSION_BITS); byte[] expectedRules = getBytes(expectedBits); byte[] actualRules = |