summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/net/ConnectivityManager.java136
-rw-r--r--core/java/android/net/IConnectivityManager.aidl5
-rw-r--r--core/java/android/net/NetworkAgent.java90
3 files changed, 226 insertions, 5 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index dc8ff8f..86a50c6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1206,6 +1206,142 @@ public class ConnectivityManager {
return true;
}
+ /** @hide */
+ public static class PacketKeepaliveCallback {
+ /** The requested keepalive was successfully started. */
+ public void onStarted() {}
+ /** The keepalive was successfully stopped. */
+ public void onStopped() {}
+ /** An error occurred. */
+ public void onError(int error) {}
+ }
+
+ /**
+ * Allows applications to request that the system periodically send specific packets on their
+ * behalf, using hardware offload to save battery power.
+ *
+ * To request that the system send keepalives, call one of the methods that return a
+ * {@link ConnectivityManager.PacketKeepalive} object, such as {@link #startNattKeepalive},
+ * passing in a non-null callback. If the callback is successfully started, the callback's
+ * {@code onStarted} method will be called. If an error occurs, {@code onError} will be called,
+ * specifying one of the {@code ERROR_*} constants in this class.
+ *
+ * To stop an existing keepalive, call {@link stop}. The system will call {@code onStopped} if
+ * the operation was successfull or {@code onError} if an error occurred.
+ *
+ * @hide
+ */
+ public class PacketKeepalive {
+
+ private static final String TAG = "PacketKeepalive";
+
+ /** @hide */
+ public static final int SUCCESS = 0;
+
+ /** @hide */
+ public static final int NO_KEEPALIVE = -1;
+
+ /** @hide */
+ public static final int BINDER_DIED = -10;
+
+ /** The specified {@code Network} is not connected. */
+ public static final int ERROR_INVALID_NETWORK = -20;
+ /** The specified IP addresses are invalid. For example, the specified source IP address is
+ * not configured on the specified {@code Network}. */
+ public static final int ERROR_INVALID_IP_ADDRESS = -21;
+ /** The requested port is invalid. */
+ public static final int ERROR_INVALID_PORT = -22;
+ /** The packet length is invalid (e.g., too long). */
+ public static final int ERROR_INVALID_LENGTH = -23;
+ /** The packet transmission interval is invalid (e.g., too short). */
+ public static final int ERROR_INVALID_INTERVAL = -24;
+
+ /** The hardware does not support this request. */
+ public static final int ERROR_HARDWARE_UNSUPPORTED = -30;
+
+ public static final int NATT_PORT = 4500;
+
+ private final Network mNetwork;
+ private final PacketKeepaliveCallback mCallback;
+ private final Looper mLooper;
+ private final Messenger mMessenger;
+
+ private volatile Integer mSlot;
+
+ void stopLooper() {
+ mLooper.quit();
+ }
+
+ public void stop() {
+ try {
+ mService.stopKeepalive(mNetwork, mSlot);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error stopping packet keepalive: ", e);
+ stopLooper();
+ }
+ }
+
+ private PacketKeepalive(Network network, PacketKeepaliveCallback callback) {
+ checkNotNull(network, "network cannot be null");
+ checkNotNull(callback, "callback cannot be null");
+ mNetwork = network;
+ mCallback = callback;
+ HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mLooper = thread.getLooper();
+ mMessenger = new Messenger(new Handler(mLooper) {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case NetworkAgent.EVENT_PACKET_KEEPALIVE:
+ int error = message.arg2;
+ try {
+ if (error == SUCCESS) {
+ if (mSlot == null) {
+ mSlot = message.arg1;
+ mCallback.onStarted();
+ } else {
+ mSlot = null;
+ stopLooper();
+ mCallback.onStopped();
+ }
+ } else {
+ stopLooper();
+ mCallback.onError(error);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in keepalive callback(" + error + ")", e);
+ }
+ break;
+ default:
+ Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
+ break;
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Starts an IPsec NAT-T keepalive packet with the specified parameters.
+ *
+ * @hide
+ */
+ public PacketKeepalive startNattKeepalive(
+ Network network, int intervalSeconds, PacketKeepaliveCallback callback,
+ InetAddress srcAddr, int srcPort, InetAddress dstAddr) {
+ final PacketKeepalive k = new PacketKeepalive(network, callback);
+ try {
+ mService.startNattKeepalive(network, intervalSeconds, k.mMessenger, new Binder(),
+ srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error starting packet keepalive: ", e);
+ k.stopLooper();
+ return null;
+ }
+ return k;
+ }
+
/**
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface. An attempt to add a route that
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 46c28a6..d4dd669 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -160,4 +160,9 @@ interface IConnectivityManager
boolean setUnderlyingNetworksForVpn(in Network[] networks);
void factoryReset();
+
+ void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger,
+ in IBinder binder, String srcAddr, int srcPort, String dstAddr);
+
+ void stopKeepalive(in Network network, int slot);
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index e6fc1ea..85a584a 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -25,6 +25,7 @@ import android.util.Log;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
+import android.net.ConnectivityManager.PacketKeepalive;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -143,11 +144,46 @@ public abstract class NetworkAgent extends Handler {
*/
public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
- /** Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
* the underlying network connection for updated bandwidth information.
*/
public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent
+ * periodically on the given interval.
+ *
+ * arg1 = the slot number of the keepalive to start
+ * arg2 = interval in seconds
+ * obj = KeepalivePacketData object describing the data to be sent
+ *
+ * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
+ */
+ public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11;
+
+ /**
+ * Requests that the specified keepalive packet be stopped.
+ *
+ * arg1 = slot number of the keepalive to stop.
+ *
+ * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
+ */
+ public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive
+ * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous
+ * error notification.
+ *
+ * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to
+ * so that the app's PacketKeepaliveCallback methods can be called.
+ *
+ * arg1 = slot number of the keepalive
+ * arg2 = error code
+ */
+ public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
+
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null);
@@ -240,18 +276,41 @@ public abstract class NetworkAgent extends Handler {
}
case CMD_SAVE_ACCEPT_UNVALIDATED: {
saveAcceptUnvalidated(msg.arg1 != 0);
+ break;
+ }
+ case CMD_START_PACKET_KEEPALIVE: {
+ startPacketKeepalive(msg);
+ break;
+ }
+ case CMD_STOP_PACKET_KEEPALIVE: {
+ stopPacketKeepalive(msg);
+ break;
}
}
}
private void queueOrSendMessage(int what, Object obj) {
+ queueOrSendMessage(what, 0, 0, obj);
+ }
+
+ private void queueOrSendMessage(int what, int arg1, int arg2) {
+ queueOrSendMessage(what, arg1, arg2, null);
+ }
+
+ private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = arg1;
+ msg.arg2 = arg2;
+ msg.obj = obj;
+ queueOrSendMessage(msg);
+ }
+
+ private void queueOrSendMessage(Message msg) {
synchronized (mPreConnectedQueue) {
if (mAsyncChannel != null) {
- mAsyncChannel.sendMessage(what, obj);
+ mAsyncChannel.sendMessage(msg);
} else {
- Message msg = Message.obtain();
- msg.what = what;
- msg.obj = obj;
mPreConnectedQueue.add(msg);
}
}
@@ -365,6 +424,27 @@ public abstract class NetworkAgent extends Handler {
protected void saveAcceptUnvalidated(boolean accept) {
}
+ /**
+ * Requests that the network hardware send the specified packet at the specified interval.
+ */
+ protected void startPacketKeepalive(Message msg) {
+ onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+ }
+
+ /**
+ * Requests that the network hardware send the specified packet at the specified interval.
+ */
+ protected void stopPacketKeepalive(Message msg) {
+ onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+ }
+
+ /**
+ * Called by the network when a packet keepalive event occurs.
+ */
+ public void onPacketKeepaliveEvent(int slot, int reason) {
+ queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason);
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}