1 /* 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 17 package android.net; 18 19 import static android.annotation.SystemApi.Client.PRIVILEGED_APPS; 20 21 import android.annotation.IntDef; 22 import android.annotation.IntRange; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.os.Binder; 27 import android.os.ParcelFileDescriptor; 28 import android.os.RemoteException; 29 30 import java.io.IOException; 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.concurrent.Executor; 34 35 /** 36 * Allows applications to request that the system periodically send specific packets on their 37 * behalf, using hardware offload to save battery power. 38 * 39 * To request that the system send keepalives, call one of the methods that return a 40 * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive}, 41 * passing in a non-null callback. If the {@link SocketKeepalive} is successfully 42 * started, the callback's {@code onStarted} method will be called. If an error occurs, 43 * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this 44 * class. 45 * 46 * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call 47 * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or 48 * {@link SocketKeepalive.Callback#onError} if an error occurred. 49 * 50 * For cellular, the device MUST support at least 1 keepalive slot. 51 * 52 * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with 53 * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload 54 * request. If it does, it MUST support at least 3 concurrent keepalive slots. 55 */ 56 public abstract class SocketKeepalive implements AutoCloseable { 57 /** @hide */ 58 protected static final String TAG = "SocketKeepalive"; 59 60 /** 61 * Success. It indicates there is no error. 62 * @hide 63 */ 64 @SystemApi 65 public static final int SUCCESS = 0; 66 67 /** 68 * Success when trying to suspend. 69 * @hide 70 */ 71 public static final int SUCCESS_PAUSED = 1; 72 73 /** 74 * No keepalive. This should only be internally as it indicates There is no keepalive. 75 * It should not propagate to applications. 76 * @hide 77 */ 78 public static final int NO_KEEPALIVE = -1; 79 80 /** 81 * Data received. 82 * @hide 83 */ 84 public static final int DATA_RECEIVED = -2; 85 86 /** 87 * The binder died. 88 * @hide 89 */ 90 public static final int BINDER_DIED = -10; 91 92 /** 93 * The invalid network. It indicates the specified {@code Network} is not connected. 94 */ 95 public static final int ERROR_INVALID_NETWORK = -20; 96 97 /** 98 * The invalid IP addresses. Indicates the specified IP addresses are invalid. 99 * For example, the specified source IP address is not configured on the 100 * specified {@code Network}. 101 */ 102 public static final int ERROR_INVALID_IP_ADDRESS = -21; 103 104 /** 105 * The port is invalid. 106 */ 107 public static final int ERROR_INVALID_PORT = -22; 108 109 /** 110 * The length is invalid (e.g. too long). 111 */ 112 public static final int ERROR_INVALID_LENGTH = -23; 113 114 /** 115 * The interval is invalid (e.g. too short). 116 */ 117 public static final int ERROR_INVALID_INTERVAL = -24; 118 119 /** 120 * The socket is invalid. 121 */ 122 public static final int ERROR_INVALID_SOCKET = -25; 123 124 /** 125 * The socket is not idle. 126 */ 127 public static final int ERROR_SOCKET_NOT_IDLE = -26; 128 129 /** 130 * The stop reason is uninitialized. This should only be internally used as initial state 131 * of stop reason, instead of propagating to application. 132 * @hide 133 */ 134 public static final int ERROR_STOP_REASON_UNINITIALIZED = -27; 135 136 /** 137 * The request is unsupported. 138 */ 139 public static final int ERROR_UNSUPPORTED = -30; 140 141 /** 142 * There was a hardware error. 143 */ 144 public static final int ERROR_HARDWARE_ERROR = -31; 145 146 /** 147 * Resources are insufficient (e.g. all hardware slots are in use). 148 */ 149 public static final int ERROR_INSUFFICIENT_RESOURCES = -32; 150 151 /** 152 * There was no such slot, or no keepalive running on this slot. 153 * @hide 154 */ 155 @SystemApi 156 public static final int ERROR_NO_SUCH_SLOT = -33; 157 158 /** @hide */ 159 @Retention(RetentionPolicy.SOURCE) 160 @IntDef(prefix = { "ERROR_" }, value = { 161 ERROR_INVALID_NETWORK, 162 ERROR_INVALID_IP_ADDRESS, 163 ERROR_INVALID_PORT, 164 ERROR_INVALID_LENGTH, 165 ERROR_INVALID_INTERVAL, 166 ERROR_INVALID_SOCKET, 167 ERROR_SOCKET_NOT_IDLE, 168 ERROR_NO_SUCH_SLOT 169 }) 170 public @interface ErrorCode {} 171 172 /** @hide */ 173 @Retention(RetentionPolicy.SOURCE) 174 @IntDef(value = { 175 SUCCESS, 176 ERROR_INVALID_LENGTH, 177 ERROR_UNSUPPORTED, 178 ERROR_INSUFFICIENT_RESOURCES, 179 }) 180 public @interface KeepaliveEvent {} 181 182 /** 183 * Whether the system automatically toggles keepalive when no TCP connection is open on the VPN. 184 * 185 * If this flag is present, the system will monitor the VPN(s) running on top of the specified 186 * network for open TCP connections. When no such connections are open, it will turn off the 187 * keepalives to conserve battery power. When there is at least one such connection it will 188 * turn on the keepalives to make sure functionality is preserved. 189 * 190 * This only works with {@link NattSocketKeepalive}. 191 * @hide 192 */ 193 @SystemApi 194 public static final int FLAG_AUTOMATIC_ON_OFF = 1 << 0; 195 196 /** @hide */ 197 @Retention(RetentionPolicy.SOURCE) 198 @IntDef(prefix = { "FLAG_"}, flag = true, value = { 199 FLAG_AUTOMATIC_ON_OFF 200 }) 201 public @interface StartFlags {} 202 203 /** 204 * The minimum interval in seconds between keepalive packet transmissions. 205 * 206 * @hide 207 **/ 208 public static final int MIN_INTERVAL_SEC = 10; 209 210 /** 211 * The maximum interval in seconds between keepalive packet transmissions. 212 * 213 * @hide 214 **/ 215 public static final int MAX_INTERVAL_SEC = 3600; 216 217 /** 218 * An exception that embarks an error code. 219 * @hide 220 */ 221 public static class ErrorCodeException extends Exception { 222 public final int error; ErrorCodeException(final int error, final Throwable e)223 public ErrorCodeException(final int error, final Throwable e) { 224 super(e); 225 this.error = error; 226 } ErrorCodeException(final int error)227 public ErrorCodeException(final int error) { 228 this.error = error; 229 } 230 } 231 232 /** 233 * This socket is invalid. 234 * See the error code for details, and the optional cause. 235 * @hide 236 */ 237 public static class InvalidSocketException extends ErrorCodeException { InvalidSocketException(final int error, final Throwable e)238 public InvalidSocketException(final int error, final Throwable e) { 239 super(error, e); 240 } InvalidSocketException(final int error)241 public InvalidSocketException(final int error) { 242 super(error); 243 } 244 } 245 246 /** @hide */ 247 @NonNull protected final IConnectivityManager mService; 248 /** @hide */ 249 @NonNull protected final Network mNetwork; 250 /** @hide */ 251 @NonNull protected final ParcelFileDescriptor mPfd; 252 /** @hide */ 253 @NonNull protected final Executor mExecutor; 254 /** @hide */ 255 @NonNull protected final ISocketKeepaliveCallback mCallback; 256 257 /** @hide */ SocketKeepalive(@onNull IConnectivityManager service, @NonNull Network network, @NonNull ParcelFileDescriptor pfd, @NonNull Executor executor, @NonNull Callback callback)258 public SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network, 259 @NonNull ParcelFileDescriptor pfd, 260 @NonNull Executor executor, @NonNull Callback callback) { 261 mService = service; 262 mNetwork = network; 263 mPfd = pfd; 264 mExecutor = executor; 265 mCallback = new ISocketKeepaliveCallback.Stub() { 266 @Override 267 public void onStarted() { 268 final long token = Binder.clearCallingIdentity(); 269 try { 270 mExecutor.execute(() -> { 271 callback.onStarted(); 272 }); 273 } finally { 274 Binder.restoreCallingIdentity(token); 275 } 276 } 277 278 @Override 279 public void onResumed() { 280 final long token = Binder.clearCallingIdentity(); 281 try { 282 mExecutor.execute(() -> { 283 callback.onResumed(); 284 }); 285 } finally { 286 Binder.restoreCallingIdentity(token); 287 } 288 } 289 290 @Override 291 public void onStopped() { 292 final long token = Binder.clearCallingIdentity(); 293 try { 294 executor.execute(() -> { 295 callback.onStopped(); 296 }); 297 } finally { 298 Binder.restoreCallingIdentity(token); 299 } 300 } 301 302 @Override 303 public void onPaused() { 304 final long token = Binder.clearCallingIdentity(); 305 try { 306 executor.execute(() -> { 307 callback.onPaused(); 308 }); 309 } finally { 310 Binder.restoreCallingIdentity(token); 311 } 312 } 313 314 @Override 315 public void onError(int error) { 316 final long token = Binder.clearCallingIdentity(); 317 try { 318 executor.execute(() -> { 319 callback.onError(error); 320 }); 321 } finally { 322 Binder.restoreCallingIdentity(token); 323 } 324 } 325 326 @Override 327 public void onDataReceived() { 328 final long token = Binder.clearCallingIdentity(); 329 try { 330 executor.execute(() -> { 331 callback.onDataReceived(); 332 }); 333 } finally { 334 Binder.restoreCallingIdentity(token); 335 } 336 } 337 }; 338 } 339 340 /** 341 * Request that keepalive be started with the given {@code intervalSec}. 342 * 343 * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an 344 * exception when invoking start or stop of the {@link SocketKeepalive}, a 345 * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the 346 * {@link Executor}. This is typically not important to catch because the remote party is 347 * the system, so if it is not in shape to communicate through binder the system is going 348 * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the 349 * {@link RuntimeException}. 350 * 351 * @param intervalSec The target interval in seconds between keepalive packet transmissions. 352 * The interval should be between 10 seconds and 3600 seconds, otherwise 353 * {@link #ERROR_INVALID_INTERVAL} will be returned. 354 */ start(@ntRangefrom = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) int intervalSec)355 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) 356 int intervalSec) { 357 startImpl(intervalSec, 0 /* flags */, null /* underpinnedNetwork */); 358 } 359 360 /** 361 * Request that keepalive be started with the given {@code intervalSec}. 362 * 363 * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an 364 * exception when invoking start or stop of the {@link SocketKeepalive}, a 365 * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the 366 * {@link Executor}. This is typically not important to catch because the remote party is 367 * the system, so if it is not in shape to communicate through binder the system is going 368 * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the 369 * {@link RuntimeException}. 370 * 371 * @param intervalSec The target interval in seconds between keepalive packet transmissions. 372 * The interval should be between 10 seconds and 3600 seconds. Otherwise, 373 * the supplied {@link Callback} will see a call to 374 * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}. 375 * @param flags Flags to enable/disable available options on this keepalive. 376 * @param underpinnedNetwork an optional network running over mNetwork that this 377 * keepalive is intended to keep up, e.g. an IPSec 378 * tunnel running over mNetwork. 379 * @hide 380 */ 381 @SystemApi(client = PRIVILEGED_APPS) start(@ntRangefrom = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) int intervalSec, @StartFlags int flags, @Nullable Network underpinnedNetwork)382 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) 383 int intervalSec, @StartFlags int flags, @Nullable Network underpinnedNetwork) { 384 startImpl(intervalSec, flags, underpinnedNetwork); 385 } 386 387 /** @hide */ startImpl(int intervalSec, @StartFlags int flags, Network underpinnedNetwork)388 protected abstract void startImpl(int intervalSec, @StartFlags int flags, 389 Network underpinnedNetwork); 390 391 /** 392 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped} 393 * before using the object. See {@link SocketKeepalive}. 394 */ stop()395 public final void stop() { 396 stopImpl(); 397 } 398 399 /** @hide */ stopImpl()400 protected abstract void stopImpl(); 401 402 /** 403 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be 404 * usable again if {@code close()} is called. 405 */ 406 @Override close()407 public final void close() { 408 stop(); 409 try { 410 mPfd.close(); 411 } catch (IOException e) { 412 // Nothing much can be done. 413 } 414 } 415 416 /** 417 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See 418 * {@link SocketKeepalive}. 419 */ 420 public static class Callback { 421 /** The requested keepalive was successfully started. */ onStarted()422 public void onStarted() {} 423 /** 424 * The keepalive was resumed by the system after being suspended. 425 * @hide 426 **/ onResumed()427 public void onResumed() {} 428 /** The keepalive was successfully stopped. */ onStopped()429 public void onStopped() {} 430 /** 431 * The keepalive was paused by the system because it's not necessary right now. 432 * @hide 433 **/ onPaused()434 public void onPaused() {} 435 /** An error occurred. */ onError(@rrorCode int error)436 public void onError(@ErrorCode int error) {} 437 /** The keepalive on a TCP socket was stopped because the socket received data. This is 438 * never called for UDP sockets. */ onDataReceived()439 public void onDataReceived() {} 440 } 441 } 442