diff --git a/services/core/java/com/android/server/integrity/TEST_MAPPING b/services/core/java/com/android/server/integrity/TEST_MAPPING new file mode 100644 index 0000000000000..b45b4eaa1ba7b --- /dev/null +++ b/services/core/java/com/android/server/integrity/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.integrity." + }, + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java index c227aea053999..a6e08d8504ed5 100644 --- a/services/core/java/com/android/server/integrity/model/Rule.java +++ b/services/core/java/com/android/server/integrity/model/Rule.java @@ -16,13 +16,20 @@ package com.android.server.integrity.model; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.annotation.Nullable; /** * Represent rules to be used in the rule evaluation engine to match against app installs. + * + *
Instances of this class are immutable. */ public final class Rule { + // Holds an empty rule instance. + public static final Rule EMPTY = new Rule(); + enum Key { PACKAGE_NAME, APP_CERTIFICATE, @@ -50,25 +57,49 @@ public final class Rule { NOT } - final Formula mFormula; - final Effect mEffect; + private final Formula mFormula; + private final Effect mEffect; + + private Rule() { + this.mFormula = null; + this.mEffect = null; + } public Rule(Formula formula, Effect effect) { - this.mFormula = formula; - this.mEffect = effect; + this.mFormula = checkNotNull(formula); + this.mEffect = checkNotNull(effect); } + /** + * Indicates whether the rule is empty or not. + * + * @return {@code true} if the rule is empty, and {@code false} otherwise. + */ + public boolean isEmpty() { + return mFormula == null && mEffect == null; + } + + public Formula getFormula() { + return mFormula; + } + + public Effect getEffect() { + return mEffect; + } + + // TODO: Consider moving the sub-components to their respective model class. + /** * Represents a rule logic/content. */ - abstract class Formula { + abstract static class Formula { } /** * Represents a simple formula consisting of an app install metadata field and a value. */ - public final class AtomicFormula extends Formula { + public static final class AtomicFormula extends Formula { final Key mKey; final Operator mOperator; @@ -113,15 +144,16 @@ public final class Rule { /** * Represents a complex formula consisting of other simple and complex formulas. */ - public final class OpenFormula extends Formula { + public static final class OpenFormula extends Formula { final Connector mConnector; final Formula mMainFormula; final Formula mAuxiliaryFormula; - public OpenFormula(Connector connector, Formula mainFormula, Formula auxiliaryFormula) { - this.mConnector = connector; - this.mMainFormula = mainFormula; + public OpenFormula(Connector connector, Formula mainFormula, + @Nullable Formula auxiliaryFormula) { + this.mConnector = checkNotNull(connector); + this.mMainFormula = checkNotNull(mainFormula); this.mAuxiliaryFormula = auxiliaryFormula; } } diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java new file mode 100644 index 0000000000000..4321c21f68b2a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.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; + +import static com.android.server.testutils.TestUtils.assertExpectException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class RuleTest { + + private static final Rule.Effect DENY_EFFECT = Rule.Effect.DENY; + private static final Rule.Formula SIMPLE_FORMULA = + new Rule.AtomicFormula(Rule.Key.PACKAGE_NAME, Rule.Operator.EQ, "com.test.app"); + + @Test + public void testEmptyRule() { + Rule emptyRule = Rule.EMPTY; + + assertNull(emptyRule.getFormula()); + assertNull(emptyRule.getEffect()); + } + + @Test + public void testValidRule() { + Rule validRule = new Rule(SIMPLE_FORMULA, DENY_EFFECT); + + assertEquals(SIMPLE_FORMULA, validRule.getFormula()); + assertEquals(DENY_EFFECT, validRule.getEffect()); + } + + @Test + public void testInvalidRule_invalidEffect() { + assertExpectException( + NullPointerException.class, + /* expectedExceptionMessageRegex */ null, + () -> new Rule(SIMPLE_FORMULA, null)); + } + + @Test + public void testInvalidRule_invalidFormula() { + assertExpectException( + NullPointerException.class, + /* expectedExceptionMessageRegex */ null, + () -> new Rule(null, DENY_EFFECT)); + } +}