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

Commit 917b275d authored by Paul Jensen's avatar Paul Jensen Committed by Android Git Automerger
Browse files

am 06287d1c: am 9a2314b0: am 682fd6ae: am a991c66c: Merge "Fix missing onLost...

am 06287d1c: am 9a2314b0: am 682fd6ae: am a991c66c: Merge "Fix missing onLost NetworkCallbacks when network loses capability" into mnc-dev

* commit '06287d1c':
  Fix missing onLost NetworkCallbacks when network loses capability
parents 9820374a 06287d1c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -792,6 +792,7 @@ public final class NetworkCapabilities implements Parcelable {
                case NET_CAPABILITY_TRUSTED:        capabilities += "TRUSTED"; break;
                case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
                case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
                case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break;
            }
            if (++i < types.length) capabilities += "&";
        }
+78 −35
Original line number Diff line number Diff line
@@ -2171,6 +2171,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
                mDefaultInetConditionPublished = 0;
            }
            notifyIfacesChanged();
            // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
            // by other networks that are already connected. Perhaps that can be done by
            // sending all CALLBACK_LOST messages (for requests, not listens) at the end
            // of rematchAllNetworksAndRequests
            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
            mKeepaliveTracker.handleStopAllKeepalives(nai,
                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
@@ -2288,7 +2292,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    //    is currently satisfying the request.  This is desirable when
                    //    cellular ends up validating but WiFi does not.
                    // 2. Unvalidated WiFi will not be reaped when validated cellular
                    //    is currently satsifying the request.  This is desirable when
                    //    is currently satisfying the request.  This is desirable when
                    //    WiFi ends up validating and out scoring cellular.
                    mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
                            nai.getCurrentScoreAsValidated())) {
@@ -3866,10 +3870,10 @@ public class ConnectivityService extends IConnectivityManager.Stub

        // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
        // satisfies mDefaultRequest.
        NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
        final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
                linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest);
                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
        synchronized (this) {
            nai.networkMonitor.systemReady = mSystemReady;
        }
@@ -4265,8 +4269,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
        ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
        if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
            NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
            if (newNetwork == currentNetwork) {
            final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
            final boolean satisfies = newNetwork.satisfies(nri.request);
            if (newNetwork == currentNetwork && satisfies) {
                if (VDBG) {
                    log("Network " + newNetwork.name() + " was already satisfying" +
                            " request " + nri.request.requestId + ". No change.");
@@ -4277,7 +4282,7 @@ public class ConnectivityService extends IConnectivityManager.Stub

            // check if it satisfies the NetworkCapabilities
            if (VDBG) log("  checking if request is satisfied: " + nri.request);
            if (newNetwork.satisfies(nri.request)) {
            if (satisfies) {
                if (!nri.isRequest) {
                    // This is not a request, it's a callback listener.
                    // Add it to newNetwork regardless of score.
@@ -4320,6 +4325,37 @@ public class ConnectivityService extends IConnectivityManager.Stub
                        oldDefaultNetwork = currentNetwork;
                    }
                }
            } else if (newNetwork.networkRequests.get(nri.request.requestId) != null) {
                // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
                // mark it as no longer satisfying "nri".  Because networks are processed by
                // rematchAllNetworkAndRequests() in descending score order, "currentNetwork" will
                // match "newNetwork" before this loop will encounter a "currentNetwork" with higher
                // score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
                // This means this code doesn't have to handle the case where "currentNetwork" no
                // longer satisfies "nri" when "currentNetwork" does not equal "newNetwork".
                if (DBG) {
                    log("Network " + newNetwork.name() + " stopped satisfying" +
                            " request " + nri.request.requestId);
                }
                newNetwork.networkRequests.remove(nri.request.requestId);
                if (currentNetwork == newNetwork) {
                    mNetworkForRequestId.remove(nri.request.requestId);
                    sendUpdatedScoreToFactories(nri.request, 0);
                } else {
                    if (nri.isRequest == true) {
                        Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
                                newNetwork.name() +
                                " without updating mNetworkForRequestId or factories!");
                    }
                }
                // TODO: technically, sending CALLBACK_LOST here is
                // incorrect if nri is a request (not a listen) and there
                // is a replacement network currently connected that can
                // satisfy it. However, the only capability that can both
                // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
                // so this code is only incorrect for a network that loses
                // the TRUSTED capability, which is a rare case.
                callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST);
            }
        }
        // Linger any networks that are no longer needed.
@@ -4338,7 +4374,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
                unlinger(nai);
            }
        }
        if (keep) {
        if (isNewDefault) {
            // Notify system services that this network is up.
            makeDefault(newNetwork);
@@ -4373,6 +4408,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
            notifyLockdownVpn(newNetwork);
        }

        if (keep) {
            // Notify battery stats service about this network, both the normal
            // interface and any stacked links.
            // TODO: Avoid redoing this; this must only be done once when a network comes online.
@@ -4791,4 +4827,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
            }
        }
    }

    @VisibleForTesting
    public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
            NetworkAgentInfo nai, NetworkRequest defaultRequest) {
        return new NetworkMonitor(context, handler, nai, defaultRequest);
    }

}
+4 −3
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.Messenger;
import android.util.SparseArray;

import com.android.internal.util.AsyncChannel;
import com.android.server.ConnectivityService;
import com.android.server.connectivity.NetworkMonitor;

import java.util.ArrayList;
@@ -51,7 +52,7 @@ import java.util.Comparator;
//    ConnectivityService will tell netd to create the network and immediately transition to
//    state #3.
// 3. registered, created, connected, unvalidated
//    If this network can satsify the default NetworkRequest, then NetworkMonitor will
//    If this network can satisfy the default NetworkRequest, then NetworkMonitor will
//    probe for Internet connectivity.
//    If this network cannot satisfy the default NetworkRequest, it will immediately be
//    transitioned to state #4.
@@ -164,7 +165,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {

    public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
            LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
            NetworkMisc misc, NetworkRequest defaultRequest) {
            NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
        this.messenger = messenger;
        asyncChannel = ac;
        network = net;
@@ -172,7 +173,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        linkProperties = lp;
        networkCapabilities = nc;
        currentScore = score;
        networkMonitor = new NetworkMonitor(context, handler, this, defaultRequest);
        networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
        networkMisc = misc;
    }

+4 −3
Original line number Diff line number Diff line
@@ -349,7 +349,7 @@ public class NetworkMonitor extends StateMachine {
    // Being in the ValidatedState State indicates a Network is:
    // - Successfully validated, or
    // - Wanted "as is" by the user, or
    // - Does not satsify the default NetworkRequest and so validation has been skipped.
    // - Does not satisfy the default NetworkRequest and so validation has been skipped.
    private class ValidatedState extends State {
        @Override
        public void enter() {
@@ -558,7 +558,7 @@ public class NetworkMonitor extends StateMachine {

    // Being in the LingeringState State indicates a Network's validated bit is true and it once
    // was the highest scoring Network satisfying a particular NetworkRequest, but since then
    // another Network satsified the NetworkRequest with a higher score and hence this Network
    // another Network satisfied the NetworkRequest with a higher score and hence this Network
    // is "lingered" for a fixed period of time before it is disconnected.  This period of time
    // allows apps to wrap up communication and allows for seamless reactivation if the other
    // higher scoring Network happens to disconnect.
@@ -633,7 +633,8 @@ public class NetworkMonitor extends StateMachine {
     * Do a URL fetch on a known server to see if we get the data we expect.
     * Returns HTTP response code.
     */
    private int isCaptivePortal() {
    @VisibleForTesting
    protected int isCaptivePortal() {
        if (!mIsCaptivePortalCheckEnabled) return 204;

        HttpURLConnection urlConnection = null;
+139 −41
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import android.util.LogPrinter;

import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;

import org.mockito.ArgumentCaptor;
@@ -118,7 +119,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    private INetworkPolicyManager mPolicyService;

    private BroadcastInterceptingContext mServiceContext;
    private ConnectivityService mService;
    private WrappedConnectivityService mService;
    private ConnectivityManager mCm;
    private MockNetworkAgent mWiFiNetworkAgent;
    private MockNetworkAgent mCellNetworkAgent;
@@ -148,6 +149,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    }

    private class MockNetworkAgent {
        private final WrappedNetworkMonitor mWrappedNetworkMonitor;
        private final NetworkInfo mNetworkInfo;
        private final NetworkCapabilities mNetworkCapabilities;
        private final Thread mThread;
@@ -172,6 +174,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
                    throw new UnsupportedOperationException("unimplemented network type");
            }
            final ConditionVariable initComplete = new ConditionVariable();
            final ConditionVariable networkMonitorAvailable = mService.getNetworkMonitorCreatedCV();
            mThread = new Thread() {
                public void run() {
                    Looper.prepare();
@@ -186,6 +189,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
            };
            mThread.start();
            waitFor(initComplete);
            waitFor(networkMonitorAvailable);
            mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
        }

        public void adjustScore(int change) {
@@ -211,44 +216,46 @@ public class ConnectivityServiceTest extends AndroidTestCase {
            assertEquals(mNetworkInfo.getDetailedState(), DetailedState.IDLE);
            assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));

            // To pretend network is validated, we transition it to the CONNECTED state without
            // NET_CAPABILITY_INTERNET so NetworkMonitor doesn't bother trying to validate and
            // just rubber stamps it as validated.  Afterwards we add NET_CAPABILITY_INTERNET so
            // the network can satisfy the default request.
            NetworkCallback callback = null;
            final ConditionVariable validatedCv = new ConditionVariable();
            if (validated) {
                // If we connect a network without INTERNET capability, it'll get reaped.
                // Prevent the reaping by adding a NetworkRequest.
                mWrappedNetworkMonitor.gen204ProbeResult = 204;
                NetworkRequest request = new NetworkRequest.Builder()
                        .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
                        .build();
                callback = new NetworkCallback() {
                    public void onCapabilitiesChanged(Network network,
                            NetworkCapabilities networkCapabilities) {
                        if (networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                        if (network.equals(getNetwork()) &&
                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                            validatedCv.open();
                        }
                    }
                };
                mCm.requestNetwork(request, callback);
            } else {
                mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
                mCm.registerNetworkCallback(request, callback);
            }
            addCapability(NET_CAPABILITY_INTERNET);

            connectWithoutInternet();

            if (validated) {
                // Wait for network to validate.
                waitFor(validatedCv);
                mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
                mWrappedNetworkMonitor.gen204ProbeResult = 500;
            }

            if (callback != null) mCm.unregisterNetworkCallback(callback);
        }

        public void connectWithCaptivePortal() {
            mWrappedNetworkMonitor.gen204ProbeResult = 200;
            connect(false);
            waitFor(new Criteria() { public boolean get() {
                NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork());
                return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} });
            mWrappedNetworkMonitor.gen204ProbeResult = 500;
        }

        public void disconnect() {
            mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -261,14 +268,18 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        public ConditionVariable getDisconnectedCV() {
            return mDisconnected;
        }

        public WrappedNetworkMonitor getWrappedNetworkMonitor() {
            return mWrappedNetworkMonitor;
        }
    }

    private static class MockNetworkFactory extends NetworkFactory {
        final ConditionVariable mNetworkStartedCV = new ConditionVariable();
        final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
        final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
        final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
        final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
        private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
        private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
        private final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
        private final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
        private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);

        public MockNetworkFactory(Looper looper, Context context, String logTag,
                NetworkCapabilities filter) {
@@ -328,7 +339,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        }
    }

    // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
    private class WrappedNetworkMonitor extends NetworkMonitor {
        // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
        public int gen204ProbeResult = 500;

        public WrappedNetworkMonitor(Context context, Handler handler,
            NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) {
            super(context, handler, networkAgentInfo, defaultRequest);
        }

        @Override
        protected int isCaptivePortal() {
            return gen204ProbeResult;
        }
    }

    private class WrappedConnectivityService extends ConnectivityService {
        private final ConditionVariable mNetworkMonitorCreated = new ConditionVariable();
        private WrappedNetworkMonitor mLastCreatedNetworkMonitor;

        public WrappedConnectivityService(Context context, INetworkManagementService netManager,
                INetworkStatsService statsService, INetworkPolicyManager policyManager) {
            super(context, netManager, statsService, policyManager);
@@ -360,6 +390,25 @@ public class ConnectivityServiceTest extends AndroidTestCase {
                return netId;
            }
        }

        @Override
        public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
                NetworkAgentInfo nai, NetworkRequest defaultRequest) {
            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(context, handler, nai,
                    defaultRequest);
            mLastCreatedNetworkMonitor = monitor;
            mNetworkMonitorCreated.open();
            return monitor;
        }

        public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
            return mLastCreatedNetworkMonitor;
        }

        public ConditionVariable getNetworkMonitorCreatedCV() {
            mNetworkMonitorCreated.close();
            return mNetworkMonitorCreated;
        }
    }

    private interface Criteria {
@@ -586,29 +635,29 @@ public class ConnectivityServiceTest extends AndroidTestCase {

    @LargeTest
    public void testUnlingeringDoesNotValidate() throws Exception {
        // Test bringing up unvalidated cellular.
        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
        // Test bringing up unvalidated WiFi.
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        ConditionVariable cv = waitForConnectivityBroadcasts(1);
        mCellNetworkAgent.connect(false);
        mWiFiNetworkAgent.connect(false);
        waitFor(cv);
        verifyActiveNetwork(TRANSPORT_CELLULAR);
        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
        verifyActiveNetwork(TRANSPORT_WIFI);
        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                NET_CAPABILITY_VALIDATED));
        // Test bringing up validated WiFi.
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        // Test bringing up validated cellular.
        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
        cv = waitForConnectivityBroadcasts(2);
        mWiFiNetworkAgent.connect(true);
        mCellNetworkAgent.connect(true);
        waitFor(cv);
        verifyActiveNetwork(TRANSPORT_WIFI);
        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
        verifyActiveNetwork(TRANSPORT_CELLULAR);
        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                NET_CAPABILITY_VALIDATED));
        // Test WiFi disconnect.
        // Test cellular disconnect.
        cv = waitForConnectivityBroadcasts(2);
        mWiFiNetworkAgent.disconnect();
        mCellNetworkAgent.disconnect();
        waitFor(cv);
        verifyActiveNetwork(TRANSPORT_CELLULAR);
        verifyActiveNetwork(TRANSPORT_WIFI);
        // Unlingering a network should not cause it to be marked as validated.
        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                NET_CAPABILITY_VALIDATED));
    }

@@ -846,12 +895,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {

        cellCv = cellNetworkCallback.getConditionVariable();
        wifiCv = wifiNetworkCallback.getConditionVariable();
        // Our method for faking successful validation generates an additional callback, so wait
        // for broadcast instead.
        cv = waitForConnectivityBroadcasts(1);
        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
        mCellNetworkAgent.connect(true);
        waitFor(cv);
        waitFor(cellCv);
        assertEquals(CallbackState.AVAILABLE, cellNetworkCallback.getLastCallback());
        assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
@@ -868,12 +913,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {

        cellCv = cellNetworkCallback.getConditionVariable();
        wifiCv = wifiNetworkCallback.getConditionVariable();
        // Our method for faking successful validation generates an additional callback, so wait
        // for broadcast instead.
        cv = waitForConnectivityBroadcasts(1);
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(true);
        waitFor(cv);
        waitFor(wifiCv);
        assertEquals(CallbackState.AVAILABLE, wifiNetworkCallback.getLastCallback());
        waitFor(cellCv);
@@ -1075,6 +1116,63 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        verifyActiveNetwork(TRANSPORT_CELLULAR);
    }

    @LargeTest
    public void testCaptivePortal() {
        final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
        final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
                .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
        mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);

        final TestNetworkCallback validatedCallback = new TestNetworkCallback();
        final NetworkRequest validatedRequest = new NetworkRequest.Builder()
                .addCapability(NET_CAPABILITY_VALIDATED).build();
        mCm.registerNetworkCallback(validatedRequest, validatedCallback);
        ConditionVariable validatedCv = validatedCallback.getConditionVariable();

        // Bring up a network with a captive portal.
        // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
        ConditionVariable cv = captivePortalCallback.getConditionVariable();
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connectWithCaptivePortal();
        waitFor(cv);
        assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());

        // Take down network.
        // Expect onLost callback.
        cv = captivePortalCallback.getConditionVariable();
        mWiFiNetworkAgent.disconnect();
        waitFor(cv);
        assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());

        // Bring up a network with a captive portal.
        // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
        cv = captivePortalCallback.getConditionVariable();
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connectWithCaptivePortal();
        waitFor(cv);
        assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());

        // Make captive portal disappear then revalidate.
        // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
        cv = captivePortalCallback.getConditionVariable();
        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
        waitFor(cv);
        assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());

        // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
        waitFor(validatedCv);
        assertEquals(CallbackState.AVAILABLE, validatedCallback.getLastCallback());

        // Break network connectivity.
        // Expect NET_CAPABILITY_VALIDATED onLost callback.
        validatedCv = validatedCallback.getConditionVariable();
        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
        waitFor(validatedCv);
        assertEquals(CallbackState.LOST, validatedCallback.getLastCallback());
    }

//    @Override
//    public void tearDown() throws Exception {
//        super.tearDown();