blob: f6cae725160917e9c0f8f5c22c475ce17b63e700 [file] [log] [blame]
junyulai4c95b082018-12-27 17:25:29 +08001/*
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
17package android.net;
18
19import android.annotation.IntDef;
20import android.annotation.IntRange;
21import android.annotation.NonNull;
junyulai0835a1e2019-01-08 20:04:33 +080022import android.annotation.Nullable;
paulhu2f7c3452020-01-13 16:18:54 +080023import android.annotation.SystemApi;
junyulai070f9ff2019-01-16 20:23:34 +080024import android.os.Binder;
junyulai7e06ad42019-03-04 22:45:36 +080025import android.os.ParcelFileDescriptor;
junyulai070f9ff2019-01-16 20:23:34 +080026import android.os.RemoteException;
junyulai4c95b082018-12-27 17:25:29 +080027
junyulai7e06ad42019-03-04 22:45:36 +080028import java.io.IOException;
junyulai4c95b082018-12-27 17:25:29 +080029import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
31import java.util.concurrent.Executor;
32
33/**
34 * Allows applications to request that the system periodically send specific packets on their
35 * behalf, using hardware offload to save battery power.
36 *
37 * To request that the system send keepalives, call one of the methods that return a
38 * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
39 * passing in a non-null callback. If the {@link SocketKeepalive} is successfully
40 * started, the callback's {@code onStarted} method will be called. If an error occurs,
41 * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
42 * class.
43 *
44 * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
45 * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
46 * {@link SocketKeepalive.Callback#onError} if an error occurred.
junyulai4dca18a2019-04-17 15:22:46 +080047 *
Aaron Huangede0d502019-06-05 17:09:29 +080048 * For cellular, the device MUST support at least 1 keepalive slot.
49 *
50 * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with
junyulai4dca18a2019-04-17 15:22:46 +080051 * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
Aaron Huangede0d502019-06-05 17:09:29 +080052 * request. If it does, it MUST support at least 3 concurrent keepalive slots.
junyulai4c95b082018-12-27 17:25:29 +080053 */
54public abstract class SocketKeepalive implements AutoCloseable {
55 static final String TAG = "SocketKeepalive";
56
paulhu2f7c3452020-01-13 16:18:54 +080057 /**
lifr75764c82021-03-18 01:11:30 +080058 * Success. It indicates there is no error.
paulhu2f7c3452020-01-13 16:18:54 +080059 * @hide
60 */
61 @SystemApi
junyulai4c95b082018-12-27 17:25:29 +080062 public static final int SUCCESS = 0;
63
lifr75764c82021-03-18 01:11:30 +080064 /**
65 * No keepalive. This should only be internally as it indicates There is no keepalive.
66 * It should not propagate to applications.
67 * @hide
68 */
junyulai4c95b082018-12-27 17:25:29 +080069 public static final int NO_KEEPALIVE = -1;
70
lifr75764c82021-03-18 01:11:30 +080071 /**
72 * Data received.
73 * @hide
74 */
junyulai4c95b082018-12-27 17:25:29 +080075 public static final int DATA_RECEIVED = -2;
76
lifr75764c82021-03-18 01:11:30 +080077 /**
78 * The binder died.
79 * @hide
80 */
junyulai4c95b082018-12-27 17:25:29 +080081 public static final int BINDER_DIED = -10;
82
lifr75764c82021-03-18 01:11:30 +080083 /**
84 * The invalid network. It indicates the specified {@code Network} is not connected.
85 */
junyulai4c95b082018-12-27 17:25:29 +080086 public static final int ERROR_INVALID_NETWORK = -20;
lifr75764c82021-03-18 01:11:30 +080087
88 /**
89 * The invalid IP addresses. Indicates the specified IP addresses are invalid.
90 * For example, the specified source IP address is not configured on the
91 * specified {@code Network}.
92 */
junyulai4c95b082018-12-27 17:25:29 +080093 public static final int ERROR_INVALID_IP_ADDRESS = -21;
lifr75764c82021-03-18 01:11:30 +080094
95 /**
96 * The port is invalid.
97 */
junyulai4c95b082018-12-27 17:25:29 +080098 public static final int ERROR_INVALID_PORT = -22;
lifr75764c82021-03-18 01:11:30 +080099
100 /**
101 * The length is invalid (e.g. too long).
102 */
junyulai4c95b082018-12-27 17:25:29 +0800103 public static final int ERROR_INVALID_LENGTH = -23;
lifr75764c82021-03-18 01:11:30 +0800104
105 /**
106 * The interval is invalid (e.g. too short).
107 */
junyulai4c95b082018-12-27 17:25:29 +0800108 public static final int ERROR_INVALID_INTERVAL = -24;
lifr75764c82021-03-18 01:11:30 +0800109
110 /**
111 * The socket is invalid.
112 */
junyulai4c95b082018-12-27 17:25:29 +0800113 public static final int ERROR_INVALID_SOCKET = -25;
lifr75764c82021-03-18 01:11:30 +0800114
115 /**
116 * The socket is not idle.
117 */
junyulai4c95b082018-12-27 17:25:29 +0800118 public static final int ERROR_SOCKET_NOT_IDLE = -26;
lifr75764c82021-03-18 01:11:30 +0800119
junyulai75125f22019-09-03 18:51:04 +0800120 /**
121 * The stop reason is uninitialized. This should only be internally used as initial state
122 * of stop reason, instead of propagating to application.
123 * @hide
124 */
125 public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
junyulai4c95b082018-12-27 17:25:29 +0800126
lifr75764c82021-03-18 01:11:30 +0800127 /**
128 * The request is unsupported.
129 */
junyulai7e06ad42019-03-04 22:45:36 +0800130 public static final int ERROR_UNSUPPORTED = -30;
lifr75764c82021-03-18 01:11:30 +0800131
132 /**
133 * There was a hardware error.
134 */
junyulai4c95b082018-12-27 17:25:29 +0800135 public static final int ERROR_HARDWARE_ERROR = -31;
lifr75764c82021-03-18 01:11:30 +0800136
137 /**
138 * Resources are insufficient (e.g. all hardware slots are in use).
139 */
junyulai7e06ad42019-03-04 22:45:36 +0800140 public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
141
lifr75764c82021-03-18 01:11:30 +0800142 /**
143 * There was no such slot. This should only be internally as it indicates
144 * a programming error in the system server. It should not propagate to
145 * applications.
146 * @hide
147 */
148 @SystemApi
149 public static final int ERROR_NO_SUCH_SLOT = -33;
junyulai4c95b082018-12-27 17:25:29 +0800150
151 /** @hide */
152 @Retention(RetentionPolicy.SOURCE)
153 @IntDef(prefix = { "ERROR_" }, value = {
154 ERROR_INVALID_NETWORK,
155 ERROR_INVALID_IP_ADDRESS,
156 ERROR_INVALID_PORT,
157 ERROR_INVALID_LENGTH,
158 ERROR_INVALID_INTERVAL,
159 ERROR_INVALID_SOCKET,
lifr75764c82021-03-18 01:11:30 +0800160 ERROR_SOCKET_NOT_IDLE,
161 ERROR_NO_SUCH_SLOT
junyulai4c95b082018-12-27 17:25:29 +0800162 })
163 public @interface ErrorCode {}
164
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900165 /** @hide */
166 @Retention(RetentionPolicy.SOURCE)
167 @IntDef(value = {
168 SUCCESS,
169 ERROR_INVALID_LENGTH,
170 ERROR_UNSUPPORTED,
Chalard Jean691a34d2020-03-27 15:00:38 +0900171 ERROR_INSUFFICIENT_RESOURCES,
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900172 })
173 public @interface KeepaliveEvent {}
174
junyulai4c95b082018-12-27 17:25:29 +0800175 /**
176 * The minimum interval in seconds between keepalive packet transmissions.
177 *
178 * @hide
179 **/
180 public static final int MIN_INTERVAL_SEC = 10;
181
182 /**
183 * The maximum interval in seconds between keepalive packet transmissions.
184 *
185 * @hide
186 **/
187 public static final int MAX_INTERVAL_SEC = 3600;
188
junyulai011b1f12019-01-03 18:50:15 +0800189 /**
markchiene5591ce2018-12-27 22:49:51 +0800190 * An exception that embarks an error code.
191 * @hide
192 */
193 public static class ErrorCodeException extends Exception {
194 public final int error;
195 public ErrorCodeException(final int error, final Throwable e) {
196 super(e);
197 this.error = error;
198 }
199 public ErrorCodeException(final int error) {
200 this.error = error;
201 }
202 }
203
204 /**
205 * This socket is invalid.
206 * See the error code for details, and the optional cause.
207 * @hide
208 */
209 public static class InvalidSocketException extends ErrorCodeException {
210 public InvalidSocketException(final int error, final Throwable e) {
211 super(error, e);
212 }
213 public InvalidSocketException(final int error) {
214 super(error);
215 }
216 }
217
junyulai4c95b082018-12-27 17:25:29 +0800218 @NonNull final IConnectivityManager mService;
219 @NonNull final Network mNetwork;
junyulai7e06ad42019-03-04 22:45:36 +0800220 @NonNull final ParcelFileDescriptor mPfd;
junyulai070f9ff2019-01-16 20:23:34 +0800221 @NonNull final Executor mExecutor;
222 @NonNull final ISocketKeepaliveCallback mCallback;
223 // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
junyulai0835a1e2019-01-08 20:04:33 +0800224 @Nullable Integer mSlot;
junyulai4c95b082018-12-27 17:25:29 +0800225
226 SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
junyulai7e06ad42019-03-04 22:45:36 +0800227 @NonNull ParcelFileDescriptor pfd,
junyulai4c95b082018-12-27 17:25:29 +0800228 @NonNull Executor executor, @NonNull Callback callback) {
229 mService = service;
230 mNetwork = network;
junyulai7e06ad42019-03-04 22:45:36 +0800231 mPfd = pfd;
junyulai4c95b082018-12-27 17:25:29 +0800232 mExecutor = executor;
junyulai070f9ff2019-01-16 20:23:34 +0800233 mCallback = new ISocketKeepaliveCallback.Stub() {
junyulai4c95b082018-12-27 17:25:29 +0800234 @Override
junyulai070f9ff2019-01-16 20:23:34 +0800235 public void onStarted(int slot) {
lucaslinbe801382020-12-30 11:54:55 +0800236 final long token = Binder.clearCallingIdentity();
237 try {
238 mExecutor.execute(() -> {
239 mSlot = slot;
240 callback.onStarted();
241 });
242 } finally {
243 Binder.restoreCallingIdentity(token);
244 }
junyulai4c95b082018-12-27 17:25:29 +0800245 }
junyulai070f9ff2019-01-16 20:23:34 +0800246
247 @Override
248 public void onStopped() {
lucaslinbe801382020-12-30 11:54:55 +0800249 final long token = Binder.clearCallingIdentity();
250 try {
251 executor.execute(() -> {
252 mSlot = null;
253 callback.onStopped();
254 });
255 } finally {
256 Binder.restoreCallingIdentity(token);
257 }
junyulai070f9ff2019-01-16 20:23:34 +0800258 }
259
260 @Override
261 public void onError(int error) {
lucaslinbe801382020-12-30 11:54:55 +0800262 final long token = Binder.clearCallingIdentity();
263 try {
264 executor.execute(() -> {
265 mSlot = null;
266 callback.onError(error);
267 });
268 } finally {
269 Binder.restoreCallingIdentity(token);
270 }
junyulai070f9ff2019-01-16 20:23:34 +0800271 }
272
273 @Override
274 public void onDataReceived() {
lucaslinbe801382020-12-30 11:54:55 +0800275 final long token = Binder.clearCallingIdentity();
276 try {
277 executor.execute(() -> {
278 mSlot = null;
279 callback.onDataReceived();
280 });
281 } finally {
282 Binder.restoreCallingIdentity(token);
283 }
junyulai070f9ff2019-01-16 20:23:34 +0800284 }
285 };
junyulai4c95b082018-12-27 17:25:29 +0800286 }
287
288 /**
289 * Request that keepalive be started with the given {@code intervalSec}. See
junyulai070f9ff2019-01-16 20:23:34 +0800290 * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
291 * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
292 * thrown into the {@code executor}. This is typically not important to catch because the remote
293 * party is the system, so if it is not in shape to communicate through binder the system is
294 * probably going down anyway. If the caller cares regardless, it can use a custom
295 * {@link Executor} to catch the {@link RemoteException}.
junyulai4c95b082018-12-27 17:25:29 +0800296 *
297 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
298 * The interval should be between 10 seconds and 3600 seconds, otherwise
299 * {@link #ERROR_INVALID_INTERVAL} will be returned.
300 */
301 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
302 int intervalSec) {
303 startImpl(intervalSec);
304 }
305
306 abstract void startImpl(int intervalSec);
307
junyulai4c95b082018-12-27 17:25:29 +0800308 /**
309 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
310 * before using the object. See {@link SocketKeepalive}.
311 */
312 public final void stop() {
313 stopImpl();
314 }
315
316 abstract void stopImpl();
317
318 /**
319 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
320 * usable again if {@code close()} is called.
321 */
322 @Override
323 public final void close() {
324 stop();
junyulai7e06ad42019-03-04 22:45:36 +0800325 try {
326 mPfd.close();
327 } catch (IOException e) {
328 // Nothing much can be done.
329 }
junyulai4c95b082018-12-27 17:25:29 +0800330 }
331
332 /**
333 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
334 * {@link SocketKeepalive}.
335 */
336 public static class Callback {
337 /** The requested keepalive was successfully started. */
338 public void onStarted() {}
339 /** The keepalive was successfully stopped. */
340 public void onStopped() {}
341 /** An error occurred. */
342 public void onError(@ErrorCode int error) {}
junyulai070f9ff2019-01-16 20:23:34 +0800343 /** The keepalive on a TCP socket was stopped because the socket received data. This is
344 * never called for UDP sockets. */
junyulai4c95b082018-12-27 17:25:29 +0800345 public void onDataReceived() {}
346 }
347}