1 /*
2  * Copyright (C) 2023 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.net.thread;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import android.annotation.FlaggedApi;
22 import android.annotation.IntDef;
23 import android.annotation.NonNull;
24 import android.annotation.SystemApi;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 
29 /**
30  * Represents a Thread network specific failure.
31  *
32  * @hide
33  */
34 @FlaggedApi(ThreadNetworkFlags.FLAG_THREAD_ENABLED)
35 @SystemApi
36 public class ThreadNetworkException extends Exception {
37     /** @hide */
38     @Retention(RetentionPolicy.SOURCE)
39     @IntDef({
40         ERROR_INTERNAL_ERROR,
41         ERROR_ABORTED,
42         ERROR_TIMEOUT,
43         ERROR_UNAVAILABLE,
44         ERROR_BUSY,
45         ERROR_FAILED_PRECONDITION,
46         ERROR_UNSUPPORTED_CHANNEL,
47         ERROR_REJECTED_BY_PEER,
48         ERROR_RESPONSE_BAD_FORMAT,
49         ERROR_RESOURCE_EXHAUSTED,
50         ERROR_UNKNOWN,
51         ERROR_THREAD_DISABLED,
52     })
53     public @interface ErrorCode {}
54 
55     /**
56      * The operation failed because some invariants expected by the underlying system have been
57      * broken. This error code is reserved for serious errors. The caller can do nothing to recover
58      * from this error. A bugreport should be created and sent to the Android community if this
59      * error is ever returned.
60      */
61     public static final int ERROR_INTERNAL_ERROR = 1;
62 
63     /**
64      * The operation failed because concurrent operations are overriding this one. Retrying an
65      * aborted operation has the risk of aborting another ongoing operation again. So the caller
66      * should retry at a higher level where it knows there won't be race conditions.
67      */
68     public static final int ERROR_ABORTED = 2;
69 
70     /**
71      * The operation failed because a deadline expired before the operation could complete. This may
72      * be caused by connectivity unavailability and the caller can retry the same operation when the
73      * connectivity issue is fixed.
74      */
75     public static final int ERROR_TIMEOUT = 3;
76 
77     /**
78      * The operation failed because the service is currently unavailable and that this is most
79      * likely a transient condition. The caller can recover from this error by retrying with a
80      * back-off scheme. Note that it is not always safe to retry non-idempotent operations.
81      */
82     public static final int ERROR_UNAVAILABLE = 4;
83 
84     /**
85      * The operation failed because this device is currently busy processing concurrent requests.
86      * The caller may recover from this error when the current operations has been finished.
87      */
88     public static final int ERROR_BUSY = 5;
89 
90     /**
91      * The operation failed because required preconditions were not satisfied. For example, trying
92      * to schedule a network migration when this device is not attached will receive this error or
93      * enable Thread while User Resitration has disabled it. The caller should not retry the same
94      * operation before the precondition is satisfied.
95      */
96     public static final int ERROR_FAILED_PRECONDITION = 6;
97 
98     /**
99      * The operation was rejected because the specified channel is currently not supported by this
100      * device in this country. For example, trying to join or migrate to a network with channel
101      * which is not supported. The caller should should change the channel or return an error to the
102      * user if the channel cannot be changed.
103      */
104     public static final int ERROR_UNSUPPORTED_CHANNEL = 7;
105 
106     /**
107      * The operation failed because a request is rejected by the peer device. This happens because
108      * the peer device is not capable of processing the request, or a request from another device
109      * has already been accepted by the peer device. The caller may not be able to recover from this
110      * error by retrying the same operation.
111      */
112     public static final int ERROR_REJECTED_BY_PEER = 8;
113 
114     /**
115      * The operation failed because the received response is malformed. This is typically because
116      * the peer device is misbehaving. The caller may only recover from this error by retrying with
117      * a different peer device.
118      */
119     public static final int ERROR_RESPONSE_BAD_FORMAT = 9;
120 
121     /**
122      * The operation failed because some resource has been exhausted. For example, no enough
123      * allocated memory buffers, or maximum number of supported operations has been exceeded. The
124      * caller may retry and recover from this error when the resource has been freed.
125      */
126     public static final int ERROR_RESOURCE_EXHAUSTED = 10;
127 
128     /**
129      * The operation failed because of an unknown error in the system. This typically indicates that
130      * the caller doesn't understand error codes added in newer Android versions.
131      */
132     public static final int ERROR_UNKNOWN = 11;
133 
134     /**
135      * The operation failed because the Thread radio is disabled by {@link
136      * ThreadNetworkController#setEnabled}, airplane mode or device admin. The caller should retry
137      * only after Thread is enabled.
138      */
139     public static final int ERROR_THREAD_DISABLED = 12;
140 
141     /**
142      * The operation failed because it is not supported by the platform. For example, some platforms
143      * may not support setting the target power of each channel. The caller should not retry and may
144      * return an error to the user.
145      *
146      * @hide
147      */
148     public static final int ERROR_UNSUPPORTED_OPERATION = 13;
149 
150     private static final int ERROR_MIN = ERROR_INTERNAL_ERROR;
151     private static final int ERROR_MAX = ERROR_UNSUPPORTED_OPERATION;
152 
153     private final int mErrorCode;
154 
155     /**
156      * Creates a new {@link ThreadNetworkException} object with given error code and message.
157      *
158      * @throws IllegalArgumentException if {@code errorCode} is not a value in {@link #ERROR_}
159      * @throws NullPointerException if {@code message} is {@code null}
160      */
ThreadNetworkException(@rrorCode int errorCode, @NonNull String message)161     public ThreadNetworkException(@ErrorCode int errorCode, @NonNull String message) {
162         super(requireNonNull(message, "message cannot be null"));
163         if (errorCode < ERROR_MIN || errorCode > ERROR_MAX) {
164             throw new IllegalArgumentException(
165                     "errorCode cannot be "
166                             + errorCode
167                             + " (allowedRange = ["
168                             + ERROR_MIN
169                             + ", "
170                             + ERROR_MAX
171                             + "])");
172         }
173         this.mErrorCode = errorCode;
174     }
175 
176     /** Returns the error code. */
getErrorCode()177     public @ErrorCode int getErrorCode() {
178         return mErrorCode;
179     }
180 }
181