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

Commit e9e251fc authored by Erik Kline's avatar Erik Kline Committed by Lorenzo Colitti
Browse files

DO NOT MERGE: Support timeouts for requestNetwork() invocations.

(cherry-pick of 06c3ef13)
(cherry picked from commit 57faba9e)

Bug: 21414325

(cherry picked from commit 3841a48d)

Change-Id: I640c43315a071ecbf881e5ce898164915e0b787f
parent db5814ed
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -2606,7 +2606,8 @@ public class ConnectivityManager {

        /**
         * Called if no network is found in the given timeout time.  If no timeout is given,
         * this will not be called.
         * this will not be called. The associated {@link NetworkRequest} will have already
         * been removed and released, as if {@link #unregisterNetworkCallback} had been called.
         * @hide
         */
        public void onUnavailable() {}
@@ -2679,6 +2680,26 @@ public class ConnectivityManager {
    /** @hide */
    public static final int CALLBACK_RESUMED             = BASE + 12;

    /** @hide */
    public static String getCallbackName(int whichCallback) {
        switch (whichCallback) {
            case CALLBACK_PRECHECK:     return "CALLBACK_PRECHECK";
            case CALLBACK_AVAILABLE:    return "CALLBACK_AVAILABLE";
            case CALLBACK_LOSING:       return "CALLBACK_LOSING";
            case CALLBACK_LOST:         return "CALLBACK_LOST";
            case CALLBACK_UNAVAIL:      return "CALLBACK_UNAVAIL";
            case CALLBACK_CAP_CHANGED:  return "CALLBACK_CAP_CHANGED";
            case CALLBACK_IP_CHANGED:   return "CALLBACK_IP_CHANGED";
            case CALLBACK_RELEASED:     return "CALLBACK_RELEASED";
            case CALLBACK_EXIT:         return "CALLBACK_EXIT";
            case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
            case CALLBACK_SUSPENDED:    return "CALLBACK_SUSPENDED";
            case CALLBACK_RESUMED:      return "CALLBACK_RESUMED";
            default:
                return Integer.toString(whichCallback);
        }
    }

    private class CallbackHandler extends Handler {
        private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
        private final AtomicInteger mRefCount;
@@ -2845,7 +2866,7 @@ public class ConnectivityManager {
    private final static int REQUEST = 2;

    private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
            NetworkCallback networkCallback, int timeoutSec, int action,
            NetworkCallback networkCallback, int timeoutMs, int action,
            int legacyType) {
        if (networkCallback == null) {
            throw new IllegalArgumentException("null NetworkCallback");
@@ -2861,7 +2882,7 @@ public class ConnectivityManager {
                            new Messenger(sCallbackHandler), new Binder());
                } else {
                    networkCallback.networkRequest = mService.requestNetwork(need,
                            new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
                            new Messenger(sCallbackHandler), timeoutMs, new Binder(), legacyType);
                }
                if (networkCallback.networkRequest != null) {
                    sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
+23 −4
Original line number Diff line number Diff line
@@ -2605,14 +2605,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
                "request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED);
    }

    private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
        if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
                nri.request.requestId) == null) {
            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL);
        }
    }

    private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
        final NetworkRequestInfo nri = getNriForAppRequest(
                request, callingUid, "release NetworkRequest");
        if (nri == null) return;
        if (nri != null) {
            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED);
        }
    }

        if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request);
    private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) {
        final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
        if (VDBG || (DBG && nri.request.isRequest())) {
            log("releasing " + nri.request + " (" + logCallbackType + ")");
        }
        nri.unlinkDeathRecipient();
        mNetworkRequests.remove(request);
        mNetworkRequests.remove(nri.request);
        synchronized (mUidToNetworkRequestCount) {
            int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
            if (requests < 1) {
@@ -2706,7 +2720,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                }
            }
        }
        callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
        callCallbackForRequest(nri, null, whichCallback, 0);
    }

    @Override
@@ -2943,6 +2957,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    handleRegisterNetworkRequestWithIntent(msg);
                    break;
                }
                case EVENT_TIMEOUT_NETWORK_REQUEST: {
                    NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
                    handleTimedOutNetworkRequest(nri);
                    break;
                }
                case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
                    handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
                    break;
+80 −1
Original line number Diff line number Diff line
@@ -1086,7 +1086,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        NETWORK_CAPABILITIES,
        LINK_PROPERTIES,
        LOSING,
        LOST
        LOST,
        UNAVAILABLE
    }

    private static class CallbackInfo {
@@ -1134,6 +1135,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
            setLastCallback(CallbackState.AVAILABLE, network, null);
        }

        @Override
        public void onUnavailable() {
            setLastCallback(CallbackState.UNAVAILABLE, null, null);
        }

        @Override
        public void onLosing(Network network, int maxMsToLive) {
            setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
@@ -2291,6 +2297,79 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        mCm.unregisterNetworkCallback(defaultCallback);
    }

    /**
     * Validate that a satisfied network request does not trigger onUnavailable() once the
     * time-out period expires.
     */
    @SmallTest
    public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                NetworkCapabilities.TRANSPORT_WIFI).build();
        final TestNetworkCallback networkCallback = new TestNetworkCallback();
        mCm.requestNetwork(nr, networkCallback, 10);

        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(false);
        networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);

        // pass timeout and validate that UNAVAILABLE is not called
        try {
            Thread.sleep(15);
        } catch (InterruptedException e) {
        }
        networkCallback.assertNoCallback();
    }

    /**
     * Validate that when a time-out is specified for a network request the onUnavailable()
     * callback is called when time-out expires. Then validate that if network request is
     * (somehow) satisfied - the callback isn't called later.
     */
    @SmallTest
    public void testTimedoutNetworkRequest() {
        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                NetworkCapabilities.TRANSPORT_WIFI).build();
        final TestNetworkCallback networkCallback = new TestNetworkCallback();
        mCm.requestNetwork(nr, networkCallback, 10);

        // pass timeout and validate that UNAVAILABLE is called
        networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);

        // create a network satisfying request - validate that request not triggered
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(false);
        networkCallback.assertNoCallback();
    }

    /**
     * Validate that when a network request is unregistered (cancelled) the time-out for that
     * request doesn't trigger the onUnavailable() callback.
     */
    @SmallTest
    public void testTimedoutAfterUnregisteredNetworkRequest() {
        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                NetworkCapabilities.TRANSPORT_WIFI).build();
        final TestNetworkCallback networkCallback = new TestNetworkCallback();
        mCm.requestNetwork(nr, networkCallback, 10);

        // remove request
        mCm.unregisterNetworkCallback(networkCallback);

        // pass timeout and validate that no callbacks
        // Note: doesn't validate that nothing called from CS since even if called the CM already
        // unregisters the callback and won't pass it through!
        try {
            Thread.sleep(15);
        } catch (InterruptedException e) {
        }
        networkCallback.assertNoCallback();

        // create a network satisfying request - validate that request not triggered
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(false);
        networkCallback.assertNoCallback();
    }

    private static class TestKeepaliveCallback extends PacketKeepaliveCallback {

        public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };