blob: 57cf5e378216341f9cc76c079d01f5bef2aecead [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 {
Remi NGUYEN VAN53eb35c2022-04-20 15:59:16 +090055 /** @hide */
56 protected static final String TAG = "SocketKeepalive";
junyulai4c95b082018-12-27 17:25:29 +080057
paulhu2f7c3452020-01-13 16:18:54 +080058 /**
lifr75764c82021-03-18 01:11:30 +080059 * Success. It indicates there is no error.
paulhu2f7c3452020-01-13 16:18:54 +080060 * @hide
61 */
62 @SystemApi
junyulai4c95b082018-12-27 17:25:29 +080063 public static final int SUCCESS = 0;
64
lifr75764c82021-03-18 01:11:30 +080065 /**
66 * No keepalive. This should only be internally as it indicates There is no keepalive.
67 * It should not propagate to applications.
68 * @hide
69 */
junyulai4c95b082018-12-27 17:25:29 +080070 public static final int NO_KEEPALIVE = -1;
71
lifr75764c82021-03-18 01:11:30 +080072 /**
73 * Data received.
74 * @hide
75 */
junyulai4c95b082018-12-27 17:25:29 +080076 public static final int DATA_RECEIVED = -2;
77
lifr75764c82021-03-18 01:11:30 +080078 /**
79 * The binder died.
80 * @hide
81 */
junyulai4c95b082018-12-27 17:25:29 +080082 public static final int BINDER_DIED = -10;
83
lifr75764c82021-03-18 01:11:30 +080084 /**
85 * The invalid network. It indicates the specified {@code Network} is not connected.
86 */
junyulai4c95b082018-12-27 17:25:29 +080087 public static final int ERROR_INVALID_NETWORK = -20;
lifr75764c82021-03-18 01:11:30 +080088
89 /**
90 * The invalid IP addresses. Indicates the specified IP addresses are invalid.
91 * For example, the specified source IP address is not configured on the
92 * specified {@code Network}.
93 */
junyulai4c95b082018-12-27 17:25:29 +080094 public static final int ERROR_INVALID_IP_ADDRESS = -21;
lifr75764c82021-03-18 01:11:30 +080095
96 /**
97 * The port is invalid.
98 */
junyulai4c95b082018-12-27 17:25:29 +080099 public static final int ERROR_INVALID_PORT = -22;
lifr75764c82021-03-18 01:11:30 +0800100
101 /**
102 * The length is invalid (e.g. too long).
103 */
junyulai4c95b082018-12-27 17:25:29 +0800104 public static final int ERROR_INVALID_LENGTH = -23;
lifr75764c82021-03-18 01:11:30 +0800105
106 /**
107 * The interval is invalid (e.g. too short).
108 */
junyulai4c95b082018-12-27 17:25:29 +0800109 public static final int ERROR_INVALID_INTERVAL = -24;
lifr75764c82021-03-18 01:11:30 +0800110
111 /**
112 * The socket is invalid.
113 */
junyulai4c95b082018-12-27 17:25:29 +0800114 public static final int ERROR_INVALID_SOCKET = -25;
lifr75764c82021-03-18 01:11:30 +0800115
116 /**
117 * The socket is not idle.
118 */
junyulai4c95b082018-12-27 17:25:29 +0800119 public static final int ERROR_SOCKET_NOT_IDLE = -26;
lifr75764c82021-03-18 01:11:30 +0800120
junyulai75125f22019-09-03 18:51:04 +0800121 /**
122 * The stop reason is uninitialized. This should only be internally used as initial state
123 * of stop reason, instead of propagating to application.
124 * @hide
125 */
126 public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
junyulai4c95b082018-12-27 17:25:29 +0800127
lifr75764c82021-03-18 01:11:30 +0800128 /**
129 * The request is unsupported.
130 */
junyulai7e06ad42019-03-04 22:45:36 +0800131 public static final int ERROR_UNSUPPORTED = -30;
lifr75764c82021-03-18 01:11:30 +0800132
133 /**
134 * There was a hardware error.
135 */
junyulai4c95b082018-12-27 17:25:29 +0800136 public static final int ERROR_HARDWARE_ERROR = -31;
lifr75764c82021-03-18 01:11:30 +0800137
138 /**
139 * Resources are insufficient (e.g. all hardware slots are in use).
140 */
junyulai7e06ad42019-03-04 22:45:36 +0800141 public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
142
lifr75764c82021-03-18 01:11:30 +0800143 /**
144 * There was no such slot. This should only be internally as it indicates
145 * a programming error in the system server. It should not propagate to
146 * applications.
147 * @hide
148 */
149 @SystemApi
150 public static final int ERROR_NO_SUCH_SLOT = -33;
junyulai4c95b082018-12-27 17:25:29 +0800151
152 /** @hide */
153 @Retention(RetentionPolicy.SOURCE)
154 @IntDef(prefix = { "ERROR_" }, value = {
155 ERROR_INVALID_NETWORK,
156 ERROR_INVALID_IP_ADDRESS,
157 ERROR_INVALID_PORT,
158 ERROR_INVALID_LENGTH,
159 ERROR_INVALID_INTERVAL,
160 ERROR_INVALID_SOCKET,
lifr75764c82021-03-18 01:11:30 +0800161 ERROR_SOCKET_NOT_IDLE,
162 ERROR_NO_SUCH_SLOT
junyulai4c95b082018-12-27 17:25:29 +0800163 })
164 public @interface ErrorCode {}
165
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900166 /** @hide */
167 @Retention(RetentionPolicy.SOURCE)
168 @IntDef(value = {
169 SUCCESS,
170 ERROR_INVALID_LENGTH,
171 ERROR_UNSUPPORTED,
Chalard Jean691a34d2020-03-27 15:00:38 +0900172 ERROR_INSUFFICIENT_RESOURCES,
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900173 })
174 public @interface KeepaliveEvent {}
175
junyulai4c95b082018-12-27 17:25:29 +0800176 /**
177 * The minimum interval in seconds between keepalive packet transmissions.
178 *
179 * @hide
180 **/
181 public static final int MIN_INTERVAL_SEC = 10;
182
183 /**
184 * The maximum interval in seconds between keepalive packet transmissions.
185 *
186 * @hide
187 **/
188 public static final int MAX_INTERVAL_SEC = 3600;
189
junyulai011b1f12019-01-03 18:50:15 +0800190 /**
markchiene5591ce2018-12-27 22:49:51 +0800191 * An exception that embarks an error code.
192 * @hide
193 */
194 public static class ErrorCodeException extends Exception {
195 public final int error;
196 public ErrorCodeException(final int error, final Throwable e) {
197 super(e);
198 this.error = error;
199 }
200 public ErrorCodeException(final int error) {
201 this.error = error;
202 }
203 }
204
205 /**
206 * This socket is invalid.
207 * See the error code for details, and the optional cause.
208 * @hide
209 */
210 public static class InvalidSocketException extends ErrorCodeException {
211 public InvalidSocketException(final int error, final Throwable e) {
212 super(error, e);
213 }
214 public InvalidSocketException(final int error) {
215 super(error);
216 }
217 }
218
Remi NGUYEN VAN53eb35c2022-04-20 15:59:16 +0900219 /** @hide */
220 @NonNull protected final IConnectivityManager mService;
221 /** @hide */
222 @NonNull protected final Network mNetwork;
223 /** @hide */
224 @NonNull protected final ParcelFileDescriptor mPfd;
225 /** @hide */
226 @NonNull protected final Executor mExecutor;
227 /** @hide */
228 @NonNull protected final ISocketKeepaliveCallback mCallback;
junyulai070f9ff2019-01-16 20:23:34 +0800229 // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
Remi NGUYEN VAN53eb35c2022-04-20 15:59:16 +0900230 /** @hide */
231 @Nullable protected Integer mSlot;
junyulai4c95b082018-12-27 17:25:29 +0800232
Remi NGUYEN VAN53eb35c2022-04-20 15:59:16 +0900233 /** @hide */
234 public SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
junyulai7e06ad42019-03-04 22:45:36 +0800235 @NonNull ParcelFileDescriptor pfd,
junyulai4c95b082018-12-27 17:25:29 +0800236 @NonNull Executor executor, @NonNull Callback callback) {
237 mService = service;
238 mNetwork = network;
junyulai7e06ad42019-03-04 22:45:36 +0800239 mPfd = pfd;
junyulai4c95b082018-12-27 17:25:29 +0800240 mExecutor = executor;
junyulai070f9ff2019-01-16 20:23:34 +0800241 mCallback = new ISocketKeepaliveCallback.Stub() {
junyulai4c95b082018-12-27 17:25:29 +0800242 @Override
junyulai070f9ff2019-01-16 20:23:34 +0800243 public void onStarted(int slot) {
lucaslinbe801382020-12-30 11:54:55 +0800244 final long token = Binder.clearCallingIdentity();
245 try {
246 mExecutor.execute(() -> {
247 mSlot = slot;
248 callback.onStarted();
249 });
250 } finally {
251 Binder.restoreCallingIdentity(token);
252 }
junyulai4c95b082018-12-27 17:25:29 +0800253 }
junyulai070f9ff2019-01-16 20:23:34 +0800254
255 @Override
256 public void onStopped() {
lucaslinbe801382020-12-30 11:54:55 +0800257 final long token = Binder.clearCallingIdentity();
258 try {
259 executor.execute(() -> {
260 mSlot = null;
261 callback.onStopped();
262 });
263 } finally {
264 Binder.restoreCallingIdentity(token);
265 }
junyulai070f9ff2019-01-16 20:23:34 +0800266 }
267
268 @Override
269 public void onError(int error) {
lucaslinbe801382020-12-30 11:54:55 +0800270 final long token = Binder.clearCallingIdentity();
271 try {
272 executor.execute(() -> {
273 mSlot = null;
274 callback.onError(error);
275 });
276 } finally {
277 Binder.restoreCallingIdentity(token);
278 }
junyulai070f9ff2019-01-16 20:23:34 +0800279 }
280
281 @Override
282 public void onDataReceived() {
lucaslinbe801382020-12-30 11:54:55 +0800283 final long token = Binder.clearCallingIdentity();
284 try {
285 executor.execute(() -> {
286 mSlot = null;
287 callback.onDataReceived();
288 });
289 } finally {
290 Binder.restoreCallingIdentity(token);
291 }
junyulai070f9ff2019-01-16 20:23:34 +0800292 }
293 };
junyulai4c95b082018-12-27 17:25:29 +0800294 }
295
296 /**
297 * Request that keepalive be started with the given {@code intervalSec}. See
junyulai070f9ff2019-01-16 20:23:34 +0800298 * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
299 * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
300 * thrown into the {@code executor}. This is typically not important to catch because the remote
301 * party is the system, so if it is not in shape to communicate through binder the system is
302 * probably going down anyway. If the caller cares regardless, it can use a custom
303 * {@link Executor} to catch the {@link RemoteException}.
junyulai4c95b082018-12-27 17:25:29 +0800304 *
305 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
306 * The interval should be between 10 seconds and 3600 seconds, otherwise
307 * {@link #ERROR_INVALID_INTERVAL} will be returned.
308 */
309 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
310 int intervalSec) {
311 startImpl(intervalSec);
312 }
313
Remi NGUYEN VAN53eb35c2022-04-20 15:59:16 +0900314 /** @hide */
315 protected abstract void startImpl(int intervalSec);
junyulai4c95b082018-12-27 17:25:29 +0800316
junyulai4c95b082018-12-27 17:25:29 +0800317 /**
318 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
319 * before using the object. See {@link SocketKeepalive}.
320 */
321 public final void stop() {
322 stopImpl();
323 }
324
Remi NGUYEN VAN53eb35c2022-04-20 15:59:16 +0900325 /** @hide */
326 protected abstract void stopImpl();
junyulai4c95b082018-12-27 17:25:29 +0800327
328 /**
329 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
330 * usable again if {@code close()} is called.
331 */
332 @Override
333 public final void close() {
334 stop();
junyulai7e06ad42019-03-04 22:45:36 +0800335 try {
336 mPfd.close();
337 } catch (IOException e) {
338 // Nothing much can be done.
339 }
junyulai4c95b082018-12-27 17:25:29 +0800340 }
341
342 /**
343 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
344 * {@link SocketKeepalive}.
345 */
346 public static class Callback {
347 /** The requested keepalive was successfully started. */
348 public void onStarted() {}
349 /** The keepalive was successfully stopped. */
350 public void onStopped() {}
351 /** An error occurred. */
352 public void onError(@ErrorCode int error) {}
junyulai070f9ff2019-01-16 20:23:34 +0800353 /** The keepalive on a TCP socket was stopped because the socket received data. This is
354 * never called for UDP sockets. */
junyulai4c95b082018-12-27 17:25:29 +0800355 public void onDataReceived() {}
356 }
357}