1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.integrity.engine; 18 19 import static android.content.integrity.Rule.DENY; 20 import static android.content.integrity.Rule.FORCE_ALLOW; 21 22 import android.annotation.NonNull; 23 import android.content.integrity.AppInstallMetadata; 24 import android.content.integrity.Rule; 25 26 import com.android.server.integrity.model.IntegrityCheckResult; 27 28 import java.util.List; 29 import java.util.stream.Collectors; 30 31 /** 32 * A helper class for evaluating rules against app install metadata to find if there are matching 33 * rules. 34 */ 35 final class RuleEvaluator { 36 37 /** 38 * Match the list of rules against an app install metadata. 39 * 40 * <p>Rules must be in disjunctive normal form (DNF). A rule should contain AND'ed formulas 41 * only. All rules are OR'ed together by default. 42 * 43 * @param rules The list of rules to evaluate. 44 * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules 45 * against. 46 * @return result of the integrity check 47 */ 48 @NonNull evaluateRules( List<Rule> rules, AppInstallMetadata appInstallMetadata)49 static IntegrityCheckResult evaluateRules( 50 List<Rule> rules, AppInstallMetadata appInstallMetadata) { 51 52 // Identify the rules that match the {@code appInstallMetadata}. 53 List<Rule> matchedRules = 54 rules.stream() 55 .filter(rule -> rule.getFormula().matches(appInstallMetadata)) 56 .collect(Collectors.toList()); 57 58 // Identify the matched power allow rules and terminate early if we have any. 59 List<Rule> matchedPowerAllowRules = 60 matchedRules.stream() 61 .filter(rule -> rule.getEffect() == FORCE_ALLOW) 62 .collect(Collectors.toList()); 63 64 if (!matchedPowerAllowRules.isEmpty()) { 65 return IntegrityCheckResult.allow(matchedPowerAllowRules); 66 } 67 68 // Identify the matched deny rules. 69 List<Rule> matchedDenyRules = 70 matchedRules.stream() 71 .filter(rule -> rule.getEffect() == DENY) 72 .collect(Collectors.toList()); 73 74 if (!matchedDenyRules.isEmpty()) { 75 return IntegrityCheckResult.deny(matchedDenyRules); 76 } 77 78 // When no rules are denied, return default allow result. 79 return IntegrityCheckResult.allow(); 80 } 81 } 82