1 /*
2  * Copyright (C) 2022 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 android.adservices.common;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.os.LimitExceededException;
22 
23 import com.android.adservices.shared.common.exception.ProviderServiceInternalException;
24 import com.android.adservices.shared.common.exception.ServiceUnavailableException;
25 
26 import java.io.IOException;
27 import java.io.InvalidObjectException;
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.concurrent.TimeoutException;
31 
32 /**
33  * Utility class containing status codes and functions used by various response objects.
34  *
35  * <p>Those status codes are internal only.
36  *
37  * @hide
38  */
39 public final class AdServicesStatusUtils {
40 
41     /**
42      * The status code has not been set. Keep unset status code the lowest value of the status
43      * codes.
44      */
45     public static final int STATUS_UNSET = -1;
46 
47     /** The call was successful. */
48     public static final int STATUS_SUCCESS = 0;
49 
50     /**
51      * An internal error occurred within the API, which the caller cannot address.
52      *
53      * <p>This error may be considered similar to {@link IllegalStateException}.
54      */
55     public static final int STATUS_INTERNAL_ERROR = 1;
56 
57     /**
58      * The caller supplied invalid arguments to the call.
59      *
60      * <p>This error may be considered similar to {@link IllegalArgumentException}.
61      */
62     public static final int STATUS_INVALID_ARGUMENT = 2;
63 
64     /** There was an unknown error. */
65     public static final int STATUS_UNKNOWN_ERROR = 3;
66 
67     /**
68      * There was an I/O error.
69      *
70      * <p>This error may be considered similar to {@link IOException}.
71      */
72     public static final int STATUS_IO_ERROR = 4;
73 
74     /**
75      * Result code for Rate Limit Reached.
76      *
77      * <p>This error may be considered similar to {@link LimitExceededException}.
78      */
79     public static final int STATUS_RATE_LIMIT_REACHED = 5;
80 
81     /**
82      * Killswitch was enabled. AdServices is not available.
83      *
84      * <p>This error may be considered similar to {@link IllegalStateException}.
85      */
86     public static final int STATUS_KILLSWITCH_ENABLED = 6;
87 
88     /**
89      * User consent was revoked. AdServices is not available.
90      *
91      * <p>This error may be considered similar to {@link IllegalStateException}.
92      */
93     public static final int STATUS_USER_CONSENT_REVOKED = 7;
94 
95     /**
96      * AdServices were disabled. AdServices is not available.
97      *
98      * <p>This error may be considered similar to {@link IllegalStateException}.
99      */
100     public static final int STATUS_ADSERVICES_DISABLED = 8;
101 
102     /**
103      * The caller is not authorized to make this call. Permission was not requested.
104      *
105      * <p>This error may be considered similar to {@link SecurityException}.
106      */
107     public static final int STATUS_PERMISSION_NOT_REQUESTED = 9;
108 
109     /**
110      * The caller is not authorized to make this call. Caller is not allowed (not present in the
111      * allowed list).
112      *
113      * <p>This error may be considered similar to {@link SecurityException}.
114      */
115     public static final int STATUS_CALLER_NOT_ALLOWED = 10;
116 
117     /**
118      * The caller is not authorized to make this call. Call was executed from background thread.
119      *
120      * <p>This error may be considered similar to {@link IllegalStateException}.
121      */
122     public static final int STATUS_BACKGROUND_CALLER = 11;
123 
124     /**
125      * The caller is not authorized to make this call.
126      *
127      * <p>This error may be considered similar to {@link SecurityException}.
128      */
129     public static final int STATUS_UNAUTHORIZED = 12;
130 
131     /**
132      * There was an internal Timeout within the API, which is non-recoverable by the caller
133      *
134      * <p>This error may be considered similar to {@link java.util.concurrent.TimeoutException}
135      */
136     public static final int STATUS_TIMEOUT = 13;
137 
138     /**
139      * The device is not running a version of WebView that supports JSSandbox, required for FLEDGE
140      * Ad Selection.
141      *
142      * <p>This error may be considered similar to {@link IllegalStateException}.
143      */
144     public static final int STATUS_JS_SANDBOX_UNAVAILABLE = 14;
145 
146     /**
147      * The service received an invalid object from the remote server.
148      *
149      * <p>This error may be considered similar to {@link InvalidObjectException}.
150      */
151     public static final int STATUS_INVALID_OBJECT = 15;
152 
153     /**
154      * The caller is not authorized to make this call because it crosses user boundaries.
155      *
156      * <p>This error may be considered similar to {@link SecurityException}.
157      */
158     public static final int STATUS_CALLER_NOT_ALLOWED_TO_CROSS_USER_BOUNDARIES = 16;
159 
160     /**
161      * Result code for Server Rate Limit Reached.
162      *
163      * <p>This error may be considered similar to {@link LimitExceededException}.
164      */
165     public static final int STATUS_SERVER_RATE_LIMIT_REACHED = 17;
166 
167     /**
168      * Consent notification has not been displayed yet. AdServices is not available.
169      *
170      * <p>This error may be considered similar to {@link IllegalStateException}.
171      */
172     public static final int STATUS_USER_CONSENT_NOTIFICATION_NOT_DISPLAYED_YET = 18;
173 
174     /**
175      * Result code for Encryption related failures.
176      *
177      * <p>This error may be considered similar to {@link IllegalArgumentException}.
178      */
179     public static final int STATUS_ENCRYPTION_FAILURE = 19;
180 
181     /**
182      * The caller is not authorized to make this call because the package is not in the allowlist.
183      *
184      * <p>This error may be considered similar to {@link SecurityException}.
185      */
186     public static final int STATUS_CALLER_NOT_ALLOWED_PACKAGE_NOT_IN_ALLOWLIST = 20;
187 
188     /**
189      * The caller is not authorized to make this call because the package is not in the allowlist.
190      *
191      * <p>This error may be considered similar to {@link SecurityException}.
192      */
193     public static final int STATUS_CALLER_NOT_ALLOWED_PACKAGE_BLOCKLISTED = 21;
194 
195     /**
196      * The caller is not authorized to make this call because enrollment data can't be found.
197      *
198      * <p>This error may be considered similar to {@link SecurityException}.
199      */
200     public static final int STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_MATCH_NOT_FOUND = 22;
201 
202     /**
203      * The caller is not authorized to make this call because enrollment ID is invalid.
204      *
205      * <p>This error may be considered similar to {@link SecurityException}.
206      */
207     public static final int STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_INVALID_ID = 23;
208 
209     /**
210      * The caller is not authorized to make this call because enrollment ID is in the blocklist.
211      *
212      * <p>This error may be considered similar to {@link SecurityException}.
213      */
214     public static final int STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_BLOCKLISTED = 24;
215 
216     /**
217      * The caller is not authorized to make this call because permission was not requested in the
218      * manifest.
219      *
220      * <p>This error may be considered similar to {@link SecurityException}.
221      */
222     public static final int STATUS_CALLER_NOT_ALLOWED_MANIFEST_ADSERVICES_CONFIG_NO_PERMISSION = 25;
223 
224     /**
225      * AdServices activity is disabled.
226      *
227      * <p>This error may be considered similar to {@link IllegalStateException}.
228      */
229     public static final int STATUS_ADSERVICES_ACTIVITY_DISABLED = 26;
230 
231     /**
232      * Callback is shut down and encountered an error when invoking its methods.
233      *
234      * <p>This error may be considered similar to {@link IllegalStateException}.
235      */
236     public static final int STATUS_CALLBACK_SHUTDOWN = 27;
237 
238     /**
239      * The provider service throws an error as the callback when AdServices tries to call it.
240      *
241      * <p>This error may be considered similar to {@link IllegalStateException}.
242      */
243     public static final int STATUS_PROVIDER_SERVICE_INTERNAL_ERROR = 28;
244 
245     /**
246      * The scheduleCustomAudienceUpdate() request failed because an existing update has not been
247      * executed yet and should be explicitly replaced by the caller.
248      *
249      * <p>This error throws an {@link IllegalStateException}.
250      */
251     public static final int STATUS_UPDATE_ALREADY_PENDING_ERROR = 29;
252 
253     /** The error message to be returned along with {@link LimitExceededException}. */
254     public static final String RATE_LIMIT_REACHED_ERROR_MESSAGE = "API rate limit exceeded.";
255 
256     /** The error message to be returned along with {@link LimitExceededException}. */
257     public static final String SERVER_RATE_LIMIT_REACHED_ERROR_MESSAGE =
258             "Server rate limit exceeded.";
259 
260     /**
261      * The error message to be returned along with {@link SecurityException} when permission was not
262      * requested in the manifest.
263      */
264     public static final String SECURITY_EXCEPTION_PERMISSION_NOT_REQUESTED_ERROR_MESSAGE =
265             "Caller is not authorized to call this API. Permission was not requested.";
266 
267     /**
268      * The error message to be returned along with {@link SecurityException} when caller is not
269      * allowed to call AdServices (not present in the allowed list).
270      */
271     public static final String SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE =
272             "Caller is not authorized to call this API. Caller is not allowed.";
273 
274     /**
275      * The error message to be returned along with {@link SecurityException} when call was executed
276      * from the background thread.
277      */
278     public static final String ILLEGAL_STATE_BACKGROUND_CALLER_ERROR_MESSAGE =
279             "Background thread is not allowed to call this service.";
280 
281     /**
282      * The error message to be returned along with {@link IllegalStateException} when call failed
283      * because AdServices activity is disabled.
284      */
285     public static final String ILLEGAL_STATE_ACTIVITY_DISABLED_ERROR_MESSAGE =
286             "AdServices activity is disabled.";
287 
288     /**
289      * The error message to be returned along with {@link SecurityException} when call failed
290      * because it crosses user boundaries.
291      */
292     public static final String SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_TO_CROSS_USER_BOUNDARIES =
293             "Caller is not authorized to access information from another user";
294 
295     /**
296      * The error message to be returned along with {@link SecurityException} when caller not allowed
297      * to perform this operation on behalf of the given package.
298      */
299     public static final String SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ON_BEHALF_ERROR_MESSAGE =
300             "Caller is not allowed to perform this operation on behalf of the given package.";
301 
302     /** The error message to be returned along with {@link TimeoutException}. */
303     public static final String TIMED_OUT_ERROR_MESSAGE = "API timed out.";
304 
305     /** The error message to be returned along with {@link InvalidObjectException}. */
306     public static final String INVALID_OBJECT_ERROR_MESSAGE =
307             "The service received an invalid object from the server.";
308 
309     /** The error message to be returned along with {@link IllegalArgumentException}. */
310     public static final String ENCRYPTION_FAILURE_MESSAGE = "Failed to encrypt responses.";
311 
312     /** The error message to be returned along with {@link ServiceUnavailableException}. */
313     public static final String SERVICE_UNAVAILABLE_ERROR_MESSAGE = "Service is not available.";
314 
315     /**
316      * The error message returned when a call to schedule a custom audience update fails because of
317      * an existing pending update.
318      */
319     public static final String UPDATE_ALREADY_PENDING_ERROR_MESSAGE =
320             "Failed to schedule update. A request is already pending.";
321 
322     /** Returns true for a successful status. */
isSuccess(@tatusCode int statusCode)323     public static boolean isSuccess(@StatusCode int statusCode) {
324         return statusCode == STATUS_SUCCESS;
325     }
326 
327     /** Converts the input {@code statusCode} to an exception to be used in the callback. */
328     @NonNull
asException(@tatusCode int statusCode)329     public static Exception asException(@StatusCode int statusCode) {
330         switch (statusCode) {
331             case STATUS_ENCRYPTION_FAILURE:
332                 return new IllegalArgumentException(ENCRYPTION_FAILURE_MESSAGE);
333             case STATUS_INVALID_ARGUMENT:
334                 return new IllegalArgumentException();
335             case STATUS_IO_ERROR:
336                 return new IOException();
337             case STATUS_KILLSWITCH_ENABLED: // Intentional fallthrough
338             case STATUS_USER_CONSENT_NOTIFICATION_NOT_DISPLAYED_YET: // Intentional fallthrough
339             case STATUS_USER_CONSENT_REVOKED: // Intentional fallthrough
340             case STATUS_JS_SANDBOX_UNAVAILABLE:
341                 return new ServiceUnavailableException(SERVICE_UNAVAILABLE_ERROR_MESSAGE);
342             case STATUS_PERMISSION_NOT_REQUESTED:
343                 return new SecurityException(
344                         SECURITY_EXCEPTION_PERMISSION_NOT_REQUESTED_ERROR_MESSAGE);
345             case STATUS_CALLER_NOT_ALLOWED:
346                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
347             case STATUS_CALLER_NOT_ALLOWED_PACKAGE_NOT_IN_ALLOWLIST:
348                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
349             case STATUS_CALLER_NOT_ALLOWED_PACKAGE_BLOCKLISTED:
350                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
351             case STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_MATCH_NOT_FOUND:
352                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
353             case STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_INVALID_ID:
354                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
355             case STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_BLOCKLISTED:
356                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
357             case STATUS_CALLER_NOT_ALLOWED_MANIFEST_ADSERVICES_CONFIG_NO_PERMISSION:
358                 return new SecurityException(SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE);
359             case STATUS_BACKGROUND_CALLER:
360                 return new IllegalStateException(ILLEGAL_STATE_BACKGROUND_CALLER_ERROR_MESSAGE);
361             case STATUS_ADSERVICES_ACTIVITY_DISABLED:
362                 return new IllegalStateException(ILLEGAL_STATE_ACTIVITY_DISABLED_ERROR_MESSAGE);
363             case STATUS_UPDATE_ALREADY_PENDING_ERROR:
364                 return new IllegalStateException(UPDATE_ALREADY_PENDING_ERROR_MESSAGE);
365             case STATUS_UNAUTHORIZED:
366                 return new SecurityException(
367                         SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ON_BEHALF_ERROR_MESSAGE);
368             case STATUS_TIMEOUT:
369                 return new TimeoutException(TIMED_OUT_ERROR_MESSAGE);
370             case STATUS_RATE_LIMIT_REACHED:
371                 return new LimitExceededException(RATE_LIMIT_REACHED_ERROR_MESSAGE);
372             case STATUS_INVALID_OBJECT:
373                 return new InvalidObjectException(INVALID_OBJECT_ERROR_MESSAGE);
374             case STATUS_SERVER_RATE_LIMIT_REACHED:
375                 return new LimitExceededException(SERVER_RATE_LIMIT_REACHED_ERROR_MESSAGE);
376             case STATUS_PROVIDER_SERVICE_INTERNAL_ERROR:
377                 return new ProviderServiceInternalException();
378             default:
379                 return new IllegalStateException();
380         }
381     }
382 
383     /** Converts the {@link AdServicesResponse} to an exception to be used in the callback. */
384     // TODO(b/328601595): Add unit test for AdServicesStatusUtils.asException
385     @NonNull
asException(@onNull AdServicesResponse adServicesResponse)386     public static Exception asException(@NonNull AdServicesResponse adServicesResponse) {
387         return asException(adServicesResponse.getStatusCode());
388     }
389 
390     /**
391      * Result codes that are common across various APIs.
392      *
393      * @hide
394      */
395     @IntDef(
396             prefix = {"STATUS_"},
397             value = {
398                 STATUS_UNSET,
399                 STATUS_SUCCESS,
400                 STATUS_INTERNAL_ERROR,
401                 STATUS_INVALID_ARGUMENT,
402                 STATUS_RATE_LIMIT_REACHED,
403                 STATUS_UNKNOWN_ERROR,
404                 STATUS_IO_ERROR,
405                 STATUS_KILLSWITCH_ENABLED,
406                 STATUS_USER_CONSENT_REVOKED,
407                 STATUS_ADSERVICES_DISABLED,
408                 STATUS_ADSERVICES_ACTIVITY_DISABLED,
409                 STATUS_PERMISSION_NOT_REQUESTED,
410                 STATUS_CALLER_NOT_ALLOWED,
411                 STATUS_BACKGROUND_CALLER,
412                 STATUS_UNAUTHORIZED,
413                 STATUS_TIMEOUT,
414                 STATUS_JS_SANDBOX_UNAVAILABLE,
415                 STATUS_INVALID_OBJECT,
416                 STATUS_SERVER_RATE_LIMIT_REACHED,
417                 STATUS_USER_CONSENT_NOTIFICATION_NOT_DISPLAYED_YET,
418                 STATUS_ENCRYPTION_FAILURE,
419                 STATUS_CALLER_NOT_ALLOWED_PACKAGE_NOT_IN_ALLOWLIST,
420                 STATUS_CALLER_NOT_ALLOWED_PACKAGE_BLOCKLISTED,
421                 STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_MATCH_NOT_FOUND,
422                 STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_INVALID_ID,
423                 STATUS_CALLER_NOT_ALLOWED_ENROLLMENT_BLOCKLISTED,
424                 STATUS_CALLER_NOT_ALLOWED_MANIFEST_ADSERVICES_CONFIG_NO_PERMISSION,
425                 STATUS_CALLBACK_SHUTDOWN,
426                 STATUS_PROVIDER_SERVICE_INTERNAL_ERROR,
427                 STATUS_UPDATE_ALREADY_PENDING_ERROR,
428             })
429     @Retention(RetentionPolicy.SOURCE)
430     public @interface StatusCode {}
431 
AdServicesStatusUtils()432     private AdServicesStatusUtils() {
433         throw new UnsupportedOperationException();
434     }
435 }
436