blob: fb224fbe13187addf4d5b53d12ee01a34b44705d [file] [log] [blame]
junyulai48eac1d42018-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;
junyulai352dc2f2019-01-08 20:04:33 +080022import android.annotation.Nullable;
junyulai7c469172019-01-16 20:23:34 +080023import android.os.Binder;
junyulai0c666972019-03-04 22:45:36 +080024import android.os.ParcelFileDescriptor;
junyulai7c469172019-01-16 20:23:34 +080025import android.os.RemoteException;
junyulai48eac1d42018-12-27 17:25:29 +080026
junyulai0c666972019-03-04 22:45:36 +080027import java.io.IOException;
junyulai48eac1d42018-12-27 17:25:29 +080028import java.lang.annotation.Retention;
29import java.lang.annotation.RetentionPolicy;
30import java.util.concurrent.Executor;
31
32/**
33 * Allows applications to request that the system periodically send specific packets on their
34 * behalf, using hardware offload to save battery power.
35 *
36 * To request that the system send keepalives, call one of the methods that return a
37 * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
38 * passing in a non-null callback. If the {@link SocketKeepalive} is successfully
39 * started, the callback's {@code onStarted} method will be called. If an error occurs,
40 * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
41 * class.
42 *
43 * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
44 * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
45 * {@link SocketKeepalive.Callback#onError} if an error occurred.
junyulaia91094a2019-04-17 15:22:46 +080046 *
Aaron Huangc0de2832019-06-05 17:09:29 +080047 * For cellular, the device MUST support at least 1 keepalive slot.
48 *
49 * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with
junyulaia91094a2019-04-17 15:22:46 +080050 * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
Aaron Huangc0de2832019-06-05 17:09:29 +080051 * request. If it does, it MUST support at least 3 concurrent keepalive slots.
junyulai48eac1d42018-12-27 17:25:29 +080052 */
53public abstract class SocketKeepalive implements AutoCloseable {
54 static final String TAG = "SocketKeepalive";
55
56 /** @hide */
57 public static final int SUCCESS = 0;
58
59 /** @hide */
60 public static final int NO_KEEPALIVE = -1;
61
62 /** @hide */
63 public static final int DATA_RECEIVED = -2;
64
65 /** @hide */
66 public static final int BINDER_DIED = -10;
67
68 /** The specified {@code Network} is not connected. */
69 public static final int ERROR_INVALID_NETWORK = -20;
70 /** The specified IP addresses are invalid. For example, the specified source IP address is
71 * not configured on the specified {@code Network}. */
72 public static final int ERROR_INVALID_IP_ADDRESS = -21;
73 /** The requested port is invalid. */
74 public static final int ERROR_INVALID_PORT = -22;
75 /** The packet length is invalid (e.g., too long). */
76 public static final int ERROR_INVALID_LENGTH = -23;
77 /** The packet transmission interval is invalid (e.g., too short). */
78 public static final int ERROR_INVALID_INTERVAL = -24;
79 /** The target socket is invalid. */
80 public static final int ERROR_INVALID_SOCKET = -25;
81 /** The target socket is not idle. */
82 public static final int ERROR_SOCKET_NOT_IDLE = -26;
83
junyulai0c666972019-03-04 22:45:36 +080084 /** The device does not support this request. */
85 public static final int ERROR_UNSUPPORTED = -30;
86 /** @hide TODO: delete when telephony code has been updated. */
87 public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
junyulai48eac1d42018-12-27 17:25:29 +080088 /** The hardware returned an error. */
89 public static final int ERROR_HARDWARE_ERROR = -31;
junyulai0c666972019-03-04 22:45:36 +080090 /** The limitation of resource is reached. */
91 public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
92
junyulai48eac1d42018-12-27 17:25:29 +080093
94 /** @hide */
95 @Retention(RetentionPolicy.SOURCE)
96 @IntDef(prefix = { "ERROR_" }, value = {
97 ERROR_INVALID_NETWORK,
98 ERROR_INVALID_IP_ADDRESS,
99 ERROR_INVALID_PORT,
100 ERROR_INVALID_LENGTH,
101 ERROR_INVALID_INTERVAL,
102 ERROR_INVALID_SOCKET,
103 ERROR_SOCKET_NOT_IDLE
104 })
105 public @interface ErrorCode {}
106
107 /**
108 * The minimum interval in seconds between keepalive packet transmissions.
109 *
110 * @hide
111 **/
112 public static final int MIN_INTERVAL_SEC = 10;
113
114 /**
115 * The maximum interval in seconds between keepalive packet transmissions.
116 *
117 * @hide
118 **/
119 public static final int MAX_INTERVAL_SEC = 3600;
120
junyulai06835112019-01-03 18:50:15 +0800121 /**
markchien150e1912018-12-27 22:49:51 +0800122 * An exception that embarks an error code.
123 * @hide
124 */
125 public static class ErrorCodeException extends Exception {
126 public final int error;
127 public ErrorCodeException(final int error, final Throwable e) {
128 super(e);
129 this.error = error;
130 }
131 public ErrorCodeException(final int error) {
132 this.error = error;
133 }
134 }
135
136 /**
137 * This socket is invalid.
138 * See the error code for details, and the optional cause.
139 * @hide
140 */
141 public static class InvalidSocketException extends ErrorCodeException {
142 public InvalidSocketException(final int error, final Throwable e) {
143 super(error, e);
144 }
145 public InvalidSocketException(final int error) {
146 super(error);
147 }
148 }
149
junyulai48eac1d42018-12-27 17:25:29 +0800150 @NonNull final IConnectivityManager mService;
151 @NonNull final Network mNetwork;
junyulai0c666972019-03-04 22:45:36 +0800152 @NonNull final ParcelFileDescriptor mPfd;
junyulai7c469172019-01-16 20:23:34 +0800153 @NonNull final Executor mExecutor;
154 @NonNull final ISocketKeepaliveCallback mCallback;
155 // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
junyulai352dc2f2019-01-08 20:04:33 +0800156 @Nullable Integer mSlot;
junyulai48eac1d42018-12-27 17:25:29 +0800157
158 SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
junyulai0c666972019-03-04 22:45:36 +0800159 @NonNull ParcelFileDescriptor pfd,
junyulai48eac1d42018-12-27 17:25:29 +0800160 @NonNull Executor executor, @NonNull Callback callback) {
161 mService = service;
162 mNetwork = network;
junyulai0c666972019-03-04 22:45:36 +0800163 mPfd = pfd;
junyulai48eac1d42018-12-27 17:25:29 +0800164 mExecutor = executor;
junyulai7c469172019-01-16 20:23:34 +0800165 mCallback = new ISocketKeepaliveCallback.Stub() {
junyulai48eac1d42018-12-27 17:25:29 +0800166 @Override
junyulai7c469172019-01-16 20:23:34 +0800167 public void onStarted(int slot) {
168 Binder.withCleanCallingIdentity(() ->
169 mExecutor.execute(() -> {
170 mSlot = slot;
171 callback.onStarted();
172 }));
junyulai48eac1d42018-12-27 17:25:29 +0800173 }
junyulai7c469172019-01-16 20:23:34 +0800174
175 @Override
176 public void onStopped() {
177 Binder.withCleanCallingIdentity(() ->
178 executor.execute(() -> {
179 mSlot = null;
180 callback.onStopped();
181 }));
182 }
183
184 @Override
185 public void onError(int error) {
186 Binder.withCleanCallingIdentity(() ->
187 executor.execute(() -> {
188 mSlot = null;
189 callback.onError(error);
190 }));
191 }
192
193 @Override
194 public void onDataReceived() {
195 Binder.withCleanCallingIdentity(() ->
196 executor.execute(() -> {
197 mSlot = null;
198 callback.onDataReceived();
199 }));
200 }
201 };
junyulai48eac1d42018-12-27 17:25:29 +0800202 }
203
204 /**
205 * Request that keepalive be started with the given {@code intervalSec}. See
junyulai7c469172019-01-16 20:23:34 +0800206 * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
207 * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
208 * thrown into the {@code executor}. This is typically not important to catch because the remote
209 * party is the system, so if it is not in shape to communicate through binder the system is
210 * probably going down anyway. If the caller cares regardless, it can use a custom
211 * {@link Executor} to catch the {@link RemoteException}.
junyulai48eac1d42018-12-27 17:25:29 +0800212 *
213 * @param intervalSec The target interval in seconds between keepalive packet transmissions.
214 * The interval should be between 10 seconds and 3600 seconds, otherwise
215 * {@link #ERROR_INVALID_INTERVAL} will be returned.
216 */
217 public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
218 int intervalSec) {
219 startImpl(intervalSec);
220 }
221
222 abstract void startImpl(int intervalSec);
223
junyulai48eac1d42018-12-27 17:25:29 +0800224 /**
225 * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
226 * before using the object. See {@link SocketKeepalive}.
227 */
228 public final void stop() {
229 stopImpl();
230 }
231
232 abstract void stopImpl();
233
234 /**
235 * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
236 * usable again if {@code close()} is called.
237 */
238 @Override
239 public final void close() {
240 stop();
junyulai0c666972019-03-04 22:45:36 +0800241 try {
242 mPfd.close();
243 } catch (IOException e) {
244 // Nothing much can be done.
245 }
junyulai48eac1d42018-12-27 17:25:29 +0800246 }
247
248 /**
249 * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
250 * {@link SocketKeepalive}.
251 */
252 public static class Callback {
253 /** The requested keepalive was successfully started. */
254 public void onStarted() {}
255 /** The keepalive was successfully stopped. */
256 public void onStopped() {}
257 /** An error occurred. */
258 public void onError(@ErrorCode int error) {}
junyulai7c469172019-01-16 20:23:34 +0800259 /** The keepalive on a TCP socket was stopped because the socket received data. This is
260 * never called for UDP sockets. */
junyulai48eac1d42018-12-27 17:25:29 +0800261 public void onDataReceived() {}
262 }
263}