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

Commit 06c3ef13 authored by Erik Kline's avatar Erik Kline Committed by Etan Cohen
Browse files

Support timeouts for requestNetwork() invocations. [DO NOT MERGE]

Bug: 21414325
Change-Id: I08118be8e8cf92fc406d431e99a6c9191a863ff3
parent 009b1fcb
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -2221,7 +2221,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() {}
@@ -2294,6 +2295,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;
@@ -2458,7 +2479,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");
@@ -2472,7 +2493,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);
+88 −69
Original line number Diff line number Diff line
@@ -2321,17 +2321,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return true;
    }

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

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

    private void handleRemoveNetworkRequest(
            final NetworkRequestInfo nri, final int callingUid, final int whichCallback) {
        if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
                if (DBG) log("Attempt to release unowned NetworkRequest " + request);
            if (DBG) log("Attempt to release unowned NetworkRequest " + nri.request);
            return;
        }
            if (DBG) log("releasing NetworkRequest " + request);
        final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
        if (DBG) log("releasing NetworkRequest " + nri.request + " (" + logCallbackType + ")");
        nri.unlinkDeathRecipient();
            mNetworkRequests.remove(request);
            mNetworkRequestInfoLogs.log("RELEASE " + nri);
        mNetworkRequests.remove(nri.request);
        mNetworkRequestInfoLogs.log("RELEASE " + nri + " (" + logCallbackType + ")");
        if (nri.isRequest) {
            // Find all networks that are satisfying this request and remove the request
            // from their request lists.
@@ -2401,8 +2416,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                }
            }
        }
            callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
        }
        callCallbackForRequest(nri, null, whichCallback);
    }

    public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
@@ -2552,6 +2566,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;
+86 −1
Original line number Diff line number Diff line
@@ -960,7 +960,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        NONE,
        AVAILABLE,
        LOSING,
        LOST
        LOST,
        UNAVAILABLE
    }

    /**
@@ -990,6 +991,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
            mConditionVariable.open();
        }

        @Override
        public void onUnavailable() {
            assertEquals(CallbackState.NONE, mLastCallback);
            mLastCallback = CallbackState.UNAVAILABLE;
            mConditionVariable.open();
        }

        void expectCallback(CallbackState state) {
            waitFor(mConditionVariable);
            assertEquals(state, mLastCallback);
@@ -1352,6 +1360,83 @@ public class ConnectivityServiceTest extends AndroidTestCase {
                execptionCalled);
    }

    /**
     * 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);

        // 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
        try {
            Thread.sleep(15);
        } catch (InterruptedException e) {
        }
        networkCallback.expectCallback(CallbackState.UNAVAILABLE);

        // 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 };