blob: d007a9520cb58d1682088839c9df2b47fada5bc4 [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 /**
58 * No errors.
59 * @hide
60 */
61 @SystemApi
junyulai4c95b082018-12-27 17:25:29 +080062 public static final int SUCCESS = 0;
63
64 /** @hide */
65 public static final int NO_KEEPALIVE = -1;
66
67 /** @hide */
68 public static final int DATA_RECEIVED = -2;
69
70 /** @hide */
71 public static final int BINDER_DIED = -10;
72
73 /** The specified {@code Network} is not connected. */
74 public static final int ERROR_INVALID_NETWORK = -20;
75 /** The specified IP addresses are invalid. For example, the specified source IP address is
76 * not configured on the specified {@code Network}. */
77 public static final int ERROR_INVALID_IP_ADDRESS = -21;
78 /** The requested port is invalid. */
79 public static final int ERROR_INVALID_PORT = -22;
80 /** The packet length is invalid (e.g., too long). */
81 public static final int ERROR_INVALID_LENGTH = -23;
82 /** The packet transmission interval is invalid (e.g., too short). */
83 public static final int ERROR_INVALID_INTERVAL = -24;
84 /** The target socket is invalid. */
85 public static final int ERROR_INVALID_SOCKET = -25;
86 /** The target socket is not idle. */
87 public static final int ERROR_SOCKET_NOT_IDLE = -26;
junyulai75125f22019-09-03 18:51:04 +080088 /**
89 * The stop reason is uninitialized. This should only be internally used as initial state
90 * of stop reason, instead of propagating to application.
91 * @hide
92 */
93 public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
junyulai4c95b082018-12-27 17:25:29 +080094
junyulai7e06ad42019-03-04 22:45:36 +080095 /** The device does not support this request. */
96 public static final int ERROR_UNSUPPORTED = -30;
97 /** @hide TODO: delete when telephony code has been updated. */
98 public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
junyulai4c95b082018-12-27 17:25:29 +080099 /** The hardware returned an error. */
100 public static final int ERROR_HARDWARE_ERROR = -31;
junyulai7e06ad42019-03-04 22:45:36 +0800101 /** The limitation of resource is reached. */
102 public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
103
junyulai4c95b082018-12-27 17:25:29 +0800104
105 /** @hide */
106 @Retention(RetentionPolicy.SOURCE)
107 @IntDef(prefix = { "ERROR_" }, value = {
108 ERROR_INVALID_NETWORK,
109 ERROR_INVALID_IP_ADDRESS,
110 ERROR_INVALID_PORT,
111 ERROR_INVALID_LENGTH,
112 ERROR_INVALID_INTERVAL,
113 ERROR_INVALID_SOCKET,
114 ERROR_SOCKET_NOT_IDLE
115 })
116 public @interface ErrorCode {}
117
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900118 /** @hide */
119 @Retention(RetentionPolicy.SOURCE)
120 @IntDef(value = {
121 SUCCESS,
122 ERROR_INVALID_LENGTH,
123 ERROR_UNSUPPORTED,
Chalard Jean691a34d2020-03-27 15:00:38 +0900124 ERROR_INSUFFICIENT_RESOURCES,
125 ERROR_HARDWARE_UNSUPPORTED
Chalard Jeanf5d1bfd2020-03-24 23:16:35 +0900126 })
127 public @interface KeepaliveEvent {}
128
junyulai4c95b082018-12-27 17:25:29 +0800129 /**
130 * The minimum interval in seconds between keepalive packet transmissions.
131 *
132 * @hide
133 **/
134 public static final int MIN_INTERVAL_SEC = 10;
135
136 /**
137 * The maximum interval in seconds between keepalive packet transmissions.
138 *
139 * @hide
140 **/
141 public static final int MAX_INTERVAL_SEC = 3600;
142
junyulai011b1f12019-01-03 18:50:15 +0800143 /**
markchiene5591ce2018-12-27 22:49:51 +0800144 * An exception that embarks an error code.
145 * @hide
146 */
147 public static class ErrorCodeException extends Exception {
148 public final int error;
149 public ErrorCodeException(final int error, final Throwable e) {
150 super(e);
151 this.error = error;
152 }
153 public ErrorCodeException(final int error) {
154 this.error = error;
155 }
156 }
157
158 /**
159 * This socket is invalid.
160 * See the error code for details, and the optional cause.
161 * @hide
162 */
163 public static class InvalidSocketException extends ErrorCodeException {
164 public InvalidSocketException(final int error, final Throwable e) {
165 super(error, e);
166 }
167 public InvalidSocketException(final int error) {
168 super(error);
169 }
170 }
171
junyulai4c95b082018-12-27 17:25:29 +0800172 @NonNull final IConnectivityManager mService;
173 @NonNull final Network mNetwork;
junyulai7e06ad42019-03-04 22:45:36 +0800174 @NonNull final ParcelFileDescriptor mPfd;
junyulai070f9ff2019-01-16 20:23:34 +0800175 @NonNull final Executor mExecutor;
176 @NonNull final ISocketKeepaliveCallback mCallback;
177 // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
junyulai0835a1e2019-01-08 20:04:33 +0800178 @Nullable Integer mSlot;
junyulai4c95b082018-12-27 17:25:29 +0800179
180 SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
junyulai7e06ad42019-03-04 22:45:36 +0800181 @NonNull ParcelFileDescriptor pfd,
junyulai4c95b082018-12-27 17:25:29 +0800182 @NonNull Executor executor, @NonNull Callback callback) {
183 mService = service;
184 mNetwork = network;
junyulai7e06ad42019-03-04 22:45:36 +0800185 mPfd = pfd;
junyulai4c95b082018-12-27 17:25:29 +0800186 mExecutor = executor;
junyulai070f9ff2019-01-16 20:23:34 +0800187 mCallback = new ISocketKeepaliveCallback.Stub() {
junyulai4c95b082018-12-27 17:25:29 +0800188 @Override
junyulai070f9ff2019-01-16 20:23:34 +0800189 public void onStarted(int slot) {
lucaslinbe801382020-12-30 11:54:55 +0800190 final long token = Binder.clearCallingIdentity();
191 try {
192 mExecutor.execute(() -> {
193 mSlot = slot;
194 callback.onStarted();
195 });
196 } finally {
197 Binder.restoreCallingIdentity(token);
198 }
junyulai4c95b082018-12-27 17:25:29 +0800199 }
junyulai070f9ff2019-01-16 20:23:34 +0800200
201 @Override
202 public void onStopped() {
lucaslinbe801382020-12-30 11:54:55 +0800203 final long token = Binder.clearCallingIdentity();
204 try {
205 executor.execute(() -> {
206 mSlot = null;
207 callback.onStopped();
208 });
209 } finally {
210 Binder.restoreCallingIdentity(token);
211 }
junyulai070f9ff2019-01-16 20:23:34 +0800212 }
213
214 @Override
215 public void onError(int error) {
lucaslinbe801382020-12-30 11:54:55 +0800216 final long token = Binder.clearCallingIdentity();
217 try {
218 executor.execute(() -> {
219 mSlot = null;
220 callback.onError(error);
221 });
222 } finally {
223 Binder.restoreCallingIdentity(token);
224 }
junyulai070f9ff2019-01-16 20:23:34 +0800225 }
226
227 @Override
228 public void onDataReceived() {
lucaslinbe801382020-12-30 11:54:55 +0800229 final long token = Binder.clearCallingIdentity();
230 try {
231 executor.execute(() -> {
232 mSlot = null;
233 callback.onDataReceived();
234 });
235 } finally {
236 Binder.restoreCallingIdentity(token);
237 }
junyulai070f9ff2019-01-16 20:23:34 +0800238 }
239 };
junyulai4c95b082018-12-27 17:25:29 +0800240 }
241
242 /**
243 * Request that keepalive be started with the given {@code intervalSec}. See
junyulai070f9ff2019-01-16 20:23:34 +0800244 * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
245 * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
246 * thrown into the {@code executor}. This is typically not important to catch because the remote
247 * party is the system, so if it is not in shape to communicate through binder the system is
248 * probably going down anyway. If the caller cares regardless, it can use a custom
249 * {@link Executor} to catch the {@link RemoteException}.
junyulai4c95b082018-12-27 17:25:29 +0800250 *
251 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
252 * The interval should be between 10 seconds and 3600 seconds, otherwise
253 * {@link #ERROR_INVALID_INTERVAL} will be returned.
254 */
255 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
256 int intervalSec) {
257 startImpl(intervalSec);
258 }
259
260 abstract void startImpl(int intervalSec);
261
junyulai4c95b082018-12-27 17:25:29 +0800262 /**
263 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
264 * before using the object. See {@link SocketKeepalive}.
265 */
266 public final void stop() {
267 stopImpl();
268 }
269
270 abstract void stopImpl();
271
272 /**
273 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
274 * usable again if {@code close()} is called.
275 */
276 @Override
277 public final void close() {
278 stop();
junyulai7e06ad42019-03-04 22:45:36 +0800279 try {
280 mPfd.close();
281 } catch (IOException e) {
282 // Nothing much can be done.
283 }
junyulai4c95b082018-12-27 17:25:29 +0800284 }
285
286 /**
287 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
288 * {@link SocketKeepalive}.
289 */
290 public static class Callback {
291 /** The requested keepalive was successfully started. */
292 public void onStarted() {}
293 /** The keepalive was successfully stopped. */
294 public void onStopped() {}
295 /** An error occurred. */
296 public void onError(@ErrorCode int error) {}
junyulai070f9ff2019-01-16 20:23:34 +0800297 /** The keepalive on a TCP socket was stopped because the socket received data. This is
298 * never called for UDP sockets. */
junyulai4c95b082018-12-27 17:25:29 +0800299 public void onDataReceived() {}
300 }
301}