Implement XML parsing for atomic formula
Parse a rule's atomic formula and effect, and wrap the result in a rule to be appended to the list of rules parsed so far. Bug: 143697198 Test: atest FrameworksServicesTests:RuleXmlParserTest Change-Id: If09503472060929c6ab914b3b178c14c0e7cd314
This commit is contained in:
@@ -19,6 +19,8 @@ package com.android.server.integrity.parser;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.server.integrity.model.AtomicFormula;
|
||||
import com.android.server.integrity.model.Formula;
|
||||
import com.android.server.integrity.model.Rule;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
@@ -38,8 +40,15 @@ public final class RuleXmlParser implements RuleParser {
|
||||
|
||||
public static final String TAG = "RuleXmlParser";
|
||||
|
||||
// TODO: Use XML attributes
|
||||
private static final String RULE_LIST_TAG = "RuleList";
|
||||
private static final String RULE_TAG = "Rule";
|
||||
private static final String OPEN_FORMULA_TAG = "OpenFormula";
|
||||
private static final String ATOMIC_FORMULA_TAG = "AtomicFormula";
|
||||
private static final String EFFECT_TAG = "Effect";
|
||||
private static final String KEY_TAG = "Key";
|
||||
private static final String OPERATOR_TAG = "Operator";
|
||||
private static final String VALUE_TAG = "Value";
|
||||
|
||||
@Override
|
||||
public List<Rule> parse(String ruleText) {
|
||||
@@ -65,7 +74,8 @@ public final class RuleXmlParser implements RuleParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Rule> parseRules(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||
private static List<Rule> parseRules(XmlPullParser parser)
|
||||
throws IOException, XmlPullParserException {
|
||||
List<Rule> rules = new ArrayList<>();
|
||||
|
||||
// Skipping the first event type, which is always {@link XmlPullParser.START_DOCUMENT}
|
||||
@@ -98,8 +108,109 @@ public final class RuleXmlParser implements RuleParser {
|
||||
return rules;
|
||||
}
|
||||
|
||||
private Rule parseRule(XmlPullParser parser) {
|
||||
// TODO: Implement rule parser.
|
||||
private static Rule parseRule(XmlPullParser parser) {
|
||||
try {
|
||||
Formula formula = null;
|
||||
@Rule.Effect int effect = 0;
|
||||
|
||||
boolean isValid = true;
|
||||
int eventType;
|
||||
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
String nodeName = parser.getName();
|
||||
|
||||
if (eventType == XmlPullParser.END_TAG && parser.getName().equals(RULE_TAG)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
switch (nodeName) {
|
||||
case OPEN_FORMULA_TAG:
|
||||
formula = parseOpenFormula(parser);
|
||||
break;
|
||||
case ATOMIC_FORMULA_TAG:
|
||||
formula = parseAtomicFormula(parser);
|
||||
break;
|
||||
case EFFECT_TAG:
|
||||
effect = Integer.parseInt(extractValue(parser));
|
||||
break;
|
||||
default:
|
||||
isValid = false;
|
||||
}
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return isValid ? new Rule(formula, effect) : null;
|
||||
} catch (Exception e) {
|
||||
// In case of any exceptions arising from constructing the rule, it will be skipped.
|
||||
// Rules are assumed to be validated on the server.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Formula parseOpenFormula(XmlPullParser parser) {
|
||||
// TODO: Implement open formula parser.
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Formula parseAtomicFormula(XmlPullParser parser)
|
||||
throws IOException, XmlPullParserException {
|
||||
@AtomicFormula.Key int key = 0;
|
||||
@AtomicFormula.Operator int operator = 0;
|
||||
String value = null;
|
||||
|
||||
boolean isValid = true;
|
||||
int eventType;
|
||||
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
String nodeName = parser.getName();
|
||||
|
||||
if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ATOMIC_FORMULA_TAG)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
switch (nodeName) {
|
||||
case KEY_TAG:
|
||||
key = Integer.parseInt(extractValue(parser));
|
||||
break;
|
||||
case OPERATOR_TAG:
|
||||
operator = Integer.parseInt(extractValue(parser));
|
||||
break;
|
||||
case VALUE_TAG:
|
||||
value = extractValue(parser);
|
||||
break;
|
||||
default:
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isValid ? constructAtomicFormulaBasedOnKey(key, operator, value) : null;
|
||||
}
|
||||
|
||||
private static Formula constructAtomicFormulaBasedOnKey(@AtomicFormula.Key int key,
|
||||
@AtomicFormula.Operator int operator, String value) {
|
||||
switch (key) {
|
||||
case AtomicFormula.PACKAGE_NAME:
|
||||
case AtomicFormula.INSTALLER_NAME:
|
||||
case AtomicFormula.APP_CERTIFICATE:
|
||||
case AtomicFormula.INSTALLER_CERTIFICATE:
|
||||
return new AtomicFormula.StringAtomicFormula(key, value);
|
||||
case AtomicFormula.PRE_INSTALLED:
|
||||
return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value));
|
||||
case AtomicFormula.VERSION_CODE:
|
||||
return new AtomicFormula.IntAtomicFormula(key, operator, Integer.parseInt(value));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractValue(XmlPullParser parser)
|
||||
throws IOException, XmlPullParserException {
|
||||
String value = null;
|
||||
if (parser.next() == XmlPullParser.TEXT) {
|
||||
value = parser.getText();
|
||||
}
|
||||
return parser.next() == XmlPullParser.END_TAG ? value : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,10 @@ package com.android.server.integrity.parser;
|
||||
|
||||
import static com.android.server.testutils.TestUtils.assertExpectException;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.android.server.integrity.model.AtomicFormula;
|
||||
import com.android.server.integrity.model.OpenFormula;
|
||||
import com.android.server.integrity.model.Rule;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -29,6 +30,7 @@ import org.junit.runners.JUnit4;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
@@ -37,14 +39,14 @@ public class RuleXmlParserTest {
|
||||
private static final String VALID_RULE_XML = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<OpenFormula>"
|
||||
+ "<Connector>NOT</Connector>"
|
||||
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>PACKAGE_NAME</Key>"
|
||||
+ "<Operator>EQ</Operator>"
|
||||
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "</OpenFormula>"
|
||||
+ "<Effect>DENY</Effect>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
|
||||
@@ -54,8 +56,7 @@ public class RuleXmlParserTest {
|
||||
|
||||
List<Rule> rules = xmlParser.parse(VALID_RULE_XML);
|
||||
|
||||
assertNotNull(rules);
|
||||
assertTrue(rules.isEmpty());
|
||||
assertThat(rules).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -65,8 +66,133 @@ public class RuleXmlParserTest {
|
||||
|
||||
List<Rule> rules = xmlParser.parse(inputStream);
|
||||
|
||||
assertNotNull(rules);
|
||||
assertTrue(rules.isEmpty());
|
||||
assertThat(rules).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlString_validAtomicFormula_stringValue() {
|
||||
String ruleXmlAtomicFormula = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
Rule expectedRule = new Rule(
|
||||
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
|
||||
Rule.DENY);
|
||||
|
||||
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlString_validAtomicFormula_integerValue() {
|
||||
String ruleXmlAtomicFormula = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>" + AtomicFormula.VERSION_CODE + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>1</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
Rule expectedRule = new Rule(
|
||||
new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
|
||||
Rule.DENY);
|
||||
|
||||
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlString_validAtomicFormula_booleanValue() {
|
||||
String ruleXmlAtomicFormula = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>" + AtomicFormula.PRE_INSTALLED + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>true</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
Rule expectedRule = new Rule(
|
||||
new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
|
||||
Rule.DENY);
|
||||
|
||||
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlString_validAtomicFormula_differentTagOrder() {
|
||||
String ruleXmlAtomicFormula = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
Rule expectedRule = new Rule(
|
||||
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
|
||||
Rule.DENY);
|
||||
|
||||
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
|
||||
|
||||
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlString_invalidAtomicFormula_invalidTags() {
|
||||
String ruleXmlAtomicFormula = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<BadKey>" + AtomicFormula.PACKAGE_NAME + "</BadKey>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
|
||||
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
|
||||
|
||||
assertThat(rules).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlString_invalidAtomicFormula() {
|
||||
String ruleXmlAtomicFormula = "<RuleList>"
|
||||
+ "<Rule>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>" + AtomicFormula.VERSION_CODE + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>"
|
||||
+ "</RuleList>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
|
||||
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
|
||||
|
||||
assertThat(rules).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -75,12 +201,12 @@ public class RuleXmlParserTest {
|
||||
+ "<OpenFormula>"
|
||||
+ "<Connector>NOT</Connector>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>PACKAGE_NAME</Key>"
|
||||
+ "<Operator>EQ</Operator>"
|
||||
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "</OpenFormula>"
|
||||
+ "<Effect>DENY</Effect>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>";
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
|
||||
@@ -96,12 +222,12 @@ public class RuleXmlParserTest {
|
||||
+ "<OpenFormula>"
|
||||
+ "<Connector>NOT</Connector>"
|
||||
+ "<AtomicFormula>"
|
||||
+ "<Key>PACKAGE_NAME</Key>"
|
||||
+ "<Operator>EQ</Operator>"
|
||||
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
|
||||
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
|
||||
+ "<Value>com.app.test</Value>"
|
||||
+ "</AtomicFormula>"
|
||||
+ "</OpenFormula>"
|
||||
+ "<Effect>DENY</Effect>"
|
||||
+ "<Effect>" + Rule.DENY + "</Effect>"
|
||||
+ "</Rule>";
|
||||
InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
|
||||
RuleParser xmlParser = new RuleXmlParser();
|
||||
|
||||
Reference in New Issue
Block a user