blob: 311126ec0a362b97f938ddfc5394ffc71ba04659 [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
chiachangwang9ef4ffe2023-01-18 01:19:27 +000019import static android.annotation.SystemApi.Client.PRIVILEGED_APPS;
20
junyulai4c95b082018-12-27 17:25:29 +080021import android.annotation.IntDef;
22import android.annotation.IntRange;
23import android.annotation.NonNull;
paulhu2f7c3452020-01-13 16:18:54 +080024import android.annotation.SystemApi;
junyulai070f9ff2019-01-16 20:23:34 +080025import android.os.Binder;
junyulai7e06ad42019-03-04 22:45:36 +080026import android.os.ParcelFileDescriptor;
junyulai070f9ff2019-01-16 20:23:34 +080027import android.os.RemoteException;
junyulai4c95b082018-12-27 17:25:29 +080028
junyulai7e06ad42019-03-04 22:45:36 +080029import java.io.IOException;
junyulai4c95b082018-12-27 17:25:29 +080030import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
32import java.util.concurrent.Executor;
33
34/**
35 * Allows applications to request that the system periodically send specific packets on their
36 * behalf, using hardware offload to save battery power.
37 *
38 * To request that the system send keepalives, call one of the methods that return a
39 * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
40 * passing in a non-null callback. If the {@link SocketKeepalive} is successfully
41 * started, the callback's {@code onStarted} method will be called. If an error occurs,
42 * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
43 * class.
44 *
45 * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
46 * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
47 * {@link SocketKeepalive.Callback#onError} if an error occurred.
junyulai4dca18a2019-04-17 15:22:46 +080048 *
Aaron Huangede0d502019-06-05 17:09:29 +080049 * For cellular, the device MUST support at least 1 keepalive slot.
50 *
51 * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with
junyulai4dca18a2019-04-17 15:22:46 +080052 * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
Aaron Huangede0d502019-06-05 17:09:29 +080053 * request. If it does, it MUST support at least 3 concurrent keepalive slots.
junyulai4c95b082018-12-27 17:25:29 +080054 */
55public abstract class SocketKeepalive implements AutoCloseable {
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +090056 /** @hide */
57 protected static final String TAG = "SocketKeepalive";
junyulai4c95b082018-12-27 17:25:29 +080058
paulhu2f7c3452020-01-13 16:18:54 +080059 /**
lifr75764c82021-03-18 01:11:30 +080060 * Success. It indicates there is no error.
paulhu2f7c3452020-01-13 16:18:54 +080061 * @hide
62 */
63 @SystemApi
junyulai4c95b082018-12-27 17:25:29 +080064 public static final int SUCCESS = 0;
65
lifr75764c82021-03-18 01:11:30 +080066 /**
Chalard Jeanbdb82822023-01-19 23:14:02 +090067 * Success when trying to suspend.
68 * @hide
69 */
70 public static final int SUCCESS_PAUSED = 1;
71
72 /**
lifr75764c82021-03-18 01:11:30 +080073 * No keepalive. This should only be internally as it indicates There is no keepalive.
74 * It should not propagate to applications.
75 * @hide
76 */
junyulai4c95b082018-12-27 17:25:29 +080077 public static final int NO_KEEPALIVE = -1;
78
lifr75764c82021-03-18 01:11:30 +080079 /**
80 * Data received.
81 * @hide
82 */
junyulai4c95b082018-12-27 17:25:29 +080083 public static final int DATA_RECEIVED = -2;
84
lifr75764c82021-03-18 01:11:30 +080085 /**
86 * The binder died.
87 * @hide
88 */
junyulai4c95b082018-12-27 17:25:29 +080089 public static final int BINDER_DIED = -10;
90
lifr75764c82021-03-18 01:11:30 +080091 /**
92 * The invalid network. It indicates the specified {@code Network} is not connected.
93 */
junyulai4c95b082018-12-27 17:25:29 +080094 public static final int ERROR_INVALID_NETWORK = -20;
lifr75764c82021-03-18 01:11:30 +080095
96 /**
97 * The invalid IP addresses. Indicates the specified IP addresses are invalid.
98 * For example, the specified source IP address is not configured on the
99 * specified {@code Network}.
100 */
junyulai4c95b082018-12-27 17:25:29 +0800101 public static final int ERROR_INVALID_IP_ADDRESS = -21;
lifr75764c82021-03-18 01:11:30 +0800102
103 /**
104 * The port is invalid.
105 */
junyulai4c95b082018-12-27 17:25:29 +0800106 public static final int ERROR_INVALID_PORT = -22;
lifr75764c82021-03-18 01:11:30 +0800107
108 /**
109 * The length is invalid (e.g. too long).
110 */
junyulai4c95b082018-12-27 17:25:29 +0800111 public static final int ERROR_INVALID_LENGTH = -23;
lifr75764c82021-03-18 01:11:30 +0800112
113 /**
114 * The interval is invalid (e.g. too short).
115 */
junyulai4c95b082018-12-27 17:25:29 +0800116 public static final int ERROR_INVALID_INTERVAL = -24;
lifr75764c82021-03-18 01:11:30 +0800117
118 /**
119 * The socket is invalid.
120 */
junyulai4c95b082018-12-27 17:25:29 +0800121 public static final int ERROR_INVALID_SOCKET = -25;
lifr75764c82021-03-18 01:11:30 +0800122
123 /**
124 * The socket is not idle.
125 */
junyulai4c95b082018-12-27 17:25:29 +0800126 public static final int ERROR_SOCKET_NOT_IDLE = -26;
lifr75764c82021-03-18 01:11:30 +0800127
junyulai75125f22019-09-03 18:51:04 +0800128 /**
129 * The stop reason is uninitialized. This should only be internally used as initial state
130 * of stop reason, instead of propagating to application.
131 * @hide
132 */
133 public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
junyulai4c95b082018-12-27 17:25:29 +0800134
lifr75764c82021-03-18 01:11:30 +0800135 /**
136 * The request is unsupported.
137 */
junyulai7e06ad42019-03-04 22:45:36 +0800138 public static final int ERROR_UNSUPPORTED = -30;
lifr75764c82021-03-18 01:11:30 +0800139
140 /**
141 * There was a hardware error.
142 */
junyulai4c95b082018-12-27 17:25:29 +0800143 public static final int ERROR_HARDWARE_ERROR = -31;
lifr75764c82021-03-18 01:11:30 +0800144
145 /**
146 * Resources are insufficient (e.g. all hardware slots are in use).
147 */
junyulai7e06ad42019-03-04 22:45:36 +0800148 public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
149
lifr75764c82021-03-18 01:11:30 +0800150 /**
151 * There was no such slot. This should only be internally as it indicates
152 * a programming error in the system server. It should not propagate to
153 * applications.
154 * @hide
155 */
156 @SystemApi
157 public static final int ERROR_NO_SUCH_SLOT = -33;
junyulai4c95b082018-12-27 17:25:29 +0800158
159 /** @hide */
160 @Retention(RetentionPolicy.SOURCE)
161 @IntDef(prefix = { "ERROR_" }, value = {
162 ERROR_INVALID_NETWORK,
163 ERROR_INVALID_IP_ADDRESS,
164 ERROR_INVALID_PORT,
165 ERROR_INVALID_LENGTH,
166 ERROR_INVALID_INTERVAL,
167 ERROR_INVALID_SOCKET,
lifr75764c82021-03-18 01:11:30 +0800168 ERROR_SOCKET_NOT_IDLE,
169 ERROR_NO_SUCH_SLOT
junyulai4c95b082018-12-27 17:25:29 +0800170 })
171 public @interface ErrorCode {}
172
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900173 /** @hide */
174 @Retention(RetentionPolicy.SOURCE)
175 @IntDef(value = {
176 SUCCESS,
177 ERROR_INVALID_LENGTH,
178 ERROR_UNSUPPORTED,
Chalard Jean691a34d2020-03-27 15:00:38 +0900179 ERROR_INSUFFICIENT_RESOURCES,
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900180 })
181 public @interface KeepaliveEvent {}
182
junyulai4c95b082018-12-27 17:25:29 +0800183 /**
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000184 * Whether the system automatically toggles keepalive when no TCP connection is open on the VPN.
185 *
186 * If this flag is present, the system will monitor the VPN(s) running on top of the specified
187 * network for open TCP connections. When no such connections are open, it will turn off the
188 * keepalives to conserve battery power. When there is at least one such connection it will
189 * turn on the keepalives to make sure functionality is preserved.
190 *
191 * This only works with {@link NattSocketKeepalive}.
192 * @hide
193 */
194 @SystemApi
195 public static final int FLAG_AUTOMATIC_ON_OFF = 1 << 0;
196
197 /** @hide */
198 @Retention(RetentionPolicy.SOURCE)
199 @IntDef(prefix = { "FLAG_"}, flag = true, value = {
200 FLAG_AUTOMATIC_ON_OFF
201 })
202 public @interface StartFlags {}
203
204 /**
junyulai4c95b082018-12-27 17:25:29 +0800205 * The minimum interval in seconds between keepalive packet transmissions.
206 *
207 * @hide
208 **/
209 public static final int MIN_INTERVAL_SEC = 10;
210
211 /**
212 * The maximum interval in seconds between keepalive packet transmissions.
213 *
214 * @hide
215 **/
216 public static final int MAX_INTERVAL_SEC = 3600;
217
junyulai011b1f12019-01-03 18:50:15 +0800218 /**
markchiene5591ce2018-12-27 22:49:51 +0800219 * An exception that embarks an error code.
220 * @hide
221 */
222 public static class ErrorCodeException extends Exception {
223 public final int error;
224 public ErrorCodeException(final int error, final Throwable e) {
225 super(e);
226 this.error = error;
227 }
228 public ErrorCodeException(final int error) {
229 this.error = error;
230 }
231 }
232
233 /**
234 * This socket is invalid.
235 * See the error code for details, and the optional cause.
236 * @hide
237 */
238 public static class InvalidSocketException extends ErrorCodeException {
239 public InvalidSocketException(final int error, final Throwable e) {
240 super(error, e);
241 }
242 public InvalidSocketException(final int error) {
243 super(error);
244 }
245 }
246
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900247 /** @hide */
248 @NonNull protected final IConnectivityManager mService;
249 /** @hide */
250 @NonNull protected final Network mNetwork;
251 /** @hide */
252 @NonNull protected final ParcelFileDescriptor mPfd;
253 /** @hide */
254 @NonNull protected final Executor mExecutor;
255 /** @hide */
256 @NonNull protected final ISocketKeepaliveCallback mCallback;
junyulai4c95b082018-12-27 17:25:29 +0800257
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900258 /** @hide */
259 public SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
junyulai7e06ad42019-03-04 22:45:36 +0800260 @NonNull ParcelFileDescriptor pfd,
junyulai4c95b082018-12-27 17:25:29 +0800261 @NonNull Executor executor, @NonNull Callback callback) {
262 mService = service;
263 mNetwork = network;
junyulai7e06ad42019-03-04 22:45:36 +0800264 mPfd = pfd;
junyulai4c95b082018-12-27 17:25:29 +0800265 mExecutor = executor;
junyulai070f9ff2019-01-16 20:23:34 +0800266 mCallback = new ISocketKeepaliveCallback.Stub() {
junyulai4c95b082018-12-27 17:25:29 +0800267 @Override
Chalard Jeanf0b261e2023-02-03 22:11:20 +0900268 public void onStarted() {
lucaslinbe801382020-12-30 11:54:55 +0800269 final long token = Binder.clearCallingIdentity();
270 try {
271 mExecutor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800272 callback.onStarted();
273 });
274 } finally {
275 Binder.restoreCallingIdentity(token);
276 }
junyulai4c95b082018-12-27 17:25:29 +0800277 }
junyulai070f9ff2019-01-16 20:23:34 +0800278
279 @Override
Chalard Jeanbdb82822023-01-19 23:14:02 +0900280 public void onResumed() {
281 final long token = Binder.clearCallingIdentity();
282 try {
283 mExecutor.execute(() -> {
284 callback.onResumed();
285 });
286 } finally {
287 Binder.restoreCallingIdentity(token);
288 }
289 }
290
291 @Override
junyulai070f9ff2019-01-16 20:23:34 +0800292 public void onStopped() {
lucaslinbe801382020-12-30 11:54:55 +0800293 final long token = Binder.clearCallingIdentity();
294 try {
295 executor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800296 callback.onStopped();
297 });
298 } finally {
299 Binder.restoreCallingIdentity(token);
300 }
junyulai070f9ff2019-01-16 20:23:34 +0800301 }
302
303 @Override
Chalard Jeanbdb82822023-01-19 23:14:02 +0900304 public void onPaused() {
305 final long token = Binder.clearCallingIdentity();
306 try {
307 executor.execute(() -> {
308 callback.onPaused();
309 });
310 } finally {
311 Binder.restoreCallingIdentity(token);
312 }
313 }
314
315 @Override
junyulai070f9ff2019-01-16 20:23:34 +0800316 public void onError(int error) {
lucaslinbe801382020-12-30 11:54:55 +0800317 final long token = Binder.clearCallingIdentity();
318 try {
319 executor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800320 callback.onError(error);
321 });
322 } finally {
323 Binder.restoreCallingIdentity(token);
324 }
junyulai070f9ff2019-01-16 20:23:34 +0800325 }
326
327 @Override
328 public void onDataReceived() {
lucaslinbe801382020-12-30 11:54:55 +0800329 final long token = Binder.clearCallingIdentity();
330 try {
331 executor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800332 callback.onDataReceived();
333 });
334 } finally {
335 Binder.restoreCallingIdentity(token);
336 }
junyulai070f9ff2019-01-16 20:23:34 +0800337 }
338 };
junyulai4c95b082018-12-27 17:25:29 +0800339 }
340
341 /**
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000342 * Request that keepalive be started with the given {@code intervalSec}.
343 *
344 * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an
345 * exception when invoking start or stop of the {@link SocketKeepalive}, a
346 * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the
347 * {@link Executor}. This is typically not important to catch because the remote party is
348 * the system, so if it is not in shape to communicate through binder the system is going
349 * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the
350 * {@link RuntimeException}.
junyulai4c95b082018-12-27 17:25:29 +0800351 *
352 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
353 * The interval should be between 10 seconds and 3600 seconds, otherwise
354 * {@link #ERROR_INVALID_INTERVAL} will be returned.
355 */
356 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
357 int intervalSec) {
chiachangwang676c84e2023-02-14 09:22:05 +0000358 startImpl(intervalSec, 0 /* flags */, null /* underpinnedNetwork */);
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000359 }
360
361 /**
362 * Request that keepalive be started with the given {@code intervalSec}.
363 *
364 * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an
365 * exception when invoking start or stop of the {@link SocketKeepalive}, a
366 * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the
367 * {@link Executor}. This is typically not important to catch because the remote party is
368 * the system, so if it is not in shape to communicate through binder the system is going
369 * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the
370 * {@link RuntimeException}.
371 *
372 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
373 * The interval should be between 10 seconds and 3600 seconds. Otherwise,
374 * the supplied {@link Callback} will see a call to
375 * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
376 * @param flags Flags to enable/disable available options on this keepalive.
chiachangwang676c84e2023-02-14 09:22:05 +0000377 * @param underpinnedNetwork The underpinned network of this keepalive.
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000378 * @hide
379 */
380 @SystemApi(client = PRIVILEGED_APPS)
381 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
chiachangwang676c84e2023-02-14 09:22:05 +0000382 int intervalSec, @StartFlags int flags, @NonNull Network underpinnedNetwork) {
383 startImpl(intervalSec, flags, underpinnedNetwork);
junyulai4c95b082018-12-27 17:25:29 +0800384 }
385
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900386 /** @hide */
chiachangwang676c84e2023-02-14 09:22:05 +0000387 protected abstract void startImpl(int intervalSec, @StartFlags int flags,
388 Network underpinnedNetwork);
junyulai4c95b082018-12-27 17:25:29 +0800389
junyulai4c95b082018-12-27 17:25:29 +0800390 /**
391 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
392 * before using the object. See {@link SocketKeepalive}.
393 */
394 public final void stop() {
395 stopImpl();
396 }
397
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900398 /** @hide */
399 protected abstract void stopImpl();
junyulai4c95b082018-12-27 17:25:29 +0800400
401 /**
402 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
403 * usable again if {@code close()} is called.
404 */
405 @Override
406 public final void close() {
407 stop();
junyulai7e06ad42019-03-04 22:45:36 +0800408 try {
409 mPfd.close();
410 } catch (IOException e) {
411 // Nothing much can be done.
412 }
junyulai4c95b082018-12-27 17:25:29 +0800413 }
414
415 /**
416 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
417 * {@link SocketKeepalive}.
418 */
419 public static class Callback {
420 /** The requested keepalive was successfully started. */
421 public void onStarted() {}
Chalard Jeanbdb82822023-01-19 23:14:02 +0900422 /**
423 * The keepalive was resumed by the system after being suspended.
424 * @hide
425 **/
426 public void onResumed() {}
junyulai4c95b082018-12-27 17:25:29 +0800427 /** The keepalive was successfully stopped. */
428 public void onStopped() {}
Chalard Jeanbdb82822023-01-19 23:14:02 +0900429 /**
430 * The keepalive was paused by the system because it's not necessary right now.
431 * @hide
432 **/
433 public void onPaused() {}
junyulai4c95b082018-12-27 17:25:29 +0800434 /** An error occurred. */
435 public void onError(@ErrorCode int error) {}
junyulai070f9ff2019-01-16 20:23:34 +0800436 /** The keepalive on a TCP socket was stopped because the socket received data. This is
437 * never called for UDP sockets. */
junyulai4c95b082018-12-27 17:25:29 +0800438 public void onDataReceived() {}
439 }
440}