Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8bf977d5 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Prerepa Viswanadham
Browse files

ConnectivityManager API for for packet keepalives.

Bug: 21405946
Change-Id: Ie1f8f8bee684fe2bb1092a9f1bc9f5dc29b1defc
parent 260a36d1
Loading
Loading
Loading
Loading
+136 −0
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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);
}
+85 −5
Original line number Diff line number Diff line
@@ -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) {
        synchronized (mPreConnectedQueue) {
            if (mAsyncChannel != null) {
                mAsyncChannel.sendMessage(what, obj);
            } else {
        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(msg);
            } else {
                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);
    }
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ LOCAL_SRC_FILES += \
    java/com/android/server/EventLogTags.logtags \
    java/com/android/server/am/EventLogTags.logtags

LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_JAVA_LIBRARIES := services.net telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update

include $(BUILD_STATIC_JAVA_LIBRARY)
+56 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
@@ -117,6 +118,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
@@ -399,6 +401,8 @@ public class ConnectivityService extends IConnectivityManager.Stub

    TelephonyManager mTelephonyManager;

    private KeepaliveTracker mKeepaliveTracker;

    // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
    private final static int MIN_NET_ID = 100; // some reserved marks
    private final static int MAX_NET_ID = 65535;
@@ -764,6 +768,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);

        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);

        mKeepaliveTracker = new KeepaliveTracker(mHandler);
    }

    private NetworkRequest createInternetRequestForTransport(int transportType) {
@@ -1449,6 +1455,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
                "ConnectivityService");
    }

    private void enforceKeepalivePermission() {
        mContext.enforceCallingPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
    }

    public void sendConnectedBroadcast(NetworkInfo info) {
        enforceConnectivityInternalPermission();
        sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
@@ -1840,10 +1850,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
                pw.println(", last requested never");
            }
        }
        pw.println();

        pw.println();
        mTethering.dump(fd, pw, args);

        pw.println();
        mKeepaliveTracker.dump(pw);

        if (mInetLog != null && mInetLog.size() > 0) {
            pw.println();
            pw.println("Inet condition reports:");
@@ -2010,6 +2023,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    nai.networkMisc.acceptUnvalidated = (boolean) msg.obj;
                    break;
                }
                case NetworkAgent.EVENT_PACKET_KEEPALIVE: {
                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
                    if (nai == null) {
                        loge("EVENT_PACKET_KEEPALIVE from unknown NetworkAgent");
                        break;
                    }
                    mKeepaliveTracker.handleEventPacketKeepalive(nai, msg);
                    break;
                }
                case NetworkMonitor.EVENT_NETWORK_TESTED: {
                    NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
                    if (isLiveNetworkAgent(nai, "EVENT_NETWORK_TESTED")) {
@@ -2148,6 +2170,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
            }
            notifyIfacesChanged();
            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
            mKeepaliveTracker.handleStopAllKeepalives(nai,
                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
            mNetworkAgentInfos.remove(msg.replyTo);
            updateClat(null, nai.linkProperties, nai);
@@ -2509,6 +2533,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    handleMobileDataAlwaysOn();
                    break;
                }
                // Sent by KeepaliveTracker to process an app request on the state machine thread.
                case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
                    mKeepaliveTracker.handleStartKeepalive(msg);
                    break;
                }
                // Sent by KeepaliveTracker to process an app request on the state machine thread.
                case NetworkAgent.CMD_STOP_PACKET_KEEPALIVE: {
                    NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj);
                    int slot = msg.arg1;
                    int reason = msg.arg2;
                    mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
                    break;
                }
                case EVENT_SYSTEM_READY: {
                    for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
                        nai.networkMonitor.systemReady = true;
@@ -3863,6 +3900,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
            notifyIfacesChanged();
            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
        }

        mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
    }

    private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo nai) {
@@ -4662,6 +4701,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return success;
    }

    @Override
    public void startNattKeepalive(Network network, int intervalSeconds, Messenger messenger,
            IBinder binder, String srcAddr, int srcPort, String dstAddr) {
        enforceKeepalivePermission();
        mKeepaliveTracker.startNattKeepalive(
                getNetworkAgentInfoForNetwork(network),
                intervalSeconds, messenger, binder,
                srcAddr, srcPort, dstAddr, ConnectivityManager.PacketKeepalive.NATT_PORT);
    }

    @Override
    public void stopKeepalive(Network network, int slot) {
        mHandler.sendMessage(mHandler.obtainMessage(
                NetworkAgent.CMD_STOP_PACKET_KEEPALIVE, slot, PacketKeepalive.SUCCESS, network));
    }

    @Override
    public void factoryReset() {
        enforceConnectivityInternalPermission();
Loading