blob: 14b1197d7f451658b2e5ad248a1d95cc9e475534 [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
Omer Nebil Yaveroglu84f7c3f2020-01-29 12:18:10 +0000134 public boolean isAppCertificateFormula() {
135 return getFormulas().stream().anyMatch(formula -> formula.isAppCertificateFormula());
136 }
137
138 @Override
139 public boolean isInstallerFormula() {
140 return getFormulas().stream().anyMatch(formula -> formula.isInstallerFormula());
141 }
142
143 @Override
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100144 public String toString() {
145 StringBuilder sb = new StringBuilder();
Song Pan097f65d2019-11-10 18:02:52 +0000146 if (mFormulas.size() == 1) {
147 sb.append(String.format("%s ", connectorToString(mConnector)));
148 sb.append(mFormulas.get(0).toString());
149 } else {
150 for (int i = 0; i < mFormulas.size(); i++) {
151 if (i > 0) {
152 sb.append(String.format(" %s ", connectorToString(mConnector)));
153 }
154 sb.append(mFormulas.get(i).toString());
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100155 }
Khaled Abdelmohsen3f878cb2019-10-09 19:10:38 +0100156 }
157 return sb.toString();
158 }
159
Khaled Abdelmohsenf5f98142019-10-10 17:29:53 +0100160 @Override
161 public boolean equals(Object o) {
162 if (this == o) {
163 return true;
164 }
165 if (o == null || getClass() != o.getClass()) {
166 return false;
167 }
Song Pan75147d52019-11-19 00:57:46 +0000168 CompoundFormula that = (CompoundFormula) o;
Song Pan097f65d2019-11-10 18:02:52 +0000169 return mConnector == that.mConnector && mFormulas.equals(that.mFormulas);
Khaled Abdelmohsenf5f98142019-10-10 17:29:53 +0100170 }
171
172 @Override
173 public int hashCode() {
174 return Objects.hash(mConnector, mFormulas);
175 }
176
Song Pan097f65d2019-11-10 18:02:52 +0000177 @Override
178 public int describeContents() {
179 return 0;
180 }
181
182 @Override
183 public void writeToParcel(@NonNull Parcel dest, int flags) {
184 dest.writeInt(mConnector);
185 dest.writeInt(mFormulas.size());
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000186 for (IntegrityFormula formula : mFormulas) {
187 IntegrityFormula.writeToParcel(formula, dest, flags);
Song Pan097f65d2019-11-10 18:02:52 +0000188 }
189 }
190
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000191 private static void validateFormulas(
192 @Connector int connector, List<IntegrityFormula> formulas) {
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100193 switch (connector) {
194 case AND:
195 case OR:
Song Pan097f65d2019-11-10 18:02:52 +0000196 checkArgument(
197 formulas.size() >= 2,
198 String.format(
199 "Connector %s must have at least 2 formulas",
200 connectorToString(connector)));
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100201 break;
202 case NOT:
Song Pan097f65d2019-11-10 18:02:52 +0000203 checkArgument(
204 formulas.size() == 1,
205 String.format(
206 "Connector %s must have 1 formula only",
207 connectorToString(connector)));
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100208 break;
Khaled Abdelmohsenbe0454d2019-10-07 10:24:18 +0100209 }
210 }
Song Pan097f65d2019-11-10 18:02:52 +0000211
Song Pan44e5aa52019-11-26 11:38:17 +0000212 private static String connectorToString(int connector) {
Song Pan097f65d2019-11-10 18:02:52 +0000213 switch (connector) {
214 case AND:
215 return "AND";
216 case OR:
217 return "OR";
218 case NOT:
219 return "NOT";
220 default:
221 throw new IllegalArgumentException("Unknown connector " + connector);
222 }
223 }
Khaled Abdelmohsen5809a5f2019-11-25 18:20:46 +0000224
225 private static boolean isValidConnector(int connector) {
Song Pan75147d52019-11-19 00:57:46 +0000226 return connector == AND || connector == OR || connector == NOT;
Khaled Abdelmohsen5809a5f2019-11-25 18:20:46 +0000227 }
Khaled Abdelmohsene959bae2019-10-04 17:01:13 +0100228}