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 package com.android.internal.util;
17 
18 import static com.android.internal.util.BitUtils.flagsUpTo;
19 
20 import android.annotation.AppIdInt;
21 import android.annotation.ColorInt;
22 import android.annotation.FloatRange;
23 import android.annotation.IntRange;
24 import android.annotation.NonNull;
25 import android.annotation.Size;
26 import android.annotation.UserIdInt;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.content.pm.PackageManager.PackageInfoFlagsBits;
30 import android.content.pm.PackageManager.PermissionResult;
31 import android.os.UserHandle;
32 
33 import java.lang.annotation.Annotation;
34 
35 /**
36  * Validations for common annotations, e.g. {@link IntRange}, {@link UserIdInt}, etc.
37  *
38  * For usability from generated {@link DataClass} code, all validations are overloads of
39  * {@link #validate} with the following shape:
40  * {@code
41  *      <A extends Annotation> void validate(
42  *              Class<A> cls, A ignored, Object value[, (String, Object)... annotationParams])
43  * }
44  * The ignored {@link Annotation} parameter is used to differentiate between overloads that would
45  * otherwise have the same jvm signature. It's usually null at runtime.
46  */
47 public class AnnotationValidations {
AnnotationValidations()48     private AnnotationValidations() {}
49 
validate(Class<UserIdInt> annotation, UserIdInt ignored, int value)50     public static void validate(Class<UserIdInt> annotation, UserIdInt ignored, int value) {
51         if ((value != UserHandle.USER_NULL && value < -3)
52                 || value > Integer.MAX_VALUE / UserHandle.PER_USER_RANGE) {
53             invalid(annotation, value);
54         }
55     }
56 
validate(Class<AppIdInt> annotation, AppIdInt ignored, int value)57     public static void validate(Class<AppIdInt> annotation, AppIdInt ignored, int value) {
58         if (value / UserHandle.PER_USER_RANGE != 0 || value < 0) {
59             invalid(annotation, value);
60         }
61     }
62 
validate(Class<IntRange> annotation, IntRange ignored, int value, String paramName1, long param1, String paramName2, long param2)63     public static void validate(Class<IntRange> annotation, IntRange ignored, int value,
64             String paramName1, long param1, String paramName2, long param2) {
65         validate(annotation, ignored, value, paramName1, param1);
66         validate(annotation, ignored, value, paramName2, param2);
67     }
68 
validate(Class<IntRange> annotation, IntRange ignored, int value, String paramName, long param)69     public static void validate(Class<IntRange> annotation, IntRange ignored, int value,
70             String paramName, long param) {
71         switch (paramName) {
72             case "from":
73                 if (value < param) {
74                     invalid(annotation, value, paramName, param);
75                 }
76                 break;
77             case "to":
78                 if (value > param) {
79                     invalid(annotation, value, paramName, param);
80                 }
81                 break;
82         }
83     }
84 
85     /**
86      * Validate a long value with two parameters.
87      */
validate(Class<IntRange> annotation, IntRange ignored, long value, String paramName1, long param1, String paramName2, long param2)88     public static void validate(Class<IntRange> annotation, IntRange ignored, long value,
89             String paramName1, long param1, String paramName2, long param2) {
90         validate(annotation, ignored, value, paramName1, param1);
91         validate(annotation, ignored, value, paramName2, param2);
92     }
93 
94     /**
95      * Validate a long value with one parameter.
96      */
validate(Class<IntRange> annotation, IntRange ignored, long value, String paramName, long param)97     public static void validate(Class<IntRange> annotation, IntRange ignored, long value,
98             String paramName, long param) {
99         switch (paramName) {
100             case "from":
101                 if (value < param) {
102                     invalid(annotation, value, paramName, param);
103                 }
104                 break;
105             case "to":
106                 if (value > param) {
107                     invalid(annotation, value, paramName, param);
108                 }
109                 break;
110         }
111     }
112 
validate(Class<FloatRange> annotation, FloatRange ignored, float value, String paramName1, float param1, String paramName2, float param2)113     public static void validate(Class<FloatRange> annotation, FloatRange ignored, float value,
114             String paramName1, float param1, String paramName2, float param2) {
115         validate(annotation, ignored, value, paramName1, param1);
116         validate(annotation, ignored, value, paramName2, param2);
117     }
118 
validate(Class<FloatRange> annotation, FloatRange ignored, float value, String paramName, float param)119     public static void validate(Class<FloatRange> annotation, FloatRange ignored, float value,
120             String paramName, float param) {
121         switch (paramName) {
122             case "from": if (value < param) invalid(annotation, value, paramName, param); break;
123             case "to": if (value > param) invalid(annotation, value, paramName, param); break;
124         }
125     }
126 
validate(Class<NonNull> annotation, NonNull ignored, Object value)127     public static void validate(Class<NonNull> annotation, NonNull ignored, Object value) {
128         if (value == null) {
129             throw new NullPointerException();
130         }
131     }
132 
validate(Class<Size> annotation, Size ignored, int value, String paramName1, int param1, String paramName2, int param2)133     public static void validate(Class<Size> annotation, Size ignored, int value,
134             String paramName1, int param1, String paramName2, int param2) {
135         validate(annotation, ignored, value, paramName1, param1);
136         validate(annotation, ignored, value, paramName2, param2);
137     }
138 
validate(Class<Size> annotation, Size ignored, int value, String paramName, int param)139     public static void validate(Class<Size> annotation, Size ignored, int value,
140             String paramName, int param) {
141         switch (paramName) {
142             case "value": {
143                 if (param != -1 && value != param) invalid(annotation, value, paramName, param);
144             } break;
145             case "min": {
146                 if (value < param) invalid(annotation, value, paramName, param);
147             } break;
148             case "max": {
149                 if (value > param) invalid(annotation, value, paramName, param);
150             } break;
151             case "multiple": {
152                 if (value % param != 0) invalid(annotation, value, paramName, param);
153             } break;
154         }
155     }
156 
validate( Class<PermissionResult> annotation, PermissionResult ignored, int value)157     public static void validate(
158             Class<PermissionResult> annotation, PermissionResult ignored, int value) {
159         validateIntEnum(annotation, value, PackageManager.PERMISSION_GRANTED);
160     }
161 
validate( Class<PackageInfoFlagsBits> annotation, PackageInfoFlagsBits ignored, long value)162     public static void validate(
163             Class<PackageInfoFlagsBits> annotation, PackageInfoFlagsBits ignored, long value) {
164         validateLongFlags(annotation, value,
165                 flagsUpTo(PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS));
166     }
167 
validate( Class<Intent.Flags> annotation, Intent.Flags ignored, int value)168     public static void validate(
169             Class<Intent.Flags> annotation, Intent.Flags ignored, int value) {
170         validateIntFlags(annotation, value, flagsUpTo(Intent.FLAG_RECEIVER_OFFLOAD));
171     }
172 
173 
174     @Deprecated
validate(Class<? extends Annotation> annotation, Annotation ignored, Object value, Object... params)175     public static void validate(Class<? extends Annotation> annotation,
176             Annotation ignored, Object value, Object... params) {}
177     @Deprecated
validate(Class<? extends Annotation> annotation, Annotation ignored, Object value)178     public static void validate(Class<? extends Annotation> annotation,
179             Annotation ignored, Object value) {}
180     @Deprecated
validate(Class<? extends Annotation> annotation, Annotation ignored, int value, Object... params)181     public static void validate(Class<? extends Annotation> annotation,
182             Annotation ignored, int value, Object... params) {}
validate(Class<? extends Annotation> annotation, Annotation ignored, int value)183     public static void validate(Class<? extends Annotation> annotation,
184             Annotation ignored, int value) {
185         if (("android.annotation".equals(annotation.getPackageName())
186                 && annotation.getSimpleName().endsWith("Res"))
187                 || ColorInt.class.equals(annotation)) {
188             if (value < 0) {
189                 invalid(annotation, value);
190             }
191         }
192     }
validate(Class<? extends Annotation> annotation, Annotation ignored, long value)193     public static void validate(Class<? extends Annotation> annotation,
194             Annotation ignored, long value) {
195         if ("android.annotation".equals(annotation.getPackageName())
196                 && annotation.getSimpleName().endsWith("Long")) {
197             if (value < 0L) {
198                 invalid(annotation, value);
199             }
200         }
201     }
202 
validateIntEnum( Class<? extends Annotation> annotation, int value, int lastValid)203     private static void validateIntEnum(
204             Class<? extends Annotation> annotation, int value, int lastValid) {
205         if (value > lastValid) {
206             invalid(annotation, value);
207         }
208     }
validateIntFlags( Class<? extends Annotation> annotation, int value, int validBits)209     private static void validateIntFlags(
210             Class<? extends Annotation> annotation, int value, int validBits) {
211         if ((validBits & value) != validBits) {
212             invalid(annotation, "0x" + Integer.toHexString(value));
213         }
214     }
validateLongFlags( Class<? extends Annotation> annotation, long value, int validBits)215     private static void validateLongFlags(
216             Class<? extends Annotation> annotation, long value, int validBits) {
217         if ((validBits & value) != validBits) {
218             invalid(annotation, "0x" + Long.toHexString(value));
219         }
220     }
invalid(Class<? extends Annotation> annotation, Object value)221     private static void invalid(Class<? extends Annotation> annotation, Object value) {
222         invalid("@" + annotation.getSimpleName(), value);
223     }
224 
invalid(Class<? extends Annotation> annotation, Object value, String paramName, Object param)225     private static void invalid(Class<? extends Annotation> annotation, Object value,
226             String paramName, Object param) {
227         String paramPrefix = "value".equals(paramName) ? "" : paramName + " = ";
228         invalid("@" + annotation.getSimpleName() + "(" + paramPrefix + param + ")", value);
229     }
230 
invalid(String valueKind, Object value)231     private static void invalid(String valueKind, Object value) {
232         throw new IllegalStateException("Invalid " + valueKind + ": " + value);
233     }
234 }
235