blob: 56061df213886662cc1d38046509a821f919af8f [file] [log] [blame]
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +01001/*
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
Song Pan75147d52019-11-19 00:57:46 +000017package android.content.integrity;
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010018
Khaled Abdelmohsena4477fa2019-10-09 14:35:32 +010019import static com.android.internal.util.Preconditions.checkArgument;
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010020
Song Pan097f65d2019-11-10 18:02:52 +000021import android.annotation.IntDef;
22import android.annotation.NonNull;
Song Pan097f65d2019-11-10 18:02:52 +000023import android.os.Parcel;
24import android.os.Parcelable;
Song Pan097f65d2019-11-10 18:02:52 +000025
26import com.android.internal.annotations.VisibleForTesting;
27
28import java.lang.annotation.Retention;
29import java.lang.annotation.RetentionPolicy;
30import java.util.ArrayList;
Khaled Abdelmohsena4477fa2019-10-09 14:35:32 +010031import java.util.Collections;
32import java.util.List;
Khaled Abdelmohsenf5f98142019-10-10 17:29:53 +010033import java.util.Objects;
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010034
35/**
Song Pan75147d52019-11-19 00:57:46 +000036 * Represents a compound formula formed by joining other simple and complex formulas with boolean
37 * connectors.
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010038 *
39 * <p>Instances of this class are immutable.
Song Pan097f65d2019-11-10 18:02:52 +000040 *
41 * @hide
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010042 */
Song Pan097f65d2019-11-10 18:02:52 +000043@VisibleForTesting
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000044public final class CompoundFormula extends IntegrityFormula implements Parcelable {
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010045
Anton Hansson57b6af02019-12-10 15:38:59 +000046 /** @hide */
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000047 @IntDef(value = {AND, OR, NOT})
Song Pan097f65d2019-11-10 18:02:52 +000048 @Retention(RetentionPolicy.SOURCE)
49 public @interface Connector {}
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010050
Song Pan097f65d2019-11-10 18:02:52 +000051 /** Boolean AND operator. */
52 public static final int AND = 0;
53
54 /** Boolean OR operator. */
55 public static final int OR = 1;
56
57 /** Boolean NOT operator. */
58 public static final int NOT = 2;
59
60 private final @Connector int mConnector;
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000061 private final @NonNull List<IntegrityFormula> mFormulas;
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010062
Song Pan097f65d2019-11-10 18:02:52 +000063 @NonNull
Song Pan75147d52019-11-19 00:57:46 +000064 public static final Creator<CompoundFormula> CREATOR =
65 new Creator<CompoundFormula>() {
Song Pan097f65d2019-11-10 18:02:52 +000066 @Override
Song Pan75147d52019-11-19 00:57:46 +000067 public CompoundFormula createFromParcel(Parcel in) {
68 return new CompoundFormula(in);
Song Pan097f65d2019-11-10 18:02:52 +000069 }
70
71 @Override
Song Pan75147d52019-11-19 00:57:46 +000072 public CompoundFormula[] newArray(int size) {
73 return new CompoundFormula[size];
Song Pan097f65d2019-11-10 18:02:52 +000074 }
75 };
76
77 /**
78 * Create a new formula from operator and operands.
79 *
80 * @throws IllegalArgumentException if the number of operands is not matching the requirements
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000081 * for that operator (at least 2 for {@link #AND} and {@link
82 * #OR}, 1 for {@link #NOT}).
Song Pan097f65d2019-11-10 18:02:52 +000083 */
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000084 public CompoundFormula(@Connector int connector, List<IntegrityFormula> formulas) {
Song Pan75147d52019-11-19 00:57:46 +000085 checkArgument(
86 isValidConnector(connector), String.format("Unknown connector: %d", connector));
Khaled Abdelmohsena4477fa2019-10-09 14:35:32 +010087 validateFormulas(connector, formulas);
Song Pan097f65d2019-11-10 18:02:52 +000088 this.mConnector = connector;
89 this.mFormulas = Collections.unmodifiableList(formulas);
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +010090 }
91
Song Pan75147d52019-11-19 00:57:46 +000092 CompoundFormula(Parcel in) {
Song Pan097f65d2019-11-10 18:02:52 +000093 mConnector = in.readInt();
94 int length = in.readInt();
95 checkArgument(length >= 0, "Must have non-negative length. Got " + length);
96 mFormulas = new ArrayList<>(length);
97 for (int i = 0; i < length; i++) {
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000098 mFormulas.add(IntegrityFormula.readFromParcel(in));
Song Pan097f65d2019-11-10 18:02:52 +000099 }
Song Pan44e5aa52019-11-26 11:38:17 +0000100 validateFormulas(mConnector, mFormulas);
Song Pan097f65d2019-11-10 18:02:52 +0000101 }
102
103 public @Connector int getConnector() {
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +0100104 return mConnector;
105 }
106
Song Pan097f65d2019-11-10 18:02:52 +0000107 @NonNull
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000108 public List<IntegrityFormula> getFormulas() {
Khaled Abdelmohsena4477fa2019-10-09 14:35:32 +0100109 return mFormulas;
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +0100110 }
111
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100112 @Override
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000113 public int getTag() {
114 return IntegrityFormula.COMPOUND_FORMULA_TAG;
Song Pan097f65d2019-11-10 18:02:52 +0000115 }
116
117 @Override
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000118 public boolean matches(AppInstallMetadata appInstallMetadata) {
119 switch (getConnector()) {
120 case NOT:
121 return !getFormulas().get(0).matches(appInstallMetadata);
122 case AND:
123 return getFormulas().stream()
124 .allMatch(formula -> formula.matches(appInstallMetadata));
125 case OR:
126 return getFormulas().stream()
127 .anyMatch(formula -> formula.matches(appInstallMetadata));
128 default:
129 throw new IllegalArgumentException("Unknown connector " + getConnector());
130 }
Song Pan44e5aa52019-11-26 11:38:17 +0000131 }
132
133 @Override
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100134 public String toString() {
135 StringBuilder sb = new StringBuilder();
Song Pan097f65d2019-11-10 18:02:52 +0000136 if (mFormulas.size() == 1) {
137 sb.append(String.format("%s ", connectorToString(mConnector)));
138 sb.append(mFormulas.get(0).toString());
139 } else {
140 for (int i = 0; i < mFormulas.size(); i++) {
141 if (i > 0) {
142 sb.append(String.format(" %s ", connectorToString(mConnector)));
143 }
144 sb.append(mFormulas.get(i).toString());
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100145 }
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100146 }
147 return sb.toString();
148 }
149
Khaled Abdelmohsenf5f98142019-10-10 17:29:53 +0100150 @Override
151 public boolean equals(Object o) {
152 if (this == o) {
153 return true;
154 }
155 if (o == null || getClass() != o.getClass()) {
156 return false;
157 }
Song Pan75147d52019-11-19 00:57:46 +0000158 CompoundFormula that = (CompoundFormula) o;
Song Pan097f65d2019-11-10 18:02:52 +0000159 return mConnector == that.mConnector && mFormulas.equals(that.mFormulas);
Khaled Abdelmohsenf5f98142019-10-10 17:29:53 +0100160 }
161
162 @Override
163 public int hashCode() {
164 return Objects.hash(mConnector, mFormulas);
165 }
166
Song Pan097f65d2019-11-10 18:02:52 +0000167 @Override
168 public int describeContents() {
169 return 0;
170 }
171
172 @Override
173 public void writeToParcel(@NonNull Parcel dest, int flags) {
174 dest.writeInt(mConnector);
175 dest.writeInt(mFormulas.size());
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000176 for (IntegrityFormula formula : mFormulas) {
177 IntegrityFormula.writeToParcel(formula, dest, flags);
Song Pan097f65d2019-11-10 18:02:52 +0000178 }
179 }
180
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000181 private static void validateFormulas(
182 @Connector int connector, List<IntegrityFormula> formulas) {
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100183 switch (connector) {
184 case AND:
185 case OR:
Song Pan097f65d2019-11-10 18:02:52 +0000186 checkArgument(
187 formulas.size() >= 2,
188 String.format(
189 "Connector %s must have at least 2 formulas",
190 connectorToString(connector)));
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100191 break;
192 case NOT:
Song Pan097f65d2019-11-10 18:02:52 +0000193 checkArgument(
194 formulas.size() == 1,
195 String.format(
196 "Connector %s must have 1 formula only",
197 connectorToString(connector)));
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100198 break;
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100199 }
200 }
Song Pan097f65d2019-11-10 18:02:52 +0000201
Song Pan44e5aa52019-11-26 11:38:17 +0000202 private static String connectorToString(int connector) {
Song Pan097f65d2019-11-10 18:02:52 +0000203 switch (connector) {
204 case AND:
205 return "AND";
206 case OR:
207 return "OR";
208 case NOT:
209 return "NOT";
210 default:
211 throw new IllegalArgumentException("Unknown connector " + connector);
212 }
213 }
Khaled Abdelmohsen5809a5f2019-11-25 18:20:46 +0000214
215 private static boolean isValidConnector(int connector) {
Song Pan75147d52019-11-19 00:57:46 +0000216 return connector == AND || connector == OR || connector == NOT;
Khaled Abdelmohsen5809a5f2019-11-25 18:20:46 +0000217 }
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +0100218}