1 /*
2  * Copyright (C) 2021 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.libraries.entitlement;
18 
19 import androidx.annotation.IntDef;
20 
21 import java.lang.annotation.Retention;
22 import java.lang.annotation.RetentionPolicy;
23 
24 /**
25  * Indicates errors happened in retrieving service entitlement configuration.
26  */
27 public class ServiceEntitlementException extends Exception {
28     /**
29      * Unknown error.
30      */
31     public static final int ERROR_UNKNOWN = 0;
32 
33     /**
34      * Failure to compose JSON when making POST requests.
35      */
36     public static final int ERROR_JSON_COMPOSE_FAILURE = 1;
37 
38     // Android telephony related failures
39     /**
40      * Android telephony is unable to provide info like IMSI, e.g. when modem crashed.
41      */
42     public static final int ERROR_PHONE_NOT_AVAILABLE = 10;
43 
44     // EAP-AKA authentication related failures
45     /**
46      * SIM not returning a response to the EAP-AKA challenge, e.g. when the challenge is invalid.
47      * This can happen only when an embedded EAP-AKA challenge is conducted, as per GSMA spec TS.43
48      * section 2.6.1.
49      */
50     public static final int ERROR_ICC_AUTHENTICATION_NOT_AVAILABLE = 20;
51     /**
52      * EAP-AKA synchronization failure that cannot be recovered even after the "Sequence number
53      * synchronization" procedure as defined in RFC 4187.
54      */
55     public static final int ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE = 21;
56     /**
57      * EAP-AKA failure that happens when the client fails to authenticate within the maximum number
58      * of attempts
59      */
60     public static final int ERROR_EAP_AKA_FAILURE = 22;
61 
62     // HTTP related failures
63     /**
64      * Cannot connect to the entitlement server, e.g. due to weak mobile network and Wi-Fi
65      * connection.
66      */
67     public static final int ERROR_SERVER_NOT_CONNECTABLE = 30;
68     /**
69      * HTTP response received with a status code indicating failure, e.g. 4xx and 5xx. Use {@link
70      * #getHttpStatus} to get the status code and {@link #getMessage} the error message in the
71      * response body.
72      */
73     public static final int ERROR_HTTP_STATUS_NOT_SUCCESS = 31;
74     /**
75      * HTTP response received with a malformed format. e.g. the response with content-type JSON but
76      * failing JSON parser.
77      */
78     public static final int ERROR_MALFORMED_HTTP_RESPONSE = 32;
79 
80     // ODSA errors
81     /**
82      * HTTP response does not contain the authentication token.
83      */
84     public static final int ERROR_TOKEN_NOT_AVAILABLE = 60;
85 
86     @Retention(RetentionPolicy.SOURCE)
87     @IntDef({
88             ERROR_UNKNOWN,
89             ERROR_PHONE_NOT_AVAILABLE,
90             ERROR_ICC_AUTHENTICATION_NOT_AVAILABLE,
91             ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE,
92             ERROR_EAP_AKA_FAILURE,
93             ERROR_SERVER_NOT_CONNECTABLE,
94             ERROR_HTTP_STATUS_NOT_SUCCESS,
95             ERROR_MALFORMED_HTTP_RESPONSE,
96             ERROR_TOKEN_NOT_AVAILABLE
97     })
98     public @interface ErrorCode {}
99 
100     /**
101      * Default HTTP status if not been specified.
102      */
103     public static final int HTTP_STATUS_UNSPECIFIED = 0;
104 
105     /**
106      * An empty string if Retry-After header in HTTP response not been specified.
107      */
108     public static final String RETRY_AFTER_UNSPECIFIED = "";
109 
110     @ErrorCode
111     private final int mError;
112     private final int mHttpStatus;
113     private final String mRetryAfter;
114 
ServiceEntitlementException(int error, String message)115     public ServiceEntitlementException(int error, String message) {
116         this(error, HTTP_STATUS_UNSPECIFIED, RETRY_AFTER_UNSPECIFIED, message);
117     }
118 
ServiceEntitlementException(int error, int httpStatus, String message)119     public ServiceEntitlementException(int error, int httpStatus, String message) {
120         this(error, httpStatus, RETRY_AFTER_UNSPECIFIED, message);
121     }
122 
ServiceEntitlementException( int error, int httpStatus, String retryAfter, String message)123     public ServiceEntitlementException(
124             int error, int httpStatus, String retryAfter, String message) {
125         super(message);
126         this.mError = error;
127         this.mHttpStatus = httpStatus;
128         this.mRetryAfter = retryAfter;
129     }
130 
ServiceEntitlementException(int error, String message, Throwable cause)131     public ServiceEntitlementException(int error, String message, Throwable cause) {
132         this(error, HTTP_STATUS_UNSPECIFIED, RETRY_AFTER_UNSPECIFIED, message, cause);
133     }
134 
ServiceEntitlementException(int error, int httpStatus, String message, Throwable cause)135     public ServiceEntitlementException(int error, int httpStatus, String message, Throwable cause) {
136         this(error, httpStatus, RETRY_AFTER_UNSPECIFIED, message, cause);
137     }
138 
ServiceEntitlementException( int error, int httpStatus, String retryAfter, String message, Throwable cause)139     public ServiceEntitlementException(
140             int error, int httpStatus, String retryAfter, String message, Throwable cause) {
141         super(message, cause);
142         this.mError = error;
143         this.mHttpStatus = httpStatus;
144         this.mRetryAfter = retryAfter;
145     }
146 
147     /**
148      * Returns the error code. {@link #ERROR_UNKNOWN} if not been specified.
149      */
150     @ErrorCode
getErrorCode()151     public int getErrorCode() {
152         return mError;
153     }
154 
155     /**
156      * Returns the HTTP status code returned by entitlement server; {@link #HTTP_STATUS_UNSPECIFIED}
157      * if not been specified.
158      */
getHttpStatus()159     public int getHttpStatus() {
160         return mHttpStatus;
161     }
162 
163     /**
164      * Returns the "Retry-After" header in HTTP response, often set with HTTP status code 503; an
165      * empty string if unavailable.
166      *
167      * @return the HTTP-date or a number of seconds to delay, as defined in RFC 7231:
168      * <a href="https://tools.ietf.org/html/rfc7231#section-7.1.3">...</a>
169      */
getRetryAfter()170     public String getRetryAfter() {
171         return mRetryAfter;
172     }
173 }
174