blob: 2911ce7afb30ffd99851554d95cebd1d1b741c2c [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 /**
67 * No keepalive. This should only be internally as it indicates There is no keepalive.
68 * It should not propagate to applications.
69 * @hide
70 */
junyulai4c95b082018-12-27 17:25:29 +080071 public static final int NO_KEEPALIVE = -1;
72
lifr75764c82021-03-18 01:11:30 +080073 /**
74 * Data received.
75 * @hide
76 */
junyulai4c95b082018-12-27 17:25:29 +080077 public static final int DATA_RECEIVED = -2;
78
lifr75764c82021-03-18 01:11:30 +080079 /**
80 * The binder died.
81 * @hide
82 */
junyulai4c95b082018-12-27 17:25:29 +080083 public static final int BINDER_DIED = -10;
84
lifr75764c82021-03-18 01:11:30 +080085 /**
86 * The invalid network. It indicates the specified {@code Network} is not connected.
87 */
junyulai4c95b082018-12-27 17:25:29 +080088 public static final int ERROR_INVALID_NETWORK = -20;
lifr75764c82021-03-18 01:11:30 +080089
90 /**
91 * The invalid IP addresses. Indicates the specified IP addresses are invalid.
92 * For example, the specified source IP address is not configured on the
93 * specified {@code Network}.
94 */
junyulai4c95b082018-12-27 17:25:29 +080095 public static final int ERROR_INVALID_IP_ADDRESS = -21;
lifr75764c82021-03-18 01:11:30 +080096
97 /**
98 * The port is invalid.
99 */
junyulai4c95b082018-12-27 17:25:29 +0800100 public static final int ERROR_INVALID_PORT = -22;
lifr75764c82021-03-18 01:11:30 +0800101
102 /**
103 * The length is invalid (e.g. too long).
104 */
junyulai4c95b082018-12-27 17:25:29 +0800105 public static final int ERROR_INVALID_LENGTH = -23;
lifr75764c82021-03-18 01:11:30 +0800106
107 /**
108 * The interval is invalid (e.g. too short).
109 */
junyulai4c95b082018-12-27 17:25:29 +0800110 public static final int ERROR_INVALID_INTERVAL = -24;
lifr75764c82021-03-18 01:11:30 +0800111
112 /**
113 * The socket is invalid.
114 */
junyulai4c95b082018-12-27 17:25:29 +0800115 public static final int ERROR_INVALID_SOCKET = -25;
lifr75764c82021-03-18 01:11:30 +0800116
117 /**
118 * The socket is not idle.
119 */
junyulai4c95b082018-12-27 17:25:29 +0800120 public static final int ERROR_SOCKET_NOT_IDLE = -26;
lifr75764c82021-03-18 01:11:30 +0800121
junyulai75125f22019-09-03 18:51:04 +0800122 /**
123 * The stop reason is uninitialized. This should only be internally used as initial state
124 * of stop reason, instead of propagating to application.
125 * @hide
126 */
127 public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
junyulai4c95b082018-12-27 17:25:29 +0800128
lifr75764c82021-03-18 01:11:30 +0800129 /**
130 * The request is unsupported.
131 */
junyulai7e06ad42019-03-04 22:45:36 +0800132 public static final int ERROR_UNSUPPORTED = -30;
lifr75764c82021-03-18 01:11:30 +0800133
134 /**
135 * There was a hardware error.
136 */
junyulai4c95b082018-12-27 17:25:29 +0800137 public static final int ERROR_HARDWARE_ERROR = -31;
lifr75764c82021-03-18 01:11:30 +0800138
139 /**
140 * Resources are insufficient (e.g. all hardware slots are in use).
141 */
junyulai7e06ad42019-03-04 22:45:36 +0800142 public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
143
lifr75764c82021-03-18 01:11:30 +0800144 /**
145 * There was no such slot. This should only be internally as it indicates
146 * a programming error in the system server. It should not propagate to
147 * applications.
148 * @hide
149 */
150 @SystemApi
151 public static final int ERROR_NO_SUCH_SLOT = -33;
junyulai4c95b082018-12-27 17:25:29 +0800152
153 /** @hide */
154 @Retention(RetentionPolicy.SOURCE)
155 @IntDef(prefix = { "ERROR_" }, value = {
156 ERROR_INVALID_NETWORK,
157 ERROR_INVALID_IP_ADDRESS,
158 ERROR_INVALID_PORT,
159 ERROR_INVALID_LENGTH,
160 ERROR_INVALID_INTERVAL,
161 ERROR_INVALID_SOCKET,
lifr75764c82021-03-18 01:11:30 +0800162 ERROR_SOCKET_NOT_IDLE,
163 ERROR_NO_SUCH_SLOT
junyulai4c95b082018-12-27 17:25:29 +0800164 })
165 public @interface ErrorCode {}
166
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900167 /** @hide */
168 @Retention(RetentionPolicy.SOURCE)
169 @IntDef(value = {
170 SUCCESS,
171 ERROR_INVALID_LENGTH,
172 ERROR_UNSUPPORTED,
Chalard Jean691a34d2020-03-27 15:00:38 +0900173 ERROR_INSUFFICIENT_RESOURCES,
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900174 })
175 public @interface KeepaliveEvent {}
176
junyulai4c95b082018-12-27 17:25:29 +0800177 /**
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000178 * Whether the system automatically toggles keepalive when no TCP connection is open on the VPN.
179 *
180 * If this flag is present, the system will monitor the VPN(s) running on top of the specified
181 * network for open TCP connections. When no such connections are open, it will turn off the
182 * keepalives to conserve battery power. When there is at least one such connection it will
183 * turn on the keepalives to make sure functionality is preserved.
184 *
185 * This only works with {@link NattSocketKeepalive}.
186 * @hide
187 */
188 @SystemApi
189 public static final int FLAG_AUTOMATIC_ON_OFF = 1 << 0;
190
191 /** @hide */
192 @Retention(RetentionPolicy.SOURCE)
193 @IntDef(prefix = { "FLAG_"}, flag = true, value = {
194 FLAG_AUTOMATIC_ON_OFF
195 })
196 public @interface StartFlags {}
197
198 /**
junyulai4c95b082018-12-27 17:25:29 +0800199 * The minimum interval in seconds between keepalive packet transmissions.
200 *
201 * @hide
202 **/
203 public static final int MIN_INTERVAL_SEC = 10;
204
205 /**
206 * The maximum interval in seconds between keepalive packet transmissions.
207 *
208 * @hide
209 **/
210 public static final int MAX_INTERVAL_SEC = 3600;
211
junyulai011b1f12019-01-03 18:50:15 +0800212 /**
markchiene5591ce2018-12-27 22:49:51 +0800213 * An exception that embarks an error code.
214 * @hide
215 */
216 public static class ErrorCodeException extends Exception {
217 public final int error;
218 public ErrorCodeException(final int error, final Throwable e) {
219 super(e);
220 this.error = error;
221 }
222 public ErrorCodeException(final int error) {
223 this.error = error;
224 }
225 }
226
227 /**
228 * This socket is invalid.
229 * See the error code for details, and the optional cause.
230 * @hide
231 */
232 public static class InvalidSocketException extends ErrorCodeException {
233 public InvalidSocketException(final int error, final Throwable e) {
234 super(error, e);
235 }
236 public InvalidSocketException(final int error) {
237 super(error);
238 }
239 }
240
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900241 /** @hide */
242 @NonNull protected final IConnectivityManager mService;
243 /** @hide */
244 @NonNull protected final Network mNetwork;
245 /** @hide */
246 @NonNull protected final ParcelFileDescriptor mPfd;
247 /** @hide */
248 @NonNull protected final Executor mExecutor;
249 /** @hide */
250 @NonNull protected final ISocketKeepaliveCallback mCallback;
junyulai4c95b082018-12-27 17:25:29 +0800251
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900252 /** @hide */
253 public SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
junyulai7e06ad42019-03-04 22:45:36 +0800254 @NonNull ParcelFileDescriptor pfd,
junyulai4c95b082018-12-27 17:25:29 +0800255 @NonNull Executor executor, @NonNull Callback callback) {
256 mService = service;
257 mNetwork = network;
junyulai7e06ad42019-03-04 22:45:36 +0800258 mPfd = pfd;
junyulai4c95b082018-12-27 17:25:29 +0800259 mExecutor = executor;
junyulai070f9ff2019-01-16 20:23:34 +0800260 mCallback = new ISocketKeepaliveCallback.Stub() {
junyulai4c95b082018-12-27 17:25:29 +0800261 @Override
Chalard Jeanf0b261e2023-02-03 22:11:20 +0900262 public void onStarted() {
lucaslinbe801382020-12-30 11:54:55 +0800263 final long token = Binder.clearCallingIdentity();
264 try {
265 mExecutor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800266 callback.onStarted();
267 });
268 } finally {
269 Binder.restoreCallingIdentity(token);
270 }
junyulai4c95b082018-12-27 17:25:29 +0800271 }
junyulai070f9ff2019-01-16 20:23:34 +0800272
273 @Override
274 public void onStopped() {
lucaslinbe801382020-12-30 11:54:55 +0800275 final long token = Binder.clearCallingIdentity();
276 try {
277 executor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800278 callback.onStopped();
279 });
280 } finally {
281 Binder.restoreCallingIdentity(token);
282 }
junyulai070f9ff2019-01-16 20:23:34 +0800283 }
284
285 @Override
286 public void onError(int error) {
lucaslinbe801382020-12-30 11:54:55 +0800287 final long token = Binder.clearCallingIdentity();
288 try {
289 executor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800290 callback.onError(error);
291 });
292 } finally {
293 Binder.restoreCallingIdentity(token);
294 }
junyulai070f9ff2019-01-16 20:23:34 +0800295 }
296
297 @Override
298 public void onDataReceived() {
lucaslinbe801382020-12-30 11:54:55 +0800299 final long token = Binder.clearCallingIdentity();
300 try {
301 executor.execute(() -> {
lucaslinbe801382020-12-30 11:54:55 +0800302 callback.onDataReceived();
303 });
304 } finally {
305 Binder.restoreCallingIdentity(token);
306 }
junyulai070f9ff2019-01-16 20:23:34 +0800307 }
308 };
junyulai4c95b082018-12-27 17:25:29 +0800309 }
310
311 /**
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000312 * Request that keepalive be started with the given {@code intervalSec}.
313 *
314 * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an
315 * exception when invoking start or stop of the {@link SocketKeepalive}, a
316 * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the
317 * {@link Executor}. This is typically not important to catch because the remote party is
318 * the system, so if it is not in shape to communicate through binder the system is going
319 * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the
320 * {@link RuntimeException}.
junyulai4c95b082018-12-27 17:25:29 +0800321 *
322 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
323 * The interval should be between 10 seconds and 3600 seconds, otherwise
324 * {@link #ERROR_INVALID_INTERVAL} will be returned.
325 */
326 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
327 int intervalSec) {
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000328 startImpl(intervalSec, 0 /* flags */);
329 }
330
331 /**
332 * Request that keepalive be started with the given {@code intervalSec}.
333 *
334 * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an
335 * exception when invoking start or stop of the {@link SocketKeepalive}, a
336 * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the
337 * {@link Executor}. This is typically not important to catch because the remote party is
338 * the system, so if it is not in shape to communicate through binder the system is going
339 * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the
340 * {@link RuntimeException}.
341 *
342 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
343 * The interval should be between 10 seconds and 3600 seconds. Otherwise,
344 * the supplied {@link Callback} will see a call to
345 * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
346 * @param flags Flags to enable/disable available options on this keepalive.
347 * @hide
348 */
349 @SystemApi(client = PRIVILEGED_APPS)
350 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
351 int intervalSec, @StartFlags int flags) {
352 startImpl(intervalSec, flags);
junyulai4c95b082018-12-27 17:25:29 +0800353 }
354
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900355 /** @hide */
chiachangwang9ef4ffe2023-01-18 01:19:27 +0000356 protected abstract void startImpl(int intervalSec, @StartFlags int flags);
junyulai4c95b082018-12-27 17:25:29 +0800357
junyulai4c95b082018-12-27 17:25:29 +0800358 /**
359 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
360 * before using the object. See {@link SocketKeepalive}.
361 */
362 public final void stop() {
363 stopImpl();
364 }
365
Remi NGUYEN VANe55a88d2022-04-20 15:59:16 +0900366 /** @hide */
367 protected abstract void stopImpl();
junyulai4c95b082018-12-27 17:25:29 +0800368
369 /**
370 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
371 * usable again if {@code close()} is called.
372 */
373 @Override
374 public final void close() {
375 stop();
junyulai7e06ad42019-03-04 22:45:36 +0800376 try {
377 mPfd.close();
378 } catch (IOException e) {
379 // Nothing much can be done.
380 }
junyulai4c95b082018-12-27 17:25:29 +0800381 }
382
383 /**
384 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
385 * {@link SocketKeepalive}.
386 */
387 public static class Callback {
388 /** The requested keepalive was successfully started. */
389 public void onStarted() {}
390 /** The keepalive was successfully stopped. */
391 public void onStopped() {}
392 /** An error occurred. */
393 public void onError(@ErrorCode int error) {}
junyulai070f9ff2019-01-16 20:23:34 +0800394 /** The keepalive on a TCP socket was stopped because the socket received data. This is
395 * never called for UDP sockets. */
junyulai4c95b082018-12-27 17:25:29 +0800396 public void onDataReceived() {}
397 }
398}