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

Commit 1dcd1819 authored by Khaled Abdelmohsen's avatar Khaled Abdelmohsen Committed by Android (Google) Code Review
Browse files

Merge "Implement basic operations for rule XML parsing"

parents 7bae749b 216109e9
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -19,18 +19,19 @@ package com.android.server.integrity.parser;
import com.android.server.integrity.model.Rule;

import java.io.InputStream;
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 Rule parse(String ruleText) {
    public List<Rule> parse(String ruleText) {
        // TODO: Implement binary text parser.
        return null;
    }

    @Override
    public Rule parse(InputStream inputStream) {
    public List<Rule> parse(InputStream inputStream) {
        // TODO: Implement stream parser.
        return null;
    }
+3 −2
Original line number Diff line number Diff line
@@ -19,13 +19,14 @@ package com.android.server.integrity.parser;
import com.android.server.integrity.model.Rule;

import java.io.InputStream;
import java.util.List;

/** A helper class to parse rules into the {@link Rule} model. */
public interface RuleParser {

    /** Parse rules from a string. */
    Rule parse(String ruleText);
    List<Rule> parse(String ruleText);

    /** Parse rules from an input stream. */
    Rule parse(InputStream inputStream);
    List<Rule> parse(InputStream inputStream);
}
+73 −5
Original line number Diff line number Diff line
@@ -16,22 +16,90 @@

package com.android.server.integrity.parser;

import android.util.Slog;
import android.util.Xml;

import com.android.server.integrity.model.Rule;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/** A helper class to parse rules into the {@link Rule} model from Xml representation. */
/**
 * A helper class to parse rules into the {@link Rule} model from Xml representation.
 */
public final class RuleXmlParser implements RuleParser {

    public static final String TAG = "RuleXmlParser";

    private static final String RULE_LIST_TAG = "RuleList";
    private static final String RULE_TAG = "Rule";

    @Override
    public Rule parse(String ruleText) {
        // TODO: Implement text parser.
    public List<Rule> parse(String ruleText) {
        try {
            XmlPullParser xmlPullParser = Xml.newPullParser();
            xmlPullParser.setInput(new StringReader(ruleText));
            return parseRules(xmlPullParser);
        } catch (XmlPullParserException | IOException e) {
            Slog.e(TAG, String.format("Unable to read rules from string: %s", ruleText), e);
        }
        return null;
    }

    @Override
    public Rule parse(InputStream inputStream) {
        // TODO: Implement stream parser.
    public List<Rule> parse(InputStream inputStream) {
        try {
            XmlPullParser xmlPullParser = Xml.newPullParser();
            xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
            return parseRules(xmlPullParser);
        } catch (XmlPullParserException | IOException e) {
            Slog.e(TAG, "Unable to read rules from stream", e);
        }
        return null;
    }

    private 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}
        parser.next();

        // Processing the first tag; which should always be a <RuleList> tag.
        String nodeName = parser.getName();
        // Validating that the XML is starting with a <RuleList> tag.
        // Note: This is the only breaking validation to run against XML files in the platform.
        // All rules inside are assumed to be validated at the server. If a rule is found to be
        // corrupt in the XML, it will be skipped to the next rule.
        if (!nodeName.equals(RULE_LIST_TAG)) {
            throw new RuntimeException(
                    String.format("Rules must start with <RuleList> tag. Found: %s at %s", nodeName,
                            parser.getPositionDescription()));
        }

        int eventType;
        while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
            nodeName = parser.getName();
            if (eventType != XmlPullParser.START_TAG || !nodeName.equals(RULE_TAG)) {
                continue;
            }
            Rule parsedRule = parseRule(parser);
            if (parsedRule != null) {
                rules.add(parsedRule);
            }
        }

        return rules;
    }

    private Rule parseRule(XmlPullParser parser) {
        // TODO: Implement rule parser.
        return null;
    }
}
+114 −0
Original line number Diff line number Diff line
/*
 * 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.testutils.TestUtils.assertExpectException;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import com.android.server.integrity.model.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.util.List;

@RunWith(JUnit4.class)
public class RuleXmlParserTest {

    private static final String VALID_RULE_XML = "<RuleList>"
            + "<Rule>"
            + "<OpenFormula>"
            + "<Connector>NOT</Connector>"
            + "<AtomicFormula>"
            + "<Key>PACKAGE_NAME</Key>"
            + "<Operator>EQ</Operator>"
            + "<Value>com.app.test</Value>"
            + "</AtomicFormula>"
            + "</OpenFormula>"
            + "<Effect>DENY</Effect>"
            + "</Rule>"
            + "</RuleList>";

    @Test
    public void testXmlString_validRule() {
        RuleParser xmlParser = new RuleXmlParser();

        List<Rule> rules = xmlParser.parse(VALID_RULE_XML);

        assertNotNull(rules);
        assertTrue(rules.isEmpty());
    }

    @Test
    public void testXmlStream_validRule() {
        RuleParser xmlParser = new RuleXmlParser();
        InputStream inputStream = new ByteArrayInputStream(VALID_RULE_XML.getBytes());

        List<Rule> rules = xmlParser.parse(inputStream);

        assertNotNull(rules);
        assertTrue(rules.isEmpty());
    }

    @Test
    public void testXmlString_withNoRuleList() {
        String ruleXmlWithNoRuleList = "<Rule>"
                + "<OpenFormula>"
                + "<Connector>NOT</Connector>"
                + "<AtomicFormula>"
                + "<Key>PACKAGE_NAME</Key>"
                + "<Operator>EQ</Operator>"
                + "<Value>com.app.test</Value>"
                + "</AtomicFormula>"
                + "</OpenFormula>"
                + "<Effect>DENY</Effect>"
                + "</Rule>";
        RuleParser xmlParser = new RuleXmlParser();

        assertExpectException(
                RuntimeException.class,
                /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
                () -> xmlParser.parse(ruleXmlWithNoRuleList));
    }

    @Test
    public void testXmlStream_withNoRuleList() {
        String ruleXmlWithNoRuleList = "<Rule>"
                + "<OpenFormula>"
                + "<Connector>NOT</Connector>"
                + "<AtomicFormula>"
                + "<Key>PACKAGE_NAME</Key>"
                + "<Operator>EQ</Operator>"
                + "<Value>com.app.test</Value>"
                + "</AtomicFormula>"
                + "</OpenFormula>"
                + "<Effect>DENY</Effect>"
                + "</Rule>";
        InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
        RuleParser xmlParser = new RuleXmlParser();

        assertExpectException(
                RuntimeException.class,
                /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
                () -> xmlParser.parse(inputStream));
    }
}